1 #include "waveform/waveformwidgetfactory.h"
2 
3 #include <QGLFormat>
4 #include <QGLShaderProgram>
5 #include <QGuiApplication>
6 #include <QOpenGLFunctions>
7 #include <QStringList>
8 #include <QTime>
9 #include <QWidget>
10 #include <QWindow>
11 #include <QtDebug>
12 
13 #include "control/controlpotmeter.h"
14 #include "moc_waveformwidgetfactory.cpp"
15 #include "util/cmdlineargs.h"
16 #include "util/math.h"
17 #include "util/performancetimer.h"
18 #include "util/timer.h"
19 #include "waveform/guitick.h"
20 #include "waveform/sharedglcontext.h"
21 #include "waveform/visualsmanager.h"
22 #include "waveform/vsyncthread.h"
23 #include "waveform/widgets/emptywaveformwidget.h"
24 #include "waveform/widgets/glrgbwaveformwidget.h"
25 #include "waveform/widgets/glsimplewaveformwidget.h"
26 #include "waveform/widgets/glslwaveformwidget.h"
27 #include "waveform/widgets/glvsynctestwidget.h"
28 #include "waveform/widgets/glwaveformwidget.h"
29 #include "waveform/widgets/hsvwaveformwidget.h"
30 #include "waveform/widgets/qthsvwaveformwidget.h"
31 #include "waveform/widgets/qtrgbwaveformwidget.h"
32 #include "waveform/widgets/qtsimplewaveformwidget.h"
33 #include "waveform/widgets/qtvsynctestwidget.h"
34 #include "waveform/widgets/qtwaveformwidget.h"
35 #include "waveform/widgets/rgbwaveformwidget.h"
36 #include "waveform/widgets/softwarewaveformwidget.h"
37 #include "waveform/widgets/waveformwidgetabstract.h"
38 #include "widget/wvumeter.h"
39 #include "widget/wwaveformviewer.h"
40 
41 namespace {
42 // Returns true if the given waveform should be rendered.
shouldRenderWaveform(WaveformWidgetAbstract * pWaveformWidget)43 bool shouldRenderWaveform(WaveformWidgetAbstract* pWaveformWidget) {
44     if (pWaveformWidget == nullptr ||
45         pWaveformWidget->getWidth() == 0 ||
46         pWaveformWidget->getHeight() == 0) {
47         return false;
48     }
49 
50     auto* glw = qobject_cast<QGLWidget*>(pWaveformWidget->getWidget());
51     if (glw == nullptr) {
52         // Not a QGLWidget. We can simply use QWidget::isVisible.
53         auto* qwidget = qobject_cast<QWidget*>(pWaveformWidget->getWidget());
54         return qwidget != nullptr && qwidget->isVisible();
55     }
56 
57     if (glw == nullptr || !glw->isValid() || !glw->isVisible()) {
58         return false;
59     }
60 
61     // Strangely, a widget can have non-zero width/height, be valid and visible,
62     // yet still not show up on the screen. QWindow::isExposed tells us this.
63     const QWindow* window = glw->windowHandle();
64     if (window == nullptr || !window->isExposed()) {
65         return false;
66     }
67 
68     return true;
69 }
70 }  // anonymous namespace
71 
72 ///////////////////////////////////////////
73 
WaveformWidgetAbstractHandle()74 WaveformWidgetAbstractHandle::WaveformWidgetAbstractHandle()
75     : m_type(WaveformWidgetType::Count_WaveformwidgetType) {
76 }
77 
78 ///////////////////////////////////////////
79 
WaveformWidgetHolder()80 WaveformWidgetHolder::WaveformWidgetHolder()
81         : m_waveformWidget(nullptr),
82           m_waveformViewer(nullptr),
83           m_skinContextCache(UserSettingsPointer(), QString()) {
84 }
85 
WaveformWidgetHolder(WaveformWidgetAbstract * waveformWidget,WWaveformViewer * waveformViewer,const QDomNode & node,const SkinContext & parentContext)86 WaveformWidgetHolder::WaveformWidgetHolder(WaveformWidgetAbstract* waveformWidget,
87                                            WWaveformViewer* waveformViewer,
88                                            const QDomNode& node,
89                                            const SkinContext& parentContext)
90     : m_waveformWidget(waveformWidget),
91       m_waveformViewer(waveformViewer),
92       m_skinNodeCache(node.cloneNode()),
93       m_skinContextCache(&parentContext) {
94 }
95 
96 ///////////////////////////////////////////
97 
WaveformWidgetFactory()98 WaveformWidgetFactory::WaveformWidgetFactory()
99         // Set an empty waveform initially. We will set the correct one when skin load finishes.
100         // Concretely, we want to set a non-GL waveform when loading the skin so that the window
101         // loads correctly.
102         : m_type(WaveformWidgetType::EmptyWaveform),
103           m_configType(WaveformWidgetType::EmptyWaveform),
104           m_config(nullptr),
105           m_skipRender(false),
106           m_frameRate(30),
107           m_endOfTrackWarningTime(30),
108           m_defaultZoom(WaveformWidgetRenderer::s_waveformDefaultZoom),
109           m_zoomSync(true),
110           m_overviewNormalized(false),
111           m_openGlAvailable(false),
112           m_openGlesAvailable(false),
113           m_openGLShaderAvailable(false),
114           m_beatGridAlpha(90),
115           m_vsyncThread(nullptr),
116           m_pGuiTick(nullptr),
117           m_pVisualsManager(nullptr),
118           m_frameCnt(0),
119           m_actualFrameRate(0),
120           m_vSyncType(0),
121           m_playMarkerPosition(WaveformWidgetRenderer::s_defaultPlayMarkerPosition) {
122     m_visualGain[All] = 1.0;
123     m_visualGain[Low] = 1.0;
124     m_visualGain[Mid] = 1.0;
125     m_visualGain[High] = 1.0;
126 
127     QGLWidget* pGlWidget = SharedGLContext::getWidget();
128     if (pGlWidget && pGlWidget->isValid()) {
129         // will be false if SafeMode is enabled
130 
131         pGlWidget->show();
132         // Without a makeCurrent, hasOpenGLShaderPrograms returns false on Qt 5.
133         // and QGLFormat::openGLVersionFlags() returns the maximum known version
134         pGlWidget->makeCurrent();
135 
136         QGLFormat::OpenGLVersionFlags version = QGLFormat::openGLVersionFlags();
137 
138         auto rendererString = QString();
139         if (QOpenGLContext::currentContext()) {
140             auto glFunctions = QOpenGLFunctions();
141 
142             glFunctions.initializeOpenGLFunctions();
143             QString versionString(QLatin1String(
144                     reinterpret_cast<const char*>(glFunctions.glGetString(GL_VERSION))));
145             QString vendorString(QLatin1String(
146                     reinterpret_cast<const char*>(glFunctions.glGetString(GL_VENDOR))));
147             rendererString = QString(QLatin1String(
148                     reinterpret_cast<const char*>(glFunctions.glGetString(GL_RENDERER))));
149 
150             // Either GL or GL ES Version is set, not both.
151             qDebug() << QString("openGLVersionFlags 0x%1").arg(version, 0, 16) << versionString << vendorString << rendererString;
152         } else {
153             qDebug() << "QOpenGLContext::currentContext() returns nullptr";
154             qDebug() << "pGlWidget->->windowHandle() =" << pGlWidget->windowHandle();
155         }
156 
157         int majorGlVersion = 0;
158         int minorGlVersion = 0;
159         int majorGlesVersion = 0;
160         int minorGlesVersion = 0;
161         if (version == QGLFormat::OpenGL_Version_None) {
162             m_openGLVersion = "None";
163         } else if (version & QGLFormat::OpenGL_Version_4_3) {
164             majorGlVersion = 4;
165             minorGlVersion = 3;
166         } else if (version & QGLFormat::OpenGL_Version_4_2) {
167             majorGlVersion = 4;
168             minorGlVersion = 2;
169         } else if (version & QGLFormat::OpenGL_Version_4_1) {
170             majorGlVersion = 4;
171             minorGlVersion = 1;
172         } else if (version & QGLFormat::OpenGL_Version_4_0) {
173             majorGlVersion = 4;
174             minorGlVersion = 0;
175         } else if (version & QGLFormat::OpenGL_Version_3_3) {
176             majorGlVersion = 3;
177             minorGlVersion = 3;
178         } else if (version & QGLFormat::OpenGL_Version_3_2) {
179             majorGlVersion = 3;
180             minorGlVersion = 2;
181         } else if (version & QGLFormat::OpenGL_Version_3_1) {
182             majorGlVersion = 3;
183             minorGlVersion = 1;
184         } else if (version & QGLFormat::OpenGL_Version_3_0) {
185             majorGlVersion = 3;
186         } else if (version & QGLFormat::OpenGL_Version_2_1) {
187             majorGlVersion = 2;
188             minorGlVersion = 1;
189         } else if (version & QGLFormat::OpenGL_Version_2_0) {
190             majorGlVersion = 2;
191             minorGlVersion = 0;
192         } else if (version & QGLFormat::OpenGL_Version_1_5) {
193             majorGlVersion = 1;
194             minorGlVersion = 5;
195         } else if (version & QGLFormat::OpenGL_Version_1_4) {
196             majorGlVersion = 1;
197             minorGlVersion = 4;
198         } else if (version & QGLFormat::OpenGL_Version_1_3) {
199             majorGlVersion = 1;
200             minorGlVersion = 3;
201         } else if (version & QGLFormat::OpenGL_Version_1_2) {
202             majorGlVersion = 1;
203             minorGlVersion = 2;
204         } else if (version & QGLFormat::OpenGL_Version_1_1) {
205             majorGlVersion = 1;
206             minorGlVersion = 1;
207         } else if (version & QGLFormat::OpenGL_ES_Version_2_0) {
208             m_openGLVersion = "ES 2.0";
209             majorGlesVersion = 2;
210             minorGlesVersion = 0;
211         } else if (version & QGLFormat::OpenGL_ES_CommonLite_Version_1_1) {
212             if (version & QGLFormat::OpenGL_ES_Common_Version_1_1) {
213                 m_openGLVersion = "ES 1.1";
214             } else {
215                 m_openGLVersion = "ES Common Lite 1.1";
216             }
217             majorGlesVersion = 1;
218             minorGlesVersion = 1;
219         } else if (version & QGLFormat::OpenGL_ES_Common_Version_1_1) {
220             m_openGLVersion = "ES Common Lite 1.1";
221             majorGlesVersion = 1;
222             minorGlesVersion = 1;
223         } else if (version & QGLFormat::OpenGL_ES_CommonLite_Version_1_0) {
224             if (version & QGLFormat::OpenGL_ES_Common_Version_1_0) {
225                 m_openGLVersion = "ES 1.0";
226             } else {
227                 m_openGLVersion = "ES Common Lite 1.0";
228             }
229             majorGlesVersion = 1;
230             minorGlesVersion = 0;
231         } else if (version & QGLFormat::OpenGL_ES_Common_Version_1_0) {
232             m_openGLVersion = "ES Common Lite 1.0";
233             majorGlesVersion = 1;
234             minorGlesVersion = 0;
235         } else {
236             m_openGLVersion = QString("Unknown 0x%1")
237                 .arg(version, 0, 16);
238         }
239 
240         if (majorGlVersion != 0) {
241             m_openGLVersion = QString::number(majorGlVersion) + "."
242                     + QString::number(minorGlVersion);
243 
244 #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2)
245             if (majorGlVersion * 100 + minorGlVersion >= 201) {
246                 // Qt5 requires at least OpenGL 2.1 or OpenGL ES 2.0
247                 m_openGlAvailable = true;
248             }
249 #endif
250         } else {
251             if (majorGlesVersion * 100 + minorGlesVersion >= 200) {
252                 // Qt5 requires at least OpenGL 2.1 or OpenGL ES 2.0
253                 m_openGlesAvailable = true;
254             }
255         }
256 
257         m_openGLShaderAvailable =
258                 QGLShaderProgram::hasOpenGLShaderPrograms(
259                         pGlWidget->context());
260 
261         if (!rendererString.isEmpty()) {
262             m_openGLVersion += " (" + rendererString + ")";
263         }
264 
265         pGlWidget->hide();
266     }
267 
268     evaluateWidgets();
269     m_time.start();
270 }
271 
~WaveformWidgetFactory()272 WaveformWidgetFactory::~WaveformWidgetFactory() {
273     if (m_vsyncThread) {
274         delete m_vsyncThread;
275     }
276 }
277 
setConfig(UserSettingsPointer config)278 bool WaveformWidgetFactory::setConfig(UserSettingsPointer config) {
279     m_config = config;
280     if (!m_config) {
281         return false;
282     }
283 
284     bool ok = false;
285 
286     int frameRate = m_config->getValue(ConfigKey("[Waveform]","FrameRate"), m_frameRate);
287     m_frameRate = math_clamp(frameRate, 1, 120);
288 
289 
290     int endTime = m_config->getValueString(ConfigKey("[Waveform]","EndOfTrackWarningTime")).toInt(&ok);
291     if (ok) {
292         setEndOfTrackWarningTime(endTime);
293     } else {
294         m_config->set(ConfigKey("[Waveform]","EndOfTrackWarningTime"),
295                 ConfigValue(m_endOfTrackWarningTime));
296     }
297 
298     m_vSyncType = m_config->getValue(ConfigKey("[Waveform]","VSync"), 0);
299 
300     double defaultZoom = m_config->getValueString(ConfigKey("[Waveform]","DefaultZoom")).toDouble(&ok);
301     if (ok) {
302         setDefaultZoom(defaultZoom);
303     } else{
304         m_config->set(ConfigKey("[Waveform]","DefaultZoom"), ConfigValue(m_defaultZoom));
305     }
306 
307     bool zoomSync = m_config->getValue(ConfigKey("[Waveform]", "ZoomSynchronization"), m_zoomSync);
308     setZoomSync(zoomSync);
309 
310     int beatGridAlpha = m_config->getValue(ConfigKey("[Waveform]", "beatGridAlpha"), m_beatGridAlpha);
311     setDisplayBeatGridAlpha(beatGridAlpha);
312 
313     WaveformWidgetType::Type type = static_cast<WaveformWidgetType::Type>(
314             m_config->getValueString(ConfigKey("[Waveform]","WaveformType")).toInt(&ok));
315     // Store the widget type on m_configType for later initialization.
316     // We will initialize the objects later because of a problem with GL on QT 5.14.2 on Windows
317     if (!ok || !setWidgetType(type, &m_configType)) {
318         setWidgetType(autoChooseWidgetType(), &m_configType);
319     }
320 
321     for (int i = 0; i < FilterCount; i++) {
322         double visualGain = m_config->getValueString(
323                 ConfigKey("[Waveform]","VisualGain_" + QString::number(i))).toDouble(&ok);
324 
325         if (ok) {
326             setVisualGain(FilterIndex(i), visualGain);
327         } else {
328             m_config->set(ConfigKey("[Waveform]","VisualGain_" + QString::number(i)),
329                           QString::number(m_visualGain[i]));
330         }
331     }
332 
333     int overviewNormalized = m_config->getValueString(ConfigKey("[Waveform]","OverviewNormalized")).toInt(&ok);
334     if (ok) {
335         setOverviewNormalized(static_cast<bool>(overviewNormalized));
336     } else {
337         m_config->set(ConfigKey("[Waveform]","OverviewNormalized"), ConfigValue(m_overviewNormalized));
338     }
339 
340     m_playMarkerPosition = m_config->getValue(ConfigKey("[Waveform]","PlayMarkerPosition"),
341             WaveformWidgetRenderer::s_defaultPlayMarkerPosition);
342     setPlayMarkerPosition(m_playMarkerPosition);
343 
344     return true;
345 }
346 
destroyWidgets()347 void WaveformWidgetFactory::destroyWidgets() {
348     for (auto& holder : m_waveformWidgetHolders) {
349         WaveformWidgetAbstract* pWidget = holder.m_waveformWidget;
350         holder.m_waveformWidget = nullptr;
351         delete pWidget;
352     }
353     m_waveformWidgetHolders.clear();
354 }
355 
addTimerListener(WVuMeter * pWidget)356 void WaveformWidgetFactory::addTimerListener(WVuMeter* pWidget) {
357     // Do not hold the pointer to of timer listeners since they may be deleted.
358     // We don't activate update() or repaint() directly so listener widgets
359     // can decide whether to paint or not.
360     connect(this,
361             &WaveformWidgetFactory::waveformUpdateTick,
362             pWidget,
363             &WVuMeter::maybeUpdate,
364             Qt::DirectConnection);
365 }
366 
slotSkinLoaded()367 void WaveformWidgetFactory::slotSkinLoaded() {
368     setWidgetTypeFromConfig();
369 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && defined __WINDOWS__
370     // This regenerates the waveforms twice because of a bug found on Windows
371     // where the first one fails.
372     // The problem is that the window of the widget thinks that it is not exposed.
373     // (https://doc.qt.io/qt-5/qwindow.html#exposeEvent )
374     setWidgetTypeFromConfig();
375 #endif
376 }
377 
setWaveformWidget(WWaveformViewer * viewer,const QDomElement & node,const SkinContext & parentContext)378 bool WaveformWidgetFactory::setWaveformWidget(WWaveformViewer* viewer,
379                                               const QDomElement& node,
380                                               const SkinContext& parentContext) {
381     int index = findIndexOf(viewer);
382     if (index != -1) {
383         qDebug() << "WaveformWidgetFactory::setWaveformWidget - "\
384                     "viewer already have a waveform widget but it's not found by the factory !";
385         delete viewer->getWaveformWidget();
386     }
387 
388     // Cast to widget done just after creation because it can't be perform in
389     // constructor (pure virtual)
390     WaveformWidgetAbstract* waveformWidget = createWaveformWidget(m_type, viewer);
391     viewer->setWaveformWidget(waveformWidget);
392     viewer->setup(node, parentContext);
393 
394     // create new holder
395     WaveformWidgetHolder holder(waveformWidget, viewer, node, &parentContext);
396     if (index == -1) {
397         // add holder
398         m_waveformWidgetHolders.push_back(std::move(holder));
399         index = static_cast<int>(m_waveformWidgetHolders.size()) - 1;
400     } else {
401         // update holder
402         DEBUG_ASSERT(index >= 0);
403         m_waveformWidgetHolders[index] = std::move(holder);
404     }
405 
406     viewer->setZoom(m_defaultZoom);
407     viewer->setDisplayBeatGridAlpha(m_beatGridAlpha);
408     viewer->setPlayMarkerPosition(m_playMarkerPosition);
409     waveformWidget->resize(viewer->width(), viewer->height());
410     waveformWidget->getWidget()->show();
411     viewer->update();
412 
413     qDebug() << "WaveformWidgetFactory::setWaveformWidget - waveform widget added in factory, index" << index;
414 
415     return true;
416 }
417 
setFrameRate(int frameRate)418 void WaveformWidgetFactory::setFrameRate(int frameRate) {
419     m_frameRate = math_clamp(frameRate, 1, 120);
420     if (m_config) {
421         m_config->set(ConfigKey("[Waveform]","FrameRate"), ConfigValue(m_frameRate));
422     }
423     if (m_vsyncThread) {
424         m_vsyncThread->setSyncIntervalTimeMicros(static_cast<int>(1e6 / m_frameRate));
425     }
426 }
427 
setEndOfTrackWarningTime(int endTime)428 void WaveformWidgetFactory::setEndOfTrackWarningTime(int endTime) {
429     m_endOfTrackWarningTime = endTime;
430     if (m_config) {
431         m_config->set(ConfigKey("[Waveform]","EndOfTrackWarningTime"), ConfigValue(m_endOfTrackWarningTime));
432     }
433 }
434 
setVSyncType(int type)435 void WaveformWidgetFactory::setVSyncType(int type) {
436     if (m_config) {
437         m_config->set(ConfigKey("[Waveform]","VSync"), ConfigValue((int)type));
438     }
439 
440     m_vSyncType = type;
441     if (m_vsyncThread) {
442         m_vsyncThread->setVSyncType(type);
443     }
444 }
445 
getVSyncType()446 int WaveformWidgetFactory::getVSyncType() {
447     return m_vSyncType;
448 }
449 
setWidgetType(WaveformWidgetType::Type type)450 bool WaveformWidgetFactory::setWidgetType(WaveformWidgetType::Type type) {
451     return setWidgetType(type, &m_type);
452 }
453 
setWidgetType(WaveformWidgetType::Type type,WaveformWidgetType::Type * pCurrentType)454 bool WaveformWidgetFactory::setWidgetType(
455         WaveformWidgetType::Type type,
456         WaveformWidgetType::Type* pCurrentType) {
457     if (type == *pCurrentType) {
458         return true;
459     }
460 
461     // check if type is acceptable
462     int index = findHandleIndexFromType(type);
463     if (index > -1) {
464         // type is acceptable
465         *pCurrentType = type;
466         if (m_config) {
467             m_config->setValue(
468                     ConfigKey("[Waveform]", "WaveformType"),
469                     static_cast<int>(*pCurrentType));
470         }
471         return true;
472     }
473 
474     // fallback
475     *pCurrentType = WaveformWidgetType::EmptyWaveform;
476     if (m_config) {
477         m_config->setValue(
478                 ConfigKey("[Waveform]", "WaveformType"),
479                 static_cast<int>(*pCurrentType));
480     }
481     return false;
482 }
483 
setWidgetTypeFromConfig()484 bool WaveformWidgetFactory::setWidgetTypeFromConfig() {
485     int empty = findHandleIndexFromType(WaveformWidgetType::EmptyWaveform);
486     int desired = findHandleIndexFromType(m_configType);
487     if (desired == -1) {
488         desired = empty;
489     }
490     return setWidgetTypeFromHandle(desired, true);
491 }
492 
setWidgetTypeFromHandle(int handleIndex,bool force)493 bool WaveformWidgetFactory::setWidgetTypeFromHandle(int handleIndex, bool force) {
494     if (handleIndex < 0 || handleIndex >= m_waveformWidgetHandles.size()) {
495         qDebug() << "WaveformWidgetFactory::setWidgetType - invalid handle --> use of 'EmptyWaveform'";
496         // fallback empty type
497         setWidgetType(WaveformWidgetType::EmptyWaveform);
498         return false;
499     }
500 
501     WaveformWidgetAbstractHandle& handle = m_waveformWidgetHandles[handleIndex];
502     if (handle.m_type == m_type && !force) {
503         qDebug() << "WaveformWidgetFactory::setWidgetType - type already in use";
504         return true;
505     }
506 
507     // change the type
508     setWidgetType(handle.m_type);
509 
510     m_skipRender = true;
511     //qDebug() << "recreate start";
512 
513     //re-create/setup all waveform widgets
514     for (auto& holder : m_waveformWidgetHolders) {
515         WaveformWidgetAbstract* previousWidget = holder.m_waveformWidget;
516         TrackPointer pTrack = previousWidget->getTrackInfo();
517         //previousWidget->hold();
518         double previousZoom = previousWidget->getZoomFactor();
519         double previousPlayMarkerPosition = previousWidget->getPlayMarkerPosition();
520         int previousbeatgridAlpha = previousWidget->getBeatGridAlpha();
521         delete previousWidget;
522         WWaveformViewer* viewer = holder.m_waveformViewer;
523         WaveformWidgetAbstract* widget = createWaveformWidget(m_type, holder.m_waveformViewer);
524         holder.m_waveformWidget = widget;
525         viewer->setWaveformWidget(widget);
526         viewer->setup(holder.m_skinNodeCache, holder.m_skinContextCache);
527         viewer->setZoom(previousZoom);
528         viewer->setPlayMarkerPosition(previousPlayMarkerPosition);
529         viewer->setDisplayBeatGridAlpha(previousbeatgridAlpha);
530         // resize() doesn't seem to get called on the widget. I think Qt skips
531         // it since the size didn't change.
532         //viewer->resize(viewer->size());
533         widget->resize(viewer->width(), viewer->height());
534         widget->setTrack(pTrack);
535         widget->getWidget()->show();
536         viewer->update();
537     }
538 
539     m_skipRender = false;
540     //qDebug() << "recreate done";
541     return true;
542 }
543 
setDefaultZoom(double zoom)544 void WaveformWidgetFactory::setDefaultZoom(double zoom) {
545     m_defaultZoom = math_clamp(zoom, WaveformWidgetRenderer::s_waveformMinZoom,
546                                WaveformWidgetRenderer::s_waveformMaxZoom);
547     if (m_config) {
548         m_config->set(ConfigKey("[Waveform]","DefaultZoom"), ConfigValue(m_defaultZoom));
549     }
550 
551     for (const auto& holder : m_waveformWidgetHolders) {
552         holder.m_waveformViewer->setZoom(m_defaultZoom);
553     }
554 }
555 
setZoomSync(bool sync)556 void WaveformWidgetFactory::setZoomSync(bool sync) {
557     m_zoomSync = sync;
558     if (m_config) {
559         m_config->set(ConfigKey("[Waveform]","ZoomSynchronization"), ConfigValue(m_zoomSync));
560     }
561 
562     if (m_waveformWidgetHolders.size() == 0) {
563         return;
564     }
565 
566     double refZoom = m_waveformWidgetHolders[0].m_waveformWidget->getZoomFactor();
567     for (const auto& holder : m_waveformWidgetHolders) {
568         holder.m_waveformViewer->setZoom(refZoom);
569     }
570 }
571 
setDisplayBeatGridAlpha(int alpha)572 void WaveformWidgetFactory::setDisplayBeatGridAlpha(int alpha) {
573     m_beatGridAlpha = alpha;
574     if (m_waveformWidgetHolders.size() == 0) {
575         return;
576     }
577 
578     for (const auto& holder : m_waveformWidgetHolders) {
579         holder.m_waveformWidget->setDisplayBeatGridAlpha(m_beatGridAlpha);
580     }
581 }
582 
setVisualGain(FilterIndex index,double gain)583 void WaveformWidgetFactory::setVisualGain(FilterIndex index, double gain) {
584     m_visualGain[index] = gain;
585     if (m_config) {
586         m_config->set(ConfigKey("[Waveform]","VisualGain_" + QString::number(index)), QString::number(m_visualGain[index]));
587     }
588 }
589 
getVisualGain(FilterIndex index) const590 double WaveformWidgetFactory::getVisualGain(FilterIndex index) const {
591     return m_visualGain[index];
592 }
593 
setOverviewNormalized(bool normalize)594 void WaveformWidgetFactory::setOverviewNormalized(bool normalize) {
595     m_overviewNormalized = normalize;
596     if (m_config) {
597         m_config->set(ConfigKey("[Waveform]","OverviewNormalized"), ConfigValue(m_overviewNormalized));
598     }
599 }
600 
setPlayMarkerPosition(double position)601 void WaveformWidgetFactory::setPlayMarkerPosition(double position) {
602     //qDebug() << "setPlayMarkerPosition, position=" << position;
603     m_playMarkerPosition = position;
604     if (m_config) {
605         m_config->setValue(ConfigKey("[Waveform]", "PlayMarkerPosition"), m_playMarkerPosition);
606     }
607 
608     for (const auto& holder : m_waveformWidgetHolders) {
609         holder.m_waveformWidget->setPlayMarkerPosition(m_playMarkerPosition);
610     }
611 }
612 
notifyZoomChange(WWaveformViewer * viewer)613 void WaveformWidgetFactory::notifyZoomChange(WWaveformViewer* viewer) {
614     WaveformWidgetAbstract* pWaveformWidget = viewer->getWaveformWidget();
615     if (pWaveformWidget != nullptr && isZoomSync()) {
616         //qDebug() << "WaveformWidgetFactory::notifyZoomChange";
617         double refZoom = pWaveformWidget->getZoomFactor();
618 
619         for (std::size_t i = 0; i < m_waveformWidgetHolders.size(); ++i) {
620             WaveformWidgetHolder& holder = m_waveformWidgetHolders[i];
621             if (holder.m_waveformViewer != viewer) {
622                 holder.m_waveformViewer->setZoom(refZoom);
623             }
624         }
625     }
626 }
627 
render()628 void WaveformWidgetFactory::render() {
629     ScopedTimer t("WaveformWidgetFactory::render() %1waveforms",
630             static_cast<int>(m_waveformWidgetHolders.size()));
631 
632     //int paintersSetupTime0 = 0;
633     //int paintersSetupTime1 = 0;
634 
635     //qDebug() << "render()" << m_vsyncThread->elapsed();
636 
637     if (!m_skipRender) {
638         if (m_type) {   // no regular updates for an empty waveform
639             // next rendered frame is displayed after next buffer swap and than after VSync
640             QVarLengthArray<bool, 10> shouldRenderWaveforms(
641                     static_cast<int>(m_waveformWidgetHolders.size()));
642             for (decltype(m_waveformWidgetHolders)::size_type i = 0;
643                     i < m_waveformWidgetHolders.size();
644                     i++) {
645                 WaveformWidgetAbstract* pWaveformWidget = m_waveformWidgetHolders[i].m_waveformWidget;
646                 // Don't bother doing the pre-render work if we aren't going to
647                 // render this widget.
648                 bool shouldRender = shouldRenderWaveform(pWaveformWidget);
649                 shouldRenderWaveforms[i] = shouldRender;
650                 if (!shouldRender) {
651                     continue;
652                 }
653                 // Calculate play position for the new Frame in following run
654                 pWaveformWidget->preRender(m_vsyncThread);
655             }
656             //qDebug() << "prerender" << m_vsyncThread->elapsed();
657 
658             // It may happen that there is an artificially delayed due to
659             // anti tearing driver settings
660             // all render commands are delayed until the swap from the previous run is executed
661             for (decltype(m_waveformWidgetHolders)::size_type i = 0;
662                     i < m_waveformWidgetHolders.size();
663                     i++) {
664                 WaveformWidgetAbstract* pWaveformWidget = m_waveformWidgetHolders[i].m_waveformWidget;
665                 if (!shouldRenderWaveforms[i]) {
666                     continue;
667                 }
668                 pWaveformWidget->render();
669                 //qDebug() << "render" << i << m_vsyncThread->elapsed();
670             }
671         }
672 
673         // WSpinnys are also double-buffered QGLWidgets, like all the waveform
674         // renderers. Render all the WSpinny widgets now.
675         emit renderSpinnies(m_vsyncThread);
676 
677         // Notify all other waveform-like widgets (e.g. WSpinny's) that they should
678         // update.
679         //int t1 = m_vsyncThread->elapsed();
680         emit waveformUpdateTick();
681         //qDebug() << "emit" << m_vsyncThread->elapsed() - t1;
682 
683         m_frameCnt += 1.0f;
684         mixxx::Duration timeCnt = m_time.elapsed();
685         if (timeCnt > mixxx::Duration::fromSeconds(1)) {
686             m_time.start();
687             m_frameCnt = m_frameCnt * 1000 / timeCnt.toIntegerMillis(); // latency correction
688             emit waveformMeasured(m_frameCnt, m_vsyncThread->droppedFrames());
689             m_frameCnt = 0.0;
690         }
691     }
692 
693     m_pVisualsManager->process(m_endOfTrackWarningTime);
694     m_pGuiTick->process();
695 
696     //qDebug() << "refresh end" << m_vsyncThread->elapsed();
697     m_vsyncThread->vsyncSlotFinished();
698 }
699 
swap()700 void WaveformWidgetFactory::swap() {
701     ScopedTimer t("WaveformWidgetFactory::swap() %1waveforms",
702             static_cast<int>(m_waveformWidgetHolders.size()));
703 
704     // Do this in an extra slot to be sure to hit the desired interval
705     if (!m_skipRender) {
706         if (m_type) {   // no regular updates for an empty waveform
707             // Show rendered buffer from last render() run
708             //qDebug() << "swap() start" << m_vsyncThread->elapsed();
709             for (const auto& holder : m_waveformWidgetHolders) {
710                 WaveformWidgetAbstract* pWaveformWidget = holder.m_waveformWidget;
711 
712                 // Don't swap invalid / invisible widgets or widgets with an
713                 // unexposed window. Prevents continuous log spew of
714                 // "QOpenGLContext::swapBuffers() called with non-exposed
715                 // window, behavior is undefined" on Qt5. See Bug #1779487.
716                 if (!shouldRenderWaveform(pWaveformWidget)) {
717                     continue;
718                 }
719                 QGLWidget* glw = qobject_cast<QGLWidget*>(pWaveformWidget->getWidget());
720                 if (glw != nullptr) {
721                     if (glw->context() != QGLContext::currentContext()) {
722                         glw->makeCurrent();
723                     }
724                     glw->swapBuffers();
725                 }
726                 //qDebug() << "swap x" << m_vsyncThread->elapsed();
727             }
728         }
729         // WSpinnys are also double-buffered QGLWidgets, like all the waveform
730         // renderers. Swap all the WSpinny widgets now.
731         emit swapSpinnies();
732     }
733     //qDebug() << "swap end" << m_vsyncThread->elapsed();
734     m_vsyncThread->vsyncSlotFinished();
735 }
736 
autoChooseWidgetType() const737 WaveformWidgetType::Type WaveformWidgetFactory::autoChooseWidgetType() const {
738     if (m_openGlAvailable) {
739         if (m_openGLShaderAvailable) {
740             return WaveformWidgetType::GLSLRGBWaveform;
741         } else {
742             return WaveformWidgetType::GLRGBWaveform;
743         }
744     }
745     return WaveformWidgetType::RGBWaveform;
746 }
747 
evaluateWidgets()748 void WaveformWidgetFactory::evaluateWidgets() {
749     m_waveformWidgetHandles.clear();
750     for (int type = 0; type < WaveformWidgetType::Count_WaveformwidgetType; type++) {
751         QString widgetName;
752         bool useOpenGl;
753         bool useOpenGles;
754         bool useOpenGLShaders;
755         bool developerOnly;
756 
757         switch(type) {
758         case WaveformWidgetType::EmptyWaveform:
759             widgetName = EmptyWaveformWidget::getWaveformWidgetName();
760             useOpenGl = EmptyWaveformWidget::useOpenGl();
761             useOpenGles = EmptyWaveformWidget::useOpenGles();
762             useOpenGLShaders = EmptyWaveformWidget::useOpenGLShaders();
763             developerOnly = EmptyWaveformWidget::developerOnly();
764             break;
765         case WaveformWidgetType::SoftwareSimpleWaveform:
766             continue; // //TODO(vrince):
767         case WaveformWidgetType::SoftwareWaveform:
768 #ifdef __APPLE__
769             // Don't offer the simple renderers on macOS, they do not work with skins
770             // that load GL widgets (spinnies, waveforms) in singletons.
771             // Also excluded in enum WaveformWidgetType
772             // https://bugs.launchpad.net/bugs/1928772
773             continue;
774 #else
775             widgetName = SoftwareWaveformWidget::getWaveformWidgetName();
776             useOpenGl = SoftwareWaveformWidget::useOpenGl();
777             useOpenGles = SoftwareWaveformWidget::useOpenGles();
778             useOpenGLShaders = SoftwareWaveformWidget::useOpenGLShaders();
779             developerOnly = SoftwareWaveformWidget::developerOnly();
780             break;
781 #endif
782         case WaveformWidgetType::HSVWaveform:
783 #ifdef __APPLE__
784             continue;
785 #else
786             widgetName = HSVWaveformWidget::getWaveformWidgetName();
787             useOpenGl = HSVWaveformWidget::useOpenGl();
788             useOpenGles = HSVWaveformWidget::useOpenGles();
789             useOpenGLShaders = HSVWaveformWidget::useOpenGLShaders();
790             developerOnly = HSVWaveformWidget::developerOnly();
791             break;
792 #endif
793         case WaveformWidgetType::RGBWaveform:
794 #ifdef __APPLE__
795             continue;
796 #else
797             widgetName = RGBWaveformWidget::getWaveformWidgetName();
798             useOpenGl = RGBWaveformWidget::useOpenGl();
799             useOpenGles = RGBWaveformWidget::useOpenGles();
800             useOpenGLShaders = RGBWaveformWidget::useOpenGLShaders();
801             developerOnly = RGBWaveformWidget::developerOnly();
802             break;
803 #endif
804         case WaveformWidgetType::QtSimpleWaveform:
805             widgetName = QtSimpleWaveformWidget::getWaveformWidgetName();
806             useOpenGl = QtSimpleWaveformWidget::useOpenGl();
807             useOpenGles = QtSimpleWaveformWidget::useOpenGles();
808             useOpenGLShaders = QtSimpleWaveformWidget::useOpenGLShaders();
809             developerOnly = QtSimpleWaveformWidget::developerOnly();
810             break;
811         case WaveformWidgetType::QtWaveform:
812             widgetName = QtWaveformWidget::getWaveformWidgetName();
813             useOpenGl = QtWaveformWidget::useOpenGl();
814             useOpenGles = QtWaveformWidget::useOpenGles();
815             useOpenGLShaders = QtWaveformWidget::useOpenGLShaders();
816             developerOnly = QtWaveformWidget::developerOnly();
817             break;
818         case WaveformWidgetType::GLSimpleWaveform:
819             widgetName = GLSimpleWaveformWidget::getWaveformWidgetName();
820             useOpenGl = GLSimpleWaveformWidget::useOpenGl();
821             useOpenGles = GLSimpleWaveformWidget::useOpenGles();
822             useOpenGLShaders = GLSimpleWaveformWidget::useOpenGLShaders();
823             developerOnly = GLSimpleWaveformWidget::developerOnly();
824             break;
825         case WaveformWidgetType::GLFilteredWaveform:
826             widgetName = GLWaveformWidget::getWaveformWidgetName();
827             useOpenGl = GLWaveformWidget::useOpenGl();
828             useOpenGles = GLWaveformWidget::useOpenGles();
829             useOpenGLShaders = GLWaveformWidget::useOpenGLShaders();
830             developerOnly = GLWaveformWidget::developerOnly();
831             break;
832         case WaveformWidgetType::GLSLFilteredWaveform:
833             widgetName = GLSLFilteredWaveformWidget::getWaveformWidgetName();
834             useOpenGl = GLSLFilteredWaveformWidget::useOpenGl();
835             useOpenGles = GLSLFilteredWaveformWidget::useOpenGles();
836             useOpenGLShaders = GLSLFilteredWaveformWidget::useOpenGLShaders();
837             developerOnly = GLSLFilteredWaveformWidget::developerOnly();
838             break;
839         case WaveformWidgetType::GLSLRGBWaveform:
840             widgetName = GLSLRGBWaveformWidget::getWaveformWidgetName();
841             useOpenGl = GLSLRGBWaveformWidget::useOpenGl();
842             useOpenGles = GLSLRGBWaveformWidget::useOpenGles();
843             useOpenGLShaders = GLSLRGBWaveformWidget::useOpenGLShaders();
844             developerOnly = GLSLRGBWaveformWidget::developerOnly();
845             break;
846         case WaveformWidgetType::GLVSyncTest:
847             widgetName = GLVSyncTestWidget::getWaveformWidgetName();
848             useOpenGl = GLVSyncTestWidget::useOpenGl();
849             useOpenGles =  GLVSyncTestWidget::useOpenGles();
850             useOpenGLShaders = GLVSyncTestWidget::useOpenGLShaders();
851             developerOnly = GLVSyncTestWidget::developerOnly();
852             break;
853         case WaveformWidgetType::GLRGBWaveform:
854             widgetName = GLRGBWaveformWidget::getWaveformWidgetName();
855             useOpenGl = GLRGBWaveformWidget::useOpenGl();
856             useOpenGles =  GLRGBWaveformWidget::useOpenGles();
857             useOpenGLShaders = GLRGBWaveformWidget::useOpenGLShaders();
858             developerOnly = GLRGBWaveformWidget::developerOnly();
859             break;
860         case WaveformWidgetType::QtVSyncTest:
861             widgetName = QtVSyncTestWidget::getWaveformWidgetName();
862             useOpenGl = QtVSyncTestWidget::useOpenGl();
863             useOpenGles =  QtVSyncTestWidget::useOpenGles();
864             useOpenGLShaders = QtVSyncTestWidget::useOpenGLShaders();
865             developerOnly = QtVSyncTestWidget::developerOnly();
866             break;
867         case WaveformWidgetType::QtHSVWaveform:
868             widgetName = QtHSVWaveformWidget::getWaveformWidgetName();
869             useOpenGl = QtHSVWaveformWidget::useOpenGl();
870             useOpenGles = QtHSVWaveformWidget::useOpenGles();
871             useOpenGLShaders = QtHSVWaveformWidget::useOpenGLShaders();
872             developerOnly = QtHSVWaveformWidget::developerOnly();
873             break;
874         case WaveformWidgetType::QtRGBWaveform:
875             widgetName = QtRGBWaveformWidget::getWaveformWidgetName();
876             useOpenGl = QtRGBWaveformWidget::useOpenGl();
877             useOpenGles = QtRGBWaveformWidget::useOpenGles();
878             useOpenGLShaders = QtRGBWaveformWidget::useOpenGLShaders();
879             developerOnly = QtRGBWaveformWidget::developerOnly();
880             break;
881         default:
882             DEBUG_ASSERT(!"Unexpected WaveformWidgetType");
883             continue;
884         }
885 
886         bool active = true;
887         if (isOpenGlAvailable()) {
888             if (useOpenGles && !useOpenGl) {
889                 active = false;
890             } else if (useOpenGLShaders && !isOpenGlShaderAvailable()) {
891                 active = false;
892             } else {
893                 if (useOpenGLShaders) {
894                     widgetName += " " + tr("(GLSL)");
895                 } else if (useOpenGl) {
896                     widgetName += " " + tr("(GL)");
897                 }
898             }
899         } else if (isOpenGlesAvailable()) {
900             if (useOpenGl && !useOpenGles) {
901                 active = false;
902             } else if (useOpenGLShaders && !isOpenGlShaderAvailable()) {
903                 active = false;
904             } else {
905                 if (useOpenGLShaders) {
906                     widgetName += " " + tr("(GLSL ES)");
907                 } else if (useOpenGles) {
908                     widgetName += " " + tr("(GL ES)");
909                 }
910             }
911         } else {
912             // No sufficiant GL supptor
913             if (useOpenGles || useOpenGl || useOpenGLShaders) {
914                 active = false;
915             }
916         }
917 
918         if (developerOnly && !CmdlineArgs::Instance().getDeveloper()) {
919             active = false;
920         }
921 
922         if (active) {
923             // add new handle for each available widget type
924             WaveformWidgetAbstractHandle handle;
925             handle.m_displayString = widgetName;
926             handle.m_type = (WaveformWidgetType::Type)type;
927 
928             m_waveformWidgetHandles.push_back(handle);
929         }
930     }
931 }
932 
createWaveformWidget(WaveformWidgetType::Type type,WWaveformViewer * viewer)933 WaveformWidgetAbstract* WaveformWidgetFactory::createWaveformWidget(
934         WaveformWidgetType::Type type, WWaveformViewer* viewer) {
935     WaveformWidgetAbstract* widget = nullptr;
936     if (viewer) {
937         if (CmdlineArgs::Instance().getSafeMode()) {
938             type = WaveformWidgetType::EmptyWaveform;
939         }
940 
941         switch(type) {
942         case WaveformWidgetType::SoftwareWaveform:
943             widget = new SoftwareWaveformWidget(viewer->getGroup(), viewer);
944             break;
945         case WaveformWidgetType::HSVWaveform:
946             widget = new HSVWaveformWidget(viewer->getGroup(), viewer);
947             break;
948         case WaveformWidgetType::RGBWaveform:
949             widget = new RGBWaveformWidget(viewer->getGroup(), viewer);
950             break;
951         case WaveformWidgetType::QtSimpleWaveform:
952             widget = new QtSimpleWaveformWidget(viewer->getGroup(), viewer);
953             break;
954         case WaveformWidgetType::QtWaveform:
955             widget = new QtWaveformWidget(viewer->getGroup(), viewer);
956             break;
957         case WaveformWidgetType::GLSimpleWaveform:
958             widget = new GLSimpleWaveformWidget(viewer->getGroup(), viewer);
959             break;
960         case WaveformWidgetType::GLFilteredWaveform:
961             widget = new GLWaveformWidget(viewer->getGroup(), viewer);
962             break;
963         case WaveformWidgetType::GLRGBWaveform:
964             widget = new GLRGBWaveformWidget(viewer->getGroup(), viewer);
965             break;
966         case WaveformWidgetType::GLSLFilteredWaveform:
967             widget = new GLSLFilteredWaveformWidget(viewer->getGroup(), viewer);
968             break;
969         case WaveformWidgetType::GLSLRGBWaveform:
970             widget = new GLSLRGBWaveformWidget(viewer->getGroup(), viewer);
971             break;
972         case WaveformWidgetType::GLVSyncTest:
973             widget = new GLVSyncTestWidget(viewer->getGroup(), viewer);
974             break;
975         case WaveformWidgetType::QtVSyncTest:
976             widget = new QtVSyncTestWidget(viewer->getGroup(), viewer);
977             break;
978         case WaveformWidgetType::QtHSVWaveform:
979             widget = new QtHSVWaveformWidget(viewer->getGroup(), viewer);
980             break;
981         case WaveformWidgetType::QtRGBWaveform:
982             widget = new QtRGBWaveformWidget(viewer->getGroup(), viewer);
983             break;
984         default:
985         //case WaveformWidgetType::SoftwareSimpleWaveform: TODO: (vrince)
986         //case WaveformWidgetType::EmptyWaveform:
987             widget = new EmptyWaveformWidget(viewer->getGroup(), viewer);
988             break;
989         }
990         widget->castToQWidget();
991         if (!widget->isValid()) {
992             qWarning() << "failed to init WafeformWidget" << type << "fall back to \"Empty\"";
993             delete widget;
994             widget = new EmptyWaveformWidget(viewer->getGroup(), viewer);
995             widget->castToQWidget();
996             if (!widget->isValid()) {
997                 qWarning() << "failed to init EmptyWaveformWidget";
998                 delete widget;
999                 widget = nullptr;
1000             }
1001         }
1002     }
1003     return widget;
1004 }
1005 
findIndexOf(WWaveformViewer * viewer) const1006 int WaveformWidgetFactory::findIndexOf(WWaveformViewer* viewer) const {
1007     for (int i = 0; i < (int)m_waveformWidgetHolders.size(); i++) {
1008         if (m_waveformWidgetHolders[i].m_waveformViewer == viewer) {
1009             return i;
1010         }
1011     }
1012     return -1;
1013 }
1014 
startVSync(GuiTick * pGuiTick,VisualsManager * pVisualsManager)1015 void WaveformWidgetFactory::startVSync(GuiTick* pGuiTick, VisualsManager* pVisualsManager) {
1016     m_pGuiTick = pGuiTick;
1017     m_pVisualsManager = pVisualsManager;
1018     m_vsyncThread = new VSyncThread(this);
1019     m_vsyncThread->setObjectName(QStringLiteral("VSync"));
1020     m_vsyncThread->setVSyncType(m_vSyncType);
1021     m_vsyncThread->setSyncIntervalTimeMicros(static_cast<int>(1e6 / m_frameRate));
1022 
1023     connect(m_vsyncThread,
1024             &VSyncThread::vsyncRender,
1025             this,
1026             &WaveformWidgetFactory::render);
1027     connect(m_vsyncThread,
1028             &VSyncThread::vsyncSwap,
1029             this,
1030             &WaveformWidgetFactory::swap);
1031 
1032     m_vsyncThread->start(QThread::NormalPriority);
1033 }
1034 
getAvailableVSyncTypes(QList<QPair<int,QString>> * pList)1035 void WaveformWidgetFactory::getAvailableVSyncTypes(QList<QPair<int, QString > >* pList) {
1036     m_vsyncThread->getAvailableVSyncTypes(pList);
1037 }
1038 
findTypeFromHandleIndex(int index)1039 WaveformWidgetType::Type WaveformWidgetFactory::findTypeFromHandleIndex(int index) {
1040     WaveformWidgetType::Type type = WaveformWidgetType::Count_WaveformwidgetType;
1041     if (index >= 0 && index < m_waveformWidgetHandles.size()) {
1042         type = m_waveformWidgetHandles[index].m_type;
1043     }
1044     return type;
1045 }
1046 
findHandleIndexFromType(WaveformWidgetType::Type type)1047 int WaveformWidgetFactory::findHandleIndexFromType(WaveformWidgetType::Type type) {
1048     int index = -1;
1049     for (int i = 0; i < m_waveformWidgetHandles.size(); i++) {
1050         WaveformWidgetAbstractHandle& handle = m_waveformWidgetHandles[i];
1051         if (handle.m_type == type) {
1052             index = i;
1053         }
1054     }
1055     return index;
1056 }
1057