diff --git a/build/depends.py b/build/depends.py index 21c6d82d725e..003580a0c233 100644 --- a/build/depends.py +++ b/build/depends.py @@ -694,6 +694,7 @@ def sources(self, build): "widget/woverview.cpp", "widget/woverviewlmh.cpp", "widget/woverviewhsv.cpp", + "widget/woverviewrgb.cpp", "widget/wspinny.cpp", "widget/wskincolor.cpp", "widget/wsearchlineedit.cpp", @@ -829,12 +830,14 @@ def sources(self, build): "waveform/renderers/waveformrendererfilteredsignal.cpp", "waveform/renderers/waveformrendererhsv.cpp", + "waveform/renderers/waveformrendererrgb.cpp", "waveform/renderers/qtwaveformrendererfilteredsignal.cpp", "waveform/renderers/qtwaveformrenderersimplesignal.cpp", "waveform/renderers/glwaveformrendererfilteredsignal.cpp", "waveform/renderers/glwaveformrenderersimplesignal.cpp", "waveform/renderers/glslwaveformrenderersignal.cpp", "waveform/renderers/glvsynctestrenderer.cpp", + "waveform/renderers/glwaveformrendererrgb.cpp", "waveform/renderers/waveformsignalcolors.cpp", @@ -847,6 +850,7 @@ def sources(self, build): "waveform/widgets/emptywaveformwidget.cpp", "waveform/widgets/softwarewaveformwidget.cpp", "waveform/widgets/hsvwaveformwidget.cpp", + "waveform/widgets/rgbwaveformwidget.cpp", "waveform/widgets/qtwaveformwidget.cpp", "waveform/widgets/qtsimplewaveformwidget.cpp", "waveform/widgets/glwaveformwidget.cpp", @@ -855,6 +859,8 @@ def sources(self, build): "waveform/widgets/glslwaveformwidget.cpp", + "waveform/widgets/glrgbwaveformwidget.cpp", + "skin/imginvert.cpp", "skin/imgloader.cpp", "skin/imgcolor.cpp", diff --git a/src/dlgprefcontrols.cpp b/src/dlgprefcontrols.cpp index a78c045ae4e0..dcb7ea383eba 100644 --- a/src/dlgprefcontrols.cpp +++ b/src/dlgprefcontrols.cpp @@ -731,6 +731,7 @@ void DlgPrefControls::initWaveformControl() { // Waveform overview init waveformOverviewComboBox->addItem( tr("Filtered") ); // "0" waveformOverviewComboBox->addItem( tr("HSV") ); // "1" + waveformOverviewComboBox->addItem( tr("RGB") ); // "2" // By default we set filtered woverview = "0" waveformOverviewComboBox->setCurrentIndex( diff --git a/src/skin/legacyskinparser.cpp b/src/skin/legacyskinparser.cpp index 7ad4b4591863..c1d2da77b05e 100644 --- a/src/skin/legacyskinparser.cpp +++ b/src/skin/legacyskinparser.cpp @@ -51,6 +51,7 @@ #include "widget/weffectparameter.h" #include "widget/woverviewlmh.h" #include "widget/woverviewhsv.h" +#include "widget/woverviewrgb.h" #include "widget/wspinny.h" #include "widget/wwaveformviewer.h" #include "waveform/waveformwidgetfactory.h" @@ -709,12 +710,14 @@ QWidget* LegacySkinParser::parseOverview(QDomElement node) { WOverview* overviewWidget = NULL; - // HSV = "1" or "Filtered" = "0" (LMH) waveform overview type - if (m_pConfig->getValueString(ConfigKey("[Waveform]","WaveformOverviewType"), - "0").toInt() == 0) { + // "RGB" = "2", "HSV" = "1" or "Filtered" = "0" (LMH) waveform overview type + int type = m_pConfig->getValueString(ConfigKey("[Waveform]","WaveformOverviewType"), "0").toInt(); + if (type == 0) { overviewWidget = new WOverviewLMH(pSafeChannelStr, m_pConfig, m_pParent); - } else { + } else if (type == 1) { overviewWidget = new WOverviewHSV(pSafeChannelStr, m_pConfig, m_pParent); + } else { + overviewWidget = new WOverviewRGB(pSafeChannelStr, m_pConfig, m_pParent); } connect(overviewWidget, SIGNAL(trackDropped(QString, QString)), diff --git a/src/waveform/renderers/glwaveformrendererrgb.cpp b/src/waveform/renderers/glwaveformrendererrgb.cpp new file mode 100644 index 000000000000..412d3785403e --- /dev/null +++ b/src/waveform/renderers/glwaveformrendererrgb.cpp @@ -0,0 +1,226 @@ +#include + +#include "glwaveformrendererrgb.h" +#include "waveformwidgetrenderer.h" +#include "waveform/waveform.h" +#include "waveform/waveformwidgetfactory.h" +#include "widget/wwidget.h" +#include "widget/wskincolor.h" +#include "controlobjectthread.h" + +#define MAX3(a, b, c) ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +GLWaveformRendererRGB::GLWaveformRendererRGB( + WaveformWidgetRenderer* waveformWidgetRenderer) + : WaveformRendererSignalBase(waveformWidgetRenderer) { + +} + +GLWaveformRendererRGB::~GLWaveformRendererRGB() { + +} + +void GLWaveformRendererRGB::onSetup(const QDomNode& /* node */) { + +} + +void GLWaveformRendererRGB::setup(const QDomNode& node, + const SkinContext& context) { + + WaveformRendererSignalBase::setup(node, context); + + m_lowColor.setNamedColor(context.selectString(node, "SignalLowColor")); + if (!m_lowColor.isValid()) { + m_lowColor = Qt::red; + } + m_lowColor = WSkinColor::getCorrectColor(m_lowColor); + + m_midColor.setNamedColor(context.selectString(node, "SignalMidColor")); + if (!m_midColor.isValid()) { + m_midColor = Qt::green; + } + m_midColor = WSkinColor::getCorrectColor(m_midColor); + + m_highColor.setNamedColor(context.selectString(node, "SignalHighColor")); + if (!m_highColor.isValid()) { + m_highColor = Qt::blue; + } + m_highColor = WSkinColor::getCorrectColor(m_highColor); +} + +void GLWaveformRendererRGB::draw(QPainter* painter, QPaintEvent* /*event*/) { + + TrackPointer pTrack = m_waveformRenderer->getTrackInfo(); + if (!pTrack) { + return; + } + + const Waveform* waveform = pTrack->getWaveform(); + if (waveform == NULL) { + return; + } + + const int dataSize = waveform->getDataSize(); + if (dataSize <= 1) { + return; + } + + const WaveformData* data = waveform->data(); + if (data == NULL) { + return; + } + + double firstVisualIndex = m_waveformRenderer->getFirstDisplayedPosition() * dataSize; + double lastVisualIndex = m_waveformRenderer->getLastDisplayedPosition() * dataSize; + + const int firstIndex = int(firstVisualIndex + 0.5); + firstVisualIndex = firstIndex - firstIndex % 2; + + const int lastIndex = int(lastVisualIndex + 0.5); + lastVisualIndex = lastIndex + lastIndex % 2; + + // Reset device for native painting + painter->beginNativePainting(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Per-band gain from the EQ knobs. + float lowGain(1.0), midGain(1.0), highGain(1.0); + if (m_pLowFilterControlObject && m_pMidFilterControlObject && m_pHighFilterControlObject) { + lowGain = m_pLowFilterControlObject->get(); + midGain = m_pMidFilterControlObject->get(); + highGain = m_pHighFilterControlObject->get(); + } + + WaveformWidgetFactory* factory = WaveformWidgetFactory::instance(); + const double visualGain = factory->getVisualGain(::WaveformWidgetFactory::All); + lowGain *= factory->getVisualGain(WaveformWidgetFactory::Low); + midGain *= factory->getVisualGain(WaveformWidgetFactory::Mid); + highGain *= factory->getVisualGain(WaveformWidgetFactory::High); + + if (m_alignment == Qt::AlignCenter) { + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(firstVisualIndex, lastVisualIndex, -255.0, 255.0, -10.0, 10.0); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glScalef(1.0f, visualGain * m_waveformRenderer->getGain(), 1.0f); + + glLineWidth(1.2); + glDisable(GL_LINE_SMOOTH); + + // Draw reference line + glBegin(GL_LINES); { + glColor4f(m_axesColor_r, m_axesColor_g, m_axesColor_b, m_axesColor_a); + glVertex2f(firstVisualIndex, 0); + glVertex2f(lastVisualIndex, 0); + } + glEnd(); + + glLineWidth(1.2); + glEnable(GL_LINE_SMOOTH); + + glBegin(GL_LINES); { + for( int visualIndex = firstVisualIndex; + visualIndex < lastVisualIndex; + visualIndex += 2) { + + if( visualIndex < 0) + continue; + + if( visualIndex > dataSize - 1) + break; + + float left_low = lowGain * (float) data[visualIndex].filtered.low; + float left_mid = midGain * (float) data[visualIndex].filtered.mid; + float left_high = highGain * (float) data[visualIndex].filtered.high; + float left_all = sqrtf(left_low * left_low + left_mid * left_mid + left_high * left_high); + float left_red = left_low * m_lowColor.red() + left_mid * m_midColor.red() + left_high * m_highColor.red(); + float left_green = left_low * m_lowColor.green() + left_mid * m_midColor.green() + left_high * m_highColor.green(); + float left_blue = left_low * m_lowColor.blue() + left_mid * m_midColor.blue() + left_high * m_highColor.blue(); + float left_max = MAX3(left_red, left_green, left_blue); + if (left_max > 0.0f) { // Prevent division by zero + glColor4f(left_red / left_max, left_green / left_max, left_blue / left_max, 0.8f); + glVertex2f(visualIndex, 0.0f); + glVertex2f(visualIndex, left_all); + } + + float right_low = lowGain * (float) data[visualIndex+1].filtered.low; + float right_mid = midGain * (float) data[visualIndex+1].filtered.mid; + float right_high = highGain * (float) data[visualIndex+1].filtered.high; + float right_all = sqrtf(right_low * right_low + right_mid * right_mid + right_high * right_high); + float right_red = right_low * m_lowColor.red() + right_mid * m_midColor.red() + right_high * m_highColor.red(); + float right_green = right_low * m_lowColor.green() + right_mid * m_midColor.green() + right_high * m_highColor.green(); + float right_blue = right_low * m_lowColor.blue() + right_mid * m_midColor.blue() + right_high * m_highColor.blue(); + float right_max = MAX3(right_red, right_green, right_blue); + if (right_max > 0.0f) { // Prevent division by zero + glColor4f(right_red / right_max, right_green / right_max, right_blue / right_max, 0.8f); + glVertex2f(visualIndex, 0.0f); + glVertex2f(visualIndex, -1.0f * right_all); + } + } + } + + glEnd(); + + } else { // top || bottom + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + if( m_alignment == Qt::AlignBottom) + glOrtho(firstVisualIndex, lastVisualIndex, 0.0, 255.0, -10.0, 10.0); + else + glOrtho(firstVisualIndex, lastVisualIndex, 255.0, 0.0, -10.0, 10.0); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glScalef(1.0f, visualGain * m_waveformRenderer->getGain(), 1.0f); + + glLineWidth(1.2); + glEnable(GL_LINE_SMOOTH); + + glBegin(GL_LINES); { + for( int visualIndex = firstVisualIndex; + visualIndex < lastVisualIndex; + visualIndex += 2) { + + if( visualIndex < 0) + continue; + + if( visualIndex > dataSize - 1) + break; + + float low = lowGain * (float) math_max(data[visualIndex].filtered.low, data[visualIndex+1].filtered.low); + float mid = midGain * (float) math_max(data[visualIndex].filtered.mid, data[visualIndex+1].filtered.mid); + float high = highGain * (float) math_max(data[visualIndex].filtered.high, data[visualIndex+1].filtered.high); + + float all = sqrtf(low * low + mid * mid + high * high); + + float red = low * m_lowColor.red() + mid * m_midColor.red() + high * m_highColor.red(); + float green = low * m_lowColor.green() + mid * m_midColor.green() + high * m_highColor.green(); + float blue = low * m_lowColor.blue() + mid * m_midColor.blue() + high * m_highColor.blue(); + + float max = MAX3(red, green, blue); + if (max > 0.0f) { // Prevent division by zero + glColor4f(red / max, green / max, blue / max, 0.9f); + glVertex2f(float(visualIndex), 0.0f); + glVertex2f(float(visualIndex), all); + } + } + } + + glEnd(); + } + + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + painter->endNativePainting(); +} diff --git a/src/waveform/renderers/glwaveformrendererrgb.h b/src/waveform/renderers/glwaveformrendererrgb.h new file mode 100644 index 000000000000..189212f2e819 --- /dev/null +++ b/src/waveform/renderers/glwaveformrendererrgb.h @@ -0,0 +1,23 @@ +#ifndef GLWAVEFORMRENDERERRGB_H +#define GLWAVEFORMRENDERERRGB_H + +#include "waveformrenderersignalbase.h" + +class ControlObject; + +class GLWaveformRendererRGB : public WaveformRendererSignalBase { +public: + explicit GLWaveformRendererRGB( WaveformWidgetRenderer* waveformWidgetRenderer); + virtual ~GLWaveformRendererRGB(); + + virtual void onSetup(const QDomNode& node); + virtual void setup(const QDomNode& node, const SkinContext& context); + virtual void draw(QPainter* painter, QPaintEvent* event); + +private: + QColor m_lowColor; + QColor m_midColor; + QColor m_highColor; +}; + +#endif // GLWAVEFORMRENDERERRGB_H diff --git a/src/waveform/renderers/waveformrendererrgb.cpp b/src/waveform/renderers/waveformrendererrgb.cpp new file mode 100644 index 000000000000..10c790f96d51 --- /dev/null +++ b/src/waveform/renderers/waveformrendererrgb.cpp @@ -0,0 +1,185 @@ +#include "waveformrendererrgb.h" + +#include "waveformwidgetrenderer.h" +#include "waveform/waveform.h" +#include "waveform/waveformwidgetfactory.h" + +#include "widget/wskincolor.h" +#include "trackinfoobject.h" +#include "widget/wwidget.h" + +#include "defs.h" + +#define MAX3(a, b, c) ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +WaveformRendererRGB::WaveformRendererRGB( + WaveformWidgetRenderer* waveformWidgetRenderer) + : WaveformRendererSignalBase( waveformWidgetRenderer) { +} + +WaveformRendererRGB::~WaveformRendererRGB() { +} + +void WaveformRendererRGB::onSetup(const QDomNode& /* node */) { +} + +void WaveformRendererRGB::setup(const QDomNode& node, + const SkinContext& context) { + WaveformRendererSignalBase::setup(node, context); + + m_lowColor.setNamedColor(context.selectString(node, "SignalLowColor")); + if (!m_lowColor.isValid()) { + m_lowColor.setRgb(255,0,0); + } + m_lowColor = WSkinColor::getCorrectColor(m_lowColor); + + m_midColor.setNamedColor(context.selectString(node, "SignalMidColor")); + if (!m_midColor.isValid()) { + m_midColor.setRgb(0,255,0); + } + m_midColor = WSkinColor::getCorrectColor(m_midColor); + + m_highColor.setNamedColor(context.selectString(node, "SignalHighColor")); + if (!m_highColor.isValid()) { + m_highColor.setRgb(0,0,255); + } + m_highColor = WSkinColor::getCorrectColor(m_highColor); +} + +void WaveformRendererRGB::draw(QPainter* painter, + QPaintEvent* /*event*/) { + const TrackPointer trackInfo = m_waveformRenderer->getTrackInfo(); + if (!trackInfo) { + return; + } + + const Waveform* waveform = trackInfo->getWaveform(); + if (waveform == NULL) { + return; + } + + const int dataSize = waveform->getDataSize(); + if (dataSize <= 1) { + return; + } + + const WaveformData* data = waveform->data(); + if (data == NULL) { + return; + } + + painter->save(); + painter->setRenderHints(QPainter::Antialiasing, false); + painter->setRenderHints(QPainter::HighQualityAntialiasing, false); + painter->setRenderHints(QPainter::SmoothPixmapTransform, false); + painter->setWorldMatrixEnabled(false); + painter->resetTransform(); + + const double firstVisualIndex = m_waveformRenderer->getFirstDisplayedPosition() * dataSize; + const double lastVisualIndex = m_waveformRenderer->getLastDisplayedPosition() * dataSize; + + const double offset = firstVisualIndex; + + // Represents the # of waveform data points per horizontal pixel. + const double gain = (lastVisualIndex - firstVisualIndex) / + (double)m_waveformRenderer->getWidth(); + + float allGain(1.0); + allGain = m_waveformRenderer->getGain(); + + WaveformWidgetFactory* factory = WaveformWidgetFactory::instance(); + allGain *= factory->getVisualGain(::WaveformWidgetFactory::All); + + QColor color; + + const float halfHeight = (float)m_waveformRenderer->getHeight()/2.0; + + const float heightFactor = allGain*halfHeight/255.0; + + // Draw reference line + painter->setPen(m_pColors->getAxesColor()); + painter->drawLine(0,halfHeight,m_waveformRenderer->getWidth(),halfHeight); + + for (int x = 0; x < m_waveformRenderer->getWidth(); ++x) { + // Width of the x position in visual indices. + const double xSampleWidth = gain * x; + + // Effective visual index of x + const double xVisualSampleIndex = xSampleWidth + offset; + + // Our current pixel (x) corresponds to a number of visual samples + // (visualSamplerPerPixel) in our waveform object. We take the max of + // all the data points on either side of xVisualSampleIndex within a + // window of 'maxSamplingRange' visual samples to measure the maximum + // data point contained by this pixel. + double maxSamplingRange = gain / 2.0; + + // Since xVisualSampleIndex is in visual-samples (e.g. R,L,R,L) we want + // to check +/- maxSamplingRange frames, not samples. To do this, divide + // xVisualSampleIndex by 2. Since frames indices are integers, we round + // to the nearest integer by adding 0.5 before casting to int. + int visualFrameStart = int(xVisualSampleIndex / 2.0 - maxSamplingRange + 0.5); + int visualFrameStop = int(xVisualSampleIndex / 2.0 + maxSamplingRange + 0.5); + const int lastVisualFrame = dataSize / 2 - 1; + + // We now know that some subset of [visualFrameStart, visualFrameStop] + // lies within the valid range of visual frames. Clamp + // visualFrameStart/Stop to within [0, lastVisualFrame]. + visualFrameStart = math_max(math_min(lastVisualFrame, visualFrameStart), 0); + visualFrameStop = math_max(math_min(lastVisualFrame, visualFrameStop), 0); + + int visualIndexStart = visualFrameStart * 2; + int visualIndexStop = visualFrameStop * 2; + + unsigned char maxLow = 0; + unsigned char maxMid = 0; + unsigned char maxHigh = 0; + unsigned char maxAllA = 0; + unsigned char maxAllB = 0; + + for (int i = visualIndexStart; + i >= 0 && i + 1 < dataSize && i + 1 <= visualIndexStop; i += 2) { + const WaveformData& waveformData = *(data + i); + const WaveformData& waveformDataNext = *(data + i + 1); + + maxLow = MAX3(maxLow, waveformData.filtered.low, waveformDataNext.filtered.low); + maxMid = MAX3(maxMid, waveformData.filtered.mid, waveformDataNext.filtered.mid); + maxHigh = MAX3(maxHigh, waveformData.filtered.high, waveformDataNext.filtered.high); + maxAllA = math_max(maxAllA, waveformData.filtered.all); + maxAllB = math_max(maxAllB, waveformDataNext.filtered.all); + } + + int red = maxLow * m_lowColor.red() + maxMid * m_midColor.red() + maxHigh * m_highColor.red(); + int green = maxLow * m_lowColor.green() + maxMid * m_midColor.green() + maxHigh * m_highColor.green(); + int blue = maxLow * m_lowColor.blue() + maxMid * m_midColor.blue() + maxHigh * m_highColor.blue(); + + // Compute maximum (needed for value normalization) + float max = (float) MAX3(red, green, blue); + + // Prevent division by zero + if (max > 0.0f) { + // Set color + color.setRgbF(red / max, green / max, blue / max); + + painter->setPen(color); + switch (m_alignment) { + case Qt::AlignBottom : + painter->drawLine( + x, m_waveformRenderer->getHeight(), + x, m_waveformRenderer->getHeight() - (int)(heightFactor*(float)math_max(maxAllA,maxAllB))); + break; + case Qt::AlignTop : + painter->drawLine( + x, 0, + x, (int)(heightFactor*(float)math_max(maxAllA,maxAllB))); + break; + default : + painter->drawLine( + x, (int)(halfHeight-heightFactor*(float)maxAllA), + x, (int)(halfHeight+heightFactor*(float)maxAllB)); + } + } + } + + painter->restore(); +} diff --git a/src/waveform/renderers/waveformrendererrgb.h b/src/waveform/renderers/waveformrendererrgb.h new file mode 100644 index 000000000000..e4cc0984e2e2 --- /dev/null +++ b/src/waveform/renderers/waveformrendererrgb.h @@ -0,0 +1,25 @@ +#ifndef WAVEFORMRENDERERRGB_H +#define WAVEFORMRENDERERRGB_H + +#include "waveformrenderersignalbase.h" +#include "util.h" + +class WaveformRendererRGB : public WaveformRendererSignalBase { + public: + explicit WaveformRendererRGB( + WaveformWidgetRenderer* waveformWidget); + virtual ~WaveformRendererRGB(); + + virtual void onSetup(const QDomNode& node); + virtual void setup(const QDomNode& node, const SkinContext& context); + virtual void draw(QPainter* painter, QPaintEvent* event); + + private: + QColor m_lowColor; + QColor m_midColor; + QColor m_highColor; + + DISALLOW_COPY_AND_ASSIGN(WaveformRendererRGB); +}; + +#endif // WAVEFORMRENDERERRGB_H diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 8b10f33b5ff7..7d979cfd63c8 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -13,6 +13,8 @@ #include "waveform/widgets/emptywaveformwidget.h" #include "waveform/widgets/softwarewaveformwidget.h" #include "waveform/widgets/hsvwaveformwidget.h" +#include "waveform/widgets/rgbwaveformwidget.h" +#include "waveform/widgets/glrgbwaveformwidget.h" #include "waveform/widgets/glwaveformwidget.h" #include "waveform/widgets/glsimplewaveformwidget.h" #include "waveform/widgets/qtwaveformwidget.h" @@ -534,6 +536,12 @@ void WaveformWidgetFactory::evaluateWidgets() { useOpenGLShaders = HSVWaveformWidget::useOpenGLShaders(); developerOnly = HSVWaveformWidget::developerOnly(); break; + case WaveformWidgetType::RGBWaveform: + widgetName = RGBWaveformWidget::getWaveformWidgetName(); + useOpenGl = RGBWaveformWidget::useOpenGl(); + useOpenGLShaders = RGBWaveformWidget::useOpenGLShaders(); + developerOnly = RGBWaveformWidget::developerOnly(); + break; case WaveformWidgetType::QtSimpleWaveform: widgetName = QtSimpleWaveformWidget::getWaveformWidgetName(); useOpenGl = QtSimpleWaveformWidget::useOpenGl(); @@ -570,6 +578,12 @@ void WaveformWidgetFactory::evaluateWidgets() { useOpenGLShaders = GLVSyncTestWidget::useOpenGLShaders(); developerOnly = GLVSyncTestWidget::developerOnly(); break; + case WaveformWidgetType::GLRGBWaveform: + widgetName = GLRGBWaveformWidget::getWaveformWidgetName(); + useOpenGl = GLRGBWaveformWidget::useOpenGl(); + useOpenGLShaders = GLRGBWaveformWidget::useOpenGLShaders(); + developerOnly = GLRGBWaveformWidget::developerOnly(); + break; default: continue; } @@ -613,6 +627,9 @@ WaveformWidgetAbstract* WaveformWidgetFactory::createWaveformWidget( case WaveformWidgetType::HSVWaveform: widget = new HSVWaveformWidget(viewer->getGroup(), viewer); break; + case WaveformWidgetType::RGBWaveform: + widget = new RGBWaveformWidget(viewer->getGroup(), viewer); + break; case WaveformWidgetType::QtSimpleWaveform: widget = new QtSimpleWaveformWidget(viewer->getGroup(), viewer); break; @@ -625,6 +642,9 @@ WaveformWidgetAbstract* WaveformWidgetFactory::createWaveformWidget( case WaveformWidgetType::GLWaveform: widget = new GLWaveformWidget(viewer->getGroup(), viewer); break; + case WaveformWidgetType::GLRGBWaveform: + widget = new GLRGBWaveformWidget(viewer->getGroup(), viewer); + break; case WaveformWidgetType::GLSLWaveform: widget = new GLSLWaveformWidget(viewer->getGroup(), viewer); break; diff --git a/src/waveform/widgets/glrgbwaveformwidget.cpp b/src/waveform/widgets/glrgbwaveformwidget.cpp new file mode 100644 index 000000000000..af2d9208e0b6 --- /dev/null +++ b/src/waveform/widgets/glrgbwaveformwidget.cpp @@ -0,0 +1,69 @@ +#include "glrgbwaveformwidget.h" + +#include "sharedglcontext.h" + +#include "waveform/renderers/waveformwidgetrenderer.h" +#include "waveform/renderers/waveformrenderbackground.h" +#include "waveform/renderers/glwaveformrendererrgb.h" +#include "waveform/renderers/waveformrendererpreroll.h" +#include "waveform/renderers/waveformrendermark.h" +#include "waveform/renderers/waveformrendermarkrange.h" +#include "waveform/renderers/waveformrendererendoftrack.h" +#include "waveform/renderers/waveformrenderbeat.h" + +#include "util/performancetimer.h" + +GLRGBWaveformWidget::GLRGBWaveformWidget( const char* group, QWidget* parent) + : QGLWidget(parent, SharedGLContext::getWidget()), + WaveformWidgetAbstract(group) { + + addRenderer(); + addRenderer(); + addRenderer(); + addRenderer(); + addRenderer(); + addRenderer(); + addRenderer(); + + setAttribute(Qt::WA_NoSystemBackground); + setAttribute(Qt::WA_OpaquePaintEvent); + + setAutoBufferSwap(false); + + qDebug() << "Created QGLWidget. Context" + << "Valid:" << context()->isValid() + << "Sharing:" << context()->isSharing(); + if (QGLContext::currentContext() != context()) { + makeCurrent(); + } + m_initSuccess = init(); +} + +GLRGBWaveformWidget::~GLRGBWaveformWidget() { + +} + +void GLRGBWaveformWidget::castToQWidget() { + m_widget = static_cast(static_cast(this)); +} + +void GLRGBWaveformWidget::paintEvent( QPaintEvent* event) { + Q_UNUSED(event); +} + +int GLRGBWaveformWidget::render() { + PerformanceTimer timer; + int t1; + //int t2, t3; + timer.start(); + // QPainter makes QGLContext::currentContext() == context() + // this may delayed until previous buffer swap finished + QPainter painter(this); + t1 = timer.restart(); + draw(&painter, NULL); + //t2 = timer.restart(); + // glFinish(); + //t3 = timer.restart(); + //qDebug() << "GLVSyncTestWidget "<< t1 << t2 << t3; + return t1 / 1000; // return timer for painter setup +} diff --git a/src/waveform/widgets/glrgbwaveformwidget.h b/src/waveform/widgets/glrgbwaveformwidget.h new file mode 100644 index 000000000000..06b06ca46ff4 --- /dev/null +++ b/src/waveform/widgets/glrgbwaveformwidget.h @@ -0,0 +1,30 @@ +#ifndef GLRGBWAVEFORMWIDGET_H +#define GLRGBWAVEFORMWIDGET_H + +#include + +#include "waveformwidgetabstract.h" + +class GLRGBWaveformWidget : public QGLWidget, public WaveformWidgetAbstract { + Q_OBJECT + public: + GLRGBWaveformWidget(const char* group, QWidget* parent); + virtual ~GLRGBWaveformWidget(); + + virtual WaveformWidgetType::Type getType() const { return WaveformWidgetType::GLRGBWaveform; } + + static inline QString getWaveformWidgetName() { return tr("RGB"); } + static inline bool useOpenGl() { return true; } + static inline bool useOpenGLShaders() { return false; } + static inline bool developerOnly() { return false; } + + protected: + virtual void castToQWidget(); + virtual void paintEvent(QPaintEvent* event); + virtual int render(); + + private: + friend class WaveformWidgetFactory; +}; + +#endif // GLRGBWAVEFORMWIDGET_H diff --git a/src/waveform/widgets/rgbwaveformwidget.cpp b/src/waveform/widgets/rgbwaveformwidget.cpp new file mode 100644 index 000000000000..f64b77b634cc --- /dev/null +++ b/src/waveform/widgets/rgbwaveformwidget.cpp @@ -0,0 +1,41 @@ +#include "rgbwaveformwidget.h" + +#include + +#include "waveform/renderers/waveformwidgetrenderer.h" +#include "waveform/renderers/waveformrenderbackground.h" +#include "waveform/renderers/waveformrendermark.h" +#include "waveform/renderers/waveformrendermarkrange.h" +#include "waveform/renderers/waveformrendererrgb.h" +#include "waveform/renderers/waveformrendererpreroll.h" +#include "waveform/renderers/waveformrendererendoftrack.h" +#include "waveform/renderers/waveformrenderbeat.h" + +RGBWaveformWidget::RGBWaveformWidget( const char* group, QWidget* parent) + : QWidget(parent), + WaveformWidgetAbstract(group) { + addRenderer(); + addRenderer(); + addRenderer(); + addRenderer(); + addRenderer(); + addRenderer(); + addRenderer(); + + setAttribute(Qt::WA_NoSystemBackground); + setAttribute(Qt::WA_OpaquePaintEvent); + + m_initSuccess = init(); +} + +RGBWaveformWidget::~RGBWaveformWidget() { +} + +void RGBWaveformWidget::castToQWidget() { + m_widget = static_cast(this); +} + +void RGBWaveformWidget::paintEvent( QPaintEvent* event) { + QPainter painter(this); + draw(&painter,event); +} diff --git a/src/waveform/widgets/rgbwaveformwidget.h b/src/waveform/widgets/rgbwaveformwidget.h new file mode 100644 index 000000000000..1c7d9387eaec --- /dev/null +++ b/src/waveform/widgets/rgbwaveformwidget.h @@ -0,0 +1,29 @@ +#ifndef RGBWAVEFORMWIDGET_H +#define RGBWAVEFORMWIDGET_H + +#include + +#include "waveformwidgetabstract.h" + +class RGBWaveformWidget : public QWidget, public WaveformWidgetAbstract { + Q_OBJECT + public: + virtual ~RGBWaveformWidget(); + + virtual WaveformWidgetType::Type getType() const { return WaveformWidgetType::RGBWaveform; } + + static inline QString getWaveformWidgetName() { return tr("RGB"); } + static inline bool useOpenGl() { return false; } + static inline bool useOpenGLShaders() { return false; } + static inline bool developerOnly() { return false; } + + protected: + virtual void castToQWidget(); + virtual void paintEvent(QPaintEvent* event); + + private: + RGBWaveformWidget(const char* group, QWidget* parent); + friend class WaveformWidgetFactory; +}; + +#endif // RGBWAVEFORMWIDGET_H diff --git a/src/waveform/widgets/waveformwidgettype.h b/src/waveform/widgets/waveformwidgettype.h index 8876a3400287..1e2eaa12a7a8 100644 --- a/src/waveform/widgets/waveformwidgettype.h +++ b/src/waveform/widgets/waveformwidgettype.h @@ -14,6 +14,8 @@ class WaveformWidgetType { GLSLWaveform, HSVWaveform, GLVSyncTest, + RGBWaveform, + GLRGBWaveform, Count_WaveformwidgetType // Also used as invalid value }; }; diff --git a/src/widget/woverviewrgb.cpp b/src/widget/woverviewrgb.cpp new file mode 100644 index 000000000000..f4c1bd9dbcbd --- /dev/null +++ b/src/widget/woverviewrgb.cpp @@ -0,0 +1,123 @@ +#include "widget/woverviewrgb.h" + +#include + +#include "util/timer.h" + +#include "waveform/waveform.h" + +#define MAX3(a, b, c) ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +WOverviewRGB::WOverviewRGB(const char* pGroup, + ConfigObject* pConfig, QWidget* parent) + : WOverview(pGroup, pConfig, parent) { +} + +bool WOverviewRGB::drawNextPixmapPart() { + ScopedTimer t("WOverviewRGB::drawNextPixmapPart"); + + //qDebug() << "WOverview::drawNextPixmapPart() - m_waveform" << m_waveform; + + int currentCompletion; + + if (!m_pWaveform) { + return false; + } + + const int dataSize = m_pWaveform->getDataSize(); + if (dataSize == 0 ) { + return false; + } + + if (!m_pWaveformSourceImage) { + // Waveform pixmap twice the height of the viewport to be scalable + // by total_gain + // We keep full range waveform data to scale it on paint + m_pWaveformSourceImage = new QImage(dataSize / 2, 2 * 255, + QImage::Format_ARGB32_Premultiplied); + m_pWaveformSourceImage->fill(QColor(0,0,0,0).value()); + } + + // Always multiple of 2 + const int waveformCompletion = m_pWaveform->getCompletion(); + // Test if there is some new to draw (at least of pixel width) + const int completionIncrement = waveformCompletion - m_actualCompletion; + + int visiblePixelIncrement = completionIncrement * width() / dataSize; + if (completionIncrement < 2 || visiblePixelIncrement == 0) { + return false; + } + + if (!m_pWaveform->getMutex()->tryLock()) { + return false; + } + + const int nextCompletion = m_actualCompletion + completionIncrement; + + //qDebug() << "WOverview::drawNextPixmapPart() - nextCompletion:" + // << nextCompletion + // << "m_actualCompletion:" << m_actualCompletion + // << "waveformCompletion:" << waveformCompletion + // << "completionIncrement:" << completionIncrement; + + QPainter painter(m_pWaveformSourceImage); + painter.translate(0.0,(double)m_pWaveformSourceImage->height()/2.0); + + QColor color; + + unsigned char low, mid, high; + + // Maximum is needed for normalization + float max; + + for (currentCompletion = m_actualCompletion; + currentCompletion < nextCompletion; currentCompletion += 2) { + + unsigned char left = m_pWaveform->getAll(currentCompletion); + unsigned char right = m_pWaveform->getAll(currentCompletion + 1); + + low = m_pWaveform->getLow(currentCompletion); + mid = m_pWaveform->getMid(currentCompletion); + high = m_pWaveform->getHigh(currentCompletion); + + max = (float) MAX3(low, mid, high); + if (max > 0.0f) { + color.setRgbF(low / max, mid / max, high / max); + painter.setPen(color); + painter.drawLine(currentCompletion / 2, -left, currentCompletion / 2, 0); + } + + low = m_pWaveform->getLow(currentCompletion + 1); + mid = m_pWaveform->getMid(currentCompletion + 1); + high = m_pWaveform->getHigh(currentCompletion + 1); + + max = (float) MAX3(low, mid, high); + if (max > 0.0f) { + color.setRgbF(low / max, mid / max, high / max); + painter.setPen(color); + painter.drawLine(currentCompletion / 2, 0, currentCompletion / 2, right); + } + } + + // Evaluate waveform ratio peak + for (currentCompletion = m_actualCompletion; + currentCompletion < nextCompletion; currentCompletion += 2) { + m_waveformPeak = math_max(m_waveformPeak, + (float)m_pWaveform->getAll(currentCompletion)); + m_waveformPeak = math_max(m_waveformPeak, + (float)m_pWaveform->getAll(currentCompletion+1)); + } + + m_actualCompletion = nextCompletion; + m_waveformImageScaled = QImage(); + m_diffGain = 0; + + // Test if the complete waveform is done + if (m_actualCompletion >= dataSize - 2) { + m_pixmapDone = true; + //qDebug() << "m_waveformPeakRatio" << m_waveformPeak; + } + + m_pWaveform->getMutex()->unlock(); + return true; +} diff --git a/src/widget/woverviewrgb.h b/src/widget/woverviewrgb.h new file mode 100644 index 000000000000..df05c15c6676 --- /dev/null +++ b/src/widget/woverviewrgb.h @@ -0,0 +1,14 @@ +#ifndef WOVERVIEWRGB_H +#define WOVERVIEWRGB_H + +#include "widget/woverview.h" + +class WOverviewRGB : public WOverview { + public: + WOverviewRGB(const char *pGroup, ConfigObject* pConfig, QWidget* parent); + + private: + virtual bool drawNextPixmapPart(); +}; + +#endif // WOVERVIEWRGB_H