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.

1247 lines
43KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "CarlaNative.hpp"
  18. #include "CarlaString.hpp"
  19. #include "JucePluginWindow.hpp"
  20. using namespace juce;
  21. #include "vex/VexArp.h"
  22. #include "vex/VexChorus.h"
  23. #include "vex/VexDelay.h"
  24. #include "vex/VexReverb.h"
  25. #include "vex/VexSyntModule.h"
  26. #include "vex/PeggyViewComponent.h"
  27. #include "vex/gui/SnappingSlider.h"
  28. #include "vex/lookandfeel/MyLookAndFeel.h"
  29. #include "vex/resources/Resources.h"
  30. // -----------------------------------------------------------------------
  31. // Copied from juce_AudioProcessor.cpp
  32. // magic number to identify memory blocks that we've stored as XML
  33. const uint32 magicXmlNumber = 0x21324356;
  34. void copyXmlToBinary(const XmlElement& xml, juce::MemoryBlock& destData)
  35. {
  36. const String xmlString(xml.createDocument(String::empty, true, false));
  37. const size_t stringLength = xmlString.getNumBytesAsUTF8();
  38. destData.setSize(stringLength + 9);
  39. uint32* const d = static_cast<uint32*>(destData.getData());
  40. d[0] = ByteOrder::swapIfBigEndian((const uint32) magicXmlNumber);
  41. d[1] = ByteOrder::swapIfBigEndian((const uint32) stringLength);
  42. xmlString.copyToUTF8((CharPointer_UTF8::CharType*) (d + 2), stringLength + 1);
  43. }
  44. XmlElement* getXmlFromBinary(const void* data, const int sizeInBytes)
  45. {
  46. if (sizeInBytes > 8 && ByteOrder::littleEndianInt(data) == magicXmlNumber)
  47. {
  48. const int stringLength = (int) ByteOrder::littleEndianInt (addBytesToPointer (data, 4));
  49. if (stringLength > 0)
  50. return XmlDocument::parse (String::fromUTF8 (static_cast<const char*> (data) + 8, jmin ((sizeInBytes - 8), stringLength)));
  51. }
  52. return nullptr;
  53. }
  54. // -----------------------------------------------------------------------
  55. class VexEditorComponent : public Component,
  56. public Timer,
  57. public ComboBox::Listener,
  58. public Slider::Listener,
  59. public Button::Listener,
  60. public PeggyViewComponent::Callback // ignored
  61. {
  62. public:
  63. class Callback
  64. {
  65. public:
  66. virtual ~Callback() {}
  67. virtual void getChangedParameters(bool params[92]) = 0;
  68. virtual float getFilterParameterValue(const uint32_t index) const = 0;
  69. virtual String getFilterWaveName(const int part) const = 0;
  70. virtual void editorParameterChanged(const uint32_t index, const float value) = 0;
  71. virtual void editorWaveChanged(const int part, const String& wave) = 0;
  72. };
  73. VexEditorComponent(Callback* const callback, VexArpSettings& arpSet1, VexArpSettings& arpSet2, VexArpSettings& arpSet3)
  74. : fCallback(callback),
  75. fNeedsUpdate(false)
  76. {
  77. internalCachedImage1 = ImageCache::getFromMemory(Resources::vex3_png, Resources::vex3_pngSize);
  78. // Comboboxes, wave selection
  79. addAndMakeVisible(comboBox1 = new ComboBox("comboBox1"));
  80. comboBox1->setEditableText(false);
  81. comboBox1->setJustificationType(Justification::centredLeft);
  82. comboBox1->setTextWhenNothingSelected(String("silent"));
  83. comboBox1->setTextWhenNoChoicesAvailable(String("silent"));
  84. comboBox1->addListener(this);
  85. comboBox1->setColour(ComboBox::backgroundColourId, Colours::black);
  86. comboBox1->setColour(ComboBox::textColourId, Colours::lightgrey);
  87. comboBox1->setColour(ComboBox::outlineColourId, Colours::grey);
  88. comboBox1->setColour(ComboBox::buttonColourId, Colours::grey);
  89. comboBox1->setWantsKeyboardFocus(false);
  90. comboBox1->setLookAndFeel(&mlaf);
  91. addAndMakeVisible(comboBox2 = new ComboBox("comboBox2"));
  92. comboBox2->setEditableText(false);
  93. comboBox2->setJustificationType(Justification::centredLeft);
  94. comboBox2->setTextWhenNothingSelected(String("silent"));
  95. comboBox2->setTextWhenNoChoicesAvailable(String("silent"));
  96. comboBox2->addListener(this);
  97. comboBox2->setColour(ComboBox::backgroundColourId, Colours::black);
  98. comboBox2->setColour(ComboBox::textColourId, Colours::lightgrey);
  99. comboBox2->setColour(ComboBox::outlineColourId, Colours::grey);
  100. comboBox2->setColour(ComboBox::buttonColourId, Colours::grey);
  101. comboBox2->setWantsKeyboardFocus(false);
  102. comboBox2->setLookAndFeel(&mlaf);
  103. addAndMakeVisible(comboBox3 = new ComboBox("comboBox3"));
  104. comboBox3->setEditableText(false);
  105. comboBox3->setJustificationType(Justification::centredLeft);
  106. comboBox3->setTextWhenNothingSelected(String("silent"));
  107. comboBox3->setTextWhenNoChoicesAvailable(String("silent"));
  108. comboBox3->addListener(this);
  109. comboBox3->setColour(ComboBox::backgroundColourId, Colours::black);
  110. comboBox3->setColour(ComboBox::textColourId, Colours::lightgrey);
  111. comboBox3->setColour(ComboBox::outlineColourId, Colours::grey);
  112. comboBox3->setColour(ComboBox::buttonColourId, Colours::grey);
  113. comboBox3->setWantsKeyboardFocus(false);
  114. comboBox3->setLookAndFeel(&mlaf);
  115. for (int i = 0, tableSize = WaveRenderer::getWaveTableSize(); i < tableSize; ++i)
  116. {
  117. String tableName(WaveRenderer::getWaveTableName(i));
  118. comboBox1->addItem(tableName, i + 1);
  119. comboBox2->addItem(tableName, i + 1);
  120. comboBox3->addItem(tableName, i + 1);
  121. }
  122. //Make sliders
  123. for (int i = 0; i < kSliderCount; ++i)
  124. {
  125. addAndMakeVisible(sliders[i] = new SnappingSlider("s"));
  126. sliders[i]->setSliderStyle(Slider::RotaryVerticalDrag);
  127. sliders[i]->setRange(0, 1, 0);
  128. sliders[i]->setSnap(0.0f, 0.0f);
  129. sliders[i]->setLookAndFeel(&mlaf);
  130. sliders[i]->addListener(this);
  131. }
  132. //Adjust the center of some
  133. sliders[1]->setRange(0, 1, 0.25f);
  134. sliders[1]->setSnap(0.5f, 0.05f);
  135. sliders[2]->setSnap(0.5f, 0.05f);
  136. sliders[3]->setSnap(0.5f, 0.05f);
  137. sliders[4]->setSnap(0.5f, 0.05f);
  138. sliders[8]->setSnap(0.5f, 0.05f);
  139. sliders[13]->setSnap(0.5f, 0.05f);
  140. sliders[18]->setSnap(0.5f, 0.05f);
  141. int tmp = 24;
  142. sliders[1 + tmp]->setRange(0, 1, 0.25f);
  143. sliders[1 + tmp]->setSnap(0.5f, 0.05f);
  144. sliders[2 + tmp]->setSnap(0.5f, 0.05f);
  145. sliders[3 + tmp]->setSnap(0.5f, 0.05f);
  146. sliders[4 + tmp]->setSnap(0.5f, 0.05f);
  147. sliders[8 + tmp]->setSnap(0.5f, 0.05f);
  148. sliders[13 + tmp]->setSnap(0.5f, 0.05f);
  149. sliders[18 + tmp]->setSnap(0.5f, 0.05f);
  150. tmp = 48;
  151. sliders[1 + tmp]->setRange(0, 1, 0.25f);
  152. sliders[1 + tmp]->setSnap(0.5f, 0.05f);
  153. sliders[2 + tmp]->setSnap(0.5f, 0.05f);
  154. sliders[3 + tmp]->setSnap(0.5f, 0.05f);
  155. sliders[4 + tmp]->setSnap(0.5f, 0.05f);
  156. sliders[8 + tmp]->setSnap(0.5f, 0.05f);
  157. sliders[13 + tmp]->setSnap(0.5f, 0.05f);
  158. sliders[18 + tmp]->setSnap(0.5f, 0.05f);
  159. sliders[83]->setSnap(0.5f, 0.05f);
  160. sliders[84]->setSnap(0.5f, 0.05f);
  161. sliders[85]->setSnap(0.5f, 0.05f);
  162. sliders[75]->setSnap(0.0f, 0.05f);
  163. sliders[78]->setSnap(0.0f, 0.05f);
  164. sliders[82]->setSnap(0.0f, 0.05f);
  165. //PART ON/OFF
  166. addAndMakeVisible(TB1 = new TextButton("TB1"));
  167. TB1->setButtonText(String::empty);
  168. TB1->addListener(this);
  169. TB1->setColour(TextButton::buttonColourId, Colours::darkred.withAlpha(0.5f));
  170. TB1->setColour(TextButton::buttonOnColourId, Colours::red);
  171. TB1->setClickingTogglesState(true);
  172. TB1->setToggleState(false, dontSendNotification);
  173. addAndMakeVisible(TB2 = new TextButton("TB2"));
  174. TB2->setButtonText(String::empty);
  175. TB2->addListener(this);
  176. TB2->setColour(TextButton::buttonColourId, Colours::darkred.withAlpha(0.5f));
  177. TB2->setColour(TextButton::buttonOnColourId, Colours::red);
  178. TB2->setClickingTogglesState(true);
  179. TB2->setToggleState(false, dontSendNotification);
  180. addAndMakeVisible(TB3 = new TextButton("TB3"));
  181. TB3->setButtonText(String::empty);
  182. TB3->addListener(this);
  183. TB3->setColour(TextButton::buttonColourId, Colours::darkred.withAlpha(0.5f));
  184. TB3->setColour(TextButton::buttonOnColourId, Colours::red);
  185. TB3->setClickingTogglesState(true);
  186. TB3->setToggleState(false, dontSendNotification);
  187. //Peggy ON/OFF
  188. addAndMakeVisible(TB4 = new TextButton("TB4"));
  189. TB4->setButtonText(String::empty);
  190. TB4->addListener(this);
  191. TB4->setColour(TextButton::buttonColourId, Colours::darkblue.withAlpha(0.5f));
  192. TB4->setColour(TextButton::buttonOnColourId, Colours::blue);
  193. TB4->setClickingTogglesState(true);
  194. TB4->setToggleState(false, dontSendNotification);
  195. addAndMakeVisible(TB5 = new TextButton("TB5"));
  196. TB5->setButtonText(String::empty);
  197. TB5->addListener(this);
  198. TB5->setColour(TextButton::buttonColourId, Colours::darkblue.withAlpha(0.5f));
  199. TB5->setColour(TextButton::buttonOnColourId, Colours::blue);
  200. TB5->setClickingTogglesState(true);
  201. TB5->setToggleState(false, dontSendNotification);
  202. addAndMakeVisible(TB6 = new TextButton("TB6"));
  203. TB6->setButtonText(String::empty);
  204. TB6->addListener(this);
  205. TB6->setColour(TextButton::buttonColourId, Colours::darkblue.withAlpha(0.5f));
  206. TB6->setColour(TextButton::buttonOnColourId, Colours::blue);
  207. TB6->setClickingTogglesState(true);
  208. TB6->setToggleState(false, dontSendNotification);
  209. addChildComponent(p1 = new PeggyViewComponent(arpSet1, this));
  210. p1->setLookAndFeel(&mlaf);
  211. addChildComponent(p2 = new PeggyViewComponent(arpSet2, this));
  212. p2->setLookAndFeel(&mlaf);
  213. addChildComponent(p3 = new PeggyViewComponent(arpSet3, this));
  214. p3->setLookAndFeel(&mlaf);
  215. setSize(800,500);
  216. updateParametersFromFilter(true);
  217. startTimer(50);
  218. }
  219. ~VexEditorComponent()
  220. {
  221. stopTimer();
  222. removeAllChildren();
  223. }
  224. void setNeedsUpdate()
  225. {
  226. fNeedsUpdate = true;
  227. }
  228. protected:
  229. void paint(Graphics& g) override
  230. {
  231. g.drawImage(internalCachedImage1,
  232. 0, 0, 800, 500,
  233. 0, 0, internalCachedImage1.getWidth(), internalCachedImage1.getHeight());
  234. }
  235. void resized() override
  236. {
  237. comboBox1->setBounds(13, 38, 173, 23);
  238. comboBox2->setBounds(213, 38, 173, 23);
  239. comboBox3->setBounds(413, 38, 173, 23);
  240. // ...
  241. sliders[73]->setBounds(623, 23, 28, 28);
  242. sliders[74]->setBounds(686, 23, 28, 28);
  243. sliders[75]->setBounds(748, 23, 28, 28);
  244. sliders[76]->setBounds(623, 98, 28, 28);
  245. sliders[77]->setBounds(686, 98, 28, 28);
  246. sliders[78]->setBounds(748, 98, 28, 28);
  247. sliders[79]->setBounds(611, 173, 28, 28);
  248. sliders[80]->setBounds(661, 173, 28, 28);
  249. sliders[81]->setBounds(711, 173, 28, 28);
  250. sliders[82]->setBounds(761, 173, 28, 28);
  251. sliders[85]->setBounds(711, 373, 28, 28);
  252. sliders[84]->setBounds(661, 373, 28, 28);
  253. sliders[83]->setBounds(611, 373, 28, 28);
  254. sliders[86]->setBounds(611, 449, 28, 28);
  255. sliders[87]->setBounds(661, 449, 28, 28);
  256. sliders[88]->setBounds(711, 449, 28, 28);
  257. sliders[0]->setBounds(761, 449, 28, 28);
  258. // ...
  259. sliders[1]->setBounds(11, 73, 28, 28);
  260. sliders[2]->setBounds(61, 73, 28, 28);
  261. sliders[3]->setBounds(111, 73, 28, 28);
  262. sliders[4]->setBounds(161, 73, 28, 28);
  263. sliders[24 + 1]->setBounds(211, 73, 28, 28);
  264. sliders[24 + 2]->setBounds(261, 73, 28, 28);
  265. sliders[24 + 3]->setBounds(311, 73, 28, 28);
  266. sliders[24 + 4]->setBounds(361, 73, 28, 28);
  267. sliders[48 + 1]->setBounds(411, 73, 28, 28);
  268. sliders[48 + 2]->setBounds(461, 73, 28, 28);
  269. sliders[48 + 3]->setBounds(511, 73, 28, 28);
  270. sliders[48 + 4]->setBounds(561, 73, 28, 28);
  271. // ...
  272. sliders[5]->setBounds(11, 149, 28, 28);
  273. sliders[6]->setBounds(61, 149, 28, 28);
  274. sliders[7]->setBounds(111, 149, 28, 28);
  275. sliders[8]->setBounds(161, 149, 28, 28);
  276. sliders[24 + 5]->setBounds(211, 149, 28, 28);
  277. sliders[24 + 6]->setBounds(261, 149, 28, 28);
  278. sliders[24 + 7]->setBounds(311, 149, 28, 28);
  279. sliders[24 + 8]->setBounds(361, 149, 28, 28);
  280. sliders[48 + 5]->setBounds(411, 149, 28, 28);
  281. sliders[48 + 6]->setBounds(461, 149, 28, 28);
  282. sliders[48 + 7]->setBounds(511, 149, 28, 28);
  283. sliders[48 + 8]->setBounds(561, 149, 28, 28);
  284. // ...
  285. sliders[9]->setBounds(11, 223, 28, 28);
  286. sliders[10]->setBounds(48, 223, 28, 28);
  287. sliders[11]->setBounds(86, 223, 28, 28);
  288. sliders[12]->setBounds(123, 223, 28, 28);
  289. sliders[13]->setBounds(161, 223, 28, 28);
  290. sliders[24 + 9]->setBounds(211, 223, 28, 28);
  291. sliders[24 + 10]->setBounds(248, 223, 28, 28);
  292. sliders[24 + 11]->setBounds(286, 223, 28, 28);
  293. sliders[24 + 12]->setBounds(323, 223, 28, 28);
  294. sliders[24 + 13]->setBounds(361, 223, 28, 28);
  295. sliders[48 + 9]->setBounds(411, 223, 28, 28);
  296. sliders[48 + 10]->setBounds(448, 223, 28, 28);
  297. sliders[48 + 11]->setBounds(486, 223, 28, 28);
  298. sliders[48 + 12]->setBounds(523, 223, 28, 28);
  299. sliders[48 + 13]->setBounds(561, 223, 28, 28);
  300. // ...
  301. sliders[14]->setBounds(11, 298, 28, 28);
  302. sliders[15]->setBounds(48, 298, 28, 28);
  303. sliders[16]->setBounds(86, 298, 28, 28);
  304. sliders[17]->setBounds(123, 298, 28, 28);
  305. sliders[18]->setBounds(161, 298, 28, 28);
  306. sliders[24 + 14]->setBounds(211, 298, 28, 28);
  307. sliders[24 + 15]->setBounds(248, 298, 28, 28);
  308. sliders[24 + 16]->setBounds(286, 298, 28, 28);
  309. sliders[24 + 17]->setBounds(323, 298, 28, 28);
  310. sliders[24 + 18]->setBounds(361, 298, 28, 28);
  311. sliders[48 + 14]->setBounds(411, 298, 28, 28);
  312. sliders[48 + 15]->setBounds(448, 298, 28, 28);
  313. sliders[48 + 16]->setBounds(486, 298, 28, 28);
  314. sliders[48 + 17]->setBounds(523, 298, 28, 28);
  315. sliders[48 + 18]->setBounds(561, 298, 28, 28);
  316. // ...
  317. sliders[19]->setBounds(11, 374, 28, 28);
  318. sliders[20]->setBounds(86, 374, 28, 28);
  319. sliders[21]->setBounds(161, 374, 28, 28);
  320. sliders[24 + 19]->setBounds(211, 374, 28, 28);
  321. sliders[24 + 20]->setBounds(286, 374, 28, 28);
  322. sliders[24 + 21]->setBounds(361, 374, 28, 28);
  323. sliders[48 + 19]->setBounds(411, 374, 28, 28);
  324. sliders[48 + 20]->setBounds(486, 374, 28, 28);
  325. sliders[48 + 21]->setBounds(561, 374, 28, 28);
  326. // ...
  327. sliders[22]->setBounds(11, 448, 28, 28);
  328. sliders[23]->setBounds(86, 448, 28, 28);
  329. sliders[24]->setBounds(161, 448, 28, 28);
  330. sliders[24 + 22]->setBounds(211, 448, 28, 28);
  331. sliders[24 + 23]->setBounds(286, 448, 28, 28);
  332. sliders[48]->setBounds(361, 448, 28, 28);
  333. sliders[48 + 22]->setBounds(411, 448, 28, 28);
  334. sliders[48 + 23]->setBounds(486, 448, 28, 28);
  335. sliders[48 + 24]->setBounds(561, 448, 28, 28);
  336. TB1->setBounds(174, 4, 13, 13);
  337. TB2->setBounds(374, 4, 13, 13);
  338. TB3->setBounds(574, 4, 13, 13);
  339. TB4->setBounds(154, 4, 13, 13);
  340. TB5->setBounds(354, 4, 13, 13);
  341. TB6->setBounds(554, 4, 13, 13);
  342. p1->setBounds(10, 20, 207, 280);
  343. p2->setBounds(210, 20, 207, 280);
  344. p3->setBounds(410, 20, 207, 280);
  345. }
  346. void timerCallback() override
  347. {
  348. if (fNeedsUpdate)
  349. {
  350. updateParametersFromFilter(true);
  351. fNeedsUpdate = false;
  352. }
  353. else
  354. {
  355. updateParametersFromFilter(false);
  356. }
  357. }
  358. void comboBoxChanged(ComboBox* comboBoxThatHasChanged) override
  359. {
  360. if (comboBoxThatHasChanged == comboBox1)
  361. fCallback->editorWaveChanged(1, comboBox1->getText());
  362. else if (comboBoxThatHasChanged == comboBox2)
  363. fCallback->editorWaveChanged(2, comboBox2->getText());
  364. else if (comboBoxThatHasChanged == comboBox3)
  365. fCallback->editorWaveChanged(3, comboBox3->getText());
  366. }
  367. void sliderValueChanged(Slider* sliderThatWasMoved) override
  368. {
  369. for (int i = 0; i < kSliderCount; ++i)
  370. {
  371. if (sliders[i] == sliderThatWasMoved)
  372. {
  373. fCallback->editorParameterChanged(i, (float)sliderThatWasMoved->getValue());
  374. return;
  375. }
  376. }
  377. }
  378. void buttonClicked(Button* buttonThatWasClicked) override
  379. {
  380. if (buttonThatWasClicked == TB1)
  381. fCallback->editorParameterChanged(89, TB1->getToggleState() ? 1.0f : 0.0f);
  382. else if (buttonThatWasClicked == TB2)
  383. fCallback->editorParameterChanged(90, TB2->getToggleState() ? 1.0f : 0.0f);
  384. else if (buttonThatWasClicked == TB3)
  385. fCallback->editorParameterChanged(91, TB3->getToggleState() ? 1.0f : 0.0f);
  386. else if (buttonThatWasClicked == TB4)
  387. p1->setVisible(!p1->isVisible());
  388. else if (buttonThatWasClicked == TB5)
  389. p2->setVisible(!p2->isVisible());
  390. else if (buttonThatWasClicked == TB6)
  391. p3->setVisible(!p3->isVisible());
  392. }
  393. void arpParameterChanged(const uint32_t) override
  394. {
  395. // unused, we don't need to register arp settings changes in synth
  396. }
  397. void updateParametersFromFilter(const bool all)
  398. {
  399. if (all)
  400. {
  401. for (int i = 0; i < kSliderCount; ++i)
  402. sliders[i]->setValue(fCallback->getFilterParameterValue(i), dontSendNotification);
  403. TB1->setToggleState(fCallback->getFilterParameterValue(89) > 0.5f ? true : false, dontSendNotification);
  404. TB2->setToggleState(fCallback->getFilterParameterValue(90) > 0.5f ? true : false, dontSendNotification);
  405. TB3->setToggleState(fCallback->getFilterParameterValue(91) > 0.5f ? true : false, dontSendNotification);
  406. comboBox1->setText(fCallback->getFilterWaveName(1), dontSendNotification);
  407. comboBox2->setText(fCallback->getFilterWaveName(2), dontSendNotification);
  408. comboBox3->setText(fCallback->getFilterWaveName(3), dontSendNotification);
  409. p1->update();
  410. p2->update();
  411. p3->update();
  412. }
  413. else
  414. {
  415. bool params[92];
  416. fCallback->getChangedParameters(params);
  417. for (int i=0; i < 89; ++i)
  418. {
  419. if (params[i])
  420. sliders[i]->setValue(fCallback->getFilterParameterValue(i), dontSendNotification);
  421. }
  422. if (params[89]) TB1->setToggleState(fCallback->getFilterParameterValue(89) > 0.5f ? true : false, dontSendNotification);
  423. if (params[90]) TB2->setToggleState(fCallback->getFilterParameterValue(90) > 0.5f ? true : false, dontSendNotification);
  424. if (params[91]) TB3->setToggleState(fCallback->getFilterParameterValue(91) > 0.5f ? true : false, dontSendNotification);
  425. }
  426. }
  427. private:
  428. static const int kSliderCount = 89;
  429. Callback* const fCallback;
  430. volatile bool fNeedsUpdate;
  431. Image internalCachedImage1;
  432. MyLookAndFeel mlaf;
  433. ScopedPointer<ComboBox> comboBox1;
  434. ScopedPointer<ComboBox> comboBox2;
  435. ScopedPointer<ComboBox> comboBox3;
  436. ScopedPointer<SnappingSlider> sliders[kSliderCount];
  437. ScopedPointer<TextButton> TB1;
  438. ScopedPointer<TextButton> TB2;
  439. ScopedPointer<TextButton> TB3;
  440. ScopedPointer<TextButton> TB4;
  441. ScopedPointer<TextButton> TB5;
  442. ScopedPointer<TextButton> TB6;
  443. ScopedPointer<PeggyViewComponent> p1;
  444. ScopedPointer<PeggyViewComponent> p2;
  445. ScopedPointer<PeggyViewComponent> p3;
  446. };
  447. // -----------------------------------------------------------------------
  448. class VexSynthPlugin : public NativePluginClass,
  449. public VexEditorComponent::Callback
  450. {
  451. public:
  452. static const unsigned int kParamCount = 92;
  453. VexSynthPlugin(const NativeHostDescriptor* const host)
  454. : NativePluginClass(host),
  455. fArp1(&fArpSet1),
  456. fArp2(&fArpSet2),
  457. fArp3(&fArpSet3),
  458. fChorus(fParameters),
  459. fDelay(fParameters),
  460. fReverb(fParameters),
  461. fSynth(fParameters)
  462. {
  463. std::memset(fParameters, 0, sizeof(float)*kParamCount);
  464. std::memset(fParamsChanged, 0, sizeof(bool)*92);
  465. fParameters[0] = 1.0f; // main volume
  466. for (int i = 0; i < 3; ++i)
  467. {
  468. const int offset = i * 24;
  469. fParameters[offset + 1] = 0.5f;
  470. fParameters[offset + 2] = 0.5f;
  471. fParameters[offset + 3] = 0.5f;
  472. fParameters[offset + 4] = 0.5f;
  473. fParameters[offset + 5] = 0.9f;
  474. fParameters[offset + 6] = 0.0f;
  475. fParameters[offset + 7] = 1.0f;
  476. fParameters[offset + 8] = 0.5f;
  477. fParameters[offset + 9] = 0.0f;
  478. fParameters[offset + 10] = 0.2f;
  479. fParameters[offset + 11] = 0.0f;
  480. fParameters[offset + 12] = 0.5f;
  481. fParameters[offset + 13] = 0.5f;
  482. fParameters[offset + 14] = 0.0f;
  483. fParameters[offset + 15] = 0.3f;
  484. fParameters[offset + 16] = 0.7f;
  485. fParameters[offset + 17] = 0.1f;
  486. fParameters[offset + 18] = 0.5f;
  487. fParameters[offset + 19] = 0.5f;
  488. fParameters[offset + 20] = 0.0f;
  489. fParameters[offset + 21] = 0.0f;
  490. fParameters[offset + 22] = 0.5f;
  491. fParameters[offset + 23] = 0.5f;
  492. fParameters[offset + 24] = 0.5f;
  493. }
  494. // ^1 - 72
  495. fParameters[73] = 0.5f; // Delay Time
  496. fParameters[74] = 0.4f; // Delay Feedback
  497. fParameters[75] = 0.0f; // Delay Volume
  498. fParameters[76] = 0.3f; // Chorus Rate
  499. fParameters[77] = 0.6f; // Chorus Depth
  500. fParameters[78] = 0.5f; // Chorus Volume
  501. fParameters[79] = 0.6f; // Reverb Size
  502. fParameters[80] = 0.7f; // Reverb Width
  503. fParameters[81] = 0.6f; // Reverb Damp
  504. fParameters[82] = 0.0f; // Reverb Volume
  505. fParameters[83] = 0.5f; // wave1 panning
  506. fParameters[84] = 0.5f; // wave2 panning
  507. fParameters[85] = 0.5f; // wave3 panning
  508. fParameters[86] = 0.5f; // wave1 volume
  509. fParameters[87] = 0.5f; // wave2 volume
  510. fParameters[88] = 0.5f; // wave3 volume
  511. fParameters[89] = 1.0f; // wave1 on/off
  512. fParameters[90] = 0.0f; // wave2 on/off
  513. fParameters[91] = 0.0f; // wave3 on/off
  514. bufferSizeChanged(getBufferSize());
  515. sampleRateChanged(getSampleRate());
  516. for (unsigned int i = 0; i < kParamCount; ++i)
  517. fSynth.update(i);
  518. fMidiInBuffer.ensureSize(512*4);
  519. }
  520. ~VexSynthPlugin() override
  521. {
  522. }
  523. protected:
  524. // -------------------------------------------------------------------
  525. // Plugin parameter calls
  526. uint32_t getParameterCount() const override
  527. {
  528. return kParamCount;
  529. }
  530. const NativeParameter* getParameterInfo(const uint32_t index) const override
  531. {
  532. static CarlaString tmpName;
  533. static NativeParameter paramInfo;
  534. int hints = PARAMETER_IS_ENABLED|PARAMETER_IS_AUTOMABLE;
  535. paramInfo.name = nullptr;
  536. paramInfo.unit = nullptr;
  537. paramInfo.ranges.def = 0.0f;
  538. paramInfo.ranges.min = 0.0f;
  539. paramInfo.ranges.max = 1.0f;
  540. paramInfo.ranges.step = PARAMETER_RANGES_DEFAULT_STEP;
  541. paramInfo.ranges.stepSmall = PARAMETER_RANGES_DEFAULT_STEP_SMALL;
  542. paramInfo.ranges.stepLarge = PARAMETER_RANGES_DEFAULT_STEP_LARGE;
  543. paramInfo.scalePointCount = 0;
  544. paramInfo.scalePoints = nullptr;
  545. if (index >= 1 && index <= 72)
  546. {
  547. uint32_t ri = index % 24;
  548. switch (ri)
  549. {
  550. case 1:
  551. tmpName = "Part0 Oct";
  552. paramInfo.ranges.def = 0.5f;
  553. break;
  554. case 2:
  555. tmpName = "Part0 Cent";
  556. paramInfo.ranges.def = 0.5f;
  557. break;
  558. case 3:
  559. tmpName = "Part0 Phase";
  560. paramInfo.ranges.def = 0.5f;
  561. break;
  562. case 4:
  563. tmpName = "Part0 Tune";
  564. paramInfo.ranges.def = 0.5f;
  565. break;
  566. case 5:
  567. tmpName = "Part0 Filter Cut";
  568. paramInfo.ranges.def = 0.9f;
  569. break;
  570. case 6:
  571. tmpName = "Part0 Filter Res";
  572. paramInfo.ranges.def = 0.0f;
  573. break;
  574. case 7:
  575. tmpName = "Part0 Filter HP/LP";
  576. paramInfo.ranges.def = 1.0f;
  577. break;
  578. case 8:
  579. tmpName = "Part0 Filter Env";
  580. paramInfo.ranges.def = 0.5f;
  581. break;
  582. case 9:
  583. tmpName = "Part0 Filter Env Atk";
  584. paramInfo.ranges.def = 0.0f;
  585. break;
  586. case 10:
  587. tmpName = "Part0 Filter Env Dec";
  588. paramInfo.ranges.def = 0.2f;
  589. break;
  590. case 11:
  591. tmpName = "Part0 Filter Env Sus";
  592. paramInfo.ranges.def = 0.0f;
  593. break;
  594. case 12:
  595. tmpName = "Part0 Filter Env Rel";
  596. paramInfo.ranges.def = 0.5f;
  597. break;
  598. case 13:
  599. tmpName = "Part0 Filter Env Vel";
  600. paramInfo.ranges.def = 0.5f;
  601. break;
  602. case 14:
  603. tmpName = "Part0 Amp Env Atk";
  604. paramInfo.ranges.def = 0.0f;
  605. break;
  606. case 15:
  607. tmpName = "Part0 Amp Env Dec";
  608. paramInfo.ranges.def = 0.3f;
  609. break;
  610. case 16:
  611. tmpName = "Part0 Amp Env Sus";
  612. paramInfo.ranges.def = 0.7f;
  613. break;
  614. case 17:
  615. tmpName = "Part0 Amp Env Rel";
  616. paramInfo.ranges.def = 0.1f;
  617. break;
  618. case 18:
  619. tmpName = "Part0 Amp Env Vel";
  620. paramInfo.ranges.def = 0.5f;
  621. break;
  622. case 19:
  623. tmpName = "Part0 LFO Rate";
  624. paramInfo.ranges.def = 0.5f;
  625. break;
  626. case 20:
  627. tmpName = "Part0 LFO Amp";
  628. paramInfo.ranges.def = 0.0f;
  629. break;
  630. case 21:
  631. tmpName = "Part0 LFO Flt";
  632. paramInfo.ranges.def = 0.0f;
  633. break;
  634. case 22:
  635. tmpName = "Part0 Delay";
  636. paramInfo.ranges.def = 0.5f;
  637. break;
  638. case 23:
  639. tmpName = "Part0 Chorus";
  640. paramInfo.ranges.def = 0.5f;
  641. break;
  642. case 24:
  643. case 0:
  644. tmpName = "Part0 Reverb";
  645. paramInfo.ranges.def = 0.5f;
  646. break;
  647. default:
  648. tmpName = "Part0 Unknown";
  649. break;
  650. }
  651. #ifdef CARLA_OS_LINUX
  652. // there seems to be a problem with this...
  653. tmpName[4] = '0' + ((index-1+24) / 24);
  654. #else
  655. char* tmpBuf(const_cast<char*>(tmpName.getBuffer()));
  656. tmpBuf[4] = '0' + ((index-1+24) / 24);
  657. #endif
  658. paramInfo.name = (const char*)tmpName;
  659. paramInfo.hints = static_cast<NativeParameterHints>(hints);
  660. return &paramInfo;
  661. }
  662. switch (index)
  663. {
  664. case 0:
  665. paramInfo.name = "Master";
  666. paramInfo.ranges.def = 1.0f;
  667. break;
  668. case 73:
  669. hints |= PARAMETER_IS_INTEGER;
  670. paramInfo.name = "Delay Time";
  671. paramInfo.unit = "steps";
  672. paramInfo.ranges.def = 4.0f;
  673. paramInfo.ranges.min = 0.0f;
  674. paramInfo.ranges.max = 8.0f;
  675. break;
  676. case 74:
  677. paramInfo.name = "Delay Feedback";
  678. paramInfo.unit = "%";
  679. paramInfo.ranges.def = 40.0f;
  680. paramInfo.ranges.min = 0.0f;
  681. paramInfo.ranges.max = 100.0f;
  682. break;
  683. case 75:
  684. paramInfo.name = "Delay Level";
  685. paramInfo.ranges.def = 0.0f;
  686. break;
  687. case 76:
  688. paramInfo.name = "Chorus Rate";
  689. paramInfo.ranges.def = 0.3f;
  690. break;
  691. case 77:
  692. paramInfo.name = "Chorus Depth";
  693. paramInfo.ranges.def = 0.6f;
  694. break;
  695. case 78:
  696. paramInfo.name = "Chorus Level";
  697. paramInfo.ranges.def = 0.5f;
  698. break;
  699. case 79:
  700. paramInfo.name = "Reverb Size";
  701. paramInfo.ranges.def = 0.6f;
  702. break;
  703. case 80:
  704. paramInfo.name = "Reverb Width";
  705. paramInfo.ranges.def = 0.7f;
  706. break;
  707. case 81:
  708. paramInfo.name = "Reverb Damp";
  709. paramInfo.ranges.def = 0.6f;
  710. break;
  711. case 82:
  712. paramInfo.name = "Reverb Level";
  713. paramInfo.ranges.def = 0.0f;
  714. break;
  715. case 83:
  716. paramInfo.name = "Part1 Panning";
  717. paramInfo.ranges.def = 0.5f;
  718. break;
  719. case 84:
  720. paramInfo.name = "Part2 Panning";
  721. paramInfo.ranges.def = 0.5f;
  722. break;
  723. case 85:
  724. paramInfo.name = "Part3 Panning";
  725. paramInfo.ranges.def = 0.5f;
  726. break;
  727. case 86:
  728. paramInfo.name = "Part1 Volume";
  729. paramInfo.ranges.def = 0.5f;
  730. break;
  731. case 87:
  732. paramInfo.name = "Part2 Volume";
  733. paramInfo.ranges.def = 0.5f;
  734. break;
  735. case 88:
  736. paramInfo.name = "Part3 Volume";
  737. paramInfo.ranges.def = 0.5f;
  738. break;
  739. case 89:
  740. hints |= PARAMETER_IS_BOOLEAN;
  741. paramInfo.name = "Part1 on/off";
  742. paramInfo.ranges.def = 1.0f;
  743. break;
  744. case 90:
  745. hints |= PARAMETER_IS_BOOLEAN;
  746. paramInfo.name = "Part2 on/off";
  747. paramInfo.ranges.def = 0.0f;
  748. break;
  749. case 91:
  750. hints |= PARAMETER_IS_BOOLEAN;
  751. paramInfo.name = "Part3 on/off";
  752. paramInfo.ranges.def = 0.0f;
  753. break;
  754. default:
  755. paramInfo.name = "unknown";
  756. break;
  757. }
  758. paramInfo.hints = static_cast<NativeParameterHints>(hints);
  759. return &paramInfo;
  760. }
  761. float getParameterValue(const uint32_t index) const override
  762. {
  763. if (index >= kParamCount)
  764. return 0.0f;
  765. switch (index)
  766. {
  767. case 73:
  768. return fParameters[index] * 8.0f;
  769. case 74:
  770. return fParameters[index] * 100.0f;
  771. default:
  772. return fParameters[index];
  773. }
  774. }
  775. // -------------------------------------------------------------------
  776. // Plugin state calls
  777. void setParameterValue(const uint32_t index, const float value) override
  778. {
  779. if (index >= kParamCount)
  780. return;
  781. float realValue;
  782. switch (index)
  783. {
  784. case 73:
  785. realValue = value/8.0f;
  786. break;
  787. case 74:
  788. realValue = value/100.0f;
  789. break;
  790. default:
  791. realValue = value;
  792. break;
  793. }
  794. fParameters[index] = realValue;
  795. fParamsChanged[index] = true;
  796. fSynth.update(index);
  797. }
  798. // -------------------------------------------------------------------
  799. // Plugin process calls
  800. void process(float**, float** outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  801. {
  802. // Get time info
  803. const NativeTimeInfo* const timeInfo(getTimeInfo());
  804. bool timePlaying = false;
  805. double ppqPos = 0.0;
  806. double barStartPos = 0.0;
  807. double bpm = 120.0;
  808. if (timeInfo != nullptr)
  809. {
  810. timePlaying = timeInfo->playing;
  811. if (timeInfo->bbt.valid)
  812. {
  813. double ppqBar = double(timeInfo->bbt.bar - 1) * timeInfo->bbt.beatsPerBar;
  814. double ppqBeat = double(timeInfo->bbt.beat - 1);
  815. double ppqTick = double(timeInfo->bbt.tick) / timeInfo->bbt.ticksPerBeat;
  816. ppqPos = ppqBar + ppqBeat + ppqTick;
  817. barStartPos = ppqBar;
  818. bpm = timeInfo->bbt.beatsPerMinute;
  819. }
  820. }
  821. // put carla events in juce midi buffer
  822. fMidiInBuffer.clear();
  823. for (uint32_t i=0; i < midiEventCount; ++i)
  824. {
  825. const NativeMidiEvent* const midiEvent(&midiEvents[i]);
  826. fMidiInBuffer.addEvent(MidiMessage(midiEvent->data, midiEvent->size), midiEvent->time);
  827. }
  828. // process MIDI (arppeggiator)
  829. const MidiBuffer& part1Midi(fArpSet1.on ? fArp1.processMidi(fMidiInBuffer, timePlaying, ppqPos, barStartPos, bpm, frames) : fMidiInBuffer);
  830. const MidiBuffer& part2Midi(fArpSet2.on ? fArp2.processMidi(fMidiInBuffer, timePlaying, ppqPos, barStartPos, bpm, frames) : fMidiInBuffer);
  831. const MidiBuffer& part3Midi(fArpSet3.on ? fArp3.processMidi(fMidiInBuffer, timePlaying, ppqPos, barStartPos, bpm, frames) : fMidiInBuffer);
  832. int snum;
  833. MidiMessage midiMessage(0xf4);
  834. MidiBuffer::Iterator Iterator1(part1Midi);
  835. while (Iterator1.getNextEvent(midiMessage, snum))
  836. {
  837. if (midiMessage.isNoteOn())
  838. fSynth.playNote(midiMessage.getNoteNumber(), midiMessage.getVelocity(), snum, 1);
  839. else if (midiMessage.isNoteOff())
  840. fSynth.releaseNote(midiMessage.getNoteNumber(), snum, 1 );
  841. else if (midiMessage.isAllSoundOff())
  842. fSynth.kill();
  843. else if (midiMessage.isAllNotesOff())
  844. fSynth.releaseAll(snum);
  845. }
  846. MidiBuffer::Iterator Iterator2(part2Midi);
  847. while (Iterator2.getNextEvent(midiMessage, snum))
  848. {
  849. if (midiMessage.isNoteOn())
  850. fSynth.playNote(midiMessage.getNoteNumber(), midiMessage.getVelocity(), snum, 2);
  851. else if (midiMessage.isNoteOff())
  852. fSynth.releaseNote(midiMessage.getNoteNumber(), snum, 2 );
  853. }
  854. MidiBuffer::Iterator Iterator3(part3Midi);
  855. while (Iterator3.getNextEvent(midiMessage, snum))
  856. {
  857. if (midiMessage.isNoteOn())
  858. fSynth.playNote(midiMessage.getNoteNumber(), midiMessage.getVelocity(), snum, 3);
  859. else if (midiMessage.isNoteOff())
  860. fSynth.releaseNote(midiMessage.getNoteNumber(), snum, 3 );
  861. }
  862. fMidiInBuffer.clear();
  863. if (obf->getNumSamples() < (int)frames)
  864. {
  865. obf->setSize(2, frames, 0, 0, 1);
  866. abf->setSize(2, frames, 0, 0, 1);
  867. dbf1->setSize(2, frames, 0, 0, 1);
  868. dbf2->setSize(2, frames, 0, 0, 1);
  869. dbf3->setSize(2, frames, 0, 0, 1);
  870. }
  871. obf ->clear();
  872. dbf1->clear();
  873. dbf2->clear();
  874. dbf3->clear();
  875. fSynth.doProcess(*obf, *abf, *dbf1, *dbf2, *dbf3);
  876. if (fParameters[75] > 0.001f) fDelay.processBlock(dbf1, bpm);
  877. if (fParameters[78] > 0.001f) fChorus.processBlock(dbf2);
  878. if (fParameters[82] > 0.001f) fReverb.processBlock(dbf3);
  879. AudioSampleBuffer output(outBuffer, 2, 0, frames);
  880. output.clear();
  881. obf->addFrom(0, 0, *dbf1, 0, 0, frames, fParameters[75]);
  882. obf->addFrom(1, 0, *dbf1, 1, 0, frames, fParameters[75]);
  883. obf->addFrom(0, 0, *dbf2, 0, 0, frames, fParameters[78]);
  884. obf->addFrom(1, 0, *dbf2, 1, 0, frames, fParameters[78]);
  885. obf->addFrom(0, 0, *dbf3, 0, 0, frames, fParameters[82]);
  886. obf->addFrom(1, 0, *dbf3, 1, 0, frames, fParameters[82]);
  887. output.addFrom(0, 0, *obf, 0, 0, frames, fParameters[0]);
  888. output.addFrom(1, 0, *obf, 1, 0, frames, fParameters[0]);
  889. }
  890. // -------------------------------------------------------------------
  891. // Plugin UI calls
  892. void uiShow(const bool show) override
  893. {
  894. MessageManagerLock mmLock;
  895. if (show)
  896. {
  897. if (fWindow == nullptr)
  898. {
  899. fWindow = new JucePluginWindow();
  900. fWindow->setName(getUiName());
  901. }
  902. if (fView == nullptr)
  903. fView = new VexEditorComponent(this, fArpSet1, fArpSet2, fArpSet3);
  904. fWindow->show(fView);
  905. }
  906. else if (fWindow != nullptr)
  907. {
  908. fWindow->hide();
  909. fView = nullptr;
  910. fWindow = nullptr;
  911. }
  912. }
  913. void uiIdle() override
  914. {
  915. if (fWindow == nullptr)
  916. return;
  917. if (fWindow->wasClosedByUser())
  918. {
  919. uiShow(false);
  920. uiClosed();
  921. }
  922. }
  923. // -------------------------------------------------------------------
  924. // Plugin state calls
  925. char* getState() const override
  926. {
  927. MemoryBlock destData;
  928. //destData.append(fParameters, sizeof(float) * kParamCount);
  929. destData.append(&fArpSet1, sizeof(VexArpSettings));
  930. destData.append(&fArpSet2, sizeof(VexArpSettings));
  931. destData.append(&fArpSet3, sizeof(VexArpSettings));
  932. XmlElement xmlState("VEX");
  933. xmlState.setAttribute("Wave1", fSynth.getWaveName(1));
  934. xmlState.setAttribute("Wave2", fSynth.getWaveName(2));
  935. xmlState.setAttribute("Wave3", fSynth.getWaveName(3));
  936. MemoryBlock tmp;
  937. copyXmlToBinary(xmlState, tmp);
  938. destData.append(tmp.getData(), tmp.getSize());
  939. return strdup(destData.toBase64Encoding().toRawUTF8());
  940. }
  941. void setState(const char* const data64) override
  942. {
  943. static const int kParamDataSize = 0; //sizeof(float)*kParamCount
  944. static const int xmlOffset = kParamDataSize + sizeof(VexArpSettings) * 3;
  945. MemoryBlock destData;
  946. destData.fromBase64Encoding(data64);
  947. const char* const data(&destData[0]);
  948. const size_t dataSize(destData.getSize());
  949. if (XmlElement* const xmlState = getXmlFromBinary(data + xmlOffset, dataSize - xmlOffset))
  950. {
  951. if (xmlState->hasTagName("VEX"))
  952. {
  953. fSynth.setWaveLater(1, xmlState->getStringAttribute("Wave1"));
  954. fSynth.setWaveLater(2, xmlState->getStringAttribute("Wave2"));
  955. fSynth.setWaveLater(3, xmlState->getStringAttribute("Wave3"));
  956. //std::memcpy(fParameters, data, sizeof(float) * kParamCount);
  957. std::memcpy(&fArpSet1, data + (kParamDataSize + sizeof(VexArpSettings)*0), sizeof(VexArpSettings));
  958. std::memcpy(&fArpSet2, data + (kParamDataSize + sizeof(VexArpSettings)*1), sizeof(VexArpSettings));
  959. std::memcpy(&fArpSet3, data + (kParamDataSize + sizeof(VexArpSettings)*2), sizeof(VexArpSettings));
  960. //for (unsigned int i = 0; i < kParamCount; ++i)
  961. // fSynth.update(i);
  962. if (fView != nullptr)
  963. fView->setNeedsUpdate();
  964. }
  965. delete xmlState;
  966. }
  967. }
  968. // -------------------------------------------------------------------
  969. // Plugin dispatcher calls
  970. void bufferSizeChanged(const uint32_t bufferSize) override
  971. {
  972. obf = new AudioSampleBuffer(2, bufferSize);
  973. abf = new AudioSampleBuffer(2, bufferSize);
  974. dbf1 = new AudioSampleBuffer(2, bufferSize);
  975. dbf2 = new AudioSampleBuffer(2, bufferSize);
  976. dbf3 = new AudioSampleBuffer(2, bufferSize);
  977. }
  978. void sampleRateChanged(const double sampleRate) override
  979. {
  980. fArp1.setSampleRate(sampleRate);
  981. fArp2.setSampleRate(sampleRate);
  982. fArp3.setSampleRate(sampleRate);
  983. fChorus.setSampleRate(sampleRate);
  984. fDelay.setSampleRate(sampleRate);
  985. fSynth.setSampleRate(sampleRate);
  986. }
  987. void uiNameChanged(const char* const uiName) override
  988. {
  989. if (fWindow == nullptr)
  990. return;
  991. MessageManagerLock mmLock;
  992. fWindow->setName(uiName);
  993. }
  994. // -------------------------------------------------------------------
  995. // Vex editor calls
  996. void getChangedParameters(bool params[92]) override
  997. {
  998. std::memcpy(params, fParamsChanged, sizeof(bool)*92);
  999. std::memset(fParamsChanged, 0, sizeof(bool)*92);
  1000. }
  1001. float getFilterParameterValue(const uint32_t index) const override
  1002. {
  1003. CARLA_SAFE_ASSERT_RETURN(index < kParamCount, 0.0f)
  1004. return fParameters[index];
  1005. }
  1006. String getFilterWaveName(const int part) const override
  1007. {
  1008. CARLA_SAFE_ASSERT_RETURN(part >= 1 && part <= 3, "")
  1009. return fSynth.getWaveName(part);
  1010. }
  1011. void editorParameterChanged(const uint32_t index, const float value) override
  1012. {
  1013. CARLA_SAFE_ASSERT_RETURN(index < kParamCount,)
  1014. if (fParameters[index] == value)
  1015. return;
  1016. fParameters[index] = value;
  1017. fSynth.update(index);
  1018. uiParameterChanged(index, getParameterValue(index)); // some params have specific bounds
  1019. }
  1020. void editorWaveChanged(const int part, const String& wave) override
  1021. {
  1022. CARLA_SAFE_ASSERT_RETURN(part >= 1 && part <= 3,)
  1023. fSynth.setWaveLater(part, wave);
  1024. }
  1025. private:
  1026. float fParameters[kParamCount];
  1027. bool fParamsChanged[92];
  1028. ScopedPointer<AudioSampleBuffer> obf;
  1029. ScopedPointer<AudioSampleBuffer> abf;
  1030. ScopedPointer<AudioSampleBuffer> dbf1; // delay
  1031. ScopedPointer<AudioSampleBuffer> dbf2; // chorus
  1032. ScopedPointer<AudioSampleBuffer> dbf3; // reverb
  1033. VexArpSettings fArpSet1, fArpSet2, fArpSet3;
  1034. VexArp fArp1, fArp2, fArp3;
  1035. VexChorus fChorus;
  1036. VexDelay fDelay;
  1037. VexReverb fReverb;
  1038. VexSyntModule fSynth;
  1039. ScopedPointer<VexEditorComponent> fView;
  1040. ScopedPointer<JucePluginWindow> fWindow;
  1041. MidiBuffer fMidiInBuffer;
  1042. PluginClassEND(VexSynthPlugin)
  1043. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VexSynthPlugin)
  1044. };
  1045. // -----------------------------------------------------------------------
  1046. static const NativePluginDescriptor vexSynthDesc = {
  1047. /* category */ PLUGIN_CATEGORY_SYNTH,
  1048. /* hints */ static_cast<NativePluginHints>(PLUGIN_IS_SYNTH|PLUGIN_HAS_UI|PLUGIN_NEEDS_UI_JUCE|PLUGIN_USES_STATE|PLUGIN_USES_TIME),
  1049. /* supports */ static_cast<NativePluginSupports>(0x0),
  1050. /* audioIns */ 0,
  1051. /* audioOuts */ 2,
  1052. /* midiIns */ 1,
  1053. /* midiOuts */ 0,
  1054. /* paramIns */ VexSynthPlugin::kParamCount,
  1055. /* paramOuts */ 0,
  1056. /* name */ "VexSynth",
  1057. /* label */ "vexSynth",
  1058. /* maker */ "falkTX",
  1059. /* copyright */ "GNU GPL v2+",
  1060. PluginDescriptorFILL(VexSynthPlugin)
  1061. };
  1062. // -----------------------------------------------------------------------
  1063. CARLA_EXPORT
  1064. void carla_register_native_plugin_vex_synth()
  1065. {
  1066. carla_register_native_plugin(&vexSynthDesc);
  1067. }
  1068. // -----------------------------------------------------------------------