1 /*
2  * FxMixer.cpp - effect mixer for LMMS
3  *
4  * Copyright (c) 2008-2011 Tobias Doerffel <tobydox/at/users.sourceforge.net>
5  *
6  * This file is part of LMMS - https://lmms.io
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public
19  * License along with this program (see COPYING); if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301 USA.
22  *
23  */
24 
25 #include <QDomElement>
26 
27 #include "BufferManager.h"
28 #include "FxMixer.h"
29 #include "Mixer.h"
30 #include "MixerWorkerThread.h"
31 #include "MixHelpers.h"
32 #include "Song.h"
33 
34 #include "InstrumentTrack.h"
35 #include "BBTrackContainer.h"
36 
FxRoute(FxChannel * from,FxChannel * to,float amount)37 FxRoute::FxRoute( FxChannel * from, FxChannel * to, float amount ) :
38 	m_from( from ),
39 	m_to( to ),
40 	m_amount( amount, 0, 1, 0.001, NULL,
41 			tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex ).arg( m_to->m_channelIndex ) )
42 {
43 	//qDebug( "created: %d to %d", m_from->m_channelIndex, m_to->m_channelIndex );
44 	// create send amount model
45 }
46 
47 
~FxRoute()48 FxRoute::~FxRoute()
49 {
50 }
51 
52 
updateName()53 void FxRoute::updateName()
54 {
55 	m_amount.setDisplayName(
56 			tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex ).arg( m_to->m_channelIndex ) );
57 }
58 
59 
FxChannel(int idx,Model * _parent)60 FxChannel::FxChannel( int idx, Model * _parent ) :
61 	m_fxChain( NULL ),
62 	m_hasInput( false ),
63 	m_stillRunning( false ),
64 	m_peakLeft( 0.0f ),
65 	m_peakRight( 0.0f ),
66 	m_buffer( new sampleFrame[Engine::mixer()->framesPerPeriod()] ),
67 	m_muteModel( false, _parent ),
68 	m_soloModel( false, _parent ),
69 	m_volumeModel( 1.0, 0.0, 2.0, 0.001, _parent ),
70 	m_name(),
71 	m_lock(),
72 	m_channelIndex( idx ),
73 	m_queued( false ),
74 	m_dependenciesMet( 0 )
75 {
76 	BufferManager::clear( m_buffer, Engine::mixer()->framesPerPeriod() );
77 }
78 
79 
80 
81 
~FxChannel()82 FxChannel::~FxChannel()
83 {
84 	delete[] m_buffer;
85 }
86 
87 
processed()88 inline void FxChannel::processed()
89 {
90 	for( const FxRoute * receiverRoute : m_sends )
91 	{
92 		if( receiverRoute->receiver()->m_muted == false )
93 		{
94 			receiverRoute->receiver()->incrementDeps();
95 		}
96 	}
97 }
98 
incrementDeps()99 void FxChannel::incrementDeps()
100 {
101 	int i = m_dependenciesMet.fetchAndAddOrdered( 1 ) + 1;
102 	if( i >= m_receives.size() && ! m_queued )
103 	{
104 		m_queued = true;
105 		MixerWorkerThread::addJob( this );
106 	}
107 }
108 
unmuteForSolo()109 void FxChannel::unmuteForSolo()
110 {
111 	//TODO: Recursively activate every channel, this channel sends to
112 	m_muteModel.setValue(false);
113 }
114 
115 
116 
doProcessing()117 void FxChannel::doProcessing()
118 {
119 	const fpp_t fpp = Engine::mixer()->framesPerPeriod();
120 
121 	if( m_muted == false )
122 	{
123 		for( FxRoute * senderRoute : m_receives )
124 		{
125 			FxChannel * sender = senderRoute->sender();
126 			FloatModel * sendModel = senderRoute->amount();
127 			if( ! sendModel ) qFatal( "Error: no send model found from %d to %d", senderRoute->senderIndex(), m_channelIndex );
128 
129 			if( sender->m_hasInput || sender->m_stillRunning )
130 			{
131 				// figure out if we're getting sample-exact input
132 				ValueBuffer * sendBuf = sendModel->valueBuffer();
133 				ValueBuffer * volBuf = sender->m_volumeModel.valueBuffer();
134 
135 				// mix it's output with this one's output
136 				sampleFrame * ch_buf = sender->m_buffer;
137 
138 				// use sample-exact mixing if sample-exact values are available
139 				if( ! volBuf && ! sendBuf ) // neither volume nor send has sample-exact data...
140 				{
141 					const float v = sender->m_volumeModel.value() * sendModel->value();
142 					MixHelpers::addSanitizedMultiplied( m_buffer, ch_buf, v, fpp );
143 				}
144 				else if( volBuf && sendBuf ) // both volume and send have sample-exact data
145 				{
146 					MixHelpers::addSanitizedMultipliedByBuffers( m_buffer, ch_buf, volBuf, sendBuf, fpp );
147 				}
148 				else if( volBuf ) // volume has sample-exact data but send does not
149 				{
150 					const float v = sendModel->value();
151 					MixHelpers::addSanitizedMultipliedByBuffer( m_buffer, ch_buf, v, volBuf, fpp );
152 				}
153 				else // vice versa
154 				{
155 					const float v = sender->m_volumeModel.value();
156 					MixHelpers::addSanitizedMultipliedByBuffer( m_buffer, ch_buf, v, sendBuf, fpp );
157 				}
158 				m_hasInput = true;
159 			}
160 		}
161 
162 
163 		const float v = m_volumeModel.value();
164 
165 		if( m_hasInput )
166 		{
167 			// only start fxchain when we have input...
168 			m_fxChain.startRunning();
169 		}
170 
171 		m_stillRunning = m_fxChain.processAudioBuffer( m_buffer, fpp, m_hasInput );
172 
173 		float peakLeft = 0.;
174 		float peakRight = 0.;
175 		Engine::mixer()->getPeakValues( m_buffer, fpp, peakLeft, peakRight );
176 		m_peakLeft = qMax( m_peakLeft, peakLeft * v );
177 		m_peakRight = qMax( m_peakRight, peakRight * v );
178 	}
179 	else
180 	{
181 		m_peakLeft = m_peakRight = 0.0f;
182 	}
183 
184 	// increment dependency counter of all receivers
185 	processed();
186 }
187 
188 
189 
FxMixer()190 FxMixer::FxMixer() :
191 	Model( NULL ),
192 	JournallingObject(),
193 	m_fxChannels()
194 {
195 	// create master channel
196 	createChannel();
197 	m_lastSoloed = -1;
198 }
199 
200 
201 
~FxMixer()202 FxMixer::~FxMixer()
203 {
204 	while( ! m_fxRoutes.isEmpty() )
205 	{
206 		deleteChannelSend( m_fxRoutes.first() );
207 	}
208 	while( m_fxChannels.size() )
209 	{
210 		FxChannel * f = m_fxChannels[m_fxChannels.size() - 1];
211 		m_fxChannels.pop_back();
212 		delete f;
213 	}
214 }
215 
216 
217 
createChannel()218 int FxMixer::createChannel()
219 {
220 	const int index = m_fxChannels.size();
221 	// create new channel
222 	m_fxChannels.push_back( new FxChannel( index, this ) );
223 
224 	// reset channel state
225 	clearChannel( index );
226 
227 	return index;
228 }
229 
activateSolo()230 void FxMixer::activateSolo()
231 {
232 	for (int i = 1; i < m_fxChannels.size(); ++i)
233 	{
234 		m_fxChannels[i]->m_muteBeforeSolo = m_fxChannels[i]->m_muteModel.value();
235 		m_fxChannels[i]->m_muteModel.setValue( true );
236 	}
237 }
238 
deactivateSolo()239 void FxMixer::deactivateSolo()
240 {
241 	for (int i = 1; i < m_fxChannels.size(); ++i)
242 	{
243 		m_fxChannels[i]->m_muteModel.setValue( m_fxChannels[i]->m_muteBeforeSolo );
244 	}
245 }
246 
toggledSolo()247 void FxMixer::toggledSolo()
248 {
249 	int soloedChan = -1;
250 	bool resetSolo = m_lastSoloed != -1;
251 	//untoggle if lastsoloed is entered
252 	if (resetSolo)
253 	{
254 		m_fxChannels[m_lastSoloed]->m_soloModel.setValue( false );
255 	}
256 	//determine the soloed channel
257 	for (int i = 0; i < m_fxChannels.size(); ++i)
258 	{
259 		if (m_fxChannels[i]->m_soloModel.value() == true)
260 			soloedChan = i;
261 	}
262 	// if no channel is soloed, unmute everything, else mute everything
263 	if (soloedChan != -1)
264 	{
265 		if (resetSolo)
266 		{
267 			deactivateSolo();
268 			activateSolo();
269 		} else {
270 			activateSolo();
271 		}
272 		// unmute the soloed chan and every channel it sends to
273 		m_fxChannels[soloedChan]->unmuteForSolo();
274 	} else {
275 		deactivateSolo();
276 	}
277 	m_lastSoloed = soloedChan;
278 }
279 
280 
281 
deleteChannel(int index)282 void FxMixer::deleteChannel( int index )
283 {
284 	// channel deletion is performed between mixer rounds
285 	Engine::mixer()->requestChangeInModel();
286 
287 	// go through every instrument and adjust for the channel index change
288 	TrackContainer::TrackList tracks;
289 	tracks += Engine::getSong()->tracks();
290 	tracks += Engine::getBBTrackContainer()->tracks();
291 
292 	for( Track* t : tracks )
293 	{
294 		if( t->type() == Track::InstrumentTrack )
295 		{
296 			InstrumentTrack* inst = dynamic_cast<InstrumentTrack *>( t );
297 			int val = inst->effectChannelModel()->value(0);
298 			if( val == index )
299 			{
300 				// we are deleting this track's fx send
301 				// send to master
302 				inst->effectChannelModel()->setValue(0);
303 			}
304 			else if( val > index )
305 			{
306 				// subtract 1 to make up for the missing channel
307 				inst->effectChannelModel()->setValue(val-1);
308 			}
309 		}
310 	}
311 
312 	FxChannel * ch = m_fxChannels[index];
313 
314 	// delete all of this channel's sends and receives
315 	while( ! ch->m_sends.isEmpty() )
316 	{
317 		deleteChannelSend( ch->m_sends.first() );
318 	}
319 	while( ! ch->m_receives.isEmpty() )
320 	{
321 		deleteChannelSend( ch->m_receives.first() );
322 	}
323 
324 	// actually delete the channel
325 	m_fxChannels.remove(index);
326 	delete ch;
327 
328 	for( int i = index; i < m_fxChannels.size(); ++i )
329 	{
330 		validateChannelName( i, i + 1 );
331 
332 		// set correct channel index
333 		m_fxChannels[i]->m_channelIndex = i;
334 
335 		// now check all routes and update names of the send models
336 		for( FxRoute * r : m_fxChannels[i]->m_sends )
337 		{
338 			r->updateName();
339 		}
340 		for( FxRoute * r : m_fxChannels[i]->m_receives )
341 		{
342 			r->updateName();
343 		}
344 	}
345 
346 	Engine::mixer()->doneChangeInModel();
347 }
348 
349 
350 
moveChannelLeft(int index)351 void FxMixer::moveChannelLeft( int index )
352 {
353 	// can't move master or first channel
354 	if( index <= 1 || index >= m_fxChannels.size() )
355 	{
356 		return;
357 	}
358 	// channels to swap
359 	int a = index - 1, b = index;
360 
361 	// go through every instrument and adjust for the channel index change
362 	QVector<Track *> songTrackList = Engine::getSong()->tracks();
363 	QVector<Track *> bbTrackList = Engine::getBBTrackContainer()->tracks();
364 
365 	QVector<Track *> trackLists[] = {songTrackList, bbTrackList};
366 	for(int tl=0; tl<2; ++tl)
367 	{
368 		QVector<Track *> trackList = trackLists[tl];
369 		for(int i=0; i<trackList.size(); ++i)
370 		{
371 			if( trackList[i]->type() == Track::InstrumentTrack )
372 			{
373 				InstrumentTrack * inst = (InstrumentTrack *) trackList[i];
374 				int val = inst->effectChannelModel()->value(0);
375 				if( val == a )
376 				{
377 					inst->effectChannelModel()->setValue(b);
378 				}
379 				else if( val == b )
380 				{
381 					inst->effectChannelModel()->setValue(a);
382 				}
383 			}
384 		}
385 	}
386 
387 	// Swap positions in array
388 	qSwap(m_fxChannels[index], m_fxChannels[index - 1]);
389 
390 	// Update m_channelIndex of both channels
391 	m_fxChannels[index]->m_channelIndex = index;
392 	m_fxChannels[index - 1]->m_channelIndex = index -1;
393 }
394 
395 
396 
moveChannelRight(int index)397 void FxMixer::moveChannelRight( int index )
398 {
399 	moveChannelLeft( index + 1 );
400 }
401 
402 
403 
createChannelSend(fx_ch_t fromChannel,fx_ch_t toChannel,float amount)404 FxRoute * FxMixer::createChannelSend( fx_ch_t fromChannel, fx_ch_t toChannel,
405 								float amount )
406 {
407 //	qDebug( "requested: %d to %d", fromChannel, toChannel );
408 	// find the existing connection
409 	FxChannel * from = m_fxChannels[fromChannel];
410 	FxChannel * to = m_fxChannels[toChannel];
411 
412 	for( int i=0; i<from->m_sends.size(); ++i )
413 	{
414 		if( from->m_sends[i]->receiver() == to )
415 		{
416 			// simply adjust the amount
417 			from->m_sends[i]->amount()->setValue( amount );
418 			return from->m_sends[i];
419 		}
420 	}
421 
422 	// connection does not exist. create a new one
423 	return createRoute( from, to, amount );
424 }
425 
426 
createRoute(FxChannel * from,FxChannel * to,float amount)427 FxRoute * FxMixer::createRoute( FxChannel * from, FxChannel * to, float amount )
428 {
429 	if( from == to )
430 	{
431 		return NULL;
432 	}
433 	Engine::mixer()->requestChangeInModel();
434 	FxRoute * route = new FxRoute( from, to, amount );
435 
436 	// add us to from's sends
437 	from->m_sends.append( route );
438 
439 	// add us to to's receives
440 	to->m_receives.append( route );
441 
442 	// add us to fxmixer's list
443 	Engine::fxMixer()->m_fxRoutes.append( route );
444 	Engine::mixer()->doneChangeInModel();
445 
446 	return route;
447 }
448 
449 
450 // delete the connection made by createChannelSend
deleteChannelSend(fx_ch_t fromChannel,fx_ch_t toChannel)451 void FxMixer::deleteChannelSend( fx_ch_t fromChannel, fx_ch_t toChannel )
452 {
453 	// delete the send
454 	FxChannel * from = m_fxChannels[fromChannel];
455 	FxChannel * to	 = m_fxChannels[toChannel];
456 
457 	// find and delete the send entry
458 	for( int i = 0; i < from->m_sends.size(); ++i )
459 	{
460 		if( from->m_sends[i]->receiver() == to )
461 		{
462 			deleteChannelSend( from->m_sends[i] );
463 			break;
464 		}
465 	}
466 }
467 
468 
deleteChannelSend(FxRoute * route)469 void FxMixer::deleteChannelSend( FxRoute * route )
470 {
471 	Engine::mixer()->requestChangeInModel();
472 	// remove us from from's sends
473 	route->sender()->m_sends.remove( route->sender()->m_sends.indexOf( route ) );
474 	// remove us from to's receives
475 	route->receiver()->m_receives.remove( route->receiver()->m_receives.indexOf( route ) );
476 	// remove us from fxmixer's list
477 	Engine::fxMixer()->m_fxRoutes.remove( Engine::fxMixer()->m_fxRoutes.indexOf( route ) );
478 	delete route;
479 	Engine::mixer()->doneChangeInModel();
480 }
481 
482 
isInfiniteLoop(fx_ch_t sendFrom,fx_ch_t sendTo)483 bool FxMixer::isInfiniteLoop( fx_ch_t sendFrom, fx_ch_t sendTo )
484 {
485 	if( sendFrom == sendTo ) return true;
486 	FxChannel * from = m_fxChannels[sendFrom];
487 	FxChannel * to = m_fxChannels[sendTo];
488 	bool b = checkInfiniteLoop( from, to );
489 	return b;
490 }
491 
492 
checkInfiniteLoop(FxChannel * from,FxChannel * to)493 bool FxMixer::checkInfiniteLoop( FxChannel * from, FxChannel * to )
494 {
495 	// can't send master to anything
496 	if( from == m_fxChannels[0] )
497 	{
498 		return true;
499 	}
500 
501 	// can't send channel to itself
502 	if( from == to )
503 	{
504 		return true;
505 	}
506 
507 	// follow sendTo's outputs recursively looking for something that sends
508 	// to sendFrom
509 	for( int i=0; i < to->m_sends.size(); ++i )
510 	{
511 		if( checkInfiniteLoop( from, to->m_sends[i]->receiver() ) )
512 		{
513 			return true;
514 		}
515 	}
516 
517 	return false;
518 }
519 
520 
521 // how much does fromChannel send its output to the input of toChannel?
channelSendModel(fx_ch_t fromChannel,fx_ch_t toChannel)522 FloatModel * FxMixer::channelSendModel( fx_ch_t fromChannel, fx_ch_t toChannel )
523 {
524 	if( fromChannel == toChannel )
525 	{
526 		return NULL;
527 	}
528 	const FxChannel * from = m_fxChannels[fromChannel];
529 	const FxChannel * to = m_fxChannels[toChannel];
530 
531 	for( FxRoute * route : from->m_sends )
532 	{
533 		if( route->receiver() == to )
534 		{
535 			return route->amount();
536 		}
537 	}
538 
539 	return NULL;
540 }
541 
542 
543 
mixToChannel(const sampleFrame * _buf,fx_ch_t _ch)544 void FxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch )
545 {
546 	if( m_fxChannels[_ch]->m_muteModel.value() == false )
547 	{
548 		m_fxChannels[_ch]->m_lock.lock();
549 		MixHelpers::add( m_fxChannels[_ch]->m_buffer, _buf, Engine::mixer()->framesPerPeriod() );
550 		m_fxChannels[_ch]->m_hasInput = true;
551 		m_fxChannels[_ch]->m_lock.unlock();
552 	}
553 }
554 
555 
556 
557 
prepareMasterMix()558 void FxMixer::prepareMasterMix()
559 {
560 	BufferManager::clear( m_fxChannels[0]->m_buffer,
561 					Engine::mixer()->framesPerPeriod() );
562 }
563 
564 
565 
masterMix(sampleFrame * _buf)566 void FxMixer::masterMix( sampleFrame * _buf )
567 {
568 	const int fpp = Engine::mixer()->framesPerPeriod();
569 
570 	// add the channels that have no dependencies (no incoming senders, ie.
571 	// no receives) to the jobqueue. The channels that have receives get
572 	// added when their senders get processed, which is detected by
573 	// dependency counting.
574 	// also instantly add all muted channels as they don't need to care
575 	// about their senders, and can just increment the deps of their
576 	// recipients right away.
577 	MixerWorkerThread::resetJobQueue( MixerWorkerThread::JobQueue::Dynamic );
578 	for( FxChannel * ch : m_fxChannels )
579 	{
580 		ch->m_muted = ch->m_muteModel.value();
581 		if( ch->m_muted ) // instantly "process" muted channels
582 		{
583 			ch->processed();
584 			ch->done();
585 		}
586 		else if( ch->m_receives.size() == 0 )
587 		{
588 			ch->m_queued = true;
589 			MixerWorkerThread::addJob( ch );
590 		}
591 	}
592 	while( m_fxChannels[0]->state() != ThreadableJob::Done )
593 	{
594 		bool found = false;
595 		for( FxChannel * ch : m_fxChannels )
596 		{
597 			int s = ch->state();
598 			if( s == ThreadableJob::Queued
599 				|| s == ThreadableJob::InProgress )
600 			{
601 				found = true;
602 				break;
603 			}
604 		}
605 		if( !found )
606 		{
607 			break;
608 		}
609 		MixerWorkerThread::startAndWaitForJobs();
610 	}
611 
612 	// handle sample-exact data in master volume fader
613 	ValueBuffer * volBuf = m_fxChannels[0]->m_volumeModel.valueBuffer();
614 
615 	if( volBuf )
616 	{
617 		for( int f = 0; f < fpp; f++ )
618 		{
619 			m_fxChannels[0]->m_buffer[f][0] *= volBuf->values()[f];
620 			m_fxChannels[0]->m_buffer[f][1] *= volBuf->values()[f];
621 		}
622 	}
623 
624 	const float v = volBuf
625 		? 1.0f
626 		: m_fxChannels[0]->m_volumeModel.value();
627 	MixHelpers::addSanitizedMultiplied( _buf, m_fxChannels[0]->m_buffer, v, fpp );
628 
629 	// clear all channel buffers and
630 	// reset channel process state
631 	for( int i = 0; i < numChannels(); ++i)
632 	{
633 		BufferManager::clear( m_fxChannels[i]->m_buffer,
634 				Engine::mixer()->framesPerPeriod() );
635 		m_fxChannels[i]->reset();
636 		m_fxChannels[i]->m_queued = false;
637 		// also reset hasInput
638 		m_fxChannels[i]->m_hasInput = false;
639 		m_fxChannels[i]->m_dependenciesMet = 0;
640 	}
641 }
642 
643 
644 
645 
clear()646 void FxMixer::clear()
647 {
648 	while( m_fxChannels.size() > 1 )
649 	{
650 		deleteChannel(1);
651 	}
652 
653 	clearChannel(0);
654 }
655 
656 
657 
clearChannel(fx_ch_t index)658 void FxMixer::clearChannel(fx_ch_t index)
659 {
660 	FxChannel * ch = m_fxChannels[index];
661 	ch->m_fxChain.clear();
662 	ch->m_volumeModel.setValue( 1.0f );
663 	ch->m_muteModel.setValue( false );
664 	ch->m_soloModel.setValue( false );
665 	ch->m_name = ( index == 0 ) ? tr( "Master" ) : tr( "FX %1" ).arg( index );
666 	ch->m_volumeModel.setDisplayName( ch->m_name + ">" + tr( "Volume" ) );
667 	ch->m_muteModel.setDisplayName( ch->m_name + ">" + tr( "Mute" ) );
668 	ch->m_soloModel.setDisplayName( ch->m_name + ">" + tr( "Solo" ) );
669 
670 	// send only to master
671 	if( index > 0)
672 	{
673 		// delete existing sends
674 		while( ! ch->m_sends.isEmpty() )
675 		{
676 			deleteChannelSend( ch->m_sends.first() );
677 		}
678 
679 		// add send to master
680 		createChannelSend( index, 0 );
681 	}
682 
683 	// delete receives
684 	while( ! ch->m_receives.isEmpty() )
685 	{
686 		deleteChannelSend( ch->m_receives.first() );
687 	}
688 }
689 
saveSettings(QDomDocument & _doc,QDomElement & _this)690 void FxMixer::saveSettings( QDomDocument & _doc, QDomElement & _this )
691 {
692 	// save channels
693 	for( int i = 0; i < m_fxChannels.size(); ++i )
694 	{
695 		FxChannel * ch = m_fxChannels[i];
696 
697 		QDomElement fxch = _doc.createElement( QString( "fxchannel" ) );
698 		_this.appendChild( fxch );
699 
700 		ch->m_fxChain.saveState( _doc, fxch );
701 		ch->m_volumeModel.saveSettings( _doc, fxch, "volume" );
702 		ch->m_muteModel.saveSettings( _doc, fxch, "muted" );
703 		ch->m_soloModel.saveSettings( _doc, fxch, "soloed" );
704 		fxch.setAttribute( "num", i );
705 		fxch.setAttribute( "name", ch->m_name );
706 
707 		// add the channel sends
708 		for( int si = 0; si < ch->m_sends.size(); ++si )
709 		{
710 			QDomElement sendsDom = _doc.createElement( QString( "send" ) );
711 			fxch.appendChild( sendsDom );
712 
713 			sendsDom.setAttribute( "channel", ch->m_sends[si]->receiverIndex() );
714 			ch->m_sends[si]->amount()->saveSettings( _doc, sendsDom, "amount" );
715 		}
716 	}
717 }
718 
719 // make sure we have at least num channels
allocateChannelsTo(int num)720 void FxMixer::allocateChannelsTo(int num)
721 {
722 	while( num > m_fxChannels.size() - 1 )
723 	{
724 		createChannel();
725 
726 		// delete the default send to master
727 		deleteChannelSend( m_fxChannels.size()-1, 0 );
728 	}
729 }
730 
731 
loadSettings(const QDomElement & _this)732 void FxMixer::loadSettings( const QDomElement & _this )
733 {
734 	clear();
735 	QDomNode node = _this.firstChild();
736 
737 	while( ! node.isNull() )
738 	{
739 		QDomElement fxch = node.toElement();
740 
741 		// index of the channel we are about to load
742 		int num = fxch.attribute( "num" ).toInt();
743 
744 		// allocate enough channels
745 		allocateChannelsTo( num );
746 
747 		m_fxChannels[num]->m_volumeModel.loadSettings( fxch, "volume" );
748 		m_fxChannels[num]->m_muteModel.loadSettings( fxch, "muted" );
749 		m_fxChannels[num]->m_soloModel.loadSettings( fxch, "soloed" );
750 		m_fxChannels[num]->m_name = fxch.attribute( "name" );
751 
752 		m_fxChannels[num]->m_fxChain.restoreState( fxch.firstChildElement(
753 			m_fxChannels[num]->m_fxChain.nodeName() ) );
754 
755 		// mixer sends
756 		QDomNodeList chData = fxch.childNodes();
757 		for( unsigned int i=0; i<chData.length(); ++i )
758 		{
759 			QDomElement chDataItem = chData.at(i).toElement();
760 			if( chDataItem.nodeName() == QString( "send" ) )
761 			{
762 				int sendTo = chDataItem.attribute( "channel" ).toInt();
763 				allocateChannelsTo( sendTo ) ;
764 				FxRoute * fxr = createChannelSend( num, sendTo, 1.0f );
765 				if( fxr ) fxr->amount()->loadSettings( chDataItem, "amount" );
766 			}
767 		}
768 
769 
770 
771 		node = node.nextSibling();
772 	}
773 
774 	emit dataChanged();
775 }
776 
777 
validateChannelName(int index,int oldIndex)778 void FxMixer::validateChannelName( int index, int oldIndex )
779 {
780 	if( m_fxChannels[index]->m_name == tr( "FX %1" ).arg( oldIndex ) )
781 	{
782 		m_fxChannels[index]->m_name = tr( "FX %1" ).arg( index );
783 	}
784 }
785 
786