Skip to content

Commit 8821d88

Browse files
InstrumentSoundShaping refactoring (LMMS#7229)
* Accessors for volume, cutoff, resonance Add private accessors for the volume, cutoff and resonance parameters (envelope and LFO). This makes the code less technical and more readable as it for example removes lots of static casts. The casts are now done in a special helper method that returns the parameters for a given target. * Remove EnvelopeAndLfoParameters array Remove the `EnvelopeAndLfoParameters` array and use explicit instances for volume, cutoff, resonance. This simplifies construction and initialization of the instances. Besides the array this also removes the `Target` enum and the `NumTargets` value. To simplify storage and retrieval of the parameters three private methods have been added which provide the node names of the volume, cutoff and resonance parameters. Adjust `InstrumentSoundShapingView` to the removed `NumTargets` property. * Use references instead of pointers Use references to the volume, cutoff and resonance parameters instead of pointers. * Remove friend relationship Remove the friend relationship between `InstrumentSoundShaping` and its related view by providing the models via getters. * Get rid of targetNames Get rid of `InstrumentSoundShaping::targetNames` by using translations and strings directly. Move the remaining stuff into `InstrumentSoundShapingView` until it is removed there as well. * Explicit EnvelopeAndLfoViews Remove the array of EnvelopeAndLfoViews and use dedicated instances instead. This also enables the final removal of the remaining `targetNames`. * Move the code of some getters Move the code of some getters into the header file. * Several code review changes Apply some code review proposals. Co-authored-by: Sotonye Atemie <sakertooth@gmail.com> --------- Co-authored-by: Sotonye Atemie <sakertooth@gmail.com>
1 parent f44aa3e commit 8821d88

File tree

4 files changed

+124
-106
lines changed

4 files changed

+124
-106
lines changed

include/InstrumentSoundShaping.h

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626
#define LMMS_INSTRUMENT_SOUND_SHAPING_H
2727

2828
#include "ComboBoxModel.h"
29+
#include "EnvelopeAndLfoParameters.h"
2930

3031
namespace lmms
3132
{
3233

3334

3435
class InstrumentTrack;
35-
class EnvelopeAndLfoParameters;
3636
class NotePlayHandle;
3737
class SampleFrame;
3838

@@ -52,14 +52,19 @@ class InstrumentSoundShaping : public Model, public JournallingObject
5252
void processAudioBuffer( SampleFrame* _ab, const fpp_t _frames,
5353
NotePlayHandle * _n );
5454

55-
enum class Target
56-
{
57-
Volume,
58-
Cut,
59-
Resonance,
60-
Count
61-
} ;
62-
constexpr static auto NumTargets = static_cast<std::size_t>(Target::Count);
55+
const EnvelopeAndLfoParameters& getVolumeParameters() const { return m_volumeParameters; }
56+
EnvelopeAndLfoParameters& getVolumeParameters() { return m_volumeParameters; }
57+
58+
const EnvelopeAndLfoParameters& getCutoffParameters() const { return m_cutoffParameters; }
59+
EnvelopeAndLfoParameters& getCutoffParameters() { return m_cutoffParameters; }
60+
61+
const EnvelopeAndLfoParameters& getResonanceParameters() const { return m_resonanceParameters; }
62+
EnvelopeAndLfoParameters& getResonanceParameters() { return m_resonanceParameters; }
63+
64+
BoolModel& getFilterEnabledModel() { return m_filterEnabledModel; }
65+
ComboBoxModel& getFilterModel() { return m_filterModel; }
66+
FloatModel& getFilterCutModel() { return m_filterCutModel; }
67+
FloatModel& getFilterResModel() { return m_filterResModel; }
6368

6469
f_cnt_t envFrames( const bool _only_vol = false ) const;
6570
f_cnt_t releaseFrames() const;
@@ -74,22 +79,23 @@ class InstrumentSoundShaping : public Model, public JournallingObject
7479
return "eldata";
7580
}
7681

82+
private:
83+
QString getVolumeNodeName() const;
84+
QString getCutoffNodeName() const;
85+
QString getResonanceNodeName() const;
7786

7887
private:
79-
EnvelopeAndLfoParameters * m_envLfoParameters[NumTargets];
8088
InstrumentTrack * m_instrumentTrack;
8189

90+
EnvelopeAndLfoParameters m_volumeParameters;
91+
EnvelopeAndLfoParameters m_cutoffParameters;
92+
EnvelopeAndLfoParameters m_resonanceParameters;
93+
8294
BoolModel m_filterEnabledModel;
8395
ComboBoxModel m_filterModel;
8496
FloatModel m_filterCutModel;
8597
FloatModel m_filterResModel;
86-
87-
static const char *const targetNames[NumTargets][3];
88-
89-
90-
friend class gui::InstrumentSoundShapingView;
91-
92-
} ;
98+
};
9399

94100

95101
} // namespace lmms

include/InstrumentSoundShapingView.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ class InstrumentSoundShapingView : public QWidget, public ModelView
5858

5959
InstrumentSoundShaping * m_ss = nullptr;
6060
TabWidget * m_targetsTabWidget;
61-
EnvelopeAndLfoView * m_envLfoViews[InstrumentSoundShaping::NumTargets];
61+
62+
EnvelopeAndLfoView* m_volumeView;
63+
EnvelopeAndLfoView* m_cutoffView;
64+
EnvelopeAndLfoView* m_resonanceView;
6265

6366
// filter-stuff
6467
GroupBox * m_filterGroupBox;
@@ -67,8 +70,7 @@ class InstrumentSoundShapingView : public QWidget, public ModelView
6770
Knob * m_filterResKnob;
6871

6972
QLabel* m_singleStreamInfoLabel;
70-
71-
} ;
73+
};
7274

7375

7476
} // namespace lmms::gui

src/core/InstrumentSoundShaping.cpp

Lines changed: 81 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
#include "BasicFilters.h"
3131
#include "embed.h"
3232
#include "Engine.h"
33-
#include "EnvelopeAndLfoParameters.h"
3433
#include "Instrument.h"
3534
#include "InstrumentTrack.h"
3635

@@ -43,42 +42,21 @@ const float RES_MULTIPLIER = 2.0f;
4342
const float RES_PRECISION = 1000.0f;
4443

4544

46-
// names for env- and lfo-targets - first is name being displayed to user
47-
// and second one is used internally, e.g. for saving/restoring settings
48-
const char *const InstrumentSoundShaping::targetNames[InstrumentSoundShaping::NumTargets][3] =
49-
{
50-
{ QT_TRANSLATE_NOOP("InstrumentSoundShaping", "VOLUME"), "vol",
51-
QT_TRANSLATE_NOOP("InstrumentSoundShaping", "Volume") },
52-
{ QT_TRANSLATE_NOOP("InstrumentSoundShaping", "CUTOFF"), "cut",
53-
QT_TRANSLATE_NOOP("InstrumentSoundShaping", "Cutoff frequency") },
54-
{ QT_TRANSLATE_NOOP("InstrumentSoundShaping", "RESO"), "res",
55-
QT_TRANSLATE_NOOP("InstrumentSoundShaping", "Resonance") }
56-
} ;
57-
58-
59-
6045
InstrumentSoundShaping::InstrumentSoundShaping(
6146
InstrumentTrack * _instrument_track ) :
6247
Model( _instrument_track, tr( "Envelopes/LFOs" ) ),
6348
m_instrumentTrack( _instrument_track ),
49+
m_volumeParameters(1., this),
50+
m_cutoffParameters(0., this),
51+
m_resonanceParameters(0., this),
6452
m_filterEnabledModel( false, this ),
6553
m_filterModel( this, tr( "Filter type" ) ),
6654
m_filterCutModel( 14000.0, 1.0, 14000.0, 1.0, this, tr( "Cutoff frequency" ) ),
6755
m_filterResModel(0.5f, BasicFilters<>::minQ(), 10.f, 0.01f, this, tr("Q/Resonance"))
6856
{
69-
for (auto i = std::size_t{0}; i < NumTargets; ++i)
70-
{
71-
float value_for_zero_amount = 0.0;
72-
if( static_cast<Target>(i) == Target::Volume )
73-
{
74-
value_for_zero_amount = 1.0;
75-
}
76-
m_envLfoParameters[i] = new EnvelopeAndLfoParameters(
77-
value_for_zero_amount,
78-
this );
79-
m_envLfoParameters[i]->setDisplayName(
80-
tr( targetNames[i][2] ) );
81-
}
57+
m_volumeParameters.setDisplayName(tr("Volume"));
58+
m_cutoffParameters.setDisplayName(tr("Cutoff frequency"));
59+
m_resonanceParameters.setDisplayName(tr("Resonance"));
8260

8361
m_filterModel.addItem( tr( "Low-pass" ), std::make_unique<PixmapLoader>( "filter_lp" ) );
8462
m_filterModel.addItem( tr( "Hi-pass" ), std::make_unique<PixmapLoader>( "filter_hp" ) );
@@ -119,7 +97,7 @@ float InstrumentSoundShaping::volumeLevel( NotePlayHandle* n, const f_cnt_t fram
11997
}
12098

12199
float level;
122-
m_envLfoParameters[static_cast<std::size_t>(Target::Volume)]->fillLevel( &level, frame, envReleaseBegin, 1 );
100+
getVolumeParameters().fillLevel(&level, frame, envReleaseBegin, 1);
123101

124102
return level;
125103
}
@@ -148,6 +126,9 @@ void InstrumentSoundShaping::processAudioBuffer( SampleFrame* buffer,
148126

149127
// only use filter, if it is really needed
150128

129+
auto& cutoffParameters = getCutoffParameters();
130+
auto& resonanceParameters = getResonanceParameters();
131+
151132
if( m_filterEnabledModel.value() )
152133
{
153134
QVarLengthArray<float> cutBuffer(frames);
@@ -162,20 +143,20 @@ void InstrumentSoundShaping::processAudioBuffer( SampleFrame* buffer,
162143
}
163144
n->m_filter->setFilterType( static_cast<BasicFilters<>::FilterType>(m_filterModel.value()) );
164145

165-
if( m_envLfoParameters[static_cast<std::size_t>(Target::Cut)]->isUsed() )
146+
if (cutoffParameters.isUsed())
166147
{
167-
m_envLfoParameters[static_cast<std::size_t>(Target::Cut)]->fillLevel( cutBuffer.data(), envTotalFrames, envReleaseBegin, frames );
148+
cutoffParameters.fillLevel(cutBuffer.data(), envTotalFrames, envReleaseBegin, frames);
168149
}
169-
if( m_envLfoParameters[static_cast<std::size_t>(Target::Resonance)]->isUsed() )
150+
151+
if (resonanceParameters.isUsed())
170152
{
171-
m_envLfoParameters[static_cast<std::size_t>(Target::Resonance)]->fillLevel( resBuffer.data(), envTotalFrames, envReleaseBegin, frames );
153+
resonanceParameters.fillLevel(resBuffer.data(), envTotalFrames, envReleaseBegin, frames);
172154
}
173155

174156
const float fcv = m_filterCutModel.value();
175157
const float frv = m_filterResModel.value();
176158

177-
if( m_envLfoParameters[static_cast<std::size_t>(Target::Cut)]->isUsed() &&
178-
m_envLfoParameters[static_cast<std::size_t>(Target::Resonance)]->isUsed() )
159+
if (cutoffParameters.isUsed() && resonanceParameters.isUsed())
179160
{
180161
for( fpp_t frame = 0; frame < frames; ++frame )
181162
{
@@ -196,7 +177,7 @@ void InstrumentSoundShaping::processAudioBuffer( SampleFrame* buffer,
196177
buffer[frame][1] = n->m_filter->update( buffer[frame][1], 1 );
197178
}
198179
}
199-
else if( m_envLfoParameters[static_cast<std::size_t>(Target::Cut)]->isUsed() )
180+
else if (cutoffParameters.isUsed())
200181
{
201182
for( fpp_t frame = 0; frame < frames; ++frame )
202183
{
@@ -213,7 +194,7 @@ void InstrumentSoundShaping::processAudioBuffer( SampleFrame* buffer,
213194
buffer[frame][1] = n->m_filter->update( buffer[frame][1], 1 );
214195
}
215196
}
216-
else if( m_envLfoParameters[static_cast<std::size_t>(Target::Resonance)]->isUsed() )
197+
else if(resonanceParameters.isUsed() )
217198
{
218199
for( fpp_t frame = 0; frame < frames; ++frame )
219200
{
@@ -241,10 +222,12 @@ void InstrumentSoundShaping::processAudioBuffer( SampleFrame* buffer,
241222
}
242223
}
243224

244-
if( m_envLfoParameters[static_cast<std::size_t>(Target::Volume)]->isUsed() )
225+
auto& volumeParameters = getVolumeParameters();
226+
227+
if (volumeParameters.isUsed())
245228
{
246229
QVarLengthArray<float> volBuffer(frames);
247-
m_envLfoParameters[static_cast<std::size_t>(Target::Volume)]->fillLevel( volBuffer.data(), envTotalFrames, envReleaseBegin, frames );
230+
volumeParameters.fillLevel(volBuffer.data(), envTotalFrames, envReleaseBegin, frames);
248231

249232
for( fpp_t frame = 0; frame < frames; ++frame )
250233
{
@@ -275,19 +258,23 @@ void InstrumentSoundShaping::processAudioBuffer( SampleFrame* buffer,
275258

276259
f_cnt_t InstrumentSoundShaping::envFrames( const bool _only_vol ) const
277260
{
278-
f_cnt_t ret_val = m_envLfoParameters[static_cast<std::size_t>(Target::Volume)]->PAHD_Frames();
261+
f_cnt_t ret_val = getVolumeParameters().PAHD_Frames();
279262

280-
if( _only_vol == false )
263+
if (!_only_vol)
281264
{
282-
for (auto i = static_cast<std::size_t>(Target::Volume) + 1; i < NumTargets; ++i)
265+
auto& cutoffParameters = getCutoffParameters();
266+
if (cutoffParameters.isUsed())
283267
{
284-
if( m_envLfoParameters[i]->isUsed() &&
285-
m_envLfoParameters[i]->PAHD_Frames() > ret_val )
286-
{
287-
ret_val = m_envLfoParameters[i]->PAHD_Frames();
288-
}
268+
ret_val = std::max(ret_val, cutoffParameters.PAHD_Frames());
269+
}
270+
271+
auto& resonanceParameters = getResonanceParameters();
272+
if (resonanceParameters.isUsed())
273+
{
274+
ret_val = std::max(ret_val, resonanceParameters.PAHD_Frames());
289275
}
290276
}
277+
291278
return ret_val;
292279
}
293280

@@ -308,23 +295,33 @@ f_cnt_t InstrumentSoundShaping::releaseFrames() const
308295
return ret_val;
309296
}
310297

311-
if( m_envLfoParameters[static_cast<std::size_t>(Target::Volume)]->isUsed() )
298+
auto& volumeParameters = getVolumeParameters();
299+
300+
if (volumeParameters.isUsed())
312301
{
313-
return m_envLfoParameters[static_cast<std::size_t>(Target::Volume)]->releaseFrames();
302+
return volumeParameters.releaseFrames();
314303
}
315304

316-
for (auto i = static_cast<std::size_t>(Target::Volume) + 1; i < NumTargets; ++i)
305+
auto& cutoffParameters = getCutoffParameters();
306+
if (cutoffParameters.isUsed())
317307
{
318-
if( m_envLfoParameters[i]->isUsed() )
319-
{
320-
ret_val = std::max(ret_val, m_envLfoParameters[i]->releaseFrames());
321-
}
308+
ret_val = std::max(ret_val, cutoffParameters.releaseFrames());
309+
}
310+
311+
auto& resonanceParameters = getResonanceParameters();
312+
if (resonanceParameters.isUsed())
313+
{
314+
ret_val = std::max(ret_val, resonanceParameters.releaseFrames());
322315
}
316+
323317
return ret_val;
324318
}
325319

326320

327-
321+
static void saveEnvelopeAndLFOParameters(EnvelopeAndLfoParameters& p, const QString & tagName, QDomDocument & _doc, QDomElement & _this)
322+
{
323+
p.saveState(_doc, _this).setTagName(tagName);
324+
}
328325

329326
void InstrumentSoundShaping::saveSettings( QDomDocument & _doc, QDomElement & _this )
330327
{
@@ -333,12 +330,9 @@ void InstrumentSoundShaping::saveSettings( QDomDocument & _doc, QDomElement & _t
333330
m_filterResModel.saveSettings( _doc, _this, "fres" );
334331
m_filterEnabledModel.saveSettings( _doc, _this, "fwet" );
335332

336-
for (auto i = std::size_t{0}; i < NumTargets; ++i)
337-
{
338-
m_envLfoParameters[i]->saveState( _doc, _this ).setTagName(
339-
m_envLfoParameters[i]->nodeName() +
340-
QString( targetNames[i][1] ).toLower() );
341-
}
333+
saveEnvelopeAndLFOParameters(getVolumeParameters(), getVolumeNodeName(), _doc, _this);
334+
saveEnvelopeAndLFOParameters(getCutoffParameters(), getCutoffNodeName(), _doc, _this);
335+
saveEnvelopeAndLFOParameters(getResonanceParameters(), getResonanceNodeName(), _doc, _this);
342336
}
343337

344338

@@ -352,27 +346,42 @@ void InstrumentSoundShaping::loadSettings( const QDomElement & _this )
352346
m_filterEnabledModel.loadSettings( _this, "fwet" );
353347

354348
QDomNode node = _this.firstChild();
355-
while( !node.isNull() )
349+
while (!node.isNull())
356350
{
357-
if( node.isElement() )
351+
if (node.isElement())
358352
{
359-
for (auto i = std::size_t{0}; i < NumTargets; ++i)
353+
const auto nodeName = node.nodeName();
354+
if (nodeName == getVolumeNodeName())
360355
{
361-
if( node.nodeName() ==
362-
m_envLfoParameters[i]->nodeName() +
363-
QString( targetNames[i][1] ).
364-
toLower() )
365-
{
366-
m_envLfoParameters[i]->restoreState( node.toElement() );
367-
}
356+
getVolumeParameters().restoreState(node.toElement());
357+
}
358+
else if (nodeName == getCutoffNodeName())
359+
{
360+
getCutoffParameters().restoreState(node.toElement());
361+
}
362+
else if (nodeName == getResonanceNodeName())
363+
{
364+
getResonanceParameters().restoreState(node.toElement());
368365
}
369366
}
367+
370368
node = node.nextSibling();
371369
}
372370
}
373371

372+
QString InstrumentSoundShaping::getVolumeNodeName() const
373+
{
374+
return getVolumeParameters().nodeName() + "vol";
375+
}
374376

377+
QString InstrumentSoundShaping::getCutoffNodeName() const
378+
{
379+
return getCutoffParameters().nodeName() + "cut";
380+
}
375381

376-
382+
QString InstrumentSoundShaping::getResonanceNodeName() const
383+
{
384+
return getResonanceParameters().nodeName() + "res";
385+
}
377386

378387
} // namespace lmms

0 commit comments

Comments
 (0)