CXX=g++
PKG_MODULES = Qt5Core Qt5Gui Qt5Widgets Qt5OpenGLExtensions Qt5OpenGL libusb-1.0 movit lua5.2 libmicrohttpd
-CXXFLAGS := -O2 -march=native -g -std=gnu++11 -Wall -Wno-deprecated-declarations -fPIC $(shell pkg-config --cflags $(PKG_MODULES)) -pthread -DMOVIT_SHADER_DIR=\"$(shell pkg-config --variable=shaderdir movit)\"
+CXXFLAGS := -O2 -march=native -g -std=gnu++11 -Wall -Wno-deprecated-declarations -Werror -fPIC $(shell pkg-config --cflags $(PKG_MODULES)) -pthread -DMOVIT_SHADER_DIR=\"$(shell pkg-config --variable=shaderdir movit)\"
LDFLAGS=$(shell pkg-config --libs $(PKG_MODULES)) -lEGL -lGL -pthread -lva -lva-drm -lva-x11 -lX11 -lavformat -lavcodec -lavutil -lswscale -lzita-resampler -lasound
# Qt objects
-OBJS=glwidget.o main.o mainwindow.o vumeter.o lrameter.o vu_common.o aboutdialog.o
-OBJS += glwidget.moc.o mainwindow.moc.o vumeter.moc.o lrameter.moc.o aboutdialog.moc.o
+OBJS=glwidget.o main.o mainwindow.o vumeter.o lrameter.o vu_common.o correlation_meter.o aboutdialog.o
+OBJS += glwidget.moc.o mainwindow.moc.o vumeter.moc.o lrameter.moc.o correlation_meter.moc.o aboutdialog.moc.o
# Mixer objects
OBJS += h264encode.o mixer.o bmusb/bmusb.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o resampling_queue.o httpd.o ebu_r128_proc.o flags.o image_input.o stereocompressor.o filter.o alsa_output.o correlation_measurer.o
{
}
+void CorrelationMeasurer::reset()
+{
+ zl = zr = zll = zlr = zrr = 0.0f;
+}
+
void CorrelationMeasurer::process_samples(const std::vector<float> &samples)
{
assert(samples.size() % 2 == 0);
CorrelationMeasurer(unsigned sample_rate, float lowpass_cutoff_hz = 1000.0f,
float falloff_seconds = 0.150f);
void process_samples(const std::vector<float> &samples); // Taken to be stereo, interleaved.
+ void reset();
float get_correlation() const;
private:
--- /dev/null
+#include <QPainter>
+
+#include "correlation_meter.h"
+
+using namespace std;
+
+CorrelationMeter::CorrelationMeter(QWidget *parent)
+ : QWidget(parent)
+{
+}
+
+void CorrelationMeter::resizeEvent(QResizeEvent *event)
+{
+ on_pixmap = QPixmap(width(), height());
+ QPainter on_painter(&on_pixmap);
+ QLinearGradient on(0, 0, width(), 0);
+ on.setColorAt(0.0f, QColor(255, 0, 0));
+ on.setColorAt(0.5f, QColor(255, 255, 0));
+ on.setColorAt(0.8f, QColor(0, 255, 0));
+ on.setColorAt(0.95f, QColor(255, 255, 0));
+ on_painter.fillRect(0, 0, width(), height(), Qt::black);
+ on_painter.fillRect(1, 1, width() - 2, height() - 2, on);
+
+ off_pixmap = QPixmap(width(), height());
+ QPainter off_painter(&off_pixmap);
+ QLinearGradient off(0, 0, width(), 0);
+ off.setColorAt(0.0f, QColor(127, 0, 0));
+ off.setColorAt(0.5f, QColor(127, 127, 0));
+ off.setColorAt(0.8f, QColor(0, 127, 0));
+ off.setColorAt(0.95f, QColor(127, 127, 0));
+ off_painter.fillRect(0, 0, width(), height(), Qt::black);
+ off_painter.fillRect(1, 1, width() - 2, height() - 2, off);
+}
+
+void CorrelationMeter::paintEvent(QPaintEvent *event)
+{
+ QPainter painter(this);
+
+ float correlation;
+ {
+ unique_lock<mutex> lock(correlation_mutex);
+ correlation = this->correlation;
+ }
+
+ // Just in case.
+ correlation = std::min(std::max(correlation, -1.0f), 1.0f);
+
+ int pos = 3 + lrintf(0.5f * (correlation + 1.0f) * (width() - 6));
+ QRect off_rect(0, 0, width(), height());
+ QRect on_rect(pos - 2, 0, 5, height());
+
+ painter.drawPixmap(off_rect, off_pixmap, off_rect);
+ painter.drawPixmap(on_rect, on_pixmap, on_rect);
+}
--- /dev/null
+#ifndef CORRELATION_METER_H
+#define CORRELATION_METER_H
+
+#include <QPaintEvent>
+#include <QWidget>
+#include <mutex>
+
+class CorrelationMeter : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CorrelationMeter(QWidget *parent);
+
+ void set_correlation(float correlation) {
+ std::unique_lock<std::mutex> lock(correlation_mutex);
+ this->correlation = correlation;
+ QMetaObject::invokeMethod(this, "update", Qt::AutoConnection);
+ }
+
+private:
+ void resizeEvent(QResizeEvent *event) override;
+ void paintEvent(QPaintEvent *event) override;
+
+ std::mutex correlation_mutex;
+ float correlation = 0.0f;
+
+ QPixmap on_pixmap, off_pixmap;
+};
+
+#endif
global_mixer->set_compressor_enabled(state == Qt::Checked);
});
connect(ui->reset_meters_button, &QPushButton::clicked, this, &MainWindow::reset_meters_button_clicked);
- mixer->set_audio_level_callback(bind(&MainWindow::audio_level_callback, this, _1, _2, _3, _4, _5, _6, _7));
+ mixer->set_audio_level_callback(bind(&MainWindow::audio_level_callback, this, _1, _2, _3, _4, _5, _6, _7, _8));
}
void MainWindow::mixer_shutting_down()
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 gain_staging_db, float final_makeup_gain_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, float final_makeup_gain_db,
+ float correlation)
{
timeval now;
gettimeofday(&now, nullptr);
post_to_main_thread([=]() {
ui->vu_meter->set_level(level_lufs);
ui->lra_meter->set_levels(global_level_lufs, range_low_lufs, range_high_lufs);
+ ui->correlation_meter->set_correlation(correlation);
char buf[256];
snprintf(buf, sizeof(buf), "%.1f", peak_db);
void set_white_balance(int channel_number, int x, int y);
// 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);
+ 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);
timeval last_audio_level_callback{0, 0};
Ui::MainWindow *ui;
num_cards(num_cards),
mixer_surface(create_surface(format)),
h264_encoder_surface(create_surface(format)),
+ correlation(OUTPUT_FREQUENCY),
level_compressor(OUTPUT_FREQUENCY),
limiter(OUTPUT_FREQUENCY),
compressor(OUTPUT_FREQUENCY)
audio_level_callback(loudness_s, 20.0 * log10(peak),
loudness_i, loudness_range_low, loudness_range_high,
- gain_staging_db, 20.0 * log10(final_makeup_gain));
+ gain_staging_db, 20.0 * log10(final_makeup_gain),
+ correlation.get_correlation());
}
for (unsigned card_index = 1; card_index < num_cards; ++card_index) {
final_makeup_gain = m;
}
- // Find R128 levels.
+ // Find R128 levels and L/R correlation.
vector<float> left, right;
deinterleave_samples(samples_out, &left, &right);
float *ptrs[] = { left.data(), right.data() };
{
unique_lock<mutex> lock(compressor_mutex);
r128.process(left.size(), ptrs);
+ correlation.process_samples(samples_out);
}
// Send the samples to the sound card.
peak = 0.0f;
r128.reset();
r128.integr_start();
+ correlation.reset();
}
Mixer::OutputChannel::~OutputChannel()
#include "stereocompressor.h"
#include "filter.h"
#include "input_state.h"
+#include "correlation_measurer.h"
class H264Encoder;
class QSurface;
typedef std::function<void(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)> audio_level_callback_t;
+ float gain_staging_db, float final_makeup_gain_db,
+ float correlation)> audio_level_callback_t;
void set_audio_level_callback(audio_level_callback_t callback)
{
audio_level_callback = callback;
audio_level_callback_t audio_level_callback = nullptr;
std::mutex compressor_mutex;
Ebu_r128_proc r128; // Under compressor_mutex.
+ CorrelationMeasurer correlation; // Under compressor_mutex.
Resampler peak_resampler;
std::atomic<float> peak{0.0f};
<item row="0" column="0">
<layout class="QVBoxLayout" name="vertical_layout" stretch="0,0,0,0">
<item>
- <layout class="QHBoxLayout" name="me_displays" stretch="0,0,0,0,0">
+ <layout class="QHBoxLayout" name="me_displays" stretch="0,0,0,0">
<item>
<layout class="QVBoxLayout" name="preview_vertical_layout">
<property name="leftMargin">
</layout>
</item>
<item>
- <layout class="QVBoxLayout" name="vu_meter_vertical_layout" stretch="1,0">
- <property name="leftMargin">
+ <layout class="QVBoxLayout" name="audio_meters">
+ <property name="rightMargin">
<number>0</number>
</property>
- <property name="bottomMargin">
- <number>4</number>
- </property>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <property name="bottomMargin">
- <number>0</number>
+ <widget class="CorrelationMeter" name="correlation_meter" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <item>
- <widget class="VUMeter" name="vu_meter" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>1</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>16</width>
- <height>0</height>
- </size>
- </property>
- <property name="sizeIncrement">
- <size>
- <width>1</width>
- <height>0</height>
- </size>
- </property>
- <property name="baseSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="palette">
- <palette>
- <active>
- <colorrole role="Base">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>255</red>
- <green>255</green>
- <blue>255</blue>
- </color>
- </brush>
- </colorrole>
- <colorrole role="Window">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>5</red>
- <green>239</green>
- <blue>111</blue>
- </color>
- </brush>
- </colorrole>
- </active>
- <inactive>
- <colorrole role="Base">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>255</red>
- <green>255</green>
- <blue>255</blue>
- </color>
- </brush>
- </colorrole>
- <colorrole role="Window">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>5</red>
- <green>239</green>
- <blue>111</blue>
- </color>
- </brush>
- </colorrole>
- </inactive>
- <disabled>
- <colorrole role="Base">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>5</red>
- <green>239</green>
- <blue>111</blue>
- </color>
- </brush>
- </colorrole>
- <colorrole role="Window">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>5</red>
- <green>239</green>
- <blue>111</blue>
- </color>
- </brush>
- </colorrole>
- </disabled>
- </palette>
- </property>
- <property name="autoFillBackground">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QLabel" name="peak_display">
<property name="minimumSize">
<size>
- <width>30</width>
- <height>0</height>
+ <width>0</width>
+ <height>14</height>
</size>
</property>
- <property name="text">
- <string>-0.0</string>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>239</red>
+ <green>0</green>
+ <blue>4</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>239</red>
+ <green>0</green>
+ <blue>4</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>239</red>
+ <green>0</green>
+ <blue>4</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>239</red>
+ <green>0</green>
+ <blue>4</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
</property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
+ <property name="autoFillBackground">
+ <bool>true</bool>
</property>
</widget>
</item>
- </layout>
- </item>
- <item>
- <layout class="QVBoxLayout" name="lra_vertical_layout" stretch="1,0">
- <property name="spacing">
- <number>3</number>
- </property>
- <property name="leftMargin">
- <number>0</number>
- </property>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <layout class="QHBoxLayout" name="vu_meters">
<item>
- <widget class="LRAMeter" name="lra_meter" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <layout class="QVBoxLayout" name="vu_meter_vertical_layout" stretch="1,0">
+ <property name="leftMargin">
+ <number>0</number>
</property>
- <property name="minimumSize">
- <size>
- <width>24</width>
- <height>0</height>
- </size>
+ <property name="bottomMargin">
+ <number>4</number>
</property>
- <property name="palette">
- <palette>
- <active>
- <colorrole role="Base">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>255</red>
- <green>255</green>
- <blue>255</blue>
- </color>
- </brush>
- </colorrole>
- <colorrole role="Window">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>0</red>
- <green>239</green>
- <blue>219</blue>
- </color>
- </brush>
- </colorrole>
- </active>
- <inactive>
- <colorrole role="Base">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>255</red>
- <green>255</green>
- <blue>255</blue>
- </color>
- </brush>
- </colorrole>
- <colorrole role="Window">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>0</red>
- <green>239</green>
- <blue>219</blue>
- </color>
- </brush>
- </colorrole>
- </inactive>
- <disabled>
- <colorrole role="Base">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>0</red>
- <green>239</green>
- <blue>219</blue>
- </color>
- </brush>
- </colorrole>
- <colorrole role="Window">
- <brush brushstyle="SolidPattern">
- <color alpha="255">
- <red>0</red>
- <green>239</green>
- <blue>219</blue>
- </color>
- </brush>
- </colorrole>
- </disabled>
- </palette>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="VUMeter" name="vu_meter" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>16</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="sizeIncrement">
+ <size>
+ <width>1</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>5</red>
+ <green>239</green>
+ <blue>111</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>5</red>
+ <green>239</green>
+ <blue>111</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>5</red>
+ <green>239</green>
+ <blue>111</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>5</red>
+ <green>239</green>
+ <blue>111</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="peak_display">
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>-0.0</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="lra_vertical_layout" stretch="1,0">
+ <property name="spacing">
+ <number>3</number>
</property>
- <property name="autoFillBackground">
- <bool>true</bool>
+ <property name="leftMargin">
+ <number>0</number>
</property>
- </widget>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="LRAMeter" name="lra_meter" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>24</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>239</green>
+ <blue>219</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>239</green>
+ <blue>219</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>239</green>
+ <blue>219</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>239</green>
+ <blue>219</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="reset_meters_button">
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>RST</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
</layout>
</item>
- <item>
- <widget class="QPushButton" name="reset_meters_button">
- <property name="maximumSize">
- <size>
- <width>30</width>
- <height>20</height>
- </size>
- </property>
- <property name="text">
- <string>RST</string>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- </widget>
- </item>
</layout>
</item>
</layout>
<header>lrameter.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>CorrelationMeter</class>
+ <extends>QWidget</extends>
+ <header>correlation_meter.h</header>
+ <container>1</container>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>