1 /*
2  * EnvelopeAndLfoParameters.cpp - class EnvelopeAndLfoParameters
3  *
4  * Copyright (c) 2004-2014 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 "EnvelopeAndLfoParameters.h"
28 #include "Engine.h"
29 #include "Mixer.h"
30 #include "Oscillator.h"
31 
32 
33 // how long should be each envelope-segment maximal (e.g. attack)?
34 extern const float SECS_PER_ENV_SEGMENT = 5.0f;
35 // how long should be one LFO-oscillation maximal?
36 extern const float SECS_PER_LFO_OSCILLATION = 20.0f;
37 
38 
39 EnvelopeAndLfoParameters::LfoInstances * EnvelopeAndLfoParameters::s_lfoInstances = NULL;
40 
41 
trigger()42 void EnvelopeAndLfoParameters::LfoInstances::trigger()
43 {
44 	QMutexLocker m( &m_lfoListMutex );
45 	for( LfoList::Iterator it = m_lfos.begin();
46 							it != m_lfos.end(); ++it )
47 	{
48 		( *it )->m_lfoFrame +=
49 				Engine::mixer()->framesPerPeriod();
50 		( *it )->m_bad_lfoShapeData = true;
51 	}
52 }
53 
54 
55 
56 
reset()57 void EnvelopeAndLfoParameters::LfoInstances::reset()
58 {
59 	QMutexLocker m( &m_lfoListMutex );
60 	for( LfoList::Iterator it = m_lfos.begin();
61 							it != m_lfos.end(); ++it )
62 	{
63 		( *it )->m_lfoFrame = 0;
64 		( *it )->m_bad_lfoShapeData = true;
65 	}
66 }
67 
68 
69 
70 
add(EnvelopeAndLfoParameters * lfo)71 void EnvelopeAndLfoParameters::LfoInstances::add( EnvelopeAndLfoParameters * lfo )
72 {
73 	QMutexLocker m( &m_lfoListMutex );
74 	m_lfos.append( lfo );
75 }
76 
77 
78 
79 
remove(EnvelopeAndLfoParameters * lfo)80 void EnvelopeAndLfoParameters::LfoInstances::remove( EnvelopeAndLfoParameters * lfo )
81 {
82 	QMutexLocker m( &m_lfoListMutex );
83 	m_lfos.removeAll( lfo );
84 }
85 
86 
87 
88 
EnvelopeAndLfoParameters(float _value_for_zero_amount,Model * _parent)89 EnvelopeAndLfoParameters::EnvelopeAndLfoParameters(
90 					float _value_for_zero_amount,
91 							Model * _parent ) :
92 	Model( _parent ),
93 	m_used( false ),
94 	m_predelayModel( 0.0, 0.0, 2.0, 0.001, this, tr( "Predelay" ) ),
95 	m_attackModel( 0.0, 0.0, 2.0, 0.001, this, tr( "Attack" ) ),
96 	m_holdModel( 0.5, 0.0, 2.0, 0.001, this, tr( "Hold" ) ),
97 	m_decayModel( 0.5, 0.0, 2.0, 0.001, this, tr( "Decay" ) ),
98 	m_sustainModel( 0.5, 0.0, 1.0, 0.001, this, tr( "Sustain" ) ),
99 	m_releaseModel( 0.1, 0.0, 2.0, 0.001, this, tr( "Release" ) ),
100 	m_amountModel( 0.0, -1.0, 1.0, 0.005, this, tr( "Modulation" ) ),
101 	m_valueForZeroAmount( _value_for_zero_amount ),
102 	m_pahdFrames( 0 ),
103 	m_rFrames( 0 ),
104 	m_pahdEnv( NULL ),
105 	m_rEnv( NULL ),
106 	m_pahdBufSize( 0 ),
107 	m_rBufSize( 0 ),
108 	m_lfoPredelayModel( 0.0, 0.0, 1.0, 0.001, this, tr( "LFO Predelay" ) ),
109 	m_lfoAttackModel( 0.0, 0.0, 1.0, 0.001, this, tr( "LFO Attack" ) ),
110 	m_lfoSpeedModel( 0.1, 0.001, 1.0, 0.0001,
111 				SECS_PER_LFO_OSCILLATION * 1000.0, this,
112 							tr( "LFO speed" ) ),
113 	m_lfoAmountModel( 0.0, -1.0, 1.0, 0.005, this, tr( "LFO Modulation" ) ),
114 	m_lfoWaveModel( SineWave, 0, NumLfoShapes, this, tr( "LFO Wave Shape" ) ),
115 	m_x100Model( false, this, tr( "Freq x 100" ) ),
116 	m_controlEnvAmountModel( false, this, tr( "Modulate Env-Amount" ) ),
117 	m_lfoFrame( 0 ),
118 	m_lfoAmountIsZero( false ),
119 	m_lfoShapeData( NULL )
120 {
121 	m_amountModel.setCenterValue( 0 );
122 	m_lfoAmountModel.setCenterValue( 0 );
123 
124 	if( s_lfoInstances == NULL )
125 	{
126 		s_lfoInstances = new LfoInstances();
127 	}
128 
129 	instances()->add( this );
130 
131 	connect( &m_predelayModel, SIGNAL( dataChanged() ),
132 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
133 	connect( &m_attackModel, SIGNAL( dataChanged() ),
134 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
135 	connect( &m_holdModel, SIGNAL( dataChanged() ),
136 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
137 	connect( &m_decayModel, SIGNAL( dataChanged() ),
138 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
139 	connect( &m_sustainModel, SIGNAL( dataChanged() ),
140 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
141 	connect( &m_releaseModel, SIGNAL( dataChanged() ),
142 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
143 	connect( &m_amountModel, SIGNAL( dataChanged() ),
144 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
145 
146 	connect( &m_lfoPredelayModel, SIGNAL( dataChanged() ),
147 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
148 	connect( &m_lfoAttackModel, SIGNAL( dataChanged() ),
149 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
150 	connect( &m_lfoSpeedModel, SIGNAL( dataChanged() ),
151 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
152 	connect( &m_lfoAmountModel, SIGNAL( dataChanged() ),
153 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
154 	connect( &m_lfoWaveModel, SIGNAL( dataChanged() ),
155 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
156 	connect( &m_x100Model, SIGNAL( dataChanged() ),
157 			this, SLOT( updateSampleVars() ), Qt::DirectConnection );
158 
159 	connect( Engine::mixer(), SIGNAL( sampleRateChanged() ),
160 				this, SLOT( updateSampleVars() ) );
161 
162 
163 	m_lfoShapeData =
164 		new sample_t[Engine::mixer()->framesPerPeriod()];
165 
166 	updateSampleVars();
167 }
168 
169 
170 
171 
~EnvelopeAndLfoParameters()172 EnvelopeAndLfoParameters::~EnvelopeAndLfoParameters()
173 {
174 	m_predelayModel.disconnect( this );
175 	m_attackModel.disconnect( this );
176 	m_holdModel.disconnect( this );
177 	m_decayModel.disconnect( this );
178 	m_sustainModel.disconnect( this );
179 	m_releaseModel.disconnect( this );
180 	m_amountModel.disconnect( this );
181 	m_lfoPredelayModel.disconnect( this );
182 	m_lfoAttackModel.disconnect( this );
183 	m_lfoSpeedModel.disconnect( this );
184 	m_lfoAmountModel.disconnect( this );
185 	m_lfoWaveModel.disconnect( this );
186 	m_x100Model.disconnect( this );
187 
188 	delete[] m_pahdEnv;
189 	delete[] m_rEnv;
190 	delete[] m_lfoShapeData;
191 
192 	instances()->remove( this );
193 
194 	if( instances()->isEmpty() )
195 	{
196 		delete instances();
197 		s_lfoInstances = NULL;
198 	}
199 }
200 
201 
202 
203 
lfoShapeSample(fpp_t _frame_offset)204 inline sample_t EnvelopeAndLfoParameters::lfoShapeSample( fpp_t _frame_offset )
205 {
206 	f_cnt_t frame = ( m_lfoFrame + _frame_offset ) % m_lfoOscillationFrames;
207 	const float phase = frame / static_cast<float>(
208 						m_lfoOscillationFrames );
209 	sample_t shape_sample;
210 	switch( m_lfoWaveModel.value()  )
211 	{
212 		case TriangleWave:
213 			shape_sample = Oscillator::triangleSample( phase );
214 			break;
215 		case SquareWave:
216 			shape_sample = Oscillator::squareSample( phase );
217 			break;
218 		case SawWave:
219 			shape_sample = Oscillator::sawSample( phase );
220 			break;
221 		case UserDefinedWave:
222 			shape_sample = m_userWave.userWaveSample( phase );
223 			break;
224 		case RandomWave:
225 			if( frame == 0 )
226 			{
227 				m_random = Oscillator::noiseSample( 0.0f );
228 			}
229 			shape_sample = m_random;
230 			break;
231 		case SineWave:
232 		default:
233 			shape_sample = Oscillator::sinSample( phase );
234 			break;
235 	}
236 	return shape_sample * m_lfoAmount;
237 }
238 
239 
240 
241 
updateLfoShapeData()242 void EnvelopeAndLfoParameters::updateLfoShapeData()
243 {
244 	const fpp_t frames = Engine::mixer()->framesPerPeriod();
245 	for( fpp_t offset = 0; offset < frames; ++offset )
246 	{
247 		m_lfoShapeData[offset] = lfoShapeSample( offset );
248 	}
249 	m_bad_lfoShapeData = false;
250 }
251 
252 
253 
254 
fillLfoLevel(float * _buf,f_cnt_t _frame,const fpp_t _frames)255 inline void EnvelopeAndLfoParameters::fillLfoLevel( float * _buf,
256 							f_cnt_t _frame,
257 							const fpp_t _frames )
258 {
259 	if( m_lfoAmountIsZero || _frame <= m_lfoPredelayFrames )
260 	{
261 		for( fpp_t offset = 0; offset < _frames; ++offset )
262 		{
263 			*_buf++ = 0.0f;
264 		}
265 		return;
266 	}
267 	_frame -= m_lfoPredelayFrames;
268 
269 	if( m_bad_lfoShapeData )
270 	{
271 		updateLfoShapeData();
272 	}
273 
274 	fpp_t offset = 0;
275 	const float lafI = 1.0f / m_lfoAttackFrames;
276 	for( ; offset < _frames && _frame < m_lfoAttackFrames; ++offset,
277 								++_frame )
278 	{
279 		*_buf++ = m_lfoShapeData[offset] * _frame * lafI;
280 	}
281 	for( ; offset < _frames; ++offset )
282 	{
283 		*_buf++ = m_lfoShapeData[offset];
284 	}
285 }
286 
287 
288 
289 
fillLevel(float * _buf,f_cnt_t _frame,const f_cnt_t _release_begin,const fpp_t _frames)290 void EnvelopeAndLfoParameters::fillLevel( float * _buf, f_cnt_t _frame,
291 						const f_cnt_t _release_begin,
292 						const fpp_t _frames )
293 {
294 	QMutexLocker m(&m_paramMutex);
295 
296 	if( _frame < 0 || _release_begin < 0 )
297 	{
298 		return;
299 	}
300 
301 	fillLfoLevel( _buf, _frame, _frames );
302 
303 	for( fpp_t offset = 0; offset < _frames; ++offset, ++_buf, ++_frame )
304 	{
305 		float env_level;
306 		if( _frame < _release_begin )
307 		{
308 			if( _frame < m_pahdFrames )
309 			{
310 				env_level = m_pahdEnv[_frame];
311 			}
312 			else
313 			{
314 				env_level = m_sustainLevel;
315 			}
316 		}
317 		else if( ( _frame - _release_begin ) < m_rFrames )
318 		{
319 			env_level = m_rEnv[_frame - _release_begin] *
320 				( ( _release_begin < m_pahdFrames ) ?
321 				m_pahdEnv[_release_begin] : m_sustainLevel );
322 		}
323 		else
324 		{
325 			env_level = 0.0f;
326 		}
327 
328 		// at this point, *_buf is LFO level
329 		*_buf = m_controlEnvAmountModel.value() ?
330 			env_level * ( 0.5f + *_buf ) :
331 			env_level + *_buf;
332 	}
333 }
334 
335 
336 
337 
saveSettings(QDomDocument & _doc,QDomElement & _parent)338 void EnvelopeAndLfoParameters::saveSettings( QDomDocument & _doc,
339 							QDomElement & _parent )
340 {
341 	m_predelayModel.saveSettings( _doc, _parent, "pdel" );
342 	m_attackModel.saveSettings( _doc, _parent, "att" );
343 	m_holdModel.saveSettings( _doc, _parent, "hold" );
344 	m_decayModel.saveSettings( _doc, _parent, "dec" );
345 	m_sustainModel.saveSettings( _doc, _parent, "sustain" );
346 	m_releaseModel.saveSettings( _doc, _parent, "rel" );
347 	m_amountModel.saveSettings( _doc, _parent, "amt" );
348 	m_lfoWaveModel.saveSettings( _doc, _parent, "lshp" );
349 	m_lfoPredelayModel.saveSettings( _doc, _parent, "lpdel" );
350 	m_lfoAttackModel.saveSettings( _doc, _parent, "latt" );
351 	m_lfoSpeedModel.saveSettings( _doc, _parent, "lspd" );
352 	m_lfoAmountModel.saveSettings( _doc, _parent, "lamt" );
353 	m_x100Model.saveSettings( _doc, _parent, "x100" );
354 	m_controlEnvAmountModel.saveSettings( _doc, _parent, "ctlenvamt" );
355 	_parent.setAttribute( "userwavefile", m_userWave.audioFile() );
356 }
357 
358 
359 
360 
loadSettings(const QDomElement & _this)361 void EnvelopeAndLfoParameters::loadSettings( const QDomElement & _this )
362 {
363 	m_predelayModel.loadSettings( _this, "pdel" );
364 	m_attackModel.loadSettings( _this, "att" );
365 	m_holdModel.loadSettings( _this, "hold" );
366 	m_decayModel.loadSettings( _this, "dec" );
367 	m_sustainModel.loadSettings( _this, "sustain" );
368 	m_releaseModel.loadSettings( _this, "rel" );
369 	m_amountModel.loadSettings( _this, "amt" );
370 	m_lfoWaveModel.loadSettings( _this, "lshp" );
371 	m_lfoPredelayModel.loadSettings( _this, "lpdel" );
372 	m_lfoAttackModel.loadSettings( _this, "latt" );
373 	m_lfoSpeedModel.loadSettings( _this, "lspd" );
374 	m_lfoAmountModel.loadSettings( _this, "lamt" );
375 	m_x100Model.loadSettings( _this, "x100" );
376 	m_controlEnvAmountModel.loadSettings( _this, "ctlenvamt" );
377 
378 /*	 ### TODO:
379 	Old reversed sustain kept for backward compatibility
380 	with 4.15 file format*/
381 
382 	if( _this.hasAttribute( "sus" ) )
383 	{
384 		m_sustainModel.loadSettings( _this, "sus" );
385 		m_sustainModel.setValue( 1.0 - m_sustainModel.value() );
386 	}
387 
388 	// ### TODO:
389 /*	// Keep compatibility with version 2.1 file format
390 	if( _this.hasAttribute( "lfosyncmode" ) )
391 	{
392 		m_lfoSpeedKnob->setSyncMode(
393 		( TempoSyncKnob::TtempoSyncMode ) _this.attribute(
394 						"lfosyncmode" ).toInt() );
395 	}*/
396 
397 	m_userWave.setAudioFile( _this.attribute( "userwavefile" ) );
398 
399 	updateSampleVars();
400 }
401 
402 
403 
404 
updateSampleVars()405 void EnvelopeAndLfoParameters::updateSampleVars()
406 {
407 	QMutexLocker m(&m_paramMutex);
408 
409 	const float frames_per_env_seg = SECS_PER_ENV_SEGMENT *
410 				Engine::mixer()->processingSampleRate();
411 	// TODO: Remove the expKnobVals, time should be linear
412 	const f_cnt_t predelay_frames = static_cast<f_cnt_t>(
413 							frames_per_env_seg *
414 					expKnobVal( m_predelayModel.value() ) );
415 
416 	const f_cnt_t attack_frames = static_cast<f_cnt_t>( frames_per_env_seg *
417 					expKnobVal( m_attackModel.value() ) );
418 
419 	const f_cnt_t hold_frames = static_cast<f_cnt_t>( frames_per_env_seg *
420 					expKnobVal( m_holdModel.value() ) );
421 
422 	const f_cnt_t decay_frames = static_cast<f_cnt_t>( frames_per_env_seg *
423 					expKnobVal( m_decayModel.value() *
424 						( 1 - m_sustainModel.value() ) ) );
425 
426 	m_sustainLevel = m_sustainModel.value();
427 	m_amount = m_amountModel.value();
428 	if( m_amount >= 0 )
429 	{
430 		m_amountAdd = ( 1.0f - m_amount ) * m_valueForZeroAmount;
431 	}
432 	else
433 	{
434 		m_amountAdd = m_valueForZeroAmount;
435 	}
436 
437 	m_pahdFrames = predelay_frames + attack_frames + hold_frames +
438 								decay_frames;
439 	m_rFrames = static_cast<f_cnt_t>( frames_per_env_seg *
440 					expKnobVal( m_releaseModel.value() ) );
441 
442 	if( static_cast<int>( floorf( m_amount * 1000.0f ) ) == 0 )
443 	{
444 		m_rFrames = 0;
445 	}
446 
447 	// if the buffers are too small, make bigger ones - so we only alloc new memory when necessary
448 	if( m_pahdBufSize < m_pahdFrames )
449 	{
450 		sample_t * tmp = m_pahdEnv;
451 		m_pahdEnv = new sample_t[m_pahdFrames];
452 		delete[] tmp;
453 		m_pahdBufSize = m_pahdFrames;
454 	}
455 	if( m_rBufSize < m_rFrames )
456 	{
457 		sample_t * tmp = m_rEnv;
458 		m_rEnv = new sample_t[m_rFrames];
459 		delete[] tmp;
460 		m_rBufSize = m_rFrames;
461 	}
462 
463 	const float aa = m_amountAdd;
464 	for( f_cnt_t i = 0; i < predelay_frames; ++i )
465 	{
466 		m_pahdEnv[i] = aa;
467 	}
468 
469 	f_cnt_t add = predelay_frames;
470 
471 	const float afI = ( 1.0f / attack_frames ) * m_amount;
472 	for( f_cnt_t i = 0; i < attack_frames; ++i )
473 	{
474 		m_pahdEnv[add+i] = i * afI + aa;
475 	}
476 
477 	add += attack_frames;
478 	const float amsum = m_amount + m_amountAdd;
479 	for( f_cnt_t i = 0; i < hold_frames; ++i )
480 	{
481 		m_pahdEnv[add + i] = amsum;
482 	}
483 
484 	add += hold_frames;
485 	const float dfI = ( 1.0 / decay_frames ) * ( m_sustainLevel -1 ) * m_amount;
486 	for( f_cnt_t i = 0; i < decay_frames; ++i )
487 	{
488 /*
489 		m_pahdEnv[add + i] = ( m_sustainLevel + ( 1.0f -
490 						(float)i / decay_frames ) *
491 						( 1.0f - m_sustainLevel ) ) *
492 							m_amount + m_amountAdd;
493 */
494 		m_pahdEnv[add + i] = amsum + i*dfI;
495 	}
496 
497 	const float rfI = ( 1.0f / m_rFrames ) * m_amount;
498 	for( f_cnt_t i = 0; i < m_rFrames; ++i )
499 	{
500 		m_rEnv[i] = (float)( m_rFrames - i ) * rfI;
501 	}
502 
503 	// save this calculation in real-time-part
504 	m_sustainLevel = m_sustainLevel * m_amount + m_amountAdd;
505 
506 
507 	const float frames_per_lfo_oscillation = SECS_PER_LFO_OSCILLATION *
508 				Engine::mixer()->processingSampleRate();
509 	m_lfoPredelayFrames = static_cast<f_cnt_t>( frames_per_lfo_oscillation *
510 				expKnobVal( m_lfoPredelayModel.value() ) );
511 	m_lfoAttackFrames = static_cast<f_cnt_t>( frames_per_lfo_oscillation *
512 				expKnobVal( m_lfoAttackModel.value() ) );
513 	m_lfoOscillationFrames = static_cast<f_cnt_t>(
514 						frames_per_lfo_oscillation *
515 						m_lfoSpeedModel.value() );
516 	if( m_x100Model.value() )
517 	{
518 		m_lfoOscillationFrames /= 100;
519 	}
520 	m_lfoAmount = m_lfoAmountModel.value() * 0.5f;
521 
522 	m_used = true;
523 	if( static_cast<int>( floorf( m_lfoAmount * 1000.0f ) ) == 0 )
524 	{
525 		m_lfoAmountIsZero = true;
526 		if( static_cast<int>( floorf( m_amount * 1000.0f ) ) == 0 )
527 		{
528 			m_used = false;
529 		}
530 	}
531 	else
532 	{
533 		m_lfoAmountIsZero = false;
534 	}
535 
536 	m_bad_lfoShapeData = true;
537 
538 	emit dataChanged();
539 
540 }
541 
542 
543 
544 
545 
546 
547 
548 
549