1 /***************************************************************************
2 * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) *
3 * This file is part of kdenlive. See www.kdenlive.org. *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 ***************************************************************************/
18 #include "waveformgenerator.h"
20 #define CHOP255(a) ((255) < (a) ? (255) : (a))
22 WaveformGenerator::WaveformGenerator()
26 WaveformGenerator::~WaveformGenerator()
30 QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QImage &image, WaveformGenerator::PaintMode paintMode,
31 bool drawAxis, WaveformGenerator::Rec rec, uint accelFactor)
33 Q_ASSERT(accelFactor >= 1);
38 QImage wave(waveformSize, QImage::Format_ARGB32);
40 if (waveformSize.width() <= 0 || waveformSize.height() <= 0 || image.width() <= 0 || image.height() <= 0) {
45 // Fill with transparent color
46 wave.fill(qRgba(0,0,0,0));
52 const uint ww = waveformSize.width();
53 const uint wh = waveformSize.height();
54 const uint iw = image.bytesPerLine();
55 const uint ih = image.height();
56 const uint byteCount = iw*ih;
58 uint waveValues[waveformSize.width()][waveformSize.height()];
59 for (int i = 0; i < waveformSize.width(); ++i) {
60 for (int j = 0; j < waveformSize.height(); j++) {
65 // Number of input pixels that will fall on one scope pixel.
66 // Must be a float because the acceleration factor can be high, leading to <1 expected px per px.
67 const float pixelDepth = (float)((byteCount>>2) / accelFactor)/(ww*wh);
68 const float gain = 255/(8*pixelDepth);
69 //qDebug() << "Pixel depth: expected " << pixelDepth << "; Gain: using " << gain << " (acceleration: " << accelFactor << "x)";
72 // Subtract 1 from sizes because we start counting from 0.
73 // Not doing it would result in attempts to paint outside of the image.
74 const float hPrediv = (float)(wh-1)/255;
75 const float wPrediv = (float)(ww-1)/(iw-1);
77 const uchar *bits = image.bits();
78 const int bpp = image.depth() / 8;
80 for (uint i = 0, x = 0; i < byteCount; i += bpp) {
82 Q_ASSERT(bits < image.bits() + byteCount);
86 if (rec == WaveformGenerator::Rec_601) {
88 dY = .299*qRed(*col) + .587*qGreen(*col) + .114*qBlue(*col);
91 dY = .2125*qRed(*col) + .7154*qGreen(*col) + .0721*qBlue(*col);
93 // dY is on [0,255] now.
97 waveValues[(int)dx][(int)dy]++;
103 if (accelFactor > 1) {
104 bits += bpp*iw*(accelFactor-1);
105 i += bpp*iw*(accelFactor-1);
111 case PaintMode_Green:
112 for (int i = 0; i < waveformSize.width(); ++i) {
113 for (int j = 0; j < waveformSize.height(); j++) {
114 // Logarithmic scale. Needs fine tuning by hand, but looks great.
115 wave.setPixel(i, waveformSize.height()-j-1, qRgba(CHOP255(52*log(0.1*gain*waveValues[i][j])),
116 CHOP255(52*log(gain*waveValues[i][j])),
117 CHOP255(52*log(.25*gain*waveValues[i][j])),
118 CHOP255(64*log(gain*waveValues[i][j]))));
122 case PaintMode_Yellow:
123 for (int i = 0; i < waveformSize.width(); ++i) {
124 for (int j = 0; j < waveformSize.height(); j++) {
125 wave.setPixel(i, waveformSize.height()-j-1, qRgba(255,242,0, CHOP255(gain*waveValues[i][j])));
130 for (int i = 0; i < waveformSize.width(); ++i) {
131 for (int j = 0; j < waveformSize.height(); j++) {
132 wave.setPixel(i, waveformSize.height()-j-1, qRgba(255,255,255, CHOP255(2*gain*waveValues[i][j])));
139 QPainter davinci(&wave);
141 davinci.setPen(qRgba(150,255,200,32));
142 davinci.setCompositionMode(QPainter::CompositionMode_Overlay);
143 for (uint i = 0; i <= 10; ++i) {
144 dy = (float)i/10 * (wh-1);
145 for (uint x = 0; x < ww; x++) {
146 opx = wave.pixel(x, dy);
147 wave.setPixel(x,dy, qRgba(CHOP255(150+qRed(opx)), 255,
148 CHOP255(200+qBlue(opx)), CHOP255(32+qAlpha(opx))));
155 //uint diff = time.elapsed();
156 //emit signalCalculationFinished(wave, diff);
162 #include "waveformgenerator.moc"