diff options
author | Daniel Schürmann <daschuer@mixxx.org> | 2019-01-06 01:04:08 +0100 |
---|---|---|
committer | Daniel Schürmann <daschuer@mixxx.org> | 2019-01-06 01:10:00 +0100 |
commit | 5a4444d520f97321bfdae6cd22c28fa1a7f835ec (patch) | |
tree | fa487c171372273ee7c2efc4b3ad94903f80402e /src | |
parent | 03dff4353f2fdec2d72fd0d384545bf681e71022 (diff) |
Added new VisualsManager class
Diffstat (limited to 'src')
-rw-r--r-- | src/engine/enginebuffer.cpp | 49 | ||||
-rw-r--r-- | src/engine/enginebuffer.h | 11 | ||||
-rw-r--r-- | src/engine/enginedeck.cpp | 1 | ||||
-rw-r--r-- | src/mixer/basetrackplayer.cpp | 4 | ||||
-rw-r--r-- | src/mixer/basetrackplayer.h | 2 | ||||
-rw-r--r-- | src/mixer/deck.cpp | 3 | ||||
-rw-r--r-- | src/mixer/deck.h | 1 | ||||
-rw-r--r-- | src/mixer/playermanager.cpp | 11 | ||||
-rw-r--r-- | src/mixer/playermanager.h | 3 | ||||
-rw-r--r-- | src/mixer/previewdeck.cpp | 3 | ||||
-rw-r--r-- | src/mixer/previewdeck.h | 1 | ||||
-rw-r--r-- | src/mixer/sampler.cpp | 3 | ||||
-rw-r--r-- | src/mixer/sampler.h | 1 | ||||
-rw-r--r-- | src/mixxx.cpp | 7 | ||||
-rw-r--r-- | src/mixxx.h | 2 | ||||
-rw-r--r-- | src/test/signalpathtest.h | 15 | ||||
-rw-r--r-- | src/waveform/visualplayposition.cpp | 11 | ||||
-rw-r--r-- | src/waveform/visualplayposition.h | 1 | ||||
-rw-r--r-- | src/waveform/visualsmanager.cpp | 66 | ||||
-rw-r--r-- | src/waveform/visualsmanager.h | 55 | ||||
-rw-r--r-- | src/waveform/waveformwidgetfactory.cpp | 6 | ||||
-rw-r--r-- | src/waveform/waveformwidgetfactory.h | 4 |
22 files changed, 184 insertions, 76 deletions
diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index f5c8a68170..7788221ac1 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -50,7 +50,7 @@ const SINT kSamplesPerFrame = 2; // Engine buffer uses Stereo frames only } // anonymous namespace -EngineBuffer::EngineBuffer(QString group, UserSettingsPointer pConfig, +EngineBuffer::EngineBuffer(const QString& group, UserSettingsPointer pConfig, EngineChannel* pChannel, EngineMaster* pMixingEngine) : m_group(group), m_pConfig(pConfig), @@ -72,8 +72,6 @@ EngineBuffer::EngineBuffer(QString group, UserSettingsPointer pConfig, m_rate_old(0.), m_trackSamplesOld(0), m_trackSampleRateOld(0), - m_iSamplesSinceLastIndicatorUpdate(0), - m_iUiSlowTick(0), m_dSlipPosition(0.), m_dSlipRate(1.0), m_bSlipEnabledProcessing(false), @@ -146,14 +144,6 @@ EngineBuffer::EngineBuffer(QString group, UserSettingsPointer pConfig, m_pSlipButton = new ControlPushButton(ConfigKey(m_group, "slip_enabled")); m_pSlipButton->setButtonMode(ControlPushButton::TOGGLE); - // BPM to display in the UI (updated more slowly than the actual bpm) - m_visualBpm = new ControlObject(ConfigKey(m_group, "visual_bpm")); - m_visualKey = new ControlObject(ConfigKey(m_group, "visual_key")); - - m_timeElapsed = new ControlObject(ConfigKey(m_group, "time_elapsed")); - m_timeRemaining = new ControlObject(ConfigKey(m_group, "time_remaining")); - m_pEndOfTrack = std::make_unique<ControlObject>(ConfigKey(group, "end_of_track")); - m_playposSlider = new ControlLinPotmeter( ConfigKey(m_group, "playposition"), 0.0, 1.0, 0, 0, true); connect(m_playposSlider, SIGNAL(valueChanged(double)), @@ -282,15 +272,10 @@ EngineBuffer::~EngineBuffer() { delete m_playStartButton; delete m_stopStartButton; - delete m_timeElapsed; - delete m_timeRemaining; - delete m_startButton; delete m_endButton; delete m_stopButton; delete m_playposSlider; - delete m_visualBpm; - delete m_visualKey; delete m_pSlipButton; delete m_pRepeat; @@ -550,11 +535,6 @@ void EngineBuffer::ejectTrack() { TrackPointer pTrack = m_pCurrentTrack; m_pCurrentTrack.reset(); m_playButton->set(0.0); - m_visualBpm->set(0.0); - m_visualKey->set(0.0); - m_timeElapsed->set(0); - m_timeRemaining->set(0); - m_pEndOfTrack->set(0.0); m_playposSlider->set(0); m_pCueControl->resetIndicators(); doSeekFractional(0.0, SEEK_EXACT); @@ -1224,35 +1204,8 @@ void EngineBuffer::updateIndicators(double speed, int iBufferSize) { // Update indicators that are only updated after every // sampleRate/kiUpdateRate samples processed. (e.g. playposSlider) if (m_iSamplesSinceLastIndicatorUpdate > (kSamplesPerFrame * m_pSampleRate->get() / kiPlaypositionUpdateRate)) { - double timeRemaining = (1.0 - fFractionalPlaypos) * tempoTrackSeconds; - m_timeRemaining->set(timeRemaining); - m_timeElapsed->set(tempoTrackSeconds - timeRemaining); - - auto pFactory = WaveformWidgetFactory::instance(); - double remainingTimeTriggerSeconds = pFactory ? pFactory->getEndOfTrackWarningTime() : 0; - - if (!m_playButton->toBool() || // not playing - m_pLoopingControl->isLoopingEnabled() || // in loop - tempoTrackSeconds <= remainingTimeTriggerSeconds || // track too short - timeRemaining > remainingTimeTriggerSeconds // before the trigger - ) { - m_pEndOfTrack->set(0.0); - } else { - m_pEndOfTrack->set(1.0); - } - m_playposSlider->set(fFractionalPlaypos); m_pCueControl->updateIndicators(); - - // Update the BPM even more slowly - m_iUiSlowTick = (m_iUiSlowTick + 1) % kiBpmUpdateCnt; - if (m_iUiSlowTick == 0) { - m_visualBpm->set(m_pBpmControl->getBpm()); - } - m_visualKey->set(m_pKeyControl->getKey()); - - // Reset sample counter - m_iSamplesSinceLastIndicatorUpdate = 0; } // Update visual control object, this needs to be done more often than the diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index b1be907595..1a477d67a2 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -76,8 +76,6 @@ const int kiTempLength = 200000; // Rate at which the playpos slider is updated const int kiPlaypositionUpdateRate = 15; // updates per second -// Number of kiUpdateRates that go by before we update BPM. -const int kiBpmUpdateCnt = 4; // about 3.75 updates per sec class EngineBuffer : public EngineObject { Q_OBJECT @@ -113,7 +111,7 @@ class EngineBuffer : public EngineObject { KEYLOCK_ENGINE_COUNT, }; - EngineBuffer(QString _group, UserSettingsPointer pConfig, + EngineBuffer(const QString& group, UserSettingsPointer pConfig, EngineChannel* pChannel, EngineMaster* pMixingEngine); virtual ~EngineBuffer(); @@ -311,7 +309,6 @@ class EngineBuffer : public EngineObject { QMutex m_pause; // Used in update of playpos slider int m_iSamplesSinceLastIndicatorUpdate; - int m_iUiSlowTick; // The location where the track would have been had slip not been engaged double m_dSlipPosition; @@ -332,19 +329,13 @@ class EngineBuffer : public EngineObject { ControlObject* m_backButton; ControlPushButton* m_pSlipButton; - ControlObject* m_visualBpm; - ControlObject* m_visualKey; ControlObject* m_pQuantize; ControlObject* m_pMasterRate; - ControlObject* m_timeElapsed; - ControlObject* m_timeRemaining; ControlPotmeter* m_playposSlider; ControlProxy* m_pSampleRate; ControlProxy* m_pKeylockEngine; ControlPushButton* m_pKeylock; - std::unique_ptr<ControlObject> m_pEndOfTrack; - // This ControlProxys is created as parent to this and deleted by // the Qt object tree. This helps that they are deleted by the creating // thread, which is required to avoid segfaults. diff --git a/src/engine/enginedeck.cpp b/src/engine/enginedeck.cpp index 0304e055b7..65453be3cf 100644 --- a/src/engine/enginedeck.cpp +++ b/src/engine/enginedeck.cpp @@ -25,6 +25,7 @@ #include "engine/enginepregain.h" #include "engine/enginevumeter.h" #include "util/sample.h" +#include "waveform/waveformwidgetfactory.h" EngineDeck::EngineDeck(const ChannelHandleAndGroup& handle_group, UserSettingsPointer pConfig, diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index f4a50db2a7..10fdcbf793 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -1,3 +1,4 @@ +#include <waveform/visualsmanager.h> #include <QMessageBox> #include "mixer/basetrackplayer.h" @@ -28,6 +29,7 @@ BaseTrackPlayerImpl::BaseTrackPlayerImpl(QObject* pParent, UserSettingsPointer pConfig, EngineMaster* pMixingEngine, EffectsManager* pEffectsManager, + VisualsManager* pVisualsManager, EngineChannel::ChannelOrientation defaultOrientation, const QString& group, bool defaultMaster, @@ -106,6 +108,8 @@ BaseTrackPlayerImpl::BaseTrackPlayerImpl(QObject* pParent, m_pReplayGain = std::make_unique<ControlProxy>(group, "replaygain", this); m_pPlay = std::make_unique<ControlProxy>(group, "play", this); m_pPlay->connectValueChanged(SLOT(slotPlayToggled(double))); + + pVisualsManager->addDeck(group); } BaseTrackPlayerImpl::~BaseTrackPlayerImpl() { diff --git a/src/mixer/basetrackplayer.h b/src/mixer/basetrackplayer.h index e814497fb0..ce50d5a441 100644 --- a/src/mixer/basetrackplayer.h +++ b/src/mixer/basetrackplayer.h @@ -17,6 +17,7 @@ class ControlObject; class ControlPotmeter; class ControlProxy; class EffectsManager; +class VisualsManager; // Interface for not leaking implementation details of BaseTrackPlayer into the // rest of Mixxx. Also makes testing a lot easier. @@ -53,6 +54,7 @@ class BaseTrackPlayerImpl : public BaseTrackPlayer { UserSettingsPointer pConfig, EngineMaster* pMixingEngine, EffectsManager* pEffectsManager, + VisualsManager* pVisualsManager, EngineChannel::ChannelOrientation defaultOrientation, const QString& group, bool defaultMaster, diff --git a/src/mixer/deck.cpp b/src/mixer/deck.cpp index 5e68611188..9b584a8024 100644 --- a/src/mixer/deck.cpp +++ b/src/mixer/deck.cpp @@ -4,10 +4,11 @@ Deck::Deck(QObject* pParent, UserSettingsPointer pConfig, EngineMaster* pMixingEngine, EffectsManager* pEffectsManager, + VisualsManager* pVisualsManager, EngineChannel::ChannelOrientation defaultOrientation, const QString& group) : BaseTrackPlayerImpl(pParent, pConfig, pMixingEngine, pEffectsManager, - defaultOrientation, group, true, false) { + pVisualsManager, defaultOrientation, group, true, false) { } Deck::~Deck() { diff --git a/src/mixer/deck.h b/src/mixer/deck.h index d596985ee6..561c37b032 100644 --- a/src/mixer/deck.h +++ b/src/mixer/deck.h @@ -12,6 +12,7 @@ class Deck : public BaseTrackPlayerImpl { UserSettingsPointer pConfig, EngineMaster* pMixingEngine, EffectsManager* pEffectsManager, + VisualsManager* pVisualsManager, EngineChannel::ChannelOrientation defaultOrientation, const QString& group); virtual ~Deck(); diff --git a/src/mixer/playermanager.cpp b/src/mixer/playermanager.cpp index 866c3f7b12..5a3ed6b547 100644 --- a/src/mixer/playermanager.cpp +++ b/src/mixer/playermanager.cpp @@ -34,11 +34,13 @@ QAtomicPointer<ControlProxy> PlayerManager::m_pCOPNumPreviewDecks; PlayerManager::PlayerManager(UserSettingsPointer pConfig, SoundManager* pSoundManager, EffectsManager* pEffectsManager, + VisualsManager* pVisualsManager, EngineMaster* pEngine) : m_mutex(QMutex::Recursive), m_pConfig(pConfig), m_pSoundManager(pSoundManager), m_pEffectsManager(pEffectsManager), + m_pVisualsManager(pVisualsManager), m_pEngine(pEngine), // NOTE(XXX) LegacySkinParser relies on these controls being Controls // and not ControlProxies. @@ -339,7 +341,7 @@ void PlayerManager::addDeckInner() { } Deck* pDeck = new Deck(this, m_pConfig, m_pEngine, m_pEffectsManager, - orientation, group); + m_pVisualsManager, orientation, group); connect(pDeck, SIGNAL(noPassthroughInputConfigured()), this, SIGNAL(noDeckPassthroughInputConfigured())); connect(pDeck, SIGNAL(noVinylControlInputConfigured()), @@ -405,8 +407,8 @@ void PlayerManager::addSamplerInner() { EngineChannel::ChannelOrientation orientation = EngineChannel::CENTER; Sampler* pSampler = new Sampler(this, m_pConfig, m_pEngine, - m_pEffectsManager, orientation, group); - if (m_pAnalyzerQueue) { + m_pEffectsManager, m_pVisualsManager, orientation, group); + if (m_pAnalyzerQueue) { connect(pSampler, SIGNAL(newTrackLoaded(TrackPointer)), m_pAnalyzerQueue, SLOT(slotAnalyseTrack(TrackPointer))); } @@ -431,8 +433,7 @@ void PlayerManager::addPreviewDeckInner() { EngineChannel::ChannelOrientation orientation = EngineChannel::CENTER; PreviewDeck* pPreviewDeck = new PreviewDeck(this, m_pConfig, m_pEngine, - m_pEffectsManager, orientation, - group); + m_pEffectsManager, m_pVisualsManager, orientation, group); if (m_pAnalyzerQueue) { connect(pPreviewDeck, SIGNAL(newTrackLoaded(TrackPointer)), m_pAnalyzerQueue, SLOT(slotAnalyseTrack(TrackPointer))); diff --git a/src/mixer/playermanager.h b/src/mixer/playermanager.h index 98d8ba60ef..2958d58ee0 100644 --- a/src/mixer/playermanager.h +++ b/src/mixer/playermanager.h @@ -25,6 +25,7 @@ class PreviewDeck; class Sampler; class SamplerBank; class SoundManager; +class VisualsManager; // For mocking PlayerManager. class PlayerManagerInterface { @@ -60,6 +61,7 @@ class PlayerManager : public QObject, public PlayerManagerInterface { PlayerManager(UserSettingsPointer pConfig, SoundManager* pSoundManager, EffectsManager* pEffectsManager, + VisualsManager* pVisualsManager, EngineMaster* pEngine); virtual ~PlayerManager(); @@ -241,6 +243,7 @@ class PlayerManager : public QObject, public PlayerManagerInterface { UserSettingsPointer m_pConfig; SoundManager* m_pSoundManager; EffectsManager* m_pEffectsManager; + VisualsManager* m_pVisualsManager; EngineMaster* m_pEngine; SamplerBank* m_pSamplerBank; AnalyzerQueue* m_pAnalyzerQueue; diff --git a/src/mixer/previewdeck.cpp b/src/mixer/previewdeck.cpp index dba001ea16..f30ca48573 100644 --- a/src/mixer/previewdeck.cpp +++ b/src/mixer/previewdeck.cpp @@ -4,10 +4,11 @@ PreviewDeck::PreviewDeck(QObject* pParent, UserSettingsPointer pConfig, EngineMaster* pMixingEngine, EffectsManager* pEffectsManager, + VisualsManager* pVisualsManager, EngineChannel::ChannelOrientation defaultOrientation, QString group) : BaseTrackPlayerImpl(pParent, pConfig, pMixingEngine, pEffectsManager, - defaultOrientation, group, false, true) { + pVisualsManager, defaultOrientation, group, false, true) { } PreviewDeck::~PreviewDeck() { diff --git a/src/mixer/previewdeck.h b/src/mixer/previewdeck.h index a5c6128770..63ad2b2768 100644 --- a/src/mixer/previewdeck.h +++ b/src/mixer/previewdeck.h @@ -10,6 +10,7 @@ class PreviewDeck : public BaseTrackPlayerImpl { UserSettingsPointer pConfig, EngineMaster* pMixingEngine, EffectsManager* pEffectsManager, + VisualsManager* pVisualsManager, EngineChannel::ChannelOrientation defaultOrientation, QString group); virtual ~PreviewDeck(); diff --git a/src/mixer/sampler.cpp b/src/mixer/sampler.cpp index b086c1b2ca..d378e1839a 100644 --- a/src/mixer/sampler.cpp +++ b/src/mixer/sampler.cpp @@ -6,10 +6,11 @@ Sampler::Sampler(QObject* pParent, UserSettingsPointer pConfig, EngineMaster* pMixingEngine, EffectsManager* pEffectsManager, + VisualsManager* pVisualsManager, EngineChannel::ChannelOrientation defaultOrientation, QString group) : BaseTrackPlayerImpl(pParent, pConfig, pMixingEngine, pEffectsManager, - defaultOrientation, group, true, false) { + pVisualsManager, defaultOrientation, group, true, false) { } Sampler::~Sampler() { diff --git a/src/mixer/sampler.h b/src/mixer/sampler.h index e2e0422ac3..20e7481338 100644 --- a/src/mixer/sampler.h +++ b/src/mixer/sampler.h @@ -10,6 +10,7 @@ class Sampler : public BaseTrackPlayerImpl { UserSettingsPointer pConfig, EngineMaster* pMixingEngine, EffectsManager* pEffectsManager, + VisualsManager* pVisualsManager, EngineChannel::ChannelOrientation defaultOrientation, QString group); virtual ~Sampler(); diff --git a/src/mixxx.cpp b/src/mixxx.cpp index 6246dcc2a7..fa1f80da26 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -51,6 +51,7 @@ #include "sources/soundsourceproxy.h" #include "track/track.h" #include "waveform/waveformwidgetfactory.h" +#include <waveform/visualsmanager.h> #include "waveform/sharedglcontext.h" #include "database/mixxxdb.h" #include "util/debug.h" @@ -264,6 +265,7 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) { // Needs to be created before CueControl (decks) and WTrackTableView. m_pGuiTick = new GuiTick(); + m_pVisualsManager = new VisualsManager(); #ifdef __VINYLCONTROL__ m_pVCManager = new VinylControlManager(this, pConfig, m_pSoundManager); @@ -273,7 +275,7 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) { // Create the player manager. (long) m_pPlayerManager = new PlayerManager(pConfig, m_pSoundManager, - m_pEffectsManager, m_pEngine); + m_pEffectsManager, m_pVisualsManager, m_pEngine); connect(m_pPlayerManager, SIGNAL(noMicrophoneInputConfigured()), this, SLOT(slotNoMicrophoneInputConfigured())); connect(m_pPlayerManager, SIGNAL(noDeckPassthroughInputConfigured()), @@ -380,7 +382,7 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) { launchProgress(47); WaveformWidgetFactory::createInstance(); // takes a long time - WaveformWidgetFactory::instance()->startVSync(m_pGuiTick); + WaveformWidgetFactory::instance()->startVSync(m_pGuiTick, m_pVisualsManager); WaveformWidgetFactory::instance()->setConfig(pConfig); launchProgress(52); @@ -671,6 +673,7 @@ void MixxxMainWindow::finalize() { WaveformWidgetFactory::destroy(); delete m_pGuiTick; + delete m_pVisualsManager; // Check for leaked ControlObjects and give warnings. QList<QSharedPointer<ControlDoublePrivate> > leakedControls; diff --git a/src/mixxx.h b/src/mixxx.h index 4559890144..cb2549ed0a 100644 --- a/src/mixxx.h +++ b/src/mixxx.h @@ -39,6 +39,7 @@ class DlgPreferences; class EffectsManager; class EngineMaster; class GuiTick; +class VisualsManager; class LaunchImage; class Library; class KeyboardEventFilter; @@ -166,6 +167,7 @@ class MixxxMainWindow : public QMainWindow { ControllerManager* m_pControllerManager; GuiTick* m_pGuiTick; + VisualsManager* m_pVisualsManager; VinylControlManager* m_pVCManager; diff --git a/src/test/signalpathtest.h b/src/test/signalpathtest.h index 4d5c0fcafc..8ba05359ce 100644 --- a/src/test/signalpathtest.h +++ b/src/test/signalpathtest.h @@ -26,6 +26,7 @@ #include "util/sample.h" #include "util/types.h" #include "waveform/guitick.h" +#include "waveform/visualsmanager.h" using ::testing::Return; using ::testing::_; @@ -58,27 +59,27 @@ class BaseSignalPathTest : public MixxxTest { m_pChannelHandleFactory = new ChannelHandleFactory(); m_pNumDecks = new ControlObject(ConfigKey("[Master]", "num_decks")); m_pEffectsManager = new EffectsManager(NULL, config(), m_pChannelHandleFactory); + m_pVisualsManager = new VisualsManager(); m_pEngineMaster = new TestEngineMaster(m_pConfig, "[Master]", m_pEffectsManager, m_pChannelHandleFactory, false); m_pMixerDeck1 = new Deck(NULL, m_pConfig, m_pEngineMaster, m_pEffectsManager, - EngineChannel::CENTER, m_sGroup1); + m_pVisualsManager, EngineChannel::CENTER, m_sGroup1); m_pMixerDeck1->setupEqControls(); m_pMixerDeck2 = new Deck(NULL, m_pConfig, m_pEngineMaster, m_pEffectsManager, - EngineChannel::CENTER, m_sGroup2); + m_pVisualsManager, EngineChannel::CENTER, m_sGroup2); m_pMixerDeck2->setupEqControls(); m_pMixerDeck3 = new Deck(NULL, m_pConfig, m_pEngineMaster, m_pEffectsManager, - EngineChannel::CENTER, m_sGroup3); + m_pVisualsManager, EngineChannel::CENTER, m_sGroup3); m_pMixerDeck3->setupEqControls(); m_pChannel1 = m_pMixerDeck1->getEngineDeck(); m_pChannel2 = m_pMixerDeck2->getEngineDeck(); m_pChannel3 = m_pMixerDeck3->getEngineDeck(); - m_pPreview1 = new PreviewDeck(NULL, m_pConfig, - m_pEngineMaster, m_pEffectsManager, - EngineChannel::CENTER, m_sPreviewGroup); + m_pPreview1 = new PreviewDeck(NULL, m_pConfig, m_pEngineMaster, m_pEffectsManager, + m_pVisualsManager, EngineChannel::CENTER, m_sPreviewGroup); ControlObject::set(ConfigKey(m_sPreviewGroup, "file_bpm"), 2.0); // TODO(owilliams) Tests fail with this turned on because EngineSync is syncing @@ -109,6 +110,7 @@ class BaseSignalPathTest : public MixxxTest { // Deletes all EngineChannels added to it. delete m_pEngineMaster; delete m_pEffectsManager; + delete m_pVisualsManager; delete m_pNumDecks; } @@ -201,6 +203,7 @@ class BaseSignalPathTest : public MixxxTest { ChannelHandleFactory* m_pChannelHandleFactory; ControlObject* m_pNumDecks; std::unique_ptr<GuiTick> m_pGuiTick; + VisualsManager* m_pVisualsManager; EffectsManager* m_pEffectsManager; EngineSync* m_pEngineSync; TestEngineMaster* m_pEngineMaster; diff --git a/src/waveform/visualplayposition.cpp b/src/waveform/visualplayposition.cpp index aae57cb5d0..8b4870307e 100644 --- a/src/waveform/visualplayposition.cpp +++ b/src/waveform/visualplayposition.cpp @@ -98,6 +98,17 @@ double VisualPlayPosition::getEnginePlayPos() { } } +void VisualPlayPosition::getTrackTime(double* pPlayPosition, double* pTempoTrackSeconds) { + if (m_valid) { + VisualPlayPositionData data = m_data.getValue(); + *pPlayPosition = data.m_enginePlayPos; + *pTempoTrackSeconds = data.m_tempoTrackSeconds; + } else { + *pPlayPosition = 0; + *pTempoTrackSeconds = 0; + } +} + void VisualPlayPosition::slotAudioBufferSizeChanged(double sizeMillis) { m_audioBufferMicros = static_cast<int>(sizeMillis * kMicrosPerMillis); } diff --git a/src/waveform/visualplayposition.h b/src/waveform/visualplayposition.h index 699b3ae9e8..0095a3b57f 100644 --- a/src/waveform/visualplayposition.h +++ b/src/waveform/visualplayposition.h @@ -51,6 +51,7 @@ class VisualPlayPosition : public QObject { double getAtNextVSync(VSyncThread* vsyncThread); void getPlaySlipAt(int usFromNow, double* playPosition, double* slipPosition); double getEnginePlayPos(); + void getTrackTime(double* pPlayPosition, double* pTempoTrackSeconds); // WARNING: Not thread safe. This function must only be called from the main // thread. diff --git a/src/waveform/visualsmanager.cpp b/src/waveform/visualsmanager.cpp new file mode 100644 index 0000000000..aae8093c75 --- /dev/null +++ b/src/waveform/visualsmanager.cpp @@ -0,0 +1,66 @@ +#include "waveform/visualsmanager.h" + +#include "waveform/waveformwidgetfactory.h" +#include "control/controlobject.h" + +namespace { + // Rate at which the playpos slider is updated + const int kUpdateRate = 15; // updates per second + // Number of kiUpdateRates that go by before we update BPM. + const int kSlowUpdateDivider = 4; // kUpdateRate / kSlowUpdateDivider = 3.75 updates per sec +} + +DeckVisuals::DeckVisuals(const QString& group) + : m_group(group), + m_SlowTickCnt(0), + playButton(ConfigKey(group, "play")), + loopEnabled(ConfigKey(group, "loop_enabled")), + engineBpm(ConfigKey(group, "bpm")), + engineKey(ConfigKey(group, "key")) { + m_pTimeElapsed = std::make_unique<ControlObject>(ConfigKey(m_group, "time_elapsed")); + m_pTimeRemaining = std::make_unique<ControlObject>(ConfigKey(m_group, "time_remaining")); + m_pEndOfTrack = std::make_unique<ControlObject>(ConfigKey(group, "end_of_track")); + m_pVisualBpm = std::make_unique<ControlObject>(ConfigKey(m_group, "visual_bpm")); + m_pVisualKey = std::make_unique<ControlObject>(ConfigKey(m_group, "visual_key")); + + // Control used to communicate ratio playpos to GUI thread + m_pVisualPlayPos = VisualPlayPosition::getVisualPlayPosition(m_group); + + m_cpuTimer.start(); +} + +// this is called from WaveformWidgetFactory::render in the main thread with the +// configured waveform frame rate +void DeckVisuals::process(double remainingTimeTriggerSeconds) { + if (m_cpuTimer.elapsed() >= mixxx::Duration::fromMillis(1000 / kUpdateRate)) { + m_cpuTimer.restart(); + + double playPosition; + double tempoTrackSeconds; + m_pVisualPlayPos->getTrackTime(&playPosition, &tempoTrackSeconds); + + double timeRemaining = (1.0 - playPosition) * tempoTrackSeconds; + m_pTimeRemaining->set(timeRemaining); + m_pTimeElapsed->set(tempoTrackSeconds - timeRemaining); + + if (!playButton.toBool() || // not playing + loopEnabled.toBool() || // in loop + tempoTrackSeconds <= remainingTimeTriggerSeconds || // track too short + timeRemaining > remainingTimeTriggerSeconds // before the trigger + ) { + m_pEndOfTrack->set(0.0); + } else { + m_pEndOfTrack->set(1.0); + } + + // m_playposSlider->set(fFractionalPlaypos); + // m_pCueControl->updateIndicators(); + + // Update the BPM even more slowly + m_SlowTickCnt = (m_SlowTickCnt + 1) % kSlowUpdateDivider; + if (m_SlowTickCnt == 0) { + m_pVisualBpm->set(engineBpm.get()); + } + m_pVisualKey->set(engineKey.get()); + } +} diff --git a/src/waveform/visualsmanager.h b/src/waveform/visualsmanager.h new file mode 100644 index 0000000000..214f64b383 --- /dev/null +++ b/src/waveform/visualsmanager.h @@ -0,0 +1,55 @@ +#pragma once + +#include "control/controlobject.h" +#include "control/controlproxy.h" +#include "util/duration.h" +#include "util/memory.h" +#include "util/performancetimer.h" +#include "waveform/visualplayposition.h" + +#include <vector> + +// This calss updates the controls used for widgets and +// controler indicator, in a CPU saving way and outside the engine thread +class DeckVisuals { + public: + DeckVisuals(const QString& group); + void process(double remainingTimeTriggerSeconds); + + private: + QString m_group; + PerformanceTimer m_cpuTimer; + mixxx::Duration m_lastUpdateTime; + int m_SlowTickCnt; + + std::unique_ptr<ControlObject> m_pTimeElapsed; + std::unique_ptr<ControlObject> m_pTimeRemaining; + std::unique_ptr<ControlObject> m_pEndOfTrack; + std::unique_ptr<ControlObject> m_pVisualBpm; + std::unique_ptr<ControlObject> m_pVisualKey; + + ControlProxy playButton; + ControlProxy loopEnabled; + ControlProxy engineBpm; + ControlProxy engineKey; + + //std::unique_ptr<ControlObject> m_playposSlider; + + QSharedPointer<VisualPlayPosition> m_pVisualPlayPos; +}; + +class VisualsManager { + public: + void addDeck(const QString& group) { + m_deckVisuals.push_back( + std::make_unique<DeckVisuals>(group)); + } + + void process(double remainingTimeTriggerSeconds) { + for (const auto& d: m_deckVisuals) { + d->process(remainingTimeTriggerSeconds); + } + } + private: + std::vector<std::unique_ptr<DeckVisuals> > m_deckVisuals; +}; diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 8db15f9e2e..78917a673d 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -25,6 +25,7 @@ #include "waveform/widgets/waveformwidgetabstract.h" #include "widget/wwaveformviewer.h" #include "waveform/guitick.h" +#include "waveform/visualsmanager.h" #include "waveform/vsyncthread.h" #include "util/cmdlineargs.h" #include "util/performancetimer.h" @@ -103,6 +104,7 @@ WaveformWidgetFactory::WaveformWidgetFactory() : m_beatGridAlpha(90), m_vsyncThread(NULL), m_pGuiTick(nullptr), + m_pVisualsManager(nullptr), m_frameCnt(0), m_actualFrameRate(0), m_vSyncType(0), @@ -596,6 +598,7 @@ void WaveformWidgetFactory::render() { } } + m_pVisualsManager->process(m_endOfTrackWarningTime); m_pGuiTick->process(); //qDebug() << "refresh end" << m_vsyncThread->elapsed(); @@ -835,8 +838,9 @@ int WaveformWidgetFactory::findIndexOf(WWaveformViewer* viewer) const { return -1; } -void WaveformWidgetFactory::startVSync(GuiTick* pGuiTick) { +void WaveformWidgetFactory::startVSync(GuiTick* pGuiTick, VisualsManager* pVisualsManager) { m_pGuiTick = pGuiTick; + m_pVisualsManager = pVisualsManager; m_vsyncThread = new VSyncThread(this); m_vsyncThread->start(QThread::NormalPriority); diff --git a/src/waveform/waveformwidgetfactory.h b/src/waveform/waveformwidgetfactory.h index 1991d1c2df..75aafd39c7 100644 --- a/src/waveform/waveformwidgetfactory.h +++ b/src/waveform/waveformwidgetfactory.h @@ -17,6 +17,7 @@ class WaveformWidgetAbstract; class QTimer; class VSyncThread; class GuiTick; +class VisualsManager; class WaveformWidgetAbstractHandle { public: @@ -102,7 +103,7 @@ class WaveformWidgetFactory : public QObject, publi |