Merge lp:~mixxxdevelopers/mixxx/features_vcman into lp:~mixxxdevelopers/mixxx/trunk
- features_vcman
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 2757 |
Proposed branch: | lp:~mixxxdevelopers/mixxx/features_vcman |
Merge into: | lp:~mixxxdevelopers/mixxx/trunk |
Diff against target: |
978 lines (+268/-207) 21 files modified
mixxx/build/features.py (+6/-5) mixxx/src/dlgpreferences.cpp (+3/-4) mixxx/src/dlgpreferences.h (+2/-1) mixxx/src/dlgprefsound.cpp (+0/-16) mixxx/src/dlgprefvinyl.cpp (+18/-41) mixxx/src/dlgprefvinyl.h (+4/-10) mixxx/src/engine/enginebuffer.cpp (+2/-2) mixxx/src/engine/enginebuffer.h (+1/-1) mixxx/src/engine/vinylcontrolcontrol.cpp (+1/-1) mixxx/src/mixxx.cpp (+27/-26) mixxx/src/mixxx.h (+3/-4) mixxx/src/soundmanager.cpp (+0/-57) mixxx/src/soundmanager.h (+0/-10) mixxx/src/vinylcontrol/vinylcontrol.cpp (+3/-3) mixxx/src/vinylcontrol/vinylcontrol.h (+4/-4) mixxx/src/vinylcontrol/vinylcontrolmanager.cpp (+148/-0) mixxx/src/vinylcontrol/vinylcontrolmanager.h (+36/-0) mixxx/src/vinylcontrol/vinylcontrolproxy.cpp (+5/-14) mixxx/src/vinylcontrol/vinylcontrolproxy.h (+2/-5) mixxx/src/vinylcontrol/vinylcontrolxwax.cpp (+2/-2) mixxx/src/vinylcontrol/vinylcontrolxwax.h (+1/-1) |
To merge this branch: | bzr merge lp:~mixxxdevelopers/mixxx/features_vcman |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
RJ Skerry-Ryan | Approve | ||
Review via email: mp+58019@code.launchpad.net |
Commit message
Description of the change
Branch:
* Moves all the vinyl control code to src/vinylcontrol/
* Moves all the vinyl control code from SoundManager to new VinylControlManager
* Sets VinylControlManager as the designated recipient of vinyl control samples from SoundManager
Features:
* Vinyl control prefs can now be applied without rebooting the portaudio callback (not a particularly useful feature but nice to keep unrelated things uncoupled)
* SoundManager now 100% unaware of vinyl control, as it ought to be.
* More stuff here I'm probably not thinking of
Bugs (???):
* The ordering in the sound prefs under the input tab is weird on my machine (order: VC1, mic, VC2). This is due to some weird Qt signal ordering, because the add-audiodest-
* Regressions??? I've tested messing with config, single deck vinyl, both-deck vinyl. I think it's good, but testers are always great.
Please excuse any glaring errors, brain is a bit numb and eyes are a bit tired.
- 2655. By William Good
-
Merge with lp:mixxx
- 2656. By William Good
-
Delete vcmanager before the engine to prevent a segfault on deref of a CO on exit
- 2657. By William Good
-
Move the vinyl control proxies to an array-based QVector (should be faster? also more in line with how I was using the data structure anyway)
- 2658. By William Good
-
Remove SoundManager usage from VinylControlManager
William Good (bkgood) wrote : | # |
> * In VinylControlMan
> passed in and that it's used to scan through its list of enabled inputs --
> seems like VCManager shouldn't know those details of SoundManager. Would
> it be possible to determine which VC decks were enabled by just keeping
> track of onInputConnect/
Fixed... ended up being way simpler once I wasn't just doing a straight copy+paste from the old code.
> Also naming the parameter
> 'deck' is a little misleading since one turntable can control multiple
> decks (or will in the future?) Since you're checking for a matching
> AudioInput index, doesn't this just test whether the N'th VC input is
> enabled?
The 'deck' parameter actually refers to the deck which the vinyl control input is to control (so deck=1 refers to [Channel1] stuff), so aside from perhaps misguided naming, I think this is correct. But yes, this just makes life easier (saves some code duplication) for some GUI code in mixxx.cpp.
> * I don't think I understand how QSemaphore protects m_proxies in this
> case. QList is not thread safe so two threads should never access it at
> once -- this includes using QList::at, so all accesses to the list should
> be guarded by a monolithic QMutex (yea .. it sucks). I would use a QMutex
> and then make sure to unlock it the second you get the VCProxy that you
> need from the list (or in the case of creating the VC proxy, create it,
> then lock and insert it and unlock).
>
Is QList::at (now QVector::at) really not save to call concurrently? I had a look at the Qt source and it looks like a totally safe operation (immediately, ::at is const so state isn't being modified). The only case I could think of in which this would be a problem is if the list was being modified while ::at was called, which was how I came to the semaphore use: any number of callback threads (which will never be greater than the number of vinyl control objects) can call receiveBuffer and submit samples, but writing requires a total lockout of all list readers so I acquire all of the semaphore's 'resources' (and block until I do) before doing any modification. As I only allocate memory for the vector once and simply replace elements afterwards, I'm wondering if I could just make a mutex for each individual vector slot and use that to keep from replacing a pointer while I'm reading it in another thread.
RJ Skerry-Ryan (rryan) wrote : | # |
Some minor fixes below but looks good to me.
> Is QList::at (now QVector::at) really not save to call concurrently?
Basically, no none of them are. The Qt docs don't claim they are thread safe at all. While you're right, the many-reader case will generally not cause issues since it doesn't update state we don't have guarantees that the list/vector isn't being grown/shrunk when we do something to it.
You're assuming that m_proxies never changes. Things like m_proxies.size() aren't ok to call without a lock protecting the entire list if the size of that list changes. Today it's a safe assumption that m_proxies never changes, so they should happen to work fine, but in the future we might change things and forget to update the locking strategy for m_proxies. I would switch to using a QReadWriteLock just to be safe.. it allows many readers concurrently but locks them out when someone is locking it for writing.
- In mixxx.cpp the else block sets m_pVCManager to NULL, but this variable doesn't exist if VINYLCONTROL isn't defined.
Today we don't really support updating the # of decks on the fly and there are only as many spots for proxies as there are physical decks. I'm a little wary of passing in the number of decks a fixed value that doesn't change because this will be a pain later when potentially we let you add decks to Mixxx on the fly, or when the skin can specify how many decks it's made for, etc. etc. What I mean is that it isn't un-imaginable that the number of decks could change on the fly. We can fix this when we n-deck'ify vinyl control though.
- 2659. By William Good
-
Move fun semaphore locking to QReadWriteLock
- 2660. By William Good
-
Always declare VinylControlManager instance in MixxxApp
- 2661. By William Good
-
Don't hardcode VinylControlManager to a set number of VinylControlPro
xies, allow arbitrary number.
William Good (bkgood) wrote : | # |
> You're assuming that m_proxies never changes. Things like m_proxies.size()
> aren't ok to call without a lock protecting the entire list if the size of
> that list changes. Today it's a safe assumption that m_proxies never changes,
> so they should happen to work fine, but in the future we might change things
> and forget to update the locking strategy for m_proxies. I would switch to
> using a QReadWriteLock just to be safe.. it allows many readers concurrently
> but locks them out when someone is locking it for writing.
>
Indeed, I wrote my locking strategy under the assumptions of how I wrote the code today and not how it might be modified in a year, but I don't guess I see this as making it particularly wrong -- but QReadWriteLock does everything I want, and that's the more obvious approach anyway.
> - In mixxx.cpp the else block sets m_pVCManager to NULL, but this variable
> doesn't exist if VINYLCONTROL isn't defined.
>
Good catch, I have to have it declared as it's passed to the DlgPreferences ctor (which is why it's NULLed) but I think I discovered this after I wrote the VinylControlManager instance into mixxx.h.
> Today we don't really support updating the # of decks on the fly and there are
> only as many spots for proxies as there are physical decks. I'm a little wary
> of passing in the number of decks a fixed value that doesn't change because
> this will be a pain later when potentially we let you add decks to Mixxx on
> the fly, or when the skin can specify how many decks it's made for, etc. etc.
> What I mean is that it isn't un-imaginable that the number of decks could
> change on the fly. We can fix this when we n-deck'ify vinyl control though.
VinylControlManager will now create a VinylControlProxy for whatever index it receives, from 0 to 255 (and why _not_ support 256 decks, VDJ has 99...). I didn't bother to mess with the big config-load/save blocks, those will have to be fixed (i.e. generalized and iterated-over) for n-decks.
Let me know about these changes and I'll merge into trunk if I still get the thumbs-up, thanks for looking at it! fyi, I've tested using a couple of instances of mixxx and crazy jack routing so I'm fairly confident in its correctness, at least in the cases I tested it.
Preview Diff
1 | === modified file 'mixxx/build/features.py' |
2 | --- mixxx/build/features.py 2011-04-17 02:42:45 +0000 |
3 | +++ mixxx/build/features.py 2011-04-18 08:02:27 +0000 |
4 | @@ -287,12 +287,13 @@ |
5 | build.env.Append(CPPPATH='#lib/scratchlib') |
6 | |
7 | def sources(self, build): |
8 | - sources = ['vinylcontrol.cpp', |
9 | - 'vinylcontrolproxy.cpp', |
10 | - 'vinylcontrolxwax.cpp', |
11 | + sources = ['vinylcontrol/vinylcontrol.cpp', |
12 | + 'vinylcontrol/vinylcontrolproxy.cpp', |
13 | + 'vinylcontrol/vinylcontrolxwax.cpp', |
14 | 'dlgprefvinyl.cpp', |
15 | - 'vinylcontrolsignalwidget.cpp', |
16 | - 'engine/vinylcontrolcontrol.cpp'] |
17 | + 'vinylcontrol/vinylcontrolsignalwidget.cpp', |
18 | + 'vinylcontrol/vinylcontrolmanager.cpp', |
19 | + 'engine/vinylcontrolcontrol.cpp',] |
20 | if build.platform_is_windows: |
21 | sources.append("#lib/xwax/timecoder_win32.cpp") |
22 | sources.append("#lib/xwax/lut.cpp") |
23 | |
24 | === modified file 'mixxx/src/dlgpreferences.cpp' |
25 | --- mixxx/src/dlgpreferences.cpp 2011-04-16 20:03:36 +0000 |
26 | +++ mixxx/src/dlgpreferences.cpp 2011-04-18 08:02:27 +0000 |
27 | @@ -50,7 +50,8 @@ |
28 | |
29 | DlgPreferences::DlgPreferences(MixxxApp * mixxx, SkinLoader* pSkinLoader, |
30 | SoundManager * soundman, PlayerManager* pPlayerManager, |
31 | - MidiDeviceManager * midi, ConfigObject<ConfigValue> * _config) |
32 | + MidiDeviceManager * midi, VinylControlManager *pVCManager, |
33 | + ConfigObject<ConfigValue> * _config) |
34 | : QDialog(), Ui::DlgPreferencesDlg() { |
35 | m_pMixxx = mixxx; |
36 | m_pMidiDeviceManager = midi; |
37 | @@ -76,7 +77,7 @@ |
38 | wreplaygain = new DlgPrefReplayGain(this, config); |
39 | wrecord = new DlgPrefRecord(this, config); |
40 | #ifdef __VINYLCONTROL__ |
41 | - wvinylcontrol = new DlgPrefVinyl(this, soundman, config); |
42 | + wvinylcontrol = new DlgPrefVinyl(this, pVCManager, config); |
43 | #else |
44 | wnovinylcontrol = new DlgPrefNoVinyl(this, soundman, config); |
45 | #endif |
46 | @@ -139,8 +140,6 @@ |
47 | #endif |
48 | |
49 | #ifdef __VINYLCONTROL__ |
50 | - connect(wvinylcontrol, SIGNAL(refreshVCProxies()), wsound, SLOT(forceApply())); |
51 | - connect(wvinylcontrol, SIGNAL(applySound()), wsound, SLOT(slotApply())); |
52 | connect(buttonBox, SIGNAL(accepted()), wvinylcontrol, SLOT(slotApply())); //It's important for this to be before the |
53 | //connect for wsound... |
54 | #endif |
55 | |
56 | === modified file 'mixxx/src/dlgpreferences.h' |
57 | --- mixxx/src/dlgpreferences.h 2011-04-16 20:03:36 +0000 |
58 | +++ mixxx/src/dlgpreferences.h 2011-04-18 08:02:27 +0000 |
59 | @@ -49,6 +49,7 @@ |
60 | class MidiDeviceManager; |
61 | class SkinLoader; |
62 | class PlayerManager; |
63 | +class VinylControlManager; |
64 | |
65 | /** |
66 | *@author Tue & Ken Haste Andersen |
67 | @@ -60,7 +61,7 @@ |
68 | public: |
69 | DlgPreferences(MixxxApp *mixxx, SkinLoader* pSkinLoader, SoundManager *soundman, |
70 | PlayerManager* pPlayerManager, MidiDeviceManager* midi, |
71 | - ConfigObject<ConfigValue> *config); |
72 | + VinylControlManager *pVCManager, ConfigObject<ConfigValue> *config); |
73 | |
74 | ~DlgPreferences(); |
75 | void createIcons(); |
76 | |
77 | === modified file 'mixxx/src/dlgprefsound.cpp' |
78 | --- mixxx/src/dlgprefsound.cpp 2011-04-15 07:08:16 +0000 |
79 | +++ mixxx/src/dlgprefsound.cpp 2011-04-18 08:02:27 +0000 |
80 | @@ -117,22 +117,6 @@ |
81 | if (!m_settingsModified && !m_forceApply) { |
82 | return; |
83 | } |
84 | -#ifdef __VINYLCONTROL__ |
85 | - // Scratchlib sucks, throw rocks at it |
86 | - // XXX(bkgood) HACKS DELETE THIS WHEN SCRATCHLIB GETS NUKED KTHX |
87 | - if ((m_pConfig->getValueString(ConfigKey("[Channel1]", "vinylcontrol_vinyl_type")) |
88 | - == MIXXX_VINYL_FINALSCRATCH || |
89 | - m_pConfig->getValueString(ConfigKey("[Channel2]", "vinylcontrol_vinyl_type")) |
90 | - == MIXXX_VINYL_FINALSCRATCH) |
91 | - && |
92 | - sampleRateComboBox->itemData(sampleRateComboBox->currentIndex()).toUInt() |
93 | - != 44100) { |
94 | - QMessageBox::warning(this, tr("Mixxx Error"), |
95 | - tr("FinalScratch records currently only work properly with a " |
96 | - "44100 Hz sample rate.\nThe sample rate has been reset to 44100 Hz.")); |
97 | - sampleRateComboBox->setCurrentIndex(sampleRateComboBox->findData(44100)); |
98 | - } |
99 | -#endif |
100 | m_forceApply = false; |
101 | m_config.clearInputs(); |
102 | m_config.clearOutputs(); |
103 | |
104 | === modified file 'mixxx/src/dlgprefvinyl.cpp' |
105 | --- mixxx/src/dlgprefvinyl.cpp 2011-04-16 20:15:25 +0000 |
106 | +++ mixxx/src/dlgprefvinyl.cpp 2011-04-18 08:02:27 +0000 |
107 | @@ -23,19 +23,17 @@ |
108 | #include <QtGui> |
109 | #include "dlgprefvinyl.h" |
110 | #include "controlobject.h" |
111 | -#include "soundmanager.h" |
112 | -#include "vinylcontrol.h" //For vinyl type string constants |
113 | +#include "vinylcontrol/vinylcontrolmanager.h" |
114 | +#include "vinylcontrol/vinylcontrol.h" //For vinyl type string constants |
115 | #include "controlobjectthreadmain.h" |
116 | -#include "vinylcontrolsignalwidget.h" |
117 | #include "dlgprefvinyl.h" |
118 | |
119 | -DlgPrefVinyl::DlgPrefVinyl(QWidget * parent, SoundManager * soundman, |
120 | +DlgPrefVinyl::DlgPrefVinyl(QWidget * parent, VinylControlManager *pVCMan, |
121 | ConfigObject<ConfigValue> * _config) : QWidget(parent), Ui::DlgPrefVinylDlg(), |
122 | m_COTMode(ControlObject::getControl(ConfigKey("[VinylControl]", "mode"))) |
123 | { |
124 | - m_pSoundManager = soundman; |
125 | + m_pVCManager = pVCMan; |
126 | config = _config; |
127 | - m_dontForce = false; |
128 | |
129 | setupUi(this); |
130 | |
131 | @@ -75,17 +73,6 @@ |
132 | connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApply())); |
133 | connect(VinylGain, SIGNAL(sliderReleased()), this, SLOT(VinylGainSlotApply())); |
134 | //connect(ComboBoxDeviceDeck1, SIGNAL(currentIndexChanged()), this, SLOT(())); |
135 | - |
136 | - connect(VinylGain, SIGNAL(sliderReleased()), this, SLOT(settingsChanged())); |
137 | - connect(ComboBoxVinylType1, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); |
138 | - connect(ComboBoxVinylType2, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); |
139 | - connect(ComboBoxVinylSpeed1, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); |
140 | - connect(ComboBoxVinylSpeed2, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); |
141 | - connect(LeadinTime, SIGNAL(textChanged(const QString&)), this, SLOT(settingsChanged())); |
142 | - connect(NeedleSkipEnable, SIGNAL(stateChanged(int)), this, SLOT(settingsChanged())); |
143 | - connect(AbsoluteMode, SIGNAL(toggled(bool)), this, SLOT(settingsChanged())); |
144 | - connect(RelativeMode, SIGNAL(toggled(bool)), this, SLOT(settingsChanged())); |
145 | - connect(m_pSoundManager, SIGNAL(devicesSetup()), this, SLOT(settingsChanged())); |
146 | } |
147 | |
148 | DlgPrefVinyl::~DlgPrefVinyl() |
149 | @@ -95,7 +82,7 @@ |
150 | /** @brief Performs any necessary actions that need to happen when the prefs dialog is opened */ |
151 | void DlgPrefVinyl::slotShow() |
152 | { |
153 | - QList<VinylControlProxy*> VCProxiesList = m_pSoundManager->getVinylControlProxies(); |
154 | + QList<VinylControlProxy*> VCProxiesList = m_pVCManager->vinylControlProxies(); |
155 | if (VCProxiesList.value(0) != NULL) |
156 | m_signalWidget1.setVinylControlProxy(VCProxiesList.value(0)); |
157 | if (VCProxiesList.value(1) != NULL) |
158 | @@ -119,8 +106,6 @@ |
159 | |
160 | void DlgPrefVinyl::slotUpdate() |
161 | { |
162 | - m_dontForce = true; // otherwise all the signals fired in here will cause |
163 | - // DlgPrefSound to call setupDevices needlessly :) -- bkgood |
164 | // Set vinyl control types in the comboboxes |
165 | int combo_index = ComboBoxVinylType1->findText(config->getValueString(ConfigKey("[Channel1]","vinylcontrol_vinyl_type"))); |
166 | if (combo_index != -1) |
167 | @@ -153,17 +138,26 @@ |
168 | |
169 | //set vinyl control gain |
170 | VinylGain->setValue( config->getValueString(ConfigKey("[VinylControl]","gain")).toInt()); |
171 | - m_dontForce = false; |
172 | + |
173 | + QList<VinylControlProxy*> VCProxiesList = m_pVCManager->vinylControlProxies(); |
174 | + if (VCProxiesList.value(0) != NULL) { |
175 | + m_signalWidget1.setVinylControlProxy(VCProxiesList.value(0)); |
176 | + } |
177 | + if (VCProxiesList.value(1) != NULL) { |
178 | + m_signalWidget2.setVinylControlProxy(VCProxiesList.value(1)); |
179 | + } |
180 | + |
181 | + m_signalWidget1.setVinylActive(m_pVCManager->vinylInputEnabled(1)); |
182 | + m_signalWidget2.setVinylActive(m_pVCManager->vinylInputEnabled(2)); |
183 | } |
184 | |
185 | // Update the config object with parameters from dialog |
186 | void DlgPrefVinyl::slotApply() |
187 | { |
188 | - QString device2; |
189 | qDebug() << "DlgPrefVinyl::Apply"; |
190 | |
191 | // Lead-in time |
192 | - QString strLeadIn = LeadinTime->text(); |
193 | + QString strLeadIn = LeadinTime->text(); |
194 | bool isInteger; |
195 | strLeadIn.toInt(&isInteger); |
196 | if (isInteger) |
197 | @@ -187,6 +181,7 @@ |
198 | config->set(ConfigKey("[VinylControl]","mode"), ConfigValue(iMode)); |
199 | config->set(ConfigKey("[VinylControl]","needle_skip_prevention" ), ConfigValue( (int)(NeedleSkipEnable->isChecked( )) ) ); |
200 | |
201 | + m_pVCManager->reloadConfig(); |
202 | slotUpdate(); |
203 | } |
204 | |
205 | @@ -201,7 +196,6 @@ |
206 | config->set(ConfigKey("[Channel2]","vinylcontrol_vinyl_type"), ConfigValue(ComboBoxVinylType2->currentText())); |
207 | config->set(ConfigKey("[Channel1]","vinylcontrol_speed_type"), ConfigValue(ComboBoxVinylSpeed1->currentText())); |
208 | config->set(ConfigKey("[Channel2]","vinylcontrol_speed_type"), ConfigValue(ComboBoxVinylSpeed2->currentText())); |
209 | - emit(applySound()); |
210 | } |
211 | |
212 | void DlgPrefVinyl::VinylGainSlotApply() |
213 | @@ -214,20 +208,3 @@ |
214 | ControlObject* pControlObjectVinylControlGain = ControlObject::getControl(ConfigKey("[VinylControl]", "gain")); |
215 | pControlObjectVinylControlGain->set(VinylGain->value()); |
216 | } |
217 | - |
218 | -void DlgPrefVinyl::settingsChanged() { |
219 | - if (!m_dontForce) { |
220 | - emit(refreshVCProxies()); |
221 | - } |
222 | - |
223 | - QList<VinylControlProxy*> VCProxiesList = m_pSoundManager->getVinylControlProxies(); |
224 | - if (VCProxiesList.value(0) != NULL) { |
225 | - m_signalWidget1.setVinylControlProxy(VCProxiesList.value(0)); |
226 | - } |
227 | - if (VCProxiesList.value(1) != NULL) { |
228 | - m_signalWidget2.setVinylControlProxy(VCProxiesList.value(1)); |
229 | - } |
230 | - |
231 | - m_signalWidget1.setVinylActive(m_pSoundManager->hasVinylInput(0)); |
232 | - m_signalWidget2.setVinylActive(m_pSoundManager->hasVinylInput(1)); |
233 | -} |
234 | |
235 | === modified file 'mixxx/src/dlgprefvinyl.h' |
236 | --- mixxx/src/dlgprefvinyl.h 2011-04-16 20:15:56 +0000 |
237 | +++ mixxx/src/dlgprefvinyl.h 2011-04-18 08:02:27 +0000 |
238 | @@ -20,14 +20,14 @@ |
239 | |
240 | #include "ui_dlgprefvinyldlg.h" |
241 | #include "configobject.h" |
242 | -#include "vinylcontrolsignalwidget.h" |
243 | +#include "vinylcontrol/vinylcontrolsignalwidget.h" |
244 | #include "controlobjectthread.h" |
245 | |
246 | class QWidget; |
247 | class PlayerProxy; |
248 | class ControlObject; |
249 | class ControlObjectThreadMain; |
250 | -class SoundManager; |
251 | +class VinylControlManager; |
252 | |
253 | /** |
254 | *@author Stefan Langhammer |
255 | @@ -37,7 +37,7 @@ |
256 | class DlgPrefVinyl : public QWidget, Ui::DlgPrefVinylDlg { |
257 | Q_OBJECT |
258 | public: |
259 | - DlgPrefVinyl(QWidget *parent, SoundManager* soundman, ConfigObject<ConfigValue> *_config); |
260 | + DlgPrefVinyl(QWidget *pParent, VinylControlManager *m_pVCMan, ConfigObject<ConfigValue> *_config); |
261 | ~DlgPrefVinyl(); |
262 | |
263 | public slots: |
264 | @@ -51,11 +51,6 @@ |
265 | void slotShow(); |
266 | |
267 | signals: |
268 | - void apply(); |
269 | - void refreshVCProxies(); |
270 | - void applySound(); |
271 | -private slots: |
272 | - void settingsChanged(); |
273 | private: |
274 | VinylControlSignalWidget m_signalWidget1; |
275 | VinylControlSignalWidget m_signalWidget2; |
276 | @@ -63,7 +58,7 @@ |
277 | |
278 | /** Pointer to player device */ |
279 | //PlayerProxy *player; |
280 | - SoundManager* m_pSoundManager; |
281 | + VinylControlManager* m_pVCManager; |
282 | /** Pointer to config object */ |
283 | ConfigObject<ConfigValue> *config; |
284 | /** Indicates the strength of the timecode signal on each input */ |
285 | @@ -74,7 +69,6 @@ |
286 | ControlObjectThreadMain* m_vinylControlInput2L; |
287 | ControlObjectThreadMain* m_vinylControlInput2R; |
288 | ControlObjectThread m_COTMode; |
289 | - bool m_dontForce; |
290 | }; |
291 | |
292 | #endif |
293 | |
294 | === modified file 'mixxx/src/engine/enginebuffer.cpp' |
295 | --- mixxx/src/engine/enginebuffer.cpp 2011-04-17 02:42:45 +0000 |
296 | +++ mixxx/src/engine/enginebuffer.cpp 2011-04-18 08:02:27 +0000 |
297 | @@ -754,9 +754,9 @@ |
298 | } |
299 | |
300 | // Update indicators that are only updated after every |
301 | - // sampleRate/UPDATE_RATE samples processed. (e.g. playposSlider, |
302 | + // sampleRate/kiUpdateRate samples processed. (e.g. playposSlider, |
303 | // rateEngine) |
304 | - if (m_iSamplesCalculated > (m_pSampleRate->get()/UPDATE_RATE)) { |
305 | + if (m_iSamplesCalculated > (m_pSampleRate->get()/kiUpdateRate)) { |
306 | playposSlider->set(fFractionalPlaypos); |
307 | |
308 | if(rate != rateEngine->get()) |
309 | |
310 | === modified file 'mixxx/src/engine/enginebuffer.h' |
311 | --- mixxx/src/engine/enginebuffer.h 2011-04-17 02:42:45 +0000 |
312 | +++ mixxx/src/engine/enginebuffer.h 2011-04-18 08:02:27 +0000 |
313 | @@ -58,7 +58,7 @@ |
314 | const int kiTempLength = 200000; |
315 | |
316 | // Rate at which the playpos slider is updated (using a sample rate of 44100 Hz): |
317 | -const int UPDATE_RATE = 10; |
318 | +const int kiUpdateRate = 10; |
319 | |
320 | // End of track mode constants |
321 | const int TRACK_END_MODE_STOP = 0; |
322 | |
323 | === modified file 'mixxx/src/engine/vinylcontrolcontrol.cpp' |
324 | --- mixxx/src/engine/vinylcontrolcontrol.cpp 2011-04-17 02:42:45 +0000 |
325 | +++ mixxx/src/engine/vinylcontrolcontrol.cpp 2011-04-18 08:02:27 +0000 |
326 | @@ -1,6 +1,6 @@ |
327 | #include "engine/vinylcontrolcontrol.h" |
328 | |
329 | -#include "vinylcontrol.h" |
330 | +#include "vinylcontrol/vinylcontrol.h" |
331 | #include "library/dao/cue.h" |
332 | |
333 | VinylControlControl::VinylControlControl(const char* pGroup, ConfigObject<ConfigValue>* pConfig) |
334 | |
335 | === modified file 'mixxx/src/mixxx.cpp' |
336 | --- mixxx/src/mixxx.cpp 2011-04-16 19:50:10 +0000 |
337 | +++ mixxx/src/mixxx.cpp 2011-04-18 08:02:27 +0000 |
338 | @@ -64,6 +64,11 @@ |
339 | |
340 | #include "defs_version.h" |
341 | |
342 | +#ifdef __VINYLCONTROL__ |
343 | +#include "vinylcontrol/vinylcontrol.h" |
344 | +#include "vinylcontrol/vinylcontrolmanager.h" |
345 | +#endif |
346 | + |
347 | #ifdef __C_METRICS__ |
348 | #include <cmetrics.h> |
349 | #include "defs_mixxxcmetrics.h" |
350 | @@ -315,6 +320,17 @@ |
351 | AudioOutput(AudioOutput::DECK, 0, deck), m_pEngine); |
352 | } |
353 | |
354 | +#ifdef __VINYLCONTROL__ |
355 | + m_pVCManager = new VinylControlManager(this, m_pConfig); |
356 | + for (unsigned int deck = 0; deck < m_pPlayerManager->numDecks(); ++deck) { |
357 | + m_pSoundManager->registerInput( |
358 | + AudioInput(AudioInput::VINYLCONTROL, 0, deck), |
359 | + m_pVCManager); |
360 | + } |
361 | +#else |
362 | + m_pVCManager = NULL; |
363 | +#endif |
364 | + |
365 | //Scan the library directory. |
366 | m_pLibraryScanner = new LibraryScanner(m_pLibrary->getTrackCollection()); |
367 | |
368 | @@ -372,16 +388,8 @@ |
369 | m_pConfig->set(ConfigKey("[BPM]", "AnalyzeEntireSong"),ConfigValue(1)); |
370 | } |
371 | |
372 | -#ifdef __VINYLCONTROL__ |
373 | //ControlObject::getControl(ConfigKey("[Channel1]","TrackEndMode"))->queueFromThread(m_pConfig->getValueString(ConfigKey("[Controls]","TrackEndModeCh1")).toDouble()); |
374 | //ControlObject::getControl(ConfigKey("[Channel2]","TrackEndMode"))->queueFromThread(m_pConfig->getValueString(ConfigKey("[Controls]","TrackEndModeCh2")).toDouble()); |
375 | - ControlObject::getControl(ConfigKey("[Channel1]","vinylcontrol_enabled"))->queueFromThread(m_pConfig->getValueString(ConfigKey("[VinylControl]","enabled_ch1")).toDouble()); |
376 | - ControlObject::getControl(ConfigKey("[Channel2]","vinylcontrol_enabled"))->queueFromThread(m_pConfig->getValueString(ConfigKey("[VinylControl]","enabled_ch2")).toDouble()); |
377 | - ControlObject::getControl(ConfigKey("[Channel1]","vinylcontrol_mode"))->queueFromThread(m_pConfig->getValueString(ConfigKey("[VinylControl]","mode")).toDouble()); |
378 | - ControlObject::getControl(ConfigKey("[Channel2]","vinylcontrol_mode"))->queueFromThread(m_pConfig->getValueString(ConfigKey("[VinylControl]","mode")).toDouble()); |
379 | - ControlObject::getControl(ConfigKey("[Channel1]","vinylcontrol_cueing"))->queueFromThread(m_pConfig->getValueString(ConfigKey("[VinylControl]","cueing_ch1")).toDouble()); |
380 | - ControlObject::getControl(ConfigKey("[Channel2]","vinylcontrol_cueing"))->queueFromThread(m_pConfig->getValueString(ConfigKey("[VinylControl]","cueing_ch2")).toDouble()); |
381 | -#endif |
382 | |
383 | qRegisterMetaType<MidiMessage>("MidiMessage"); |
384 | qRegisterMetaType<MidiStatusByte>("MidiStatusByte"); |
385 | @@ -394,7 +402,7 @@ |
386 | |
387 | // Initialize preference dialog |
388 | m_pPrefDlg = new DlgPreferences(this, m_pSkinLoader, m_pSoundManager, m_pPlayerManager, |
389 | - m_pMidiDeviceManager, m_pConfig); |
390 | + m_pMidiDeviceManager, m_pVCManager, m_pConfig); |
391 | m_pPrefDlg->setHidden(true); |
392 | |
393 | // Try open player device If that fails, the preference panel is opened. |
394 | @@ -529,18 +537,18 @@ |
395 | // Save state of End of track controls in config database |
396 | //m_pConfig->set(ConfigKey("[Controls]","TrackEndModeCh1"), ConfigValue((int)ControlObject::getControl(ConfigKey("[Channel1]","TrackEndMode"))->get())); |
397 | //m_pConfig->set(ConfigKey("[Controls]","TrackEndModeCh2"), ConfigValue((int)ControlObject::getControl(ConfigKey("[Channel2]","TrackEndMode"))->get())); |
398 | -#ifdef __VINYLCONTROL__ |
399 | - m_pConfig->set(ConfigKey("[VinylControl]","enabled_ch1"), ConfigValue((int)ControlObject::getControl(ConfigKey("[Channel1]","vinylcontrol_enabled"))->get())); |
400 | - m_pConfig->set(ConfigKey("[VinylControl]","enabled_ch2"), ConfigValue((int)ControlObject::getControl(ConfigKey("[Channel2]","vinylcontrol_enabled"))->get())); |
401 | - m_pConfig->set(ConfigKey("[VinylControl]","mode"), ConfigValue((int)ControlObject::getControl(ConfigKey("[Channel1]","vinylcontrol_mode"))->get())); |
402 | - m_pConfig->set(ConfigKey("[VinylControl]","mode"), ConfigValue((int)ControlObject::getControl(ConfigKey("[Channel2]","vinylcontrol_mode"))->get())); |
403 | - m_pConfig->set(ConfigKey("[VinylControl]","cueing_ch1"), ConfigValue((int)ControlObject::getControl(ConfigKey("[Channel1]","vinylcontrol_cueing"))->get())); |
404 | - m_pConfig->set(ConfigKey("[VinylControl]","cueing_ch2"), ConfigValue((int)ControlObject::getControl(ConfigKey("[Channel2]","vinylcontrol_cueing"))->get())); |
405 | -#endif |
406 | + |
407 | // SoundManager depend on Engine and Config |
408 | qDebug() << "delete soundmanager, " << qTime.elapsed(); |
409 | delete m_pSoundManager; |
410 | |
411 | +#ifdef __VINYLCONTROL__ |
412 | + // VinylControlManager depends on a CO the engine owns |
413 | + // (vinylcontrol_enabled in VinylControlControl) |
414 | + qDebug() << "delete vinylcontrolmanager, " << qTime.elapsed(); |
415 | + delete m_pVCManager; |
416 | +#endif |
417 | + |
418 | // View depends on MixxxKeyboard, PlayerManager, Library |
419 | qDebug() << "delete view, " << qTime.elapsed(); |
420 | delete m_pView; |
421 | @@ -1143,7 +1151,7 @@ |
422 | void MixxxApp::slotControlVinylControl(double toggle) |
423 | { |
424 | #ifdef __VINYLCONTROL__ |
425 | - if (tryToggleVinylControl(0)) { |
426 | + if (m_pVCManager->vinylInputEnabled(1)) { |
427 | m_pConfig->set( |
428 | ConfigKey("[VinylControl]", "enabled_ch1"), ConfigValue((int)toggle)); |
429 | m_pOptionsVinylControl->setChecked((bool)toggle); |
430 | @@ -1180,18 +1188,11 @@ |
431 | #endif |
432 | } |
433 | |
434 | -int MixxxApp::tryToggleVinylControl(int deck) |
435 | -{ |
436 | -#ifdef __VINYLCONTROL__ |
437 | - return m_pSoundManager->hasVinylInput(deck); |
438 | -#endif |
439 | -} |
440 | - |
441 | void MixxxApp::slotControlVinylControl2(double toggle) |
442 | { |
443 | #ifdef __VINYLCONTROL__ |
444 | //we just need at least 1 input (deck 1) because of single deck mode |
445 | - if (tryToggleVinylControl(1)) { |
446 | + if (m_pVCManager->vinylInputEnabled(2)) { |
447 | m_pConfig->set( |
448 | ConfigKey("[VinylControl]", "enabled_ch2"), ConfigValue((int)toggle)); |
449 | m_pOptionsVinylControl2->setChecked((bool)toggle); |
450 | |
451 | === modified file 'mixxx/src/mixxx.h' |
452 | --- mixxx/src/mixxx.h 2011-04-16 20:57:48 +0000 |
453 | +++ mixxx/src/mixxx.h 2011-04-18 08:02:27 +0000 |
454 | @@ -42,9 +42,6 @@ |
455 | #include "controlobject.h" |
456 | #include "dlgpreferences.h" |
457 | //#include "trackplaylist.h" |
458 | -#ifdef __VINYLCONTROL__ |
459 | -#include "vinylcontrol.h" |
460 | -#endif |
461 | #include "recording/recordingmanager.h" |
462 | |
463 | #ifdef __SCRIPT__ |
464 | @@ -66,6 +63,8 @@ |
465 | class MixxxKeyboard; |
466 | class SkinLoader; |
467 | |
468 | +class VinylControlManager; |
469 | + |
470 | /** |
471 | * This Class is the base class for Mixxx. It sets up the main |
472 | * window and providing a menubar. |
473 | @@ -105,7 +104,6 @@ |
474 | /** toggle vinyl control - Don't #ifdef this because MOC is dumb**/ |
475 | void slotControlVinylControl(double toggle); |
476 | void slotCheckboxVinylControl(bool toggle); |
477 | - int tryToggleVinylControl(int deck); |
478 | void slotControlVinylControl2(double toggle); |
479 | void slotCheckboxVinylControl2(bool toggle); |
480 | /** toggle recording - Don't #ifdef this because MOC is dumb**/ |
481 | @@ -168,6 +166,7 @@ |
482 | |
483 | ConfigObject<ConfigValue> *m_pConfig; |
484 | |
485 | + VinylControlManager *m_pVCManager; |
486 | |
487 | MixxxKeyboard* m_pKeyboard; |
488 | /** Library scanner object */ |
489 | |
490 | === modified file 'mixxx/src/soundmanager.cpp' |
491 | --- mixxx/src/soundmanager.cpp 2011-04-16 15:25:20 +0000 |
492 | +++ mixxx/src/soundmanager.cpp 2011-04-18 08:02:27 +0000 |
493 | @@ -26,10 +26,6 @@ |
494 | #include "controlobjectthreadmain.h" |
495 | #include "soundmanagerutil.h" |
496 | |
497 | -#ifdef __VINYLCONTROL__ |
498 | -#include "vinylcontrolxwax.h" |
499 | -#endif |
500 | - |
501 | /** Initializes Mixxx's audio core |
502 | * @param pConfig The config key table |
503 | * @param _master A pointer to the audio engine's mastering class. |
504 | @@ -232,21 +228,6 @@ |
505 | } |
506 | } |
507 | m_inputBuffers.clear(); |
508 | - |
509 | -#ifdef __VINYLCONTROL__ |
510 | - // TODO(bkgood) see comment where these objects are created in setupDevices, |
511 | - // this should probably be in the dtor or at least somewhere other |
512 | - // than here. |
513 | - while (!m_vinylControl.empty()) { |
514 | - VinylControlProxy *vc = m_vinylControl.takeLast(); |
515 | - if (vc != NULL) { |
516 | - delete vc; |
517 | - } |
518 | - //xwax has a global LUT that we need to free after we've shut down our |
519 | - //vinyl control threads because it's not thread-safe. |
520 | - VinylControlXwax::freeLUTs(); |
521 | - } |
522 | -#endif |
523 | } |
524 | |
525 | /** Closes all the devices and empties the list of devices we have. */ |
526 | @@ -372,18 +353,6 @@ |
527 | |
528 | // close open devices, close running vinyl control proxies |
529 | closeDevices(); |
530 | -#ifdef __VINYLCONTROL__ |
531 | - //Initialize vinyl control |
532 | - // TODO(bkgood) this ought to be done in the ctor or something. Not here. Really |
533 | - // shouldn't be any reason for these to be reinitialized every time the |
534 | - // audio prefs are updated. Will require work in DlgPrefVinyl. |
535 | - m_vinylControl.append(new VinylControlProxy(m_pConfig, "[Channel1]")); |
536 | - m_vinylControl.append(new VinylControlProxy(m_pConfig, "[Channel2]")); |
537 | - qDebug() << "Created VinylControlProxies" << |
538 | - m_vinylControl[0] << m_vinylControl[1]; |
539 | - registerInput(AudioInput(AudioInput::VINYLCONTROL, 0, 0), m_vinylControl[0]); |
540 | - registerInput(AudioInput(AudioInput::VINYLCONTROL, 0, 1), m_vinylControl[1]); |
541 | -#endif |
542 | foreach (SoundDevice *device, m_devices) { |
543 | bool isInput = false; |
544 | bool isOutput = false; |
545 | @@ -471,32 +440,6 @@ |
546 | return m_config; |
547 | } |
548 | |
549 | -#ifdef __VINYLCONTROL__ |
550 | -bool SoundManager::hasVinylInput(int deck) |
551 | -{ |
552 | - if (deck >= m_vinylControl.length()) |
553 | - return false; |
554 | - VinylControlProxy* vinyl_control = m_vinylControl[deck]; |
555 | - |
556 | - bool hasInput = false; |
557 | - QList<AudioInput> inputs = getConfig().getInputs().values(); |
558 | - foreach (AudioInput in, inputs) { |
559 | - if (in.getType() == AudioInput::VINYLCONTROL |
560 | - && in.getIndex() == deck) { |
561 | - hasInput = true; |
562 | - break; |
563 | - } |
564 | - } |
565 | - |
566 | - return vinyl_control != NULL && hasInput; |
567 | -} |
568 | - |
569 | -QList<VinylControlProxy*> SoundManager::getVinylControlProxies() |
570 | -{ |
571 | - return m_vinylControl; |
572 | -} |
573 | -#endif |
574 | - |
575 | int SoundManager::setConfig(SoundManagerConfig config) { |
576 | int err = OK; |
577 | m_config = config; |
578 | |
579 | === modified file 'mixxx/src/soundmanager.h' |
580 | --- mixxx/src/soundmanager.h 2011-04-15 07:08:16 +0000 |
581 | +++ mixxx/src/soundmanager.h 2011-04-18 08:02:27 +0000 |
582 | @@ -21,9 +21,6 @@ |
583 | #include "configobject.h" |
584 | #include "controlobject.h" |
585 | #include "defs.h" |
586 | -#ifdef __VINYLCONTROL__ |
587 | -#include "vinylcontrolproxy.h" |
588 | -#endif |
589 | #include "soundmanagerconfig.h" |
590 | #include <QTimer> |
591 | |
592 | @@ -59,10 +56,6 @@ |
593 | QList<unsigned int> getSampleRates() const; |
594 | QList<QString> getHostAPIList() const; |
595 | SoundManagerConfig getConfig() const; |
596 | -#ifdef __VINYLCONTROL__ |
597 | - bool hasVinylInput(int deck); |
598 | - QList<VinylControlProxy*> getVinylControlProxies(); |
599 | -#endif |
600 | int setConfig(SoundManagerConfig config); |
601 | void checkConfig(); |
602 | QHash<AudioOutput, const CSAMPLE*> |
603 | @@ -92,9 +85,6 @@ |
604 | QHash<AudioInput, short*> m_inputBuffers; /** Audio received from input */ |
605 | QHash<SoundDevice*, long> m_deviceFrameCount; /** Sound card sync */ |
606 | SoundDevice* m_pClkRefDevice; /** Sound card sync */ |
607 | -#ifdef __VINYLCONTROL__ |
608 | - QList<VinylControlProxy*> m_vinylControl; |
609 | -#endif |
610 | unsigned int iNumDevicesOpenedForOutput; |
611 | unsigned int iNumDevicesOpenedForInput; |
612 | QMutex requestBufferMutex; |
613 | |
614 | === added directory 'mixxx/src/vinylcontrol' |
615 | === renamed file 'mixxx/src/vinylcontrol.cpp' => 'mixxx/src/vinylcontrol/vinylcontrol.cpp' |
616 | --- mixxx/src/vinylcontrol.cpp 2011-04-16 21:06:35 +0000 |
617 | +++ mixxx/src/vinylcontrol/vinylcontrol.cpp 2011-04-18 08:02:27 +0000 |
618 | @@ -1,10 +1,10 @@ |
619 | #include "vinylcontrol.h" |
620 | #include "controlobjectthread.h" |
621 | |
622 | -VinylControl::VinylControl(ConfigObject<ConfigValue> * pConfig, const char * _group) |
623 | +VinylControl::VinylControl(ConfigObject<ConfigValue> * pConfig, QString group) |
624 | { |
625 | m_pConfig = pConfig; |
626 | - group = _group; |
627 | + m_group = group; |
628 | iRIAACorrection = 0; |
629 | |
630 | iSampleRate = m_pConfig->getValueString(ConfigKey("[Soundcard]","Samplerate")).toULong(); |
631 | @@ -59,7 +59,7 @@ |
632 | { |
633 | bIsEnabled = enable; |
634 | if (m_pConfig) |
635 | - m_pConfig->set(ConfigKey(group,"vinylcontrol_enabled"), ConfigValue((int)enable)); |
636 | + m_pConfig->set(ConfigKey(m_group,"vinylcontrol_enabled"), ConfigValue((int)enable)); |
637 | |
638 | enabled->slotSet(enable); |
639 | |
640 | |
641 | === renamed file 'mixxx/src/vinylcontrol.h' => 'mixxx/src/vinylcontrol/vinylcontrol.h' |
642 | --- mixxx/src/vinylcontrol.h 2011-04-16 21:06:35 +0000 |
643 | +++ mixxx/src/vinylcontrol/vinylcontrol.h 2011-04-18 08:02:27 +0000 |
644 | @@ -1,5 +1,5 @@ |
645 | -#ifndef __VINYLCONTROL_H__ |
646 | -#define __VINYLCONTROL_H__ |
647 | +#ifndef VINYLCONTROL_H |
648 | +#define VINYLCONTROL_H |
649 | |
650 | #include <qthread.h> |
651 | #include "configobject.h" |
652 | @@ -39,7 +39,7 @@ |
653 | class VinylControl : public QThread |
654 | { |
655 | public: |
656 | - VinylControl(ConfigObject<ConfigValue> *pConfig, const char *_group); |
657 | + VinylControl(ConfigObject<ConfigValue> *pConfig, QString group); |
658 | virtual ~VinylControl(); |
659 | virtual void ToggleVinylControl(bool enable) = 0; |
660 | virtual bool isEnabled() = 0; |
661 | @@ -56,7 +56,7 @@ |
662 | QString strVinylType; |
663 | QString strVinylSpeed; |
664 | ConfigObject<ConfigValue> *m_pConfig; /** Pointer to config database */ |
665 | - const char* group; |
666 | + QString m_group; |
667 | ControlObjectThread *playButton; //The ControlObject used to start/stop playback of the song. |
668 | ControlObjectThread *playPos; //The ControlObject used to read the playback position in the song. |
669 | ControlObjectThread *vinylSeek; //The ControlObject used to change the playback position in the song. |
670 | |
671 | === added file 'mixxx/src/vinylcontrol/vinylcontrolmanager.cpp' |
672 | --- mixxx/src/vinylcontrol/vinylcontrolmanager.cpp 1970-01-01 00:00:00 +0000 |
673 | +++ mixxx/src/vinylcontrol/vinylcontrolmanager.cpp 2011-04-18 08:02:27 +0000 |
674 | @@ -0,0 +1,148 @@ |
675 | +/** |
676 | + * @file vinylcontrolmanager.cpp |
677 | + * @author Bill Good <bkgood@gmail.com> |
678 | + * @date April 15, 2011 |
679 | + */ |
680 | + |
681 | +#include "vinylcontrolmanager.h" |
682 | +#include "vinylcontrolproxy.h" |
683 | +#include "vinylcontrolxwax.h" |
684 | +#include "soundmanager.h" |
685 | + |
686 | +const int kNumberOfDecks = 4; // set to 4 because it will ideally not be more |
687 | +// or less than the number of vinyl-controlled decks but will probably be |
688 | +// forgotten in any 2->4 deck switchover. Only real consequence is |
689 | +// sizeof(void*)*2 bytes of wasted memory if we're only using 2 decks -bkgood |
690 | + |
691 | +const QString kVCProxyGroup = QString("[Channel%1]"); |
692 | + |
693 | +VinylControlManager::VinylControlManager(QObject *pParent, |
694 | + ConfigObject<ConfigValue> *pConfig) |
695 | + : QObject(pParent) |
696 | + , m_pConfig(pConfig) |
697 | + , m_proxies(kNumberOfDecks, NULL) { |
698 | + // load a bunch of stuff |
699 | + ControlObject::getControl(ConfigKey("[Channel1]","vinylcontrol_enabled")) |
700 | + ->queueFromThread(m_pConfig->getValueString( |
701 | + ConfigKey("[VinylControl]","enabled_ch1")).toDouble()); |
702 | + ControlObject::getControl(ConfigKey("[Channel2]","vinylcontrol_enabled")) |
703 | + ->queueFromThread(m_pConfig->getValueString( |
704 | + ConfigKey("[VinylControl]","enabled_ch2")).toDouble()); |
705 | + ControlObject::getControl(ConfigKey("[Channel1]","vinylcontrol_mode")) |
706 | + ->queueFromThread(m_pConfig->getValueString( |
707 | + ConfigKey("[VinylControl]","mode")).toDouble()); |
708 | + ControlObject::getControl(ConfigKey("[Channel2]","vinylcontrol_mode")) |
709 | + ->queueFromThread(m_pConfig->getValueString( |
710 | + ConfigKey("[VinylControl]","mode")).toDouble()); |
711 | + ControlObject::getControl(ConfigKey("[Channel1]","vinylcontrol_cueing")) |
712 | + ->queueFromThread(m_pConfig->getValueString( |
713 | + ConfigKey("[VinylControl]","cueing_ch1")).toDouble()); |
714 | + ControlObject::getControl(ConfigKey("[Channel2]","vinylcontrol_cueing")) |
715 | + ->queueFromThread(m_pConfig->getValueString( |
716 | + ConfigKey("[VinylControl]","cueing_ch2")).toDouble()); |
717 | +} |
718 | + |
719 | +VinylControlManager::~VinylControlManager() { |
720 | + m_proxiesLock.lockForWrite(); |
721 | + for (int i = 0; i < m_proxies.size(); ++i) { |
722 | + if (m_proxies.at(i)) { |
723 | + delete m_proxies.at(i); |
724 | + m_proxies.replace(i, NULL); |
725 | + } |
726 | + } |
727 | + m_proxiesLock.unlock(); |
728 | + |
729 | + // xwax has a global LUT that we need to free after we've shut down our |
730 | + // vinyl control threads because it's not thread-safe. |
731 | + VinylControlXwax::freeLUTs(); |
732 | + |
733 | + // save a bunch of stuff to config |
734 | + m_pConfig->set(ConfigKey("[VinylControl]","enabled_ch1"), |
735 | + ConfigValue((int)ControlObject::getControl( |
736 | + ConfigKey("[Channel1]","vinylcontrol_enabled"))->get())); |
737 | + m_pConfig->set(ConfigKey("[VinylControl]","enabled_ch2"), |
738 | + ConfigValue((int)ControlObject::getControl( |
739 | + ConfigKey("[Channel2]","vinylcontrol_enabled"))->get())); |
740 | + m_pConfig->set(ConfigKey("[VinylControl]","mode"), |
741 | + ConfigValue((int)ControlObject::getControl( |
742 | + ConfigKey("[Channel1]","vinylcontrol_mode"))->get())); |
743 | + m_pConfig->set(ConfigKey("[VinylControl]","mode"), |
744 | + ConfigValue((int)ControlObject::getControl( |
745 | + ConfigKey("[Channel2]","vinylcontrol_mode"))->get())); |
746 | + m_pConfig->set(ConfigKey("[VinylControl]","cueing_ch1"), |
747 | + ConfigValue((int)ControlObject::getControl( |
748 | + ConfigKey("[Channel1]","vinylcontrol_cueing"))->get())); |
749 | + m_pConfig->set(ConfigKey("[VinylControl]","cueing_ch2"), |
750 | + ConfigValue((int)ControlObject::getControl( |
751 | + ConfigKey("[Channel2]","vinylcontrol_cueing"))->get())); |
752 | +} |
753 | + |
754 | +void VinylControlManager::receiveBuffer(AudioInput input, |
755 | + const short *pBuffer, unsigned int nFrames) { |
756 | + Q_ASSERT(input.getType() == AudioInput::VINYLCONTROL); |
757 | + if (m_proxiesLock.tryLockForRead()) { |
758 | + Q_ASSERT(input.getIndex() < m_proxies.size()); |
759 | + VinylControlProxy *pProxy(m_proxies.at(input.getIndex())); |
760 | + Q_ASSERT(pProxy); |
761 | + pProxy->AnalyseSamples(pBuffer, nFrames); |
762 | + m_proxiesLock.unlock(); |
763 | + } |
764 | +} |
765 | + |
766 | +void VinylControlManager::onInputConnected(AudioInput input) { |
767 | + Q_ASSERT(input.getType() == AudioInput::VINYLCONTROL); |
768 | + unsigned char index = input.getIndex(); |
769 | + VinylControlProxy *pNewVC = new VinylControlProxy(m_pConfig, |
770 | + kVCProxyGroup.arg(index + 1)); |
771 | + m_proxiesLock.lockForWrite(); |
772 | + if (index < m_proxies.size()) { |
773 | + if (m_proxies.at(index)) { |
774 | + delete m_proxies.at(index); |
775 | + } |
776 | + m_proxies.replace(index, pNewVC); |
777 | + } else { |
778 | + m_proxies.resize(index + 1); |
779 | + m_proxies.replace(index, pNewVC); |
780 | + } |
781 | + m_proxiesLock.unlock(); |
782 | +} |
783 | + |
784 | +void VinylControlManager::onInputDisconnected(AudioInput input) { |
785 | + Q_ASSERT(input.getType() == AudioInput::VINYLCONTROL); |
786 | + m_proxiesLock.lockForWrite(); |
787 | + Q_ASSERT(input.getIndex() < m_proxies.size()); |
788 | + Q_ASSERT(m_proxies.at(input.getIndex())); |
789 | + |
790 | + delete m_proxies.at(input.getIndex()); |
791 | + m_proxies.replace(input.getIndex(), NULL); |
792 | + m_proxiesLock.unlock(); |
793 | +} |
794 | + |
795 | +void VinylControlManager::reloadConfig() { |
796 | + m_proxiesLock.lockForWrite(); |
797 | + for (int i = 0; i < m_proxies.size(); ++i) { |
798 | + if (!m_proxies.at(i)) continue; |
799 | + VinylControlProxy *pProxy = m_proxies.at(i); |
800 | + QString group = kVCProxyGroup.arg(i + 1); |
801 | + delete pProxy; |
802 | + pProxy = new VinylControlProxy(m_pConfig, group); |
803 | + m_proxies.replace(i, pProxy); |
804 | + } |
805 | + m_proxiesLock.unlock(); |
806 | +} |
807 | + |
808 | +QList<VinylControlProxy*> VinylControlManager::vinylControlProxies() { |
809 | + m_proxiesLock.lockForRead(); |
810 | + QList<VinylControlProxy*> list(m_proxies.toList()); |
811 | + m_proxiesLock.unlock(); |
812 | + return list; |
813 | +} |
814 | + |
815 | +bool VinylControlManager::vinylInputEnabled(int deck) { |
816 | + // a vinylcontrolproxy is only created if vinyl control is enabled for |
817 | + // a deck, so... |
818 | + m_proxiesLock.lockForRead(); |
819 | + bool ret = (deck - 1) < m_proxies.size() && m_proxies[deck-1]; |
820 | + m_proxiesLock.unlock(); |
821 | + return ret; |
822 | +} |
823 | |
824 | === added file 'mixxx/src/vinylcontrol/vinylcontrolmanager.h' |
825 | --- mixxx/src/vinylcontrol/vinylcontrolmanager.h 1970-01-01 00:00:00 +0000 |
826 | +++ mixxx/src/vinylcontrol/vinylcontrolmanager.h 2011-04-18 08:02:27 +0000 |
827 | @@ -0,0 +1,36 @@ |
828 | +/** |
829 | + * @file vinylcontrolmanager.h |
830 | + * @author Bill Good <bkgood@gmail.com> |
831 | + * @date April 15, 2011 |
832 | + */ |
833 | + |
834 | +#ifndef VINYLCONTROLMANAGER_H |
835 | +#define VINYLCONTROLMANAGER_H |
836 | + |
837 | +#include <QtCore> |
838 | +#include "soundmanagerutil.h" |
839 | +#include "configobject.h" |
840 | + |
841 | +class VinylControlProxy; |
842 | +class SoundManager; |
843 | + |
844 | +class VinylControlManager : public QObject, public AudioDestination { |
845 | + Q_OBJECT; |
846 | + public: |
847 | + VinylControlManager(QObject *pParent, ConfigObject<ConfigValue> *pConfig); |
848 | + virtual ~VinylControlManager(); |
849 | + virtual void receiveBuffer(AudioInput input, const short *pBuffer, unsigned int nFrames); |
850 | + virtual void onInputConnected(AudioInput input); |
851 | + virtual void onInputDisconnected(AudioInput input); |
852 | + QList<VinylControlProxy*> vinylControlProxies(); |
853 | + bool vinylInputEnabled(int deck); |
854 | + public slots: |
855 | + void reloadConfig(); |
856 | + signals: |
857 | + private: |
858 | + ConfigObject<ConfigValue> *m_pConfig; |
859 | + QVector<VinylControlProxy*> m_proxies; |
860 | + QReadWriteLock m_proxiesLock; |
861 | +}; |
862 | + |
863 | +#endif // VINYLCONTROLMANAGER_H |
864 | |
865 | === renamed file 'mixxx/src/vinylcontrolproxy.cpp' => 'mixxx/src/vinylcontrol/vinylcontrolproxy.cpp' |
866 | --- mixxx/src/vinylcontrolproxy.cpp 2011-04-15 07:18:41 +0000 |
867 | +++ mixxx/src/vinylcontrol/vinylcontrolproxy.cpp 2011-04-18 08:02:27 +0000 |
868 | @@ -8,7 +8,7 @@ |
869 | |
870 | //IVinylControl *VinylControlProxy::m_pVinylControl = 0; |
871 | |
872 | -VinylControlProxy::VinylControlProxy(ConfigObject<ConfigValue> * pConfig, const char * _group) : VinylControl(pConfig, _group) |
873 | +VinylControlProxy::VinylControlProxy(ConfigObject<ConfigValue> * pConfig, QString group) : VinylControl(pConfig, group) |
874 | { |
875 | QList<QString> xwax_timecodes; |
876 | QList<QString> scratchlib_timecodes; |
877 | @@ -20,20 +20,20 @@ |
878 | xwax_timecodes.push_back(MIXXX_VINYL_TRAKTORSCRATCHSIDEB); |
879 | |
880 | //Figure out which type of timecoded vinyl we're using. |
881 | - strVinylType = m_pConfig->getValueString(ConfigKey(_group,"vinylcontrol_vinyl_type")); |
882 | + strVinylType = m_pConfig->getValueString(ConfigKey(m_group,"vinylcontrol_vinyl_type")); |
883 | |
884 | //Create the VinylControl object that matches the type of vinyl selected in the prefs... |
885 | if (xwax_timecodes.contains(strVinylType)) |
886 | { |
887 | - m_pVinylControl = new VinylControlXwax(pConfig, _group); |
888 | + m_pVinylControl = new VinylControlXwax(pConfig, m_group); |
889 | } |
890 | else |
891 | { |
892 | qDebug() << "VinylControlProxy: Unknown vinyl type " << strVinylType; |
893 | qDebug() << "Defaulting to Serato..."; |
894 | strVinylType = MIXXX_VINYL_SERATOCV02VINYLSIDEA; |
895 | - pConfig->set(ConfigKey(_group,"vinylcontrol_vinyl_type"), ConfigValue(MIXXX_VINYL_SERATOCV02VINYLSIDEA)); |
896 | - m_pVinylControl = new VinylControlXwax(pConfig, _group); |
897 | + pConfig->set(ConfigKey(m_group,"vinylcontrol_vinyl_type"), ConfigValue(MIXXX_VINYL_SERATOCV02VINYLSIDEA)); |
898 | + m_pVinylControl = new VinylControlXwax(pConfig, m_group); |
899 | } |
900 | } |
901 | |
902 | @@ -116,12 +116,3 @@ |
903 | return -1.0; |
904 | } |
905 | |
906 | -void VinylControlProxy::receiveBuffer(AudioInput input, const short* pBuffer, |
907 | - unsigned int iNumFrames) { |
908 | - if (input.getType() != AudioPath::VINYLCONTROL || |
909 | - QString("[Channel%1]").arg(input.getIndex()+1) != this->group) { |
910 | - qDebug() << "WARNING: vinyl control proxy got a buffer for an " |
911 | - "AudioInput it doesn't own"; |
912 | - } |
913 | - AnalyseSamples(pBuffer, iNumFrames); |
914 | -} |
915 | |
916 | === renamed file 'mixxx/src/vinylcontrolproxy.h' => 'mixxx/src/vinylcontrol/vinylcontrolproxy.h' |
917 | --- mixxx/src/vinylcontrolproxy.h 2011-04-16 21:07:10 +0000 |
918 | +++ mixxx/src/vinylcontrol/vinylcontrolproxy.h 2011-04-18 08:02:27 +0000 |
919 | @@ -4,12 +4,10 @@ |
920 | #include "vinylcontrol.h" |
921 | #include "soundmanagerutil.h" |
922 | |
923 | -//#include "vinylcontrolscratchlib.h" |
924 | - |
925 | -class VinylControlProxy : public VinylControl, public AudioDestination |
926 | +class VinylControlProxy : public VinylControl |
927 | { |
928 | public: |
929 | - VinylControlProxy(ConfigObject<ConfigValue> *pConfig, const char *_group); |
930 | + VinylControlProxy(ConfigObject<ConfigValue> *pConfig, QString group); |
931 | ~VinylControlProxy(); |
932 | bool isEnabled(); |
933 | void AnalyseSamples(const short* samples, size_t size); |
934 | @@ -19,7 +17,6 @@ |
935 | float getTimecodeQuality(); |
936 | unsigned char* getScopeBytemap(); |
937 | float getAngle(); |
938 | - virtual void receiveBuffer(AudioInput input, const short *pBuffer, unsigned int iNumFrames); |
939 | protected: |
940 | VinylControl* m_pVinylControl; //Pointer to active VinylControl object |
941 | }; |
942 | |
943 | === renamed file 'mixxx/src/vinylcontrolsignalwidget.cpp' => 'mixxx/src/vinylcontrol/vinylcontrolsignalwidget.cpp' |
944 | === renamed file 'mixxx/src/vinylcontrolsignalwidget.h' => 'mixxx/src/vinylcontrol/vinylcontrolsignalwidget.h' |
945 | === renamed file 'mixxx/src/vinylcontrolxwax.cpp' => 'mixxx/src/vinylcontrol/vinylcontrolxwax.cpp' |
946 | --- mixxx/src/vinylcontrolxwax.cpp 2011-04-15 07:08:16 +0000 |
947 | +++ mixxx/src/vinylcontrol/vinylcontrolxwax.cpp 2011-04-18 08:02:27 +0000 |
948 | @@ -37,7 +37,7 @@ |
949 | bool VinylControlXwax::m_bLUTInitialized = false; |
950 | QMutex VinylControlXwax::s_xwaxLUTMutex; |
951 | |
952 | -VinylControlXwax::VinylControlXwax(ConfigObject<ConfigValue> * pConfig, const char * _group) : VinylControl(pConfig, _group) |
953 | +VinylControlXwax::VinylControlXwax(ConfigObject<ConfigValue> * pConfig, QString group) : VinylControl(pConfig, group) |
954 | { |
955 | dOldPos = 0.0f; |
956 | m_samples = NULL; |
957 | @@ -380,7 +380,7 @@ |
958 | { |
959 | qDebug() << "discontinuing select mode, selecting track"; |
960 | if (trackLoader == NULL) |
961 | - trackLoader = new ControlObjectThread(ControlObject::getControl(ConfigKey(group,"LoadSelectedTrack"))); |
962 | + trackLoader = new ControlObjectThread(ControlObject::getControl(ConfigKey(m_group,"LoadSelectedTrack"))); |
963 | |
964 | if (!trackLoader) |
965 | qDebug() << "ERROR: couldn't get track loading object?"; |
966 | |
967 | === renamed file 'mixxx/src/vinylcontrolxwax.h' => 'mixxx/src/vinylcontrol/vinylcontrolxwax.h' |
968 | --- mixxx/src/vinylcontrolxwax.h 2011-04-16 22:32:31 +0000 |
969 | +++ mixxx/src/vinylcontrol/vinylcontrolxwax.h 2011-04-18 08:02:27 +0000 |
970 | @@ -23,7 +23,7 @@ |
971 | class VinylControlXwax : public VinylControl |
972 | { |
973 | public: |
974 | - VinylControlXwax(ConfigObject<ConfigValue> *pConfig, const char *_group); |
975 | + VinylControlXwax(ConfigObject<ConfigValue> *pConfig, QString group); |
976 | virtual ~VinylControlXwax(); |
977 | void ToggleVinylControl(bool enable); |
978 | bool isEnabled(); |
Hey Bill,
Looking good -- here are my comments:
* In VinylControlMan ager, it's a little sketchy to me that SoundManager is passed in and that it's used to scan through its list of enabled inputs -- seems like VCManager shouldn't know those details of SoundManager. Would it be possible to determine which VC decks were enabled by just keeping track of onInputConnect/ onInputDisconne ct calls? Also naming the parameter 'deck' is a little misleading since one turntable can control multiple decks (or will in the future?) Since you're checking for a matching AudioInput index, doesn't this just test whether the N'th VC input is enabled? Anyway I would just replace this with a QSet<AudioInput> that you add to onInputConnect and remove from onInputDisconnect, that way you can just make this test whether an appropriate AudioInput is in the set.
* I don't think I understand how QSemaphore protects m_proxies in this case. QList is not thread safe so two threads should never access it at once -- this includes using QList::at, so all accesses to the list should be guarded by a monolithic QMutex (yea .. it sucks). I would use a QMutex and then make sure to unlock it the second you get the VCProxy that you need from the list (or in the case of creating the VC proxy, create it, then lock and insert it and unlock).
Otherwise everything seems fine to me -- we should have someone test it out first to verify that it actually works ;)