1 /***************************************************************************
2 * Copyright (C) 2011 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 ***************************************************************************/
11 #include "scopemanager.h"
13 #include <QDockWidget>
15 #include "definitions.h"
16 #include "monitormanager.h"
17 #include "kdenlivesettings.h"
21 #include <QtCore/QDebug>
24 ScopeManager::ScopeManager(MonitorManager *monitorManager) :
25 m_monitorManager(monitorManager),
26 m_lastConnectedRenderer(NULL)
28 m_signalMapper = new QSignalMapper(this);
31 b &= connect(m_monitorManager, SIGNAL(checkColorScopes()), this, SLOT(slotUpdateActiveRenderer()));
32 b &= connect(m_monitorManager, SIGNAL(clearScopes()), this, SLOT(slotClearColorScopes()));
33 b &= connect(m_signalMapper, SIGNAL(mapped(QString)), this, SLOT(slotRequestFrame(QString)));
36 slotUpdateActiveRenderer();
39 bool ScopeManager::addScope(AbstractAudioScopeWidget *audioScope, QDockWidget *audioScopeWidget)
43 // Only add the scope if it does not exist yet in the list
44 for (int i = 0; i < m_audioScopes.size(); ++i) {
45 if (m_audioScopes[i].scope == audioScope) {
51 // Add scope to the list, set up signal/slot connections
53 qDebug() << "Adding scope to scope manager: " << audioScope->widgetName();
56 m_signalMapper->setMapping(audioScopeWidget, QString(audioScope->widgetName()));
59 asd.scope = audioScope;
60 asd.scopeDockWidget = audioScopeWidget;
61 m_audioScopes.append(asd);
64 b &= connect(audioScope, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotCheckActiveScopes()));
65 // b &= connect(audioScope, SIGNAL(signalFrameRequest(QString)), this, SLOT(slotRequestFrame(QString)));
66 if (audioScopeWidget != NULL) {
67 b &= connect(audioScopeWidget, SIGNAL(visibilityChanged(bool)), this, SLOT(slotCheckActiveScopes()));
68 b &= connect(audioScopeWidget, SIGNAL(visibilityChanged(bool)), m_signalMapper, SLOT(map()));
76 bool ScopeManager::addScope(AbstractGfxScopeWidget *colorScope, QDockWidget *colorScopeWidget)
80 for (int i = 0; i < m_colorScopes.size(); ++i) {
81 if (m_colorScopes[i].scope == colorScope) {
88 qDebug() << "Adding scope to scope manager: " << colorScope->widgetName();
91 m_signalMapper->setMapping(colorScopeWidget, QString(colorScope->widgetName()));
94 gsd.scope = colorScope;
95 gsd.scopeDockWidget = colorScopeWidget;
96 m_colorScopes.append(gsd);
99 b &= connect(colorScope, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotCheckActiveScopes()));
100 b &= connect(colorScope, SIGNAL(signalFrameRequest(QString)), this, SLOT(slotRequestFrame(QString)));
101 if (colorScopeWidget != NULL) {
102 b &= connect(colorScopeWidget, SIGNAL(visibilityChanged(bool)), this, SLOT(slotCheckActiveScopes()));
103 b &= connect(colorScopeWidget, SIGNAL(visibilityChanged(bool)), m_signalMapper, SLOT(map()));
113 void ScopeManager::slotDistributeAudio(const QVector<int16_t> &sampleData, int freq, int num_channels, int num_samples)
116 qDebug() << "ScopeManager: Starting to distribute audio.";
118 for (int i = 0; i < m_audioScopes.size(); ++i) {
119 // Distribute audio to all scopes that are visible and want to be refreshed
120 if (!m_audioScopes[i].scope->visibleRegion().isEmpty()) {
121 if (m_audioScopes[i].scope->autoRefreshEnabled()) {
122 m_audioScopes[i].scope->slotReceiveAudio(sampleData, freq, num_channels, num_samples);
124 qDebug() << "ScopeManager: Distributed audio to " << m_audioScopes[i].scope->widgetName();
130 checkActiveAudioScopes();
132 void ScopeManager::slotDistributeFrame(const QImage &image)
135 qDebug() << "ScopeManager: Starting to distribute frame.";
137 for (int i = 0; i < m_colorScopes.size(); ++i) {
138 if (!m_colorScopes[i].scope->visibleRegion().isEmpty()) {
139 if (m_colorScopes[i].scope->autoRefreshEnabled()) {
140 m_colorScopes[i].scope->slotRenderZoneUpdated(image);
142 qDebug() << "ScopeManager: Distributed frame to " << m_colorScopes[i].scope->widgetName();
144 } else if (m_colorScopes[i].singleFrameRequested) {
145 // Special case: Auto refresh is disabled, but user requested an update (e.g. by clicking).
146 // Force the scope to update.
147 m_colorScopes[i].singleFrameRequested = false;
148 m_colorScopes[i].scope->slotRenderZoneUpdated(image);
149 m_colorScopes[i].scope->forceUpdateScope();
151 qDebug() << "ScopeManager: Distributed forced frame to " << m_colorScopes[i].scope->widgetName();
157 checkActiveColourScopes();
161 void ScopeManager::slotRequestFrame(const QString &widgetName)
164 qDebug() << "ScopeManager: New frame was requested by " << widgetName;
167 // Search for the scope in the lists and tag it to trigger a forced update
168 // in the distribution slots
169 for (int i = 0; i < m_colorScopes.size(); ++i) {
170 if (m_colorScopes[i].scope->widgetName() == widgetName) {
171 m_colorScopes[i].singleFrameRequested = true;
175 for (int i = 0; i < m_audioScopes.size(); ++i) {
176 if (m_audioScopes[i].scope->widgetName() == widgetName) {
177 m_audioScopes[i].singleFrameRequested = true;
181 if (m_lastConnectedRenderer) m_lastConnectedRenderer->sendFrameUpdate();
185 void ScopeManager::slotClearColorScopes()
187 m_lastConnectedRenderer = NULL;
191 void ScopeManager::slotUpdateActiveRenderer()
195 // Disconnect old connections
196 if (m_lastConnectedRenderer != NULL) {
198 qDebug() << "Disconnected previous renderer: " << m_lastConnectedRenderer->name();
200 b &= m_lastConnectedRenderer->disconnect(this);
204 m_lastConnectedRenderer = m_monitorManager->activeRenderer();
205 // DVD monitor shouldn't be monitored or will cause crash on deletion
206 if (m_monitorManager->isActive(Kdenlive::dvdMonitor)) m_lastConnectedRenderer = NULL;
208 // Connect new renderer
209 if (m_lastConnectedRenderer != NULL) {
210 b &= connect(m_lastConnectedRenderer, SIGNAL(frameUpdated(QImage)),
211 this, SLOT(slotDistributeFrame(QImage)), Qt::UniqueConnection);
212 b &= connect(m_lastConnectedRenderer, SIGNAL(audioSamplesSignal(QVector<int16_t>,int,int,int)),
213 this, SLOT(slotDistributeAudio(QVector<int16_t>,int,int,int)), Qt::UniqueConnection);
217 qDebug() << "Renderer connected to ScopeManager: " << m_lastConnectedRenderer->name();
220 if (imagesAcceptedByScopes()) {
222 qDebug() << "Some scopes accept images, triggering frame update.";
224 m_lastConnectedRenderer->sendFrameUpdate();
230 void ScopeManager::slotCheckActiveScopes()
233 qDebug() << "Checking active scopes ...";
235 checkActiveAudioScopes();
236 checkActiveColourScopes();
240 bool ScopeManager::audioAcceptedByScopes() const
242 bool accepted = false;
243 for (int i = 0; i < m_audioScopes.size(); ++i) {
244 if (!m_audioScopes[i].scope->visibleRegion().isEmpty() && m_audioScopes[i].scope->autoRefreshEnabled()) {
250 qDebug() << "Any scope accepting audio? " << accepted;
254 bool ScopeManager::imagesAcceptedByScopes() const
256 bool accepted = false;
257 for (int i = 0; i < m_colorScopes.size(); ++i) {
258 if (!m_colorScopes[i].scope->visibleRegion().isEmpty() && m_colorScopes[i].scope->autoRefreshEnabled()) {
264 qDebug() << "Any scope accepting images? " << accepted;
271 void ScopeManager::checkActiveAudioScopes()
273 bool audioStillRequested = audioAcceptedByScopes();
276 qDebug() << "ScopeManager: New audio data still requested? " << audioStillRequested;
279 KdenliveSettings::setMonitor_audio(audioStillRequested);
280 m_monitorManager->slotUpdateAudioMonitoring();
282 void ScopeManager::checkActiveColourScopes()
284 bool imageStillRequested = imagesAcceptedByScopes();
287 qDebug() << "ScopeManager: New frames still requested? " << imageStillRequested;
290 // Notify monitors whether frames are still required
292 monitor = static_cast<Monitor*>( m_monitorManager->monitor(Kdenlive::projectMonitor) );
293 if (monitor != NULL) {
294 if (monitor->effectSceneDisplayed()) monitor->render->sendFrameForAnalysis = true;
295 else monitor->render->sendFrameForAnalysis = imageStillRequested;
298 monitor = static_cast<Monitor*>( m_monitorManager->monitor(Kdenlive::clipMonitor) );
299 if (monitor != NULL) { monitor->render->sendFrameForAnalysis = imageStillRequested; }
301 RecMonitor *recMonitor = static_cast<RecMonitor*>( m_monitorManager->monitor(Kdenlive::recordMonitor) );
302 if (recMonitor != NULL) { recMonitor->analyseFrames(imageStillRequested); }
306 #include "scopemanager.moc"