Merge lp:~mattmik/mixxx/features_passthrough into lp:~mixxxdevelopers/mixxx/trunk

Proposed by Matthew Mikolay
Status: Needs review
Proposed branch: lp:~mattmik/mixxx/features_passthrough
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 609 lines (+239/-101)
12 files modified
mixxx/build/depends.py (+0/-1)
mixxx/res/skins/Deere1280x800-WXGA/skin.xml (+1/-1)
mixxx/src/basetrackplayer.cpp (+9/-5)
mixxx/src/basetrackplayer.h (+4/-0)
mixxx/src/engine/enginedeck.cpp (+133/-8)
mixxx/src/engine/enginedeck.h (+34/-2)
mixxx/src/engine/enginemaster.cpp (+2/-0)
mixxx/src/engine/enginepassthrough.h (+0/-51)
mixxx/src/engine/enginepregain.cpp (+18/-22)
mixxx/src/engine/enginepregain.h (+2/-1)
mixxx/src/mixxx.cpp (+17/-4)
mixxx/src/soundmanager.cpp (+19/-6)
To merge this branch: bzr merge lp:~mattmik/mixxx/features_passthrough
Reviewer Review Type Date Requested Status
RJ Skerry-Ryan Approve
Review via email: mp+109726@code.launchpad.net

Description of the change

Passthrough has been implemented through the EngineDeck class. This required some modifications to additional classes.

Passthrough for a certain deck is enabled using a ControlPushButton linked to the ConfigKey "passthrough_enabled". Passthrough uses the vinyl inputs for a deck specified in the Preferences dialog.

Please ignore all modifications to the EnginePassthrough class, as passthrough using this class is deprecated.

If there are any questions, please contact me!

To post a comment you must log in.
3255. By Daniel Schürmann

merged with lp:mixxx/1.10

3256. By RJ Skerry-Ryan

Add patch from Max Linke for Bug #1002330 to fix some more star-rating issues.

3257. By RJ Skerry-Ryan

Merging bkgood's lp:~mixxxdevelopers/mixxx/fixes_midi_burnout branch to lp:mixxx.

3258. By RJ Skerry-Ryan

On Linux, use a 5ms polling interval instead of 1ms. Workaround for Bug #990992 until we have a better fix.

3259. By jus

ic_template_keyboard_mapping_sheet.svg re-drawn and arranged more clearly. Makes future maintainance easier if keyboard shortcuts change.

3260. By Daniel Schürmann

set default recording folder to QDesktopServices::MusicLocation

3261. By RJ Skerry-Ryan

Add Max Linke's patch to add a 'Hidden Tracks' view to Mixxx and change default terminology from 'remove' to 'hide'. Fixes Bug #949828

3262. By RJ Skerry-Ryan

Remove redundant rollback since ScopedTransaction auto-rollbacks when it leaves scope w/o being committed.

3263. By RJ Skerry-Ryan

For some reason bzr patch did not add hiddentablemodel.cpp from Max's patch.

3264. By RJ Skerry-Ryan

Not my day today .. add hiddentablemodel.h

3265. By RJ Skerry-Ryan

Add mutil's patch to close the preference dialog when quitting Mixxx. Fixes Bug #1007958

3266. By RJ Skerry-Ryan

Add Max Linke's patch to fix external drag and drop. Fixes Bug #1014842

3267. By RJ Skerry-Ryan

Add patch from daschuer and mutil that warns the user if the skin does not match their screen resolution. Fixes Bug #1011002

3268. By RJ Skerry-Ryan

Add Numark OMNI control preset from Baxter.

3269. By RJ Skerry-Ryan

Re-enable bitrate column and allow bitrate: search queries. Fixes Bug #1008872

3270. By RJ Skerry-Ryan

When a CO does not exist, make it a toggle ControlPushButton by default instead of a ControlObject. Fixes Bug #1009547

3271. By RJ Skerry-Ryan

Add missing warning icon.

3272. By jus

Add new preferences icon for controllers & update icon template accordingly, fixes lp:992813

3273. By RJ Skerry-Ryan

Add Max Linke's patch to clean up cues, analyses, crates and playlists on purge of tracks from the library. Fixes Bug #949828

3274. By RJ Skerry-Ryan

Add patch from daschuer to improve schema upgrade error messages. Fixes Bug #963408

3275. By RJ Skerry-Ryan

Version bump to 1.11.0 beta1

3276. By RJ Skerry-Ryan

Add 1.11.0~beta1-0ubuntu1 to Debian changelog.

3277. By RJ Skerry-Ryan

Add Numark N4 preset from dj.stuartbrand.

3278. By RJ Skerry-Ryan

Merging lp:~hile/mixxx/forumlinks into lp:mixxx/1.11

3279. By RJ Skerry-Ryan

Add support for displaying wiki links from presets in the controller preferences dialog.

3280. By RJ Skerry-Ryan

Minor preset cleanups.

3281. By RJ Skerry-Ryan

Potentially fix PPA upload by supporting an explicit ubuntu_ppa SConscript command and allowing ubuntu_dist to be a comma separated list of distros to upload for. This allows us to have one original source tarball for all the individual Ubuntu versions we support.

3282. By RJ Skerry-Ryan

Merging from lp:mixxx

3283. By RJ Skerry-Ryan

Hack the mixxx_version when we're doing a PPA upload by appending -bzrXXXX.

3284. By RJ Skerry-Ryan

Merging from lp:mixxx/1.11

3285. By RJ Skerry-Ryan

Merging from lp:mixxx/1.11

3286. By Daniel Schürmann

Merging from lp:mixxx/1.11

3287. By RJ Skerry-Ryan

Merging from lp:mixxx/1.11

3288. By Daniel Schürmann

merged with lp:mixxx/1.11

3289. By Daniel Schürmann

merged with lp:mixxx/1.11

3290. By RJ Skerry-Ryan

Merging from lp:mixxx/1.11

3291. By Daniel Schürmann

merged with lp:mixxx/1.11

3292. By Matthew Mikolay

Merging from lp:mixxx/1.11

3293. By Matthew Mikolay

Merging from lp:mixxx/1.11

3294. By Matthew Mikolay

Merging from lp:mixxx

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

Thanks Matt -- Owen merged this a few days ago.

review: Approve

Unmerged revisions

3294. By Matthew Mikolay

Merging from lp:mixxx

3293. By Matthew Mikolay

Merging from lp:mixxx/1.11

3292. By Matthew Mikolay

Merging from lp:mixxx/1.11

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mixxx/build/depends.py'
2--- mixxx/build/depends.py 2012-09-05 06:24:48 +0000
3+++ mixxx/build/depends.py 2012-10-22 14:36:20 +0000
4@@ -458,7 +458,6 @@
5 "engine/enginexfader.cpp",
6 "engine/enginemicrophone.cpp",
7 "engine/enginedeck.cpp",
8- "engine/enginepassthrough.cpp",
9
10 "engine/enginecontrol.cpp",
11 "engine/ratecontrol.cpp",
12
13=== modified file 'mixxx/res/skins/Deere1280x800-WXGA/skin.xml'
14--- mixxx/res/skins/Deere1280x800-WXGA/skin.xml 2012-09-09 09:25:58 +0000
15+++ mixxx/res/skins/Deere1280x800-WXGA/skin.xml 2012-10-22 14:36:20 +0000
16@@ -3873,7 +3873,7 @@
17
18 <!--
19 **********************************************
20- Button - Quantize
21+ Button - Quantize <ConfigKey>[Channel1],quantize</ConfigKey>
22 **********************************************
23 -->
24 <PushButton>
25
26=== modified file 'mixxx/src/basetrackplayer.cpp'
27--- mixxx/src/basetrackplayer.cpp 2012-06-25 00:02:38 +0000
28+++ mixxx/src/basetrackplayer.cpp 2012-10-22 14:36:20 +0000
29@@ -9,7 +9,6 @@
30 #include "controlpotmeter.h"
31 #include "trackinfoobject.h"
32 #include "engine/enginebuffer.h"
33-#include "engine/enginedeck.h"
34 #include "engine/enginemaster.h"
35 #include "soundsourceproxy.h"
36 #include "engine/cuecontrol.h"
37@@ -34,10 +33,10 @@
38 // pSafeGroupName is leaked. It's like 5 bytes so whatever.
39 const char* pSafeGroupName = strdup(getGroup().toAscii().constData());
40
41- EngineDeck* pChannel = new EngineDeck(pSafeGroupName,
42- pConfig, defaultOrientation);
43- EngineBuffer* pEngineBuffer = pChannel->getEngineBuffer();
44- pMixingEngine->addChannel(pChannel);
45+ m_pChannel = new EngineDeck(pSafeGroupName, pConfig, defaultOrientation);
46+
47+ EngineBuffer* pEngineBuffer = m_pChannel->getEngineBuffer();
48+ pMixingEngine->addChannel(m_pChannel);
49
50 ClockControl* pClockControl = new ClockControl(pSafeGroupName, pConfig);
51 pEngineBuffer->addControl(pClockControl);
52@@ -246,3 +245,8 @@
53 TrackPointer BaseTrackPlayer::getLoadedTrack() const {
54 return m_pLoadedTrack;
55 }
56+
57+EngineDeck* BaseTrackPlayer::getEngineDeck() const {
58+ return m_pChannel;
59+}
60+
61
62=== modified file 'mixxx/src/basetrackplayer.h'
63--- mixxx/src/basetrackplayer.h 2012-04-25 04:43:42 +0000
64+++ mixxx/src/basetrackplayer.h 2012-10-22 14:36:20 +0000
65@@ -6,6 +6,7 @@
66 #include "baseplayer.h"
67 #include "analyserqueue.h"
68 #include "engine/enginechannel.h"
69+#include "engine/enginedeck.h"
70
71 class EngineMaster;
72 class ControlObject;
73@@ -25,6 +26,7 @@
74
75 AnalyserQueue* getAnalyserQueue() const;
76 TrackPointer getLoadedTrack() const;
77+ EngineDeck* getEngineDeck() const;
78
79 public slots:
80 void slotLoadTrack(TrackPointer track, bool bStartFromEndPos=false);
81@@ -53,6 +55,8 @@
82 ControlObject* m_pDuration;
83 ControlObjectThreadMain* m_pBPM;
84 ControlObjectThreadMain* m_pReplayGain;
85+
86+ EngineDeck* m_pChannel;
87 };
88
89
90
91=== modified file 'mixxx/src/engine/enginedeck.cpp'
92--- mixxx/src/engine/enginedeck.cpp 2011-06-11 22:55:41 +0000
93+++ mixxx/src/engine/enginedeck.cpp 2012-10-22 14:36:20 +0000
94@@ -26,11 +26,30 @@
95 #include "enginevumeter.h"
96 #include "enginefilteriir.h"
97
98+#include "sampleutil.h"
99+
100 EngineDeck::EngineDeck(const char* group,
101 ConfigObject<ConfigValue>* pConfig,
102 EngineChannel::ChannelOrientation defaultOrientation)
103 : EngineChannel(group, defaultOrientation),
104- m_pConfig(pConfig) {
105+ m_pConfig(pConfig),
106+ m_pPassing(new ControlPushButton(ConfigKey(group, "passthrough_enabled"))),
107+ // Need a +1 here because the CircularBuffer only allows its size-1
108+ // items to be held at once (it keeps a blank spot open persistently)
109+ m_sampleBuffer(MAX_BUFFER_LEN+1) {
110+
111+ // Set up passthrough utilities and fields
112+ m_pPassing->setButtonMode(ControlPushButton::TOGGLE);
113+ m_pConversionBuffer = SampleUtil::alloc(MAX_BUFFER_LEN);
114+ m_bPassthroughIsActive = false;
115+ m_bPassthroughWasActive = false;
116+
117+ // Set up passthrough toggle button
118+ connect(m_pPassing, SIGNAL(valueChanged(double)),
119+ this, SLOT(slotPassingToggle(double)),
120+ Qt::DirectConnection);
121+
122+ // Set up additional engines
123 m_pPregain = new EnginePregain(group);
124 m_pFilter = new EngineFilterBlock(group);
125 m_pFlanger = new EngineFlanger(group);
126@@ -41,6 +60,9 @@
127 }
128
129 EngineDeck::~EngineDeck() {
130+ SampleUtil::free(m_pConversionBuffer);
131+ delete m_pPassing;
132+
133 delete m_pBuffer;
134 delete m_pClipping;
135 delete m_pFilter;
136@@ -50,11 +72,40 @@
137 delete m_pVUMeter;
138 }
139
140-void EngineDeck::process(const CSAMPLE*, const CSAMPLE * pOut, const int iBufferSize) {
141- // Process the raw audio
142- m_pBuffer->process(0, pOut, iBufferSize);
143- // Emulate vinyl sounds
144- m_pVinylSoundEmu->process(pOut, pOut, iBufferSize);
145+void EngineDeck::process(const CSAMPLE*, const CSAMPLE * pOutput, const int iBufferSize) {
146+
147+ CSAMPLE* pOut = const_cast<CSAMPLE*>(pOutput);
148+
149+ // Feed the incoming audio through if passthrough is active
150+ if (isPassthroughActive()) {
151+ int samplesRead = m_sampleBuffer.read(pOut, iBufferSize);
152+ if (samplesRead < iBufferSize) {
153+ // Buffer underflow. There aren't getting samples fast enough. This
154+ // shouldn't happen since PortAudio should feed us samples just as fast
155+ // as we consume them, right?
156+ Q_ASSERT(false);
157+ }
158+
159+ m_bPassthroughWasActive = true;
160+
161+ } else {
162+
163+ // If passthrough is no longer enabled, zero out the buffer
164+ if (m_bPassthroughWasActive) {
165+ SampleUtil::applyGain(pOut, 0.0, iBufferSize);
166+ m_sampleBuffer.skip(iBufferSize);
167+ m_bPassthroughWasActive = false;
168+ return;
169+ }
170+
171+ // Process the raw audio
172+ m_pBuffer->process(0, pOut, iBufferSize);
173+ // Emulate vinyl sounds
174+ m_pVinylSoundEmu->process(pOut, pOut, iBufferSize);
175+
176+ m_bPassthroughWasActive = false;
177+ }
178+
179 // Apply pregain
180 m_pPregain->process(pOut, pOut, iBufferSize);
181 // Filter the channel with EQs
182@@ -72,5 +123,79 @@
183 }
184
185 bool EngineDeck::isActive() {
186- return m_pBuffer->isTrackLoaded();
187-}
188+ if (m_bPassthroughWasActive && !m_bPassthroughIsActive) {
189+ return true;
190+ }
191+
192+ return (m_pBuffer->isTrackLoaded() || isPassthroughActive());
193+}
194+
195+void EngineDeck::receiveBuffer(AudioInput input, const short* pBuffer, unsigned int nFrames) {
196+
197+ // Skip receiving audio input if passthrough is not active
198+ if (!m_bPassthroughIsActive) {
199+ return;
200+ }
201+
202+ if (input.getType() != AudioPath::VINYLCONTROL) {
203+ // This is an error!
204+ qDebug() << "WARNING: EngineDeck receieved an AudioInput for a non-vinylcontrol type!";
205+ return;
206+ }
207+
208+ // Use the conversion buffer to both convert from short and double into
209+ // stereo.
210+
211+ // Check that the number of mono samples doesn't exceed MAX_BUFFER_LEN/2
212+ // because thats our conversion buffer size.
213+ if (nFrames > MAX_BUFFER_LEN / 2) {
214+ qDebug() << "WARNING: Dropping passthrough samples because the input buffer is too large.";
215+ nFrames = MAX_BUFFER_LEN / 2;
216+ }
217+
218+ // There isn't a suitable SampleUtil method that can do mono->stereo and
219+ // short->float in one pass.
220+ // SampleUtil::convert(m_pConversionBuffer, pBuffer, iNumSamples);
221+ SampleUtil::convert(m_pConversionBuffer, pBuffer, nFrames*2);
222+
223+ // TODO(rryan) (or bkgood?) do we need to verify the input is the one we asked for? Oh well.
224+ unsigned int samplesWritten = m_sampleBuffer.write(m_pConversionBuffer, nFrames*2);
225+ if (samplesWritten < nFrames*2) {
226+ // Buffer overflow. We aren't processing samples fast enough. This
227+ // shouldn't happen since the deck spits out samples just as fast as they
228+ // come in, right?
229+ Q_ASSERT(false);
230+ }
231+}
232+
233+void EngineDeck::onInputConnected(AudioInput input) {
234+ if (input.getType() != AudioPath::VINYLCONTROL) {
235+ // This is an error!
236+ qDebug() << "WARNING: EngineDeck connected to AudioInput for a non-vinylcontrol type!";
237+ return;
238+ }
239+ m_sampleBuffer.clear();
240+}
241+
242+void EngineDeck::onInputDisconnected(AudioInput input) {
243+ if (input.getType() != AudioPath::VINYLCONTROL) {
244+ // This is an error!
245+ qDebug() << "WARNING: EngineDeck connected to AudioInput for a non-vinylcontrol type!";
246+ return;
247+ }
248+ m_sampleBuffer.clear();
249+}
250+
251+bool EngineDeck::isPassthroughActive() {
252+ return (m_bPassthroughIsActive && !m_sampleBuffer.isEmpty());
253+}
254+
255+void EngineDeck::slotPassingToggle(double v) {
256+ if (v > 0) {
257+ m_bPassthroughIsActive = true;
258+ }
259+ else {
260+ m_bPassthroughIsActive = false;
261+ }
262+}
263+
264
265=== modified file 'mixxx/src/engine/enginedeck.h'
266--- mixxx/src/engine/enginedeck.h 2011-04-01 04:51:24 +0000
267+++ mixxx/src/engine/enginedeck.h 2012-10-22 14:36:20 +0000
268@@ -18,10 +18,14 @@
269 #ifndef ENGINEDECK_H
270 #define ENGINEDECK_H
271
272+#include "circularbuffer.h"
273+#include "controlpushbutton.h"
274 #include "engine/engineobject.h"
275 #include "engine/enginechannel.h"
276 #include "configobject.h"
277
278+#include "soundmanagerutil.h"
279+
280 class EngineBuffer;
281 class EnginePregain;
282 class EngineBuffer;
283@@ -32,19 +36,40 @@
284 class EngineVinylSoundEmu;
285 class ControlPushButton;
286
287-class EngineDeck : public EngineChannel {
288+class EngineDeck : public EngineChannel, public AudioDestination {
289 Q_OBJECT
290 public:
291 EngineDeck(const char *group, ConfigObject<ConfigValue>* pConfig,
292 EngineChannel::ChannelOrientation defaultOrientation = CENTER);
293 virtual ~EngineDeck();
294
295- virtual void process(const CSAMPLE *pIn, const CSAMPLE *pOut, const int iBufferSize);
296+ virtual void process(const CSAMPLE *pInput, const CSAMPLE *pOutput, const int iBufferSize);
297
298 // TODO(XXX) This hack needs to be removed.
299 virtual EngineBuffer* getEngineBuffer();
300
301 virtual bool isActive();
302+
303+ // Begin vinyl passthrough methods
304+
305+ // This is called by SoundManager whenever there are new samples from the
306+ // deck to be processed
307+ virtual void receiveBuffer(AudioInput input, const short *pBuffer, unsigned int nFrames);
308+
309+ // Called by SoundManager whenever the passthrough input is connected to a
310+ // soundcard input.
311+ virtual void onInputConnected(AudioInput input);
312+
313+ // Called by SoundManager whenever the passthrough input is disconnected from
314+ // a soundcard input.
315+ virtual void onInputDisconnected(AudioInput input);
316+
317+ // Return whether or not passthrough is active
318+ bool isPassthroughActive();
319+
320+ public slots:
321+ void slotPassingToggle(double v);
322+
323 private:
324 ConfigObject<ConfigValue>* m_pConfig;
325 EngineBuffer* m_pBuffer;
326@@ -54,6 +79,13 @@
327 EnginePregain* m_pPregain;
328 EngineVinylSoundEmu* m_pVinylSoundEmu;
329 EngineVuMeter* m_pVUMeter;
330+
331+ // Begin vinyl passthrough fields
332+ ControlPushButton* m_pPassing;
333+ CSAMPLE* m_pConversionBuffer;
334+ CircularBuffer<CSAMPLE> m_sampleBuffer;
335+ bool m_bPassthroughIsActive;
336+ bool m_bPassthroughWasActive;
337 };
338
339 #endif
340
341=== modified file 'mixxx/src/engine/enginemaster.cpp'
342--- mixxx/src/engine/enginemaster.cpp 2012-09-23 20:26:44 +0000
343+++ mixxx/src/engine/enginemaster.cpp 2012-10-22 14:36:20 +0000
344@@ -203,6 +203,8 @@
345 }
346 }
347
348+ // qDebug() << "Total active channels: " << totalActive;
349+
350 if (totalActive == 0) {
351 SampleUtil::applyGain(pOutput, 0.0f, iBufferSize);
352 } else if (totalActive == 1) {
353
354=== removed file 'mixxx/src/engine/enginepassthrough.h'
355--- mixxx/src/engine/enginepassthrough.h 2011-04-08 08:27:29 +0000
356+++ mixxx/src/engine/enginepassthrough.h 1970-01-01 00:00:00 +0000
357@@ -1,51 +0,0 @@
358-// enginepassthrough.h
359-// created 4/8/2011 by Bill Good (bkgood@gmail.com)
360-// unapologetically copied from enginemicrophone.h from RJ
361-
362-#ifndef ENGINEPASSTHROUGH_H
363-#define ENGINEPASSTHROUGH_H
364-
365-#include "circularbuffer.h"
366-#include "controlpushbutton.h"
367-#include "engine/enginechannel.h"
368-#include "engine/engineclipping.h"
369-#include "engine/enginevumeter.h"
370-#include "soundmanagerutil.h"
371-
372-// EnginePassthrough is an EngineChannel that implements a mixing source whose
373-// samples are fed directly from the SoundManager
374-class EnginePassthrough : public EngineChannel, public AudioDestination {
375- Q_OBJECT
376- public:
377- EnginePassthrough(const char *pGroup);
378- virtual ~EnginePassthrough();
379-
380- bool isActive();
381- bool isPFL();
382- bool isMaster();
383-
384- // Called by EngineMaster whenever is requesting a new buffer of audio.
385- virtual void process(const CSAMPLE *pInput, const CSAMPLE *pOutput, const int iBufferSize);
386-
387- // This is called by SoundManager whenever there are new samples from the
388- // deck to be processed
389- virtual void receiveBuffer(AudioInput input, const short *pBuffer, unsigned int nFrames);
390-
391- // Called by SoundManager whenever the passthrough input is connected to a
392- // soundcard input.
393- virtual void onInputConnected(AudioInput input);
394-
395- // Called by SoundManager whenever the passthrough input is disconnected from
396- // a soundcard input.
397- virtual void onInputDisconnected(AudioInput input);
398-
399- private:
400- EngineClipping m_clipping;
401- EngineVuMeter m_vuMeter;
402- ControlObject *m_pEnabled;
403- ControlPushButton *m_pPassing;
404- CSAMPLE *m_pConversionBuffer;
405- CircularBuffer<CSAMPLE> m_sampleBuffer;
406-};
407-
408-#endif /* ENGINEPASSTHROUGH_H */
409
410=== modified file 'mixxx/src/engine/enginepregain.cpp'
411--- mixxx/src/engine/enginepregain.cpp 2012-08-10 23:57:22 +0000
412+++ mixxx/src/engine/enginepregain.cpp 2012-10-22 14:36:20 +0000
413@@ -38,6 +38,7 @@
414 //Replay Gain things
415 m_pControlReplayGain = new ControlObject(ConfigKey(group, "replaygain"));
416 m_pTotalGain = new ControlObject(ConfigKey(group, "total_gain"));
417+ m_pPassthroughEnabled = ControlObject::getControl(ConfigKey(group, "passthrough_enabled"));
418
419 if (s_pReplayGainBoost == NULL) {
420 s_pReplayGainBoost = new ControlPotmeter(ConfigKey("[ReplayGain]", "InitialReplayGainBoost"),0., 15.);
421@@ -72,58 +73,53 @@
422 float fGain = potmeterPregain->get();
423 float fReplayGain = m_pControlReplayGain->get();
424 m_fReplayGainCorrection=1;
425+ float fPassing = m_pPassthroughEnabled->get();
426 // TODO(XXX) Why do we do this? Removing it results in clipping at unity
427 // gain so I think it was trying to compensate for some issue when we added
428 // replaygain but even at unity gain (no RG) we are clipping. rryan 5/2012
429 fGain = fGain/2;
430- if(fReplayGain*fEnableReplayGain != 0)
431- {
432+
433+ // Override replaygain value if passing through
434+ if (fPassing == 0.0) {
435+ fReplayGain = 1.0;
436+ }
437+
438+ else if (fReplayGain*fEnableReplayGain != 0) {
439 // Here is the point, when ReplayGain Analyser takes its action, suggested gain changes from 0 to a nonzero value
440 // We want to smoothly fade to this last.
441 // Anyway we have some the problem that code cannot block the full process for one second.
442 // So we need to alter gain each time ::process is called.
443+ if (m_bSmoothFade) { // This means that a ReplayGain value has been calculated after the track has been loaded
444
445- if(m_bSmoothFade)//This means that a ReplayGain value has been calculated after the track has been loaded
446- {
447- if(m_fClock==0)
448+ if (m_fClock==0) {
449 m_fClock=clock();
450+ }
451 m_fSumClock += (float)((clock()-m_fClock)/CLOCKS_PER_SEC);
452 m_fClock=clock();
453- if(m_fSumClock<1)
454- {
455+ if (m_fSumClock<1) {
456 //Fade smoothly
457-
458 m_fReplayGainCorrection=(1-m_fSumClock)+(m_fSumClock)*fReplayGain*pow(10, fReplayGainBoost/20);
459-
460 }
461- else
462- {
463+ else {
464 m_bSmoothFade = false;
465 }
466 }
467- else
468- {
469+ else {
470 //Passing a user defined boost
471 m_fReplayGainCorrection=fReplayGain*pow(10, fReplayGainBoost/20);
472 }
473 }
474- else
475- {
476+ else {
477 // If track has not ReplayGain value and ReplayGain is enabled
478 // we prepare for smoothfading to ReplayGain suggested gain
479- if(fEnableReplayGain != 0)
480- {
481+ if(fEnableReplayGain != 0) {
482 m_bSmoothFade=true;
483 m_fClock=0;
484 m_fSumClock=0;
485 }
486 }
487
488- // Clamp gain to within [0, 10.0] to prevent insane gains. This can happen
489- // (some corrupt files get really high replay gain values).
490- // 10 allows a maximum replay Gain Boost * calculated replay gain of ~2
491- fGain = fGain * math_max(0.0, math_min(10.0, m_fReplayGainCorrection));
492-
493+ fGain = fGain*m_fReplayGainCorrection;
494 m_pTotalGain->set(fGain);
495
496 //qDebug()<<"Clock"<<(float)clock()/CLOCKS_PER_SEC;
497
498=== modified file 'mixxx/src/engine/enginepregain.h'
499--- mixxx/src/engine/enginepregain.h 2012-07-22 09:31:52 +0000
500+++ mixxx/src/engine/enginepregain.h 2012-10-22 14:36:20 +0000
501@@ -35,7 +35,8 @@
502 private:
503 ControlLogpotmeter *potmeterPregain;
504 ControlObject *m_pTotalGain;
505- ControlObject *m_pControlReplayGain;
506+ ControlObject* m_pControlReplayGain;
507+ ControlObject* m_pPassthroughEnabled;
508 static ControlPotmeter *s_pReplayGainBoost;
509 static ControlObject *s_pEnableReplayGain;
510 float m_fReplayGainCorrection, m_fReplayGain, m_fOldReplayGainCorrection;
511
512=== modified file 'mixxx/src/mixxx.cpp'
513--- mixxx/src/mixxx.cpp 2012-10-09 20:07:04 +0000
514+++ mixxx/src/mixxx.cpp 2012-10-22 14:36:20 +0000
515@@ -26,10 +26,12 @@
516 #include "build.h" // Generated by SCons
517 #include "controlobjectthreadmain.h"
518 #include "controlpotmeter.h"
519+#include "deck.h"
520 #include "defs_urls.h"
521 #include "defs_version.h"
522 #include "dlgabout.h"
523 #include "dlgpreferences.h"
524+#include "engine/enginedeck.h"
525 #include "engine/enginemaster.h"
526 #include "engine/enginemicrophone.h"
527 #include "library/library.h"
528@@ -309,10 +311,21 @@
529
530 // Create the player manager.
531 m_pPlayerManager = new PlayerManager(m_pConfig, m_pEngine, m_pLibrary);
532- m_pPlayerManager->addDeck();
533- m_pPlayerManager->addDeck();
534- m_pPlayerManager->addDeck();
535- m_pPlayerManager->addDeck();
536+
537+ // Set up four decks for with the player manager
538+ for (unsigned int deck = 0; deck < 4; ++deck) {
539+
540+ // Add deck to the player manager
541+ Deck* pDeck = m_pPlayerManager->addDeck();
542+
543+#ifdef __VINYLCONTROL__
544+ EngineDeck* pEngineDeck = pDeck->getEngineDeck();
545+ // Register vinyl input signal with deck for passthrough
546+ m_pSoundManager->registerInput(AudioInput(AudioInput::VINYLCONTROL, 0, deck), pEngineDeck);
547+#endif
548+
549+ }
550+
551 m_pPlayerManager->addSampler();
552 m_pPlayerManager->addSampler();
553 m_pPlayerManager->addSampler();
554
555=== modified file 'mixxx/src/soundmanager.cpp'
556--- mixxx/src/soundmanager.cpp 2012-10-06 00:31:03 +0000
557+++ mixxx/src/soundmanager.cpp 2012-10-22 14:36:20 +0000
558@@ -177,7 +177,11 @@
559 // Need to tell all registered AudioDestinations for this AudioInput
560 // that the input was disconnected.
561 if (m_registeredDestinations.contains(in)) {
562- m_registeredDestinations[in]->onInputDisconnected(in);
563+ QList<AudioDestination*> destList = m_registeredDestinations.values(in);
564+ AudioDestination* dest;
565+ foreach(dest, destList) {
566+ dest->onInputDisconnected(in);
567+ }
568 }
569
570 short *buffer = m_inputBuffers[in];
571@@ -323,7 +327,11 @@
572 // Check if any AudioDestination is registered for this AudioInput,
573 // and call the onInputConnected method.
574 if (m_registeredDestinations.contains(in)) {
575- m_registeredDestinations[in]->onInputConnected(in);
576+ QList<AudioDestination*> destList = m_registeredDestinations.values(in);
577+ AudioDestination* dest;
578+ foreach(dest, destList) {
579+ dest->onInputConnected(in);
580+ }
581 }
582 }
583 foreach (AudioOutput out, m_config.getOutputs().values(device->getInternalName())) {
584@@ -588,9 +596,12 @@
585 short* pInputBuffer = m_inputBuffers[in];
586
587 if (m_registeredDestinations.contains(in)) {
588- AudioDestination* destination = m_registeredDestinations[in];
589- if (destination) {
590- destination->receiveBuffer(in, pInputBuffer, iFramesPerBuffer);
591+ QList<AudioDestination*> destList = m_registeredDestinations.values(in);
592+ AudioDestination* dest;
593+ foreach(dest, destList) {
594+ if(dest) {
595+ dest->receiveBuffer(in, pInputBuffer, iFramesPerBuffer);
596+ }
597 }
598 }
599 }
600@@ -613,7 +624,9 @@
601 // AudioInput to be going to a different AudioDest -bkgood
602 qDebug() << "WARNING: AudioInput already registered!";
603 }
604- m_registeredDestinations[input] = dest;
605+
606+ m_registeredDestinations.insertMulti(input, dest);
607+
608 emit(inputRegistered(input, dest));
609 }
610