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
=== modified file 'mixxx/build/depends.py'
--- mixxx/build/depends.py 2012-09-05 06:24:48 +0000
+++ mixxx/build/depends.py 2012-10-22 14:36:20 +0000
@@ -458,7 +458,6 @@
458 "engine/enginexfader.cpp",458 "engine/enginexfader.cpp",
459 "engine/enginemicrophone.cpp",459 "engine/enginemicrophone.cpp",
460 "engine/enginedeck.cpp",460 "engine/enginedeck.cpp",
461 "engine/enginepassthrough.cpp",
462461
463 "engine/enginecontrol.cpp",462 "engine/enginecontrol.cpp",
464 "engine/ratecontrol.cpp",463 "engine/ratecontrol.cpp",
465464
=== modified file 'mixxx/res/skins/Deere1280x800-WXGA/skin.xml'
--- mixxx/res/skins/Deere1280x800-WXGA/skin.xml 2012-09-09 09:25:58 +0000
+++ mixxx/res/skins/Deere1280x800-WXGA/skin.xml 2012-10-22 14:36:20 +0000
@@ -3873,7 +3873,7 @@
38733873
3874 <!--3874 <!--
3875 **********************************************3875 **********************************************
3876 Button - Quantize3876 Button - Quantize <ConfigKey>[Channel1],quantize</ConfigKey>
3877 **********************************************3877 **********************************************
3878 -->3878 -->
3879 <PushButton>3879 <PushButton>
38803880
=== modified file 'mixxx/src/basetrackplayer.cpp'
--- mixxx/src/basetrackplayer.cpp 2012-06-25 00:02:38 +0000
+++ mixxx/src/basetrackplayer.cpp 2012-10-22 14:36:20 +0000
@@ -9,7 +9,6 @@
9#include "controlpotmeter.h"9#include "controlpotmeter.h"
10#include "trackinfoobject.h"10#include "trackinfoobject.h"
11#include "engine/enginebuffer.h"11#include "engine/enginebuffer.h"
12#include "engine/enginedeck.h"
13#include "engine/enginemaster.h"12#include "engine/enginemaster.h"
14#include "soundsourceproxy.h"13#include "soundsourceproxy.h"
15#include "engine/cuecontrol.h"14#include "engine/cuecontrol.h"
@@ -34,10 +33,10 @@
34 // pSafeGroupName is leaked. It's like 5 bytes so whatever.33 // pSafeGroupName is leaked. It's like 5 bytes so whatever.
35 const char* pSafeGroupName = strdup(getGroup().toAscii().constData());34 const char* pSafeGroupName = strdup(getGroup().toAscii().constData());
3635
37 EngineDeck* pChannel = new EngineDeck(pSafeGroupName,36 m_pChannel = new EngineDeck(pSafeGroupName, pConfig, defaultOrientation);
38 pConfig, defaultOrientation);37
39 EngineBuffer* pEngineBuffer = pChannel->getEngineBuffer();38 EngineBuffer* pEngineBuffer = m_pChannel->getEngineBuffer();
40 pMixingEngine->addChannel(pChannel);39 pMixingEngine->addChannel(m_pChannel);
4140
42 ClockControl* pClockControl = new ClockControl(pSafeGroupName, pConfig);41 ClockControl* pClockControl = new ClockControl(pSafeGroupName, pConfig);
43 pEngineBuffer->addControl(pClockControl);42 pEngineBuffer->addControl(pClockControl);
@@ -246,3 +245,8 @@
246TrackPointer BaseTrackPlayer::getLoadedTrack() const {245TrackPointer BaseTrackPlayer::getLoadedTrack() const {
247 return m_pLoadedTrack;246 return m_pLoadedTrack;
248}247}
248
249EngineDeck* BaseTrackPlayer::getEngineDeck() const {
250 return m_pChannel;
251}
252
249253
=== modified file 'mixxx/src/basetrackplayer.h'
--- mixxx/src/basetrackplayer.h 2012-04-25 04:43:42 +0000
+++ mixxx/src/basetrackplayer.h 2012-10-22 14:36:20 +0000
@@ -6,6 +6,7 @@
6#include "baseplayer.h"6#include "baseplayer.h"
7#include "analyserqueue.h"7#include "analyserqueue.h"
8#include "engine/enginechannel.h"8#include "engine/enginechannel.h"
9#include "engine/enginedeck.h"
910
10class EngineMaster;11class EngineMaster;
11class ControlObject;12class ControlObject;
@@ -25,6 +26,7 @@
2526
26 AnalyserQueue* getAnalyserQueue() const;27 AnalyserQueue* getAnalyserQueue() const;
27 TrackPointer getLoadedTrack() const;28 TrackPointer getLoadedTrack() const;
29 EngineDeck* getEngineDeck() const;
2830
29 public slots:31 public slots:
30 void slotLoadTrack(TrackPointer track, bool bStartFromEndPos=false);32 void slotLoadTrack(TrackPointer track, bool bStartFromEndPos=false);
@@ -53,6 +55,8 @@
53 ControlObject* m_pDuration;55 ControlObject* m_pDuration;
54 ControlObjectThreadMain* m_pBPM;56 ControlObjectThreadMain* m_pBPM;
55 ControlObjectThreadMain* m_pReplayGain;57 ControlObjectThreadMain* m_pReplayGain;
58
59 EngineDeck* m_pChannel;
56};60};
5761
5862
5963
=== modified file 'mixxx/src/engine/enginedeck.cpp'
--- mixxx/src/engine/enginedeck.cpp 2011-06-11 22:55:41 +0000
+++ mixxx/src/engine/enginedeck.cpp 2012-10-22 14:36:20 +0000
@@ -26,11 +26,30 @@
26#include "enginevumeter.h"26#include "enginevumeter.h"
27#include "enginefilteriir.h"27#include "enginefilteriir.h"
2828
29#include "sampleutil.h"
30
29EngineDeck::EngineDeck(const char* group,31EngineDeck::EngineDeck(const char* group,
30 ConfigObject<ConfigValue>* pConfig,32 ConfigObject<ConfigValue>* pConfig,
31 EngineChannel::ChannelOrientation defaultOrientation)33 EngineChannel::ChannelOrientation defaultOrientation)
32 : EngineChannel(group, defaultOrientation),34 : EngineChannel(group, defaultOrientation),
33 m_pConfig(pConfig) {35 m_pConfig(pConfig),
36 m_pPassing(new ControlPushButton(ConfigKey(group, "passthrough_enabled"))),
37 // Need a +1 here because the CircularBuffer only allows its size-1
38 // items to be held at once (it keeps a blank spot open persistently)
39 m_sampleBuffer(MAX_BUFFER_LEN+1) {
40
41 // Set up passthrough utilities and fields
42 m_pPassing->setButtonMode(ControlPushButton::TOGGLE);
43 m_pConversionBuffer = SampleUtil::alloc(MAX_BUFFER_LEN);
44 m_bPassthroughIsActive = false;
45 m_bPassthroughWasActive = false;
46
47 // Set up passthrough toggle button
48 connect(m_pPassing, SIGNAL(valueChanged(double)),
49 this, SLOT(slotPassingToggle(double)),
50 Qt::DirectConnection);
51
52 // Set up additional engines
34 m_pPregain = new EnginePregain(group);53 m_pPregain = new EnginePregain(group);
35 m_pFilter = new EngineFilterBlock(group);54 m_pFilter = new EngineFilterBlock(group);
36 m_pFlanger = new EngineFlanger(group);55 m_pFlanger = new EngineFlanger(group);
@@ -41,6 +60,9 @@
41}60}
4261
43EngineDeck::~EngineDeck() {62EngineDeck::~EngineDeck() {
63 SampleUtil::free(m_pConversionBuffer);
64 delete m_pPassing;
65
44 delete m_pBuffer;66 delete m_pBuffer;
45 delete m_pClipping;67 delete m_pClipping;
46 delete m_pFilter;68 delete m_pFilter;
@@ -50,11 +72,40 @@
50 delete m_pVUMeter;72 delete m_pVUMeter;
51}73}
5274
53void EngineDeck::process(const CSAMPLE*, const CSAMPLE * pOut, const int iBufferSize) {75void EngineDeck::process(const CSAMPLE*, const CSAMPLE * pOutput, const int iBufferSize) {
54 // Process the raw audio76
55 m_pBuffer->process(0, pOut, iBufferSize);77 CSAMPLE* pOut = const_cast<CSAMPLE*>(pOutput);
56 // Emulate vinyl sounds78
57 m_pVinylSoundEmu->process(pOut, pOut, iBufferSize);79 // Feed the incoming audio through if passthrough is active
80 if (isPassthroughActive()) {
81 int samplesRead = m_sampleBuffer.read(pOut, iBufferSize);
82 if (samplesRead < iBufferSize) {
83 // Buffer underflow. There aren't getting samples fast enough. This
84 // shouldn't happen since PortAudio should feed us samples just as fast
85 // as we consume them, right?
86 Q_ASSERT(false);
87 }
88
89 m_bPassthroughWasActive = true;
90
91 } else {
92
93 // If passthrough is no longer enabled, zero out the buffer
94 if (m_bPassthroughWasActive) {
95 SampleUtil::applyGain(pOut, 0.0, iBufferSize);
96 m_sampleBuffer.skip(iBufferSize);
97 m_bPassthroughWasActive = false;
98 return;
99 }
100
101 // Process the raw audio
102 m_pBuffer->process(0, pOut, iBufferSize);
103 // Emulate vinyl sounds
104 m_pVinylSoundEmu->process(pOut, pOut, iBufferSize);
105
106 m_bPassthroughWasActive = false;
107 }
108
58 // Apply pregain109 // Apply pregain
59 m_pPregain->process(pOut, pOut, iBufferSize);110 m_pPregain->process(pOut, pOut, iBufferSize);
60 // Filter the channel with EQs111 // Filter the channel with EQs
@@ -72,5 +123,79 @@
72}123}
73124
74bool EngineDeck::isActive() {125bool EngineDeck::isActive() {
75 return m_pBuffer->isTrackLoaded();126 if (m_bPassthroughWasActive && !m_bPassthroughIsActive) {
76}127 return true;
128 }
129
130 return (m_pBuffer->isTrackLoaded() || isPassthroughActive());
131}
132
133void EngineDeck::receiveBuffer(AudioInput input, const short* pBuffer, unsigned int nFrames) {
134
135 // Skip receiving audio input if passthrough is not active
136 if (!m_bPassthroughIsActive) {
137 return;
138 }
139
140 if (input.getType() != AudioPath::VINYLCONTROL) {
141 // This is an error!
142 qDebug() << "WARNING: EngineDeck receieved an AudioInput for a non-vinylcontrol type!";
143 return;
144 }
145
146 // Use the conversion buffer to both convert from short and double into
147 // stereo.
148
149 // Check that the number of mono samples doesn't exceed MAX_BUFFER_LEN/2
150 // because thats our conversion buffer size.
151 if (nFrames > MAX_BUFFER_LEN / 2) {
152 qDebug() << "WARNING: Dropping passthrough samples because the input buffer is too large.";
153 nFrames = MAX_BUFFER_LEN / 2;
154 }
155
156 // There isn't a suitable SampleUtil method that can do mono->stereo and
157 // short->float in one pass.
158 // SampleUtil::convert(m_pConversionBuffer, pBuffer, iNumSamples);
159 SampleUtil::convert(m_pConversionBuffer, pBuffer, nFrames*2);
160
161 // TODO(rryan) (or bkgood?) do we need to verify the input is the one we asked for? Oh well.
162 unsigned int samplesWritten = m_sampleBuffer.write(m_pConversionBuffer, nFrames*2);
163 if (samplesWritten < nFrames*2) {
164 // Buffer overflow. We aren't processing samples fast enough. This
165 // shouldn't happen since the deck spits out samples just as fast as they
166 // come in, right?
167 Q_ASSERT(false);
168 }
169}
170
171void EngineDeck::onInputConnected(AudioInput input) {
172 if (input.getType() != AudioPath::VINYLCONTROL) {
173 // This is an error!
174 qDebug() << "WARNING: EngineDeck connected to AudioInput for a non-vinylcontrol type!";
175 return;
176 }
177 m_sampleBuffer.clear();
178}
179
180void EngineDeck::onInputDisconnected(AudioInput input) {
181 if (input.getType() != AudioPath::VINYLCONTROL) {
182 // This is an error!
183 qDebug() << "WARNING: EngineDeck connected to AudioInput for a non-vinylcontrol type!";
184 return;
185 }
186 m_sampleBuffer.clear();
187}
188
189bool EngineDeck::isPassthroughActive() {
190 return (m_bPassthroughIsActive && !m_sampleBuffer.isEmpty());
191}
192
193void EngineDeck::slotPassingToggle(double v) {
194 if (v > 0) {
195 m_bPassthroughIsActive = true;
196 }
197 else {
198 m_bPassthroughIsActive = false;
199 }
200}
201
77202
=== modified file 'mixxx/src/engine/enginedeck.h'
--- mixxx/src/engine/enginedeck.h 2011-04-01 04:51:24 +0000
+++ mixxx/src/engine/enginedeck.h 2012-10-22 14:36:20 +0000
@@ -18,10 +18,14 @@
18#ifndef ENGINEDECK_H18#ifndef ENGINEDECK_H
19#define ENGINEDECK_H19#define ENGINEDECK_H
2020
21#include "circularbuffer.h"
22#include "controlpushbutton.h"
21#include "engine/engineobject.h"23#include "engine/engineobject.h"
22#include "engine/enginechannel.h"24#include "engine/enginechannel.h"
23#include "configobject.h"25#include "configobject.h"
2426
27#include "soundmanagerutil.h"
28
25class EngineBuffer;29class EngineBuffer;
26class EnginePregain;30class EnginePregain;
27class EngineBuffer;31class EngineBuffer;
@@ -32,19 +36,40 @@
32class EngineVinylSoundEmu;36class EngineVinylSoundEmu;
33class ControlPushButton;37class ControlPushButton;
3438
35class EngineDeck : public EngineChannel {39class EngineDeck : public EngineChannel, public AudioDestination {
36 Q_OBJECT40 Q_OBJECT
37 public:41 public:
38 EngineDeck(const char *group, ConfigObject<ConfigValue>* pConfig,42 EngineDeck(const char *group, ConfigObject<ConfigValue>* pConfig,
39 EngineChannel::ChannelOrientation defaultOrientation = CENTER);43 EngineChannel::ChannelOrientation defaultOrientation = CENTER);
40 virtual ~EngineDeck();44 virtual ~EngineDeck();
4145
42 virtual void process(const CSAMPLE *pIn, const CSAMPLE *pOut, const int iBufferSize);46 virtual void process(const CSAMPLE *pInput, const CSAMPLE *pOutput, const int iBufferSize);
4347
44 // TODO(XXX) This hack needs to be removed.48 // TODO(XXX) This hack needs to be removed.
45 virtual EngineBuffer* getEngineBuffer();49 virtual EngineBuffer* getEngineBuffer();
4650
47 virtual bool isActive();51 virtual bool isActive();
52
53 // Begin vinyl passthrough methods
54
55 // This is called by SoundManager whenever there are new samples from the
56 // deck to be processed
57 virtual void receiveBuffer(AudioInput input, const short *pBuffer, unsigned int nFrames);
58
59 // Called by SoundManager whenever the passthrough input is connected to a
60 // soundcard input.
61 virtual void onInputConnected(AudioInput input);
62
63 // Called by SoundManager whenever the passthrough input is disconnected from
64 // a soundcard input.
65 virtual void onInputDisconnected(AudioInput input);
66
67 // Return whether or not passthrough is active
68 bool isPassthroughActive();
69
70 public slots:
71 void slotPassingToggle(double v);
72
48 private:73 private:
49 ConfigObject<ConfigValue>* m_pConfig;74 ConfigObject<ConfigValue>* m_pConfig;
50 EngineBuffer* m_pBuffer;75 EngineBuffer* m_pBuffer;
@@ -54,6 +79,13 @@
54 EnginePregain* m_pPregain;79 EnginePregain* m_pPregain;
55 EngineVinylSoundEmu* m_pVinylSoundEmu;80 EngineVinylSoundEmu* m_pVinylSoundEmu;
56 EngineVuMeter* m_pVUMeter;81 EngineVuMeter* m_pVUMeter;
82
83 // Begin vinyl passthrough fields
84 ControlPushButton* m_pPassing;
85 CSAMPLE* m_pConversionBuffer;
86 CircularBuffer<CSAMPLE> m_sampleBuffer;
87 bool m_bPassthroughIsActive;
88 bool m_bPassthroughWasActive;
57};89};
5890
59#endif91#endif
6092
=== modified file 'mixxx/src/engine/enginemaster.cpp'
--- mixxx/src/engine/enginemaster.cpp 2012-09-23 20:26:44 +0000
+++ mixxx/src/engine/enginemaster.cpp 2012-10-22 14:36:20 +0000
@@ -203,6 +203,8 @@
203 }203 }
204 }204 }
205205
206 // qDebug() << "Total active channels: " << totalActive;
207
206 if (totalActive == 0) {208 if (totalActive == 0) {
207 SampleUtil::applyGain(pOutput, 0.0f, iBufferSize);209 SampleUtil::applyGain(pOutput, 0.0f, iBufferSize);
208 } else if (totalActive == 1) {210 } else if (totalActive == 1) {
209211
=== removed file 'mixxx/src/engine/enginepassthrough.h'
--- mixxx/src/engine/enginepassthrough.h 2011-04-08 08:27:29 +0000
+++ mixxx/src/engine/enginepassthrough.h 1970-01-01 00:00:00 +0000
@@ -1,51 +0,0 @@
1// enginepassthrough.h
2// created 4/8/2011 by Bill Good (bkgood@gmail.com)
3// unapologetically copied from enginemicrophone.h from RJ
4
5#ifndef ENGINEPASSTHROUGH_H
6#define ENGINEPASSTHROUGH_H
7
8#include "circularbuffer.h"
9#include "controlpushbutton.h"
10#include "engine/enginechannel.h"
11#include "engine/engineclipping.h"
12#include "engine/enginevumeter.h"
13#include "soundmanagerutil.h"
14
15// EnginePassthrough is an EngineChannel that implements a mixing source whose
16// samples are fed directly from the SoundManager
17class EnginePassthrough : public EngineChannel, public AudioDestination {
18 Q_OBJECT
19 public:
20 EnginePassthrough(const char *pGroup);
21 virtual ~EnginePassthrough();
22
23 bool isActive();
24 bool isPFL();
25 bool isMaster();
26
27 // Called by EngineMaster whenever is requesting a new buffer of audio.
28 virtual void process(const CSAMPLE *pInput, const CSAMPLE *pOutput, const int iBufferSize);
29
30 // This is called by SoundManager whenever there are new samples from the
31 // deck to be processed
32 virtual void receiveBuffer(AudioInput input, const short *pBuffer, unsigned int nFrames);
33
34 // Called by SoundManager whenever the passthrough input is connected to a
35 // soundcard input.
36 virtual void onInputConnected(AudioInput input);
37
38 // Called by SoundManager whenever the passthrough input is disconnected from
39 // a soundcard input.
40 virtual void onInputDisconnected(AudioInput input);
41
42 private:
43 EngineClipping m_clipping;
44 EngineVuMeter m_vuMeter;
45 ControlObject *m_pEnabled;
46 ControlPushButton *m_pPassing;
47 CSAMPLE *m_pConversionBuffer;
48 CircularBuffer<CSAMPLE> m_sampleBuffer;
49};
50
51#endif /* ENGINEPASSTHROUGH_H */
520
=== modified file 'mixxx/src/engine/enginepregain.cpp'
--- mixxx/src/engine/enginepregain.cpp 2012-08-10 23:57:22 +0000
+++ mixxx/src/engine/enginepregain.cpp 2012-10-22 14:36:20 +0000
@@ -38,6 +38,7 @@
38 //Replay Gain things38 //Replay Gain things
39 m_pControlReplayGain = new ControlObject(ConfigKey(group, "replaygain"));39 m_pControlReplayGain = new ControlObject(ConfigKey(group, "replaygain"));
40 m_pTotalGain = new ControlObject(ConfigKey(group, "total_gain"));40 m_pTotalGain = new ControlObject(ConfigKey(group, "total_gain"));
41 m_pPassthroughEnabled = ControlObject::getControl(ConfigKey(group, "passthrough_enabled"));
4142
42 if (s_pReplayGainBoost == NULL) {43 if (s_pReplayGainBoost == NULL) {
43 s_pReplayGainBoost = new ControlPotmeter(ConfigKey("[ReplayGain]", "InitialReplayGainBoost"),0., 15.);44 s_pReplayGainBoost = new ControlPotmeter(ConfigKey("[ReplayGain]", "InitialReplayGainBoost"),0., 15.);
@@ -72,58 +73,53 @@
72 float fGain = potmeterPregain->get();73 float fGain = potmeterPregain->get();
73 float fReplayGain = m_pControlReplayGain->get();74 float fReplayGain = m_pControlReplayGain->get();
74 m_fReplayGainCorrection=1;75 m_fReplayGainCorrection=1;
76 float fPassing = m_pPassthroughEnabled->get();
75 // TODO(XXX) Why do we do this? Removing it results in clipping at unity77 // TODO(XXX) Why do we do this? Removing it results in clipping at unity
76 // gain so I think it was trying to compensate for some issue when we added78 // gain so I think it was trying to compensate for some issue when we added
77 // replaygain but even at unity gain (no RG) we are clipping. rryan 5/201279 // replaygain but even at unity gain (no RG) we are clipping. rryan 5/2012
78 fGain = fGain/2;80 fGain = fGain/2;
79 if(fReplayGain*fEnableReplayGain != 0)81
80 {82 // Override replaygain value if passing through
83 if (fPassing == 0.0) {
84 fReplayGain = 1.0;
85 }
86
87 else if (fReplayGain*fEnableReplayGain != 0) {
81 // Here is the point, when ReplayGain Analyser takes its action, suggested gain changes from 0 to a nonzero value88 // Here is the point, when ReplayGain Analyser takes its action, suggested gain changes from 0 to a nonzero value
82 // We want to smoothly fade to this last.89 // We want to smoothly fade to this last.
83 // Anyway we have some the problem that code cannot block the full process for one second.90 // Anyway we have some the problem that code cannot block the full process for one second.
84 // So we need to alter gain each time ::process is called.91 // So we need to alter gain each time ::process is called.
92 if (m_bSmoothFade) { // This means that a ReplayGain value has been calculated after the track has been loaded
8593
86 if(m_bSmoothFade)//This means that a ReplayGain value has been calculated after the track has been loaded94 if (m_fClock==0) {
87 {
88 if(m_fClock==0)
89 m_fClock=clock();95 m_fClock=clock();
96 }
90 m_fSumClock += (float)((clock()-m_fClock)/CLOCKS_PER_SEC);97 m_fSumClock += (float)((clock()-m_fClock)/CLOCKS_PER_SEC);
91 m_fClock=clock();98 m_fClock=clock();
92 if(m_fSumClock<1)99 if (m_fSumClock<1) {
93 {
94 //Fade smoothly100 //Fade smoothly
95
96 m_fReplayGainCorrection=(1-m_fSumClock)+(m_fSumClock)*fReplayGain*pow(10, fReplayGainBoost/20);101 m_fReplayGainCorrection=(1-m_fSumClock)+(m_fSumClock)*fReplayGain*pow(10, fReplayGainBoost/20);
97
98 }102 }
99 else103 else {
100 {
101 m_bSmoothFade = false;104 m_bSmoothFade = false;
102 }105 }
103 }106 }
104 else107 else {
105 {
106 //Passing a user defined boost108 //Passing a user defined boost
107 m_fReplayGainCorrection=fReplayGain*pow(10, fReplayGainBoost/20);109 m_fReplayGainCorrection=fReplayGain*pow(10, fReplayGainBoost/20);
108 }110 }
109 }111 }
110 else112 else {
111 {
112 // If track has not ReplayGain value and ReplayGain is enabled113 // If track has not ReplayGain value and ReplayGain is enabled
113 // we prepare for smoothfading to ReplayGain suggested gain114 // we prepare for smoothfading to ReplayGain suggested gain
114 if(fEnableReplayGain != 0)115 if(fEnableReplayGain != 0) {
115 {
116 m_bSmoothFade=true;116 m_bSmoothFade=true;
117 m_fClock=0;117 m_fClock=0;
118 m_fSumClock=0;118 m_fSumClock=0;
119 }119 }
120 }120 }
121121
122 // Clamp gain to within [0, 10.0] to prevent insane gains. This can happen122 fGain = fGain*m_fReplayGainCorrection;
123 // (some corrupt files get really high replay gain values).
124 // 10 allows a maximum replay Gain Boost * calculated replay gain of ~2
125 fGain = fGain * math_max(0.0, math_min(10.0, m_fReplayGainCorrection));
126
127 m_pTotalGain->set(fGain);123 m_pTotalGain->set(fGain);
128124
129 //qDebug()<<"Clock"<<(float)clock()/CLOCKS_PER_SEC;125 //qDebug()<<"Clock"<<(float)clock()/CLOCKS_PER_SEC;
130126
=== modified file 'mixxx/src/engine/enginepregain.h'
--- mixxx/src/engine/enginepregain.h 2012-07-22 09:31:52 +0000
+++ mixxx/src/engine/enginepregain.h 2012-10-22 14:36:20 +0000
@@ -35,7 +35,8 @@
35private:35private:
36 ControlLogpotmeter *potmeterPregain;36 ControlLogpotmeter *potmeterPregain;
37 ControlObject *m_pTotalGain;37 ControlObject *m_pTotalGain;
38 ControlObject *m_pControlReplayGain;38 ControlObject* m_pControlReplayGain;
39 ControlObject* m_pPassthroughEnabled;
39 static ControlPotmeter *s_pReplayGainBoost;40 static ControlPotmeter *s_pReplayGainBoost;
40 static ControlObject *s_pEnableReplayGain;41 static ControlObject *s_pEnableReplayGain;
41 float m_fReplayGainCorrection, m_fReplayGain, m_fOldReplayGainCorrection;42 float m_fReplayGainCorrection, m_fReplayGain, m_fOldReplayGainCorrection;
4243
=== modified file 'mixxx/src/mixxx.cpp'
--- mixxx/src/mixxx.cpp 2012-10-09 20:07:04 +0000
+++ mixxx/src/mixxx.cpp 2012-10-22 14:36:20 +0000
@@ -26,10 +26,12 @@
26#include "build.h" // Generated by SCons26#include "build.h" // Generated by SCons
27#include "controlobjectthreadmain.h"27#include "controlobjectthreadmain.h"
28#include "controlpotmeter.h"28#include "controlpotmeter.h"
29#include "deck.h"
29#include "defs_urls.h"30#include "defs_urls.h"
30#include "defs_version.h"31#include "defs_version.h"
31#include "dlgabout.h"32#include "dlgabout.h"
32#include "dlgpreferences.h"33#include "dlgpreferences.h"
34#include "engine/enginedeck.h"
33#include "engine/enginemaster.h"35#include "engine/enginemaster.h"
34#include "engine/enginemicrophone.h"36#include "engine/enginemicrophone.h"
35#include "library/library.h"37#include "library/library.h"
@@ -309,10 +311,21 @@
309311
310 // Create the player manager.312 // Create the player manager.
311 m_pPlayerManager = new PlayerManager(m_pConfig, m_pEngine, m_pLibrary);313 m_pPlayerManager = new PlayerManager(m_pConfig, m_pEngine, m_pLibrary);
312 m_pPlayerManager->addDeck();314
313 m_pPlayerManager->addDeck();315 // Set up four decks for with the player manager
314 m_pPlayerManager->addDeck();316 for (unsigned int deck = 0; deck < 4; ++deck) {
315 m_pPlayerManager->addDeck();317
318 // Add deck to the player manager
319 Deck* pDeck = m_pPlayerManager->addDeck();
320
321#ifdef __VINYLCONTROL__
322 EngineDeck* pEngineDeck = pDeck->getEngineDeck();
323 // Register vinyl input signal with deck for passthrough
324 m_pSoundManager->registerInput(AudioInput(AudioInput::VINYLCONTROL, 0, deck), pEngineDeck);
325#endif
326
327 }
328
316 m_pPlayerManager->addSampler();329 m_pPlayerManager->addSampler();
317 m_pPlayerManager->addSampler();330 m_pPlayerManager->addSampler();
318 m_pPlayerManager->addSampler();331 m_pPlayerManager->addSampler();
319332
=== modified file 'mixxx/src/soundmanager.cpp'
--- mixxx/src/soundmanager.cpp 2012-10-06 00:31:03 +0000
+++ mixxx/src/soundmanager.cpp 2012-10-22 14:36:20 +0000
@@ -177,7 +177,11 @@
177 // Need to tell all registered AudioDestinations for this AudioInput177 // Need to tell all registered AudioDestinations for this AudioInput
178 // that the input was disconnected.178 // that the input was disconnected.
179 if (m_registeredDestinations.contains(in)) {179 if (m_registeredDestinations.contains(in)) {
180 m_registeredDestinations[in]->onInputDisconnected(in);180 QList<AudioDestination*> destList = m_registeredDestinations.values(in);
181 AudioDestination* dest;
182 foreach(dest, destList) {
183 dest->onInputDisconnected(in);
184 }
181 }185 }
182186
183 short *buffer = m_inputBuffers[in];187 short *buffer = m_inputBuffers[in];
@@ -323,7 +327,11 @@
323 // Check if any AudioDestination is registered for this AudioInput,327 // Check if any AudioDestination is registered for this AudioInput,
324 // and call the onInputConnected method.328 // and call the onInputConnected method.
325 if (m_registeredDestinations.contains(in)) {329 if (m_registeredDestinations.contains(in)) {
326 m_registeredDestinations[in]->onInputConnected(in);330 QList<AudioDestination*> destList = m_registeredDestinations.values(in);
331 AudioDestination* dest;
332 foreach(dest, destList) {
333 dest->onInputConnected(in);
334 }
327 }335 }
328 }336 }
329 foreach (AudioOutput out, m_config.getOutputs().values(device->getInternalName())) {337 foreach (AudioOutput out, m_config.getOutputs().values(device->getInternalName())) {
@@ -588,9 +596,12 @@
588 short* pInputBuffer = m_inputBuffers[in];596 short* pInputBuffer = m_inputBuffers[in];
589597
590 if (m_registeredDestinations.contains(in)) {598 if (m_registeredDestinations.contains(in)) {
591 AudioDestination* destination = m_registeredDestinations[in];599 QList<AudioDestination*> destList = m_registeredDestinations.values(in);
592 if (destination) {600 AudioDestination* dest;
593 destination->receiveBuffer(in, pInputBuffer, iFramesPerBuffer);601 foreach(dest, destList) {
602 if(dest) {
603 dest->receiveBuffer(in, pInputBuffer, iFramesPerBuffer);
604 }
594 }605 }
595 }606 }
596 }607 }
@@ -613,7 +624,9 @@
613 // AudioInput to be going to a different AudioDest -bkgood624 // AudioInput to be going to a different AudioDest -bkgood
614 qDebug() << "WARNING: AudioInput already registered!";625 qDebug() << "WARNING: AudioInput already registered!";
615 }626 }
616 m_registeredDestinations[input] = dest;627
628 m_registeredDestinations.insertMulti(input, dest);
629
617 emit(inputRegistered(input, dest));630 emit(inputRegistered(input, dest));
618}631}
619632