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