2014-11-29 20:07:01 +01:00
|
|
|
/* This file is part of Clementine.
|
|
|
|
Copyright 2003-2005, Max Howell <max.howell@methylblue.com>
|
|
|
|
Copyright 2005, Mark Kretschmann <markey@web.de>
|
|
|
|
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
|
|
|
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
2014-11-29 20:07:01 +01:00
|
|
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
2022-08-18 23:23:59 +02:00
|
|
|
Copyright 2022, Andrew Reading <andrew@areading.me>
|
2014-11-29 20:07:01 +01:00
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Original Author: Max Howell <max.howell@methylblue.com> 2003-2005
|
|
|
|
* Original Author: Mark Kretschmann <markey@web.de> 2005
|
|
|
|
*/
|
2009-12-24 20:16:07 +01:00
|
|
|
|
|
|
|
#include "blockanalyzer.h"
|
|
|
|
|
|
|
|
#include <QMouseEvent>
|
2020-09-18 16:15:19 +02:00
|
|
|
#include <QPainter>
|
2009-12-24 20:16:07 +01:00
|
|
|
#include <QResizeEvent>
|
2020-09-18 16:15:19 +02:00
|
|
|
#include <cmath>
|
2009-12-24 20:16:07 +01:00
|
|
|
#include <cstdlib>
|
|
|
|
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
const uint BlockAnalyzer::kHeight = 2;
|
|
|
|
const uint BlockAnalyzer::kWidth = 4;
|
2022-08-18 23:23:59 +02:00
|
|
|
const uint BlockAnalyzer::kMinRows = 3; // arbitrary
|
|
|
|
const uint BlockAnalyzer::kMaxRows = 256; // arbitrary
|
|
|
|
const uint BlockAnalyzer::kMinColumns = 32; // arbitrary
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
const uint BlockAnalyzer::kMaxColumns = 256; // must be 2**n
|
|
|
|
const uint BlockAnalyzer::kFadeSize = 90;
|
2022-08-18 23:23:59 +02:00
|
|
|
const uint BlockAnalyzer::kFadeInitial = 32;
|
2014-02-07 16:34:20 +01:00
|
|
|
|
|
|
|
const char* BlockAnalyzer::kName =
|
|
|
|
QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
|
|
|
|
|
|
|
|
BlockAnalyzer::BlockAnalyzer(QWidget* parent)
|
|
|
|
: Analyzer::Base(parent, 9),
|
2022-08-18 23:23:59 +02:00
|
|
|
scope_(kMinColumns),
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
columns_(0),
|
|
|
|
rows_(0),
|
|
|
|
y_(0),
|
2022-08-18 23:23:59 +02:00
|
|
|
canvas_(),
|
|
|
|
rthresh_(kMaxRows + 1, 0.f),
|
|
|
|
bg_grad_(kMaxRows + 1, 0),
|
|
|
|
fade_bars_(kFadeSize, 0),
|
|
|
|
bandinfo_(kMaxColumns) {
|
|
|
|
// Right and bottom edges are 1px padding.
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
setMinimumSize(kMinColumns * (kWidth + 1) - 1, kMinRows * (kHeight + 1) - 1);
|
|
|
|
setMaximumWidth(kMaxColumns * (kWidth + 1) - 1);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
BlockAnalyzer::~BlockAnalyzer() {}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void BlockAnalyzer::resizeEvent(QResizeEvent* e) {
|
|
|
|
QWidget::resizeEvent(e);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
uint newRows, newCols;
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// all is explained in analyze()..
|
2014-11-29 20:07:01 +01:00
|
|
|
// +1 to counter -1 in maxSizes, trust me we need this!
|
2022-08-18 23:23:59 +02:00
|
|
|
newCols = 1 + (width() + 1) / (kWidth + 1);
|
|
|
|
newRows = 0 + (height() + 1) / (kHeight + 1);
|
|
|
|
newCols = qMin(kMaxColumns, qMax(kMinColumns, newCols));
|
|
|
|
newRows = qMin(kMaxRows, qMax(kMinRows, newRows));
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
if (newCols != columns_) {
|
|
|
|
columns_ = newCols;
|
|
|
|
scope_.resize(columns_);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
updateBandSize(columns_);
|
|
|
|
bandinfo_.fill(FHTBand());
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
if (rows_ != newRows) {
|
|
|
|
rows_ = newRows;
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// this is the y-offset for drawing from the top of the widget
|
|
|
|
y_ = (height() - (rows_ * (kHeight + 1)) + 2) / 2;
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
const float PRE = 1.f,
|
|
|
|
PRO =
|
|
|
|
1.f, // PRE and PRO allow us to restrict the range somewhat
|
|
|
|
SCL = log10f(PRE + PRO + (1.f * rows_));
|
2009-12-24 20:16:07 +01:00
|
|
|
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
for (uint z = 0; z < rows_; ++z)
|
2022-08-18 23:23:59 +02:00
|
|
|
rthresh_[z] = 1.f - log10f(PRE + (1.f * z)) / SCL;
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
rthresh_[rows_] = 0.f;
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
determineStep();
|
|
|
|
paletteChange(palette());
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
canvas_ = QImage(columns_ * (kWidth + 1), rows_ * (kHeight + 1),
|
|
|
|
QImage::Format_ARGB32_Premultiplied);
|
|
|
|
canvas_.fill(pad_color_);
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void BlockAnalyzer::determineStep() {
|
2022-08-18 23:23:59 +02:00
|
|
|
// falltime is dependent on rowcount
|
2014-05-13 00:15:00 +02:00
|
|
|
// the fall time of 30 is too slow on framerates above 50fps
|
2022-08-18 23:23:59 +02:00
|
|
|
const float rFallTime = 1.f / (timeout() < 20 ? 20.f : 30.f);
|
|
|
|
step_ = timeout() * rFallTime;
|
2010-08-28 20:48:16 +02:00
|
|
|
}
|
|
|
|
|
2014-05-13 22:43:46 +02:00
|
|
|
void BlockAnalyzer::framerateChanged() { // virtual
|
|
|
|
determineStep();
|
|
|
|
}
|
|
|
|
|
2014-11-29 20:07:01 +01:00
|
|
|
void BlockAnalyzer::transform(Analyzer::Scope& s) {
|
2022-08-18 23:23:59 +02:00
|
|
|
for (uint x = 0; x < s.size(); ++x) s[x] *= 2.f;
|
2010-08-28 20:48:16 +02:00
|
|
|
|
2017-03-11 18:14:11 +01:00
|
|
|
fht_->spectrum(s.data());
|
2022-08-18 23:23:59 +02:00
|
|
|
fht_->scale(s.data(), 1.f / 20.f);
|
2010-08-28 20:48:16 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// the second half is pretty dull, so only show it if the user has a large
|
|
|
|
// analyzer
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
// by setting to scope_.size() if large we prevent interpolation of large
|
2014-02-07 16:34:20 +01:00
|
|
|
// analyzers, this is good!
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
s.resize(scope_.size() <= kMaxColumns / 2 ? kMaxColumns / 2 : scope_.size());
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
|
|
|
|
bool new_frame) {
|
2022-08-18 23:23:59 +02:00
|
|
|
float yf;
|
|
|
|
uint x, y;
|
|
|
|
|
|
|
|
if (p.paintEngine() == 0) return;
|
|
|
|
if (canvas_.isNull()) return;
|
2014-02-07 16:34:20 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
p.setCompositionMode(QPainter::CompositionMode_Source);
|
2014-02-07 16:34:20 +01:00
|
|
|
|
2014-04-27 07:54:42 +02:00
|
|
|
if (!new_frame) {
|
2022-08-18 23:23:59 +02:00
|
|
|
p.drawImage(0, 0, canvas_, 0, 0, width(), height(), Qt::NoFormatConversion);
|
2014-04-27 07:54:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
Analyzer::interpolate(s, scope_);
|
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// Update the color palettes.
|
|
|
|
if (psychedelic_enabled_) paletteChange(QPalette());
|
2014-02-07 16:34:20 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// Visual Aid
|
|
|
|
//
|
|
|
|
// This analyzer maintains a list of intensity thresholds for each row of
|
|
|
|
// the analyzer. For each frequency band (represented column-wise, one per
|
|
|
|
// band), the spectral power calculation obtained from the analyzer scope
|
|
|
|
// output is compared against these thresholds to determine the row indices
|
|
|
|
// at which the regions become active. While inactive regions are dark,
|
|
|
|
// active regions and all those below the corresponding transition region
|
|
|
|
// are "lit up".
|
|
|
|
//
|
|
|
|
// So, where
|
|
|
|
// . indicates block is inactive/dark
|
|
|
|
// # indicates block is active /lit,
|
|
|
|
// what is drawn is (for example)
|
|
|
|
//
|
|
|
|
// COLUMNS/Bands
|
|
|
|
// . . . . # . R
|
|
|
|
// . . . # # . O
|
|
|
|
// # . # # # # W
|
|
|
|
// # # # # # # S
|
|
|
|
//
|
|
|
|
// y = 2 3 2 1 0 2
|
|
|
|
//
|
|
|
|
// Here y is the row index for which the intensity threshold is met, with
|
|
|
|
// 0 indicating the topmost row. The nRows+1 intensity values are stored
|
|
|
|
// in rthresh_[], sorted in decreasing order (the top, y=0 region would
|
|
|
|
// be the most spectrally intense); the additional, final value is always
|
|
|
|
// zero and exists mostly as a sort of loop optimization.
|
|
|
|
//
|
|
|
|
// For the above illustration, rthresh_[] might have values similar to
|
|
|
|
// { 0.7, 0.5, 0.25, 0.15, 0.1, 0 }
|
|
|
|
//
|
|
|
|
// Now, consider two "frames" that occur sequentially after each other. Where
|
|
|
|
// . indicates block is inactive/dark
|
|
|
|
// o indicates block is inactive/dark and fading out (was active)
|
|
|
|
// # indicates block is active /lit,
|
|
|
|
// [ ] indicates block is the bar topper
|
|
|
|
//
|
|
|
|
// frame 1 ====> frame 2
|
|
|
|
// COLUMNS/Bands COLUMNS/Bands
|
|
|
|
// . . . . [#] . R . . . . o .
|
|
|
|
// . . . [#] # . O . . [#] o [#] .
|
|
|
|
// [#] . [#] # # [#] W o . # o # [#]
|
|
|
|
// # [#] # # # # S [#] o # [#] # #
|
|
|
|
//
|
|
|
|
// 2 3 2 1 0 2 = B_y = 3 4 1 1 1 2
|
|
|
|
//
|
|
|
|
// After a previously active region becomes inactive, for a period of time
|
|
|
|
// it is drawn in a color that darkens over time. These are based upon the
|
|
|
|
// the current color scheme and get stored within fade_bars_[].
|
|
|
|
// Additionally, a rowwise gradient is applied to active bands to help keep
|
|
|
|
// the spectrum display visually interesting, with colors darkening as
|
|
|
|
// intensities decrease -- that is, as rthresh_[] values decrease. The
|
|
|
|
// inactive-active transition area is drawn with the brightest color and
|
|
|
|
// acts as a "bar topper"; this topper should visually rise and fall over
|
|
|
|
// time.
|
|
|
|
//
|
|
|
|
// As in the transition example above, bands (columns) are drawn vertically
|
|
|
|
// from top to bottom, progressing from left to right. Supposing Y_r is the
|
|
|
|
// row coordinate, B_y is the band coordinate, and
|
|
|
|
// 0 <= Y_r,B_y < nRows <= kMaxRows,
|
|
|
|
// the drawing procedure for each band can be described as follows:
|
|
|
|
// a. Y_r < B_y
|
|
|
|
// First the '.' regions that have not been recently active are
|
|
|
|
// darkened (background). This is determined via the band's
|
|
|
|
// fade_intensity and fade_row values.
|
|
|
|
// b. Y_r < B_y
|
|
|
|
// Recently active areas are drawn using a special darkening-fade
|
|
|
|
// color, until either some number of frames have elapsed or they
|
|
|
|
// became active since the countdown began.
|
|
|
|
// c. Y_r = B_y
|
|
|
|
// The transition region is drawn as a bar topper.
|
|
|
|
// d. Y_r > B_y < nRows
|
|
|
|
// Each subsequent region below the transition region should be active.
|
|
|
|
// Draw these using a gradient that darkens as Y_r -> nRows.
|
|
|
|
// The logic for these can be found in the colorFromRowAndBand() function.
|
|
|
|
//
|
2014-02-07 16:34:20 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// Update band information.
|
|
|
|
for (x = 0; x < scope_.size(); ++x) {
|
|
|
|
const float& bandthr = scope_[x];
|
|
|
|
FHTBand& band = bandinfo_[x];
|
2014-02-07 16:34:20 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// Calculate activity transition row values.
|
|
|
|
// Note: rows_ < rthresh_.size()
|
|
|
|
for (y = 0; y < rows_; ++y) {
|
|
|
|
if (bandthr >= rthresh_[y]) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// y <= band height :: band matches or exceeds power from last frame.
|
|
|
|
// y > band height :: band lost power since last frame.
|
|
|
|
if ((yf = 1.f * y) <= band.height) {
|
|
|
|
band.height = yf;
|
|
|
|
band.row = y;
|
|
|
|
} else {
|
|
|
|
// This band has lost power since the last-recorded maximal threshold
|
|
|
|
// value. Gradually decrease this until it meets the current value.
|
|
|
|
band.height += step_;
|
|
|
|
band.row = y = static_cast<uint>(band.height);
|
2014-02-07 16:34:20 +01:00
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// y <= band fade_row :: the current threshold exceeds the previously-
|
|
|
|
// marked position in which to begin fade-out. Use the current position
|
|
|
|
// as a new marker and start/restart fade_intensity, the fade-out period
|
|
|
|
// counter.
|
|
|
|
if (y <= band.fade_row) {
|
|
|
|
band.fade_row = y;
|
|
|
|
band.fade_intensity = kFadeSize;
|
2014-02-07 16:34:20 +01:00
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// Check the fade-out period counter. If expired (i.e., <= 0), the
|
|
|
|
// fade-out effect is complete. Otherwise, continue downcounting and
|
|
|
|
// select the next color for the fade-out sequence.
|
|
|
|
if (band.fade_intensity <= 0) {
|
|
|
|
// fade_intensity <= 0: Done with fade out effect (time expired).
|
|
|
|
band.fade_row = rows_;
|
|
|
|
band.fade_coloridx = 0;
|
|
|
|
} else {
|
|
|
|
// fade_intensity > 0: Continue effect; continue color change.
|
|
|
|
band.fade_coloridx = --band.fade_intensity;
|
|
|
|
}
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// A block will be drawn and colored according to each band (column) of
|
|
|
|
// the FHT spectrum data. This block is a kWidth x kHeight region, along
|
|
|
|
// with 1-px of padding on its right and bottom.
|
|
|
|
//
|
|
|
|
// Conditional (FHTBand) Block State / Color
|
|
|
|
// ===================== ===================
|
|
|
|
// 0 < y < fade_row & fade-out : Inactive / BG color
|
|
|
|
// fade_row < y < row & fade-out : Fade-out / darkening
|
|
|
|
// 0 < y < row & no fade-out : Inactive / BG color
|
|
|
|
// row == y : Threshold / FG color
|
|
|
|
// row < y < rows_ : Active / Vert. gradient
|
|
|
|
// {1-px padding region} : Padding / Pad color
|
|
|
|
//
|
|
|
|
|
|
|
|
//
|
|
|
|
// Paint the canvas in one go in order to mimize cache thrashing.
|
|
|
|
//
|
|
|
|
QRgb* line; // Current scanline.
|
|
|
|
uint px_w, px_h; // Current width and height in pixels (just to avoid cast).
|
|
|
|
uint to_x; // [0, width()) Current and ending x pixel coordinate.
|
|
|
|
uint to_y; // [0, height()) Current and ending y pixel coordinate.
|
|
|
|
uint blk_r; // [0, rows_) Current block's row.
|
|
|
|
uint blk_c; // [0, columns_) Current block's column.
|
|
|
|
|
|
|
|
quint32 padcolor = pad_color_.rgba();
|
|
|
|
quint32 blkcolor;
|
|
|
|
|
|
|
|
px_w = static_cast<uint>(width());
|
|
|
|
px_h = static_cast<uint>(height());
|
|
|
|
|
|
|
|
// Draw empty top padding, if needed (when y_ > 0. weird window size?).
|
|
|
|
for (y = 0; y < y_; ++y) {
|
|
|
|
line = reinterpret_cast<QRgb*>(canvas_.scanLine(y));
|
|
|
|
for (x = 0; x < px_w; line[x++] = padcolor)
|
|
|
|
;
|
2014-02-07 16:34:20 +01:00
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// Draw the texture in one shot, iterating in a row-major fashion.
|
|
|
|
for (blk_r = 0; blk_r < rows_; ++blk_r) {
|
|
|
|
to_y = qMin(y + kHeight, px_h);
|
2014-04-27 07:54:42 +02:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// This block may take several 1-px high scanlines. Each column needs
|
|
|
|
// to be filled accordingly for each of these rows.
|
|
|
|
for (; y < to_y; ++y) {
|
|
|
|
line = reinterpret_cast<QRgb*>(canvas_.scanLine(y));
|
|
|
|
|
|
|
|
for (x = 0, blk_c = 0; blk_c < columns_; ++blk_c) {
|
|
|
|
to_x = qMin(x + kWidth, px_w);
|
|
|
|
|
|
|
|
// Draw [x, to_x], then padding on the right.
|
|
|
|
blkcolor = colorFromRowAndBand(blk_r, bandinfo_[blk_c]);
|
|
|
|
|
|
|
|
for (; x < to_x; line[x++] = blkcolor)
|
|
|
|
;
|
|
|
|
if (x < px_w) line[x++] = padcolor;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If extra space remains in line, fill to the right edge.
|
|
|
|
for (; x < px_w; line[x++] = padcolor)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw a full line of padding below the just-drawn region (if in bounds).
|
|
|
|
if (y < px_h) {
|
|
|
|
line = reinterpret_cast<QRgb*>(canvas_.scanLine(y++));
|
|
|
|
for (x = 0; x < px_w; line[x++] = padcolor)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If not at bottom boundary yet, pad remaining lines.
|
|
|
|
while (y < px_h) {
|
|
|
|
line = reinterpret_cast<QRgb*>(canvas_.scanLine(y++));
|
|
|
|
for (x = 0; x < px_w; line[x++] = padcolor)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
p.drawImage(0, 0, canvas_, 0, 0, width(), height(), Qt::NoFormatConversion);
|
2010-08-18 20:21:30 +02:00
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
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) {
|
|
|
|
if (b > 255 - f) {
|
|
|
|
amount -= f;
|
|
|
|
f = 0;
|
|
|
|
} else {
|
|
|
|
amount -= (255 - f);
|
|
|
|
f = 255;
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
2014-02-07 16:34:20 +01:00
|
|
|
} else {
|
|
|
|
if (f > 255 - b) {
|
|
|
|
amount -= f;
|
|
|
|
f = 0;
|
|
|
|
} else {
|
|
|
|
amount -= (255 - f);
|
|
|
|
f = 255;
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
2014-02-07 16:34:20 +01:00
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
void BlockAnalyzer::psychedelicModeChanged(bool enabled) {
|
|
|
|
psychedelic_enabled_ = enabled;
|
|
|
|
// reset colours back to normal
|
|
|
|
paletteChange(QPalette());
|
|
|
|
}
|
|
|
|
|
2009-12-24 20:16:07 +01:00
|
|
|
/**
|
|
|
|
* Clever contrast function
|
|
|
|
*
|
2014-02-07 16:34:20 +01:00
|
|
|
* It will try to adjust the foreground color such that it contrasts well with
|
|
|
|
*the background
|
2009-12-24 20:16:07 +01:00
|
|
|
* It won't modify the hue of fg unless absolutely necessary
|
|
|
|
* @return the adjusted form of fg
|
|
|
|
*/
|
2022-08-18 23:23:59 +02:00
|
|
|
static QColor ensureContrast(const QColor& bg, const QColor& fg,
|
|
|
|
uint _amount = 150) {
|
2014-02-07 16:34:20 +01:00
|
|
|
class OutputOnExit {
|
|
|
|
public:
|
2014-11-29 20:07:01 +01:00
|
|
|
explicit OutputOnExit(const QColor& color) : c(color) {}
|
2014-02-07 16:34:20 +01:00
|
|
|
~OutputOnExit() {
|
|
|
|
int h, s, v;
|
|
|
|
c.getHsv(&h, &s, &v);
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
private:
|
|
|
|
const QColor& c;
|
|
|
|
};
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
OutputOnExit allocateOnTheStack(fg);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
int bh, bs, bv;
|
|
|
|
int fh, fs, fv;
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bg.getHsv(&bh, &bs, &bv);
|
|
|
|
fg.getHsv(&fh, &fs, &fv);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
int dv = abs(bv - fv);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// value is the best measure of contrast
|
|
|
|
// if there is enough difference in value already, return fg unchanged
|
2014-11-29 20:07:01 +01:00
|
|
|
if (dv > static_cast<int>(_amount)) return fg;
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
int ds = abs(bs - fs);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// saturation is good enough too. But not as good. TODO adapt this a little
|
2014-11-29 20:07:01 +01:00
|
|
|
if (ds > static_cast<int>(_amount)) return fg;
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
int dh = abs(bh - fh);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (dh > 120) {
|
2019-08-22 05:43:16 +02:00
|
|
|
// a third of the colour wheel automatically guarantees contrast
|
2014-02-07 16:34:20 +01:00
|
|
|
// but only if the values are high enough and saturations significant enough
|
|
|
|
// to allow the colours to be visible and not be shades of grey or black
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// check the saturation for the two colours is sufficient that hue alone can
|
|
|
|
// provide sufficient contrast
|
2014-11-29 20:07:01 +01:00
|
|
|
if (ds > static_cast<int>(_amount) / 2 && (bs > 125 && fs > 125))
|
2014-02-07 16:34:20 +01:00
|
|
|
return fg;
|
2014-11-29 20:07:01 +01:00
|
|
|
else if (dv > static_cast<int>(_amount) / 2 && (bv > 125 && fv > 125))
|
2014-02-07 16:34:20 +01:00
|
|
|
return fg;
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (fs < 50 && ds < 40) {
|
|
|
|
// low saturation on a low saturation is sad
|
|
|
|
const int tmp = 50 - fs;
|
|
|
|
fs = 50;
|
2014-11-29 20:07:01 +01:00
|
|
|
if (static_cast<int>(_amount) > tmp)
|
2014-02-07 16:34:20 +01:00
|
|
|
_amount -= tmp;
|
|
|
|
else
|
|
|
|
_amount = 0;
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// test that there is available value to honor our contrast requirement
|
2014-11-29 20:07:01 +01:00
|
|
|
if (255 - dv < static_cast<int>(_amount)) {
|
2014-02-07 16:34:20 +01:00
|
|
|
// we have to modify the value and saturation of fg
|
|
|
|
// adjustToLimits( bv, fv, amount );
|
|
|
|
// see if we need to adjust the saturation
|
2014-11-29 20:07:01 +01:00
|
|
|
if (static_cast<int>(_amount) > 0) adjustToLimits(bs, fs, _amount);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// see if we need to adjust the hue
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
if (static_cast<int>(_amount) > 0)
|
|
|
|
fh += static_cast<int>(_amount); // cycles around;
|
2014-02-07 16:34:20 +01:00
|
|
|
|
|
|
|
return QColor::fromHsv(fh, fs, fv);
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-11-29 20:07:01 +01:00
|
|
|
if (fv > bv && bv > static_cast<int>(_amount))
|
|
|
|
return QColor::fromHsv(fh, fs, bv - static_cast<int>(_amount));
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-11-29 20:07:01 +01:00
|
|
|
if (fv < bv && fv > static_cast<int>(_amount))
|
|
|
|
return QColor::fromHsv(fh, fs, fv - static_cast<int>(_amount));
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-11-29 20:07:01 +01:00
|
|
|
if (fv > bv && (255 - fv > static_cast<int>(_amount)))
|
|
|
|
return QColor::fromHsv(fh, fs, fv + static_cast<int>(_amount));
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-11-29 20:07:01 +01:00
|
|
|
if (fv < bv && (255 - bv > static_cast<int>(_amount)))
|
|
|
|
return QColor::fromHsv(fh, fs, bv + static_cast<int>(_amount));
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
return Qt::blue;
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-11-29 20:07:01 +01:00
|
|
|
void BlockAnalyzer::paletteChange(const QPalette&) {
|
2022-08-18 23:23:59 +02:00
|
|
|
QColor bg, bgdark, fg;
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
bg = palette().color(QPalette::Background);
|
|
|
|
bgdark = bg.darker(112);
|
|
|
|
|
|
|
|
if (psychedelic_enabled_)
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
fg = getPsychedelicColor(scope_, 10, 75);
|
2022-08-18 23:23:59 +02:00
|
|
|
else
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
fg = ensureContrast(bg, palette().color(QPalette::Highlight));
|
2014-02-07 16:34:20 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
fg_color_ = fg;
|
|
|
|
bg_color_ = bgdark;
|
|
|
|
pad_color_ = bg;
|
2014-02-07 16:34:20 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// Calculate background gradient colors.
|
2014-02-07 16:34:20 +01:00
|
|
|
{
|
2022-08-18 23:23:59 +02:00
|
|
|
const float dr = 15.f * (bg.red() - fg.red()) / (16.f * rows_);
|
|
|
|
const float dg = 15.f * (bg.green() - fg.green()) / (16.f * rows_);
|
|
|
|
const float db = 15.f * (bg.blue() - fg.blue()) / (16.f * rows_);
|
|
|
|
|
|
|
|
for (uint y = 0; y < rows_; ++y) {
|
|
|
|
bg_grad_[y] = qRgba(fg.red() + static_cast<int>(dr * y),
|
|
|
|
fg.green() + static_cast<int>(dg * y),
|
|
|
|
fg.blue() + static_cast<int>(db * y), 255);
|
2014-02-07 16:34:20 +01:00
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
bg_grad_[rows_] = bg.rgba();
|
2017-03-27 13:57:24 +02:00
|
|
|
}
|
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
// make a complimentary fadebar colour
|
|
|
|
// TODO(John Maguire): dark is not always correct, dumbo!
|
|
|
|
{
|
|
|
|
int h, s, v;
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
bg.darker(150).getHsv(&h, &s, &v);
|
|
|
|
fg = QColor::fromHsv(h + 120, s, v);
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
const float r = 1.f * bgdark.red();
|
|
|
|
const float g = 1.f * bgdark.green();
|
|
|
|
const float b = 1.f * bgdark.blue();
|
|
|
|
const float dr = 1.f * fg.red() - r;
|
|
|
|
const float dg = 1.f * fg.green() - g;
|
|
|
|
const float db = 1.f * fg.blue() - b;
|
Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.)
I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do.
I find this gives the analyzer a sort of "third dimention".
This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion.
This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default.
I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
2015-07-01 17:48:03 +02:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
const float fFscl = 1. * kFadeSize;
|
|
|
|
const float frlogFscl = 1.f / log10f(fFscl);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2022-08-18 23:23:59 +02:00
|
|
|
for (uint y = 0; y < kFadeSize; ++y) {
|
|
|
|
const float lrY = 1.f - (frlogFscl * log10f(fFscl - y));
|
|
|
|
fade_bars_[y] =
|
|
|
|
qRgba(static_cast<int>(r + lrY * dr), static_cast<int>(g + lrY * dg),
|
|
|
|
static_cast<int>(b + lrY * db), 255);
|
|
|
|
}
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|