16
16
***************************************************************************/
18
22
#include "controlpushbutton.h"
19
23
#include "configobject.h"
20
24
#include "controlpotmeter.h"
25
#include "enginebuffer.h"
21
26
#include "enginemaster.h"
22
27
#include "engine/engineworkerscheduler.h"
23
28
#include "enginebuffer.h"
24
29
#include "enginevolume.h"
25
30
#include "enginechannel.h"
26
31
#include "engineclipping.h"
27
#include "engineflanger.h"
28
32
#include "enginevumeter.h"
29
#include "enginevinylsoundemu.h"
30
33
#include "enginexfader.h"
31
34
#include "enginesidechain.h"
35
#include "sampleutil.h"
33
38
#include "engineladspa.h"
35
#ifdef __VINYLCONTROL__
36
#include "enginevinylcontrol.h"
38
// #include "enginebuffermasterrate.h"
41
42
EngineMaster::EngineMaster(ConfigObject<ConfigValue> * _config,
42
EngineBuffer * _buffer1, EngineBuffer * _buffer2,
43
EngineChannel * _channel1, EngineChannel * _channel2,
46
45
m_pWorkerScheduler = new EngineWorkerScheduler(this);
53
// TODO(XXX) In features_hydra, stick this in addChannel()
54
buffer1->bindWorkers(m_pWorkerScheduler);
55
buffer2->bindWorkers(m_pWorkerScheduler);
62
flanger = new EngineFlanger("[Flanger]");
48
ControlObject * sr = new ControlObject(ConfigKey(group, "samplerate"));
52
new ControlObject(ConfigKey(group, "latency"));
55
new ControlPotmeter(ConfigKey(group, "rate"), -1.0, 1.0);
95
84
// Headphone Clipping
96
85
head_clipping = new EngineClipping("");
98
// Channel Volume control:
99
volume1 = new EngineVolume(ConfigKey("[Channel1]","volume"));
100
volume2 = new EngineVolume(ConfigKey("[Channel2]","volume"));
103
vumeter1 = new EngineVuMeter("[Channel1]");
104
vumeter2 = new EngineVuMeter("[Channel2]");
106
// Vinyl sound emulation
107
vinylsound1 = new EngineVinylSoundEmu(_config, "[Channel1]");
108
vinylsound2 = new EngineVinylSoundEmu(_config, "[Channel2]");
110
// Mute on active headphone
111
// m_pControlObjectHeadphoneMute = new ControlObject(ConfigKey(group,"HeadphoneMute"));
113
pfl1 = channel1->getPFL();
114
pfl2 = channel2->getPFL();
116
flanger1 = flanger->getButtonCh1();
117
flanger2 = flanger->getButtonCh2();
122
// m_pEngineBufferMasterRate = new EngineBufferMasterRate();
124
87
// Allocate buffers
125
m_pTemp1 = new CSAMPLE[MAX_BUFFER_LEN];
126
m_pTemp2 = new CSAMPLE[MAX_BUFFER_LEN];
127
m_pHead = new CSAMPLE[MAX_BUFFER_LEN];
128
m_pMaster = new CSAMPLE[MAX_BUFFER_LEN];
130
memset(m_pTemp1, 0, sizeof(CSAMPLE) * MAX_BUFFER_LEN);
131
memset(m_pTemp2, 0, sizeof(CSAMPLE) * MAX_BUFFER_LEN);
88
m_pHead = SampleUtil::alloc(MAX_BUFFER_LEN);
89
m_pMaster = SampleUtil::alloc(MAX_BUFFER_LEN);
132
90
memset(m_pHead, 0, sizeof(CSAMPLE) * MAX_BUFFER_LEN);
133
91
memset(m_pMaster, 0, sizeof(CSAMPLE) * MAX_BUFFER_LEN);
135
93
sidechain = new EngineSideChain(_config);
138
xFaderCurve = new ControlPotmeter(ConfigKey("[Mixer Profile]", "xFaderCurve"), 0., 2.);
139
xFaderCalibration = new ControlPotmeter(ConfigKey("[Mixer Profile]", "xFaderCalibration"), -2., 2.);
96
xFaderCurve = new ControlPotmeter(
97
ConfigKey("[Mixer Profile]", "xFaderCurve"), 0., 2.);
98
xFaderCalibration = new ControlPotmeter(
99
ConfigKey("[Mixer Profile]", "xFaderCalibration"), -2., 2.);
142
102
EngineMaster::~EngineMaster()
180
155
CSAMPLE **pOutput = (CSAMPLE**)pOut;
183
// Process the buffer, the channels and the effects:
188
buffer1->process(0, m_pTemp1, iBufferSize);
189
vinylsound1->process(m_pTemp1, m_pTemp1, iBufferSize);
190
channel1->process(m_pTemp1, m_pTemp1, iBufferSize);
191
if (flanger1->get()==1. && flanger2->get()==0.)
192
flanger->process(m_pTemp1, m_pTemp1, iBufferSize);
197
buffer2->process(0, m_pTemp2, iBufferSize);
198
vinylsound2->process(m_pTemp2, m_pTemp2, iBufferSize);
199
channel2->process(m_pTemp2, m_pTemp2, iBufferSize);
200
if (flanger1->get()==0. && flanger2->get()==1.)
201
flanger->process(m_pTemp2, m_pTemp2, iBufferSize);
209
// Headphone channel:
211
// Head phone left/right mix
212
float cf_val = head_mix->get();
213
float chead_gain = 0.5*(-cf_val+1.);
214
float cmaster_gain = 0.5*(cf_val+1.);
215
//qDebug() << "head val " << cf_val << ", head " << chead_gain << ", master " << cmaster_gain;
217
if (master1 && pfl1->get()==1. && master2 && pfl2->get()==1.)
219
//qDebug() << "both";
220
for (int i=0; i<iBufferSize; i++)
221
m_pHead[i] = m_pTemp1[i]*chead_gain + m_pTemp2[i]*chead_gain;
223
else if (master1 && pfl1->get()==1.)
225
//qDebug() << "ch 1";
226
for (int i=0; i<iBufferSize; i++)
227
m_pHead[i] = m_pTemp1[i]*chead_gain;
229
else if (master2 && pfl2->get()==1.)
231
//qDebug() << "ch 2";
232
for (int i=0; i<iBufferSize; i++)
233
m_pHead[i] = m_pTemp2[i]*chead_gain;
237
//qDebug() << "none";
238
for (int i=0; i<iBufferSize; i++)
242
// Volume and vu meters for each channel
243
vumeter1->process(m_pTemp1, m_pTemp1, iBufferSize);
244
volume1->process(m_pTemp1, m_pTemp1, iBufferSize);
245
vumeter2->process(m_pTemp2, m_pTemp2, iBufferSize);
246
volume2->process(m_pTemp2, m_pTemp2, iBufferSize);
157
// Prepare each channel for output
159
QList<CSAMPLE*> pflChannels;
160
QList<QPair<CSAMPLE*, EngineChannel::ChannelOrientation> > masterChannels;
162
for (int channel_number = 0; channel_number < m_channels.size(); ++channel_number) {
163
EngineChannel* channel = m_channels[channel_number];
164
CSAMPLE* buffer = m_channelBuffers[channel_number];
165
channel->process(NULL, buffer, iBufferSize);
167
// If the channel is enabled for previewing in headphones, add it to a
168
// list of headphone channels.
169
if (channel->isPFL()) {
170
pflChannels.push_back(buffer);
173
// Add the channel to the list of master output channels.
174
masterChannels.push_back(
175
QPair<CSAMPLE*, EngineChannel::ChannelOrientation>(
176
buffer, channel->getOrientation()));
179
// Perform the master mix.
249
181
// Crossfader and Transform buttons
251
cf_val = crossfader->get();
252
//qDebug() << "cf_val: " << cf_val;
253
183
float c1_gain, c2_gain;
256
if (transform2->get()) {
184
EngineXfader::getXfadeGains(c1_gain, c2_gain,
185
crossfader->get(), xFaderCurve->get(),
186
xFaderCalibration->get());
188
if (masterChannels.size() == 0) {
189
SampleUtil::applyGain(m_pMaster, 0.0f, iBufferSize);
190
} else if (masterChannels.size() == 1) {
191
QPair<CSAMPLE*, EngineChannel::ChannelOrientation>& channel =
193
CSAMPLE* buffer = channel.first;
194
EngineChannel::ChannelOrientation orientation = channel.second;
197
double gain = gainForOrientation(orientation, c1_gain, 1.0f, c2_gain);
198
SampleUtil::copyWithGain(m_pMaster, buffer, gain, iBufferSize);
199
} else if (masterChannels.size() == 2) {
200
QPair<CSAMPLE*, EngineChannel::ChannelOrientation> channel1 =
202
QPair<CSAMPLE*, EngineChannel::ChannelOrientation> channel2 =
204
CSAMPLE* buffer1 = channel1.first;
205
CSAMPLE* buffer2 = channel2.first;
206
EngineChannel::ChannelOrientation orientation1 = channel1.second;
207
EngineChannel::ChannelOrientation orientation2 = channel2.second;
208
double gain1 = gainForOrientation(orientation1, c1_gain, 1.0f, c2_gain);
209
double gain2 = gainForOrientation(orientation2, c1_gain, 1.0f, c2_gain);
211
SampleUtil::copy2WithGain(m_pMaster,
216
// Set m_pMaster to all 0s
217
SampleUtil::applyGain(m_pMaster, 0.0f, iBufferSize);
219
for (int i = 0; i < masterChannels.size(); ++i) {
220
QPair<CSAMPLE*, EngineChannel::ChannelOrientation> channel =
222
CSAMPLE* buffer = channel.first;
223
EngineChannel::ChannelOrientation orientation = channel.second;
224
double gain = gainForOrientation(orientation, c1_gain, 1.0f, c2_gain);
225
SampleUtil::addWithGain(m_pMaster, buffer, gain, iBufferSize);
267
if (transform1->get()) {
276
float c1_gain, c2_gain;
277
EngineXfader::getXfadeGains(c1_gain, c2_gain, crossfader->get(), xFaderCurve->get(), xFaderCalibration->get());
279
for (int i=0; i<iBufferSize; ++i)
280
m_pMaster[i] = (m_pTemp1[i]*c1_gain) + (m_pTemp2[i]*c2_gain);
284
230
volume->process(m_pMaster, m_pMaster, iBufferSize);
286
232
#ifdef __LADSPA__
233
// LADPSA master effects
287
234
ladspa->process(m_pMaster, m_pMaster, iBufferSize);
290
// Process the flanger on master if flanger is enabled on both channels
291
if (flanger1->get()==1. && flanger2->get()==1.)
292
flanger->process(m_pMaster, m_pMaster, iBufferSize);
295
238
clipping->process(m_pMaster, m_pMaster, iBufferSize);
306
for (int i=0; i<iBufferSize; i+=2)
308
//Perform balancing on main out
309
m_pMaster[i ] = m_pMaster[i ]*balleft;
310
m_pMaster[i+1] = m_pMaster[i+1]*balright;
249
// Perform balancing on main out
250
SampleUtil::applyAlternatingGain(m_pMaster, balleft, balright, iBufferSize);
252
// Update VU meter (it does not return anything). Needs to be here so that
253
// master balance is reflected in the VU meter.
255
vumeter->process(m_pMaster, m_pMaster, iBufferSize);
257
//Submit master samples to the side chain to do shoutcasting, recording,
258
//etc. (cpu intensive non-realtime tasks)
259
sidechain->submitSamples(m_pMaster, iBufferSize);
261
// Compute headphone mix
263
// Head phone left/right mix
264
float cf_val = head_mix->get();
265
float chead_gain = 0.5*(-cf_val+1.);
266
float cmaster_gain = 0.5*(cf_val+1.);
267
// qDebug() << "head val " << cf_val
268
// << ", head " << chead_gain
269
// << ", master " << cmaster_gain;
271
// Set headphone to master with appropriate gain
272
SampleUtil::copyWithGain(m_pHead, m_pMaster, cmaster_gain, iBufferSize);
274
if (pflChannels.size() == 0) {
276
} else if (pflChannels.size() == 1) {
278
CSAMPLE* buffer = pflChannels[0];
279
SampleUtil::addWithGain(m_pHead, buffer, chead_gain, iBufferSize);
280
} else if (pflChannels.size() == 2) {
281
CSAMPLE* buffer1 = pflChannels[0];
282
CSAMPLE* buffer2 = pflChannels[1];
283
SampleUtil::add2WithGain(m_pHead,
288
for (int i = 0; i < pflChannels.size(); ++i) {
289
CSAMPLE* buffer = pflChannels[i];
290
SampleUtil::addWithGain(m_pHead, buffer, chead_gain, iBufferSize);
313
// Add master to headphone
314
for (int i=0; i<iBufferSize; i++)
315
m_pHead[i] += m_pMaster[i]*cmaster_gain;
317
294
// Head volume and clipping
318
295
head_volume->process(m_pHead, m_pHead, iBufferSize);
319
296
head_clipping->process(m_pHead, m_pHead, iBufferSize);
323
// moved here to take balance into account -elysion
324
// Update VU meter (it does not return anything):
326
vumeter->process(m_pMaster, m_pMaster, iBufferSize);
329
//Submit samples to the side chain to do shoutcasting, recording, etc.
330
//(cpu intensive non-realtime tasks)
331
sidechain->submitSamples(m_pMaster, iBufferSize);
333
//Master/headphones interleaving is now done in SoundManager::requestBuffer() - Albert Nov 18/07
298
//Master/headphones interleaving is now done in
299
//SoundManager::requestBuffer() - Albert Nov 18/07
336
301
// We're close to the end of the callback. Schedule the workers. Hopefully
337
302
// the work thread doesn't get scheduled between now and then.
338
303
m_pWorkerScheduler->runWorkers();
306
void EngineMaster::addChannel(EngineChannel* pChannel) {
307
CSAMPLE* pChannelBuffer = SampleUtil::alloc(MAX_BUFFER_LEN);
308
memset(pChannelBuffer, 0, sizeof(CSAMPLE) * MAX_BUFFER_LEN);
309
m_channelBuffers.push_back(pChannelBuffer);
310
m_channels.push_back(pChannel);
311
pChannel->getEngineBuffer()->bindWorkers(m_pWorkerScheduler);
313
// TODO(XXX) WARNING HUGE HACK ALERT In the case of 2-decks, this code hooks
314
// the two EngineBuffers together so they can beat-sync off of each other.
316
if (m_channels.length() == 2) {
317
EngineBuffer *pBuffer1 = m_channels[0]->getEngineBuffer();
318
EngineBuffer *pBuffer2 = m_channels[1]->getEngineBuffer();
319
pBuffer1->setOtherEngineBuffer(pBuffer2);
320
pBuffer2->setOtherEngineBuffer(pBuffer1);
324
int EngineMaster::numChannels() {
325
return m_channels.size();
328
const CSAMPLE* EngineMaster::getChannelBuffer(int i) {
329
if (i >= 0 && i < numChannels()) {
330
return m_channelBuffers[i];
336
double EngineMaster::gainForOrientation(EngineChannel::ChannelOrientation orientation,
340
if (orientation == EngineChannel::LEFT) {
342
} else if (orientation == EngineChannel::RIGHT) {