This replaces the old code for the audio meter that was using calculations in two different places with the new audio meter api. The source signal will now emit simple levels instead of dB values, in order to avoid dB conversion and calculation in the source. The GUI on the other hand now expects simple position values from the volume meter api with no knowledge about dB calculus either. That way all code that handles those conversions is in one place, with the option to easily add new mappings that can be used everywhere.
223 lines
5.2 KiB
C++
223 lines
5.2 KiB
C++
#include "volume-control.hpp"
|
|
#include "qt-wrappers.hpp"
|
|
#include <util/platform.h>
|
|
#include <QHBoxLayout>
|
|
#include <QVBoxLayout>
|
|
#include <QSlider>
|
|
#include <QLabel>
|
|
#include <QPainter>
|
|
#include <QTimer>
|
|
#include <string>
|
|
#include <math.h>
|
|
|
|
using namespace std;
|
|
|
|
#define UPDATE_INTERVAL_MS 50
|
|
|
|
void VolControl::OBSVolumeChanged(void *data, calldata_t *calldata)
|
|
{
|
|
Q_UNUSED(calldata);
|
|
VolControl *volControl = static_cast<VolControl*>(data);
|
|
|
|
QMetaObject::invokeMethod(volControl, "VolumeChanged");
|
|
}
|
|
|
|
void VolControl::OBSVolumeLevel(void *data, calldata_t *calldata)
|
|
{
|
|
VolControl *volControl = static_cast<VolControl*>(data);
|
|
float peak = calldata_float(calldata, "level");
|
|
float mag = calldata_float(calldata, "magnitude");
|
|
float peakHold = calldata_float(calldata, "peak");
|
|
|
|
QMetaObject::invokeMethod(volControl, "VolumeLevel",
|
|
Q_ARG(float, mag),
|
|
Q_ARG(float, peak),
|
|
Q_ARG(float, peakHold));
|
|
}
|
|
|
|
void VolControl::VolumeChanged()
|
|
{
|
|
slider->setValue((int) (obs_fader_get_deflection(obs_fader) * 100.0f));
|
|
}
|
|
|
|
void VolControl::VolumeLevel(float mag, float peak, float peakHold)
|
|
{
|
|
uint64_t curMeterTime = os_gettime_ns() / 1000000;
|
|
|
|
/*
|
|
Add again peak averaging?
|
|
*/
|
|
|
|
/* only update after a certain amount of time */
|
|
if ((curMeterTime - lastMeterTime) > UPDATE_INTERVAL_MS) {
|
|
lastMeterTime = curMeterTime;
|
|
volMeter->setLevels(mag, peak, peakHold);
|
|
}
|
|
}
|
|
|
|
void VolControl::SliderChanged(int vol)
|
|
{
|
|
obs_fader_set_deflection(obs_fader, float(vol) * 0.01f);
|
|
volLabel->setText(QString::number(obs_fader_get_db(obs_fader), 'f', 1)
|
|
.append(" dB"));
|
|
}
|
|
|
|
QString VolControl::GetName() const
|
|
{
|
|
return nameLabel->text();
|
|
}
|
|
|
|
void VolControl::SetName(const QString &newName)
|
|
{
|
|
nameLabel->setText(newName);
|
|
}
|
|
|
|
VolControl::VolControl(OBSSource source_)
|
|
: source (source_),
|
|
lastMeterTime (0),
|
|
levelTotal (0.0f),
|
|
levelCount (0.0f),
|
|
obs_fader (obs_fader_create(OBS_FADER_CUBIC)),
|
|
obs_volmeter (obs_volmeter_create(OBS_FADER_LOG))
|
|
{
|
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
|
QHBoxLayout *textLayout = new QHBoxLayout();
|
|
|
|
nameLabel = new QLabel();
|
|
volLabel = new QLabel();
|
|
volMeter = new VolumeMeter();
|
|
slider = new QSlider(Qt::Horizontal);
|
|
|
|
QFont font = nameLabel->font();
|
|
font.setPointSize(font.pointSize()-1);
|
|
|
|
nameLabel->setText(obs_source_get_name(source));
|
|
nameLabel->setFont(font);
|
|
volLabel->setFont(font);
|
|
slider->setMinimum(0);
|
|
slider->setMaximum(100);
|
|
|
|
// slider->setMaximumHeight(13);
|
|
|
|
textLayout->setContentsMargins(0, 0, 0, 0);
|
|
textLayout->addWidget(nameLabel);
|
|
textLayout->addWidget(volLabel);
|
|
textLayout->setAlignment(nameLabel, Qt::AlignLeft);
|
|
textLayout->setAlignment(volLabel, Qt::AlignRight);
|
|
|
|
mainLayout->setContentsMargins(4, 4, 4, 4);
|
|
mainLayout->setSpacing(2);
|
|
mainLayout->addItem(textLayout);
|
|
mainLayout->addWidget(volMeter);
|
|
mainLayout->addWidget(slider);
|
|
|
|
setLayout(mainLayout);
|
|
|
|
signal_handler_connect(obs_fader_get_signal_handler(obs_fader),
|
|
"volume_changed", OBSVolumeChanged, this);
|
|
|
|
signal_handler_connect(obs_volmeter_get_signal_handler(obs_volmeter),
|
|
"levels_updated", OBSVolumeLevel, this);
|
|
|
|
QWidget::connect(slider, SIGNAL(valueChanged(int)),
|
|
this, SLOT(SliderChanged(int)));
|
|
|
|
obs_fader_attach_source(obs_fader, source);
|
|
obs_volmeter_attach_source(obs_volmeter, source);
|
|
|
|
/* Call volume changed once to init the slider position and label */
|
|
VolumeChanged();
|
|
}
|
|
|
|
VolControl::~VolControl()
|
|
{
|
|
signal_handler_disconnect(obs_fader_get_signal_handler(obs_fader),
|
|
"volume_changed", OBSVolumeChanged, this);
|
|
|
|
signal_handler_disconnect(obs_volmeter_get_signal_handler(obs_volmeter),
|
|
"levels_updated", OBSVolumeLevel, this);
|
|
|
|
obs_fader_destroy(obs_fader);
|
|
obs_volmeter_destroy(obs_volmeter);
|
|
}
|
|
|
|
VolumeMeter::VolumeMeter(QWidget *parent)
|
|
: QWidget(parent)
|
|
{
|
|
setMinimumSize(1, 3);
|
|
|
|
bkColor.setRgb(0xDD, 0xDD, 0xDD);
|
|
magColor.setRgb(0x20, 0x7D, 0x17);
|
|
peakColor.setRgb(0x3E, 0xF1, 0x2B);
|
|
peakHoldColor.setRgb(0x00, 0x00, 0x00);
|
|
|
|
resetTimer = new QTimer(this);
|
|
connect(resetTimer, SIGNAL(timeout()), this, SLOT(resetState()));
|
|
|
|
resetState();
|
|
}
|
|
|
|
void VolumeMeter::resetState(void)
|
|
{
|
|
setLevels(0.0f, 0.0f, 0.0f);
|
|
if (resetTimer->isActive())
|
|
resetTimer->stop();
|
|
}
|
|
|
|
void VolumeMeter::setLevels(float nmag, float npeak, float npeakHold)
|
|
{
|
|
mag = nmag;
|
|
peak = npeak;
|
|
peakHold = npeakHold;
|
|
|
|
update();
|
|
|
|
if (resetTimer->isActive())
|
|
resetTimer->stop();
|
|
resetTimer->start(1000);
|
|
}
|
|
|
|
void VolumeMeter::paintEvent(QPaintEvent *event)
|
|
{
|
|
UNUSED_PARAMETER(event);
|
|
|
|
QPainter painter(this);
|
|
QLinearGradient gradient;
|
|
|
|
int width = size().width();
|
|
int height = size().height();
|
|
|
|
int scaledMag = int((float)width * mag);
|
|
int scaledPeak = int((float)width * peak);
|
|
int scaledPeakHold = int((float)width * peakHold);
|
|
|
|
gradient.setStart(qreal(scaledMag), 0);
|
|
gradient.setFinalStop(qreal(scaledPeak), 0);
|
|
gradient.setColorAt(0, magColor);
|
|
gradient.setColorAt(1, peakColor);
|
|
|
|
// RMS
|
|
painter.fillRect(0, 0,
|
|
scaledMag, height,
|
|
magColor);
|
|
|
|
// RMS - Peak gradient
|
|
painter.fillRect(scaledMag, 0,
|
|
scaledPeak - scaledMag + 1, height,
|
|
QBrush(gradient));
|
|
|
|
// Background
|
|
painter.fillRect(scaledPeak, 0,
|
|
width - scaledPeak, height,
|
|
bkColor);
|
|
|
|
// Peak hold
|
|
if (peakHold == 1.0f)
|
|
scaledPeakHold--;
|
|
|
|
painter.setPen(peakHoldColor);
|
|
painter.drawLine(scaledPeakHold, 0,
|
|
scaledPeakHold, height);
|
|
|
|
}
|