Refactor analyzers for new FHT modifications. Use QVectors where possible. Make readability changes in the code.

This commit is contained in:
santigl 2017-03-11 14:14:11 -03:00 committed by John Maguire
parent 6a19afde15
commit 6c9bc43bbb
9 changed files with 61 additions and 75 deletions

View File

@ -62,14 +62,13 @@ static const int sBarkBandCount = arraysize(sBarkBands);
Analyzer::Base::Base(QWidget* parent, uint scopeSize) Analyzer::Base::Base(QWidget* parent, uint scopeSize)
: QWidget(parent), : QWidget(parent),
timeout_(40) // msec timeout_(40), // msec
,
fht_(new FHT(scopeSize)), fht_(new FHT(scopeSize)),
engine_(nullptr), engine_(nullptr),
lastScope_(512), lastScope_(512),
new_frame_(false), new_frame_(false),
is_playing_(false), is_playing_(false),
barkband_table_(QList<uint>()), barkband_table_(),
prev_color_index_(0), prev_color_index_(0),
bands_(0), bands_(0),
psychedelic_enabled_(false) {} psychedelic_enabled_(false) {}
@ -86,15 +85,17 @@ void Analyzer::Base::transform(Scope& scope) {
// values // values
// scope.resize( fht_->size() ); // scope.resize( fht_->size() );
float* front = static_cast<float*>(&scope.front()); QVector<float> aux(fht_->size());
if (aux.size() >= scope.size()) {
qCopy(scope.begin(), scope.end(), aux.begin());
} else {
qCopy(scope.begin(), scope.begin() + aux.size(), aux.begin());
}
float* f = new float[fht_->size()]; fht_->logSpectrum(scope.data(), aux.data());
fht_->copy(&f[0], front); fht_->scale(scope.data(), 1.0 / 20);
fht_->logSpectrum(front, &f[0]);
fht_->scale(front, 1.0 / 20);
scope.resize(fht_->size() / 2); // second half of values are rubbish scope.resize(fht_->size() / 2); // second half of values are rubbish
delete[] f;
} }
void Analyzer::Base::paintEvent(QPaintEvent* e) { void Analyzer::Base::paintEvent(QPaintEvent* e) {
@ -202,7 +203,7 @@ void Analyzer::Base::updateBandSize(const int scopeSize) {
bands_ = scopeSize; bands_ = scopeSize;
barkband_table_.clear(); barkband_table_.clear();
barkband_table_.reserve(bands_ + 1); barkband_table_.resize(bands_ + 1);
int barkband = 0; int barkband = 0;
for (int i = 0; i < bands_ + 1; ++i) { for (int i = 0; i < bands_ + 1; ++i) {
@ -218,7 +219,7 @@ void Analyzer::Base::updateBandSize(const int scopeSize) {
QColor Analyzer::Base::getPsychedelicColor(const Scope& scope, QColor Analyzer::Base::getPsychedelicColor(const Scope& scope,
const int ampFactor, const int ampFactor,
const int bias) { const int bias) {
if (scope.size() > barkband_table_.length()) { if (scope.size() > barkband_table_.size()) {
return palette().color(QPalette::Highlight); return palette().color(QPalette::Highlight);
} }
@ -232,15 +233,12 @@ QColor Analyzer::Base::getPsychedelicColor(const Scope& scope,
// Now divide the bark bands into thirds and compute their total amplitudes. // Now divide the bark bands into thirds and compute their total amplitudes.
double rgb[3]{}; double rgb[3]{};
for (int i = 0; i < sBarkBandCount - 1; ++i) { for (int i = 0; i < sBarkBandCount - 1; ++i) {
rgb[(i * 3) / sBarkBandCount] += bands[i] * bands[i]; rgb[(i * 3) / sBarkBandCount] += pow(bands[i], 2);
} }
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
// bias colours for a threshold around normally amplified audio // bias colours for a threshold around normally amplified audio
rgb[i] = (int)((sqrt(rgb[i]) * ampFactor) + bias); rgb[i] = qMin(255, (int)((sqrt(rgb[i]) * ampFactor) + bias));
if (rgb[i] > 255) {
rgb[i] = 255;
}
} }
return QColor::fromRgb(rgb[0], rgb[1], rgb[2]); return QColor::fromRgb(rgb[0], rgb[1], rgb[2]);

View File

@ -109,7 +109,7 @@ class Base : public QWidget {
bool new_frame_; bool new_frame_;
bool is_playing_; bool is_playing_;
QList<uint> barkband_table_; QVector<uint> barkband_table_;
double prev_colors_[10][3]; double prev_colors_[10][3];
int prev_color_index_; int prev_color_index_;
int bands_; int bands_;

View File

@ -100,8 +100,11 @@ void BarAnalyzer::colorChanged() {
rgb = palette().color(QPalette::Highlight); rgb = palette().color(QPalette::Highlight);
} }
for (int x = 0, r = rgb.red(), g = rgb.green(), b = rgb.blue(), r2 = 255 - r; for (int x = 0; x < height(); ++x) {
x < height(); ++x) { int r = rgb.red();
int g = rgb.green();
int b = rgb.blue();
int r2 = 255 - r;
for (int y = x; y > 0; --y) { for (int y = x; y > 0; --y) {
const double fraction = static_cast<double>(y) / height(); const double fraction = static_cast<double>(y) / height();
@ -121,7 +124,7 @@ void BarAnalyzer::psychedelicModeChanged(bool enabled) {
} }
void BarAnalyzer::analyze(QPainter& p, const Scope& s, bool new_frame) { void BarAnalyzer::analyze(QPainter& p, const Scope& s, bool new_frame) {
if (!new_frame || engine_->state() == Engine::Paused) { if (!new_frame || engine_->state() == Engine::Paused) {
p.drawPixmap(0, 0, canvas_); p.drawPixmap(0, 0, canvas_);
return; return;
} }

View File

@ -127,10 +127,8 @@ void BlockAnalyzer::framerateChanged() { // virtual
void BlockAnalyzer::transform(Analyzer::Scope& s) { void BlockAnalyzer::transform(Analyzer::Scope& s) {
for (uint x = 0; x < s.size(); ++x) s[x] *= 2; for (uint x = 0; x < s.size(); ++x) s[x] *= 2;
float* front = static_cast<float*>(&s.front()); fht_->spectrum(s.data());
fht_->scale(s.data(), 1.0 / 20);
fht_->spectrum(front);
fht_->scale(front, 1.0 / 20);
// the second half is pretty dull, so only show it if the user has a large // the second half is pretty dull, so only show it if the user has a large
// analyzer // analyzer

View File

@ -68,14 +68,13 @@ class BlockAnalyzer : public Analyzer::Base {
QPixmap topBarPixmap_; QPixmap topBarPixmap_;
QPixmap background_; QPixmap background_;
QPixmap canvas_; QPixmap canvas_;
Analyzer::Scope scope_; // so we don't create a vector every frame Analyzer::Scope scope_; // so we don't create a vector every frame
std::vector<float> store_; // current bar kHeights QVector<float> store_; // current bar kHeights
std::vector<float> yscale_; QVector<float> yscale_;
// FIXME why can't I namespace these? c++ issue? QVector<QPixmap> fade_bars_;
std::vector<QPixmap> fade_bars_; QVector<uint> fade_pos_;
std::vector<uint> fade_pos_; QVector<int> fade_intensity_;
std::vector<int> fade_intensity_;
float step_; // rows to fall per frame float step_; // rows to fall per frame
}; };

View File

@ -93,10 +93,8 @@ void BoomAnalyzer::resizeEvent(QResizeEvent* e) {
} }
void BoomAnalyzer::transform(Scope& s) { void BoomAnalyzer::transform(Scope& s) {
float* front = static_cast<float*>(&s.front()); fht_->spectrum(s.data());
fht_->scale(s.data(), 1.0 / 50);
fht_->spectrum(front);
fht_->scale(front, 1.0 / 50);
s.resize(scope_.size() <= kMaxBandCount / 2 ? kMaxBandCount / 2 s.resize(scope_.size() <= kMaxBandCount / 2 ? kMaxBandCount / 2
: scope_.size()); : scope_.size());

View File

@ -6,7 +6,7 @@
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com> Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca> Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
Copyright 2015, Arun Narayanankutty <n.arun.lifescience@gmail.com> Copyright 2015, Arun Narayanankutty <n.arun.lifescience@gmail.com>
Clementine is free software: you can redistribute it and/or modify Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
@ -26,19 +26,19 @@
#include <cmath> #include <cmath>
#include <QTimerEvent> #include <QTimerEvent>
#include <QBrush> #include <QBrush>
#include "core/arraysize.h" #include "core/arraysize.h"
#include "core/logging.h" #include "core/logging.h"
using Analyzer::Scope; using Analyzer::Scope;
const int Rainbow::RainbowAnalyzer::kHeight[] = { 21, 33 }; const int Rainbow::RainbowAnalyzer::kHeight[] = {21, 33};
const int Rainbow::RainbowAnalyzer::kWidth[] = { 34, 53 }; const int Rainbow::RainbowAnalyzer::kWidth[] = {34, 53};
const int Rainbow::RainbowAnalyzer::kFrameCount[] = { 6, 16 }; const int Rainbow::RainbowAnalyzer::kFrameCount[] = {6, 16};
const int Rainbow::RainbowAnalyzer::kRainbowHeight[] = { 21, 16 }; const int Rainbow::RainbowAnalyzer::kRainbowHeight[] = {21, 16};
const int Rainbow::RainbowAnalyzer::kRainbowOverlap[] = { 13, 15 }; const int Rainbow::RainbowAnalyzer::kRainbowOverlap[] = {13, 15};
const int Rainbow::RainbowAnalyzer::kSleepingHeight[] = { 24, 33 }; const int Rainbow::RainbowAnalyzer::kSleepingHeight[] = {24, 33};
const char* Rainbow::NyanCatAnalyzer::kName = "Nyanalyzer Cat"; const char* Rainbow::NyanCatAnalyzer::kName = "Nyanalyzer Cat";
const char* Rainbow::RainbowDashAnalyzer::kName = "Rainbow Dash"; const char* Rainbow::RainbowDashAnalyzer::kName = "Rainbow Dash";
@ -46,7 +46,8 @@ const float Rainbow::RainbowAnalyzer::kPixelScale = 0.02f;
Rainbow::RainbowAnalyzer::RainbowType Rainbow::RainbowAnalyzer::rainbowtype; Rainbow::RainbowAnalyzer::RainbowType Rainbow::RainbowAnalyzer::rainbowtype;
Rainbow::RainbowAnalyzer::RainbowAnalyzer(const RainbowType& rbtype, QWidget* parent) Rainbow::RainbowAnalyzer::RainbowAnalyzer(const RainbowType& rbtype,
QWidget* parent)
: Analyzer::Base(parent, 9), : Analyzer::Base(parent, 9),
timer_id_(startTimer(kFrameIntervalMs)), timer_id_(startTimer(kFrameIntervalMs)),
frame_(0), frame_(0),
@ -62,7 +63,7 @@ Rainbow::RainbowAnalyzer::RainbowAnalyzer(const RainbowType& rbtype, QWidget* pa
for (int i = 0; i < kRainbowBands; ++i) { for (int i = 0; i < kRainbowBands; ++i) {
colors_[i] = QPen(QColor::fromHsv(i * 255 / kRainbowBands, 255, 255), colors_[i] = QPen(QColor::fromHsv(i * 255 / kRainbowBands, 255, 255),
kRainbowHeight[rainbowtype] / kRainbowBands, kRainbowHeight[rainbowtype] / kRainbowBands,
Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin); Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin);
// pow constants computed so that // pow constants computed so that
@ -72,7 +73,7 @@ Rainbow::RainbowAnalyzer::RainbowAnalyzer(const RainbowType& rbtype, QWidget* pa
} }
} }
void Rainbow::RainbowAnalyzer::transform(Scope& s) { fht_->spectrum(&s.front()); } void Rainbow::RainbowAnalyzer::transform(Scope& s) { fht_->spectrum(s.data()); }
void Rainbow::RainbowAnalyzer::timerEvent(QTimerEvent* e) { void Rainbow::RainbowAnalyzer::timerEvent(QTimerEvent* e) {
if (e->timerId() == timer_id_) { if (e->timerId() == timer_id_) {
@ -88,15 +89,15 @@ void Rainbow::RainbowAnalyzer::resizeEvent(QResizeEvent* e) {
buffer_[0] = QPixmap(); buffer_[0] = QPixmap();
buffer_[1] = QPixmap(); buffer_[1] = QPixmap();
available_rainbow_width_ = width() - kWidth[rainbowtype] available_rainbow_width_ =
+ kRainbowOverlap[rainbowtype]; width() - kWidth[rainbowtype] + kRainbowOverlap[rainbowtype];
px_per_frame_ = px_per_frame_ =
static_cast<float>(available_rainbow_width_) / (kHistorySize - 1) + 1; static_cast<float>(available_rainbow_width_) / (kHistorySize - 1) + 1;
x_offset_ = px_per_frame_ * (kHistorySize - 1) - available_rainbow_width_; x_offset_ = px_per_frame_ * (kHistorySize - 1) - available_rainbow_width_;
} }
void Rainbow::RainbowAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, void Rainbow::RainbowAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
bool new_frame) { bool new_frame) {
// Discard the second half of the transform // Discard the second half of the transform
const int scope_size = s.size() / 2; const int scope_size = s.size() / 2;
@ -129,15 +130,13 @@ void Rainbow::RainbowAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
QPointF* dest = polyline; QPointF* dest = polyline;
float* source = history_; float* source = history_;
const float top_of = const float top_of = static_cast<float>(height()) / 2 -
static_cast<float>(height()) / 2 - static_cast<float>( static_cast<float>(kRainbowHeight[rainbowtype]) / 2;
kRainbowHeight[rainbowtype]) / 2;
for (int band = 0; band < kRainbowBands; ++band) { for (int band = 0; band < kRainbowBands; ++band) {
// Calculate the Y position of this band. // Calculate the Y position of this band.
const float y = const float y = static_cast<float>(kRainbowHeight[rainbowtype]) /
static_cast<float>(kRainbowHeight[rainbowtype]) / ( (kRainbowBands + 1) * (band + 0.5) +
kRainbowBands + 1) * (band + 0.5) + top_of;
top_of;
// Add each point in the line. // Add each point in the line.
for (int x = 0; x < kHistorySize; ++x) { for (int x = 0; x < kHistorySize; ++x) {
@ -178,7 +177,7 @@ void Rainbow::RainbowAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
x_offset_ + available_rainbow_width_ - px_per_frame_, 0); x_offset_ + available_rainbow_width_ - px_per_frame_, 0);
buffer_painter.fillRect( buffer_painter.fillRect(
x_offset_ + available_rainbow_width_ - px_per_frame_, 0, x_offset_ + available_rainbow_width_ - px_per_frame_, 0,
kWidth[rainbowtype] - kRainbowOverlap[rainbowtype] + px_per_frame_, kWidth[rainbowtype] - kRainbowOverlap[rainbowtype] + px_per_frame_,
height(), background_brush_); height(), background_brush_);
for (int band = kRainbowBands - 1; band >= 0; --band) { for (int band = kRainbowBands - 1; band >= 0; --band) {
@ -196,18 +195,16 @@ void Rainbow::RainbowAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
// Nyan nyan nyan nyan dash dash dash dash. // Nyan nyan nyan nyan dash dash dash dash.
if (!is_playing_) { if (!is_playing_) {
// Ssshhh! // Ssshhh!
p.drawPixmap(SleepingDestRect(rainbowtype), cat_dash_[rainbowtype], p.drawPixmap(SleepingDestRect(rainbowtype), cat_dash_[rainbowtype],
SleepingSourceRect(rainbowtype)); SleepingSourceRect(rainbowtype));
} else { } else {
p.drawPixmap(DestRect(rainbowtype), cat_dash_[rainbowtype], p.drawPixmap(DestRect(rainbowtype), cat_dash_[rainbowtype],
SourceRect(rainbowtype)); SourceRect(rainbowtype));
} }
} }
Rainbow::NyanCatAnalyzer::NyanCatAnalyzer(QWidget* parent) Rainbow::NyanCatAnalyzer::NyanCatAnalyzer(QWidget* parent)
:RainbowAnalyzer(Rainbow::RainbowAnalyzer::Nyancat, parent) { : RainbowAnalyzer(Rainbow::RainbowAnalyzer::Nyancat, parent) {}
}
Rainbow::RainbowDashAnalyzer::RainbowDashAnalyzer(QWidget* parent) Rainbow::RainbowDashAnalyzer::RainbowDashAnalyzer(QWidget* parent)
:RainbowAnalyzer(Rainbow::RainbowAnalyzer::Dash, parent) { : RainbowAnalyzer(Rainbow::RainbowAnalyzer::Dash, parent) {}
}

View File

@ -114,9 +114,8 @@ void Sonogram::analyze(QPainter& p, const Scope& s, bool new_frame) {
} }
void Sonogram::transform(Scope& scope) { void Sonogram::transform(Scope& scope) {
float* front = static_cast<float*>(&scope.front()); fht_->power2(scope.data());
fht_->power2(front); fht_->scale(scope.data(), 1.0 / 256);
fht_->scale(front, 1.0 / 256);
scope.resize(fht_->size() / 2); scope.resize(fht_->size() / 2);
} }

View File

@ -40,7 +40,6 @@ void TurbineAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
return; return;
} }
float h;
const uint hd2 = height() / 2; const uint hd2 = height() / 2;
const uint kMaxHeight = hd2 - 1; const uint kMaxHeight = hd2 - 1;
@ -55,13 +54,10 @@ void TurbineAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
} }
for (uint i = 0, x = 0, y; i < bands_; ++i, x += kColumnWidth + 1) { for (uint i = 0, x = 0, y; i < bands_; ++i, x += kColumnWidth + 1) {
h = log10(scope_[i] * 256.0) * F_ * 0.5; float h = std::min(log10(scope_[i] * 256.0) * F_ * 0.5, kMaxHeight * 1.0);
if (h > kMaxHeight) h = kMaxHeight;
if (h > bar_height_[i]) { if (h > bar_height_[i]) {
bar_height_[i] = h; bar_height_[i] = h;
if (h > peak_height_[i]) { if (h > peak_height_[i]) {
peak_height_[i] = h; peak_height_[i] = h;
peak_speed_[i] = 0.01; peak_speed_[i] = 0.01;
@ -75,13 +71,11 @@ void TurbineAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
} }
peak_handling: peak_handling:
if (peak_height_[i] > 0.0) { if (peak_height_[i] > 0.0) {
peak_height_[i] -= peak_speed_[i]; peak_height_[i] -= peak_speed_[i];
peak_speed_[i] *= F_peakSpeed_; // 1.12 peak_speed_[i] *= F_peakSpeed_; // 1.12
peak_height_[i] =
if (peak_height_[i] < bar_height_[i]) peak_height_[i] = bar_height_[i]; std::max(0.0f, std::max(bar_height_[i], peak_height_[i]));
if (peak_height_[i] < 0.0) peak_height_[i] = 0.0;
} }
} }