]> git.sesse.net Git - kdenlive/blob - src/scopes/scopemanager.cpp
283dc3417ccf6504632e2bd3b87d71085765f903
[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(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
206     // Connect new renderer
207     if (m_lastConnectedRenderer != NULL) {
208         b &= connect(m_lastConnectedRenderer, SIGNAL(frameUpdated(const QImage)),
209                 this, SLOT(slotDistributeFrame(const QImage)), Qt::UniqueConnection);
210         b &= connect(m_lastConnectedRenderer, SIGNAL(audioSamplesSignal(QVector<int16_t>,int,int,int)),
211                 this, SLOT(slotDistributeAudio(QVector<int16_t>,int,int,int)), Qt::UniqueConnection);
212         Q_ASSERT(b);
213
214 #ifdef DEBUG_SM
215         qDebug() << "Renderer connected to ScopeManager: " << m_lastConnectedRenderer->name();
216 #endif
217
218         if (imagesAcceptedByScopes()) {
219 #ifdef DEBUG_SM
220             qDebug() << "Some scopes accept images, triggering frame update.";
221 #endif
222             m_lastConnectedRenderer->sendFrameUpdate();
223         }
224     }
225 }
226
227
228 void ScopeManager::slotCheckActiveScopes()
229 {
230 #ifdef DEBUG_SM
231     qDebug() << "Checking active scopes ...";
232 #endif
233     checkActiveAudioScopes();
234     checkActiveColourScopes();
235 }
236
237
238 bool ScopeManager::audioAcceptedByScopes() const
239 {
240     bool accepted = false;
241     for (int i = 0; i < m_audioScopes.size(); i++) {
242         if (!m_audioScopes[i].scope->visibleRegion().isEmpty() && m_audioScopes[i].scope->autoRefreshEnabled()) {
243             accepted = true;
244             break;
245         }
246     }
247 #ifdef DEBUG_SM
248     qDebug() << "Any scope accepting audio? " << accepted;
249 #endif
250     return accepted;
251 }
252 bool ScopeManager::imagesAcceptedByScopes() const
253 {
254     bool accepted = false;
255     for (int i = 0; i < m_colorScopes.size(); i++) {
256         if (!m_colorScopes[i].scope->visibleRegion().isEmpty() && m_colorScopes[i].scope->autoRefreshEnabled()) {
257             accepted = true;
258             break;
259         }
260     }
261 #ifdef DEBUG_SM
262     qDebug() << "Any scope accepting images? " << accepted;
263 #endif
264     return accepted;
265 }
266
267
268
269 void ScopeManager::checkActiveAudioScopes()
270 {
271     bool audioStillRequested = audioAcceptedByScopes();
272
273 #ifdef DEBUG_SM
274     qDebug() << "ScopeManager: New audio data still requested? " << audioStillRequested;
275 #endif
276
277     KdenliveSettings::setMonitor_audio(audioStillRequested);
278     m_monitorManager->slotUpdateAudioMonitoring();
279 }
280 void ScopeManager::checkActiveColourScopes()
281 {
282     bool imageStillRequested = imagesAcceptedByScopes();
283
284 #ifdef DEBUG_SM
285     qDebug() << "ScopeManager: New frames still requested? " << imageStillRequested;
286 #endif
287
288     // Notify monitors whether frames are still required
289     Monitor *monitor;
290     monitor = static_cast<Monitor*>( m_monitorManager->monitor(Kdenlive::projectMonitor) );
291     if (monitor != NULL) { 
292         if (monitor->effectSceneDisplayed()) monitor->render->sendFrameForAnalysis = true;
293         else monitor->render->sendFrameForAnalysis = imageStillRequested;
294     }
295
296     monitor = static_cast<Monitor*>( m_monitorManager->monitor(Kdenlive::clipMonitor) );
297     if (monitor != NULL) { monitor->render->sendFrameForAnalysis = imageStillRequested; }
298
299     RecMonitor *recMonitor = static_cast<RecMonitor*>( m_monitorManager->monitor(Kdenlive::recordMonitor) );
300     if (recMonitor != NULL) { recMonitor->analyseFrames(imageStillRequested); }
301 }
302