Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_ParameterAttachments.cpp 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. ParameterAttachment::ParameterAttachment (RangedAudioParameter& param,
  21. std::function<void (float)> parameterChangedCallback,
  22. UndoManager* um)
  23. : parameter (param),
  24. undoManager (um),
  25. setValue (std::move (parameterChangedCallback))
  26. {
  27. parameter.addListener (this);
  28. }
  29. ParameterAttachment::~ParameterAttachment()
  30. {
  31. parameter.removeListener (this);
  32. cancelPendingUpdate();
  33. }
  34. void ParameterAttachment::sendInitialUpdate()
  35. {
  36. parameterValueChanged ({}, parameter.getValue());
  37. }
  38. void ParameterAttachment::setValueAsCompleteGesture (float newDenormalisedValue)
  39. {
  40. callIfParameterValueChanged (newDenormalisedValue, [this] (float f)
  41. {
  42. beginGesture();
  43. parameter.setValueNotifyingHost (f);
  44. endGesture();
  45. });
  46. }
  47. void ParameterAttachment::beginGesture()
  48. {
  49. if (undoManager != nullptr)
  50. undoManager->beginNewTransaction();
  51. parameter.beginChangeGesture();
  52. }
  53. void ParameterAttachment::setValueAsPartOfGesture (float newDenormalisedValue)
  54. {
  55. callIfParameterValueChanged (newDenormalisedValue, [this] (float f)
  56. {
  57. parameter.setValueNotifyingHost (f);
  58. });
  59. }
  60. void ParameterAttachment::endGesture()
  61. {
  62. parameter.endChangeGesture();
  63. }
  64. template <typename Callback>
  65. void ParameterAttachment::callIfParameterValueChanged (float newDenormalisedValue,
  66. Callback&& callback)
  67. {
  68. const auto newValue = normalise (newDenormalisedValue);
  69. if (parameter.getValue() != newValue)
  70. callback (newValue);
  71. }
  72. void ParameterAttachment::parameterValueChanged (int, float newValue)
  73. {
  74. lastValue = newValue;
  75. if (MessageManager::getInstance()->isThisTheMessageThread())
  76. {
  77. cancelPendingUpdate();
  78. handleAsyncUpdate();
  79. }
  80. else
  81. {
  82. triggerAsyncUpdate();
  83. }
  84. }
  85. void ParameterAttachment::handleAsyncUpdate()
  86. {
  87. if (setValue != nullptr)
  88. setValue (parameter.convertFrom0to1 (lastValue));
  89. }
  90. //==============================================================================
  91. SliderParameterAttachment::SliderParameterAttachment (RangedAudioParameter& param,
  92. Slider& s,
  93. UndoManager* um)
  94. : slider (s),
  95. attachment (param, [this] (float f) { setValue (f); }, um)
  96. {
  97. slider.valueFromTextFunction = [&param] (const String& text) { return (double) param.convertFrom0to1 (param.getValueForText (text)); };
  98. slider.textFromValueFunction = [&param] (double value) { return param.getText (param.convertTo0to1 ((float) value), 0); };
  99. slider.setDoubleClickReturnValue (true, param.convertFrom0to1 (param.getDefaultValue()));
  100. auto range = param.getNormalisableRange();
  101. auto convertFrom0To1Function = [range] (double currentRangeStart,
  102. double currentRangeEnd,
  103. double normalisedValue) mutable
  104. {
  105. range.start = (float) currentRangeStart;
  106. range.end = (float) currentRangeEnd;
  107. return (double) range.convertFrom0to1 ((float) normalisedValue);
  108. };
  109. auto convertTo0To1Function = [range] (double currentRangeStart,
  110. double currentRangeEnd,
  111. double mappedValue) mutable
  112. {
  113. range.start = (float) currentRangeStart;
  114. range.end = (float) currentRangeEnd;
  115. return (double) range.convertTo0to1 ((float) mappedValue);
  116. };
  117. auto snapToLegalValueFunction = [range] (double currentRangeStart,
  118. double currentRangeEnd,
  119. double mappedValue) mutable
  120. {
  121. range.start = (float) currentRangeStart;
  122. range.end = (float) currentRangeEnd;
  123. return (double) range.snapToLegalValue ((float) mappedValue);
  124. };
  125. NormalisableRange<double> newRange { (double) range.start,
  126. (double) range.end,
  127. std::move (convertFrom0To1Function),
  128. std::move (convertTo0To1Function),
  129. std::move (snapToLegalValueFunction) };
  130. newRange.interval = range.interval;
  131. newRange.skew = range.skew;
  132. newRange.symmetricSkew = range.symmetricSkew;
  133. slider.setNormalisableRange (newRange);
  134. sendInitialUpdate();
  135. slider.valueChanged();
  136. slider.addListener (this);
  137. }
  138. SliderParameterAttachment::~SliderParameterAttachment()
  139. {
  140. slider.removeListener (this);
  141. }
  142. void SliderParameterAttachment::sendInitialUpdate() { attachment.sendInitialUpdate(); }
  143. void SliderParameterAttachment::setValue (float newValue)
  144. {
  145. const ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  146. slider.setValue (newValue, sendNotificationSync);
  147. }
  148. void SliderParameterAttachment::sliderValueChanged (Slider*)
  149. {
  150. if (ignoreCallbacks || ModifierKeys::currentModifiers.isRightButtonDown())
  151. return;
  152. attachment.setValueAsPartOfGesture ((float) slider.getValue());
  153. }
  154. //==============================================================================
  155. ComboBoxParameterAttachment::ComboBoxParameterAttachment (RangedAudioParameter& param,
  156. ComboBox& c,
  157. UndoManager* um)
  158. : comboBox (c),
  159. storedParameter (param),
  160. attachment (param, [this] (float f) { setValue (f); }, um)
  161. {
  162. sendInitialUpdate();
  163. comboBox.addListener (this);
  164. }
  165. ComboBoxParameterAttachment::~ComboBoxParameterAttachment()
  166. {
  167. comboBox.removeListener (this);
  168. }
  169. void ComboBoxParameterAttachment::sendInitialUpdate()
  170. {
  171. attachment.sendInitialUpdate();
  172. }
  173. void ComboBoxParameterAttachment::setValue (float newValue)
  174. {
  175. const auto normValue = storedParameter.convertTo0to1 (newValue);
  176. const auto index = roundToInt (normValue * (float) (comboBox.getNumItems() - 1));
  177. if (index == comboBox.getSelectedItemIndex())
  178. return;
  179. const ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  180. comboBox.setSelectedItemIndex (index, sendNotificationSync);
  181. }
  182. void ComboBoxParameterAttachment::comboBoxChanged (ComboBox*)
  183. {
  184. if (ignoreCallbacks)
  185. return;
  186. const auto numItems = comboBox.getNumItems();
  187. const auto selected = (float) comboBox.getSelectedItemIndex();
  188. const auto newValue = numItems > 1 ? selected / (float) (numItems - 1)
  189. : 0.0f;
  190. attachment.setValueAsCompleteGesture (storedParameter.convertFrom0to1 (newValue));
  191. }
  192. //==============================================================================
  193. ButtonParameterAttachment::ButtonParameterAttachment (RangedAudioParameter& param,
  194. Button& b,
  195. UndoManager* um)
  196. : button (b),
  197. attachment (param, [this] (float f) { setValue (f); }, um)
  198. {
  199. sendInitialUpdate();
  200. button.addListener (this);
  201. }
  202. ButtonParameterAttachment::~ButtonParameterAttachment()
  203. {
  204. button.removeListener (this);
  205. }
  206. void ButtonParameterAttachment::sendInitialUpdate()
  207. {
  208. attachment.sendInitialUpdate();
  209. }
  210. void ButtonParameterAttachment::setValue (float newValue)
  211. {
  212. const ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  213. button.setToggleState (newValue >= 0.5f, sendNotificationSync);
  214. }
  215. void ButtonParameterAttachment::buttonClicked (Button*)
  216. {
  217. if (ignoreCallbacks)
  218. return;
  219. attachment.setValueAsCompleteGesture (button.getToggleState() ? 1.0f : 0.0f);
  220. }
  221. } // namespace juce