~mixxxdevelopers/mixxx/features_autodj

« back to all changes in this revision

Viewing changes to mixxx/src/engine/enginemaster.cpp

  • Committer: RJ Ryan
  • Date: 2010-10-18 21:55:09 UTC
  • mfrom: (2194.1.60 mixxx-hydra)
  • Revision ID: rryan@mit.edu-20101018215509-xkj7uii9qwfa7bks
Merging lp:~mixxxdevelopers/mixxx/features_hydra into lp:mixxx! 

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
*                                                                         *
16
16
***************************************************************************/
17
17
 
 
18
#include <QDebug>
 
19
#include <QList>
 
20
#include <QPair>
 
21
 
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"
 
36
 
32
37
#ifdef __LADSPA__
33
38
#include "engineladspa.h"
34
39
#endif
35
 
#ifdef __VINYLCONTROL__
36
 
#include "enginevinylcontrol.h"
37
 
#endif
38
 
// #include "enginebuffermasterrate.h"
39
 
#include <QDebug>
 
40
 
40
41
 
41
42
EngineMaster::EngineMaster(ConfigObject<ConfigValue> * _config,
42
 
                           EngineBuffer * _buffer1, EngineBuffer * _buffer2,
43
 
                           EngineChannel * _channel1, EngineChannel * _channel2,
44
 
                           const char * group)
45
 
{
 
43
                           const char * group) {
 
44
 
46
45
    m_pWorkerScheduler = new EngineWorkerScheduler(this);
47
46
 
48
 
    buffer1 = _buffer1;
49
 
    buffer2 = _buffer2;
50
 
    channel1 = _channel1;
51
 
    channel2 = _channel2;
52
 
 
53
 
    // TODO(XXX) In features_hydra, stick this in addChannel()
54
 
    buffer1->bindWorkers(m_pWorkerScheduler);
55
 
    buffer2->bindWorkers(m_pWorkerScheduler);
56
 
 
57
 
    // Defaults
58
 
    master1 = true;
59
 
    master2 = true;
60
 
 
61
 
    // Flanger
62
 
    flanger = new EngineFlanger("[Flanger]");
 
47
    // Master sample rate
 
48
    ControlObject * sr = new ControlObject(ConfigKey(group, "samplerate"));
 
49
    sr->set(44100.);
 
50
 
 
51
    // Latency control
 
52
    new ControlObject(ConfigKey(group, "latency"));
 
53
 
 
54
    // Master rate
 
55
    new ControlPotmeter(ConfigKey(group, "rate"), -1.0, 1.0);
63
56
 
64
57
#ifdef __LADSPA__
65
58
    // LADSPA
69
62
    // Crossfader
70
63
    crossfader = new ControlPotmeter(ConfigKey(group, "crossfader"),-1.,1.);
71
64
 
72
 
    // Transform buttons
73
 
    transform1 = new ControlPushButton(ConfigKey("[Channel1]", "transform"));
74
 
    transform2 = new ControlPushButton(ConfigKey("[Channel2]", "transform"));
75
 
 
76
65
    // Balance
77
66
    m_pBalance = new ControlPotmeter(ConfigKey(group, "balance"), -1., 1.);
78
67
 
95
84
    // Headphone Clipping
96
85
    head_clipping = new EngineClipping("");
97
86
 
98
 
    // Channel Volume control:
99
 
    volume1 = new EngineVolume(ConfigKey("[Channel1]","volume"));
100
 
    volume2 = new EngineVolume(ConfigKey("[Channel2]","volume"));
101
 
 
102
 
    // Channel VU meter:
103
 
    vumeter1 = new EngineVuMeter("[Channel1]");
104
 
    vumeter2 = new EngineVuMeter("[Channel2]");
105
 
 
106
 
    // Vinyl sound emulation
107
 
    vinylsound1 = new EngineVinylSoundEmu(_config, "[Channel1]");
108
 
    vinylsound2 = new EngineVinylSoundEmu(_config, "[Channel2]");
109
 
 
110
 
    // Mute on active headphone
111
 
//     m_pControlObjectHeadphoneMute = new ControlObject(ConfigKey(group,"HeadphoneMute"));
112
 
 
113
 
    pfl1 = channel1->getPFL();
114
 
    pfl2 = channel2->getPFL();
115
 
 
116
 
    flanger1 = flanger->getButtonCh1();
117
 
    flanger2 = flanger->getButtonCh2();
118
 
 
119
 
    Q_ASSERT(flanger1);
120
 
    Q_ASSERT(flanger2);
121
 
 
122
 
//     m_pEngineBufferMasterRate = new EngineBufferMasterRate();
123
 
 
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];
129
 
 
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);
134
92
 
135
93
    sidechain = new EngineSideChain(_config);
136
94
 
137
 
        //X-Fader Setup
138
 
        xFaderCurve = new ControlPotmeter(ConfigKey("[Mixer Profile]", "xFaderCurve"), 0., 2.);
139
 
        xFaderCalibration = new ControlPotmeter(ConfigKey("[Mixer Profile]", "xFaderCalibration"), -2., 2.);
 
95
    //X-Fader Setup
 
96
    xFaderCurve = new ControlPotmeter(
 
97
        ConfigKey("[Mixer Profile]", "xFaderCurve"), 0., 2.);
 
98
    xFaderCalibration = new ControlPotmeter(
 
99
        ConfigKey("[Mixer Profile]", "xFaderCalibration"), -2., 2.);
140
100
}
141
101
 
142
102
EngineMaster::~EngineMaster()
150
110
    delete clipping;
151
111
    delete head_clipping;
152
112
    delete sidechain;
153
 
//     delete m_pControlObjectHeadphoneMute;
154
 
//     delete m_pEngineBufferMasterRate;
155
 
    delete [] m_pTemp1;
156
 
    delete [] m_pTemp2;
157
 
    delete [] m_pHead;
158
 
    delete [] m_pMaster;
 
113
 
 
114
    SampleUtil::free(m_pHead);
 
115
    SampleUtil::free(m_pMaster);
 
116
 
 
117
    QMutableListIterator<CSAMPLE*> buffer_it(m_channelBuffers);
 
118
    while (buffer_it.hasNext()) {
 
119
        CSAMPLE* buffer = buffer_it.next();
 
120
        buffer_it.remove();
 
121
        SampleUtil::free(buffer);
 
122
    }
 
123
 
 
124
    QMutableListIterator<EngineChannel*> channel_it(m_channels);
 
125
    while (channel_it.hasNext()) {
 
126
        EngineChannel* channel = channel_it.next();
 
127
        channel_it.remove();
 
128
        delete channel;
 
129
    }
159
130
 
160
131
}
161
132
 
162
133
void EngineMaster::setPitchIndpTimeStretch(bool b)
163
134
{
164
 
    buffer1->setPitchIndpTimeStretch(b);
165
 
    buffer2->setPitchIndpTimeStretch(b);
 
135
    QListIterator<EngineChannel*> channel_iter(m_channels);
 
136
 
 
137
    while (channel_iter.hasNext()) {
 
138
        EngineChannel* pChannel = channel_iter.next();
 
139
        pChannel->setPitchIndpTimeStretch(b);
 
140
    }
166
141
}
167
142
 
168
143
const CSAMPLE* EngineMaster::getMasterBuffer()
179
154
{
180
155
    CSAMPLE **pOutput = (CSAMPLE**)pOut;
181
156
 
182
 
    //
183
 
    // Process the buffer, the channels and the effects:
184
 
    //
185
 
 
186
 
    if (master1)
187
 
    {
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);
193
 
    }
194
 
 
195
 
    if (master2)
196
 
    {
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);
202
 
    }
203
 
 
204
 
    //
205
 
    // Output channel:
206
 
    //
207
 
 
208
 
    //
209
 
    // Headphone channel:
210
 
    //
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;
216
 
 
217
 
    if (master1 && pfl1->get()==1. && master2 && pfl2->get()==1.)
218
 
    {
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;
222
 
    }
223
 
    else if (master1 && pfl1->get()==1.)
224
 
    {
225
 
        //qDebug() << "ch 1";
226
 
        for (int i=0; i<iBufferSize; i++)
227
 
            m_pHead[i] = m_pTemp1[i]*chead_gain;
228
 
    }
229
 
    else if (master2 && pfl2->get()==1.)
230
 
    {
231
 
        //qDebug() << "ch 2";
232
 
        for (int i=0; i<iBufferSize; i++)
233
 
            m_pHead[i] = m_pTemp2[i]*chead_gain;
234
 
    }
235
 
    else
236
 
    {
237
 
        //qDebug() << "none";
238
 
        for (int i=0; i<iBufferSize; i++)
239
 
            m_pHead[i] = 0.;
240
 
    }
241
 
 
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);
247
 
 
 
157
    // Prepare each channel for output
 
158
 
 
159
    QList<CSAMPLE*> pflChannels;
 
160
    QList<QPair<CSAMPLE*, EngineChannel::ChannelOrientation> > masterChannels;
 
161
 
 
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);
 
166
 
 
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);
 
171
        }
 
172
 
 
173
        // Add the channel to the list of master output channels.
 
174
        masterChannels.push_back(
 
175
            QPair<CSAMPLE*, EngineChannel::ChannelOrientation>(
 
176
                buffer, channel->getOrientation()));
 
177
    }
 
178
 
 
179
    // Perform the master mix.
248
180
 
249
181
    // Crossfader and Transform buttons
250
 
        /*
251
 
    cf_val = crossfader->get();
252
 
    //qDebug() << "cf_val: " << cf_val;
 
182
    //set gain levels;
253
183
    float c1_gain, c2_gain;
254
 
    if (cf_val>0)
255
 
    {
256
 
        if (transform2->get()) {
257
 
            c1_gain = 1.;
258
 
            c2_gain = 1.-cf_val;
259
 
        } else {
260
 
            c1_gain = 1.-cf_val;
261
 
            c2_gain = 1.;
 
184
    EngineXfader::getXfadeGains(c1_gain, c2_gain,
 
185
                                crossfader->get(), xFaderCurve->get(),
 
186
                                xFaderCalibration->get());
 
187
 
 
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 =
 
192
                masterChannels[0];
 
193
        CSAMPLE* buffer = channel.first;
 
194
        EngineChannel::ChannelOrientation orientation = channel.second;
 
195
 
 
196
        // Apply gain
 
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 =
 
201
                masterChannels[0];
 
202
        QPair<CSAMPLE*, EngineChannel::ChannelOrientation> channel2 =
 
203
                masterChannels[1];
 
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);
 
210
 
 
211
        SampleUtil::copy2WithGain(m_pMaster,
 
212
                                  buffer1, gain1,
 
213
                                  buffer2, gain2,
 
214
                                  iBufferSize);
 
215
    } else {
 
216
        // Set m_pMaster to all 0s
 
217
        SampleUtil::applyGain(m_pMaster, 0.0f, iBufferSize);
 
218
 
 
219
        for (int i = 0; i < masterChannels.size(); ++i) {
 
220
            QPair<CSAMPLE*, EngineChannel::ChannelOrientation> channel =
 
221
                    masterChannels[i];
 
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);
262
226
        }
263
 
 
264
227
    }
265
 
    else
266
 
    {
267
 
        if (transform1->get()) {
268
 
            c1_gain = 1.+cf_val;
269
 
            c2_gain = 1.;
270
 
        } else {
271
 
            c1_gain = 1.;
272
 
            c2_gain = 1.+cf_val;
273
 
        }
274
 
    }*/
275
 
        //set gain levels;
276
 
        float c1_gain, c2_gain;
277
 
        EngineXfader::getXfadeGains(c1_gain, c2_gain, crossfader->get(), xFaderCurve->get(), xFaderCalibration->get());
278
 
 
279
 
    for (int i=0; i<iBufferSize; ++i)
280
 
        m_pMaster[i] = (m_pTemp1[i]*c1_gain) + (m_pTemp2[i]*c2_gain);
281
 
 
282
228
 
283
229
    // Master volume
284
230
    volume->process(m_pMaster, m_pMaster, iBufferSize);
285
231
 
286
232
#ifdef __LADSPA__
 
233
    // LADPSA master effects
287
234
    ladspa->process(m_pMaster, m_pMaster, iBufferSize);
288
235
#endif
289
236
 
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);
293
 
 
294
237
    // Clipping
295
238
    clipping->process(m_pMaster, m_pMaster, iBufferSize);
296
239
 
303
246
    else if (bal<0.)
304
247
        balright += bal;
305
248
 
306
 
    for (int i=0; i<iBufferSize; i+=2)
307
 
    {
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);
 
251
 
 
252
    // Update VU meter (it does not return anything). Needs to be here so that
 
253
    // master balance is reflected in the VU meter.
 
254
    if (vumeter != NULL)
 
255
        vumeter->process(m_pMaster, m_pMaster, iBufferSize);
 
256
 
 
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);
 
260
 
 
261
    // Compute headphone mix
 
262
 
 
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;
 
270
 
 
271
    // Set headphone to master with appropriate gain
 
272
    SampleUtil::copyWithGain(m_pHead, m_pMaster, cmaster_gain, iBufferSize);
 
273
 
 
274
    if (pflChannels.size() == 0) {
 
275
        // Do nothing
 
276
    } else if (pflChannels.size() == 1) {
 
277
        // Apply gain
 
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,
 
284
                                 buffer1, chead_gain,
 
285
                                 buffer2, chead_gain,
 
286
                                 iBufferSize);
 
287
    } else {
 
288
        for (int i = 0; i < pflChannels.size(); ++i) {
 
289
            CSAMPLE* buffer = pflChannels[i];
 
290
            SampleUtil::addWithGain(m_pHead, buffer, chead_gain, iBufferSize);
 
291
        }
311
292
    }
312
293
 
313
 
    // Add master to headphone
314
 
    for (int i=0; i<iBufferSize; i++)
315
 
        m_pHead[i] += m_pMaster[i]*cmaster_gain;
316
 
 
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);
320
297
 
321
 
    int j=0;
322
 
 
323
 
    // moved here to take balance into account -elysion
324
 
    // Update VU meter (it does not return anything):
325
 
    if (vumeter!=0)
326
 
        vumeter->process(m_pMaster, m_pMaster, iBufferSize);
327
 
 
328
 
 
329
 
    //Submit samples to the side chain to do shoutcasting, recording, etc.
330
 
    //(cpu intensive non-realtime tasks)
331
 
    sidechain->submitSamples(m_pMaster, iBufferSize);
332
 
 
333
 
    //Master/headphones interleaving is now done in SoundManager::requestBuffer() - Albert Nov 18/07
334
 
 
 
298
    //Master/headphones interleaving is now done in
 
299
    //SoundManager::requestBuffer() - Albert Nov 18/07
335
300
 
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();
339
304
}
340
305
 
 
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);
 
312
 
 
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.
 
315
    // rryan 6/2010
 
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);
 
321
    }
 
322
}
 
323
 
 
324
int EngineMaster::numChannels() {
 
325
    return m_channels.size();
 
326
}
 
327
 
 
328
const CSAMPLE* EngineMaster::getChannelBuffer(int i) {
 
329
    if (i >= 0 && i < numChannels()) {
 
330
        return m_channelBuffers[i];
 
331
    }
 
332
    return NULL;
 
333
}
 
334
 
 
335
// static
 
336
double EngineMaster::gainForOrientation(EngineChannel::ChannelOrientation orientation,
 
337
                                        double leftGain,
 
338
                                        double centerGain,
 
339
                                        double rightGain) {
 
340
    if (orientation == EngineChannel::LEFT) {
 
341
        return leftGain;
 
342
    } else if (orientation == EngineChannel::RIGHT) {
 
343
        return rightGain;
 
344
    }
 
345
    return centerGain;
 
346
}