1 #include "vinylcontrol/vinylcontrolmanager.h"
2 
3 #include "control/controlobject.h"
4 #include "control/controlproxy.h"
5 #include "mixer/playermanager.h"
6 #include "moc_vinylcontrolmanager.cpp"
7 #include "soundio/soundmanager.h"
8 #include "util/compatibility.h"
9 #include "util/timer.h"
10 #include "vinylcontrol/defs_vinylcontrol.h"
11 #include "vinylcontrol/vinylcontrol.h"
12 #include "vinylcontrol/vinylcontrolprocessor.h"
13 #include "vinylcontrol/vinylcontrolxwax.h"
14 
VinylControlManager(QObject * pParent,UserSettingsPointer pConfig,SoundManager * pSoundManager)15 VinylControlManager::VinylControlManager(QObject* pParent,
16                                          UserSettingsPointer pConfig,
17                                          SoundManager* pSoundManager)
18         : QObject(pParent),
19           m_pConfig(pConfig),
20           m_pProcessor(new VinylControlProcessor(this, pConfig)),
21           m_iTimerId(-1),
22           m_pNumDecks(nullptr),
23           m_iNumConfiguredDecks(0) {
24     // Register every possible VC input with SoundManager to route to the
25     // VinylControlProcessor.
26     for (int i = 0; i < kMaximumVinylControlInputs; ++i) {
27         pSoundManager->registerInput(
28             AudioInput(AudioInput::VINYLCONTROL, 0, 2, i), m_pProcessor);
29     }
30 }
31 
~VinylControlManager()32 VinylControlManager::~VinylControlManager() {
33     delete m_pProcessor;
34 
35     // save a bunch of stuff to config
36     // turn off vinyl control so it won't be enabled on load (this is redundant to mixxx.cpp)
37     for (int i = 0; i < m_iNumConfiguredDecks; ++i) {
38         QString group = PlayerManager::groupForDeck(i);
39         m_pConfig->setValue(ConfigKey(group, "vinylcontrol_enabled"), false);
40         m_pConfig->set(ConfigKey(VINYL_PREF_KEY, QString("cueing_ch%1").arg(i + 1)),
41             ConfigValue(static_cast<int>(ControlObject::get(
42                 ConfigKey(group, "vinylcontrol_cueing")))));
43         m_pConfig->set(ConfigKey(VINYL_PREF_KEY, QString("mode_ch%1").arg(i + 1)),
44             ConfigValue(static_cast<int>(ControlObject::get(
45                 ConfigKey(group, "vinylcontrol_mode")))));
46     }
47 }
48 
init()49 void VinylControlManager::init() {
50     m_pNumDecks = new ControlProxy("[Master]", "num_decks", this);
51     m_pNumDecks->connectValueChanged(this, &VinylControlManager::slotNumDecksChanged);
52     slotNumDecksChanged(m_pNumDecks->get());
53 }
54 
toggleVinylControl(int deck)55 void VinylControlManager::toggleVinylControl(int deck) {
56     if (deck < 0 || deck >= m_pVcEnabled.size()) {
57         return;
58     }
59 
60     ControlProxy* pEnabled = m_pVcEnabled[deck];
61     pEnabled->set(!pEnabled->toBool());
62 }
63 
slotNumDecksChanged(double dNumDecks)64 void VinylControlManager::slotNumDecksChanged(double dNumDecks) {
65     int num_decks = static_cast<int>(dNumDecks);
66 
67     // Complain if we try to create more decks than we can handle.
68     if (num_decks > kMaxNumberOfDecks) {
69         qWarning() << "Number of decks increased to " << num_decks << ", but Mixxx only supports "
70                    << kMaxNumberOfDecks << " vinyl inputs.  Decks above the maximum will not have "
71                    << " vinyl control";
72         num_decks = kMaxNumberOfDecks;
73     }
74 
75     if (num_decks <= m_iNumConfiguredDecks) {
76         // TODO(owilliams): If we implement deck deletion, shrink the size of configured decks.
77         return;
78     }
79 
80     for (int i = m_iNumConfiguredDecks; i < num_decks; ++i) {
81         QString group = PlayerManager::groupForDeck(i);
82         ControlProxy* pEnabled = new ControlProxy(group, "vinylcontrol_enabled", this);
83         m_pVcEnabled.push_back(pEnabled);
84         pEnabled->connectValueChanged(this, [this, i] { slotVinylControlEnabledChanged(i); });
85 
86         // Default cueing should be off.
87         ControlObject::set(ConfigKey(group, "vinylcontrol_cueing"),
88                 m_pConfig->getValue(
89                         ConfigKey(VINYL_PREF_KEY, QString("cueing_ch%1").arg(i + 1)),
90                         0.0));
91         // Default mode should be relative.
92         ControlObject::set(ConfigKey(group, "vinylcontrol_mode"),
93                 m_pConfig->getValue(
94                         ConfigKey(VINYL_PREF_KEY, QString("mode_ch%1").arg(i + 1)),
95                         MIXXX_VCMODE_RELATIVE));
96     }
97     m_iNumConfiguredDecks = num_decks;
98 }
99 
slotVinylControlEnabledChanged(int deck)100 void VinylControlManager::slotVinylControlEnabledChanged(int deck) {
101     if (deck < 0 || deck >= m_pVcEnabled.size()) {
102         DEBUG_ASSERT(false);
103         return;
104     }
105 
106     ControlProxy* pEnabled = m_pVcEnabled.at(deck);
107     emit vinylControlDeckEnabled(deck, pEnabled->toBool());
108 }
109 
requestReloadConfig()110 void VinylControlManager::requestReloadConfig() {
111     m_pProcessor->requestReloadConfig();
112 }
113 
vinylInputConnected(int deck)114 bool VinylControlManager::vinylInputConnected(int deck) {
115     if (deck < 0 || deck >= m_iNumConfiguredDecks) {
116         return false;
117     }
118     if (deck < 0 || deck >= m_pVcEnabled.length()) {
119         qDebug() << "WARNING, tried to get vinyl enabled status for non-existent deck " << deck;
120         return false;
121     }
122     return m_pProcessor->deckConfigured(deck);
123 }
124 
vinylInputFromGroup(const QString & group)125 int VinylControlManager::vinylInputFromGroup(const QString& group) {
126     QRegExp channelMatcher("\\[Channel([1-9]\\d*)\\]");
127     if (channelMatcher.exactMatch(group)) {
128         bool ok = false;
129         int input = channelMatcher.cap(1).toInt(&ok);
130         return ok ? input - 1 : -1;
131     }
132     return -1;
133 }
134 
addSignalQualityListener(VinylSignalQualityListener * pListener)135 void VinylControlManager::addSignalQualityListener(VinylSignalQualityListener* pListener) {
136     m_listeners.insert(pListener);
137     m_pProcessor->setSignalQualityReporting(true);
138 
139     if (m_iTimerId == -1) {
140         m_iTimerId = startTimer(MIXXX_VINYL_SCOPE_UPDATE_LATENCY_MS);
141     }
142 }
143 
removeSignalQualityListener(VinylSignalQualityListener * pListener)144 void VinylControlManager::removeSignalQualityListener(VinylSignalQualityListener* pListener) {
145     m_listeners.remove(pListener);
146     if (m_listeners.empty()) {
147         m_pProcessor->setSignalQualityReporting(false);
148         if (m_iTimerId != -1) {
149             killTimer(m_iTimerId);
150             m_iTimerId = -1;
151         }
152     }
153 }
154 
updateSignalQualityListeners()155 void VinylControlManager::updateSignalQualityListeners() {
156     FIFO<VinylSignalQualityReport>* signalQualityFifo = m_pProcessor->getSignalQualityFifo();
157     if (signalQualityFifo == nullptr) {
158         return;
159     }
160 
161     VinylSignalQualityReport report;
162     while (signalQualityFifo->read(&report, 1) == 1) {
163         foreach (VinylSignalQualityListener* pListener, m_listeners) {
164             pListener->onVinylSignalQualityUpdate(report);
165         }
166     }
167 }
168 
timerEvent(QTimerEvent *)169 void VinylControlManager::timerEvent(QTimerEvent*) {
170     updateSignalQualityListeners();
171 }
172