Files
oak-editor/app/widget/audiomonitor/audiomonitor.cpp
T
itsmattkc 26cafa7936 implemented bulk of curve editor's functionality
While certainly not entirely complete yet, this implements most of the UI
functionality of the graph editor.
2019-12-28 18:26:37 +11:00

148 lines
3.6 KiB
C++

#include "audiomonitor.h"
#include <QAudio>
#include <QDebug>
#include <QPainter>
#include "audio/audiomanager.h"
#include "common/qtversionabstraction.h"
const int kDecibelStep = 6;
const int kDecibelMinimum = -200;
const int kClearTimerInterval = 500;
AudioMonitor::AudioMonitor(QWidget *parent) :
QWidget(parent)
{
clear_timer_.setInterval(kClearTimerInterval);
connect(AudioManager::instance(), &AudioManager::SentSamples, this, &AudioMonitor::SetValues);
connect(&clear_timer_, &QTimer::timeout, this, &AudioMonitor::Clear);
connect(&clear_timer_, &QTimer::timeout, &clear_timer_, &QTimer::stop);
}
void AudioMonitor::SetValues(QVector<double> values)
{
values_ = values;
if (values_.size() != peaked_.size()) {
peaked_.resize(values_.size());
peaked_.fill(false);
}
clear_timer_.stop();
clear_timer_.start();
update();
}
void AudioMonitor::Clear()
{
values_.fill(0);
update();
}
void AudioMonitor::paintEvent(QPaintEvent *)
{
int channels = values_.size();
if (channels == 0) {
return;
}
QPainter p(this);
QFontMetrics fm = p.fontMetrics();
int peaks_y = 0;
int peaks_height = fm.height();
QRect db_labels_rect = rect();
db_labels_rect.setWidth(QFontMetricsWidth(p.fontMetrics(), "-00"));
db_labels_rect.adjust(0, peaks_height, 0, 0);
QRect full_meter_rect = rect();
full_meter_rect.adjust(db_labels_rect.width(), peaks_height, 0, 0);
// Draw decibel markings
QRect last_db_marking_rect;
for (int i=0;i>=kDecibelMinimum;i-=kDecibelStep) {
QString db_label;
if (i <= kDecibelMinimum) {
db_label = "-∞";
} else {
db_label = QStringLiteral("%1").arg(i);
}
qreal log_val = QAudio::convertVolume(i, QAudio::DecibelVolumeScale, QAudio::LogarithmicVolumeScale);
QRect db_marking_rect = db_labels_rect;
db_marking_rect.adjust(0, db_labels_rect.height() - qRound(log_val * db_labels_rect.height()), 0, 0);
db_marking_rect.setHeight(fm.height());
// Prevent any dB markings overlapping
if (i == 0 || !db_marking_rect.intersects(last_db_marking_rect)) {
p.drawText(db_marking_rect, Qt::AlignRight, db_label);
p.drawLine(db_marking_rect.topLeft(), db_marking_rect.topRight());
last_db_marking_rect = db_marking_rect;
}
}
QLinearGradient g(full_meter_rect.topLeft(), full_meter_rect.bottomLeft());
g.setStops({
QGradientStop(0.0, Qt::red),
QGradientStop(0.25, Qt::yellow),
QGradientStop(1.0, Qt::green)
});
int channel_width = full_meter_rect.width() / channels;
for (int i=0;i<channels;i++) {
int channel_x = full_meter_rect.x() + channel_width * i;
QRect peaks_rect(channel_x, peaks_y, channel_width, peaks_height);
QRect meter_rect = full_meter_rect;
meter_rect.setX(channel_x);
meter_rect.setWidth(channel_width);
p.setPen(Qt::black);
// Draw peak rects
p.setBrush(Qt::red);
p.drawRect(peaks_rect);
// Draw gradient meter
p.setBrush(g);
p.drawRect(meter_rect);
// Draw inverted semi-transparent black overlay depending on information
p.setPen(Qt::NoPen);
// Validate value and whether it peaked
double vol = values_.at(i);
if (vol > 1.0) {
peaked_[i] = true;
}
// Convert val to logarithmic scale
vol = QAudio::convertVolume(vol, QAudio::LinearVolumeScale, QAudio::LogarithmicVolumeScale);
p.setBrush(QColor(0, 0, 0, 128));
meter_rect.adjust(0, 0, 0, -qRound(meter_rect.height() * vol));
p.drawRect(meter_rect);
if (!peaked_.at(i))
p.drawRect(peaks_rect);
}
}
void AudioMonitor::mousePressEvent(QMouseEvent *)
{
peaked_.fill(false);
update();
}