]> git.sesse.net Git - kdenlive/blob - src/scopes/scopemanager.cpp
cb76f7ddcb93d1896b5d7d33c7dde13df5fff90f
[kdenlive] / src / scopes / scopemanager.cpp
1 /***************************************************************************
2  *   Copyright (C) 2011 by Simon Andreas Eugster (simon.eu@gmail.com)      *
3  *   This file is part of kdenlive. See www.kdenlive.org.                  *
4  *                                                                         *
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  ***************************************************************************/
10
11 #include "scopemanager.h"
12
13 #include <QDockWidget>
14
15 #include "definitions.h"
16 #include "monitormanager.h"
17 #include "kdenlivesettings.h"
18
19 //#define DEBUG_SM
20 #ifdef DEBUG_SM
21 #include <QtCore/QDebug>
22 #endif
23
24 ScopeManager::ScopeManager(MonitorManager *monitorManager) :
25     m_monitorManager(monitorManager),
26     m_lastConnectedRenderer(NULL)
27 {
28     m_signalMapper = new QSignalMapper(this);
29
30     bool b = true;
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)));
34     Q_ASSERT(b);
35
36     slotUpdateActiveRenderer();
37 }
38
39 bool ScopeManager::addScope(AbstractAudioScopeWidget *audioScope, QDockWidget *audioScopeWidget)
40 {
41     bool added = false;
42     int exists = false;
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) {
46             exists = true;
47             break;
48         }
49     }
50     if (!exists) {
51         // Add scope to the list, set up signal/slot connections
52 #ifdef DEBUG_SM
53         qDebug() << "Adding scope to scope manager: " << audioScope->widgetName();
54 #endif
55
56         m_signalMapper->setMapping(audioScopeWidget, QString(audioScope->widgetName()));
57
58         AudioScopeData asd;
59         asd.scope = audioScope;
60         asd.scopeDockWidget = audioScopeWidget;
61         m_audioScopes.append(asd);
62
63         bool b = true;
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()));
69         }
70         Q_ASSERT(b);
71
72         added = true;
73     }
74     return added;
75 }
76 bool ScopeManager::addScope(AbstractGfxScopeWidget *colorScope, QDockWidget *colorScopeWidget)
77 {
78     bool added = false;
79     int exists = false;
80     for (int i = 0; i < m_colorScopes.size(); ++i) {
81         if (m_colorScopes[i].scope == colorScope) {
82             exists = true;
83             break;
84         }
85     }
86     if (!exists) {
87 #ifdef DEBUG_SM
88         qDebug() << "Adding scope to scope manager: " << colorScope->widgetName();
89 #endif
90
91         m_signalMapper->setMapping(colorScopeWidget, QString(colorScope->widgetName()));
92
93         GfxScopeData gsd;
94         gsd.scope = colorScope;
95         gsd.scopeDockWidget = colorScopeWidget;
96         m_colorScopes.append(gsd);
97
98         bool b = true;
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()));
104         }
105         Q_ASSERT(b);
106
107         added = true;
108     }
109     return added;
110 }
111
112
113 void ScopeManager::slotDistributeAudio(const QVector<int16_t> &sampleData, int freq, int num_channels, int num_samples)
114 {
115 #ifdef DEBUG_SM
116     qDebug() << "ScopeManager: Starting to distribute audio.";
117 #endif
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);
123 #ifdef DEBUG_SM
124                 qDebug() << "ScopeManager: Distributed audio to " << m_audioScopes[i].scope->widgetName();
125 #endif
126             }
127         }
128     }
129
130     checkActiveAudioScopes();
131 }
132 void ScopeManager::slotDistributeFrame(const QImage &image)
133 {
134 #ifdef DEBUG_SM
135     qDebug() << "ScopeManager: Starting to distribute frame.";
136 #endif
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);
141 #ifdef DEBUG_SM
142                 qDebug() << "ScopeManager: Distributed frame to " << m_colorScopes[i].scope->widgetName();
143 #endif
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();
150 #ifdef DEBUG_SM
151                 qDebug() << "ScopeManager: Distributed forced frame to " << m_colorScopes[i].scope->widgetName();
152 #endif
153             }
154         }
155     }
156
157     checkActiveColourScopes();
158 }
159
160
161 void ScopeManager::slotRequestFrame(const QString &widgetName)
162 {
163 #ifdef DEBUG_SM
164     qDebug() << "ScopeManager: New frame was requested by " << widgetName;
165 #endif
166
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;
172             break;
173         }
174     }
175     for (int i = 0; i < m_audioScopes.size(); ++i) {
176         if (m_audioScopes[i].scope->widgetName() == widgetName) {
177             m_audioScopes[i].singleFrameRequested = true;
178             break;
179         }
180     }
181     if (m_lastConnectedRenderer) m_lastConnectedRenderer->sendFrameUpdate();
182 }
183
184
185 void ScopeManager::slotClearColorScopes()
186 {
187     m_lastConnectedRenderer = NULL;
188 }
189
190
191 void ScopeManager::slotUpdateActiveRenderer()
192 {
193     bool b = true;
194
195     // Disconnect old connections
196     if (m_lastConnectedRenderer != NULL) {
197 #ifdef DEBUG_SM
198         qDebug() << "Disconnected previous renderer: " << m_lastConnectedRenderer->name();
199 #endif
200         b &= m_lastConnectedRenderer->disconnect(this);
201         Q_ASSERT(b);
202     }
203
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;
207
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);
214         Q_ASSERT(b);
215
216 #ifdef DEBUG_SM
217         qDebug() << "Renderer connected to ScopeManager: " << m_lastConnectedRenderer->name();
218 #endif
219
220         if (imagesAcceptedByScopes()) {
221 #ifdef DEBUG_SM
222             qDebug() << "Some scopes accept images, triggering frame update.";
223 #endif
224             m_lastConnectedRenderer->sendFrameUpdate();
225         }
226     }
227 }
228
229
230 void ScopeManager::slotCheckActiveScopes()
231 {
232 #ifdef DEBUG_SM
233     qDebug() << "Checking active scopes ...";
234 #endif
235     checkActiveAudioScopes();
236     checkActiveColourScopes();
237 }
238
239
240 bool ScopeManager::audioAcceptedByScopes() const
241 {
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()) {
245             accepted = true;
246             break;
247         }
248     }
249 #ifdef DEBUG_SM
250     qDebug() << "Any scope accepting audio? " << accepted;
251 #endif
252     return accepted;
253 }
254 bool ScopeManager::imagesAcceptedByScopes() const
255 {
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()) {
259             accepted = true;
260             break;
261         }
262     }
263 #ifdef DEBUG_SM
264     qDebug() << "Any scope accepting images? " << accepted;
265 #endif
266     return accepted;
267 }
268
269
270
271 void ScopeManager::checkActiveAudioScopes()
272 {
273     bool audioStillRequested = audioAcceptedByScopes();
274
275 #ifdef DEBUG_SM
276     qDebug() << "ScopeManager: New audio data still requested? " << audioStillRequested;
277 #endif
278
279     KdenliveSettings::setMonitor_audio(audioStillRequested);
280     m_monitorManager->slotUpdateAudioMonitoring();
281 }
282 void ScopeManager::checkActiveColourScopes()
283 {
284     bool imageStillRequested = imagesAcceptedByScopes();
285
286 #ifdef DEBUG_SM
287     qDebug() << "ScopeManager: New frames still requested? " << imageStillRequested;
288 #endif
289
290     // Notify monitors whether frames are still required
291     Monitor *monitor;
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;
296     }
297
298     monitor = static_cast<Monitor*>( m_monitorManager->monitor(Kdenlive::clipMonitor) );
299     if (monitor != NULL) { monitor->render->sendFrameForAnalysis = imageStillRequested; }
300
301     RecMonitor *recMonitor = static_cast<RecMonitor*>( m_monitorManager->monitor(Kdenlive::recordMonitor) );
302     if (recMonitor != NULL) { recMonitor->analyseFrames(imageStillRequested); }
303 }
304
305
306 #include "scopemanager.moc"