From 9522922e9d58a72c762d668177662f7d7ab00e8e Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Tue, 6 Mar 2012 14:16:19 +0100 Subject: [PATCH] Merging of scopes manager by Granjow (final merge) --- src/abstractmonitor.h | 5 +- src/definitions.h | 11 +- src/mainwindow.cpp | 252 +++++------------- src/mainwindow.h | 16 +- src/mltdevicecapture.cpp | 6 +- src/mltdevicecapture.h | 3 - src/monitor.cpp | 14 +- src/monitormanager.cpp | 20 +- src/monitormanager.h | 4 + src/recmonitor.cpp | 46 ++-- src/renderer.cpp | 47 ++-- src/renderer.h | 2 - src/scopes/abstractscopewidget.cpp | 10 +- src/scopes/abstractscopewidget.h | 85 +++--- .../audioscopes/abstractaudioscopewidget.cpp | 2 +- .../audioscopes/abstractaudioscopewidget.h | 11 +- src/scopes/audioscopes/audiosignal.cpp | 181 +++++++------ src/scopes/audioscopes/audiosignal.h | 28 +- src/scopes/audioscopes/audiospectrum.h | 13 +- .../colorscopes/abstractgfxscopewidget.cpp | 45 +--- .../colorscopes/abstractgfxscopewidget.h | 20 +- src/scopes/colorscopes/histogram.cpp | 5 +- src/scopes/colorscopes/histogram.h | 5 +- src/scopes/colorscopes/rgbparade.cpp | 5 +- src/scopes/colorscopes/rgbparade.h | 7 +- src/scopes/colorscopes/vectorscope.cpp | 5 +- src/scopes/colorscopes/vectorscope.h | 10 +- src/scopes/colorscopes/waveform.cpp | 5 +- src/scopes/colorscopes/waveform.h | 7 +- 29 files changed, 402 insertions(+), 468 deletions(-) diff --git a/src/abstractmonitor.h b/src/abstractmonitor.h index c58ae0e0..df3f9db1 100644 --- a/src/abstractmonitor.h +++ b/src/abstractmonitor.h @@ -82,6 +82,9 @@ Q_OBJECT public: /** @brief This property is used to decide if the renderer should convert it's frames to QImage for use in other Kdenlive widgets. */ bool sendFrameForAnalysis; + /** @brief This property is used to decide if the renderer should send audio data for monitoring. */ + bool analyseAudio; + const QString &name() const {return m_name;}; /** @brief Someone needs us to send again a frame. */ @@ -95,7 +98,7 @@ signals: void frameUpdated(QImage); /** @brief This signal contains the audio of the current frame. */ - void audioSamplesSignal(const QVector&, const int&, const int&, const int&); + void audioSamplesSignal(QVector,int,int,int); }; class AbstractMonitor : public QWidget diff --git a/src/definitions.h b/src/definitions.h index 9c69a485..1b27cf8b 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -24,11 +24,20 @@ #include "gentime.h" #include "effectslist.h" -#include #include +#include + #include + const int MAXCLIPDURATION = 15000; +namespace Kdenlive { + const QString clipMonitor("clipMonitor"); + const QString recordMonitor("recordMonitor"); + const QString projectMonitor("projectMonitor"); + const QString stopmotionMonitor("stopmotionMonitor"); +} + enum OPERATIONTYPE { NONE = 0, MOVE = 1, RESIZESTART = 2, RESIZEEND = 3, FADEIN = 4, FADEOUT = 5, TRANSITIONSTART = 6, TRANSITIONEND = 7, MOVEGUIDE = 8, KEYFRAME = 9, SEEK = 10, SPACER = 11, RUBBERSELECTION = 12}; enum CLIPTYPE { UNKNOWN = 0, AUDIO = 1, VIDEO = 2, AV = 3, COLOR = 4, IMAGE = 5, TEXT = 6, SLIDESHOW = 7, VIRTUAL = 8, PLAYLIST = 9 }; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index bfeab9c5..8b60492e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -39,7 +39,6 @@ #include "transitionsettings.h" #include "renderwidget.h" #include "renderer.h" -#include "audiosignal.h" #ifdef USE_JOGSHUTTLE #include "jogshuttle.h" #include "jogaction.h" @@ -55,12 +54,14 @@ #include "config-kdenlive.h" #include "cliptranscode.h" #include "ui_templateclip_ui.h" -#include "colorscopes/vectorscope.h" -#include "colorscopes/waveform.h" -#include "colorscopes/rgbparade.h" -#include "colorscopes/histogram.h" -#include "audioscopes/audiospectrum.h" -#include "audioscopes/spectrogram.h" +#include "scopes/scopemanager.h" +#include "scopes/colorscopes/vectorscope.h" +#include "scopes/colorscopes/waveform.h" +#include "scopes/colorscopes/rgbparade.h" +#include "scopes/colorscopes/histogram.h" +#include "scopes/audioscopes/audiosignal.h" +#include "scopes/audioscopes/audiospectrum.h" +#include "scopes/audioscopes/spectrogram.h" #include "archivewidget.h" #include "databackup/backupwidget.h" #include "utils/resourcewidget.h" @@ -151,7 +152,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & #endif m_findActivated(false), m_stopmotion(NULL) -{ +{ qRegisterMetaType > (); qRegisterMetaType ("stringMap"); qRegisterMetaType ("audioByteArray"); @@ -166,7 +167,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & if (strncmp(separator, ".", 1) == 0) systemLocale = QLocale::c(); else if (strncmp(separator, ",", 1) == 0) systemLocale = QLocale("fr_FR.UTF-8"); } - + systemLocale.setNumberOptions(QLocale::OmitGroupSeparator); QLocale::setDefault(systemLocale); @@ -176,7 +177,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & dbus.registerObject("/MainWindow", this); if (!KdenliveSettings::colortheme().isEmpty()) slotChangePalette(NULL, KdenliveSettings::colortheme()); - setFont(KGlobalSettings::toolBarFont()); + //setFont(KGlobalSettings::toolBarFont()); parseProfiles(MltPath); KdenliveSettings::setCurrent_profile(KdenliveSettings::default_profile()); m_commandStack = new QUndoGroup; @@ -218,9 +219,9 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & m_clipMonitorDock = new QDockWidget(i18n("Clip Monitor"), this); m_clipMonitorDock->setObjectName("clip_monitor"); - m_clipMonitor = new Monitor("clip", m_monitorManager, QString(), m_timelineArea); + m_clipMonitor = new Monitor(Kdenlive::clipMonitor, m_monitorManager, QString(), m_timelineArea); m_clipMonitorDock->setWidget(m_clipMonitor); - + // Connect the project list connect(m_projectList, SIGNAL(clipSelected(DocClipBase *, QPoint, bool)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint, bool))); connect(m_projectList, SIGNAL(raiseClipMonitor()), m_clipMonitor, SLOT(activateMonitor())); @@ -236,18 +237,18 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & m_projectMonitorDock = new QDockWidget(i18n("Project Monitor"), this); m_projectMonitorDock->setObjectName("project_monitor"); - m_projectMonitor = new Monitor("project", m_monitorManager, QString()); + m_projectMonitor = new Monitor(Kdenlive::projectMonitor, m_monitorManager, QString()); m_projectMonitorDock->setWidget(m_projectMonitor); #ifndef Q_WS_MAC m_recMonitorDock = new QDockWidget(i18n("Record Monitor"), this); m_recMonitorDock->setObjectName("record_monitor"); - m_recMonitor = new RecMonitor("record", m_monitorManager); + m_recMonitor = new RecMonitor(Kdenlive::recordMonitor, m_monitorManager); m_recMonitorDock->setWidget(m_recMonitor); connect(m_recMonitor, SIGNAL(addProjectClip(KUrl)), this, SLOT(slotAddProjectClip(KUrl))); connect(m_recMonitor, SIGNAL(addProjectClipList(KUrl::List)), this, SLOT(slotAddProjectClipList(KUrl::List))); connect(m_recMonitor, SIGNAL(showConfigDialog(int, int)), this, SLOT(slotPreferences(int, int))); - + #endif /* ! Q_WS_MAC */ m_monitorManager->initMonitors(m_clipMonitor, m_projectMonitor, m_recMonitor); @@ -256,7 +257,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & m_notesWidget = new NotesWidget(); connect(m_notesWidget, SIGNAL(insertNotesTimecode()), this, SLOT(slotInsertNotesTimecode())); connect(m_notesWidget, SIGNAL(seekProject(int)), m_projectMonitor->render, SLOT(seekToFrame(int))); - + m_notesWidget->setTabChangesFocus(true); #if KDE_IS_VERSION(4,4,0) m_notesWidget->setClickMessage(i18n("Enter your project notes here ...")); @@ -283,97 +284,55 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & m_effectListDock->setWidget(m_effectList); addDockWidget(Qt::TopDockWidgetArea, m_effectListDock); - m_vectorscope = new Vectorscope(m_monitorManager); + m_scopeManager = new ScopeManager(m_monitorManager); + m_vectorscope = new Vectorscope(); m_vectorscopeDock = new QDockWidget(i18n("Vectorscope"), this); m_vectorscopeDock->setObjectName(m_vectorscope->widgetName()); m_vectorscopeDock->setWidget(m_vectorscope); addDockWidget(Qt::TopDockWidgetArea, m_vectorscopeDock); - connect(m_vectorscopeDock, SIGNAL(visibilityChanged(bool)), m_vectorscope, SLOT(forceUpdate(bool))); - connect(m_vectorscopeDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest())); - connect(m_vectorscope, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest())); - m_gfxScopesList.append(m_vectorscopeDock); + m_scopeManager->addScope(m_vectorscope, m_vectorscopeDock); - m_waveform = new Waveform(m_monitorManager); + m_waveform = new Waveform(); m_waveformDock = new QDockWidget(i18n("Waveform"), this); m_waveformDock->setObjectName(m_waveform->widgetName()); m_waveformDock->setWidget(m_waveform); addDockWidget(Qt::TopDockWidgetArea, m_waveformDock); - connect(m_waveformDock, SIGNAL(visibilityChanged(bool)), m_waveform, SLOT(forceUpdate(bool))); - connect(m_waveformDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest())); - connect(m_waveform, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest())); - m_gfxScopesList.append(m_waveformDock); + m_scopeManager->addScope(m_waveform, m_waveformDock); - m_RGBParade = new RGBParade(m_monitorManager); + m_RGBParade = new RGBParade(); m_RGBParadeDock = new QDockWidget(i18n("RGB Parade"), this); m_RGBParadeDock->setObjectName(m_RGBParade->widgetName()); m_RGBParadeDock->setWidget(m_RGBParade); addDockWidget(Qt::TopDockWidgetArea, m_RGBParadeDock); - connect(m_RGBParadeDock, SIGNAL(visibilityChanged(bool)), m_RGBParade, SLOT(forceUpdate(bool))); - connect(m_RGBParadeDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest())); - connect(m_RGBParade, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest())); - m_gfxScopesList.append(m_RGBParadeDock); + m_scopeManager->addScope(m_RGBParade, m_RGBParadeDock); - m_histogram = new Histogram(m_monitorManager); + m_histogram = new Histogram(); m_histogramDock = new QDockWidget(i18n("Histogram"), this); m_histogramDock->setObjectName(m_histogram->widgetName()); m_histogramDock->setWidget(m_histogram); addDockWidget(Qt::TopDockWidgetArea, m_histogramDock); - connect(m_histogramDock, SIGNAL(visibilityChanged(bool)), m_histogram, SLOT(forceUpdate(bool))); - connect(m_histogramDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest())); - connect(m_histogram, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateGfxScopeFrameRequest())); - m_gfxScopesList.append(m_histogramDock); - + m_scopeManager->addScope(m_histogram, m_histogramDock); m_audiosignal = new AudioSignal; m_audiosignalDock = new QDockWidget(i18n("Audio Signal"), this); m_audiosignalDock->setObjectName("audiosignal"); m_audiosignalDock->setWidget(m_audiosignal); addDockWidget(Qt::TopDockWidgetArea, m_audiosignalDock); - connect(m_audiosignalDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateAudioScopeFrameRequest())); - connect(m_audiosignal, SIGNAL(updateAudioMonitoring()), this, SLOT(slotUpdateAudioScopeFrameRequest())); + m_scopeManager->addScope(m_audiosignal, m_audiosignalDock); m_audioSpectrum = new AudioSpectrum(); m_audioSpectrumDock = new QDockWidget(i18n("AudioSpectrum"), this); m_audioSpectrumDock->setObjectName(m_audioSpectrum->widgetName()); m_audioSpectrumDock->setWidget(m_audioSpectrum); addDockWidget(Qt::TopDockWidgetArea, m_audioSpectrumDock); - m_audioScopesList.append(m_audioSpectrum); - connect(m_audioSpectrumDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateAudioScopeFrameRequest())); - connect(m_audioSpectrum, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateAudioScopeFrameRequest())); + m_scopeManager->addScope(m_audioSpectrum, m_audioSpectrumDock); m_spectrogram = new Spectrogram(); m_spectrogramDock = new QDockWidget(i18n("Spectrogram"), this); m_spectrogramDock->setObjectName(m_spectrogram->widgetName()); m_spectrogramDock->setWidget(m_spectrogram); addDockWidget(Qt::TopDockWidgetArea, m_spectrogramDock); - m_audioScopesList.append(m_spectrogram); - connect(m_audioSpectrumDock, SIGNAL(visibilityChanged(bool)), this, SLOT(slotUpdateAudioScopeFrameRequest())); - connect(m_audioSpectrum, SIGNAL(requestAutoRefresh(bool)), this, SLOT(slotUpdateAudioScopeFrameRequest())); - - // Connect the audio signal to the audio scope slots - bool b = true; - if (m_projectMonitor) { - qDebug() << "project monitor connected"; - b &= connect(m_projectMonitor->render, SIGNAL(audioSamplesSignal(QVector, int, int, int)), - m_audioSpectrum, SLOT(slotReceiveAudio(QVector, int, int, int))); - b &= connect(m_projectMonitor->render, SIGNAL(audioSamplesSignal(const QVector&, const int&, const int&, const int&)), - m_audiosignal, SLOT(slotReceiveAudio(const QVector&, const int&, const int&, const int&))); - b &= connect(m_projectMonitor->render, SIGNAL(audioSamplesSignal(QVector,int,int,int)), - m_spectrogram, SLOT(slotReceiveAudio(QVector,int,int,int))); - } - if (m_clipMonitor) { - qDebug() << "clip monitor connected"; - b &= connect(m_clipMonitor->render, SIGNAL(audioSamplesSignal(QVector, int, int, int)), - m_audioSpectrum, SLOT(slotReceiveAudio(QVector, int, int, int))); - b &= connect(m_clipMonitor->render, SIGNAL(audioSamplesSignal(const QVector&, int, int, int)), - m_audiosignal, SLOT(slotReceiveAudio(const QVector&, int, int, int))); - b &= connect(m_clipMonitor->render, SIGNAL(audioSamplesSignal(QVector,int,int,int)), - m_spectrogram, SLOT(slotReceiveAudio(QVector,int,int,int))); - } - // Ensure connections were set up correctly - Q_ASSERT(b); - - + m_scopeManager->addScope(m_spectrogram, m_spectrogramDock); // Add monitors here to keep them at the right of the window addDockWidget(Qt::TopDockWidgetArea, m_clipMonitorDock); @@ -466,7 +425,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & m_effectActions = new KActionCategory(i18n("Effects"), actionCollection()); m_effectList->reloadEffectList(m_effectsMenu, m_effectActions); m_effectsActionCollection->readSettings(); - + setupGUI(); // Find QDockWidget tab bars and show / hide widget title bars on right click @@ -607,8 +566,8 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & connect(m_projectMonitorDock, SIGNAL(visibilityChanged(bool)), m_projectMonitor, SLOT(refreshMonitor(bool))); connect(m_clipMonitorDock, SIGNAL(visibilityChanged(bool)), m_clipMonitor, SLOT(refreshMonitor(bool))); - connect(m_monitorManager, SIGNAL(checkColorScopes()), this, SLOT(slotUpdateColorScopes())); - connect(m_monitorManager, SIGNAL(clearScopes()), this, SLOT(slotClearColorScopes())); + //connect(m_monitorManager, SIGNAL(checkColorScopes()), this, SLOT(slotUpdateColorScopes())); + //connect(m_monitorManager, SIGNAL(clearScopes()), this, SLOT(slotClearColorScopes())); connect(m_effectList, SIGNAL(addEffect(const QDomElement)), this, SLOT(slotAddEffect(const QDomElement))); connect(m_effectList, SIGNAL(reloadEffects()), this, SLOT(slotReloadEffects())); @@ -644,7 +603,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & actionCollection()->addAssociatedWidget(m_clipMonitor->container()); actionCollection()->addAssociatedWidget(m_projectMonitor->container()); - + // Populate encoding profiles KConfig conf("encodingprofiles.rc", KConfig::FullConfig, "appdata"); if (KdenliveSettings::proxyparams().isEmpty() || KdenliveSettings::proxyextension().isEmpty()) { @@ -701,6 +660,8 @@ MainWindow::~MainWindow() delete m_clipMonitor; delete m_shortcutRemoveFocus; delete[] m_transitions; + delete m_monitorManager; + delete m_scopeManager; Mlt::Factory::close(); } @@ -859,10 +820,10 @@ void MainWindow::activateShuttleDevice() delete m_jogProcess; m_jogProcess = NULL; if (KdenliveSettings::enableshuttle() == false) return; - + m_jogProcess = new JogShuttle(KdenliveSettings::shuttledevice()); m_jogShuttle = new JogShuttleAction(m_jogProcess, JogShuttleConfig::actionMap(KdenliveSettings::shuttlebuttons())); - + connect(m_jogShuttle, SIGNAL(rewindOneFrame()), m_monitorManager, SLOT(slotRewindOneFrame())); connect(m_jogShuttle, SIGNAL(forwardOneFrame()), m_monitorManager, SLOT(slotForwardOneFrame())); connect(m_jogShuttle, SIGNAL(rewind(double)), m_monitorManager, SLOT(slotRewind(double))); @@ -929,7 +890,7 @@ void MainWindow::slotConnectMonitors() connect(m_projectMonitor->render, SIGNAL(replyGetFileProperties(const QString &, Mlt::Producer*, const stringMap &, const stringMap &, bool)), m_projectList, SLOT(slotReplyGetFileProperties(const QString &, Mlt::Producer*, const stringMap &, const stringMap &, bool))); connect(m_projectMonitor->render, SIGNAL(removeInvalidClip(const QString &, bool)), m_projectList, SLOT(slotRemoveInvalidClip(const QString &, bool))); - + connect(m_projectMonitor->render, SIGNAL(removeInvalidProxy(const QString &, bool)), m_projectList, SLOT(slotRemoveInvalidProxy(const QString &, bool))); connect(m_clipMonitor, SIGNAL(refreshClipThumbnail(const QString &, bool)), m_projectList, SLOT(slotRefreshClipThumbnail(const QString &, bool))); @@ -1001,7 +962,7 @@ void MainWindow::setupActions() QColor buttonBg = scheme.background(KColorScheme::LinkBackground).color(); QColor buttonBord = scheme.foreground(KColorScheme::LinkText).color(); QColor buttonBord2 = scheme.shade(KColorScheme::LightShade); - statusBar()->setStyleSheet(QString("QStatusBar QLabel {font-size:%1pt;} QStatusBar::item { border: 0px; font-size:%1pt;padding:0px; }").arg(statusBar()->font().pointSize())); + //statusBar()->setStyleSheet(QString("QStatusBar QLabel {font-size:%1pt;} QStatusBar::item { border: 0px; font-size:%1pt;padding:0px; }").arg(statusBar()->font().pointSize())); QString style1 = QString("QToolBar { border: 0px } QToolButton { border-style: inset; border:1px solid transparent;border-radius: 3px;margin: 0px 3px;padding: 0px;} QToolButton:hover { background: rgb(%7, %8, %9);border-style: inset; border:1px solid rgb(%7, %8, %9);border-radius: 3px;} QToolButton:checked { background-color: rgb(%1, %2, %3); border-style: inset; border:1px solid rgb(%4, %5, %6);border-radius: 3px;}").arg(buttonBg.red()).arg(buttonBg.green()).arg(buttonBg.blue()).arg(buttonBord.red()).arg(buttonBord.green()).arg(buttonBord.blue()).arg(buttonBord2.red()).arg(buttonBord2.green()).arg(buttonBord2.blue()); QString styleBorderless = "QToolButton { border-width: 0px;margin: 1px 3px 0px;padding: 0px;}"; @@ -1296,7 +1257,7 @@ void MainWindow::setupActions() KAction *archiveProject = new KAction(KIcon("file-save"), i18n("Archive Project"), this); collection.addAction("archive_project", archiveProject); connect(archiveProject, SIGNAL(triggered(bool)), this, SLOT(slotArchiveProject())); - + KAction *markIn = collection.addAction("mark_in"); markIn->setText(i18n("Set Zone In")); @@ -1546,7 +1507,7 @@ void MainWindow::setupActions() m_tracksActionCollection = new KActionCollection(this, KGlobal::mainComponent()); m_tracksActionCollection->addAssociatedWidget(m_timelineArea); - + KAction *insertTrack = new KAction(KIcon(), i18n("Insert Track"), m_tracksActionCollection); m_tracksActionCollection->addAction("insert_track", insertTrack); connect(insertTrack, SIGNAL(triggered()), this, SLOT(slotInsertTrack())); @@ -1562,11 +1523,11 @@ void MainWindow::setupActions() KAction *selectTrack = new KAction(KIcon(), i18n("Select All in Current Track"), m_tracksActionCollection); connect(selectTrack, SIGNAL(triggered()), this, SLOT(slotSelectTrack())); m_tracksActionCollection->addAction("select_track", selectTrack); - + QAction *selectAll = KStandardAction::selectAll(this, SLOT(slotSelectAllTracks()), m_tracksActionCollection); selectAll->setShortcutContext(Qt::WidgetWithChildrenShortcut); m_tracksActionCollection->addAction("select_all_tracks", selectAll); - + KAction *addGuide = new KAction(KIcon("document-new"), i18n("Add Guide"), this); collection.addAction("add_guide", addGuide); connect(addGuide, SIGNAL(triggered()), this, SLOT(slotAddGuide())); @@ -1652,7 +1613,7 @@ void MainWindow::setupActions() QAction *addFolderButton = new KAction(KIcon("folder-new"), i18n("Create Folder"), this); collection.addAction("add_folder", addFolderButton); connect(addFolderButton , SIGNAL(triggered()), m_projectList, SLOT(slotAddFolder())); - + QAction *downloadResources = new KAction(KIcon("download"), i18n("Online Resources"), this); collection.addAction("download_resource", downloadResources); connect(downloadResources , SIGNAL(triggered()), this, SLOT(slotDownloadResources())); @@ -1687,9 +1648,9 @@ void MainWindow::setupActions() proxyClip->setCheckable(true); proxyClip->setChecked(false); connect(proxyClip, SIGNAL(toggled(bool)), m_projectList, SLOT(slotProxyCurrentItem(bool))); - + QAction *stopMotion = new KAction(KIcon("image-x-generic"), i18n("Stop Motion Capture"), this); - collection.addAction("stopmotion", stopMotion); + collection.addAction(Kdenlive::stopmotionMonitor, stopMotion); connect(stopMotion , SIGNAL(triggered()), this, SLOT(slotOpenStopmotion())); QMenu *addClips = new QMenu(); @@ -1910,7 +1871,7 @@ void MainWindow::newFile(bool showProjectSettings, bool force) connectDocument(trackView, doc); } else m_timelineArea->setTabBarHidden(false); - m_monitorManager->activateMonitor("clip"); + m_monitorManager->activateMonitor(Kdenlive::clipMonitor); m_closeAction->setEnabled(m_timelineArea->count() > 1); } @@ -2065,7 +2026,7 @@ void MainWindow::openFile(const KUrl &url) KMessageBox::sorry(this, i18n("File %1 is not a Kdenlive project file", url.path())); return; } - + // Check if the document is already opened const int ct = m_timelineArea->count(); bool isOpened = false; @@ -2118,7 +2079,7 @@ void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale) delete m_stopmotion; m_stopmotion = NULL; } - + m_timer.start(); KProgressDialog progressDialog(this, i18n("Loading project"), i18n("Loading project")); progressDialog.setAllowCancel(false); @@ -2514,7 +2475,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //cha disconnect(m_activeTimeline->projectView(), SIGNAL(displayMessage(const QString&, MessageType)), m_messageLabel, SLOT(setMessage(const QString&, MessageType))); disconnect(m_activeTimeline->projectView(), SIGNAL(showClipFrame(DocClipBase *, QPoint, bool, const int)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint, bool, const int))); disconnect(m_projectList, SIGNAL(gotFilterJobResults(const QString &, int, int, const QString &, stringMap)), m_activeTimeline->projectView(), SLOT(slotGotFilterJobResults(const QString &, int, int, const QString &, stringMap))); - + disconnect(m_activeTimeline, SIGNAL(cursorMoved()), m_projectMonitor, SLOT(activateMonitor())); disconnect(m_activeTimeline, SIGNAL(configTrack(int)), this, SLOT(slotConfigTrack(int))); disconnect(m_activeDocument, SIGNAL(docModified(bool)), this, SLOT(slotUpdateDocumentState(bool))); @@ -2569,7 +2530,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //cha connect(doc, SIGNAL(docModified(bool)), this, SLOT(slotUpdateDocumentState(bool))); connect(doc, SIGNAL(guidesUpdated()), this, SLOT(slotGuidesUpdated())); connect(doc, SIGNAL(saveTimelinePreview(const QString &)), trackView, SLOT(slotSaveTimelinePreview(const QString))); - + connect(m_notesWidget, SIGNAL(textChanged()), doc, SLOT(setModified())); connect(trackView->projectView(), SIGNAL(clipItemSelected(ClipItem*, int, bool)), m_effectStack, SLOT(slotClipItemSelected(ClipItem*, int))); @@ -2591,7 +2552,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //cha connect(trackView->projectView(), SIGNAL(clipItemSelected(ClipItem*, int, bool)), m_projectMonitor, SLOT(slotSetSelectedClip(ClipItem*))); connect(trackView->projectView(), SIGNAL(transitionItemSelected(Transition*, int, QPoint, bool)), m_projectMonitor, SLOT(slotSetSelectedClip(Transition*))); - + connect(m_projectList, SIGNAL(gotFilterJobResults(const QString &, int, int, const QString &, stringMap)), trackView->projectView(), SLOT(slotGotFilterJobResults(const QString &, int, int, const QString &, stringMap))); connect(m_effectStack, SIGNAL(updateEffect(ClipItem*, int, QDomElement, QDomElement, int)), trackView->projectView(), SLOT(slotUpdateClipEffect(ClipItem*, int, QDomElement, QDomElement, int))); @@ -2638,7 +2599,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //cha #endif //Update the mouse position display so it will display in DF/NDF format by default based on the project setting. slotUpdateMousePosition(0); - m_monitorManager->activateMonitor("clip"); + m_monitorManager->activateMonitor(Kdenlive::clipMonitor); // set tool to select tool m_buttonSelectTool->setChecked(true); } @@ -2680,14 +2641,14 @@ void MainWindow::slotPreferences(int page, int option) // KConfigDialog didn't find an instance of this dialog, so lets // create it : - + // Get the mappable actions in localized form QMap actions; KActionCollection* collection = actionCollection(); foreach (const QString& action_name, m_action_names) { actions[collection->action(action_name)->text()] = action_name; } - + KdenliveSettingsDialog* dialog = new KdenliveSettingsDialog(actions, this); connect(dialog, SIGNAL(settingsChanged(const QString&)), this, SLOT(updateConfiguration())); connect(dialog, SIGNAL(doResetProfile()), m_monitorManager, SLOT(slotResetProfiles())); @@ -3331,7 +3292,7 @@ void MainWindow::slotShowClipProperties(QList cliplist, QMapclipType() == IMAGE) new EditClipCommand(m_projectList, clip->getId(), clip->currentProperties(newImageProps), newImageProps, true, command); - else + else new EditClipCommand(m_projectList, clip->getId(), clip->currentProperties(newProps), newProps, true, command); } m_activeDocument->commandStack()->push(command); @@ -3863,7 +3824,7 @@ void MainWindow::loadTranscoders() { QMenu *transMenu = static_cast(factory()->container("transcoders", this)); transMenu->clear(); - + QMenu *extractAudioMenu = static_cast(factory()->container("extract_audio", this)); extractAudioMenu->clear(); @@ -3908,7 +3869,7 @@ void MainWindow::slotStabilize() QString destination; ProjectItem *item = m_projectList->getClipById(ids.at(0)); if (ids.count() == 1) { - + } ClipStabilize *d = new ClipStabilize(destination, ids.count(), filtername); //connect(d, SIGNAL(addClip(KUrl)), this, SLOT(slotAddProjectClip(KUrl))); @@ -4054,7 +4015,7 @@ void MainWindow::slotPrepareRendering(bool scriptExport, bool zoneOnly, const QS } } } - + // Do we want proxy rendering if (m_projectList->useProxy() && !m_renderWidget->proxyRendering()) { QString root = doc.documentElement().attribute("root"); @@ -4088,7 +4049,7 @@ void MainWindow::slotPrepareRendering(bool scriptExport, bool zoneOnly, const QS } } } - + /*QMapIterator i(proxies); while (i.hasNext()) { i.next(); @@ -4103,7 +4064,7 @@ void MainWindow::slotPrepareRendering(bool scriptExport, bool zoneOnly, const QS }*/ } playlistContent = doc.toString(); - + // Do save scenelist QFile file(playlistPath); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { @@ -4184,19 +4145,19 @@ void MainWindow::slotChangePalette(QAction *action, const QString &themename) plt = KGlobalSettings::createNewApplicationPalette(config); #else // Since there was a bug in createApplicationPalette in KDE < 4.6.3 we need - // to do the palette loading stuff ourselves. (https://bugs.kde.org/show_bug.cgi?id=263497) + // to do the palette loading stuff ourselves. (https://bugs.kde.org/show_bug.cgi?id=263497) QPalette::ColorGroup states[3] = { QPalette::Active, QPalette::Inactive, QPalette::Disabled }; // TT thinks tooltips shouldn't use active, so we use our active colors for all states KColorScheme schemeTooltip(QPalette::Active, KColorScheme::Tooltip, config); - + for ( int i = 0; i < 3 ; i++ ) { QPalette::ColorGroup state = states[i]; KColorScheme schemeView(state, KColorScheme::View, config); KColorScheme schemeWindow(state, KColorScheme::Window, config); KColorScheme schemeButton(state, KColorScheme::Button, config); KColorScheme schemeSelection(state, KColorScheme::Selection, config); - + plt.setBrush( state, QPalette::WindowText, schemeWindow.foreground() ); plt.setBrush( state, QPalette::Window, schemeWindow.background() ); plt.setBrush( state, QPalette::Base, schemeView.background() ); @@ -4207,13 +4168,13 @@ void MainWindow::slotChangePalette(QAction *action, const QString &themename) plt.setBrush( state, QPalette::HighlightedText, schemeSelection.foreground() ); plt.setBrush( state, QPalette::ToolTipBase, schemeTooltip.background() ); plt.setBrush( state, QPalette::ToolTipText, schemeTooltip.foreground() ); - + plt.setColor( state, QPalette::Light, schemeWindow.shade( KColorScheme::LightShade ) ); plt.setColor( state, QPalette::Midlight, schemeWindow.shade( KColorScheme::MidlightShade ) ); plt.setColor( state, QPalette::Mid, schemeWindow.shade( KColorScheme::MidShade ) ); plt.setColor( state, QPalette::Dark, schemeWindow.shade( KColorScheme::DarkShade ) ); plt.setColor( state, QPalette::Shadow, schemeWindow.shade( KColorScheme::ShadowShade ) ); - + plt.setBrush( state, QPalette::AlternateBase, schemeView.background( KColorScheme::AlternateBackground) ); plt.setBrush( state, QPalette::Link, schemeView.foreground( KColorScheme::LinkText ) ); plt.setBrush( state, QPalette::LinkVisited, schemeView.foreground( KColorScheme::VisitedText ) ); @@ -4375,87 +4336,6 @@ void MainWindow::slotMonitorRequestRenderFrame(bool request) } } -void MainWindow::slotUpdateGfxScopeFrameRequest() -{ - // We need a delay to make sure widgets are hidden after a close event for example - QTimer::singleShot(500, this, SLOT(slotDoUpdateGfxScopeFrameRequest())); -} - -void MainWindow::slotDoUpdateGfxScopeFrameRequest() -{ - // Check scopes - bool request = false; - for (int i = 0; i < m_gfxScopesList.count(); i++) { - if (!m_gfxScopesList.at(i)->widget()->visibleRegion().isEmpty() && static_cast(m_gfxScopesList.at(i)->widget())->autoRefreshEnabled()) { - kDebug() << "SCOPE VISIBLE: " << static_cast(m_gfxScopesList.at(i)->widget())->widgetName(); - request = true; - break; - } - } - if (!request) { - if (!m_projectMonitor->effectSceneDisplayed()) { - m_projectMonitor->render->sendFrameForAnalysis = false; - } - m_clipMonitor->render->sendFrameForAnalysis = false; - if (m_recMonitor) - m_recMonitor->analyseFrames(false); - } else { - m_projectMonitor->render->sendFrameForAnalysis = true; - m_clipMonitor->render->sendFrameForAnalysis = true; - if (m_recMonitor) - m_recMonitor->analyseFrames(true); - } -} - -void MainWindow::slotUpdateAudioScopeFrameRequest() -{ - QTimer::singleShot(500, this, SLOT(slotDoUpdateAudioScopeFrameRequest())); -} - -void MainWindow::slotDoUpdateAudioScopeFrameRequest() -{ - bool request = false; - for (int i = 0; i < m_audioScopesList.count(); i++) { - if (!m_audioScopesList.at(i)->visibleRegion().isEmpty() && m_audioScopesList.at(i)->autoRefreshEnabled()) { - kDebug() << "AUDIO SCOPE VISIBLE: " << m_audioScopesList.at(i)->widgetName(); - request = true; - break; - } - } - // Handle audio signal separately (no common interface) - if (!m_audiosignal->visibleRegion().isEmpty() && m_audiosignal->monitoringEnabled()) { - kDebug() << "AUDIO SCOPE VISIBLE: " << "audiosignal"; - request = true; - } -#ifdef DEBUG_MAINW - qDebug() << "Scopes Requesting Audio data: " << request; -#endif - KdenliveSettings::setMonitor_audio(request); - m_monitorManager->slotUpdateAudioMonitoring(); -} - -void MainWindow::slotUpdateColorScopes() -{ - bool request = false; - for (int i = 0; i < m_gfxScopesList.count(); i++) { - // Check if we need the renderer to send a new frame for update - if (!m_gfxScopesList.at(i)->widget()->visibleRegion().isEmpty() && !(static_cast(m_gfxScopesList.at(i)->widget())->autoRefreshEnabled())) request = true; - static_cast(m_gfxScopesList.at(i)->widget())->slotActiveMonitorChanged(); - } - if (request && m_monitorManager->activeRenderer()) { - m_monitorManager->activeRenderer()->sendFrameUpdate(); - } - if (m_audiosignal->isVisible() && m_recMonitor->abstractRender()) { - connect(m_recMonitor->abstractRender(), SIGNAL(audioSamplesSignal(const QVector&, const int&, const int&, const int&)), m_audiosignal, SLOT(slotReceiveAudio(const QVector&, const int&, const int&, const int&))); - } -} - -void MainWindow::slotClearColorScopes() -{ - for (int i = 0; i < m_gfxScopesList.count(); i++) { - static_cast(m_gfxScopesList.at(i)->widget())->slotClearMonitor(); - } -} void MainWindow::slotOpenStopmotion() { diff --git a/src/mainwindow.h b/src/mainwindow.h index 4444ef34..e4445629 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -66,6 +66,7 @@ class JogShuttleAction; class DocClipBase; class Render; class Transition; +class ScopeManager; class Histogram; class Vectorscope; class Waveform; @@ -137,6 +138,8 @@ private: KTabWidget* m_timelineArea; QProgressBar *m_statusProgressBar; + ScopeManager *m_scopeManager; + /** @brief Sets up all the actions and attaches them to the collection. */ void setupActions(); KdenliveDoc *m_activeDocument; @@ -197,7 +200,6 @@ private: /** This list holds all the scopes used in Kdenlive, allowing to manage some global settings */ QList m_gfxScopesList; - QList m_audioScopesList; KActionCategory *m_effectActions; QMenu *m_effectsMenu; @@ -209,7 +211,7 @@ private: /** Actions used in the stopmotion widget */ KActionCategory *m_stopmotion_actions; - + /** Action names that can be used in the slotDoAction() slot, with their i18n() names */ QStringList m_action_names; @@ -529,16 +531,6 @@ private slots: /** @brief The monitor informs that it needs (or not) to have frames sent by the renderer. */ void slotMonitorRequestRenderFrame(bool request); - /** @brief Check if someone needs the render frame sent. */ - void slotUpdateGfxScopeFrameRequest(); - /** @brief Check if someone needs the render frame sent. */ - void slotDoUpdateGfxScopeFrameRequest(); - void slotUpdateAudioScopeFrameRequest(); - void slotDoUpdateAudioScopeFrameRequest(); - /** @brief When switching between monitors, update the visible scopes. */ - void slotUpdateColorScopes(); - /** @brief Active monitor deleted, clear scopes. */ - void slotClearColorScopes(); /** @brief Switch current monitor to fullscreen. */ void slotSwitchFullscreen(); /** @brief Open the stopmotion dialog. */ diff --git a/src/mltdevicecapture.cpp b/src/mltdevicecapture.cpp index aebcf41c..2cddcad1 100644 --- a/src/mltdevicecapture.cpp +++ b/src/mltdevicecapture.cpp @@ -48,12 +48,12 @@ static void consumer_gl_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_fr self->showFrame(frame); } -static void rec_consumer_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr) +/*static void rec_consumer_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr) { Mlt::Frame frame(frame_ptr); if (!frame.is_valid()) return; self->gotCapturedFrame(frame); -} +}*/ static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr) { @@ -80,7 +80,6 @@ MltDeviceCapture::MltDeviceCapture(QString profile, VideoPreviewContainer *surfa AbstractRender("capture", parent), doCapture(0), sendFrameForAnalysis(false), - analyseAudio(KdenliveSettings::monitor_audio()), processingImage(false), m_mltConsumer(NULL), m_mltProducer(NULL), @@ -91,6 +90,7 @@ MltDeviceCapture::MltDeviceCapture(QString profile, VideoPreviewContainer *surfa m_captureDisplayWidget(surface), m_winid((int) surface->winId()) { + analyseAudio = KdenliveSettings::monitor_audio(); if (profile.isEmpty()) profile = KdenliveSettings::current_profile(); buildConsumer(profile); connect(this, SIGNAL(unblockPreview()), this, SLOT(slotPreparePreview())); diff --git a/src/mltdevicecapture.h b/src/mltdevicecapture.h index 69ad361e..f6fdfbe5 100644 --- a/src/mltdevicecapture.h +++ b/src/mltdevicecapture.h @@ -89,9 +89,6 @@ Q_OBJECT public: /** @brief This will add a horizontal flip effect, easier to work when filming yourself. */ void mirror(bool activate); - - /** @brief This property is used to decide if the renderer should send audio data for monitoring. */ - bool analyseAudio; /** @brief True if we are processing an image (yuv > rgb) when recording. */ bool processingImage; diff --git a/src/monitor.cpp b/src/monitor.cpp index 3a28ac48..1160dff2 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -116,7 +116,7 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget configButton->setPopupMode(QToolButton::QToolButton::InstantPopup); m_toolbar->addWidget(configButton); - if (name == "clip") { + if (name == Kdenlive::clipMonitor) { m_markerMenu = new QMenu(i18n("Go to marker..."), this); m_markerMenu->setEnabled(false); m_configMenu->addMenu(m_markerMenu); @@ -182,7 +182,7 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget connect(render, SIGNAL(rendererStopped(int)), this, SLOT(rendererStopped(int))); connect(render, SIGNAL(rendererPosition(int)), this, SLOT(seekCursor(int))); - if (name != "clip") { + if (name != Kdenlive::clipMonitor) { connect(render, SIGNAL(rendererPosition(int)), this, SIGNAL(renderPosition(int))); connect(render, SIGNAL(durationChanged(int)), this, SIGNAL(durationChanged(int))); connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SIGNAL(zoneUpdated(QPoint))); @@ -192,7 +192,7 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget if (m_monitorRefresh) m_monitorRefresh->show(); - if (name == "project") { + if (name == Kdenlive::projectMonitor) { m_effectWidget = new MonitorEditWidget(render, m_videoBox); m_toolbar->addAction(m_effectWidget->getVisibilityAction()); lay->addWidget(m_effectWidget); @@ -271,7 +271,7 @@ void Monitor::setupMenu(QMenu *goMenu, QAction *playZone, QAction *loopZone, QMe } //TODO: add save zone to timeline monitor when fixed - if (m_name == "clip") { + if (m_name == Kdenlive::clipMonitor) { m_contextMenu->addMenu(m_markerMenu); m_contextMenu->addAction(KIcon("document-save"), i18n("Save zone"), this, SLOT(slotSaveZone())); QAction *extractZone = m_configMenu->addAction(KIcon("document-new"), i18n("Extract Zone"), this, SLOT(slotExtractCurrentZone())); @@ -280,7 +280,7 @@ void Monitor::setupMenu(QMenu *goMenu, QAction *playZone, QAction *loopZone, QMe QAction *extractFrame = m_configMenu->addAction(KIcon("document-new"), i18n("Extract frame"), this, SLOT(slotExtractCurrentFrame())); m_contextMenu->addAction(extractFrame); - if (m_name != "clip") { + if (m_name != Kdenlive::clipMonitor) { QAction *splitView = m_contextMenu->addAction(KIcon("view-split-left-right"), i18n("Split view"), render, SLOT(slotSplitView(bool))); splitView->setCheckable(true); m_configMenu->addAction(splitView); @@ -841,7 +841,7 @@ void Monitor::slotSetClipProducer(DocClipBase *clip, QPoint zone, bool forceUpda render->setProducer(NULL, -1); return; } - + if (clip != m_currentClip || forceUpdate) { m_currentClip = clip; if (m_currentClip) activateMonitor(); @@ -1005,7 +1005,7 @@ void Monitor::slotSetSelectedClip(Transition* item) void Monitor::slotEffectScene(bool show) { - if (m_name == "project") { + if (m_name == Kdenlive::projectMonitor) { if (m_monitorRefresh) { m_monitorRefresh->setVisible(!show); } else { diff --git a/src/monitormanager.cpp b/src/monitormanager.cpp index c7fe6b50..fa51ca4d 100644 --- a/src/monitormanager.cpp +++ b/src/monitormanager.cpp @@ -63,6 +63,17 @@ void MonitorManager::removeMonitor(AbstractMonitor *monitor) m_monitorsList.removeAll(monitor); } +AbstractMonitor* MonitorManager::monitor(const QString monitorName) +{ + AbstractMonitor *monitor = NULL; + for (int i = 0; i < m_monitorsList.size(); i++) { + if (m_monitorsList[i]->name() == monitorName) { + monitor = m_monitorsList[i]; + } + } + return monitor; +} + bool MonitorManager::activateMonitor(const QString &name) { if (m_clipMonitor == NULL || m_projectMonitor == NULL) @@ -94,9 +105,9 @@ bool MonitorManager::isActive(const QString &name) const void MonitorManager::slotSwitchMonitors(bool activateClip) { if (activateClip) - activateMonitor("clip"); + activateMonitor(Kdenlive::clipMonitor); else - activateMonitor("project"); + activateMonitor(Kdenlive::projectMonitor); } void MonitorManager::stopActiveMonitor() @@ -207,11 +218,14 @@ void MonitorManager::slotRefreshCurrentMonitor(const QString &id) void MonitorManager::slotUpdateAudioMonitoring() { // if(...) added since they are 0x0 when the config wizard is running! --Granjow - if (m_clipMonitor) { + /*if (m_clipMonitor) { m_clipMonitor->render->analyseAudio = KdenliveSettings::monitor_audio(); } if (m_projectMonitor) { m_projectMonitor->render->analyseAudio = KdenliveSettings::monitor_audio(); + }*/ + for (int i = 0; i < m_monitorsList.count(); i++) { + if (m_monitorsList.at(i)->abstractRender()) m_monitorsList.at(i)->abstractRender()->analyseAudio = KdenliveSettings::monitor_audio(); } } diff --git a/src/monitormanager.h b/src/monitormanager.h index 7fbe5200..5468fdf7 100644 --- a/src/monitormanager.h +++ b/src/monitormanager.h @@ -39,6 +39,10 @@ public: void resetProfiles(Timecode tc); void stopActiveMonitor(); AbstractRender *activeRenderer(); + /** Searches for a monitor with the given name. + @return NULL, if no monitor could be found, or the monitor otherwise. + */ + AbstractMonitor *monitor(const QString monitorName); void updateScopeSource(); void clearScopeSource(); diff --git a/src/recmonitor.cpp b/src/recmonitor.cpp index 8988df99..6a7140d5 100644 --- a/src/recmonitor.cpp +++ b/src/recmonitor.cpp @@ -93,20 +93,20 @@ RecMonitor::RecMonitor(QString name, MonitorManager *manager, QWidget *parent) : m_recAction = toolbar->addAction(KIcon("media-record"), i18n("Record")); connect(m_recAction, SIGNAL(triggered()), this, SLOT(slotRecord())); m_recAction->setCheckable(true); - + rec_options->setIcon(KIcon("system-run")); QMenu *menu = new QMenu(this); m_addCapturedClip = new QAction(i18n("Add Captured File to Project"), this); m_addCapturedClip->setCheckable(true); m_addCapturedClip->setChecked(true); menu->addAction(m_addCapturedClip); - + rec_audio->setChecked(KdenliveSettings::v4l_captureaudio()); rec_video->setChecked(KdenliveSettings::v4l_capturevideo()); - + m_previewSettings = new QAction(i18n("Recording Preview"), this); m_previewSettings->setCheckable(true); - + rec_options->setMenu(menu); menu->addAction(m_previewSettings); @@ -142,7 +142,7 @@ RecMonitor::RecMonitor(QString name, MonitorManager *manager, QWidget *parent) : connect(m_captureProcess, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotProcessStatus(QProcess::ProcessState))); connect(m_captureProcess, SIGNAL(readyReadStandardError()), this, SLOT(slotReadDvgrabInfo())); - + QString videoDriver = KdenliveSettings::videodrivername(); #if QT_VERSION >= 0x040600 QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); @@ -488,34 +488,34 @@ void RecMonitor::slotStartPreview(bool play) break; case VIDEO4LINUX: path = KStandardDirs::locateLocal("appdata", "profiles/video4linux"); - m_manager->activateMonitor("record"); + m_manager->activateMonitor(Kdenlive::recordMonitor); buildMltDevice(path); profile = ProfilesDialog::getVideoProfile(path); producer = getV4lXmlPlaylist(profile); - + //producer = QString("avformat-novalidate:video4linux2:%1?width:%2&height:%3&frame_rate:%4").arg(KdenliveSettings::video4vdevice()).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den); if (!m_captureDevice->slotStartPreview(producer, true)) { // v4l capture failed to start video_frame->setText(i18n("Failed to start Video4Linux,\ncheck your parameters...")); m_videoBox->setHidden(true); - + } else { m_playAction->setEnabled(false); m_stopAction->setEnabled(true); m_isPlaying = true; } - + break; case BLACKMAGIC: path = KdenliveSettings::current_profile(); - m_manager->activateMonitor("record"); + m_manager->activateMonitor(Kdenlive::recordMonitor); buildMltDevice(path); producer = QString("decklink:%1").arg(KdenliveSettings::decklink_capturedevice()); if (!m_captureDevice->slotStartPreview(producer)) { // v4l capture failed to start video_frame->setText(i18n("Failed to start Decklink,\ncheck your parameters...")); m_videoBox->setHidden(true); - + } else { m_playAction->setEnabled(false); m_stopAction->setEnabled(true); @@ -583,7 +583,7 @@ void RecMonitor::slotRecord() switch (device_selector->currentIndex()) { case VIDEO4LINUX: - m_manager->activateMonitor("record"); + m_manager->activateMonitor(Kdenlive::recordMonitor); path = KStandardDirs::locateLocal("appdata", "profiles/video4linux"); profile = ProfilesDialog::getVideoProfile(path); m_videoBox->setRatio((double) profile.display_aspect_num / profile.display_aspect_den); @@ -591,7 +591,7 @@ void RecMonitor::slotRecord() playlist = getV4lXmlPlaylist(profile); v4lparameters = KdenliveSettings::v4l_parameters(); - + // TODO: when recording audio only, allow param configuration? if (!rec_video->isChecked()) v4lparameters.clear(); @@ -623,7 +623,7 @@ void RecMonitor::slotRecord() v4lparameters = QString(v4lparameters.section("acodec", 0, 0) + "an=1 " + endParam).simplified(); } } - + showPreview = m_previewSettings->isChecked(); if (!rec_video->isChecked()) showPreview = false; @@ -635,19 +635,19 @@ void RecMonitor::slotRecord() m_previewSettings->setEnabled(false); } else { - video_frame->setText(i18n("Failed to start Video4Linux,\ncheck your parameters...")); + video_frame->setText(i18n("Failed to start Video4Linux,\ncheck your parameters...")); m_videoBox->setHidden(true); m_isCapturing = false; } break; - + case BLACKMAGIC: - m_manager->activateMonitor("record"); + m_manager->activateMonitor(Kdenlive::recordMonitor); path = KdenliveSettings::current_profile(); profile = ProfilesDialog::getVideoProfile(path); m_videoBox->setRatio((double) profile.display_aspect_num / profile.display_aspect_den); buildMltDevice(path); - + playlist = QString("producer100000pause%1decklink").arg(KdenliveSettings::decklink_capturedevice()); if (m_captureDevice->slotStartCapture(KdenliveSettings::decklink_parameters(), m_captureFile.path(), QString("decklink:%1").arg(KdenliveSettings::decklink_capturedevice()), m_previewSettings->isChecked(), false)) { @@ -665,7 +665,7 @@ void RecMonitor::slotRecord() m_isCapturing = false; } break; - + case SCREENGRAB: switch (KdenliveSettings::rmd_capture_type()) { case 0: @@ -731,13 +731,13 @@ void RecMonitor::slotRecord() } const QString RecMonitor::getV4lXmlPlaylist(MltVideoProfile profile) { - + QString playlist = QString("").arg(profile.width).arg(profile.height).arg(profile.progressive).arg(profile.sample_aspect_num).arg(profile.sample_aspect_den).arg(profile.display_aspect_num).arg(profile.display_aspect_den).arg(profile.frame_rate_num).arg(profile.frame_rate_den).arg(profile.colorspace); - + if (rec_video->isChecked()) { playlist.append(QString("producer1000000loopvideo4linux2:%1?width:%2&height:%3&frame_rate:%4avformat-novalidate").arg(KdenliveSettings::video4vdevice()).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den)); } - + if (rec_audio->isChecked()) { playlist.append(QString("producer1000000loopalsa:%50-1avformat-novalidate").arg(KdenliveSettings::v4l_alsadevicename())); } @@ -859,7 +859,7 @@ void RecMonitor::manageCapturedFiles() if (QFile::rename(url.path(), newUrl)) { url = KUrl(newUrl); } - + } capturedFiles.append(url); } diff --git a/src/renderer.cpp b/src/renderer.cpp index 3dd02443..53520518 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -105,7 +105,6 @@ static void consumer_gl_frame_show(mlt_consumer, Render * self, mlt_frame frame_ Render::Render(const QString & rendererName, int winid, QString profile, QWidget *parent) : AbstractRender(rendererName, parent), - analyseAudio(KdenliveSettings::monitor_audio()), m_name(rendererName), m_mltConsumer(NULL), m_mltProducer(NULL), @@ -119,6 +118,7 @@ Render::Render(const QString & rendererName, int winid, QString profile, QWidget m_blackClip(NULL), m_winid(winid) { + analyseAudio = KdenliveSettings::monitor_audio(); if (profile.isEmpty()) profile = KdenliveSettings::current_profile(); buildConsumer(profile); m_mltProducer = m_blackClip->cut(0, 1); @@ -137,7 +137,7 @@ Render::~Render() void Render::closeMlt() -{ +{ //delete m_osdTimer; m_requestList.clear(); m_infoThread.waitForFinished(); @@ -203,7 +203,7 @@ void Render::buildConsumer(const QString &profileName) m_blackClip->set("id", "black"); m_blackClip->set("mlt_type", "producer"); - if (KdenliveSettings::external_display() && m_name != "clip") { + if (KdenliveSettings::external_display() && m_name != Kdenlive::clipMonitor) { #ifdef USE_BLACKMAGIC // Use blackmagic card for video output QMap< QString, QString > profileProperties = ProfilesDialog::getSettingsFromFile(profileName); @@ -360,7 +360,7 @@ int Render::resetProfile(const QString &profileName, bool dropSceneList) buildConsumer(profileName); double new_fps = m_mltProfile->fps(); double new_dar = m_mltProfile->dar(); - + if (!dropSceneList) { // We need to recover our playlist if (current_fps != new_fps) { @@ -447,7 +447,7 @@ QImage Render::extractFrame(int frame_position, QString path, int width, int hei else delete producer; } } - + if (!m_mltProducer || !path.isEmpty()) { QImage pix(width, height, QImage::Format_RGB32); pix.fill(Qt::black); @@ -644,7 +644,7 @@ void Render::processFileProperties() info = m_requestList.takeFirst(); m_processingClipId = info.clipId; m_infoMutex.unlock(); - + QString path; bool proxyProducer; if (info.xml.hasAttribute("proxy") && info.xml.attribute("proxy") != "-") { @@ -784,7 +784,7 @@ void Render::processFileProperties() int imageWidth = (int)((double) info.imageHeight * m_mltProfile->width() / m_mltProfile->height() + 0.5); int fullWidth = (int)((double) info.imageHeight * m_mltProfile->dar() + 0.5); int frameNumber = info.xml.attribute("thumbnail", "-1").toInt(); - + if ((!info.replaceProducer && info.xml.hasAttribute("file_hash")) || proxyProducer) { // Clip already has all properties if (proxyProducer) { @@ -805,9 +805,9 @@ void Render::processFileProperties() stringMap filePropertyMap; stringMap metadataPropertyMap; char property[200]; - + if (frameNumber > 0) producer->seek(frameNumber); - + duration = duration > 0 ? duration : producer->get_playtime(); filePropertyMap["duration"] = QString::number(duration); //kDebug() << "/////// PRODUCER: " << url.path() << " IS: " << producer->get_playtime(); @@ -857,9 +857,9 @@ void Render::processFileProperties() } } } - + // Get frame rate - int vindex = producer->get_int("video_index"); + int vindex = producer->get_int("video_index"); if (vindex > -1) { snprintf(property, sizeof(property), "meta.media.%d.stream.frame_rate", vindex); if (producer->get(property)) @@ -925,7 +925,7 @@ void Render::processFileProperties() int video_max = 0; int default_audio = producer->get_int("audio_index"); int audio_max = 0; - + int scan = producer->get_int("meta.media.progressive"); filePropertyMap["progressive"] = QString::number(scan); @@ -1295,7 +1295,7 @@ void Render::saveZone(KUrl url, QString desc, QPoint zone) Mlt::Consumer xmlConsumer(*m_mltProfile, ("xml:" + url.path()).toUtf8().constData()); m_mltProducer->optimise(); xmlConsumer.set("terminate_on_pause", 1); - if (m_name == "clip") { + if (m_name == Kdenlive::clipMonitor) { Mlt::Producer *prod = m_mltProducer->cut(zone.x(), zone.y()); Mlt::Playlist list; list.insert_at(0, prod, 0); @@ -1425,7 +1425,7 @@ void Render::switchPlay(bool play) return; if (m_isZoneMode) resetZoneMode(); if (play && m_mltProducer->get_speed() == 0.0) { - if (m_name == "clip" && m_mltConsumer->position() == m_mltProducer->get_out()) m_mltProducer->seek(0); + if (m_name == Kdenlive::clipMonitor && m_mltConsumer->position() == m_mltProducer->get_out()) m_mltProducer->seek(0); if (m_mltConsumer->is_stopped()) { m_mltConsumer->start(); } @@ -1437,7 +1437,7 @@ void Render::switchPlay(bool play) m_mltProducer->seek(m_mltConsumer->position()); if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop(); if (m_isZoneMode) resetZoneMode(); - + //emitConsumerStopped(); /*m_mltConsumer->set("refresh", 0); m_mltConsumer->stop(); @@ -1585,12 +1585,19 @@ const QString & Render::rendererName() const void Render::emitFrameUpdated(Mlt::Frame& frame) { - mlt_image_format format = mlt_image_rgb24; + mlt_image_format format = mlt_image_rgb24a; + int width = 0; + int height = 0; + const uchar* image = frame.get_image(format, width, height); + QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied); + memcpy(qimage.scanLine(0), image, width * height * 4); + + /*mlt_image_format format = mlt_image_rgb24; int width = 0; int height = 0; const uchar* image = frame.get_image(format, width, height); QImage qimage(width, height, QImage::Format_RGB888); - memcpy(qimage.bits(), image, width * height * 3); + memcpy(qimage.bits(), image, width * height * 3);*/ emit frameUpdated(qimage); } @@ -1925,7 +1932,7 @@ Mlt::Tractor *Render::lockService() } service.lock(); return new Mlt::Tractor(service); - + } void Render::unlockService(Mlt::Tractor *tractor) @@ -2812,7 +2819,7 @@ bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList par service.lock(); for (int j = 0; j < params.count(); j++) { filter->set((prefix + params.at(j).name()).toUtf8().constData(), params.at(j).value().toUtf8().constData()); - } + } delete clip; service.unlock(); @@ -3105,7 +3112,7 @@ void Render::mltChangeTrackState(int track, bool mute, bool blind) trackProducer.set("hide", 0); } if (audioMixingBroken) fixAudioMixing(tractor); - + tractor.multitrack()->refresh(); tractor.refresh(); refresh(); diff --git a/src/renderer.h b/src/renderer.h index 800f1ea5..1b8d133e 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -277,8 +277,6 @@ Q_OBJECT public: void showFrame(Mlt::Frame&); void showAudio(Mlt::Frame&); - /** @brief This property is used to decide if the renderer should send audio data for monitoring. */ - bool analyseAudio; QList checkTrackSequence(int); void sendFrameUpdate(); diff --git a/src/scopes/abstractscopewidget.cpp b/src/scopes/abstractscopewidget.cpp index 0622bd97..6d4b1c8e 100644 --- a/src/scopes/abstractscopewidget.cpp +++ b/src/scopes/abstractscopewidget.cpp @@ -8,11 +8,12 @@ * (at your option) any later version. * ***************************************************************************/ +#include "qtconcurrentrun.h" + #include "abstractscopewidget.h" #include "renderer.h" #include "monitor.h" -#include #include #include #include @@ -62,7 +63,8 @@ AbstractScopeWidget::AbstractScopeWidget(bool trackMouse, QWidget *parent) : initialDimensionUpdateDone(false), m_requestForcedUpdate(false), m_rescaleMinDist(4), - m_rescaleVerticalThreshold(2.0f) + m_rescaleVerticalThreshold(2.0f), + m_rescaleActive(false) { m_scopePalette = QPalette(); @@ -427,7 +429,7 @@ void AbstractScopeWidget::slotHUDRenderingFinished(uint mseconds, uint oldFactor qDebug() << "Trying to start a new HUD thread for " << m_widgetName << ". New frames/updates: " << m_newHUDFrames << "/" << m_newHUDUpdates; #endif - prodHUDThread();; + prodHUDThread(); } } @@ -531,7 +533,7 @@ void AbstractScopeWidget::slotResetRealtimeFactor(bool realtimeChecked) } } -bool AbstractScopeWidget::autoRefreshEnabled() +bool AbstractScopeWidget::autoRefreshEnabled() const { return m_aAutoRefresh->isChecked(); } diff --git a/src/scopes/abstractscopewidget.h b/src/scopes/abstractscopewidget.h index e518e1f0..4fe726d9 100644 --- a/src/scopes/abstractscopewidget.h +++ b/src/scopes/abstractscopewidget.h @@ -8,16 +8,28 @@ * (at your option) any later version. * ***************************************************************************/ + + +#ifndef ABSTRACTSCOPEWIDGET_H +#define ABSTRACTSCOPEWIDGET_H + +#include +#include + +class QMenu; /** - This abstract widget is a proof that abstract things sometimes *are* useful. + \brief Abstract class for audio/colour scopes (receive data and paint it). + + This abstract widget is a proof that abstract things sometimes \b *are* useful. The widget expects three layers which - * Will be painted on top of each other on each update - * Are rendered in a separate thread so that the UI is not blocked - * Are rendered only if necessary (e.g., if a layer does not depend + \li Will be painted on top of each other on each update + \li Are rendered in a separate thread so that the UI is not blocked + \li Are rendered only if necessary (e.g., if a layer does not depend on input images, it will not be re-rendered for incoming frames) The layer order is as follows: + \verbatim _____________________ / \ / HUD Layer \ @@ -33,6 +45,7 @@ / Background Layer \ / \ --------------------------- + \endverbatim Colors of Scope Widgets are defined in here (and thus don't need to be re-defined in the implementation of the widget's .ui file). @@ -44,22 +57,16 @@ the comments on the unimplemented methods carefully. They are not only here for optical amusement, but also contain important information. */ - -#ifndef ABSTRACTSCOPEWIDGET_H -#define ABSTRACTSCOPEWIDGET_H - -#include -#include - -class QMenu; - class AbstractScopeWidget : public QWidget { Q_OBJECT public: - /** trackMouse enables mouse tracking; The variables m_mousePos and m_mouseWithinWidget will be set - if mouse tracking is enabled. See also signalMousePositionChanged(). */ + /** + \param trackMouse enables mouse tracking; The variables m_mousePos and m_mouseWithinWidget will be set + if mouse tracking is enabled. + \see signalMousePositionChanged(): Emitted when mouse tracking is enabled + */ AbstractScopeWidget(bool trackMouse = false, QWidget *parent = 0); virtual ~AbstractScopeWidget(); // Must be virtual because of inheritance, to avoid memory leaks @@ -75,7 +82,9 @@ public: /** Tell whether this scope has auto-refresh enabled. Required for determining whether new data (e.g. an image frame) has to be delivered to this widget. */ - bool autoRefreshEnabled(); + bool autoRefreshEnabled() const; + + bool needsSingleFrame(); ///// Unimplemented ///// @@ -156,13 +165,20 @@ protected: that have to change together with the widget's size. */ virtual QRect scopeRect() = 0; - /** @brief HUD renderer. Must emit signalHUDRenderingFinished(). @see renderScope */ + /** @brief HUD renderer. Must emit signalHUDRenderingFinished(). + @see renderScope(uint). */ virtual QImage renderHUD(uint accelerationFactor) = 0; - /** @brief Scope renderer. Must emit signalScopeRenderingFinished() - when calculation has finished, to allow multi-threading. - accelerationFactor hints how much faster than usual the calculation should be accomplished, if possible. */ + /** @brief Rendering function for the scope layer. + This function \b must emit signalScopeRenderingFinished(), otherwise the scope + will not attempt to ever call this function again. This signal is required for multi-threading; + not emitting it on unused rendering function may increase performance. + @param accelerationFactor hints how much faster than usual the calculation should be accomplished, if possible. + @see renderHUD(uint) for the upper layer + @see renderBackground(uint) for the layer below + */ virtual QImage renderScope(uint accelerationFactor) = 0; - /** @brief Background renderer. Must emit signalBackgroundRenderingFinished(). @see renderScope */ + /** @brief Background renderer. Must emit signalBackgroundRenderingFinished(). + @see renderScope(uint) */ virtual QImage renderBackground(uint accelerationFactor) = 0; /** Must return true if the HUD layer depends on the input data. @@ -198,17 +214,21 @@ protected: // void raise(); // Called only when manually calling the event -> useless -protected slots: +public slots: /** Forces an update of all layers. */ void forceUpdate(bool doUpdate = true); void forceUpdateHUD(); void forceUpdateScope(); void forceUpdateBackground(); + +protected slots: void slotAutoRefreshToggled(bool); signals: - /** mseconds represent the time taken for the calculation, - accelerationFactor is the acceleration factor that has been used for this calculation. */ + /** + \param mseconds represents the time taken for the calculation. + \param accelerationFactor is the acceleration factor that has been used for this calculation. + */ void signalHUDRenderingFinished(uint mseconds, uint accelerationFactor); void signalScopeRenderingFinished(uint mseconds, uint accelerationFactor); void signalBackgroundRenderingFinished(uint mseconds, uint accelerationFactor); @@ -218,26 +238,27 @@ signals: This signal is typically connected to forceUpdateHUD(). */ void signalMousePositionChanged(); - /** Do we need the renderer to send its frames to us? */ + /** Do we need the renderer to send its frames to us? + Emitted when auto-refresh is toggled. */ void requestAutoRefresh(bool); private: /** Counts the number of data frames that have been rendered in the active monitor. - The frame number will be reset when the calculation starts for the current data set. */ + The frame number will be reset when the calculation starts for the current data set. */ QAtomicInt m_newHUDFrames; QAtomicInt m_newScopeFrames; QAtomicInt m_newBackgroundFrames; /** Counts the number of updates that, unlike new frames, force a recalculation - of the scope, like for example a resize event. */ + of the scope, like for example a resize event. */ QAtomicInt m_newHUDUpdates; QAtomicInt m_newScopeUpdates; QAtomicInt m_newBackgroundUpdates; /** The semaphores ensure that the QFutures for the HUD/Scope/Background threads cannot - be assigned a new thread while it is still running. (Could cause deadlocks and other - nasty things known from parallelism.) */ + be assigned a new thread while it is still running. (Could cause deadlocks and other + nasty things known from parallelism.) */ QSemaphore m_semaphoreHUD; QSemaphore m_semaphoreScope; QSemaphore m_semaphoreBackground; @@ -273,11 +294,11 @@ private: protected slots: void customContextMenuRequested(const QPoint &pos); /** To be called when a new frame has been received. - The scope then decides whether and when it wants to recalculate the scope, depending - on whether it is currently visible and whether a calculation thread is already running. */ + The scope then decides whether and when it wants to recalculate the scope, depending + on whether it is currently visible and whether a calculation thread is already running. */ void slotRenderZoneUpdated(); /** The following slots are called when rendering of a component has finished. They e.g. update - the widget and decide whether to immediately restart the calculation thread. */ + the widget and decide whether to immediately restart the calculation thread. */ void slotHUDRenderingFinished(uint mseconds, uint accelerationFactor); void slotScopeRenderingFinished(uint mseconds, uint accelerationFactor); void slotBackgroundRenderingFinished(uint mseconds, uint accelerationFactor); diff --git a/src/scopes/audioscopes/abstractaudioscopewidget.cpp b/src/scopes/audioscopes/abstractaudioscopewidget.cpp index 16b50681..25000045 100644 --- a/src/scopes/audioscopes/abstractaudioscopewidget.cpp +++ b/src/scopes/audioscopes/abstractaudioscopewidget.cpp @@ -36,7 +36,7 @@ AbstractAudioScopeWidget::AbstractAudioScopeWidget(bool trackMouse, QWidget *par { } -void AbstractAudioScopeWidget::slotReceiveAudio(const QVector &sampleData, int freq, int num_channels, int num_samples) +void AbstractAudioScopeWidget::slotReceiveAudio(QVector sampleData, int freq, int num_channels, int num_samples) { #ifdef DEBUG_AASW qDebug() << "Received audio for " << widgetName() << "."; diff --git a/src/scopes/audioscopes/abstractaudioscopewidget.h b/src/scopes/audioscopes/abstractaudioscopewidget.h index b9c3430a..a3c352b7 100644 --- a/src/scopes/audioscopes/abstractaudioscopewidget.h +++ b/src/scopes/audioscopes/abstractaudioscopewidget.h @@ -17,13 +17,16 @@ #include -#include "abstractscopewidget.h" +#include "../abstractscopewidget.h" class QMenu; class Monitor; class Render; +/** + \brief Abstract class for scopes analyzing audio samples. + */ class AbstractAudioScopeWidget : public AbstractScopeWidget { Q_OBJECT @@ -31,6 +34,9 @@ public: AbstractAudioScopeWidget(bool trackMouse = false, QWidget *parent = 0); virtual ~AbstractAudioScopeWidget(); +public slots: + void slotReceiveAudio(QVector sampleData, int freq, int num_channels, int num_samples); + protected: /** @brief This is just a wrapper function, subclasses can use renderAudioScope. */ virtual QImage renderScope(uint accelerationFactor); @@ -51,9 +57,6 @@ private: QVector m_audioFrame; QAtomicInt m_newData; -private slots: - void slotReceiveAudio(const QVector& sampleData, int freq, int num_channels, int num_samples); - }; #endif // ABSTRACTAUDIOSCOPEWIDGET_H diff --git a/src/scopes/audioscopes/audiosignal.cpp b/src/scopes/audioscopes/audiosignal.cpp index 3582148c..bc4f68f9 100644 --- a/src/scopes/audioscopes/audiosignal.cpp +++ b/src/scopes/audioscopes/audiosignal.cpp @@ -20,123 +20,68 @@ #include "audiosignal.h" #include +#include #include -#include #include +#include #include #include #include #include -AudioSignal::AudioSignal(QWidget *parent): QWidget(parent) +AudioSignal::AudioSignal(QWidget *parent): AbstractAudioScopeWidget(false, parent) { - //QVBoxLayout *vbox=new QVBoxLayout(this); - //label=new QLabel(); - //vbox->addWidget(label); setMinimumHeight(10); setMinimumWidth(10); dbscale << 0 << -1 << -2 << -3 << -4 << -5 << -6 << -8 << -10 << -20 << -40 ; - setContextMenuPolicy(Qt::ActionsContextMenu); - m_aMonitoringEnabled = new QAction(i18n("Monitor audio signal"), this); - m_aMonitoringEnabled->setCheckable(true); - m_aMonitoringEnabled->setChecked(true); - connect(m_aMonitoringEnabled, SIGNAL(toggled(bool)), this, SLOT(slotSwitchAudioMonitoring(bool))); + m_menu->removeAction(m_aRealtime); connect(&m_timer,SIGNAL(timeout()),this,SLOT(slotNoAudioTimeout())); - addAction(m_aMonitoringEnabled); + init(); } AudioSignal::~AudioSignal() { - delete m_aMonitoringEnabled; } -bool AudioSignal::monitoringEnabled() const -{ - return m_aMonitoringEnabled->isChecked(); -} - -void AudioSignal::slotReceiveAudio(const QVector& data, int, int num_channels, int samples) +QImage AudioSignal::renderAudioScope(uint, const QVector audioFrame, + const int, const int num_channels, const int samples, const int) { + QTime start = QTime::currentTime(); int num_samples = samples > 200 ? 200 : samples; QByteArray channels; - int num_oversample=0; for (int i = 0; i < num_channels; i++) { long val = 0; - double over1=0.0; - double over2=0.0; for (int s = 0; s < num_samples; s ++) { - int sample=abs(data[i+s*num_channels] / 128); - val += sample; - if (sample==128){ - num_oversample++; - }else{ - num_oversample=0; - } - //if 3 samples over max => 1 peak over 0 db (0db=40.0) - if (num_oversample>3){ - over1=41.0/42.0*127; - } - // 10 samples @max => show max signal - if (num_oversample>10){ - over2=127; - } - - - + val += abs(audioFrame[i+s*num_channels] / 128); } - //max amplitude = 40/42, 3to10 oversamples=41, more then 10 oversamples=42 - if (over2>0.0){ - channels.append(over2); - } else if (over1>0.0){ - channels.append(over1); - }else - channels.append(val / num_samples*40.0/42.0); + channels.append(val / num_samples); } - showAudio(channels); - m_timer.start(1000); -} -void AudioSignal::slotNoAudioTimeout(){ - peeks.fill(0); - showAudio(QByteArray(2,0)); - m_timer.stop(); -} - -void AudioSignal::showAudio(const QByteArray arr) -{ - channels = arr; if (peeks.count()!=channels.count()){ peeks=QByteArray(channels.count(),0); peekage=QByteArray(channels.count(),0); } for (int chan=0;chan50 ) + peekage[chan] = peekage[chan]+1; + if ( peeks.at(chan)50 ) { peekage[chan]=0; - peeks[chan]=arr[chan]; + peeks[chan]=channels[chan]; } } - update(); -} - -double AudioSignal::valueToPixel(double in) -{ - //in=0 -> return 0 (null length from max), in=127/127 return 1 (max length ) - return 1.0- log10( in)/log10(1.0/127.0); -} -void AudioSignal::paintEvent(QPaintEvent* /*e*/) -{ - if (!m_aMonitoringEnabled->isChecked()) { - return; - } - QPainter p(this); + QImage image(m_scopeRect.size(), QImage::Format_ARGB32); + image.fill(Qt::transparent); + QPainter p(&image); + p.setPen(Qt::white); + p.setRenderHint(QPainter::TextAntialiasing, false); + p.setRenderHint(QPainter::Antialiasing, false); + int numchan = channels.size(); bool horiz=width() > height(); int dbsize=20; @@ -145,7 +90,7 @@ void AudioSignal::paintEvent(QPaintEvent* /*e*/) for (int i = 0; i < numchan; i++) { //int maxx= (unsigned char)channels[i] * (horiz ? width() : height() ) / 127; double valpixel=valueToPixel((double)(unsigned char)channels[i]/127.0); - int maxx= height() * valpixel; + int maxx= height() * valpixel; int xdelta= height() /42 ; int _y2= (showdb?width()-dbsize:width () ) / numchan - 1 ; int _y1= (showdb?width()-dbsize:width() ) *i/numchan; @@ -153,7 +98,7 @@ void AudioSignal::paintEvent(QPaintEvent* /*e*/) if (horiz){ dbsize=9; showdb=height()>(dbsize); - maxx=width()*valpixel; + maxx=width()*valpixel; xdelta = width() / 42; _y2=( showdb?height()-dbsize:height() ) / numchan - 1 ; _y1= (showdb?height()-dbsize:height() ) * i/numchan; @@ -182,7 +127,7 @@ void AudioSignal::paintEvent(QPaintEvent* /*e*/) } } int xp=valueToPixel((double)peeks.at(i)/127.0)*(horiz?width():height())-2; - p.fillRect(horiz?xp:_y1,horiz?_y1:height()-xdelta-xp,horiz?3:_y2,horiz?_y2:3,QBrush(Qt::black,Qt::SolidPattern)); + p.fillRect(horiz?xp:_y1,horiz?_y1:height()-xdelta-xp,horiz?3:_y2,horiz?_y2:3,QBrush(Qt::gray,Qt::SolidPattern)); } if (showdb){ @@ -198,11 +143,87 @@ void AudioSignal::paintEvent(QPaintEvent* /*e*/) } } p.end(); + emit signalScopeRenderingFinished((uint) start.elapsed(), 1); + return image; +} + +QRect AudioSignal::scopeRect() { return QRect(0, 0, width(), height()); } + +QImage AudioSignal::renderHUD(uint) { return QImage(); } +QImage AudioSignal::renderBackground(uint) { return QImage(); } + +void AudioSignal::slotReceiveAudio(QVector data, int, int num_channels, int samples) +{ + + int num_samples = samples > 200 ? 200 : samples; + + QByteArray channels; + int num_oversample=0; + for (int i = 0; i < num_channels; i++) { + long val = 0; + double over1=0.0; + double over2=0.0; + for (int s = 0; s < num_samples; s ++) { + int sample=abs(data[i+s*num_channels] / 128); + val += sample; + if (sample==128){ + num_oversample++; + }else{ + num_oversample=0; + } + //if 3 samples over max => 1 peak over 0 db (0db=40.0) + if (num_oversample>3){ + over1=41.0/42.0*127; + } + // 10 samples @max => show max signal + if (num_oversample>10){ + over2=127; + } + + + + } + //max amplitude = 40/42, 3to10 oversamples=41, more then 10 oversamples=42 + if (over2>0.0){ + channels.append(over2); + } else if (over1>0.0){ + channels.append(over1); + }else + channels.append(val / num_samples*40.0/42.0); + } + showAudio(channels); + m_timer.start(1000); +} + +void AudioSignal::slotNoAudioTimeout(){ + peeks.fill(0); + showAudio(QByteArray(2,0)); + m_timer.stop(); +} + +void AudioSignal::showAudio(const QByteArray arr) +{ + channels = arr; + if (peeks.count()!=channels.count()){ + peeks=QByteArray(channels.count(),0); + peekage=QByteArray(channels.count(),0); + } + for (int chan=0;chan50 ) + { + peekage[chan]=0; + peeks[chan]=arr[chan]; + } + } + update(); } -void AudioSignal::slotSwitchAudioMonitoring(bool) +double AudioSignal::valueToPixel(double in) { - emit updateAudioMonitoring(); + //in=0 -> return 0 (null length from max), in=127/127 return 1 (max length ) + return 1.0- log10( in)/log10(1.0/127.0); } #include "audiosignal.moc" diff --git a/src/scopes/audioscopes/audiosignal.h b/src/scopes/audioscopes/audiosignal.h index 6cb9b071..dd683850 100644 --- a/src/scopes/audioscopes/audiosignal.h +++ b/src/scopes/audioscopes/audiosignal.h @@ -20,6 +20,8 @@ #ifndef AUDIOSIGNAL_H #define AUDIOSIGNAL_H +#include "scopes/audioscopes/abstractaudioscopewidget.h" + #include #include #include @@ -30,7 +32,7 @@ class QLabel; #include -class AudioSignal : public QWidget +class AudioSignal : public AbstractAudioScopeWidget { Q_OBJECT public: @@ -39,23 +41,27 @@ public: /** @brief Used for checking whether audio data needs to be delivered */ bool monitoringEnabled() const; + QRect scopeRect(); + QImage renderHUD(uint accelerationFactor); + QImage renderBackground(uint accelerationFactor); + QImage renderAudioScope(uint accelerationFactor, const QVector audioFrame, const int, const int num_channels, const int samples, const int); + + QString widgetName() const { return "audioSignal"; } + bool isHUDDependingOnInput() const { return false; } + bool isScopeDependingOnInput() const { return true; } + bool isBackgroundDependingOnInput() const { return false; } + private: double valueToPixel(double in); - QTimer m_timer; - QLabel* label; + QTimer m_timer; QByteArray channels,peeks,peekage; - QList dbscale; - QAction *m_aMonitoringEnabled; - -protected: - void paintEvent(QPaintEvent*); + QList dbscale; public slots: void showAudio(const QByteArray); - void slotReceiveAudio(const QVector&,int,int,int); + void slotReceiveAudio(QVector,int,int,int); private slots: - void slotSwitchAudioMonitoring(bool isOn); - void slotNoAudioTimeout(); + void slotNoAudioTimeout(); signals: void updateAudioMonitoring(); diff --git a/src/scopes/audioscopes/audiospectrum.h b/src/scopes/audioscopes/audiospectrum.h index 77308afa..ca29fdb0 100644 --- a/src/scopes/audioscopes/audiospectrum.h +++ b/src/scopes/audioscopes/audiospectrum.h @@ -8,11 +8,6 @@ * (at your option) any later version. * ***************************************************************************/ -/** - Displays a spectral power distribution of audio samples. - The frequency distribution is calculated by means of a Fast Fourier Transformation. - For more information see Wikipedia:FFT and the code comments. -*/ #ifndef AUDIOSPECTRUM_H #define AUDIOSPECTRUM_H @@ -33,6 +28,14 @@ #include "ffttools.h" class AudioSpectrum_UI; + +/** + \brief Displays a spectral power distribution of audio samples. + The frequency distribution is calculated by means of a Fast Fourier Transformation. + For more information see Wikipedia:FFT and the code comments. + + \todo Currently only supports one channel. Add support for multiple channels. +*/ class AudioSpectrum : public AbstractAudioScopeWidget { Q_OBJECT diff --git a/src/scopes/colorscopes/abstractgfxscopewidget.cpp b/src/scopes/colorscopes/abstractgfxscopewidget.cpp index 5c82fc22..430b3319 100644 --- a/src/scopes/colorscopes/abstractgfxscopewidget.cpp +++ b/src/scopes/colorscopes/abstractgfxscopewidget.cpp @@ -28,16 +28,9 @@ const int REALTIME_FPS = 30; -AbstractGfxScopeWidget::AbstractGfxScopeWidget(MonitorManager *manager, bool trackMouse, QWidget *parent) : - AbstractScopeWidget(trackMouse, parent), - m_manager(manager) +AbstractGfxScopeWidget::AbstractGfxScopeWidget(bool trackMouse, QWidget *parent) : + AbstractScopeWidget(trackMouse, parent) { - m_activeRender = m_manager->activeRenderer(); - - bool b = true; - if (m_activeRender != NULL) - b &= connect(m_activeRender, SIGNAL(frameUpdated(QImage)), this, SLOT(slotRenderZoneUpdated(QImage))); - Q_ASSERT(b); } AbstractGfxScopeWidget::~AbstractGfxScopeWidget() { } @@ -49,41 +42,13 @@ QImage AbstractGfxScopeWidget::renderScope(uint accelerationFactor) void AbstractGfxScopeWidget::mouseReleaseEvent(QMouseEvent *event) { - if (!m_aAutoRefresh->isChecked() && m_activeRender) { - m_activeRender->sendFrameUpdate(); - } AbstractScopeWidget::mouseReleaseEvent(event); + emit signalFrameRequest(widgetName()); } ///// Slots ///// -void AbstractGfxScopeWidget::slotActiveMonitorChanged() -{ - if (m_activeRender) { - if (m_activeRender == m_manager->activeRenderer()) return; - bool b = true; - b &= m_activeRender->disconnect(this); - Q_ASSERT(b); - } - m_activeRender = m_manager->activeRenderer(); - - if (m_activeRender) { -#ifdef DEBUG_AGSW - qDebug() << "Active monitor has changed in " << widgetName() << ". Is the clip monitor active now? " << m_activeRender->name(); -#endif - bool b = connect(m_activeRender, SIGNAL(frameUpdated(QImage)), this, SLOT(slotRenderZoneUpdated(QImage))); - Q_ASSERT(b); - } - - // Update the scope for the new monitor. - forceUpdate(true); -} - -void AbstractGfxScopeWidget::slotClearMonitor() -{ - m_activeRender = NULL; -} void AbstractGfxScopeWidget::slotRenderZoneUpdated(QImage frame) { @@ -93,8 +58,8 @@ void AbstractGfxScopeWidget::slotRenderZoneUpdated(QImage frame) void AbstractGfxScopeWidget::slotAutoRefreshToggled(bool autoRefresh) { - if (autoRefresh && m_activeRender) { - m_activeRender->sendFrameUpdate(); + if (autoRefresh) { + emit signalFrameRequest(widgetName()); } } diff --git a/src/scopes/colorscopes/abstractgfxscopewidget.h b/src/scopes/colorscopes/abstractgfxscopewidget.h index 5748dae5..54e335ad 100644 --- a/src/scopes/colorscopes/abstractgfxscopewidget.h +++ b/src/scopes/colorscopes/abstractgfxscopewidget.h @@ -12,29 +12,28 @@ #define ABSTRACTGFXSCOPEWIDGET_H #include +#include #include -#include "abstractscopewidget.h" -#include "renderer.h" +#include "../abstractscopewidget.h" class QMenu; -class MonitorManager; +/** +\brief Abstract class for scopes analyzing image frames. +*/ class AbstractGfxScopeWidget : public AbstractScopeWidget { Q_OBJECT public: - AbstractGfxScopeWidget(MonitorManager *manager, bool trackMouse = false, QWidget *parent = 0); + AbstractGfxScopeWidget(bool trackMouse = false, QWidget *parent = 0); virtual ~AbstractGfxScopeWidget(); // Must be virtual because of inheritance, to avoid memory leaks protected: ///// Variables ///// - MonitorManager *m_manager; - AbstractRender *m_activeRender; - /** @brief Scope renderer. Must emit signalScopeRenderingFinished() when calculation has finished, to allow multi-threading. accelerationFactor hints how much faster than usual the calculation should be accomplished, if possible. */ @@ -51,14 +50,13 @@ public slots: /** @brief Must be called when the active monitor has shown a new frame. This slot must be connected in the implementing class, it is *not* done in this abstract class. */ - void slotActiveMonitorChanged(); - void slotClearMonitor(); + void slotRenderZoneUpdated(QImage); protected slots: virtual void slotAutoRefreshToggled(bool autoRefresh); -private slots: - void slotRenderZoneUpdated(QImage); +signals: + void signalFrameRequest(const QString widgetName); }; diff --git a/src/scopes/colorscopes/histogram.cpp b/src/scopes/colorscopes/histogram.cpp index 9b5915a5..99bb3403 100644 --- a/src/scopes/colorscopes/histogram.cpp +++ b/src/scopes/colorscopes/histogram.cpp @@ -12,10 +12,9 @@ #include #include "colorcorrection/histogramgenerator.h" #include "histogram.h" -#include "renderer.h" -Histogram::Histogram(MonitorManager *manager, QWidget *parent) : - AbstractGfxScopeWidget(manager, false, parent) +Histogram::Histogram(QWidget *parent) : + AbstractGfxScopeWidget(false, parent) { ui = new Ui::Histogram_UI(); ui->setupUi(this); diff --git a/src/scopes/colorscopes/histogram.h b/src/scopes/colorscopes/histogram.h index 19b86da2..85a954a2 100644 --- a/src/scopes/colorscopes/histogram.h +++ b/src/scopes/colorscopes/histogram.h @@ -16,11 +16,14 @@ class HistogramGenerator; +/** + * \brief Displays the histogram of frames. + */ class Histogram : public AbstractGfxScopeWidget { Q_OBJECT public: - Histogram(MonitorManager *manager, QWidget *parent = 0); + Histogram(QWidget *parent = 0); ~Histogram(); QString widgetName() const; diff --git a/src/scopes/colorscopes/rgbparade.cpp b/src/scopes/colorscopes/rgbparade.cpp index 18be787a..f2583262 100644 --- a/src/scopes/colorscopes/rgbparade.cpp +++ b/src/scopes/colorscopes/rgbparade.cpp @@ -12,12 +12,11 @@ #include #include #include -#include "renderer.h" #include "rgbparade.h" #include "colorcorrection/rgbparadegenerator.h" -RGBParade::RGBParade(MonitorManager *manager, QWidget *parent) : - AbstractGfxScopeWidget(manager, true, parent) +RGBParade::RGBParade(QWidget *parent) : + AbstractGfxScopeWidget(true, parent) { ui = new Ui::RGBParade_UI(); ui->setupUi(this); diff --git a/src/scopes/colorscopes/rgbparade.h b/src/scopes/colorscopes/rgbparade.h index db178b20..1d6a3c6d 100644 --- a/src/scopes/colorscopes/rgbparade.h +++ b/src/scopes/colorscopes/rgbparade.h @@ -15,15 +15,18 @@ #include "abstractgfxscopewidget.h" #include "ui_rgbparade_ui.h" -class Monitor; class QImage; class RGBParade_UI; class RGBParadeGenerator; +/** + * \brief Displays the RGB waveform of a frame. + * This is the same as the Waveform, but for each colour channel separately. + */ class RGBParade : public AbstractGfxScopeWidget { public: - RGBParade(MonitorManager *manager, QWidget *parent = 0); + RGBParade(QWidget *parent = 0); ~RGBParade(); QString widgetName() const; diff --git a/src/scopes/colorscopes/vectorscope.cpp b/src/scopes/colorscopes/vectorscope.cpp index 76a6e722..55437fff 100644 --- a/src/scopes/colorscopes/vectorscope.cpp +++ b/src/scopes/colorscopes/vectorscope.cpp @@ -20,7 +20,6 @@ #include "colorplaneexport.h" #include "colortools.h" -#include "renderer.h" #include "vectorscope.h" #include "colorcorrection/vectorscopegenerator.h" @@ -42,8 +41,8 @@ const QPointF YPbPr_Mg(.331, .419); const QPointF YPbPr_Yl(-.5, .081); -Vectorscope::Vectorscope(MonitorManager *manager, QWidget *parent) : - AbstractGfxScopeWidget(manager, true, parent), +Vectorscope::Vectorscope(QWidget *parent) : + AbstractGfxScopeWidget(true, parent), m_gain(1) { ui = new Ui::Vectorscope_UI(); diff --git a/src/scopes/colorscopes/vectorscope.h b/src/scopes/colorscopes/vectorscope.h index de54440d..adeba60a 100644 --- a/src/scopes/colorscopes/vectorscope.h +++ b/src/scopes/colorscopes/vectorscope.h @@ -17,18 +17,22 @@ class ColorPlaneExport; class ColorTools; -class Render; -class Monitor; + class Vectorscope_UI; class VectorscopeGenerator; enum BACKGROUND_MODE { BG_NONE = 0, BG_YUV = 1, BG_CHROMA = 2, BG_YPbPr = 3 }; +/** + \brief Displays the vectorscope of a frame. + + \see VectorscopeGenerator for more details about the vectorscope. + */ class Vectorscope : public AbstractGfxScopeWidget { Q_OBJECT public: - Vectorscope(MonitorManager *manager, QWidget *parent = 0); + Vectorscope(QWidget *parent = 0); ~Vectorscope(); QString widgetName() const; diff --git a/src/scopes/colorscopes/waveform.cpp b/src/scopes/colorscopes/waveform.cpp index f8fec8b1..9a567c2b 100644 --- a/src/scopes/colorscopes/waveform.cpp +++ b/src/scopes/colorscopes/waveform.cpp @@ -17,7 +17,6 @@ #include "kdenlivesettings.h" #include "profilesdialog.h" -#include "renderer.h" #include "waveform.h" #include "colorcorrection/waveformgenerator.h" @@ -25,8 +24,8 @@ const QSize Waveform::m_textWidth(35,0); const int Waveform::m_paddingBottom(20); -Waveform::Waveform(MonitorManager *manager, QWidget *parent) : - AbstractGfxScopeWidget(manager, true, parent) +Waveform::Waveform(QWidget *parent) : + AbstractGfxScopeWidget(true, parent) ,ui(NULL) { ui = new Ui::Waveform_UI(); diff --git a/src/scopes/colorscopes/waveform.h b/src/scopes/colorscopes/waveform.h index ce031397..2455f817 100644 --- a/src/scopes/colorscopes/waveform.h +++ b/src/scopes/colorscopes/waveform.h @@ -18,11 +18,16 @@ class Waveform_UI; class WaveformGenerator; +/** + \brief Displays the waveform of a frame. + + For further explanations of the waveform see the WaveformGenerator class. +*/ class Waveform : public AbstractGfxScopeWidget { Q_OBJECT public: - Waveform(MonitorManager *manager, QWidget *parent = 0); + Waveform(QWidget *parent = 0); ~Waveform(); virtual QString widgetName() const; -- 2.39.2