1 #include "engine/controls/vinylcontrolcontrol.h"
2 
3 #include "moc_vinylcontrolcontrol.cpp"
4 #include "track/track.h"
5 #include "vinylcontrol/vinylcontrol.h"
6 
VinylControlControl(const QString & group,UserSettingsPointer pConfig)7 VinylControlControl::VinylControlControl(const QString& group, UserSettingsPointer pConfig)
8         : EngineControl(group, pConfig),
9           m_bSeekRequested(false) {
10     m_pControlVinylStatus = new ControlObject(ConfigKey(group, "vinylcontrol_status"));
11     m_pControlVinylSpeedType = new ControlObject(ConfigKey(group, "vinylcontrol_speed_type"));
12 
13     //Convert the ConfigKey's value into a double for the CO (for fast reads).
14     QString strVinylSpeedType = pConfig->getValueString(ConfigKey(group,
15                                                       "vinylcontrol_speed_type"));
16     if (strVinylSpeedType == MIXXX_VINYL_SPEED_33) {
17         m_pControlVinylSpeedType->set(MIXXX_VINYL_SPEED_33_NUM);
18     } else if (strVinylSpeedType == MIXXX_VINYL_SPEED_45) {
19         m_pControlVinylSpeedType->set(MIXXX_VINYL_SPEED_45_NUM);
20     } else {
21         m_pControlVinylSpeedType->set(MIXXX_VINYL_SPEED_33_NUM);
22     }
23 
24     m_pControlVinylSeek = new ControlObject(ConfigKey(group, "vinylcontrol_seek"));
25     connect(m_pControlVinylSeek, &ControlObject::valueChanged,
26             this, &VinylControlControl::slotControlVinylSeek,
27             Qt::DirectConnection);
28 
29     m_pControlVinylRate = new ControlObject(ConfigKey(group, "vinylcontrol_rate"));
30     m_pControlVinylScratching = new ControlPushButton(ConfigKey(group, "vinylcontrol_scratching"));
31     m_pControlVinylScratching->set(0);
32     m_pControlVinylScratching->setButtonMode(ControlPushButton::TOGGLE);
33     m_pControlVinylEnabled = new ControlPushButton(ConfigKey(group, "vinylcontrol_enabled"));
34     m_pControlVinylEnabled->set(0);
35     m_pControlVinylEnabled->setButtonMode(ControlPushButton::TOGGLE);
36     m_pControlVinylWantEnabled = new ControlPushButton(ConfigKey(group, "vinylcontrol_wantenabled"));
37     m_pControlVinylWantEnabled->set(0);
38     m_pControlVinylWantEnabled->setButtonMode(ControlPushButton::TOGGLE);
39     m_pControlVinylMode = new ControlPushButton(ConfigKey(group, "vinylcontrol_mode"));
40     m_pControlVinylMode->setStates(3);
41     m_pControlVinylMode->setButtonMode(ControlPushButton::TOGGLE);
42     m_pControlVinylCueing = new ControlPushButton(ConfigKey(group, "vinylcontrol_cueing"));
43     m_pControlVinylCueing->setStates(3);
44     m_pControlVinylCueing->setButtonMode(ControlPushButton::TOGGLE);
45     m_pControlVinylSignalEnabled = new ControlPushButton(ConfigKey(group, "vinylcontrol_signal_enabled"));
46     m_pControlVinylSignalEnabled->set(1);
47     m_pControlVinylSignalEnabled->setButtonMode(ControlPushButton::TOGGLE);
48 
49     m_pPlayEnabled = new ControlProxy(group, "play", this);
50 }
51 
~VinylControlControl()52 VinylControlControl::~VinylControlControl() {
53     delete m_pControlVinylRate;
54     delete m_pControlVinylSignalEnabled;
55     delete m_pControlVinylCueing;
56     delete m_pControlVinylMode;
57     delete m_pControlVinylWantEnabled;
58     delete m_pControlVinylEnabled;
59     delete m_pControlVinylScratching;
60     delete m_pControlVinylSeek;
61     delete m_pControlVinylSpeedType;
62     delete m_pControlVinylStatus;
63 }
64 
trackLoaded(TrackPointer pNewTrack)65 void VinylControlControl::trackLoaded(TrackPointer pNewTrack) {
66     m_pTrack = pNewTrack;
67 }
68 
notifySeekQueued()69 void VinylControlControl::notifySeekQueued() {
70     // m_bRequested is set and unset in a single execution path,
71     // so there are no issues with signals/slots causing timing
72     // issues.
73     if (m_pControlVinylMode->get() == MIXXX_VCMODE_ABSOLUTE &&
74         m_pPlayEnabled->get() > 0.0 &&
75         !m_bSeekRequested) {
76         m_pControlVinylMode->set(MIXXX_VCMODE_RELATIVE);
77     }
78 }
79 
slotControlVinylSeek(double fractionalPos)80 void VinylControlControl::slotControlVinylSeek(double fractionalPos) {
81     // Prevent NaN's from sneaking into the engine.
82     if (util_isnan(fractionalPos)) {
83         return;
84     }
85 
86     // Do nothing if no track is loaded.
87     TrackPointer pTrack = m_pTrack;
88     if (!pTrack) {
89         return;
90     }
91 
92     double total_samples = getSampleOfTrack().total;
93     double new_playpos = round(fractionalPos * total_samples);
94 
95     if (m_pControlVinylEnabled->get() > 0.0 && m_pControlVinylMode->get() == MIXXX_VCMODE_RELATIVE) {
96         int cuemode = (int)m_pControlVinylCueing->get();
97 
98         //if in preroll, always seek
99         if (new_playpos < 0) {
100             seekExact(new_playpos);
101             return;
102         }
103 
104         switch (cuemode) {
105         case MIXXX_RELATIVE_CUE_OFF:
106             return; // If off, do nothing.
107         case MIXXX_RELATIVE_CUE_ONECUE:
108             //if onecue, just seek to the regular cue
109             seekExact(pTrack->getCuePoint().getPosition());
110             return;
111         case MIXXX_RELATIVE_CUE_HOTCUE:
112             // Continue processing in this function.
113             break;
114         default:
115             qWarning() << "Invalid vinyl cue setting";
116             return;
117         }
118 
119         double shortest_distance = 0;
120         double nearest_playpos = -1;
121 
122         const QList<CuePointer> cuePoints(pTrack->getCuePoints());
123         QListIterator<CuePointer> it(cuePoints);
124         while (it.hasNext()) {
125             CuePointer pCue(it.next());
126             if (pCue->getType() != mixxx::CueType::HotCue || pCue->getHotCue() == -1) {
127                 continue;
128             }
129 
130             double cue_position = pCue->getPosition();
131             // pick cues closest to new_playpos
132             if ((nearest_playpos == -1) ||
133                 (fabs(new_playpos - cue_position) < shortest_distance)) {
134                 nearest_playpos = cue_position;
135                 shortest_distance = fabs(new_playpos - cue_position);
136             }
137         }
138 
139         if (nearest_playpos == -1) {
140             if (new_playpos >= 0) {
141                 //never found an appropriate cue, so don't seek?
142                 return;
143             }
144             //if negative, allow a seek by falling down to the bottom
145         } else {
146             m_bSeekRequested = true;
147             seekExact(nearest_playpos);
148             m_bSeekRequested = false;
149             return;
150         }
151     }
152 
153     // Just seek where it wanted to originally.
154     m_bSeekRequested = true;
155     seekExact(new_playpos);
156     m_bSeekRequested = false;
157 }
158 
isEnabled()159 bool VinylControlControl::isEnabled()
160 {
161     return m_pControlVinylEnabled->toBool();
162 }
163 
isScratching()164 bool VinylControlControl::isScratching()
165 {
166     return m_pControlVinylScratching->toBool();
167 }
168