From 6d888eb51aeeef2716b393110aaa6728b52b7b6a Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Sun, 30 Sep 2018 15:32:21 +0200 Subject: [PATCH] Analyzer code cleanup and try to fix crash on Fedora --- src/analyzer/analyzerbase.cpp | 86 ++++++++-------- src/analyzer/analyzerbase.h | 25 +++-- src/analyzer/blockanalyzer.cpp | 181 +++++++++++++++++---------------- src/analyzer/blockanalyzer.h | 26 ++--- 4 files changed, 160 insertions(+), 158 deletions(-) diff --git a/src/analyzer/analyzerbase.cpp b/src/analyzer/analyzerbase.cpp index bc70dd86f..5536e965b 100644 --- a/src/analyzer/analyzerbase.cpp +++ b/src/analyzer/analyzerbase.cpp @@ -27,14 +27,13 @@ #include "analyzerbase.h" +#include "core/logging.h" #include "engine/enginebase.h" // INSTRUCTIONS Base2D -// 1. do anything that depends on height() in init(), Base2D will call it before -// you are shown +// 1. do anything that depends on height() in init(), Base2D will call it before you are shown // 2. otherwise you can use the constructor to initialise things -// 3. reimplement analyze(), and paint to canvas(), Base2D will update the -// widget when you return control to it +// 3. reimplement analyze(), and paint to canvas(), Base2D will update the widget when you return control to it // 4. if you want to manipulate the scope, reimplement transform() // 5. for convenience are pre-included // TODO make an INSTRUCTIONS file @@ -50,37 +49,32 @@ template class Analyzer::Base; Analyzer::Base::Base(QWidget *parent, uint scopeSize) : QWidget(parent), - m_timeout(40) // msec - , - m_fht(new FHT(scopeSize)), - m_engine(nullptr), - m_lastScope(512), + timeout_(40), + fht_(new FHT(scopeSize)), + engine_(nullptr), + lastscope_(512), current_chunk_(0), new_frame_(false), is_playing_(false) {} -void Analyzer::Base::hideEvent(QHideEvent*) { m_timer.stop(); } +void Analyzer::Base::hideEvent(QHideEvent*) { timer_.stop(); } -void Analyzer::Base::showEvent(QShowEvent*) { m_timer.start(timeout(), this); } +void Analyzer::Base::showEvent(QShowEvent*) { timer_.start(timeout(), this); } -void Analyzer::Base::transform(Scope& scope) // virtual -{ +void Analyzer::Base::transform(Scope& scope) { - // this is a standard transformation that should give - // an FFT scope that has bands for pretty analyzers + // This is a standard transformation that should give an FFT scope that has bands for pretty analyzers - // NOTE resizing here is redundant as FHT routines only calculate FHT::size() - // values - // scope.resize( m_fht->size() ); + // NOTE: Resizing here is redundant as FHT routines only calculate FHT::size() values scope.resize( fht_->size() ); float *front = static_cast(&scope.front()); - float *f = new float[m_fht->size()]; - m_fht->copy(&f[0], front); - m_fht->logSpectrum(front, &f[0]); - m_fht->scale(front, 1.0 / 20); + float *f = new float[fht_->size()]; + fht_->copy(&f[0], front); + fht_->logSpectrum(front, &f[0]); + fht_->scale(front, 1.0 / 20); - scope.resize(m_fht->size() / 2); // second half of values are rubbish + scope.resize(fht_->size() / 2); // second half of values are rubbish delete[] f; } @@ -90,28 +84,28 @@ void Analyzer::Base::paintEvent(QPaintEvent *e) { QPainter p(this); p.fillRect(e->rect(), palette().color(QPalette::Window)); - switch (m_engine->state()) { + switch (engine_->state()) { case Engine::Playing: { - const Engine::Scope& thescope = m_engine->scope(m_timeout); + const Engine::Scope& thescope = engine_->scope(timeout_); int i = 0; // convert to mono here - our built in analyzers need mono, but the engines provide interleaved pcm - for (uint x = 0; (int)x < m_fht->size(); ++x) { - m_lastScope[x] = double(thescope[i] + thescope[i + 1]) / (2 * (1 << 15)); + for (uint x = 0; (int)x < fht_->size(); ++x) { + lastscope_[x] = double(thescope[i] + thescope[i + 1]) / (2 * (1 << 15)); i += 2; } is_playing_ = true; - transform(m_lastScope); - analyze(p, m_lastScope, new_frame_); + transform(lastscope_); + analyze(p, lastscope_, new_frame_); - // scope.resize( m_fht->size() ); + lastscope_.resize(fht_->size()); break; } case Engine::Paused: is_playing_ = false; - analyze(p, m_lastScope, new_frame_); + analyze(p, lastscope_, new_frame_); break; default: @@ -124,16 +118,18 @@ void Analyzer::Base::paintEvent(QPaintEvent *e) { } int Analyzer::Base::resizeExponent(int exp) { + if (exp < 3) exp = 3; else if (exp > 9) exp = 9; - if (exp != m_fht->sizeExp()) { - delete m_fht; - m_fht = new FHT(exp); + if (exp != fht_->sizeExp()) { + delete fht_; + fht_ = new FHT(exp); } return exp; + } int Analyzer::Base::resizeForBands(int bands) { @@ -153,12 +149,11 @@ int Analyzer::Base::resizeForBands(int bands) { exp = 9; resizeExponent(exp); - return m_fht->size() / 2; + return fht_->size() / 2; } -void Analyzer::Base::demo(QPainter& p) // virtual -{ +void Analyzer::Base::demo(QPainter& p) { static int t = 201; // FIXME make static to namespace perhaps @@ -171,7 +166,8 @@ void Analyzer::Base::demo(QPainter& p) // virtual s[i] = dt * (sin(M_PI + (i * M_PI) / s.size()) + 1.0); analyze(p, s, new_frame_); - } else + } + else analyze(p, Scope(32, 0), new_frame_); ++t; @@ -179,7 +175,7 @@ void Analyzer::Base::demo(QPainter& p) // virtual } void Analyzer::Base::polishEvent() { - init(); // virtual + init(); } void Analyzer::interpolate(const Scope& inVec, Scope& outVec) { @@ -189,13 +185,13 @@ void Analyzer::interpolate(const Scope& inVec, Scope& outVec) { for (uint i = 0; i < outVec.size(); ++i, pos += step) { const double error = pos - std::floor(pos); - const unsigned long offset = (unsigned long)pos; + const uint64_t offset = (uint64_t)pos; - unsigned long indexLeft = offset + 0; + uint64_t indexLeft = offset + 0; if (indexLeft >= inVec.size()) indexLeft = inVec.size() - 1; - unsigned long indexRight = offset + 1; + uint64_t indexRight = offset + 1; if (indexRight >= inVec.size()) indexRight = inVec.size() - 1; @@ -205,6 +201,7 @@ void Analyzer::interpolate(const Scope& inVec, Scope& outVec) { } void Analyzer::initSin(Scope& v, const uint size) { + double step = (M_PI * 2) / size; double radian = 0; @@ -212,12 +209,15 @@ void Analyzer::initSin(Scope& v, const uint size) { v.push_back(sin(radian)); radian += step; } + } void Analyzer::Base::timerEvent(QTimerEvent *e) { + QWidget::timerEvent(e); - if (e->timerId() != m_timer.timerId()) return; + if (e->timerId() != timer_.timerId()) return; new_frame_ = true; update(); + } diff --git a/src/analyzer/analyzerbase.h b/src/analyzer/analyzerbase.h index 2f4fe199f..2ec8354de 100644 --- a/src/analyzer/analyzerbase.h +++ b/src/analyzer/analyzerbase.h @@ -37,17 +37,17 @@ class Base : public QWidget { Q_OBJECT public: - ~Base() { delete m_fht; } + ~Base() { delete fht_; } - uint timeout() const { return m_timeout; } + uint timeout() const { return timeout_; } - void set_engine(EngineBase *engine) { m_engine = engine; } + void set_engine(EngineBase *engine) { engine_ = engine; } void changeTimeout(uint newTimeout) { - m_timeout = newTimeout; - if (m_timer.isActive()) { - m_timer.stop(); - m_timer.start(m_timeout, this); + timeout_ = newTimeout; + if (timer_.isActive()) { + timer_.stop(); + timer_.start(timeout_, this); } } @@ -71,13 +71,12 @@ class Base : public QWidget { virtual void demo(QPainter& p); protected: - QBasicTimer m_timer; - uint m_timeout; - FHT* m_fht; - EngineBase* m_engine; - Scope m_lastScope; + QBasicTimer timer_; + uint timeout_; + FHT *fht_; + EngineBase *engine_; + Scope lastscope_; int current_chunk_; - bool new_frame_; bool is_playing_; }; diff --git a/src/analyzer/blockanalyzer.cpp b/src/analyzer/blockanalyzer.cpp index 781e41a4e..32b308b10 100644 --- a/src/analyzer/blockanalyzer.cpp +++ b/src/analyzer/blockanalyzer.cpp @@ -26,109 +26,105 @@ const uint BlockAnalyzer::MIN_COLUMNS = 32; // arbituary const uint BlockAnalyzer::MAX_COLUMNS = 256; // must be 2**n const uint BlockAnalyzer::FADE_SIZE = 90; -const char *BlockAnalyzer::kName = - QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer"); +const char *BlockAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer"); BlockAnalyzer::BlockAnalyzer(QWidget *parent) : Analyzer::Base(parent, 9), - m_columns(0) // uint - , - m_rows(0) // uint - , - m_y(0) // uint - , - m_barPixmap(1, 1) // null qpixmaps cause crashes - , - m_topBarPixmap(WIDTH, HEIGHT), - m_scope(MIN_COLUMNS) // Scope - , - m_store(1 << 8, 0) // vector - , - m_fade_bars(FADE_SIZE) // vector - , - m_fade_pos(1 << 8, 50) // vector - , - m_fade_intensity(1 << 8, 32) // vector -{ + columns_(0), + rows_(0), + y_(0), + barpixmap_(1, 1), + topbarpixmap_(WIDTH, HEIGHT), + scope_(MIN_COLUMNS), + store_(1 << 8, 0), + fade_bars_(FADE_SIZE), + fade_pos_(1 << 8, 50), + fade_intensity_(1 << 8, 32) { + setMinimumSize(MIN_COLUMNS * (WIDTH + 1) - 1, MIN_ROWS * (HEIGHT + 1) - 1); //-1 is padding, no drawing takes place there setMaximumWidth(MAX_COLUMNS * (WIDTH + 1) - 1); // mxcl says null pixmaps cause crashes, so let's play it safe - for (uint i = 0; i < FADE_SIZE; ++i) m_fade_bars[i] = QPixmap(1, 1); + for (uint i = 0; i < FADE_SIZE; ++i) fade_bars_[i] = QPixmap(1, 1); + } BlockAnalyzer::~BlockAnalyzer() {} void BlockAnalyzer::resizeEvent(QResizeEvent *e) { + QWidget::resizeEvent(e); - m_background = QPixmap(size()); + background_ = QPixmap(size()); canvas_ = QPixmap(size()); - const uint oldRows = m_rows; + const uint oldRows = rows_; // all is explained in analyze().. //+1 to counter -1 in maxSizes, trust me we need this! - m_columns = qMax(uint(double(width() + 1) / (WIDTH + 1)), MAX_COLUMNS); - m_rows = uint(double(height() + 1) / (HEIGHT + 1)); + columns_ = qMax(uint(double(width() + 1) / (WIDTH + 1)), MAX_COLUMNS); + rows_ = uint(double(height() + 1) / (HEIGHT + 1)); // this is the y-offset for drawing from the top of the widget - m_y = (height() - (m_rows * (HEIGHT + 1)) + 2) / 2; + y_ = (height() - (rows_ * (HEIGHT + 1)) + 2) / 2; - m_scope.resize(m_columns); + scope_.resize(columns_); - if (m_rows != oldRows) { - m_barPixmap = QPixmap(WIDTH, m_rows * (HEIGHT + 1)); + if (rows_ != oldRows) { + barpixmap_ = QPixmap(WIDTH, rows_ * (HEIGHT + 1)); for (uint i = 0; i < FADE_SIZE; ++i) - m_fade_bars[i] = QPixmap(WIDTH, m_rows * (HEIGHT + 1)); + fade_bars_[i] = QPixmap(WIDTH, rows_ * (HEIGHT + 1)); - m_yscale.resize(m_rows + 1); + yscale_.resize(rows_ + 1); - const uint PRE = 1, - PRO = 1; // PRE and PRO allow us to restrict the range somewhat + const uint PRE = 1, PRO = 1; // PRE and PRO allow us to restrict the range somewhat - for (uint z = 0; z < m_rows; ++z) - m_yscale[z] = 1 - (log10(PRE + z) / log10(PRE + m_rows + PRO)); + for (uint z = 0; z < rows_; ++z) + yscale_[z] = 1 - (log10(PRE + z) / log10(PRE + rows_ + PRO)); - m_yscale[m_rows] = 0; + yscale_[rows_] = 0; determineStep(); paletteChange(palette()); } drawBackground(); + } void BlockAnalyzer::determineStep() { + // falltime is dependent on rowcount due to our digital resolution (ie we have boxes/blocks of pixels) // I calculated the value 30 based on some trial and error // the fall time of 30 is too slow on framerates above 50fps - const double fallTime = timeout() < 20 ? 20 * m_rows : 30 * m_rows; + const double fallTime = timeout() < 20 ? 20 * rows_ : 30 * rows_; + + step_ = double(rows_ * timeout()) / fallTime; - m_step = double(m_rows * timeout()) / fallTime; } -void BlockAnalyzer::framerateChanged() { // virtual +void BlockAnalyzer::framerateChanged() { determineStep(); } -void BlockAnalyzer::transform(Analyzer::Scope& s) // pure virtual -{ +void BlockAnalyzer::transform(Analyzer::Scope &s) { + for (uint x = 0; x < s.size(); ++x) s[x] *= 2; float* front = static_cast(&s.front()); - m_fht->spectrum(front); - m_fht->scale(front, 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 analyzer by setting to scope_.size() if large we prevent interpolation of large analyzers, this is good! + s.resize(scope_.size() <= MAX_COLUMNS / 2 ? MAX_COLUMNS / 2 : scope_.size()); - // the second half is pretty dull, so only show it if the user has a large analyzer by setting to m_scope.size() if large we prevent interpolation of large analyzers, this is good! - s.resize(m_scope.size() <= MAX_COLUMNS / 2 ? MAX_COLUMNS / 2 : m_scope.size()); } -void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, - bool new_frame) { +void BlockAnalyzer::analyze(QPainter &p, const Analyzer::Scope &s, bool new_frame) { + // y = 2 3 2 1 0 2 // . . . . # . // . . . # # . @@ -139,7 +135,7 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, // y represents the number of blanks // y starts from the top and increases in units of blocks - // m_yscale looks similar to: { 0.7, 0.5, 0.25, 0.15, 0.1, 0 } + // yscale_ looks similar to: { 0.7, 0.5, 0.25, 0.15, 0.1, 0 } // if it contains 6 elements there are 5 rows in the analyzer if (!new_frame) { @@ -149,50 +145,51 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, QPainter canvas_painter(&canvas_); - Analyzer::interpolate(s, m_scope); + Analyzer::interpolate(s, scope_); // Paint the background - canvas_painter.drawPixmap(0, 0, m_background); + canvas_painter.drawPixmap(0, 0, background_); - for (uint y, x = 0; x < m_scope.size(); ++x) { + for (uint y, x = 0; x < scope_.size(); ++x) { // determine y - for (y = 0; m_scope[x] < m_yscale[y]; ++y) - ; + for (y = 0; scope_[x] < yscale_[y]; ++y) continue; // this is opposite to what you'd think, higher than y means the bar is lower than y (physically) - if ((float)y > m_store[x]) - y = int(m_store[x] += m_step); + if ((float)y > store_[x]) + y = int(store_[x] += step_); else - m_store[x] = y; + store_[x] = y; - // if y is lower than m_fade_pos, then the bar has exceeded the height of the fadeout + // if y is lower than fade_pos_, then the bar has exceeded the height of the fadeout // if the fadeout is quite faded now, then display the new one - if (y <= m_fade_pos[x] /*|| m_fade_intensity[x] < FADE_SIZE / 3*/) { - m_fade_pos[x] = y; - m_fade_intensity[x] = FADE_SIZE; + if (y <= fade_pos_[x] /*|| fade_intensity_[x] < FADE_SIZE / 3*/) { + fade_pos_[x] = y; + fade_intensity_[x] = FADE_SIZE; } - if (m_fade_intensity[x] > 0) { - const uint offset = --m_fade_intensity[x]; - const uint y = m_y + (m_fade_pos[x] * (HEIGHT + 1)); - canvas_painter.drawPixmap(x * (WIDTH + 1), y, m_fade_bars[offset], 0, 0, WIDTH, height() - y); + if (fade_intensity_[x] > 0) { + const uint offset = --fade_intensity_[x]; + const uint y = y_ + (fade_pos_[x] * (HEIGHT + 1)); + canvas_painter.drawPixmap(x * (WIDTH + 1), y, fade_bars_[offset], 0, 0, WIDTH, height() - y); } - if (m_fade_intensity[x] == 0) m_fade_pos[x] = m_rows; + if (fade_intensity_[x] == 0) fade_pos_[x] = rows_; - // REMEMBER: y is a number from 0 to m_rows, 0 means all blocks are glowing, m_rows means none are - canvas_painter.drawPixmap(x * (WIDTH + 1), y * (HEIGHT + 1) + m_y, *bar(), + // REMEMBER: y is a number from 0 to rows_, 0 means all blocks are glowing, rows_ means none are + canvas_painter.drawPixmap(x * (WIDTH + 1), y * (HEIGHT + 1) + y_, *bar(), 0, y * (HEIGHT + 1), bar()->width(), bar()->height()); } - for (uint x = 0; x < m_store.size(); ++x) - canvas_painter.drawPixmap(x * (WIDTH + 1), int(m_store[x]) * (HEIGHT + 1) + m_y, m_topBarPixmap); + for (uint x = 0; x < store_.size(); ++x) + canvas_painter.drawPixmap(x * (WIDTH + 1), int(store_[x]) * (HEIGHT + 1) + y_, topbarpixmap_); p.drawPixmap(0, 0, canvas_); + } -static inline void adjustToLimits(int& b, int& f, uint& amount) { +static inline void adjustToLimits(int &b, int &f, uint &amount) { + // with a range of 0-255 and maximum adjustment of amount, maximise the difference between f and b if (b < f) { @@ -215,6 +212,7 @@ static inline void adjustToLimits(int& b, int& f, uint& amount) { f = 255; } } + } /** @@ -225,17 +223,18 @@ static inline void adjustToLimits(int& b, int& f, uint& amount) { * It won't modify the hue of fg unless absolutely necessary * @return the adjusted form of fg */ -QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) { +QColor ensureContrast(const QColor &bg, const QColor &fg, uint _amount = 150) { + class OutputOnExit { public: - OutputOnExit(const QColor& color) : c(color) {} + OutputOnExit(const QColor &color) : c(color) {} ~OutputOnExit() { int h, s, v; c.getHsv(&h, &s, &v); } private: - const QColor& c; + const QColor &c; }; // hack so I don't have to cast everywhere @@ -352,24 +351,25 @@ QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) { #undef amount // #undef STAMP + } -void BlockAnalyzer::paletteChange(const QPalette&) // virtual -{ +void BlockAnalyzer::paletteChange(const QPalette&) { + const QColor bg = palette().color(QPalette::Background); const QColor fg = ensureContrast(bg, palette().color(QPalette::Highlight)); - m_topBarPixmap.fill(fg); + topbarpixmap_.fill(fg); - const double dr = 15 * double(bg.red() - fg.red()) / (m_rows * 16); - const double dg = 15 * double(bg.green() - fg.green()) / (m_rows * 16); - const double db = 15 * double(bg.blue() - fg.blue()) / (m_rows * 16); + const double dr = 15 * double(bg.red() - fg.red()) / (rows_ * 16); + const double dg = 15 * double(bg.green() - fg.green()) / (rows_ * 16); + const double db = 15 * double(bg.blue() - fg.blue()) / (rows_ * 16); const int r = fg.red(), g = fg.green(), b = fg.blue(); bar()->fill(bg); QPainter p(bar()); - for (int y = 0; (uint)y < m_rows; ++y) + for (int y = 0; (uint)y < rows_; ++y) // graduate the fg color p.fillRect(0, y * (HEIGHT + 1), WIDTH, HEIGHT, QColor(r + int(dr * y), g + int(dg * y), b + int(db * y))); @@ -389,9 +389,9 @@ void BlockAnalyzer::paletteChange(const QPalette&) // virtual // Precalculate all fade-bar pixmaps for (uint y = 0; y < FADE_SIZE; ++y) { - m_fade_bars[y].fill(palette().color(QPalette::Background)); - QPainter f(&m_fade_bars[y]); - for (int z = 0; (uint)z < m_rows; ++z) { + fade_bars_[y].fill(palette().color(QPalette::Background)); + QPainter f(&fade_bars_[y]); + for (int z = 0; (uint)z < rows_; ++z) { const double Y = 1.0 - (log10(FADE_SIZE - y) / log10(FADE_SIZE)); f.fillRect(0, z * (HEIGHT + 1), WIDTH, HEIGHT, QColor(r + int(dr * Y), g + int(dg * Y), b + int(db * Y))); } @@ -399,16 +399,19 @@ void BlockAnalyzer::paletteChange(const QPalette&) // virtual } drawBackground(); + } void BlockAnalyzer::drawBackground() { + const QColor bg = palette().color(QPalette::Background); const QColor bgdark = bg.dark(112); - m_background.fill(bg); + background_.fill(bg); + + QPainter p(&background_); + for (int x = 0; (uint)x < columns_; ++x) + for (int y = 0; (uint)y < rows_; ++y) + p.fillRect(x * (WIDTH + 1), y * (HEIGHT + 1) + y_, WIDTH, HEIGHT, bgdark); - QPainter p(&m_background); - for (int x = 0; (uint)x < m_columns; ++x) - for (int y = 0; (uint)y < m_rows; ++y) - p.fillRect(x * (WIDTH + 1), y * (HEIGHT + 1) + m_y, WIDTH, HEIGHT, bgdark); } diff --git a/src/analyzer/blockanalyzer.h b/src/analyzer/blockanalyzer.h index e77bf72d9..be4dfe33b 100644 --- a/src/analyzer/blockanalyzer.h +++ b/src/analyzer/blockanalyzer.h @@ -51,24 +51,24 @@ class BlockAnalyzer : public Analyzer::Base { void determineStep(); private: - QPixmap* bar() { return &m_barPixmap; } + QPixmap *bar() { return &barpixmap_; } - uint m_columns, m_rows; // number of rows and columns of blocks - uint m_y; // y-offset from top of widget - QPixmap m_barPixmap; - QPixmap m_topBarPixmap; - QPixmap m_background; + uint columns_, rows_; // number of rows and columns of blocks + uint y_; // y-offset from top of widget + QPixmap barpixmap_; + QPixmap topbarpixmap_; + QPixmap background_; QPixmap canvas_; - Analyzer::Scope m_scope; // so we don't create a vector every frame - std::vector m_store; // current bar heights - std::vector m_yscale; + Analyzer::Scope scope_; // so we don't create a vector every frame + std::vector store_; // current bar heights + std::vector yscale_; // FIXME why can't I namespace these? c++ issue? - std::vector m_fade_bars; - std::vector m_fade_pos; - std::vector m_fade_intensity; + std::vector fade_bars_; + std::vector fade_pos_; + std::vector fade_intensity_; - float m_step; // rows to fall per frame + float step_; // rows to fall per frame }; #endif