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