* (at your option) any later version. *
***************************************************************************/
-#include <QDebug>
-#include <QTime>
-#include <QColor>
+#include <cmath>
+
+#include <QImage>
#include <QPainter>
+#include <QSize>
+#include <QTime>
#include "waveformgenerator.h"
{
}
-QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QImage &image, const bool &drawAxis, const uint &accelFactor)
+QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QImage &image, WaveformGenerator::PaintMode paintMode,
+ bool drawAxis, WaveformGenerator::Rec rec, uint accelFactor)
{
Q_ASSERT(accelFactor >= 1);
- QTime time;
- time.start();
+ //QTime time;
+ //time.start();
QImage wave(waveformSize, QImage::Format_ARGB32);
- if (waveformSize.width() <= 0 || waveformSize.height() <= 0) {
- qCritical("Waveform size should not be 0.");
+ if (waveformSize.width() <= 0 || waveformSize.height() <= 0 || image.width() <= 0 || image.height() <= 0) {
+ return QImage();
} else {
- qDebug() << "Waveform calculation started.";
-
// Fill with transparent color
wave.fill(qRgba(0,0,0,0));
QRgb *col;
- QRgb waveCol;
- QPoint wavePoint;
double dY, dx, dy;
const uint ih = image.height();
const uint byteCount = iw*ih;
+ uint waveValues[waveformSize.width()][waveformSize.height()];
+ for (int i = 0; i < waveformSize.width(); ++i) {
+ for (int j = 0; j < waveformSize.height(); j++) {
+ waveValues[i][j] = 0;
+ }
+ }
+
+ // Number of input pixels that will fall on one scope pixel.
+ // Must be a float because the acceleration factor can be high, leading to <1 expected px per px.
+ const float pixelDepth = (float)((byteCount>>2) / accelFactor)/(ww*wh);
+ const float gain = 255/(8*pixelDepth);
+ //qDebug() << "Pixel depth: expected " << pixelDepth << "; Gain: using " << gain << " (acceleration: " << accelFactor << "x)";
+
+
// Subtract 1 from sizes because we start counting from 0.
// Not doing it would result in attempts to paint outside of the image.
const float hPrediv = (float)(wh-1)/255;
const float wPrediv = (float)(ww-1)/(iw-1);
const uchar *bits = image.bits();
- const uint stepsize = 4*accelFactor;
+ const int bpp = image.depth() / 8;
- for (uint i = 0, x = 0; i < byteCount; i += stepsize) {
+ for (uint i = 0, x = 0; i < byteCount; i += bpp) {
+
+ Q_ASSERT(bits < image.bits() + byteCount);
col = (QRgb *)bits;
- // CIE 601 Luminance
+ if (rec == WaveformGenerator::Rec_601) {
+ // CIE 601 Luminance
+ dY = .299*qRed(*col) + .587*qGreen(*col) + .114*qBlue(*col);
+ } else {
+ // CIE 709 Luminance
+ dY = .2125*qRed(*col) + .7154*qGreen(*col) + .0721*qBlue(*col);
+ }
// dY is on [0,255] now.
- dY = .299*qRed(*col) + .587*qGreen(*col) + .114*qBlue(*col);
dy = dY*hPrediv;
dx = x*wPrediv;
- wavePoint = QPoint((int)dx, (int)(wh-1 - dy));
-
- waveCol = QRgb(wave.pixel(wavePoint));
- wave.setPixel(wavePoint, qRgba(CHOP255(9 + qRed(waveCol)), CHOP255(36 + qGreen(waveCol)),
- CHOP255(18 + qBlue(waveCol)), 255));
+ waveValues[(int)dx][(int)dy]++;
+
+ bits += bpp;
+ x += bpp;
+ if (x > iw) {
+ x -= iw;
+ if (accelFactor > 1) {
+ bits += bpp*iw*(accelFactor-1);
+ i += bpp*iw*(accelFactor-1);
+ }
+ }
+ }
- bits += stepsize;
- x += stepsize;
- x %= iw; // Modulo image width, to represent the current x position in the image
+ switch (paintMode) {
+ case PaintMode_Green:
+ for (int i = 0; i < waveformSize.width(); ++i) {
+ for (int j = 0; j < waveformSize.height(); j++) {
+ // Logarithmic scale. Needs fine tuning by hand, but looks great.
+ wave.setPixel(i, waveformSize.height()-j-1, qRgba(CHOP255(52*log(0.1*gain*waveValues[i][j])),
+ CHOP255(52*log(gain*waveValues[i][j])),
+ CHOP255(52*log(.25*gain*waveValues[i][j])),
+ CHOP255(64*log(gain*waveValues[i][j]))));
+ }
+ }
+ break;
+ case PaintMode_Yellow:
+ for (int i = 0; i < waveformSize.width(); ++i) {
+ for (int j = 0; j < waveformSize.height(); j++) {
+ wave.setPixel(i, waveformSize.height()-j-1, qRgba(255,242,0, CHOP255(gain*waveValues[i][j])));
+ }
+ }
+ break;
+ default:
+ for (int i = 0; i < waveformSize.width(); ++i) {
+ for (int j = 0; j < waveformSize.height(); j++) {
+ wave.setPixel(i, waveformSize.height()-j-1, qRgba(255,255,255, CHOP255(2*gain*waveValues[i][j])));
+ }
+ }
+ break;
}
if (drawAxis) {
QRgb opx;
davinci.setPen(qRgba(150,255,200,32));
davinci.setCompositionMode(QPainter::CompositionMode_Overlay);
- for (uint i = 0; i <= 10; i++) {
+ for (uint i = 0; i <= 10; ++i) {
dy = (float)i/10 * (wh-1);
for (uint x = 0; x < ww; x++) {
opx = wave.pixel(x, dy);
wave.setPixel(x,dy, qRgba(CHOP255(150+qRed(opx)), 255,
CHOP255(200+qBlue(opx)), CHOP255(32+qAlpha(opx))));
}
- //davinci.drawLine(0, dy, ww-1, dy);
}
}
}
- uint diff = time.elapsed();
-// qDebug() << "Waveform calculation ended. Time taken: " << diff << " ms. Sending signal now.";
- emit signalCalculationFinished(wave, diff);
+ //uint diff = time.elapsed();
+ //emit signalCalculationFinished(wave, diff);
return wave;
}
+#undef CHOP255
+
+#include "waveformgenerator.moc"