gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

parameter.cpp (7826B)


      1 #include "parameter.h"
      2 
      3 #include "controller.h"
      4 
      5 namespace pluginLib
      6 {
      7 	Parameter::Parameter(Controller& _controller, const Description& _desc, const uint8_t _partNum, const int _uniqueId, const PartFormatter& _partFormatter)
      8 		: juce::RangedAudioParameter(genId(_desc, _partNum, _uniqueId), _partFormatter(_partNum, _desc.isNonPartSensitive()) + " " + _desc.displayName)
      9 		, m_controller(_controller)
     10 		, m_desc(_desc)
     11 		, m_part(_partNum)
     12 		, m_uniqueId(_uniqueId)
     13 	{
     14 		m_range.start = static_cast<float>(m_desc.range.getStart());
     15 		m_range.end = static_cast<float>(m_desc.range.getEnd());
     16 		m_range.interval = m_desc.step ? static_cast<float>(m_desc.step) : (m_desc.isDiscrete || m_desc.isBool ? 1.0f : 0.0f);
     17 
     18 		m_value.setValue(m_range.start);
     19 		m_value.addListener(this);
     20     }
     21 
     22     void Parameter::valueChanged(juce::Value&)
     23     {
     24 		sendToSynth();
     25 		onValueChanged(this);
     26 	}
     27 
     28     void Parameter::setDerivedValue(const int _value)
     29     {
     30 		const int newValue = clampValue(_value);
     31 
     32 		if (newValue == m_lastValue)
     33 			return;
     34 
     35 		m_lastValue = newValue;
     36 		m_lastValueOrigin = Origin::Derived;
     37 
     38 		m_value.setValue(newValue);
     39 	}
     40 
     41     void Parameter::sendToSynth()
     42     {
     43 		const float floatValue = m_value.getValue();
     44 		const auto value = juce::roundToInt(floatValue);
     45 
     46 		jassert(m_range.getRange().contains(floatValue) || m_range.end == floatValue);
     47 
     48 		if (value == m_lastValue)
     49 			return;
     50 
     51 		// ignore initial update
     52 		if (m_lastValue != -1)
     53 		{
     54 			if(m_rateLimit)
     55 			{
     56 				sendParameterChangeDelayed(value, ++m_uniqueDelayCallbackId);
     57 			}
     58 			else
     59 			{
     60 				m_lastSendTime = milliseconds();
     61 				m_controller.sendParameterChange(*this, value);
     62 			}
     63 		}
     64 
     65 		m_lastValue = value;
     66     }
     67 
     68     uint64_t Parameter::milliseconds()
     69     {
     70 		const auto t = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch());
     71 		return t.count();
     72     }
     73 
     74     void Parameter::sendParameterChangeDelayed(const ParamValue _value, uint32_t _uniqueId)
     75     {
     76 		if(_uniqueId != m_uniqueDelayCallbackId)
     77 			return;
     78 
     79 		const auto ms = milliseconds();
     80 
     81 		const auto elapsed = ms - m_lastSendTime;
     82 		if(elapsed >= m_rateLimit)
     83 		{
     84 			m_lastSendTime = ms;
     85 			m_controller.sendParameterChange(*this, _value);
     86 		}
     87 		else
     88 		{
     89 			juce::Timer::callAfterDelay(static_cast<int>(elapsed), [this, _value, _uniqueId]
     90 			{
     91 				sendParameterChangeDelayed(_value, _uniqueId);
     92 			});
     93 		}
     94     }
     95 
     96     int Parameter::clampValue(const int _value) const
     97     {
     98 		return juce::roundToInt(m_range.getRange().clipValue(static_cast<float>(_value)));
     99     }
    100 
    101     void Parameter::setValueNotifyingHost(const float _value, const Origin _origin)
    102     {
    103 		ScopedChangeGesture g(*this);
    104 		setUnnormalizedValue(juce::roundToInt(convertFrom0to1(_value)), _origin);
    105 		notifyHost(_value);
    106 	}
    107 
    108     void Parameter::setUnnormalizedValueNotifyingHost(const float _value, const Origin _origin)
    109     {
    110 		ScopedChangeGesture g(*this);
    111 		setUnnormalizedValue(juce::roundToInt(_value), _origin);
    112 		notifyHost(convertTo0to1(_value));
    113     }
    114 
    115     void Parameter::setUnnormalizedValueNotifyingHost(const int _value, const Origin _origin)
    116     {
    117 		ScopedChangeGesture g(*this);
    118 		setUnnormalizedValue(_value, _origin);
    119 		notifyHost(convertTo0to1(static_cast<float>(_value)));
    120     }
    121 
    122     void Parameter::setRateLimitMilliseconds(const uint32_t _ms)
    123     {
    124 	    m_rateLimit = _ms;
    125     }
    126 
    127     void Parameter::setLinkState(const ParameterLinkType _type)
    128     {
    129 		const auto prev = m_linkType;
    130 		m_linkType = static_cast<ParameterLinkType>(m_linkType | _type);
    131 		if(m_linkType != prev)
    132 			onLinkStateChanged(this, m_linkType);
    133     }
    134 
    135     void Parameter::clearLinkState(const ParameterLinkType _type)
    136     {
    137 		const auto prev = m_linkType;
    138 		m_linkType = static_cast<ParameterLinkType>(m_linkType & ~_type);
    139 		if(m_linkType != prev)
    140 			onLinkStateChanged(this, m_linkType);
    141     }
    142 
    143     void Parameter::pushChangeGesture()
    144     {
    145 		if(!m_changeGestureCount)
    146 			beginChangeGesture();
    147 		++m_changeGestureCount;
    148     }
    149 
    150     void Parameter::popChangeGesture()
    151     {
    152 		assert(m_changeGestureCount > 0);
    153 		--m_changeGestureCount;
    154 		if(!m_changeGestureCount)
    155 			endChangeGesture();
    156     }
    157 
    158     bool Parameter::isMetaParameter() const
    159     {
    160 	    return !m_derivedParameters.empty();
    161     }
    162 
    163     void Parameter::setValue(const float _newValue)
    164 	{
    165 		// some plugin formats (VST3 for example) bounce back immediately, skip this, we don't
    166 		// want it and VST2 doesn't do it either so why does Juce for VST3?
    167 		// It's not the host, it's the Juce VST3 implementation
    168 		if(m_notifyingHost)
    169 			return;
    170 
    171 		setUnnormalizedValue(juce::roundToInt(convertFrom0to1(_newValue)), Origin::HostAutomation);
    172 	}
    173 
    174     void Parameter::setUnnormalizedValue(const int _newValue, const Origin _origin)
    175     {
    176 		if (m_changingDerivedValues)
    177 			return;
    178 
    179 		m_lastValueOrigin = _origin;
    180 		m_value.setValue(clampValue(_newValue));
    181 
    182 		if(_origin != Origin::Derived)
    183 			sendToSynth();
    184 
    185 		forwardToDerived(_newValue);
    186     }
    187 
    188     void Parameter::setValueFromSynth(const int _newValue, const Origin _origin)
    189 	{
    190 		const auto clampedValue = clampValue(_newValue);
    191 
    192 		// we do not want to send an excessive amount of value changes to the host if a preset is
    193 		// changed, we use updateHostDisplay() (see caller) to inform the host to read all
    194 		// parameters again instead
    195 		const auto notifyHost = _origin != Origin::PresetChange;
    196 
    197 		if (clampedValue != m_lastValue)
    198 		{
    199 			m_lastValue = clampedValue;
    200 			m_lastValueOrigin = _origin;
    201 
    202 			if (notifyHost && getDescription().isPublic)
    203 			{
    204 				setUnnormalizedValueNotifyingHost(clampedValue, _origin);
    205 			}
    206 			else
    207 			{
    208 				m_value.setValue(clampedValue);
    209 			}
    210 		}
    211 
    212 		forwardToDerived(_newValue);
    213 	}
    214 
    215     void Parameter::forwardToDerived(const int _newValue)
    216     {
    217 		if (m_changingDerivedValues)
    218 			return;
    219 
    220 		m_changingDerivedValues = true;
    221 
    222 		for (const auto& p : m_derivedParameters)
    223 			p->setDerivedValue(_newValue);
    224 
    225 		m_changingDerivedValues = false;
    226     }
    227 
    228     void Parameter::notifyHost(const float _value)
    229     {
    230 		m_notifyingHost = true;
    231 		sendValueChangedMessageToListeners(_value);
    232 		m_notifyingHost = false;
    233     }
    234 
    235     juce::String Parameter::genId(const Description& d, const int part, const int uniqueId)
    236 	{
    237 		if(uniqueId > 0)
    238 			return juce::String::formatted("%d_%d_%d_%d", static_cast<int>(d.page), part, d.index, uniqueId);
    239 		return juce::String::formatted("%d_%d_%d", static_cast<int>(d.page), part, d.index);
    240 	}
    241 
    242 	float Parameter::getValueForText(const juce::String& _text) const
    243 	{
    244 		auto res = m_desc.valueList.textToValue(std::string(_text.getCharPointer()));
    245 		if(m_desc.range.getStart() < 0)
    246 			res += m_desc.range.getStart();
    247 		return convertTo0to1(static_cast<float>(res));
    248 	}
    249 
    250 	ParamValue Parameter::getDefault() const
    251 	{
    252 		if(m_desc.defaultValue != Description::NoDefaultValue)
    253 			return m_desc.defaultValue;
    254 		return 0;
    255 	}
    256 
    257 	juce::String Parameter::getText(const float _normalisedValue, int _i) const
    258 	{
    259 		const auto v = convertFrom0to1(_normalisedValue);
    260 		return m_desc.valueList.valueToText(juce::roundToInt(v) - std::min(0, m_desc.range.getStart()));
    261 	}
    262 
    263 	void Parameter::setLocked(const bool _locked)
    264 	{
    265 		if(m_isLocked == _locked)
    266 			return;
    267 
    268 		m_isLocked = _locked;
    269 
    270 		onLockedChanged(this, m_isLocked);
    271 	}
    272 
    273 	void Parameter::addDerivedParameter(Parameter* _param)
    274 	{
    275 		if (_param == this)
    276 			return;
    277 
    278 		for (auto* p : m_derivedParameters)
    279 		{
    280 			_param->m_derivedParameters.insert(p);
    281 			p->m_derivedParameters.insert(_param);
    282 		}
    283 
    284 		m_derivedParameters.insert(_param);
    285 		_param->m_derivedParameters.insert(this);
    286 	}
    287 
    288 	Parameter::ScopedChangeGesture::ScopedChangeGesture(Parameter& _p) : m_parameter(_p)
    289     {
    290 		if(_p.getDescription().isPublic)
    291 		    _p.pushChangeGesture();
    292     }
    293 
    294     Parameter::ScopedChangeGesture::~ScopedChangeGesture()
    295     {
    296 		if(m_parameter.getDescription().isPublic)
    297 		    m_parameter.popChangeGesture();
    298     }
    299 
    300 }