Merge lp:~mixxxdevelopers/mixxx/features_hydra into lp:~mixxxdevelopers/mixxx/trunk

Proposed by RJ Skerry-Ryan
Status: Merged
Merged at revision: 2721
Proposed branch: lp:~mixxxdevelopers/mixxx/features_hydra
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 923 lines (+456/-204)
9 files modified
mixxx/build/depends.py (+0/-1)
mixxx/src/engine/enginechannel.cpp (+0/-11)
mixxx/src/engine/enginechannel.h (+0/-3)
mixxx/src/engine/enginemaster.cpp (+210/-98)
mixxx/src/engine/enginemaster.h (+57/-9)
mixxx/src/engine/enginevolume.cpp (+0/-42)
mixxx/src/engine/enginevolume.h (+0/-36)
mixxx/src/sampleutil.cpp (+149/-0)
mixxx/src/sampleutil.h (+40/-4)
To merge this branch: bzr merge lp:~mixxxdevelopers/mixxx/features_hydra
Reviewer Review Type Date Requested Status
Albert Santoni Approve
Review via email: mp+55693@code.launchpad.net

Description of the change

Threw together some quick engine changes, but I'd like a review on them because they're substantial:

* Delete EngineVolume -- it was a trivial wrapper around a ControlLogpotmeter

* Make per-channel volume a gain factor when mixing the master output. This eliminates some hackyness w/ EngineChannel::isPFL that has been bugging me and saves 1 pass over every channel buffer.

* Eliminate use of QList in EngineMaster::process(). I noticed from gprof and some of Jus's traces that time spent in the QList in EngineMaster::process was higher than I had expected. Furthermore, allocating a QList on the stack malloc's every callback. It's not desirable if we can get around it. I removed that in favor of a bitvector approach, and I made way for some hard-coding of the mixing of higher #s of decks, because Mixxx will by default come with 6 or 7 EngineChannels turned on in 1.10.0, this is going to be more important than before.

To post a comment you must log in.
Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

BTW, the EngineMaster tests still pass, so I'm pretty confident this is fine for our uses. Something should be done about the 16-deck limit. With an int64, we could support 64-decks. We could also use two to get 128, but those aren't realistic cases for Mixxx right now so I didn't bother.

2721. By RJ Skerry-Ryan

More improvements to EngineMaster. Headphone mixing now goes through the fast-path of mixing channels instead of being added one by one (this has the added benefit of unifying the mixing code used for both the master and headphone channels). Added special-casing for the mixing of up to 7 channels. Folded the master volume into the master mixing step so we save a pass over the buffer there.

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

Many more improvements now. I think this tightens up the EngineMaster code quite a bit. Headphone and master mixing are both done through the same codepath now. I also shaved another pass off by folding the master volume into the master mixing step. Headphone mixing is now faster because it uses the hard-coded mixing steps instead of the N-pass adding.

2722. By RJ Skerry-Ryan

Forgot a return value, and for some braindead reason GCC compiled it.

Revision history for this message
Albert Santoni (gamegod) wrote :

I checked the coefficients and looked over the code, didn't see anything that looks out of place. Though we haven't measured the performance gains, this is definitely a step in the right direction.

Thanks RJ!

review: Approve

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 2011-03-29 08:45:42 +0000
+++ mixxx/build/depends.py 2011-04-01 04:36:32 +0000
@@ -358,7 +358,6 @@
358 "engine/enginefilter.cpp",358 "engine/enginefilter.cpp",
359 "engine/engineobject.cpp",359 "engine/engineobject.cpp",
360 "engine/enginepregain.cpp",360 "engine/enginepregain.cpp",
361 "engine/enginevolume.cpp",
362 "engine/enginechannel.cpp",361 "engine/enginechannel.cpp",
363 "engine/enginemaster.cpp",362 "engine/enginemaster.cpp",
364 "engine/enginedelay.cpp",363 "engine/enginedelay.cpp",
365364
=== modified file 'mixxx/src/engine/enginechannel.cpp'
--- mixxx/src/engine/enginechannel.cpp 2011-03-13 00:21:05 +0000
+++ mixxx/src/engine/enginechannel.cpp 2011-04-01 04:36:32 +0000
@@ -22,7 +22,6 @@
22#include "enginechannel.h"22#include "enginechannel.h"
23#include "engineclipping.h"23#include "engineclipping.h"
24#include "enginepregain.h"24#include "enginepregain.h"
25#include "enginevolume.h"
26#include "engineflanger.h"25#include "engineflanger.h"
27#include "enginefilterblock.h"26#include "enginefilterblock.h"
28#include "enginevumeter.h"27#include "enginevumeter.h"
@@ -39,7 +38,6 @@
39 m_pClipping = new EngineClipping(group);38 m_pClipping = new EngineClipping(group);
40 m_pBuffer = new EngineBuffer(group, pConfig);39 m_pBuffer = new EngineBuffer(group, pConfig);
41 m_pVinylSoundEmu = new EngineVinylSoundEmu(pConfig, group);40 m_pVinylSoundEmu = new EngineVinylSoundEmu(pConfig, group);
42 m_pVolume = new EngineVolume(ConfigKey(group, "volume"));
43 m_pVUMeter = new EngineVuMeter(group);41 m_pVUMeter = new EngineVuMeter(group);
44 m_pPFL = new ControlPushButton(ConfigKey(group, "pfl"));42 m_pPFL = new ControlPushButton(ConfigKey(group, "pfl"));
45 m_pPFL->setToggleButton(true);43 m_pPFL->setToggleButton(true);
@@ -54,7 +52,6 @@
54 delete m_pFlanger;52 delete m_pFlanger;
55 delete m_pPregain;53 delete m_pPregain;
56 delete m_pVinylSoundEmu;54 delete m_pVinylSoundEmu;
57 delete m_pVolume;
58 delete m_pVUMeter;55 delete m_pVUMeter;
59 delete m_pPFL;56 delete m_pPFL;
60}57}
@@ -82,14 +79,6 @@
82 m_pClipping->process(pOut, pOut, iBufferSize);79 m_pClipping->process(pOut, pOut, iBufferSize);
83 // Update VU meter80 // Update VU meter
84 m_pVUMeter->process(pOut, pOut, iBufferSize);81 m_pVUMeter->process(pOut, pOut, iBufferSize);
85 // Apply channel volume if we aren't PFL
86 if (!isPFL()) {
87 m_pVolume->process(pOut, pOut, iBufferSize);
88 }
89}
90
91void EngineChannel::applyVolume(CSAMPLE *pBuff, const int iBufferSize) const {
92 m_pVolume->process(pBuff, pBuff, iBufferSize);
93}82}
9483
95EngineBuffer* EngineChannel::getEngineBuffer() {84EngineBuffer* EngineChannel::getEngineBuffer() {
9685
=== modified file 'mixxx/src/engine/enginechannel.h'
--- mixxx/src/engine/enginechannel.h 2011-03-13 00:21:05 +0000
+++ mixxx/src/engine/enginechannel.h 2011-04-01 04:36:32 +0000
@@ -27,7 +27,6 @@
27class EngineBuffer;27class EngineBuffer;
28class EngineFilterBlock;28class EngineFilterBlock;
29class EngineClipping;29class EngineClipping;
30class EngineVolume;
31class EngineFlanger;30class EngineFlanger;
32class EngineVuMeter;31class EngineVuMeter;
33class EngineVinylSoundEmu;32class EngineVinylSoundEmu;
@@ -50,7 +49,6 @@
50 virtual const QString& getGroup();49 virtual const QString& getGroup();
5150
52 virtual void process(const CSAMPLE *pIn, const CSAMPLE *pOut, const int iBufferSize);51 virtual void process(const CSAMPLE *pIn, const CSAMPLE *pOut, const int iBufferSize);
53 virtual void applyVolume(CSAMPLE *pBuff, const int iBufferSize) const;
5452
55 // TODO(XXX) This hack needs to be removed.53 // TODO(XXX) This hack needs to be removed.
56 virtual EngineBuffer* getEngineBuffer();54 virtual EngineBuffer* getEngineBuffer();
@@ -68,7 +66,6 @@
68 EngineFlanger* m_pFlanger;66 EngineFlanger* m_pFlanger;
69 EnginePregain* m_pPregain;67 EnginePregain* m_pPregain;
70 EngineVinylSoundEmu* m_pVinylSoundEmu;68 EngineVinylSoundEmu* m_pVinylSoundEmu;
71 EngineVolume* m_pVolume;
72 EngineVuMeter* m_pVUMeter;69 EngineVuMeter* m_pVUMeter;
73};70};
7471
7572
=== modified file 'mixxx/src/engine/enginemaster.cpp'
--- mixxx/src/engine/enginemaster.cpp 2010-12-16 16:29:53 +0000
+++ mixxx/src/engine/enginemaster.cpp 2011-04-01 04:36:32 +0000
@@ -21,12 +21,12 @@
2121
22#include "controlpushbutton.h"22#include "controlpushbutton.h"
23#include "configobject.h"23#include "configobject.h"
24#include "controllogpotmeter.h"
24#include "controlpotmeter.h"25#include "controlpotmeter.h"
25#include "enginebuffer.h"26#include "enginebuffer.h"
26#include "enginemaster.h"27#include "enginemaster.h"
27#include "engine/engineworkerscheduler.h"28#include "engine/engineworkerscheduler.h"
28#include "enginebuffer.h"29#include "enginebuffer.h"
29#include "enginevolume.h"
30#include "enginechannel.h"30#include "enginechannel.h"
31#include "engineclipping.h"31#include "engineclipping.h"
32#include "enginevumeter.h"32#include "enginevumeter.h"
@@ -66,7 +66,7 @@
66 m_pBalance = new ControlPotmeter(ConfigKey(group, "balance"), -1., 1.);66 m_pBalance = new ControlPotmeter(ConfigKey(group, "balance"), -1., 1.);
6767
68 // Master volume68 // Master volume
69 volume = new EngineVolume(ConfigKey(group,"volume"), 5.);69 m_pMasterVolume = new ControlLogpotmeter(ConfigKey(group, "volume"), 5.);
7070
71 // Clipping71 // Clipping
72 clipping = new EngineClipping(group);72 clipping = new EngineClipping(group);
@@ -75,7 +75,7 @@
75 vumeter = new EngineVuMeter(group);75 vumeter = new EngineVuMeter(group);
7676
77 // Headphone volume77 // Headphone volume
78 head_volume = new EngineVolume(ConfigKey(group, "headVolume"), 5.);78 m_pHeadVolume = new ControlLogpotmeter(ConfigKey(group, "headVolume"), 5.);
7979
80 // Headphone mix (left/right)80 // Headphone mix (left/right)
81 head_mix = new ControlPotmeter(ConfigKey(group, "headMix"),-1.,1.);81 head_mix = new ControlPotmeter(ConfigKey(group, "headMix"),-1.,1.);
@@ -105,34 +105,24 @@
105 delete crossfader;105 delete crossfader;
106 delete m_pBalance;106 delete m_pBalance;
107 delete head_mix;107 delete head_mix;
108 delete volume;108 delete m_pMasterVolume;
109 delete head_volume;109 delete m_pHeadVolume;
110 delete clipping;110 delete clipping;
111 delete head_clipping;111 delete head_clipping;
112 delete sidechain;112 delete sidechain;
113113
114
115 SampleUtil::free(m_pHead);114 SampleUtil::free(m_pHead);
116 SampleUtil::free(m_pMaster);115 SampleUtil::free(m_pMaster);
117116
118117 QMutableListIterator<ChannelInfo*> channel_it(m_channels);
119 QMutableListIterator<CSAMPLE*> buffer_it(m_channelBuffers);
120 while (buffer_it.hasNext()) {
121 CSAMPLE* buffer = buffer_it.next();
122 buffer_it.remove();
123 SampleUtil::free(buffer);
124 }
125
126
127 QMutableListIterator<EngineChannel*> channel_it(m_channels);
128 while (channel_it.hasNext()) {118 while (channel_it.hasNext()) {
129 EngineChannel* channel = channel_it.next();119 ChannelInfo* pChannelInfo = channel_it.next();
130 channel_it.remove();120 channel_it.remove();
131 delete channel;121 SampleUtil::free(pChannelInfo->m_pBuffer);
122 delete pChannelInfo->m_pChannel;
123 delete pChannelInfo->m_pVolumeControl;
124 delete pChannelInfo;
132 }125 }
133
134
135
136}126}
137127
138const CSAMPLE* EngineMaster::getMasterBuffer() const128const CSAMPLE* EngineMaster::getMasterBuffer() const
@@ -145,6 +135,167 @@
145 return m_pHead;135 return m_pHead;
146}136}
147137
138void EngineMaster::mixChannels(unsigned int channelBitvector, unsigned int maxChannels,
139 CSAMPLE* pOutput, unsigned int iBufferSize,
140 GainCalculator* pGainCalculator) {
141 // Common case: 2 decks, 4 samplers, 1 mic
142 ChannelInfo* pChannel1 = NULL;
143 ChannelInfo* pChannel2 = NULL;
144 ChannelInfo* pChannel3 = NULL;
145 ChannelInfo* pChannel4 = NULL;
146 ChannelInfo* pChannel5 = NULL;
147 ChannelInfo* pChannel6 = NULL;
148 ChannelInfo* pChannel7 = NULL;
149
150 unsigned int totalActive = 0;
151 for (unsigned int i = 0; i < maxChannels; ++i) {
152 if ((channelBitvector & (1 << i)) == 0) {
153 continue;
154 }
155
156 ++totalActive;
157
158 if (pChannel1 == NULL) {
159 pChannel1 = m_channels[i];
160 } else if (pChannel2 == NULL) {
161 pChannel2 = m_channels[i];
162 } else if (pChannel3 == NULL) {
163 pChannel3 = m_channels[i];
164 } else if (pChannel4 == NULL) {
165 pChannel4 = m_channels[i];
166 } else if (pChannel5 == NULL) {
167 pChannel5 = m_channels[i];
168 } else if (pChannel6 == NULL) {
169 pChannel6 = m_channels[i];
170 } else if (pChannel7 == NULL) {
171 pChannel7 = m_channels[i];
172 }
173 }
174
175 if (totalActive == 0) {
176 SampleUtil::applyGain(pOutput, 0.0f, iBufferSize);
177 } else if (totalActive == 1) {
178 CSAMPLE* pBuffer1 = pChannel1->m_pBuffer;
179 double gain1 = pGainCalculator->getGain(pChannel1);
180 SampleUtil::copyWithGain(pOutput,
181 pBuffer1, gain1,
182 iBufferSize);
183 } else if (totalActive == 2) {
184 CSAMPLE* pBuffer1 = pChannel1->m_pBuffer;
185 double gain1 = pGainCalculator->getGain(pChannel1);
186 CSAMPLE* pBuffer2 = pChannel2->m_pBuffer;
187 double gain2 = pGainCalculator->getGain(pChannel2);
188 SampleUtil::copy2WithGain(pOutput,
189 pBuffer1, gain1,
190 pBuffer2, gain2,
191 iBufferSize);
192 } else if (totalActive == 3) {
193 CSAMPLE* pBuffer1 = pChannel1->m_pBuffer;
194 double gain1 = pGainCalculator->getGain(pChannel1);
195 CSAMPLE* pBuffer2 = pChannel2->m_pBuffer;
196 double gain2 = pGainCalculator->getGain(pChannel2);
197 CSAMPLE* pBuffer3 = pChannel3->m_pBuffer;
198 double gain3 = pGainCalculator->getGain(pChannel3);
199
200 SampleUtil::copy3WithGain(pOutput,
201 pBuffer1, gain1,
202 pBuffer2, gain2,
203 pBuffer3, gain3,
204 iBufferSize);
205 } else if (totalActive == 4) {
206 CSAMPLE* pBuffer1 = pChannel1->m_pBuffer;
207 double gain1 = pGainCalculator->getGain(pChannel1);
208 CSAMPLE* pBuffer2 = pChannel2->m_pBuffer;
209 double gain2 = pGainCalculator->getGain(pChannel2);
210 CSAMPLE* pBuffer3 = pChannel3->m_pBuffer;
211 double gain3 = pGainCalculator->getGain(pChannel3);
212 CSAMPLE* pBuffer4 = pChannel4->m_pBuffer;
213 double gain4 = pGainCalculator->getGain(pChannel4);
214 SampleUtil::copy4WithGain(pOutput,
215 pBuffer1, gain1,
216 pBuffer2, gain2,
217 pBuffer3, gain3,
218 pBuffer4, gain4,
219 iBufferSize);
220 } else if (totalActive == 5) {
221 CSAMPLE* pBuffer1 = pChannel1->m_pBuffer;
222 double gain1 = pGainCalculator->getGain(pChannel1);
223 CSAMPLE* pBuffer2 = pChannel2->m_pBuffer;
224 double gain2 = pGainCalculator->getGain(pChannel2);
225 CSAMPLE* pBuffer3 = pChannel3->m_pBuffer;
226 double gain3 = pGainCalculator->getGain(pChannel3);
227 CSAMPLE* pBuffer4 = pChannel4->m_pBuffer;
228 double gain4 = pGainCalculator->getGain(pChannel4);
229 CSAMPLE* pBuffer5 = pChannel5->m_pBuffer;
230 double gain5 = pGainCalculator->getGain(pChannel5);
231
232 SampleUtil::copy5WithGain(pOutput,
233 pBuffer1, gain1,
234 pBuffer2, gain2,
235 pBuffer3, gain3,
236 pBuffer4, gain4,
237 pBuffer5, gain5,
238 iBufferSize);
239 } else if (totalActive == 6) {
240 CSAMPLE* pBuffer1 = pChannel1->m_pBuffer;
241 double gain1 = pGainCalculator->getGain(pChannel1);
242 CSAMPLE* pBuffer2 = pChannel2->m_pBuffer;
243 double gain2 = pGainCalculator->getGain(pChannel2);
244 CSAMPLE* pBuffer3 = pChannel3->m_pBuffer;
245 double gain3 = pGainCalculator->getGain(pChannel3);
246 CSAMPLE* pBuffer4 = pChannel4->m_pBuffer;
247 double gain4 = pGainCalculator->getGain(pChannel4);
248 CSAMPLE* pBuffer5 = pChannel5->m_pBuffer;
249 double gain5 = pGainCalculator->getGain(pChannel5);
250 CSAMPLE* pBuffer6 = pChannel6->m_pBuffer;
251 double gain6 = pGainCalculator->getGain(pChannel6);
252 SampleUtil::copy6WithGain(pOutput,
253 pBuffer1, gain1,
254 pBuffer2, gain2,
255 pBuffer3, gain3,
256 pBuffer4, gain4,
257 pBuffer5, gain5,
258 pBuffer6, gain6,
259 iBufferSize);
260 } else if (totalActive == 7) {
261 CSAMPLE* pBuffer1 = pChannel1->m_pBuffer;
262 double gain1 = pGainCalculator->getGain(pChannel1);
263 CSAMPLE* pBuffer2 = pChannel2->m_pBuffer;
264 double gain2 = pGainCalculator->getGain(pChannel2);
265 CSAMPLE* pBuffer3 = pChannel3->m_pBuffer;
266 double gain3 = pGainCalculator->getGain(pChannel3);
267 CSAMPLE* pBuffer4 = pChannel4->m_pBuffer;
268 double gain4 = pGainCalculator->getGain(pChannel4);
269 CSAMPLE* pBuffer5 = pChannel5->m_pBuffer;
270 double gain5 = pGainCalculator->getGain(pChannel5);
271 CSAMPLE* pBuffer6 = pChannel6->m_pBuffer;
272 double gain6 = pGainCalculator->getGain(pChannel6);
273 CSAMPLE* pBuffer7 = pChannel7->m_pBuffer;
274 double gain7 = pGainCalculator->getGain(pChannel7);
275 SampleUtil::copy7WithGain(pOutput,
276 pBuffer1, gain1,
277 pBuffer2, gain2,
278 pBuffer3, gain3,
279 pBuffer4, gain4,
280 pBuffer5, gain5,
281 pBuffer6, gain6,
282 pBuffer7, gain7,
283 iBufferSize);
284 } else {
285 // Set pOutput to all 0s
286 SampleUtil::applyGain(pOutput, 0.0f, iBufferSize);
287
288 for (unsigned int i = 0; i < maxChannels; ++i) {
289 if (channelBitvector & (1 << i)) {
290 ChannelInfo* pChannelInfo = m_channels[i];
291 CSAMPLE* pBuffer = pChannelInfo->m_pBuffer;
292 double gain = pGainCalculator->getGain(pChannelInfo);
293 SampleUtil::addWithGain(pOutput, pBuffer, gain, iBufferSize);
294 }
295 }
296 }
297}
298
148void EngineMaster::process(const CSAMPLE *, const CSAMPLE *pOut, const int iBufferSize)299void EngineMaster::process(const CSAMPLE *, const CSAMPLE *pOut, const int iBufferSize)
149{300{
150 CSAMPLE **pOutput = (CSAMPLE**)pOut;301 CSAMPLE **pOutput = (CSAMPLE**)pOut;
@@ -152,7 +303,10 @@
152303
153 // Prepare each channel for output304 // Prepare each channel for output
154305
155 QList<QPair<CSAMPLE*, EngineChannel::ChannelOrientation> > masterChannels;306 // Bitvector of enabled channels
307 const unsigned int maxChannels = 32;
308 unsigned int masterOutput = 0;
309 unsigned int headphoneOutput = 0;
156310
157 // Compute headphone mix311 // Compute headphone mix
158 // Head phone left/right mix312 // Head phone left/right mix
@@ -162,88 +316,43 @@
162 // qDebug() << "head val " << cf_val << ", head " << chead_gain316 // qDebug() << "head val " << cf_val << ", head " << chead_gain
163 // << ", master " << cmaster_gain;317 // << ", master " << cmaster_gain;
164318
165 // we have to copy PFL channels to the headphone buffer here before we319 QList<ChannelInfo*>::iterator it = m_channels.begin();
166 // process the master mix, as PFL channels don't have their fader volume320 for (unsigned int channel_number = 0;
167 // applied but the master channels do -- bkgood321 it != m_channels.end(); ++it, ++channel_number) {
168 SampleUtil::applyGain(m_pHead, 0.0f, iBufferSize);322 ChannelInfo* pChannelInfo = *it;
169323 EngineChannel* pChannel = pChannelInfo->m_pChannel;
170 for (int channel_number = 0; channel_number < m_channels.size(); ++channel_number) {324
171 EngineChannel* channel = m_channels[channel_number];325 if (!pChannel->isActive()) {
172
173 if (!channel->isActive()) {
174 continue;326 continue;
175 }327 }
176328
177 CSAMPLE* buffer = m_channelBuffers[channel_number];329 masterOutput |= (1 << channel_number);
178 channel->process(NULL, buffer, iBufferSize);330
331 // Process the buffer
332 pChannel->process(NULL, pChannelInfo->m_pBuffer, iBufferSize);
179333
180 // If the channel is enabled for previewing in headphones, copy it334 // If the channel is enabled for previewing in headphones, copy it
181 // over to the headphone buffer335 // over to the headphone buffer
182 if (channel->isPFL()) {336 if (pChannel->isPFL()) {
183 SampleUtil::addWithGain(m_pHead, buffer, chead_gain, iBufferSize);337 headphoneOutput |= (1 << channel_number);
184 // EngineChannel doesn't apply the volume if it knows it's PFL,
185 // so apply it
186 channel->applyVolume(buffer, iBufferSize);
187 }338 }
188
189 // Add the channel to the list of master output channels.
190 masterChannels.push_back(
191 QPair<CSAMPLE*, EngineChannel::ChannelOrientation>(
192 buffer, channel->getOrientation()));
193 }339 }
194340
195 // Perform the master mix.341 // Mix all the enabled headphone channels together.
342 m_headphoneGain.setGain(chead_gain);
343 mixChannels(headphoneOutput, maxChannels, m_pHead, iBufferSize, &m_headphoneGain);
196344
197 // Crossfader and Transform buttons345 // Calculate the crossfader gains for left and right side of the crossfader
198 //set gain levels;
199 float c1_gain, c2_gain;346 float c1_gain, c2_gain;
200 EngineXfader::getXfadeGains(c1_gain, c2_gain,347 EngineXfader::getXfadeGains(c1_gain, c2_gain,
201 crossfader->get(), xFaderCurve->get(),348 crossfader->get(), xFaderCurve->get(),
202 xFaderCalibration->get());349 xFaderCalibration->get());
203350
204 if (masterChannels.size() == 0) {351 // Now set the gains for overall volume and the left, center, right gains.
205 SampleUtil::applyGain(m_pMaster, 0.0f, iBufferSize);352 m_masterGain.setGains(m_pMasterVolume->get(), c1_gain, 1.0, c2_gain);
206 } else if (masterChannels.size() == 1) {353
207 QPair<CSAMPLE*, EngineChannel::ChannelOrientation>& channel =354 // Perform the master mix
208 masterChannels[0];355 mixChannels(masterOutput, maxChannels, m_pMaster, iBufferSize, &m_masterGain);
209 CSAMPLE* buffer = channel.first;
210 EngineChannel::ChannelOrientation orientation = channel.second;
211
212 // Apply gain
213 double gain = gainForOrientation(orientation, c1_gain, 1.0f, c2_gain);
214 SampleUtil::copyWithGain(m_pMaster, buffer, gain, iBufferSize);
215 } else if (masterChannels.size() == 2) {
216 QPair<CSAMPLE*, EngineChannel::ChannelOrientation> channel1 =
217 masterChannels[0];
218 QPair<CSAMPLE*, EngineChannel::ChannelOrientation> channel2 =
219 masterChannels[1];
220 CSAMPLE* buffer1 = channel1.first;
221 CSAMPLE* buffer2 = channel2.first;
222 EngineChannel::ChannelOrientation orientation1 = channel1.second;
223 EngineChannel::ChannelOrientation orientation2 = channel2.second;
224 double gain1 = gainForOrientation(orientation1, c1_gain, 1.0f, c2_gain);
225 double gain2 = gainForOrientation(orientation2, c1_gain, 1.0f, c2_gain);
226
227 SampleUtil::copy2WithGain(m_pMaster,
228 buffer1, gain1,
229 buffer2, gain2,
230 iBufferSize);
231 } else {
232 // Set m_pMaster to all 0s
233 SampleUtil::applyGain(m_pMaster, 0.0f, iBufferSize);
234
235 for (int i = 0; i < masterChannels.size(); ++i) {
236 QPair<CSAMPLE*, EngineChannel::ChannelOrientation> channel =
237 masterChannels[i];
238 CSAMPLE* buffer = channel.first;
239 EngineChannel::ChannelOrientation orientation = channel.second;
240 double gain = gainForOrientation(orientation, c1_gain, 1.0f, c2_gain);
241 SampleUtil::addWithGain(m_pMaster, buffer, gain, iBufferSize);
242 }
243 }
244
245 // Master volume
246 volume->process(m_pMaster, m_pMaster, iBufferSize);
247356
248#ifdef __LADSPA__357#ifdef __LADSPA__
249 // LADPSA master effects358 // LADPSA master effects
@@ -278,7 +387,7 @@
278 SampleUtil::addWithGain(m_pHead, m_pMaster, cmaster_gain, iBufferSize);387 SampleUtil::addWithGain(m_pHead, m_pMaster, cmaster_gain, iBufferSize);
279388
280 // Head volume and clipping389 // Head volume and clipping
281 head_volume->process(m_pHead, m_pHead, iBufferSize);390 SampleUtil::applyGain(m_pHead, m_pHeadVolume->get(), iBufferSize);
282 head_clipping->process(m_pHead, m_pHead, iBufferSize);391 head_clipping->process(m_pHead, m_pHead, iBufferSize);
283392
284 //Master/headphones interleaving is now done in393 //Master/headphones interleaving is now done in
@@ -290,18 +399,21 @@
290}399}
291400
292void EngineMaster::addChannel(EngineChannel* pChannel) {401void EngineMaster::addChannel(EngineChannel* pChannel) {
293 CSAMPLE* pChannelBuffer = SampleUtil::alloc(MAX_BUFFER_LEN);402 ChannelInfo* pChannelInfo = new ChannelInfo();
294 memset(pChannelBuffer, 0, sizeof(CSAMPLE) * MAX_BUFFER_LEN);403 pChannelInfo->m_pChannel = pChannel;
295 m_channelBuffers.push_back(pChannelBuffer);404 pChannelInfo->m_pVolumeControl = new ControlLogpotmeter(
296 m_channels.push_back(pChannel);405 ConfigKey(pChannel->getGroup(), pChannel->getGroup()), 1.0);
297 pChannel->getEngineBuffer()->bindWorkers(m_pWorkerScheduler);406 pChannelInfo->m_pBuffer = SampleUtil::alloc(MAX_BUFFER_LEN);
407 memset(pChannelInfo->m_pBuffer, 0, sizeof(CSAMPLE) * MAX_BUFFER_LEN);
408 m_channels.push_back(pChannelInfo);
409 pChannelInfo->m_pChannel->getEngineBuffer()->bindWorkers(m_pWorkerScheduler);
298410
299 // TODO(XXX) WARNING HUGE HACK ALERT In the case of 2-decks, this code hooks411 // TODO(XXX) WARNING HUGE HACK ALERT In the case of 2-decks, this code hooks
300 // the two EngineBuffers together so they can beat-sync off of each other.412 // the two EngineBuffers together so they can beat-sync off of each other.
301 // rryan 6/2010413 // rryan 6/2010
302 if (m_channels.length() == 2) {414 if (m_channels.length() == 2) {
303 EngineBuffer *pBuffer1 = m_channels[0]->getEngineBuffer();415 EngineBuffer *pBuffer1 = m_channels[0]->m_pChannel->getEngineBuffer();
304 EngineBuffer *pBuffer2 = m_channels[1]->getEngineBuffer();416 EngineBuffer *pBuffer2 = m_channels[1]->m_pChannel->getEngineBuffer();
305 pBuffer1->setOtherEngineBuffer(pBuffer2);417 pBuffer1->setOtherEngineBuffer(pBuffer2);
306 pBuffer2->setOtherEngineBuffer(pBuffer1);418 pBuffer2->setOtherEngineBuffer(pBuffer1);
307 }419 }
@@ -313,7 +425,7 @@
313425
314const CSAMPLE* EngineMaster::getChannelBuffer(unsigned int i) const {426const CSAMPLE* EngineMaster::getChannelBuffer(unsigned int i) const {
315 if (i < numChannels()) {427 if (i < numChannels()) {
316 return m_channelBuffers[i];428 return m_channels[i]->m_pBuffer;
317 }429 }
318 return NULL;430 return NULL;
319}431}
320432
=== modified file 'mixxx/src/engine/enginemaster.h'
--- mixxx/src/engine/enginemaster.h 2010-10-27 18:28:54 +0000
+++ mixxx/src/engine/enginemaster.h 2011-04-01 04:36:32 +0000
@@ -18,12 +18,14 @@
18#ifndef ENGINEMASTER_H18#ifndef ENGINEMASTER_H
19#define ENGINEMASTER_H19#define ENGINEMASTER_H
2020
21#include <QMap>
22
23#include "controlobject.h"
21#include "engine/engineobject.h"24#include "engine/engineobject.h"
22#include "engine/enginechannel.h"25#include "engine/enginechannel.h"
2326
24class EngineWorkerScheduler;27class EngineWorkerScheduler;
25class EngineBuffer;28class EngineBuffer;
26class EngineVolume;
27class EngineChannel;29class EngineChannel;
28class EngineClipping;30class EngineClipping;
29class EngineFlanger;31class EngineFlanger;
@@ -33,7 +35,6 @@
33class EngineVuMeter;35class EngineVuMeter;
34class ControlPotmeter;36class ControlPotmeter;
35class ControlPushButton;37class ControlPushButton;
36class ControlObject;
37class EngineVinylSoundEmu;38class EngineVinylSoundEmu;
38class EngineSideChain;39class EngineSideChain;
3940
@@ -55,20 +56,64 @@
55 // only call it before the engine has started mixing.56 // only call it before the engine has started mixing.
56 void addChannel(EngineChannel* pChannel);57 void addChannel(EngineChannel* pChannel);
5758
58 static double gainForOrientation(EngineChannel::ChannelOrientation orientation,59 static inline double gainForOrientation(EngineChannel::ChannelOrientation orientation,
59 double leftGain,60 double leftGain,
60 double centerGain,61 double centerGain,
61 double rightGain);62 double rightGain);
6263
63 private:64 private:
64 QList<EngineChannel*> m_channels;65 struct ChannelInfo {
66 EngineChannel* m_pChannel;
67 CSAMPLE* m_pBuffer;
68 ControlObject* m_pVolumeControl;
69 };
70
71 class GainCalculator {
72 public:
73 virtual double getGain(ChannelInfo* pChannelInfo) = 0;
74 };
75 class ConstantGainCalculator : public GainCalculator {
76 public:
77 inline double getGain(ChannelInfo* pChannelInfo) {
78 return m_dGain;
79 }
80 inline double setGain(double dGain) {
81 m_dGain = dGain;
82 }
83 private:
84 double m_dGain;
85 };
86 class OrientationVolumeGainCalculator : public GainCalculator {
87 public:
88 inline double getGain(ChannelInfo* pChannelInfo) {
89 double channelVolume = pChannelInfo->m_pVolumeControl->get();
90 double orientationGain = EngineMaster::gainForOrientation(
91 pChannelInfo->m_pChannel->getOrientation(),
92 m_dLeftGain, m_dCenterGain, m_dRightGain);
93 return m_dVolume * channelVolume * orientationGain;
94 }
95
96 inline void setGains(double dVolume, double leftGain, double centerGain, double rightGain) {
97 m_dVolume = dVolume;
98 m_dLeftGain = leftGain;
99 m_dCenterGain = centerGain;
100 m_dRightGain = rightGain;
101 }
102 private:
103 double m_dVolume, m_dLeftGain, m_dCenterGain, m_dRightGain;
104 };
105
106 void mixChannels(unsigned int channelBitvector, unsigned int maxChannels,
107 CSAMPLE* pOutput, unsigned int iBufferSize, GainCalculator* pGainCalculator);
108
109
110 QList<ChannelInfo*> m_channels;
65111
66 CSAMPLE *m_pMaster, *m_pHead;112 CSAMPLE *m_pMaster, *m_pHead;
67 QList<CSAMPLE*> m_channelBuffers;
68113
69 EngineWorkerScheduler *m_pWorkerScheduler;114 EngineWorkerScheduler *m_pWorkerScheduler;
70115
71 EngineVolume *volume, *head_volume;116 ControlObject *m_pMasterVolume, *m_pHeadVolume;
72 EngineClipping *clipping, *head_clipping;117 EngineClipping *clipping, *head_clipping;
73#ifdef __LADSPA__118#ifdef __LADSPA__
74 EngineLADSPA *ladspa;119 EngineLADSPA *ladspa;
@@ -78,6 +123,9 @@
78123
79 ControlPotmeter *crossfader, *head_mix,124 ControlPotmeter *crossfader, *head_mix,
80 *m_pBalance, *xFaderCurve, *xFaderCalibration;125 *m_pBalance, *xFaderCurve, *xFaderCalibration;
126
127 ConstantGainCalculator m_headphoneGain;
128 OrientationVolumeGainCalculator m_masterGain;
81};129};
82130
83#endif131#endif
84132
=== removed file 'mixxx/src/engine/enginevolume.cpp'
--- mixxx/src/engine/enginevolume.cpp 2010-06-02 21:26:29 +0000
+++ mixxx/src/engine/enginevolume.cpp 1970-01-01 00:00:00 +0000
@@ -1,42 +0,0 @@
1/***************************************************************************
2 enginevolume.cpp - description
3 -------------------
4 copyright : (C) 2002 by Tue and Ken Haste Andersen
5 email :
6***************************************************************************/
7
8/***************************************************************************
9* *
10* This program is free software; you can redistribute it and/or modify *
11* it under the terms of the GNU General Public License as published by *
12* the Free Software Foundation; either version 2 of the License, or *
13* (at your option) any later version. *
14* *
15***************************************************************************/
16
17#include "enginevolume.h"
18#include "controllogpotmeter.h"
19#include "configobject.h"
20#include "sampleutil.h"
21
22/*----------------------------------------------------------------
23 Volume effect.
24 ----------------------------------------------------------------*/
25EngineVolume::EngineVolume(ConfigKey key, double maxval)
26{
27 potmeter = new ControlLogpotmeter(key, maxval);
28}
29
30EngineVolume::~EngineVolume()
31{
32 delete potmeter;
33}
34
35void EngineVolume::process(const CSAMPLE * pIn, const CSAMPLE * pOut, const int iBufferSize)
36{
37 CSAMPLE * pOutput = (CSAMPLE *)pOut;
38 double volume = potmeter->get();
39
40 // SampleUtil handles aliased buffers and gains of 1 or 0.
41 SampleUtil::copyWithGain(pOutput, pIn, volume, iBufferSize);
42}
430
=== removed file 'mixxx/src/engine/enginevolume.h'
--- mixxx/src/engine/enginevolume.h 2009-01-24 04:39:32 +0000
+++ mixxx/src/engine/enginevolume.h 1970-01-01 00:00:00 +0000
@@ -1,36 +0,0 @@
1/***************************************************************************
2 enginevolume.h - description
3 -------------------
4 copyright : (C) 2002 by Tue and Ken Haste Andersen
5 email :
6 ***************************************************************************/
7
8/***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17#ifndef ENGINEVOLUME_H
18#define ENGINEVOLUME_H
19
20#include "engineobject.h"
21
22class ControlLogpotmeter;
23class ConfigKey;
24
25class EngineVolume : public EngineObject {
26public:
27 EngineVolume(ConfigKey key, double maxval=1.);
28 ~EngineVolume();
29 void process(const CSAMPLE *pIn, const CSAMPLE *pOut, const int iBufferSize);
30
31private:
32 CSAMPLE *buffer;
33 ControlLogpotmeter *potmeter;
34};
35
36#endif
370
=== modified file 'mixxx/src/sampleutil.cpp'
--- mixxx/src/sampleutil.cpp 2010-06-02 11:16:22 +0000
+++ mixxx/src/sampleutil.cpp 2011-04-01 04:36:32 +0000
@@ -489,6 +489,155 @@
489}489}
490490
491// static491// static
492void SampleUtil::copy4WithGain(CSAMPLE* pDest,
493 const CSAMPLE* pSrc1, CSAMPLE gain1,
494 const CSAMPLE* pSrc2, CSAMPLE gain2,
495 const CSAMPLE* pSrc3, CSAMPLE gain3,
496 const CSAMPLE* pSrc4, CSAMPLE gain4,
497 int iNumSamples) {
498 if (gain1 == 0.0f) {
499 return copy3WithGain(pDest, pSrc2, gain2, pSrc3, gain3, pSrc4, gain4, iNumSamples);
500 }
501 if (gain2 == 0.0f) {
502 return copy3WithGain(pDest, pSrc1, gain1, pSrc3, gain3, pSrc4, gain4, iNumSamples);
503 }
504 if (gain3 == 0.0f) {
505 return copy3WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc4, gain4, iNumSamples);
506 }
507 if (gain4 == 0.0f) {
508 return copy3WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc3, gain3, iNumSamples);
509 }
510 if (m_sOptimizationsOn) {
511 // TODO(rryan) implement SSE for this? worth it?
512 }
513 for (int i = 0; i < iNumSamples; ++i) {
514 pDest[i] = pSrc1[i] * gain1 + pSrc2[i] * gain2 + pSrc3[i] * gain3 + pSrc4[i] * gain4;
515 }
516}
517
518// static
519void SampleUtil::copy5WithGain(CSAMPLE* pDest,
520 const CSAMPLE* pSrc1, CSAMPLE gain1,
521 const CSAMPLE* pSrc2, CSAMPLE gain2,
522 const CSAMPLE* pSrc3, CSAMPLE gain3,
523 const CSAMPLE* pSrc4, CSAMPLE gain4,
524 const CSAMPLE* pSrc5, CSAMPLE gain5,
525 int iNumSamples) {
526 if (gain1 == 0.0f) {
527 return copy4WithGain(pDest, pSrc2, gain2, pSrc3, gain3, pSrc4, gain4, pSrc5, gain5, iNumSamples);
528 }
529 if (gain2 == 0.0f) {
530 return copy4WithGain(pDest, pSrc1, gain1, pSrc3, gain3, pSrc4, gain4, pSrc5, gain5, iNumSamples);
531 }
532 if (gain3 == 0.0f) {
533 return copy4WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc4, gain4, pSrc5, gain5, iNumSamples);
534 }
535 if (gain4 == 0.0f) {
536 return copy4WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc3, gain3, pSrc5, gain5, iNumSamples);
537 }
538 if (gain5 == 0.0f) {
539 return copy4WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc3, gain3, pSrc4, gain4, iNumSamples);
540 }
541
542 if (m_sOptimizationsOn) {
543 // TODO(rryan) implement SSE for this? worth it?
544 }
545
546 for (int i = 0; i < iNumSamples; ++i) {
547 pDest[i] = pSrc1[i] * gain1 + pSrc2[i] * gain2 + pSrc3[i] * gain3 + pSrc4[i] * gain4 + pSrc5[i] * gain5;
548 }
549}
550
551// static
552void SampleUtil::copy6WithGain(CSAMPLE* pDest,
553 const CSAMPLE* pSrc1, CSAMPLE gain1,
554 const CSAMPLE* pSrc2, CSAMPLE gain2,
555 const CSAMPLE* pSrc3, CSAMPLE gain3,
556 const CSAMPLE* pSrc4, CSAMPLE gain4,
557 const CSAMPLE* pSrc5, CSAMPLE gain5,
558 const CSAMPLE* pSrc6, CSAMPLE gain6,
559 int iNumSamples) {
560 if (gain1 == 0.0f) {
561 return copy5WithGain(pDest, pSrc2, gain2, pSrc3, gain3, pSrc4, gain4,
562 pSrc5, gain5, pSrc6, gain6, iNumSamples);
563 }
564 if (gain2 == 0.0f) {
565 return copy5WithGain(pDest, pSrc1, gain1, pSrc3, gain3, pSrc4, gain4,
566 pSrc5, gain5, pSrc6, gain6, iNumSamples);
567 }
568 if (gain3 == 0.0f) {
569 return copy5WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc4, gain4,
570 pSrc5, gain5, pSrc6, gain6, iNumSamples);
571 }
572 if (gain4 == 0.0f) {
573 return copy5WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc3, gain3,
574 pSrc5, gain5, pSrc6, gain6, iNumSamples);
575 }
576 if (gain5 == 0.0f) {
577 return copy5WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc3, gain3,
578 pSrc4, gain4, pSrc6, gain6, iNumSamples);
579 }
580 if (gain6 == 0.0f) {
581 return copy5WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc3, gain3,
582 pSrc4, gain4, pSrc5, gain5, iNumSamples);
583 }
584 if (m_sOptimizationsOn) {
585 // TODO(rryan) implement SSE for this? worth it?
586 }
587 for (int i = 0; i < iNumSamples; ++i) {
588 pDest[i] = pSrc1[i] * gain1 + pSrc2[i] * gain2 + pSrc3[i] * gain3 +
589 pSrc4[i] * gain4 + pSrc5[i] * gain5 + pSrc6[i] * gain6;
590 }
591}
592
593// static
594void SampleUtil::copy7WithGain(CSAMPLE* pDest,
595 const CSAMPLE* pSrc1, CSAMPLE gain1,
596 const CSAMPLE* pSrc2, CSAMPLE gain2,
597 const CSAMPLE* pSrc3, CSAMPLE gain3,
598 const CSAMPLE* pSrc4, CSAMPLE gain4,
599 const CSAMPLE* pSrc5, CSAMPLE gain5,
600 const CSAMPLE* pSrc6, CSAMPLE gain6,
601 const CSAMPLE* pSrc7, CSAMPLE gain7,
602 int iNumSamples) {
603 if (gain1 == 0.0f) {
604 return copy6WithGain(pDest, pSrc2, gain2, pSrc3, gain3, pSrc4, gain4,
605 pSrc5, gain5, pSrc6, gain6, pSrc7, gain7, iNumSamples);
606 }
607 if (gain2 == 0.0f) {
608 return copy6WithGain(pDest, pSrc1, gain1, pSrc3, gain3, pSrc4, gain4,
609 pSrc5, gain5, pSrc6, gain6, pSrc7, gain7, iNumSamples);
610 }
611 if (gain3 == 0.0f) {
612 return copy6WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc4, gain4,
613 pSrc5, gain5, pSrc6, gain6, pSrc7, gain7, iNumSamples);
614 }
615 if (gain4 == 0.0f) {
616 return copy6WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc3, gain3,
617 pSrc5, gain5, pSrc6, gain6, pSrc7, gain7, iNumSamples);
618 }
619 if (gain5 == 0.0f) {
620 return copy6WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc3, gain3,
621 pSrc4, gain4, pSrc6, gain6, pSrc7, gain7, iNumSamples);
622 }
623 if (gain6 == 0.0f) {
624 return copy6WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc3, gain3,
625 pSrc4, gain4, pSrc5, gain5, pSrc7, gain7, iNumSamples);
626 }
627 if (gain7 == 0.0f) {
628 return copy6WithGain(pDest, pSrc1, gain1, pSrc2, gain2, pSrc3, gain3,
629 pSrc4, gain4, pSrc5, gain5, pSrc6, gain6, iNumSamples);
630 }
631 if (m_sOptimizationsOn) {
632 // TODO(rryan) implement SSE for this? worth it?
633 }
634 for (int i = 0; i < iNumSamples; ++i) {
635 pDest[i] = pSrc1[i] * gain1 + pSrc2[i] * gain2 + pSrc3[i] * gain3 +
636 pSrc4[i] * gain4 + pSrc5[i] * gain5 + pSrc6[i] * gain6 + pSrc7[i] * gain7;
637 }
638}
639
640// static
492void SampleUtil::convert(CSAMPLE* pDest, const SAMPLE* pSrc,641void SampleUtil::convert(CSAMPLE* pDest, const SAMPLE* pSrc,
493 int iNumSamples) {642 int iNumSamples) {
494 if (m_sOptimizationsOn) {643 if (m_sOptimizationsOn) {
495644
=== modified file 'mixxx/src/sampleutil.h'
--- mixxx/src/sampleutil.h 2010-06-01 07:23:52 +0000
+++ mixxx/src/sampleutil.h 2011-04-01 04:36:32 +0000
@@ -73,21 +73,57 @@
73 static void copyWithGain(CSAMPLE* pDest, const CSAMPLE* pSrc,73 static void copyWithGain(CSAMPLE* pDest, const CSAMPLE* pSrc,
74 CSAMPLE gain, int iNumSamples);74 CSAMPLE gain, int iNumSamples);
7575
76 // Copy to pDest, each sample of pSrc1 multiplied by gain1 plus pSrc276 // Copies the sum of each channel, multiplied by its gain into pDest
77 // multiplied by gain2
78 static void copy2WithGain(CSAMPLE* pDest,77 static void copy2WithGain(CSAMPLE* pDest,
79 const CSAMPLE* pSrc1, CSAMPLE gain1,78 const CSAMPLE* pSrc1, CSAMPLE gain1,
80 const CSAMPLE* pSrc2, CSAMPLE gain2,79 const CSAMPLE* pSrc2, CSAMPLE gain2,
81 int iNumSamples);80 int iNumSamples);
8281
83 // Copy to pDest, each sample of pSrc1 multiplied by gain1 plus pSrc282 // Copies the sum of each channel, multiplied by its gain into pDest
84 // multiplied by gain2 plus pSrc3 multiplied by gain3
85 static void copy3WithGain(CSAMPLE* pDest,83 static void copy3WithGain(CSAMPLE* pDest,
86 const CSAMPLE* pSrc1, CSAMPLE gain1,84 const CSAMPLE* pSrc1, CSAMPLE gain1,
87 const CSAMPLE* pSrc2, CSAMPLE gain2,85 const CSAMPLE* pSrc2, CSAMPLE gain2,
88 const CSAMPLE* pSrc3, CSAMPLE gain3,86 const CSAMPLE* pSrc3, CSAMPLE gain3,
89 int iNumSamples);87 int iNumSamples);
9088
89 // Copies the sum of each channel, multiplied by its gain into pDest
90 static void copy4WithGain(CSAMPLE* pDest,
91 const CSAMPLE* pSrc1, CSAMPLE gain1,
92 const CSAMPLE* pSrc2, CSAMPLE gain2,
93 const CSAMPLE* pSrc3, CSAMPLE gain3,
94 const CSAMPLE* pSrc4, CSAMPLE gain4,
95 int iNumSamples);
96
97 // Copies the sum of each channel, multiplied by its gain into pDest
98 static void copy5WithGain(CSAMPLE* pDest,
99 const CSAMPLE* pSrc1, CSAMPLE gain1,
100 const CSAMPLE* pSrc2, CSAMPLE gain2,
101 const CSAMPLE* pSrc3, CSAMPLE gain3,
102 const CSAMPLE* pSrc4, CSAMPLE gain4,
103 const CSAMPLE* pSrc5, CSAMPLE gain5,
104 int iNumSamples);
105
106 // Copies the sum of each channel, multiplied by its gain into pDest
107 static void copy6WithGain(CSAMPLE* pDest,
108 const CSAMPLE* pSrc1, CSAMPLE gain1,
109 const CSAMPLE* pSrc2, CSAMPLE gain2,
110 const CSAMPLE* pSrc3, CSAMPLE gain3,
111 const CSAMPLE* pSrc4, CSAMPLE gain4,
112 const CSAMPLE* pSrc5, CSAMPLE gain5,
113 const CSAMPLE* pSrc6, CSAMPLE gain6,
114 int iNumSamples);
115
116 // Copies the sum of each channel, multiplied by its gain into pDest
117 static void copy7WithGain(CSAMPLE* pDest,
118 const CSAMPLE* pSrc1, CSAMPLE gain1,
119 const CSAMPLE* pSrc2, CSAMPLE gain2,
120 const CSAMPLE* pSrc3, CSAMPLE gain3,
121 const CSAMPLE* pSrc4, CSAMPLE gain4,
122 const CSAMPLE* pSrc5, CSAMPLE gain5,
123 const CSAMPLE* pSrc6, CSAMPLE gain6,
124 const CSAMPLE* pSrc7, CSAMPLE gain7,
125 int iNumSamples);
126
91 // Convert a buffer of SAMPLEs to a buffer of CSAMPLEs. Does not work127 // Convert a buffer of SAMPLEs to a buffer of CSAMPLEs. Does not work
92 // in-place! pDest and pSrc must not be aliased.128 // in-place! pDest and pSrc must not be aliased.
93 static void convert(CSAMPLE* pDest, const SAMPLE* pSrc, int iNumSamples);129 static void convert(CSAMPLE* pDest, const SAMPLE* pSrc, int iNumSamples);