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_signalMapper, SIGNAL(mapped(QString)), this, SLOT(slotRequestFrame(QString)));
35 slotUpdateActiveRenderer();
38 bool ScopeManager::addScope(AbstractAudioScopeWidget *audioScope, QDockWidget *audioScopeWidget)
42 // Only add the scope if it does not exist yet in the list
43 for (int i = 0; i < m_audioScopes.size(); i++) {
44 if (m_audioScopes[i].scope == audioScope) {
50 // Add scope to the list, set up signal/slot connections
52 qDebug() << "Adding scope to scope manager: " << audioScope->widgetName();
55 m_signalMapper->setMapping(audioScopeWidget, QString(audioScope->widgetName()));
58 asd.scope = audioScope;
59 asd.scopeDockWidget = audioScopeWidget;
60 m_audioScopes.append(asd);
63 b &= connect(audioScope, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotCheckActiveScopes()));
64 // b &= connect(audioScope, SIGNAL(signalFrameRequest(QString)), this, SLOT(slotRequestFrame(QString)));
65 if (audioScopeWidget != NULL) {
66 b &= connect(audioScopeWidget, SIGNAL(visibilityChanged(bool)), this, SLOT(slotCheckActiveScopes()));
67 b &= connect(audioScopeWidget, SIGNAL(visibilityChanged(bool)), m_signalMapper, SLOT(map()));
75 bool ScopeManager::addScope(AbstractGfxScopeWidget *colorScope, QDockWidget *colorScopeWidget)
79 for (int i = 0; i < m_colorScopes.size(); i++) {
80 if (m_colorScopes[i].scope == colorScope) {
87 qDebug() << "Adding scope to scope manager: " << colorScope->widgetName();
90 m_signalMapper->setMapping(colorScopeWidget, QString(colorScope->widgetName()));
93 gsd.scope = colorScope;
94 gsd.scopeDockWidget = colorScopeWidget;
95 m_colorScopes.append(gsd);
98 b &= connect(colorScope, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotCheckActiveScopes()));
99 b &= connect(colorScope, SIGNAL(signalFrameRequest(QString)), this, SLOT(slotRequestFrame(QString)));
100 if (colorScopeWidget != NULL) {
101 b &= connect(colorScopeWidget, SIGNAL(visibilityChanged(bool)), this, SLOT(slotCheckActiveScopes()));
102 b &= connect(colorScopeWidget, SIGNAL(visibilityChanged(bool)), m_signalMapper, SLOT(map()));
112 void ScopeManager::slotDistributeAudio(QVector<int16_t> sampleData, int freq, int num_channels, int num_samples)
115 qDebug() << "ScopeManager: Starting to distribute audio.";
117 for (int i = 0; i < m_audioScopes.size(); i++) {
118 // Distribute audio to all scopes that are visible and want to be refreshed
119 if (!m_audioScopes[i].scope->visibleRegion().isEmpty()) {
120 if (m_audioScopes[i].scope->autoRefreshEnabled()) {
121 m_audioScopes[i].scope->slotReceiveAudio(sampleData, freq, num_channels, num_samples);
123 qDebug() << "ScopeManager: Distributed audio to " << m_audioScopes[i].scope->widgetName();
129 checkActiveAudioScopes();
131 void ScopeManager::slotDistributeFrame(QImage image)
134 qDebug() << "ScopeManager: Starting to distribute frame.";
136 for (int i = 0; i < m_colorScopes.size(); i++) {
137 if (!m_colorScopes[i].scope->visibleRegion().isEmpty()) {
138 if (m_colorScopes[i].scope->autoRefreshEnabled()) {
139 m_colorScopes[i].scope->slotRenderZoneUpdated(image);
141 qDebug() << "ScopeManager: Distributed frame to " << m_colorScopes[i].scope->widgetName();
143 } else if (m_colorScopes[i].singleFrameRequested) {
144 // Special case: Auto refresh is disabled, but user requested an update (e.g. by clicking).
145 // Force the scope to update.
146 m_colorScopes[i].singleFrameRequested = false;
147 m_colorScopes[i].scope->slotRenderZoneUpdated(image);
148 m_colorScopes[i].scope->forceUpdateScope();
150 qDebug() << "ScopeManager: Distributed forced frame to " << m_colorScopes[i].scope->widgetName();
156 checkActiveColourScopes();
160 void ScopeManager::slotRequestFrame(const QString widgetName)
163 qDebug() << "ScopeManager: New frame was requested by " << widgetName;
166 // Search for the scope in the lists and tag it to trigger a forced update
167 // in the distribution slots
168 for (int i = 0; i < m_colorScopes.size(); i++) {
169 if (m_colorScopes[i].scope->widgetName() == widgetName) {
170 m_colorScopes[i].singleFrameRequested = true;
174 for (int i = 0; i < m_audioScopes.size(); i++) {
175 if (m_audioScopes[i].scope->widgetName() == widgetName) {
176 m_audioScopes[i].singleFrameRequested = true;
180 m_lastConnectedRenderer->sendFrameUpdate();
185 void ScopeManager::slotUpdateActiveRenderer()
189 // Disconnect old connections
190 if (m_lastConnectedRenderer != NULL) {
192 qDebug() << "Disconnected previous renderer: " << m_lastConnectedRenderer->name();
194 b &= m_lastConnectedRenderer->disconnect(this);
198 m_lastConnectedRenderer = m_monitorManager->activeRenderer();
200 // Connect new renderer
201 if (m_lastConnectedRenderer != NULL) {
202 b &= connect(m_lastConnectedRenderer, SIGNAL(frameUpdated(QImage)),
203 this, SLOT(slotDistributeFrame(QImage)), Qt::UniqueConnection);
204 b &= connect(m_lastConnectedRenderer, SIGNAL(audioSamplesSignal(QVector<int16_t>,int,int,int)),
205 this, SLOT(slotDistributeAudio(QVector<int16_t>,int,int,int)), Qt::UniqueConnection);
209 qDebug() << "Renderer connected to ScopeManager: " << m_lastConnectedRenderer->name();
212 if (imagesAcceptedByScopes()) {
214 qDebug() << "Some scopes accept images, triggering frame update.";
216 m_lastConnectedRenderer->sendFrameUpdate();
222 void ScopeManager::slotCheckActiveScopes()
225 qDebug() << "Checking active scopes ...";
227 checkActiveAudioScopes();
228 checkActiveColourScopes();
232 bool ScopeManager::audioAcceptedByScopes() const
234 bool accepted = false;
235 for (int i = 0; i < m_audioScopes.size(); i++) {
236 if (!m_audioScopes[i].scope->visibleRegion().isEmpty() && m_audioScopes[i].scope->autoRefreshEnabled()) {
242 qDebug() << "Any scope accepting audio? " << accepted;
246 bool ScopeManager::imagesAcceptedByScopes() const
248 bool accepted = false;
249 for (int i = 0; i < m_colorScopes.size(); i++) {
250 if (!m_colorScopes[i].scope->visibleRegion().isEmpty() && m_colorScopes[i].scope->autoRefreshEnabled()) {
256 qDebug() << "Any scope accepting images? " << accepted;
263 void ScopeManager::checkActiveAudioScopes()
265 bool audioStillRequested = audioAcceptedByScopes();
268 qDebug() << "ScopeManager: New audio data still requested? " << audioStillRequested;
271 KdenliveSettings::setMonitor_audio(audioStillRequested);
272 m_monitorManager->slotUpdateAudioMonitoring();
274 void ScopeManager::checkActiveColourScopes()
276 bool imageStillRequested = imagesAcceptedByScopes();
279 qDebug() << "ScopeManager: New frames still requested? " << imageStillRequested;
282 // Notify monitors whether frames are still required
284 monitor = static_cast<Monitor*>( m_monitorManager->monitor(Kdenlive::projectMonitor) );
285 if (monitor != NULL) { monitor->render->sendFrameForAnalysis = imageStillRequested; }
287 monitor = static_cast<Monitor*>( m_monitorManager->monitor(Kdenlive::clipMonitor) );
288 if (monitor != NULL) { monitor->render->sendFrameForAnalysis = imageStillRequested; }
290 RecMonitor *recMonitor = static_cast<RecMonitor*>( m_monitorManager->monitor(Kdenlive::recordMonitor) );
291 if (recMonitor != NULL) { recMonitor->analyseFrames(imageStillRequested); }