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