~ubuntu-branches/ubuntu/utopic/lmms/utopic

« back to all changes in this revision

Viewing changes to src/core/FxMixer.cpp

  • Committer: Package Import Robot
  • Author(s): Israel Dahl
  • Date: 2014-04-30 18:49:37 UTC
  • mfrom: (1.1.15)
  • Revision ID: package-import@ubuntu.com-20140430184937-hozuuxonlbshciya
Tags: 1.0.1-src-0ubuntu1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 *
23
23
 */
24
24
 
 
25
 
25
26
#include <QtXml/QDomElement>
26
27
 
27
28
#include "FxMixer.h"
28
 
#include "MixerWorkerThread.h"
29
 
#include "MixHelpers.h"
30
29
#include "Effect.h"
31
30
#include "song.h"
32
31
 
33
 
#include "InstrumentTrack.h"
34
 
#include "bb_track_container.h"
35
 
 
36
 
 
37
 
FxChannel::FxChannel( int idx, Model * _parent ) :
 
32
 
 
33
FxChannel::FxChannel( Model * _parent ) :
38
34
        m_fxChain( NULL ),
 
35
        m_used( false ),
39
36
        m_stillRunning( false ),
40
37
        m_peakLeft( 0.0f ),
41
38
        m_peakRight( 0.0f ),
43
40
        m_muteModel( false, _parent ),
44
41
        m_volumeModel( 1.0, 0.0, 2.0, 0.01, _parent ),
45
42
        m_name(),
46
 
        m_lock(),
47
 
        m_channelIndex( idx ),
48
 
        m_queued( false )
 
43
        m_lock()
49
44
{
50
45
        engine::mixer()->clearAudioBuffer( m_buffer,
51
46
                                        engine::mixer()->framesPerPeriod() );
62
57
 
63
58
 
64
59
 
65
 
void FxChannel::doProcessing( sampleFrame * _buf )
66
 
{
67
 
        FxMixer * fxm = engine::fxMixer();
68
 
        const fpp_t fpp = engine::mixer()->framesPerPeriod();
69
 
 
70
 
        // <tobydox> ignore the passed _buf
71
 
        // <tobydox> always use m_buffer
72
 
        // <tobydox> this is just an auxilliary buffer if doProcessing()
73
 
        //                       needs one for processing while running
74
 
        // <tobydox> particularly important for playHandles, so Instruments
75
 
        //                       can operate on this buffer the whole time
76
 
        // <tobydox> this improves cache hit rate
77
 
        _buf = m_buffer;
78
 
 
79
 
        // SMF: OK, due to the fact, that the data from the audio-tracks has been
80
 
        //                      written into our buffer already, all which needs to be done at this
81
 
        //                      stage is to process inter-channel sends. I really don't like the idea
82
 
        //                      of using threads for this -- it just doesn't make any sense and wastes
83
 
        //                      cpu-cylces... so I just go through every child of this channel and
84
 
        //                      call the acc. doProcessing() directly.
85
 
 
86
 
        if( m_muteModel.value() == false )
87
 
        {
88
 
                // OK, we are not muted, so we go recursively through all the channels
89
 
                // which send to us (our children)...
90
 
                foreach( fx_ch_t senderIndex, m_receives )
91
 
                {
92
 
                        FxChannel * sender = fxm->effectChannel( senderIndex );
93
 
 
94
 
                        // wait for the sender job - either it's just been queued yet,
95
 
                        // then ThreadableJob::process() will process it now within this
96
 
                        // thread - otherwise it has been is is being processed by another
97
 
                        // thread and we just have to wait for it to finish
98
 
                        while( sender->state() != ThreadableJob::Done )
99
 
                        {
100
 
                                sender->process();
101
 
                        }
102
 
 
103
 
                        // get the send level...
104
 
                        const float amt =
105
 
                                fxm->channelSendModel( senderIndex, m_channelIndex )->value();
106
 
 
107
 
                        // mix it's output with this one's output
108
 
                        sampleFrame * ch_buf = sender->m_buffer;
109
 
                        const float v = sender->m_volumeModel.value() * amt;
110
 
                        for( f_cnt_t f = 0; f < fpp; ++f )
111
 
                        {
112
 
                                _buf[f][0] += ch_buf[f][0] * v;
113
 
                                _buf[f][1] += ch_buf[f][1] * v;
114
 
                        }
115
 
                }
116
 
        }
117
 
 
118
 
        const float v = m_volumeModel.value();
119
 
 
120
 
        m_fxChain.startRunning();
121
 
        m_stillRunning = m_fxChain.processAudioBuffer( _buf, fpp, true );
122
 
        m_peakLeft = qMax( m_peakLeft, engine::mixer()->peakValueLeft( _buf, fpp ) * v );
123
 
        m_peakRight = qMax( m_peakRight, engine::mixer()->peakValueRight( _buf, fpp ) * v );
124
 
}
125
 
 
126
60
 
127
61
 
128
62
FxMixer::FxMixer() :
129
63
        JournallingObject(),
130
 
        Model( NULL ),
131
 
        m_fxChannels()
 
64
        Model( NULL )
132
65
{
133
 
        // create master channel
134
 
        createChannel();
 
66
        for( int i = 0; i < NumFxChannels+1; ++i )
 
67
        {
 
68
                m_fxChannels[i] = new FxChannel( this );
 
69
        }
 
70
        // reset name etc.
 
71
        clear();
135
72
}
136
73
 
137
74
 
138
75
 
 
76
 
139
77
FxMixer::~FxMixer()
140
78
{
141
 
        for( int i = 0; i < m_fxChannels.size(); ++i )
 
79
        for( int i = 0; i < NumFxChannels+1; ++i )
142
80
        {
143
 
                for( int j = 0; j < m_fxChannels[i]->m_sendAmount.size(); ++j)
144
 
                {
145
 
                        delete m_fxChannels[i]->m_sendAmount[j];
146
 
                }
147
81
                delete m_fxChannels[i];
148
82
        }
149
83
}
150
84
 
151
85
 
152
86
 
153
 
int FxMixer::createChannel()
154
 
{
155
 
        const int index = m_fxChannels.size();
156
 
        // create new channel
157
 
        m_fxChannels.push_back( new FxChannel( index, this ) );
158
 
 
159
 
        // reset channel state
160
 
        clearChannel( index );
161
 
 
162
 
        return index;
163
 
}
164
 
 
165
 
 
166
 
void FxMixer::deleteChannel(int index)
167
 
{
168
 
        m_fxChannels[index]->m_lock.lock();
169
 
 
170
 
        // go through every instrument and adjust for the channel index change
171
 
        TrackContainer::TrackList tracks;
172
 
        tracks += engine::getSong()->tracks();
173
 
        tracks += engine::getBBTrackContainer()->tracks();
174
 
 
175
 
        foreach( track* t, tracks )
176
 
        {
177
 
                if( t->type() == track::InstrumentTrack )
178
 
                {
179
 
                        InstrumentTrack* inst = dynamic_cast<InstrumentTrack *>( t );
180
 
                        int val = inst->effectChannelModel()->value(0);
181
 
                        if( val == index )
182
 
                        {
183
 
                                // we are deleting this track's fx send
184
 
                                // send to master
185
 
                                inst->effectChannelModel()->setValue(0);
186
 
                        }
187
 
                        else if( val > index )
188
 
                        {
189
 
                                // subtract 1 to make up for the missing channel
190
 
                                inst->effectChannelModel()->setValue(val-1);
191
 
                        }
192
 
                }
193
 
        }
194
 
 
195
 
        // delete all of this channel's sends and receives
196
 
        for(int i=0; i<m_fxChannels[index]->m_sends.size(); ++i)
197
 
        {
198
 
                deleteChannelSend(index, m_fxChannels[index]->m_sends[i]);
199
 
        }
200
 
        for(int i=0; i<m_fxChannels[index]->m_receives.size(); ++i)
201
 
        {
202
 
                deleteChannelSend(m_fxChannels[index]->m_receives[i], index);
203
 
        }
204
 
 
205
 
        for(int i=0; i<m_fxChannels.size(); ++i)
206
 
        {
207
 
                // for every send/receive, adjust for the channel index change
208
 
                for(int j=0; j<m_fxChannels[i]->m_sends.size(); ++j)
209
 
                {
210
 
                        if( m_fxChannels[i]->m_sends[j] > index )
211
 
                        {
212
 
                                // subtract 1 to make up for the missing channel
213
 
                                --m_fxChannels[i]->m_sends[j];
214
 
                        }
215
 
                }
216
 
                for(int j=0; j<m_fxChannels[i]->m_receives.size(); ++j)
217
 
                {
218
 
                        if( m_fxChannels[i]->m_receives[j] > index )
219
 
                        {
220
 
                                // subtract 1 to make up for the missing channel
221
 
                                --m_fxChannels[i]->m_receives[j];
222
 
                        }
223
 
                }
224
 
 
225
 
        }
226
 
 
227
 
        // actually delete the channel
228
 
        delete m_fxChannels[index];
229
 
        m_fxChannels.remove(index);
230
 
}
231
 
 
232
 
 
233
 
 
234
 
void FxMixer::moveChannelLeft(int index)
235
 
{
236
 
        // can't move master or first channel
237
 
        if( index <= 1 || index >= m_fxChannels.size() )
238
 
        {
239
 
                return;
240
 
        }
241
 
 
242
 
        // channels to swap
243
 
        int a = index - 1, b = index;
244
 
 
245
 
        // go through every instrument and adjust for the channel index change
246
 
        QVector<track *> songTrackList = engine::getSong()->tracks();
247
 
        QVector<track *> bbTrackList = engine::getBBTrackContainer()->tracks();
248
 
 
249
 
        QVector<track *> trackLists[] = {songTrackList, bbTrackList};
250
 
        for(int tl=0; tl<2; ++tl)
251
 
        {
252
 
                QVector<track *> trackList = trackLists[tl];
253
 
                for(int i=0; i<trackList.size(); ++i)
254
 
                {
255
 
                        if( trackList[i]->type() == track::InstrumentTrack )
256
 
                        {
257
 
                                InstrumentTrack * inst = (InstrumentTrack *) trackList[i];
258
 
                                int val = inst->effectChannelModel()->value(0);
259
 
                                if( val == a )
260
 
                                {
261
 
                                        inst->effectChannelModel()->setValue(b);
262
 
                                }
263
 
                                else if( val == b )
264
 
                                {
265
 
                                        inst->effectChannelModel()->setValue(a);
266
 
                                }
267
 
 
268
 
                        }
269
 
                }
270
 
        }
271
 
 
272
 
        for(int i=0; i<m_fxChannels.size(); ++i)
273
 
        {
274
 
                // for every send/receive, adjust for the channel index change
275
 
                for(int j=0; j<m_fxChannels[i]->m_sends.size(); ++j)
276
 
                {
277
 
                        if( m_fxChannels[i]->m_sends[j] == a )
278
 
                        {
279
 
                                m_fxChannels[i]->m_sends[j] = b;
280
 
                        }
281
 
                        else if( m_fxChannels[i]->m_sends[j] == b )
282
 
                        {
283
 
                                m_fxChannels[i]->m_sends[j] = a;
284
 
                        }
285
 
                }
286
 
                for(int j=0; j<m_fxChannels[i]->m_receives.size(); ++j)
287
 
                {
288
 
                        if( m_fxChannels[i]->m_receives[j] == a )
289
 
                        {
290
 
                                m_fxChannels[i]->m_receives[j] = b;
291
 
                        }
292
 
                        else if( m_fxChannels[i]->m_receives[j] == b )
293
 
                        {
294
 
                                m_fxChannels[i]->m_receives[j] = a;
295
 
                        }
296
 
                }
297
 
        }
298
 
 
299
 
        // actually do the swap
300
 
        FxChannel * tmpChannel = m_fxChannels[a];
301
 
        m_fxChannels[a] = m_fxChannels[b];
302
 
        m_fxChannels[b] = tmpChannel;
303
 
}
304
 
 
305
 
 
306
 
 
307
 
void FxMixer::moveChannelRight(int index)
308
 
{
309
 
        moveChannelLeft(index+1);
310
 
}
311
 
 
312
 
 
313
 
 
314
 
void FxMixer::createChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel,
315
 
                                                                float amount)
316
 
{
317
 
        // find the existing connection
318
 
        FxChannel * from = m_fxChannels[fromChannel];
319
 
        for(int i=0; i<from->m_sends.size(); ++i){
320
 
                if( from->m_sends[i] == toChannel )
321
 
                {
322
 
                        // simply adjust the amount
323
 
                        from->m_sendAmount[i]->setValue(amount);
324
 
                        return;
325
 
                }
326
 
        }
327
 
 
328
 
        // connection does not exist. create a new one
329
 
 
330
 
        // add to from's sends
331
 
        from->m_sends.push_back(toChannel);
332
 
        from->m_sendAmount.push_back(new FloatModel(amount, 0, 1, 0.001, NULL,
333
 
                                                                                                tr("Amount to send")));
334
 
 
335
 
        // add to to's receives
336
 
        m_fxChannels[toChannel]->m_receives.push_back(fromChannel);
337
 
 
338
 
}
339
 
 
340
 
 
341
 
 
342
 
// delete the connection made by createChannelSend
343
 
void FxMixer::deleteChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel)
344
 
{
345
 
        // delete the send
346
 
        FxChannel * from = m_fxChannels[fromChannel];
347
 
        FxChannel * to   = m_fxChannels[toChannel];
348
 
 
349
 
        // find and delete the send entry
350
 
        for(int i=0; i<from->m_sends.size(); ++i) {
351
 
                if( from->m_sends[i] == toChannel )
352
 
                {
353
 
                        // delete this index
354
 
                        delete from->m_sendAmount[i];
355
 
                        from->m_sendAmount.remove(i);
356
 
                        from->m_sends.remove(i);
357
 
                        break;
358
 
                }
359
 
        }
360
 
 
361
 
        // find and delete the receive entry
362
 
        for(int i=0; i<to->m_receives.size(); ++i)
363
 
        {
364
 
                if( to->m_receives[i] == fromChannel )
365
 
                {
366
 
                        // delete this index
367
 
                        to->m_receives.remove(i);
368
 
                        break;
369
 
                }
370
 
        }
371
 
}
372
 
 
373
 
 
374
 
bool FxMixer::isInfiniteLoop(fx_ch_t sendFrom, fx_ch_t sendTo) {
375
 
        // can't send master to anything
376
 
        if( sendFrom == 0 ) return true;
377
 
 
378
 
        // can't send channel to itself
379
 
        if( sendFrom == sendTo ) return true;
380
 
 
381
 
        // follow sendTo's outputs recursively looking for something that sends
382
 
        // to sendFrom
383
 
        for(int i=0; i<m_fxChannels[sendTo]->m_sends.size(); ++i)
384
 
        {
385
 
                if( isInfiniteLoop( sendFrom, m_fxChannels[sendTo]->m_sends[i] ) )
386
 
                {
387
 
                        return true;
388
 
                }
389
 
        }
390
 
 
391
 
        return false;
392
 
}
393
 
 
394
 
 
395
 
// how much does fromChannel send its output to the input of toChannel?
396
 
FloatModel * FxMixer::channelSendModel(fx_ch_t fromChannel, fx_ch_t toChannel)
397
 
{
398
 
        FxChannel * from = m_fxChannels[fromChannel];
399
 
        for(int i=0; i<from->m_sends.size(); ++i){
400
 
                if( from->m_sends[i] == toChannel )
401
 
                        return from->m_sendAmount[i];
402
 
        }
403
 
        return NULL;
404
 
}
405
 
 
406
 
 
407
87
 
408
88
void FxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch )
409
89
{
410
 
        // SMF: it seems like here the track-channels are mixed in... but from where
411
 
        //                      is this called and when and why...?!?
412
 
        //
413
 
        //                      OK, found it (git grep is your friend...): This is the next part,
414
 
        //                      where there is a mix between push and pull model inside the core, as
415
 
        //                      the audio-tracks *push* their data into the fx-channels hopefully just
416
 
        //                      before the Mixer-Channels are processed... Sorry to say this: but this
417
 
        //                      took me senseless hours to find out and is silly, too...
418
 
 
419
90
        if( m_fxChannels[_ch]->m_muteModel.value() == false )
420
91
        {
421
92
                m_fxChannels[_ch]->m_lock.lock();
422
 
                MixHelpers::add( m_fxChannels[_ch]->m_buffer, _buf, engine::mixer()->framesPerPeriod() );
 
93
                sampleFrame * buf = m_fxChannels[_ch]->m_buffer;
 
94
                for( f_cnt_t f = 0; f < engine::mixer()->framesPerPeriod(); ++f )
 
95
                {
 
96
                        buf[f][0] += _buf[f][0];
 
97
                        buf[f][1] += _buf[f][1];
 
98
                }
 
99
                m_fxChannels[_ch]->m_used = true;
423
100
                m_fxChannels[_ch]->m_lock.unlock();
424
101
        }
425
102
}
427
104
 
428
105
 
429
106
 
 
107
void FxMixer::processChannel( fx_ch_t _ch, sampleFrame * _buf )
 
108
{
 
109
        if( m_fxChannels[_ch]->m_muteModel.value() == false &&
 
110
                ( m_fxChannels[_ch]->m_used || m_fxChannels[_ch]->m_stillRunning || _ch == 0 ) )
 
111
        {
 
112
                if( _buf == NULL )
 
113
                {
 
114
                        _buf = m_fxChannels[_ch]->m_buffer;
 
115
                }
 
116
                const fpp_t f = engine::mixer()->framesPerPeriod();
 
117
 
 
118
                // only start effects if sound was mixed to this FX channel before
 
119
                if( m_fxChannels[_ch]->m_used )
 
120
                {
 
121
                        m_fxChannels[_ch]->m_fxChain.startRunning();
 
122
                }
 
123
 
 
124
                // process FX chain
 
125
                m_fxChannels[_ch]->m_stillRunning = m_fxChannels[_ch]->m_fxChain.processAudioBuffer( _buf, f, m_fxChannels[_ch]->m_used );
 
126
 
 
127
                float peakLeft = engine::mixer()->peakValueLeft( _buf, f ) * m_fxChannels[_ch]->m_volumeModel.value();
 
128
                float peakRight = engine::mixer()->peakValueRight( _buf, f ) * m_fxChannels[_ch]->m_volumeModel.value();
 
129
 
 
130
                if( peakLeft > m_fxChannels[_ch]->m_peakLeft )
 
131
                {
 
132
                        m_fxChannels[_ch]->m_peakLeft = peakLeft;
 
133
                }
 
134
                if( peakRight > m_fxChannels[_ch]->m_peakRight )
 
135
                {
 
136
                        m_fxChannels[_ch]->m_peakRight = peakRight;
 
137
                }
 
138
 
 
139
                m_fxChannels[_ch]->m_used = true;
 
140
        }
 
141
        else
 
142
        {
 
143
                m_fxChannels[_ch]->m_peakLeft = m_fxChannels[_ch]->m_peakRight = 0.0f; 
 
144
        }
 
145
}
 
146
 
 
147
 
 
148
 
 
149
 
430
150
void FxMixer::prepareMasterMix()
431
151
{
432
152
        engine::mixer()->clearAudioBuffer( m_fxChannels[0]->m_buffer,
435
155
 
436
156
 
437
157
 
438
 
void FxMixer::addChannelLeaf( int _ch, sampleFrame * _buf )
439
 
{
440
 
        FxChannel * thisCh = m_fxChannels[_ch];
441
 
 
442
 
        // if we're muted or this channel is seen already, discount it
443
 
        if( thisCh->m_queued )
444
 
        {
445
 
                return;
446
 
        }
447
 
 
448
 
        foreach( const int senderIndex, thisCh->m_receives )
449
 
        {
450
 
                addChannelLeaf( senderIndex, _buf );
451
 
        }
452
 
 
453
 
        // add this channel to job list
454
 
        thisCh->m_queued = true;
455
 
        MixerWorkerThread::addJob( thisCh );
456
 
}
457
 
 
458
 
 
459
158
 
460
159
void FxMixer::masterMix( sampleFrame * _buf )
461
160
{
462
161
        const int fpp = engine::mixer()->framesPerPeriod();
463
 
 
464
 
        // recursively loop through channel dependency chain
465
 
        // and add all channels to job list that have no dependencies
466
 
        // when the channel completes it will check its parent to see if it needs
467
 
        // to be processed.
468
 
        MixerWorkerThread::resetJobQueue( MixerWorkerThread::JobQueue::Dynamic );
469
 
        addChannelLeaf( 0, _buf );
470
 
        while( m_fxChannels[0]->state() != ThreadableJob::Done )
471
 
        {
472
 
                MixerWorkerThread::startAndWaitForJobs();
473
 
        }
474
 
        //m_fxChannels[0]->doProcessing( NULL );
 
162
        memcpy( _buf, m_fxChannels[0]->m_buffer, sizeof( sampleFrame ) * fpp );
 
163
 
 
164
        for( int i = 1; i < NumFxChannels+1; ++i )
 
165
        {
 
166
                if( m_fxChannels[i]->m_used )
 
167
                {
 
168
                        sampleFrame * ch_buf = m_fxChannels[i]->m_buffer;
 
169
                        const float v = m_fxChannels[i]->m_volumeModel.value();
 
170
                        for( f_cnt_t f = 0; f < fpp; ++f )
 
171
                        {
 
172
                                _buf[f][0] += ch_buf[f][0] * v;
 
173
                                _buf[f][1] += ch_buf[f][1] * v;
 
174
                        }
 
175
                        engine::mixer()->clearAudioBuffer( ch_buf,
 
176
                                        engine::mixer()->framesPerPeriod() );
 
177
                        m_fxChannels[i]->m_used = false;
 
178
                }
 
179
        }
 
180
 
 
181
        processChannel( 0, _buf );
 
182
 
 
183
        if( m_fxChannels[0]->m_muteModel.value() )
 
184
        {
 
185
                engine::mixer()->clearAudioBuffer( _buf,
 
186
                                        engine::mixer()->framesPerPeriod() );
 
187
                return;
 
188
        }
475
189
 
476
190
        const float v = m_fxChannels[0]->m_volumeModel.value();
477
 
        MixHelpers::addMultiplied( _buf, m_fxChannels[0]->m_buffer, v, fpp );
 
191
        for( f_cnt_t f = 0; f < engine::mixer()->framesPerPeriod(); ++f )
 
192
        {
 
193
                _buf[f][0] *= v;
 
194
                _buf[f][1] *= v;
 
195
        }
478
196
 
479
197
        m_fxChannels[0]->m_peakLeft *= engine::mixer()->masterGain();
480
198
        m_fxChannels[0]->m_peakRight *= engine::mixer()->masterGain();
481
 
 
482
 
        // clear all channel buffers and
483
 
        // reset channel process state
484
 
        for( int i = 0; i < numChannels(); ++i)
485
 
        {
486
 
                engine::mixer()->clearAudioBuffer( m_fxChannels[i]->m_buffer, engine::mixer()->framesPerPeriod() );
487
 
                m_fxChannels[i]->reset();
488
 
                m_fxChannels[i]->m_queued = false;
489
 
        }
490
199
}
491
200
 
492
201
 
494
203
 
495
204
void FxMixer::clear()
496
205
{
497
 
        while( m_fxChannels.size() > 1 )
498
 
        {
499
 
                deleteChannel(1);
500
 
        }
501
 
 
502
 
        clearChannel(0);
503
 
}
504
 
 
505
 
 
506
 
 
507
 
void FxMixer::clearChannel(fx_ch_t index)
508
 
{
509
 
        FxChannel * ch = m_fxChannels[index];
510
 
        ch->m_fxChain.clear();
511
 
        ch->m_volumeModel.setValue( 1.0f );
512
 
        ch->m_muteModel.setValue( false );
513
 
        ch->m_name = ( index == 0 ) ? tr( "Master" ) : tr( "FX %1" ).arg( index );
514
 
        ch->m_volumeModel.setDisplayName(ch->m_name );
515
 
 
516
 
        // send only to master
517
 
        if( index > 0)
518
 
        {
519
 
                // delete existing sends
520
 
                for( int i=0; i<ch->m_sends.size(); ++i)
521
 
                {
522
 
                        deleteChannelSend(index, ch->m_sends[i]);
523
 
                }
524
 
 
525
 
                // add send to master
526
 
                createChannelSend(index, 0);
527
 
        }
528
 
 
529
 
        // delete receives
530
 
        for( int i=0; i<ch->m_receives.size(); ++i)
531
 
        {
532
 
                deleteChannelSend(ch->m_receives[i], index);
533
 
        }
534
 
 
535
 
}
 
206
        for( int i = 0; i <= NumFxChannels; ++i )
 
207
        {
 
208
                m_fxChannels[i]->m_fxChain.clear();
 
209
                m_fxChannels[i]->m_volumeModel.setValue( 1.0f );
 
210
                m_fxChannels[i]->m_muteModel.setValue( false );
 
211
                m_fxChannels[i]->m_name = ( i == 0 ) ?
 
212
                                tr( "Master" ) : tr( "FX %1" ).arg( i );
 
213
                m_fxChannels[i]->m_volumeModel.setDisplayName( 
 
214
                                m_fxChannels[i]->m_name );
 
215
 
 
216
        }
 
217
}
 
218
 
 
219
 
 
220
 
536
221
 
537
222
void FxMixer::saveSettings( QDomDocument & _doc, QDomElement & _this )
538
223
{
539
 
        for( int i = 0; i < m_fxChannels.size(); ++i )
 
224
        for( int i = 0; i <= NumFxChannels; ++i )
540
225
        {
541
 
                FxChannel * ch = m_fxChannels[i];
542
 
 
543
226
                QDomElement fxch = _doc.createElement( QString( "fxchannel" ) );
544
227
                _this.appendChild( fxch );
545
 
 
546
 
                ch->m_fxChain.saveState( _doc, fxch );
547
 
                ch->m_volumeModel.saveSettings( _doc, fxch, "volume" );
548
 
                ch->m_muteModel.saveSettings( _doc, fxch, "muted" );
 
228
                m_fxChannels[i]->m_fxChain.saveState( _doc, fxch );
 
229
                m_fxChannels[i]->m_volumeModel.saveSettings( _doc, fxch,
 
230
                                                                "volume" );
 
231
                m_fxChannels[i]->m_muteModel.saveSettings( _doc, fxch,
 
232
                                                                "muted" );
549
233
                fxch.setAttribute( "num", i );
550
 
                fxch.setAttribute( "name", ch->m_name );
551
 
 
552
 
                // add the channel sends
553
 
                for( int si = 0; si < ch->m_sends.size(); ++si )
554
 
                {
555
 
                        QDomElement sendsDom = _doc.createElement( QString( "send" ) );
556
 
                        fxch.appendChild( sendsDom );
557
 
 
558
 
                        sendsDom.setAttribute( "channel", ch->m_sends[si] );
559
 
                        ch->m_sendAmount[si]->saveSettings( _doc, sendsDom, "amount");
560
 
                }
561
 
        }
562
 
}
563
 
 
564
 
// make sure we have at least num channels
565
 
void FxMixer::allocateChannelsTo(int num)
566
 
{
567
 
        while( num > m_fxChannels.size() - 1 )
568
 
        {
569
 
                createChannel();
570
 
 
571
 
                // delete the default send to master
572
 
                deleteChannelSend(m_fxChannels.size()-1, 0);
573
 
        }
574
 
}
 
234
                fxch.setAttribute( "name", m_fxChannels[i]->m_name );
 
235
        }
 
236
}
 
237
 
 
238
 
575
239
 
576
240
 
577
241
void FxMixer::loadSettings( const QDomElement & _this )
578
242
{
579
243
        clear();
580
244
        QDomNode node = _this.firstChild();
581
 
        bool thereIsASend = false;
582
 
 
583
 
        while( ! node.isNull() )
 
245
        for( int i = 0; i <= NumFxChannels; ++i )
584
246
        {
585
247
                QDomElement fxch = node.toElement();
586
 
 
587
 
                // index of the channel we are about to load
588
248
                int num = fxch.attribute( "num" ).toInt();
589
 
 
590
 
                // allocate enough channels
591
 
                allocateChannelsTo( num );
592
 
 
 
249
                m_fxChannels[num]->m_fxChain.restoreState(
 
250
                        fxch.firstChildElement(
 
251
                                m_fxChannels[num]->m_fxChain.nodeName() ) );
593
252
                m_fxChannels[num]->m_volumeModel.loadSettings( fxch, "volume" );
594
253
                m_fxChannels[num]->m_muteModel.loadSettings( fxch, "muted" );
595
254
                m_fxChannels[num]->m_name = fxch.attribute( "name" );
596
 
 
597
 
                m_fxChannels[num]->m_fxChain.restoreState( fxch.firstChildElement(
598
 
                        m_fxChannels[num]->m_fxChain.nodeName() ) );
599
 
 
600
 
                // mixer sends
601
 
                QDomNodeList chData = fxch.childNodes();
602
 
                for( unsigned int i=0; i<chData.length(); ++i )
603
 
                {
604
 
                        QDomElement chDataItem = chData.at(i).toElement();
605
 
                        if( chDataItem.nodeName() == QString( "send" ) )
606
 
                        {
607
 
                                thereIsASend = true;
608
 
                                int sendTo = chDataItem.attribute( "channel" ).toInt();
609
 
                                allocateChannelsTo( sendTo) ;
610
 
                                float amount = chDataItem.attribute( "amount" ).toFloat();
611
 
                                createChannelSend( num, sendTo, amount );
612
 
                        }
613
 
                }
614
 
 
615
 
 
616
 
 
617
255
                node = node.nextSibling();
618
256
        }
619
257
 
620
 
        // check for old format. 65 fx channels and no explicit sends.
621
 
        if( ! thereIsASend && m_fxChannels.size() == 65 ) {
622
 
                // create a send from every channel into master
623
 
                for( int i=1; i<m_fxChannels.size(); ++i )
624
 
                {
625
 
                        createChannelSend(i, 0);
626
 
                }
627
 
        }
628
 
 
629
258
        emit dataChanged();
630
259
}
631
260