The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

1893 lines
84KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE examples.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. The code included in this file is provided under the terms of the ISC license
  6. http://www.isc.org/downloads/software-support-policy/isc-license. Permission
  7. To use, copy, modify, and/or distribute this software for any purpose with or
  8. without fee is hereby granted provided that the above copyright notice and
  9. this permission notice appear in all copies.
  10. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES,
  11. WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR
  12. PURPOSE, ARE DISCLAIMED.
  13. ==============================================================================
  14. */
  15. /*******************************************************************************
  16. The block below describes the properties of this PIP. A PIP is a short snippet
  17. of code that can be read by the Projucer and used to generate a JUCE project.
  18. BEGIN_JUCE_PIP_METADATA
  19. name: DSPModulePluginDemo
  20. version: 1.0.0
  21. vendor: JUCE
  22. website: http://juce.com
  23. description: An audio plugin using the DSP module.
  24. dependencies: juce_audio_basics, juce_audio_devices, juce_audio_formats,
  25. juce_audio_plugin_client, juce_audio_processors,
  26. juce_audio_utils, juce_core, juce_data_structures, juce_dsp,
  27. juce_events, juce_graphics, juce_gui_basics, juce_gui_extra
  28. exporters: xcode_mac, vs2019, linux_make
  29. moduleFlags: JUCE_STRICT_REFCOUNTEDPOINTER=1
  30. type: AudioProcessor
  31. mainClass: DspModulePluginDemoAudioProcessor
  32. useLocalCopy: 1
  33. END_JUCE_PIP_METADATA
  34. *******************************************************************************/
  35. #pragma once
  36. #include "../Assets/DemoUtilities.h"
  37. namespace ID
  38. {
  39. #define PARAMETER_ID(str) constexpr const char* str { #str };
  40. PARAMETER_ID (inputGain)
  41. PARAMETER_ID (outputGain)
  42. PARAMETER_ID (pan)
  43. PARAMETER_ID (distortionEnabled)
  44. PARAMETER_ID (distortionType)
  45. PARAMETER_ID (distortionOversampler)
  46. PARAMETER_ID (distortionLowpass)
  47. PARAMETER_ID (distortionHighpass)
  48. PARAMETER_ID (distortionInGain)
  49. PARAMETER_ID (distortionCompGain)
  50. PARAMETER_ID (distortionMix)
  51. PARAMETER_ID (multiBandEnabled)
  52. PARAMETER_ID (multiBandFreq)
  53. PARAMETER_ID (multiBandLowVolume)
  54. PARAMETER_ID (multiBandHighVolume)
  55. PARAMETER_ID (compressorEnabled)
  56. PARAMETER_ID (compressorThreshold)
  57. PARAMETER_ID (compressorRatio)
  58. PARAMETER_ID (compressorAttack)
  59. PARAMETER_ID (compressorRelease)
  60. PARAMETER_ID (noiseGateEnabled)
  61. PARAMETER_ID (noiseGateThreshold)
  62. PARAMETER_ID (noiseGateRatio)
  63. PARAMETER_ID (noiseGateAttack)
  64. PARAMETER_ID (noiseGateRelease)
  65. PARAMETER_ID (limiterEnabled)
  66. PARAMETER_ID (limiterThreshold)
  67. PARAMETER_ID (limiterRelease)
  68. PARAMETER_ID (directDelayEnabled)
  69. PARAMETER_ID (directDelayType)
  70. PARAMETER_ID (directDelayValue)
  71. PARAMETER_ID (directDelaySmoothing)
  72. PARAMETER_ID (directDelayMix)
  73. PARAMETER_ID (delayEffectEnabled)
  74. PARAMETER_ID (delayEffectType)
  75. PARAMETER_ID (delayEffectValue)
  76. PARAMETER_ID (delayEffectSmoothing)
  77. PARAMETER_ID (delayEffectLowpass)
  78. PARAMETER_ID (delayEffectFeedback)
  79. PARAMETER_ID (delayEffectMix)
  80. PARAMETER_ID (phaserEnabled)
  81. PARAMETER_ID (phaserRate)
  82. PARAMETER_ID (phaserDepth)
  83. PARAMETER_ID (phaserCentreFrequency)
  84. PARAMETER_ID (phaserFeedback)
  85. PARAMETER_ID (phaserMix)
  86. PARAMETER_ID (chorusEnabled)
  87. PARAMETER_ID (chorusRate)
  88. PARAMETER_ID (chorusDepth)
  89. PARAMETER_ID (chorusCentreDelay)
  90. PARAMETER_ID (chorusFeedback)
  91. PARAMETER_ID (chorusMix)
  92. PARAMETER_ID (ladderEnabled)
  93. PARAMETER_ID (ladderCutoff)
  94. PARAMETER_ID (ladderResonance)
  95. PARAMETER_ID (ladderDrive)
  96. PARAMETER_ID (ladderMode)
  97. #undef PARAMETER_ID
  98. }
  99. template <typename Func, typename... Items>
  100. constexpr void forEach (Func&& func, Items&&... items)
  101. noexcept (noexcept (std::initializer_list<int> { (func (std::forward<Items> (items)), 0)... }))
  102. {
  103. (void) std::initializer_list<int> { ((void) func (std::forward<Items> (items)), 0)... };
  104. }
  105. template <typename... Components>
  106. void addAllAndMakeVisible (Component& target, Components&... children)
  107. {
  108. forEach ([&] (Component& child) { target.addAndMakeVisible (child); }, children...);
  109. }
  110. template <typename... Processors>
  111. void prepareAll (const dsp::ProcessSpec& spec, Processors&... processors)
  112. {
  113. forEach ([&] (auto& proc) { proc.prepare (spec); }, processors...);
  114. }
  115. template <typename... Processors>
  116. void resetAll (Processors&... processors)
  117. {
  118. forEach ([] (auto& proc) { proc.reset(); }, processors...);
  119. }
  120. //==============================================================================
  121. class DspModulePluginDemo : public AudioProcessor,
  122. private ValueTree::Listener
  123. {
  124. public:
  125. DspModulePluginDemo()
  126. {
  127. apvts.state.addListener (this);
  128. forEach ([] (dsp::Gain<float>& gain) { gain.setRampDurationSeconds (0.05); },
  129. dsp::get<inputGainIndex> (chain),
  130. dsp::get<outputGainIndex> (chain));
  131. dsp::get<pannerIndex> (chain).setRule (dsp::PannerRule::linear);
  132. }
  133. //==============================================================================
  134. void prepareToPlay (double sampleRate, int samplesPerBlock) override
  135. {
  136. if (jmin (getTotalNumInputChannels(), getTotalNumOutputChannels()) == 0)
  137. return;
  138. chain.prepare ({ sampleRate, (uint32) samplesPerBlock, (uint32) getTotalNumOutputChannels() });
  139. reset();
  140. }
  141. void reset() override
  142. {
  143. chain.reset();
  144. update();
  145. }
  146. void releaseResources() override {}
  147. void processBlock (AudioBuffer<float>& buffer, MidiBuffer&) override
  148. {
  149. if (jmin (getTotalNumInputChannels(), getTotalNumOutputChannels()) == 0)
  150. return;
  151. ScopedNoDenormals noDenormals;
  152. if (requiresUpdate.load())
  153. update();
  154. const auto totalNumInputChannels = getTotalNumInputChannels();
  155. const auto totalNumOutputChannels = getTotalNumOutputChannels();
  156. const auto numChannels = jmax (totalNumInputChannels, totalNumOutputChannels);
  157. auto inoutBlock = dsp::AudioBlock<float> (buffer).getSubsetChannelBlock (0, (size_t) numChannels);
  158. chain.process (dsp::ProcessContextReplacing<float> (inoutBlock));
  159. }
  160. void processBlock (AudioBuffer<double>&, MidiBuffer&) override {}
  161. //==============================================================================
  162. AudioProcessorEditor* createEditor() override { return nullptr; }
  163. bool hasEditor() const override { return false; }
  164. //==============================================================================
  165. const String getName() const override { return "DSPModulePluginDemo"; }
  166. bool acceptsMidi() const override { return false; }
  167. bool producesMidi() const override { return false; }
  168. bool isMidiEffect() const override { return false; }
  169. double getTailLengthSeconds() const override { return 0.0; }
  170. //==============================================================================
  171. int getNumPrograms() override { return 1; }
  172. int getCurrentProgram() override { return 0; }
  173. void setCurrentProgram (int) override {}
  174. const String getProgramName (int) override { return {}; }
  175. void changeProgramName (int, const String&) override {}
  176. //==============================================================================
  177. void getStateInformation (MemoryBlock& destData) override
  178. {
  179. copyXmlToBinary (*apvts.copyState().createXml(), destData);
  180. }
  181. void setStateInformation (const void* data, int sizeInBytes) override
  182. {
  183. apvts.replaceState (ValueTree::fromXml (*getXmlFromBinary (data, sizeInBytes)));
  184. }
  185. //==============================================================================
  186. AudioProcessorValueTreeState apvts { *this, nullptr, "state", createParameters() };
  187. // We store this here so that the editor retains its state if it is closed and reopened
  188. int indexTab = 0;
  189. private:
  190. //==============================================================================
  191. void valueTreePropertyChanged (ValueTree&, const Identifier&) override
  192. {
  193. requiresUpdate.store (true);
  194. }
  195. // This struct holds references to the raw parameter values, so that we don't have to look up
  196. // the parameters (involving string comparisons and map lookups!) every time a parameter
  197. // changes.
  198. struct ParameterValues
  199. {
  200. explicit ParameterValues (AudioProcessorValueTreeState& state)
  201. : inputGain (*state.getRawParameterValue (ID::inputGain)),
  202. outputGain (*state.getRawParameterValue (ID::outputGain)),
  203. pan (*state.getRawParameterValue (ID::pan)),
  204. distortionEnabled (*state.getRawParameterValue (ID::distortionEnabled)),
  205. distortionType (*state.getRawParameterValue (ID::distortionType)),
  206. distortionOversampler (*state.getRawParameterValue (ID::distortionOversampler)),
  207. distortionLowpass (*state.getRawParameterValue (ID::distortionLowpass)),
  208. distortionHighpass (*state.getRawParameterValue (ID::distortionHighpass)),
  209. distortionInGain (*state.getRawParameterValue (ID::distortionInGain)),
  210. distortionCompGain (*state.getRawParameterValue (ID::distortionCompGain)),
  211. distortionMix (*state.getRawParameterValue (ID::distortionMix)),
  212. multiBandEnabled (*state.getRawParameterValue (ID::multiBandEnabled)),
  213. multiBandFreq (*state.getRawParameterValue (ID::multiBandFreq)),
  214. multiBandLowVolume (*state.getRawParameterValue (ID::multiBandLowVolume)),
  215. multiBandHighVolume (*state.getRawParameterValue (ID::multiBandHighVolume)),
  216. compressorEnabled (*state.getRawParameterValue (ID::compressorEnabled)),
  217. compressorThreshold (*state.getRawParameterValue (ID::compressorThreshold)),
  218. compressorRatio (*state.getRawParameterValue (ID::compressorRatio)),
  219. compressorAttack (*state.getRawParameterValue (ID::compressorAttack)),
  220. compressorRelease (*state.getRawParameterValue (ID::compressorRelease)),
  221. noiseGateEnabled (*state.getRawParameterValue (ID::noiseGateEnabled)),
  222. noiseGateThreshold (*state.getRawParameterValue (ID::noiseGateThreshold)),
  223. noiseGateRatio (*state.getRawParameterValue (ID::noiseGateRatio)),
  224. noiseGateAttack (*state.getRawParameterValue (ID::noiseGateAttack)),
  225. noiseGateRelease (*state.getRawParameterValue (ID::noiseGateRelease)),
  226. limiterEnabled (*state.getRawParameterValue (ID::limiterEnabled)),
  227. limiterThreshold (*state.getRawParameterValue (ID::limiterThreshold)),
  228. limiterRelease (*state.getRawParameterValue (ID::limiterRelease)),
  229. directDelayEnabled (*state.getRawParameterValue (ID::directDelayEnabled)),
  230. directDelayType (*state.getRawParameterValue (ID::directDelayType)),
  231. directDelayValue (*state.getRawParameterValue (ID::directDelayValue)),
  232. directDelaySmoothing (*state.getRawParameterValue (ID::directDelaySmoothing)),
  233. directDelayMix (*state.getRawParameterValue (ID::directDelayMix)),
  234. delayEffectEnabled (*state.getRawParameterValue (ID::delayEffectEnabled)),
  235. delayEffectType (*state.getRawParameterValue (ID::delayEffectType)),
  236. delayEffectValue (*state.getRawParameterValue (ID::delayEffectValue)),
  237. delayEffectSmoothing (*state.getRawParameterValue (ID::delayEffectSmoothing)),
  238. delayEffectLowpass (*state.getRawParameterValue (ID::delayEffectLowpass)),
  239. delayEffectFeedback (*state.getRawParameterValue (ID::delayEffectFeedback)),
  240. delayEffectMix (*state.getRawParameterValue (ID::delayEffectMix)),
  241. phaserEnabled (*state.getRawParameterValue (ID::phaserEnabled)),
  242. phaserRate (*state.getRawParameterValue (ID::phaserRate)),
  243. phaserDepth (*state.getRawParameterValue (ID::phaserDepth)),
  244. phaserCentreFrequency (*state.getRawParameterValue (ID::phaserCentreFrequency)),
  245. phaserFeedback (*state.getRawParameterValue (ID::phaserFeedback)),
  246. phaserMix (*state.getRawParameterValue (ID::phaserMix)),
  247. chorusEnabled (*state.getRawParameterValue (ID::chorusEnabled)),
  248. chorusRate (*state.getRawParameterValue (ID::chorusRate)),
  249. chorusDepth (*state.getRawParameterValue (ID::chorusDepth)),
  250. chorusCentreDelay (*state.getRawParameterValue (ID::chorusCentreDelay)),
  251. chorusFeedback (*state.getRawParameterValue (ID::chorusFeedback)),
  252. chorusMix (*state.getRawParameterValue (ID::chorusMix)),
  253. ladderEnabled (*state.getRawParameterValue (ID::ladderEnabled)),
  254. ladderCutoff (*state.getRawParameterValue (ID::ladderCutoff)),
  255. ladderResonance (*state.getRawParameterValue (ID::ladderResonance)),
  256. ladderDrive (*state.getRawParameterValue (ID::ladderDrive)),
  257. ladderMode (*state.getRawParameterValue (ID::ladderMode))
  258. {}
  259. std::atomic<float>& inputGain;
  260. std::atomic<float>& outputGain;
  261. std::atomic<float>& pan;
  262. std::atomic<float>& distortionEnabled;
  263. std::atomic<float>& distortionType;
  264. std::atomic<float>& distortionOversampler;
  265. std::atomic<float>& distortionLowpass;
  266. std::atomic<float>& distortionHighpass;
  267. std::atomic<float>& distortionInGain;
  268. std::atomic<float>& distortionCompGain;
  269. std::atomic<float>& distortionMix;
  270. std::atomic<float>& multiBandEnabled;
  271. std::atomic<float>& multiBandFreq;
  272. std::atomic<float>& multiBandLowVolume;
  273. std::atomic<float>& multiBandHighVolume;
  274. std::atomic<float>& compressorEnabled;
  275. std::atomic<float>& compressorThreshold;
  276. std::atomic<float>& compressorRatio;
  277. std::atomic<float>& compressorAttack;
  278. std::atomic<float>& compressorRelease;
  279. std::atomic<float>& noiseGateEnabled;
  280. std::atomic<float>& noiseGateThreshold;
  281. std::atomic<float>& noiseGateRatio;
  282. std::atomic<float>& noiseGateAttack;
  283. std::atomic<float>& noiseGateRelease;
  284. std::atomic<float>& limiterEnabled;
  285. std::atomic<float>& limiterThreshold;
  286. std::atomic<float>& limiterRelease;
  287. std::atomic<float>& directDelayEnabled;
  288. std::atomic<float>& directDelayType;
  289. std::atomic<float>& directDelayValue;
  290. std::atomic<float>& directDelaySmoothing;
  291. std::atomic<float>& directDelayMix;
  292. std::atomic<float>& delayEffectEnabled;
  293. std::atomic<float>& delayEffectType;
  294. std::atomic<float>& delayEffectValue;
  295. std::atomic<float>& delayEffectSmoothing;
  296. std::atomic<float>& delayEffectLowpass;
  297. std::atomic<float>& delayEffectFeedback;
  298. std::atomic<float>& delayEffectMix;
  299. std::atomic<float>& phaserEnabled;
  300. std::atomic<float>& phaserRate;
  301. std::atomic<float>& phaserDepth;
  302. std::atomic<float>& phaserCentreFrequency;
  303. std::atomic<float>& phaserFeedback;
  304. std::atomic<float>& phaserMix;
  305. std::atomic<float>& chorusEnabled;
  306. std::atomic<float>& chorusRate;
  307. std::atomic<float>& chorusDepth;
  308. std::atomic<float>& chorusCentreDelay;
  309. std::atomic<float>& chorusFeedback;
  310. std::atomic<float>& chorusMix;
  311. std::atomic<float>& ladderEnabled;
  312. std::atomic<float>& ladderCutoff;
  313. std::atomic<float>& ladderResonance;
  314. std::atomic<float>& ladderDrive;
  315. std::atomic<float>& ladderMode;
  316. };
  317. ParameterValues parameters { apvts };
  318. //==============================================================================
  319. void update()
  320. {
  321. {
  322. DistortionProcessor& distortion = dsp::get<distortionIndex> (chain);
  323. if (distortion.currentIndexOversampling != parameters.distortionOversampler.load())
  324. {
  325. distortion.currentIndexOversampling = roundToInt (parameters.distortionOversampler.load());
  326. prepareToPlay (getSampleRate(), getBlockSize());
  327. return;
  328. }
  329. distortion.currentIndexWaveshaper = roundToInt (parameters.distortionType.load());
  330. distortion.lowpass .setCutoffFrequency (parameters.distortionLowpass);
  331. distortion.highpass.setCutoffFrequency (parameters.distortionHighpass);
  332. distortion.distGain.setGainDecibels (parameters.distortionInGain);
  333. distortion.compGain.setGainDecibels (parameters.distortionCompGain);
  334. distortion.mixer.setWetMixProportion (parameters.distortionMix / 100.0f);
  335. dsp::setBypassed<distortionIndex> (chain, parameters.distortionEnabled.load() == 0.0f);
  336. }
  337. dsp::get<inputGainIndex> (chain).setGainDecibels (parameters.inputGain);
  338. dsp::get<outputGainIndex> (chain).setGainDecibels (parameters.outputGain);
  339. dsp::get<pannerIndex> (chain).setPan (parameters.pan / 100.0f);
  340. {
  341. MultiBandProcessor& multiband = dsp::get<multiBandIndex> (chain);
  342. const auto multibandFreq = parameters.multiBandFreq.load();
  343. multiband.lowpass .setCutoffFrequency (multibandFreq);
  344. multiband.highpass.setCutoffFrequency (multibandFreq);
  345. const auto enabled = parameters.multiBandEnabled.load() != 0.0f;
  346. multiband.lowVolume .setGainDecibels (enabled ? parameters.multiBandLowVolume .load() : 0.0f);
  347. multiband.highVolume.setGainDecibels (enabled ? parameters.multiBandHighVolume.load() : 0.0f);
  348. dsp::setBypassed<multiBandIndex> (chain, ! enabled);
  349. }
  350. {
  351. dsp::Compressor<float>& compressor = dsp::get<compressorIndex> (chain);
  352. compressor.setThreshold (parameters.compressorThreshold);
  353. compressor.setRatio (parameters.compressorRatio);
  354. compressor.setAttack (parameters.compressorAttack);
  355. compressor.setRelease (parameters.compressorRelease);
  356. dsp::setBypassed<compressorIndex> (chain, parameters.compressorEnabled.load() == 0.0f);
  357. }
  358. {
  359. dsp::NoiseGate<float>& noiseGate = dsp::get<noiseGateIndex> (chain);
  360. noiseGate.setThreshold (parameters.noiseGateThreshold);
  361. noiseGate.setRatio (parameters.noiseGateRatio);
  362. noiseGate.setAttack (parameters.noiseGateAttack);
  363. noiseGate.setRelease (parameters.noiseGateRelease);
  364. dsp::setBypassed<noiseGateIndex> (chain, parameters.noiseGateEnabled.load() == 0.0f);
  365. }
  366. {
  367. dsp::Limiter<float>& limiter = dsp::get<limiterIndex> (chain);
  368. limiter.setThreshold (parameters.limiterThreshold);
  369. limiter.setRelease (parameters.limiterRelease);
  370. dsp::setBypassed<limiterIndex> (chain, parameters.limiterEnabled.load() == 0.0f);
  371. }
  372. {
  373. DirectDelayProcessor& delay = dsp::get<directDelayIndex> (chain);
  374. delay.delayLineDirectType = roundToInt (parameters.directDelayType.load());
  375. std::fill (delay.delayDirectValue.begin(),
  376. delay.delayDirectValue.end(),
  377. (double) parameters.directDelayValue);
  378. delay.smoothFilter.setCutoffFrequency (1000.0 / parameters.directDelaySmoothing);
  379. delay.mixer.setWetMixProportion (parameters.directDelayMix / 100.0f);
  380. dsp::setBypassed<directDelayIndex> (chain, parameters.directDelayEnabled.load() == 0.0f);
  381. }
  382. {
  383. DelayEffectProcessor& delay = dsp::get<delayEffectIndex> (chain);
  384. delay.delayEffectType = roundToInt (parameters.delayEffectType.load());
  385. std::fill (delay.delayEffectValue.begin(),
  386. delay.delayEffectValue.end(),
  387. (double) parameters.delayEffectValue / 1000.0 * getSampleRate());
  388. const auto feedbackGain = Decibels::decibelsToGain (parameters.delayEffectFeedback.load(), -100.0f);
  389. for (auto& volume : delay.delayFeedbackVolume)
  390. volume.setTargetValue (feedbackGain);
  391. delay.smoothFilter.setCutoffFrequency (1000.0 / parameters.delayEffectSmoothing);
  392. delay.lowpass.setCutoffFrequency (parameters.delayEffectLowpass);
  393. delay.mixer.setWetMixProportion (parameters.delayEffectMix / 100.0f);
  394. dsp::setBypassed<delayEffectIndex> (chain, parameters.delayEffectEnabled.load() == 0.0f);
  395. }
  396. {
  397. dsp::Phaser<float>& phaser = dsp::get<phaserIndex> (chain);
  398. phaser.setRate (parameters.phaserRate);
  399. phaser.setDepth (parameters.phaserDepth / 100.0f);
  400. phaser.setCentreFrequency (parameters.phaserCentreFrequency);
  401. phaser.setFeedback (parameters.phaserFeedback / 100.0f * 0.95f);
  402. phaser.setMix (parameters.phaserMix / 100.0f);
  403. dsp::setBypassed<phaserIndex> (chain, parameters.phaserEnabled.load() == 0.0f);
  404. }
  405. {
  406. dsp::Chorus<float>& chorus = dsp::get<chorusIndex> (chain);
  407. chorus.setRate (parameters.chorusRate);
  408. chorus.setDepth (parameters.chorusDepth / 100.0f);
  409. chorus.setCentreDelay (parameters.chorusCentreDelay);
  410. chorus.setFeedback (parameters.chorusFeedback / 100.0f * 0.95f);
  411. chorus.setMix (parameters.chorusMix / 100.0f);
  412. dsp::setBypassed<chorusIndex> (chain, parameters.chorusEnabled.load() == 0.0f);
  413. }
  414. {
  415. dsp::LadderFilter<float>& ladder = dsp::get<ladderIndex> (chain);
  416. ladder.setCutoffFrequencyHz (parameters.ladderCutoff);
  417. ladder.setResonance (parameters.ladderResonance / 100.0f);
  418. ladder.setDrive (Decibels::decibelsToGain (parameters.ladderDrive.load()));
  419. ladder.setMode ([&]
  420. {
  421. switch (roundToInt (parameters.ladderMode.load()))
  422. {
  423. case 0: return dsp::LadderFilterMode::LPF12;
  424. case 1: return dsp::LadderFilterMode::LPF24;
  425. case 2: return dsp::LadderFilterMode::HPF12;
  426. case 3: return dsp::LadderFilterMode::HPF24;
  427. case 4: return dsp::LadderFilterMode::BPF12;
  428. default: break;
  429. }
  430. return dsp::LadderFilterMode::BPF24;
  431. }());
  432. dsp::setBypassed<ladderIndex> (chain, parameters.ladderEnabled.load() == 0.0f);
  433. }
  434. requiresUpdate.store (false);
  435. }
  436. //==============================================================================
  437. static String getPanningTextForValue (float value)
  438. {
  439. if (value == 0.5f)
  440. return "center";
  441. if (value < 0.5f)
  442. return String (roundToInt ((0.5f - value) * 200.0f)) + "%L";
  443. return String (roundToInt ((value - 0.5f) * 200.0f)) + "%R";
  444. }
  445. static float getPanningValueForText (String strText)
  446. {
  447. if (strText.compareIgnoreCase ("center") == 0 || strText.compareIgnoreCase ("c") == 0)
  448. return 0.5f;
  449. strText = strText.trim();
  450. if (strText.indexOfIgnoreCase ("%L") != -1)
  451. {
  452. auto percentage = (float) strText.substring (0, strText.indexOf ("%")).getDoubleValue();
  453. return (100.0f - percentage) / 100.0f * 0.5f;
  454. }
  455. if (strText.indexOfIgnoreCase ("%R") != -1)
  456. {
  457. auto percentage = (float) strText.substring (0, strText.indexOf ("%")).getDoubleValue();
  458. return percentage / 100.0f * 0.5f + 0.5f;
  459. }
  460. return 0.5f;
  461. }
  462. static AudioProcessorValueTreeState::ParameterLayout createParameters()
  463. {
  464. using Parameter = AudioProcessorValueTreeState::Parameter;
  465. auto valueToTextFunction = [] (float x) { return String (x, 2); };
  466. auto textToValueFunction = [] (const String& str) { return str.getFloatValue(); };
  467. auto valueToTextPanFunction = [] (float x) { return getPanningTextForValue ((x + 100.0f) / 200.0f); };
  468. auto textToValuePanFunction = [] (const String& str) { return getPanningValueForText (str) * 200.0f - 100.0f; };
  469. AudioProcessorValueTreeState::ParameterLayout layout;
  470. layout.add (std::make_unique<Parameter> (ID::inputGain,
  471. "Input",
  472. "dB",
  473. NormalisableRange<float> (-40.0f, 40.0f),
  474. 0.0f,
  475. valueToTextFunction,
  476. textToValueFunction));
  477. layout.add (std::make_unique<Parameter> (ID::outputGain,
  478. "Output",
  479. "dB",
  480. NormalisableRange<float> (-40.0f, 40.0f),
  481. 0.0f,
  482. valueToTextFunction,
  483. textToValueFunction));
  484. layout.add (std::make_unique<Parameter> (ID::pan,
  485. "Panning",
  486. "",
  487. NormalisableRange<float> (-100.0f, 100.0f),
  488. 0.0f,
  489. valueToTextPanFunction,
  490. textToValuePanFunction));
  491. layout.add (std::make_unique<AudioParameterBool> (ID::distortionEnabled, "Distortion", true, ""));
  492. layout.add (std::make_unique<AudioParameterChoice> (ID::distortionType,
  493. "Waveshaper",
  494. StringArray { "std::tanh", "Approx. tanh" },
  495. 0));
  496. layout.add (std::make_unique<Parameter> (ID::distortionInGain,
  497. "Gain",
  498. "dB",
  499. NormalisableRange<float> (-40.0f, 40.0f),
  500. 0.0f,
  501. valueToTextFunction,
  502. textToValueFunction));
  503. layout.add (std::make_unique<Parameter> (ID::distortionLowpass,
  504. "Post Low-pass",
  505. "Hz",
  506. NormalisableRange<float> (20.0f, 22000.0f, 0.0f, 0.25f),
  507. 22000.0f,
  508. valueToTextFunction,
  509. textToValueFunction));
  510. layout.add (std::make_unique<Parameter> (ID::distortionHighpass,
  511. "Pre High-pass",
  512. "Hz",
  513. NormalisableRange<float> (20.0f, 22000.0f, 0.0f, 0.25f),
  514. 20.0f,
  515. valueToTextFunction,
  516. textToValueFunction));
  517. layout.add (std::make_unique<Parameter> (ID::distortionCompGain,
  518. "Compensat.",
  519. "dB",
  520. NormalisableRange<float> (-40.0f, 40.0f),
  521. 0.0f,
  522. valueToTextFunction,
  523. textToValueFunction));
  524. layout.add (std::make_unique<Parameter> (ID::distortionMix,
  525. "Mix",
  526. "%",
  527. NormalisableRange<float> (0.0f, 100.0f),
  528. 100.0f,
  529. valueToTextFunction,
  530. textToValueFunction));
  531. layout.add (std::make_unique<AudioParameterChoice> (ID::distortionOversampler,
  532. "Oversampling",
  533. StringArray { "2X",
  534. "4X",
  535. "8X",
  536. "2X compensated",
  537. "4X compensated",
  538. "8X compensated" },
  539. 1));
  540. layout.add (std::make_unique<AudioParameterBool> (ID::multiBandEnabled, "Multi-band", false, ""));
  541. layout.add (std::make_unique<Parameter> (ID::multiBandFreq,
  542. "Sep. Freq.",
  543. "Hz",
  544. NormalisableRange<float> (20.0f, 22000.0f, 0.0f, 0.25f),
  545. 2000.0f,
  546. valueToTextFunction,
  547. textToValueFunction));
  548. layout.add (std::make_unique<Parameter> (ID::multiBandLowVolume,
  549. "Low volume",
  550. "dB",
  551. NormalisableRange<float> (-40.0f, 40.0f),
  552. 0.0f,
  553. valueToTextFunction,
  554. textToValueFunction));
  555. layout.add (std::make_unique<Parameter> (ID::multiBandHighVolume,
  556. "High volume",
  557. "dB",
  558. NormalisableRange<float> (-40.0f, 40.0f),
  559. 0.0f,
  560. valueToTextFunction,
  561. textToValueFunction));
  562. layout.add (std::make_unique<AudioParameterBool> (ID::compressorEnabled, "Comp.", false, ""));
  563. layout.add (std::make_unique<Parameter> (ID::compressorThreshold,
  564. "Threshold",
  565. "dB",
  566. NormalisableRange<float> (-100.0f, 0.0f),
  567. 0.0f,
  568. valueToTextFunction,
  569. textToValueFunction));
  570. layout.add (std::make_unique<Parameter> (ID::compressorRatio,
  571. "Ratio",
  572. ":1",
  573. NormalisableRange<float> (1.0f, 100.0f, 0.0f, 0.25f),
  574. 1.0f,
  575. valueToTextFunction,
  576. textToValueFunction));
  577. layout.add (std::make_unique<Parameter> (ID::compressorAttack,
  578. "Attack",
  579. "ms",
  580. NormalisableRange<float> (0.01f, 1000.0f, 0.0f, 0.25f),
  581. 1.0f,
  582. valueToTextFunction,
  583. textToValueFunction));
  584. layout.add (std::make_unique<Parameter> (ID::compressorRelease,
  585. "Release",
  586. "ms",
  587. NormalisableRange<float> (10.0f, 10000.0f, 0.0f, 0.25f),
  588. 100.0f,
  589. valueToTextFunction,
  590. textToValueFunction));
  591. layout.add (std::make_unique<AudioParameterBool> (ID::noiseGateEnabled, "Gate", false, ""));
  592. layout.add (std::make_unique<Parameter> (ID::noiseGateThreshold,
  593. "Threshold",
  594. "dB",
  595. NormalisableRange<float> (-100.0f, 0.0f),
  596. -100.0f,
  597. valueToTextFunction,
  598. textToValueFunction));
  599. layout.add (std::make_unique<Parameter> (ID::noiseGateRatio,
  600. "Ratio",
  601. ":1",
  602. NormalisableRange<float> (1.0f, 100.0f, 0.0f, 0.25f),
  603. 10.0f,
  604. valueToTextFunction,
  605. textToValueFunction));
  606. layout.add (std::make_unique<Parameter> (ID::noiseGateAttack,
  607. "Attack",
  608. "ms",
  609. NormalisableRange<float> (0.01f, 1000.0f, 0.0f, 0.25f),
  610. 1.0f,
  611. valueToTextFunction,
  612. textToValueFunction));
  613. layout.add (std::make_unique<Parameter> (ID::noiseGateRelease,
  614. "Release",
  615. "ms",
  616. NormalisableRange<float> (10.0f, 10000.0f, 0.0f, 0.25f),
  617. 100.0f,
  618. valueToTextFunction,
  619. textToValueFunction));
  620. layout.add (std::make_unique<AudioParameterBool> (ID::limiterEnabled, "Limiter", false, ""));
  621. layout.add (std::make_unique<Parameter> (ID::limiterThreshold,
  622. "Threshold",
  623. "dB",
  624. NormalisableRange<float> (-40.0f, 0.0f),
  625. 0.0f,
  626. valueToTextFunction,
  627. textToValueFunction));
  628. layout.add (std::make_unique<Parameter> (ID::limiterRelease,
  629. "Release",
  630. "ms",
  631. NormalisableRange<float> (10.0f, 10000.0f, 0.0f, 0.25f),
  632. 100.0f,
  633. valueToTextFunction,
  634. textToValueFunction));
  635. layout.add (std::make_unique<AudioParameterBool> (ID::directDelayEnabled, "DL Dir.", false, ""));
  636. layout.add (std::make_unique<AudioParameterChoice> (ID::directDelayType,
  637. "DL Type",
  638. StringArray { "None",
  639. "Linear",
  640. "Lagrange",
  641. "Thiran" },
  642. 1));
  643. layout.add (std::make_unique<Parameter> (ID::directDelayValue,
  644. "Delay",
  645. "smps",
  646. NormalisableRange<float> (0.0f, 44100.0f),
  647. 0.0f,
  648. valueToTextFunction,
  649. textToValueFunction));
  650. layout.add (std::make_unique<Parameter> (ID::directDelaySmoothing,
  651. "Smooth",
  652. "ms",
  653. NormalisableRange<float> (20.0f, 10000.0f, 0.0f, 0.25f),
  654. 200.0f,
  655. valueToTextFunction,
  656. textToValueFunction));
  657. layout.add (std::make_unique<Parameter> (ID::directDelayMix,
  658. "Delay Mix",
  659. "%",
  660. NormalisableRange<float> (0.0f, 100.0f),
  661. 50.0f,
  662. valueToTextFunction,
  663. textToValueFunction));
  664. layout.add (std::make_unique<AudioParameterBool> (ID::delayEffectEnabled, "DL Effect", false, ""));
  665. layout.add (std::make_unique<AudioParameterChoice> (ID::delayEffectType,
  666. "DL Type",
  667. StringArray { "None",
  668. "Linear",
  669. "Lagrange",
  670. "Thiran" },
  671. 1));
  672. layout.add (std::make_unique<Parameter> (ID::delayEffectValue,
  673. "Delay",
  674. "ms",
  675. NormalisableRange<float> (0.01f, 1000.0f),
  676. 100.0f,
  677. valueToTextFunction,
  678. textToValueFunction));
  679. layout.add (std::make_unique<Parameter> (ID::delayEffectSmoothing,
  680. "Smooth",
  681. "ms",
  682. NormalisableRange<float> (20.0f, 10000.0f, 0.0f, 0.25f),
  683. 400.0f,
  684. valueToTextFunction,
  685. textToValueFunction));
  686. layout.add (std::make_unique<Parameter> (ID::delayEffectLowpass,
  687. "Low-pass",
  688. "Hz",
  689. NormalisableRange<float> (20.0f, 22000.0f, 0.0f, 0.25f),
  690. 22000.0f,
  691. valueToTextFunction,
  692. textToValueFunction));
  693. layout.add (std::make_unique<Parameter> (ID::delayEffectMix,
  694. "Delay Mix",
  695. "%",
  696. NormalisableRange<float> (0.0f, 100.0f),
  697. 50.0f,
  698. valueToTextFunction,
  699. textToValueFunction));
  700. layout.add (std::make_unique<Parameter> (ID::delayEffectFeedback,
  701. "Feedback",
  702. "dB",
  703. NormalisableRange<float> (-100.0f, 0.0f),
  704. -100.0f,
  705. valueToTextFunction,
  706. textToValueFunction));
  707. layout.add (std::make_unique<AudioParameterBool> (ID::phaserEnabled, "Phaser", false, ""));
  708. layout.add (std::make_unique<Parameter> (ID::phaserRate,
  709. "Rate",
  710. "Hz",
  711. NormalisableRange<float> (0.05f, 20.0f, 0.0f, 0.25f),
  712. 1.0f,
  713. valueToTextFunction,
  714. textToValueFunction));
  715. layout.add (std::make_unique<Parameter> (ID::phaserDepth,
  716. "Depth",
  717. "%",
  718. NormalisableRange<float> (0.0f, 100.0f),
  719. 50.0f,
  720. valueToTextFunction,
  721. textToValueFunction));
  722. layout.add (std::make_unique<Parameter> (ID::phaserCentreFrequency,
  723. "Center",
  724. "Hz",
  725. NormalisableRange<float> (20.0f, 20000.0f, 0.0f, 0.25f),
  726. 600.0f,
  727. valueToTextFunction,
  728. textToValueFunction));
  729. layout.add (std::make_unique<Parameter> (ID::phaserFeedback,
  730. "Feedback",
  731. "%",
  732. NormalisableRange<float> (0.0f, 100.0f),
  733. 50.0f,
  734. valueToTextFunction,
  735. textToValueFunction));
  736. layout.add (std::make_unique<Parameter> (ID::phaserMix,
  737. "Mix",
  738. "%",
  739. NormalisableRange<float> (0.0f, 100.0f),
  740. 50.0f,
  741. valueToTextFunction,
  742. textToValueFunction));
  743. layout.add (std::make_unique<AudioParameterBool> (ID::chorusEnabled, "Chorus", false, ""));
  744. layout.add (std::make_unique<Parameter> (ID::chorusRate,
  745. "Rate",
  746. "Hz",
  747. NormalisableRange<float> (0.05f, 20.0f, 0.0f, 0.25f),
  748. 1.0f,
  749. valueToTextFunction,
  750. textToValueFunction));
  751. layout.add (std::make_unique<Parameter> (ID::chorusDepth,
  752. "Depth",
  753. "%",
  754. NormalisableRange<float> (0.0f, 100.0f),
  755. 50.0f,
  756. valueToTextFunction,
  757. textToValueFunction));
  758. layout.add (std::make_unique<Parameter> (ID::chorusCentreDelay,
  759. "Center",
  760. "ms",
  761. NormalisableRange<float> (1.0f, 100.0f, 0.0f, 0.25f),
  762. 7.0f,
  763. valueToTextFunction,
  764. textToValueFunction));
  765. layout.add (std::make_unique<Parameter> (ID::chorusFeedback,
  766. "Feedback",
  767. "%",
  768. NormalisableRange<float> (0.0f, 100.0f),
  769. 50.0f,
  770. valueToTextFunction,
  771. textToValueFunction));
  772. layout.add (std::make_unique<Parameter> (ID::chorusMix,
  773. "Mix",
  774. "%",
  775. NormalisableRange<float> (0.0f, 100.0f),
  776. 50.0f,
  777. valueToTextFunction,
  778. textToValueFunction));
  779. layout.add (std::make_unique<AudioParameterBool> (ID::ladderEnabled, "Ladder", false, ""));
  780. layout.add (std::make_unique<AudioParameterChoice> (ID::ladderMode,
  781. "Mode",
  782. StringArray { "LP12",
  783. "LP24",
  784. "HP12",
  785. "HP24",
  786. "BP12",
  787. "BP24" },
  788. 1));
  789. layout.add (std::make_unique<Parameter> (ID::ladderCutoff,
  790. "Frequency",
  791. "Hz",
  792. NormalisableRange<float> (10.0f, 22000.0f, 0.0f, 0.25f),
  793. 1000.0f,
  794. valueToTextFunction,
  795. textToValueFunction));
  796. layout.add (std::make_unique<Parameter> (ID::ladderResonance,
  797. "Resonance",
  798. "%",
  799. NormalisableRange<float> (0.0f, 100.0f),
  800. 0.0f,
  801. valueToTextFunction,
  802. textToValueFunction));
  803. layout.add (std::make_unique<Parameter> (ID::ladderDrive,
  804. "Drive",
  805. "dB",
  806. NormalisableRange<float> (0.0f, 40.0f),
  807. 0.0f,
  808. valueToTextFunction,
  809. textToValueFunction));
  810. return layout;
  811. }
  812. //==============================================================================
  813. struct DistortionProcessor
  814. {
  815. DistortionProcessor()
  816. {
  817. forEach ([] (dsp::Gain<float>& gain) { gain.setRampDurationSeconds (0.05); },
  818. distGain,
  819. compGain);
  820. lowpass.setType (dsp::FirstOrderTPTFilterType::lowpass);
  821. highpass.setType (dsp::FirstOrderTPTFilterType::highpass);
  822. mixer.setMixingRule (dsp::DryWetMixingRule::linear);
  823. }
  824. void prepare (const dsp::ProcessSpec& spec)
  825. {
  826. for (auto& oversampler : oversamplers)
  827. oversampler.initProcessing (spec.maximumBlockSize);
  828. prepareAll (spec, lowpass, highpass, distGain, compGain, mixer);
  829. }
  830. void reset()
  831. {
  832. for (auto& oversampler : oversamplers)
  833. oversampler.reset();
  834. resetAll (lowpass, highpass, distGain, compGain, mixer);
  835. }
  836. float getLatency() const
  837. {
  838. return oversamplers[size_t (currentIndexOversampling)].getLatencyInSamples();
  839. }
  840. template <typename Context>
  841. void process (Context& context)
  842. {
  843. if (context.isBypassed)
  844. return;
  845. const auto& inputBlock = context.getInputBlock();
  846. mixer.setWetLatency (getLatency());
  847. mixer.pushDrySamples (inputBlock);
  848. distGain.process (context);
  849. highpass.process (context);
  850. auto ovBlock = oversamplers[size_t (currentIndexOversampling)].processSamplesUp (inputBlock);
  851. dsp::ProcessContextReplacing<float> waveshaperContext (ovBlock);
  852. if (isPositiveAndBelow (currentIndexWaveshaper, waveShapers.size()))
  853. {
  854. waveShapers[size_t (currentIndexWaveshaper)].process (waveshaperContext);
  855. if (currentIndexWaveshaper == 1)
  856. clipping.process (waveshaperContext);
  857. waveshaperContext.getOutputBlock() *= 0.7f;
  858. }
  859. auto& outputBlock = context.getOutputBlock();
  860. oversamplers[size_t (currentIndexOversampling)].processSamplesDown (outputBlock);
  861. lowpass.process (context);
  862. compGain.process (context);
  863. mixer.mixWetSamples (outputBlock);
  864. }
  865. std::array<dsp::Oversampling<float>, 6> oversamplers
  866. { {
  867. { 2, 1, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR, true, false },
  868. { 2, 2, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR, true, false },
  869. { 2, 3, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR, true, false },
  870. { 2, 1, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR, true, true },
  871. { 2, 2, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR, true, true },
  872. { 2, 3, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR, true, true },
  873. } };
  874. dsp::FirstOrderTPTFilter<float> lowpass, highpass;
  875. dsp::Gain<float> distGain, compGain;
  876. dsp::DryWetMixer<float> mixer { 10 };
  877. std::array<dsp::WaveShaper<float>, 2> waveShapers { { { std::tanh },
  878. { dsp::FastMathApproximations::tanh } } };
  879. dsp::WaveShaper<float> clipping;
  880. int currentIndexOversampling = 0;
  881. int currentIndexWaveshaper = 0;
  882. };
  883. struct MultiBandProcessor
  884. {
  885. MultiBandProcessor()
  886. {
  887. forEach ([] (dsp::Gain<float>& gain) { gain.setRampDurationSeconds (0.05); },
  888. lowVolume,
  889. highVolume);
  890. lowpass .setType (dsp::LinkwitzRileyFilterType::lowpass);
  891. highpass.setType (dsp::LinkwitzRileyFilterType::highpass);
  892. }
  893. void prepare (const dsp::ProcessSpec& spec)
  894. {
  895. prepareAll (spec, lowpass, highpass, lowVolume, highVolume);
  896. bufferSeparation.setSize (4, int (spec.maximumBlockSize), false, false, true);
  897. }
  898. void reset()
  899. {
  900. resetAll (lowpass, highpass, lowVolume, highVolume);
  901. }
  902. template <typename Context>
  903. void process (Context& context)
  904. {
  905. const auto& inputBlock = context.getInputBlock();
  906. const auto numSamples = inputBlock.getNumSamples();
  907. const auto numChannels = inputBlock.getNumChannels();
  908. auto sepBlock = dsp::AudioBlock<float> (bufferSeparation).getSubBlock (0, (size_t) numSamples);
  909. auto sepLowBlock = sepBlock.getSubsetChannelBlock (0, (size_t) numChannels);
  910. auto sepHighBlock = sepBlock.getSubsetChannelBlock (2, (size_t) numChannels);
  911. sepLowBlock .copyFrom (inputBlock);
  912. sepHighBlock.copyFrom (inputBlock);
  913. auto contextLow = dsp::ProcessContextReplacing<float> (sepLowBlock);
  914. contextLow.isBypassed = context.isBypassed;
  915. lowpass .process (contextLow);
  916. lowVolume.process (contextLow);
  917. auto contextHigh = dsp::ProcessContextReplacing<float> (sepHighBlock);
  918. contextHigh.isBypassed = context.isBypassed;
  919. highpass .process (contextHigh);
  920. highVolume.process (contextHigh);
  921. if (! context.isBypassed)
  922. {
  923. sepLowBlock.add (sepHighBlock);
  924. context.getOutputBlock().copyFrom (sepLowBlock);
  925. }
  926. }
  927. dsp::LinkwitzRileyFilter<float> lowpass, highpass;
  928. dsp::Gain<float> lowVolume, highVolume;
  929. AudioBuffer<float> bufferSeparation;
  930. };
  931. struct DirectDelayProcessor
  932. {
  933. DirectDelayProcessor()
  934. {
  935. smoothFilter.setType (dsp::FirstOrderTPTFilterType::lowpass);
  936. mixer.setMixingRule (dsp::DryWetMixingRule::linear);
  937. }
  938. void prepare (const dsp::ProcessSpec& spec)
  939. {
  940. prepareAll (spec, noInterpolation, linear, lagrange, thiran, smoothFilter, mixer);
  941. }
  942. void reset()
  943. {
  944. resetAll (noInterpolation, linear, lagrange, thiran, smoothFilter, mixer);
  945. }
  946. template <typename Context>
  947. void process (Context& context)
  948. {
  949. if (context.isBypassed)
  950. return;
  951. const auto& inputBlock = context.getInputBlock();
  952. const auto& outputBlock = context.getOutputBlock();
  953. mixer.pushDrySamples (inputBlock);
  954. const auto numChannels = inputBlock.getNumChannels();
  955. const auto numSamples = inputBlock.getNumSamples();
  956. for (size_t channel = 0; channel < numChannels; ++channel)
  957. {
  958. auto* samplesIn = inputBlock .getChannelPointer (channel);
  959. auto* samplesOut = outputBlock.getChannelPointer (channel);
  960. for (size_t i = 0; i < numSamples; ++i)
  961. {
  962. const auto delay = smoothFilter.processSample (int (channel), delayDirectValue[channel]);
  963. samplesOut[i] = [&]
  964. {
  965. switch (delayLineDirectType)
  966. {
  967. case 0:
  968. noInterpolation.pushSample (int (channel), samplesIn[i]);
  969. noInterpolation.setDelay ((float) delay);
  970. return noInterpolation.popSample (int (channel));
  971. case 1:
  972. linear.pushSample (int (channel), samplesIn[i]);
  973. linear.setDelay ((float) delay);
  974. return linear.popSample (int (channel));
  975. case 2:
  976. lagrange.pushSample (int (channel), samplesIn[i]);
  977. lagrange.setDelay ((float) delay);
  978. return lagrange.popSample (int (channel));
  979. case 3:
  980. thiran.pushSample (int (channel), samplesIn[i]);
  981. thiran.setDelay ((float) delay);
  982. return thiran.popSample (int (channel));
  983. default:
  984. break;
  985. }
  986. jassertfalse;
  987. return 0.0f;
  988. }();
  989. }
  990. }
  991. mixer.mixWetSamples (outputBlock);
  992. }
  993. static constexpr auto directDelayBufferSize = 44100;
  994. dsp::DelayLine<float, dsp::DelayLineInterpolationTypes::None> noInterpolation { directDelayBufferSize };
  995. dsp::DelayLine<float, dsp::DelayLineInterpolationTypes::Linear> linear { directDelayBufferSize };
  996. dsp::DelayLine<float, dsp::DelayLineInterpolationTypes::Lagrange3rd> lagrange { directDelayBufferSize };
  997. dsp::DelayLine<float, dsp::DelayLineInterpolationTypes::Thiran> thiran { directDelayBufferSize };
  998. // Double precision to avoid some approximation issues
  999. dsp::FirstOrderTPTFilter<double> smoothFilter;
  1000. dsp::DryWetMixer<float> mixer;
  1001. std::array<double, 2> delayDirectValue { {} };
  1002. int delayLineDirectType = 1;
  1003. };
  1004. struct DelayEffectProcessor
  1005. {
  1006. DelayEffectProcessor()
  1007. {
  1008. smoothFilter.setType (dsp::FirstOrderTPTFilterType::lowpass);
  1009. lowpass.setType (dsp::FirstOrderTPTFilterType::lowpass);
  1010. mixer.setMixingRule (dsp::DryWetMixingRule::linear);
  1011. }
  1012. void prepare (const dsp::ProcessSpec& spec)
  1013. {
  1014. prepareAll (spec, noInterpolation, linear, lagrange, thiran, smoothFilter, lowpass, mixer);
  1015. for (auto& volume : delayFeedbackVolume)
  1016. volume.reset (spec.sampleRate, 0.05);
  1017. }
  1018. void reset()
  1019. {
  1020. resetAll (noInterpolation, linear, lagrange, thiran, smoothFilter, lowpass, mixer);
  1021. std::fill (lastDelayEffectOutput.begin(), lastDelayEffectOutput.end(), 0.0f);
  1022. }
  1023. template <typename Context>
  1024. void process (Context& context)
  1025. {
  1026. if (context.isBypassed)
  1027. return;
  1028. const auto& inputBlock = context.getInputBlock();
  1029. const auto& outputBlock = context.getOutputBlock();
  1030. const auto numSamples = inputBlock.getNumSamples();
  1031. const auto numChannels = inputBlock.getNumChannels();
  1032. mixer.pushDrySamples (inputBlock);
  1033. for (size_t channel = 0; channel < numChannels; ++channel)
  1034. {
  1035. auto* samplesIn = inputBlock .getChannelPointer (channel);
  1036. auto* samplesOut = outputBlock.getChannelPointer (channel);
  1037. for (size_t i = 0; i < numSamples; ++i)
  1038. {
  1039. auto input = samplesIn[i] - lastDelayEffectOutput[channel];
  1040. auto delay = smoothFilter.processSample (int (channel), delayEffectValue[channel]);
  1041. const auto output = [&]
  1042. {
  1043. switch (delayEffectType)
  1044. {
  1045. case 0:
  1046. noInterpolation.pushSample (int (channel), input);
  1047. noInterpolation.setDelay ((float) delay);
  1048. return noInterpolation.popSample (int (channel));
  1049. case 1:
  1050. linear.pushSample (int (channel), input);
  1051. linear.setDelay ((float) delay);
  1052. return linear.popSample (int (channel));
  1053. case 2:
  1054. lagrange.pushSample (int (channel), input);
  1055. lagrange.setDelay ((float) delay);
  1056. return lagrange.popSample (int (channel));
  1057. case 3:
  1058. thiran.pushSample (int (channel), input);
  1059. thiran.setDelay ((float) delay);
  1060. return thiran.popSample (int (channel));
  1061. default:
  1062. break;
  1063. }
  1064. jassertfalse;
  1065. return 0.0f;
  1066. }();
  1067. const auto processed = lowpass.processSample (int (channel), output);
  1068. samplesOut[i] = processed;
  1069. lastDelayEffectOutput[channel] = processed * delayFeedbackVolume[channel].getNextValue();
  1070. }
  1071. }
  1072. mixer.mixWetSamples (outputBlock);
  1073. }
  1074. static constexpr auto effectDelaySamples = 192000;
  1075. dsp::DelayLine<float, dsp::DelayLineInterpolationTypes::None> noInterpolation { effectDelaySamples };
  1076. dsp::DelayLine<float, dsp::DelayLineInterpolationTypes::Linear> linear { effectDelaySamples };
  1077. dsp::DelayLine<float, dsp::DelayLineInterpolationTypes::Lagrange3rd> lagrange { effectDelaySamples };
  1078. dsp::DelayLine<float, dsp::DelayLineInterpolationTypes::Thiran> thiran { effectDelaySamples };
  1079. // Double precision to avoid some approximation issues
  1080. dsp::FirstOrderTPTFilter<double> smoothFilter;
  1081. std::array<double, 2> delayEffectValue;
  1082. std::array<LinearSmoothedValue<float>, 2> delayFeedbackVolume;
  1083. dsp::FirstOrderTPTFilter<float> lowpass;
  1084. dsp::DryWetMixer<float> mixer;
  1085. std::array<float, 2> lastDelayEffectOutput;
  1086. int delayEffectType = 1;
  1087. };
  1088. using Chain = dsp::ProcessorChain<dsp::NoiseGate<float>,
  1089. dsp::Gain<float>,
  1090. DirectDelayProcessor,
  1091. MultiBandProcessor,
  1092. dsp::Compressor<float>,
  1093. dsp::Phaser<float>,
  1094. dsp::Chorus<float>,
  1095. DistortionProcessor,
  1096. dsp::LadderFilter<float>,
  1097. DelayEffectProcessor,
  1098. dsp::Limiter<float>,
  1099. dsp::Gain<float>,
  1100. dsp::Panner<float>>;
  1101. Chain chain;
  1102. // We use this enum to index into the chain above
  1103. enum ProcessorIndices
  1104. {
  1105. noiseGateIndex,
  1106. inputGainIndex,
  1107. directDelayIndex,
  1108. multiBandIndex,
  1109. compressorIndex,
  1110. phaserIndex,
  1111. chorusIndex,
  1112. distortionIndex,
  1113. ladderIndex,
  1114. delayEffectIndex,
  1115. limiterIndex,
  1116. outputGainIndex,
  1117. pannerIndex
  1118. };
  1119. //==============================================================================
  1120. std::atomic<bool> requiresUpdate { true };
  1121. //==============================================================================
  1122. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DspModulePluginDemo)
  1123. };
  1124. //==============================================================================
  1125. class DspModulePluginDemoEditor : public AudioProcessorEditor
  1126. {
  1127. public:
  1128. explicit DspModulePluginDemoEditor (DspModulePluginDemo& p)
  1129. : AudioProcessorEditor (&p),
  1130. proc (p)
  1131. {
  1132. comboEffect.addSectionHeading ("Main");
  1133. comboEffect.addItem ("Distortion", TabDistortion);
  1134. comboEffect.addItem ("Multi-band", TabMultiBand);
  1135. comboEffect.addSectionHeading ("Dynamics");
  1136. comboEffect.addItem ("Compressor", TabCompressor);
  1137. comboEffect.addItem ("Noise gate", TabNoiseGate);
  1138. comboEffect.addItem ("Limiter", TabLimiter);
  1139. comboEffect.addSectionHeading ("Delay");
  1140. comboEffect.addItem ("Delay line direct", TabDelayLineDirect);
  1141. comboEffect.addItem ("Delay line effect", TabDelayLineEffect);
  1142. comboEffect.addSectionHeading ("Others");
  1143. comboEffect.addItem ("Phaser", TabPhaser);
  1144. comboEffect.addItem ("Chorus", TabChorus);
  1145. comboEffect.addItem ("Ladder filter", TabLadder);
  1146. comboEffect.setSelectedId (proc.indexTab + 1, dontSendNotification);
  1147. comboEffect.onChange = [this]
  1148. {
  1149. proc.indexTab = comboEffect.getSelectedId() - 1;
  1150. updateVisibility();
  1151. };
  1152. addAllAndMakeVisible (*this,
  1153. comboEffect,
  1154. labelEffect,
  1155. basicControls,
  1156. distortionControls,
  1157. multibandControls,
  1158. compressorControls,
  1159. noiseGateControls,
  1160. limiterControls,
  1161. directDelayControls,
  1162. delayEffectControls,
  1163. phaserControls,
  1164. chorusControls,
  1165. ladderControls);
  1166. labelEffect.setJustificationType (Justification::centredRight);
  1167. labelEffect.attachToComponent (&comboEffect, true);
  1168. updateVisibility();
  1169. setSize (800, 430);
  1170. }
  1171. //==============================================================================
  1172. void paint (Graphics& g) override
  1173. {
  1174. auto rect = getLocalBounds();
  1175. auto rectTop = rect.removeFromTop (topSize);
  1176. auto rectBottom = rect.removeFromBottom (bottomSize);
  1177. auto rectEffects = rect.removeFromBottom (tabSize);
  1178. auto rectChoice = rect.removeFromBottom (midSize);
  1179. g.setColour (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
  1180. g.fillRect (rect);
  1181. g.setColour (getLookAndFeel().findColour (ResizableWindow::backgroundColourId).brighter (0.2f));
  1182. g.fillRect (rectEffects);
  1183. g.setColour (getLookAndFeel().findColour (ResizableWindow::backgroundColourId).darker (0.2f));
  1184. g.fillRect (rectTop);
  1185. g.fillRect (rectBottom);
  1186. g.fillRect (rectChoice);
  1187. g.setColour (Colours::white);
  1188. g.setFont (Font (20.0f).italicised().withExtraKerningFactor (0.1f));
  1189. g.drawFittedText ("DSP MODULE DEMO", rectTop.reduced (10, 0), Justification::centredLeft, 1);
  1190. }
  1191. void resized() override
  1192. {
  1193. auto rect = getLocalBounds();
  1194. rect.removeFromTop (topSize);
  1195. rect.removeFromBottom (bottomSize);
  1196. auto rectEffects = rect.removeFromBottom (tabSize);
  1197. auto rectChoice = rect.removeFromBottom (midSize);
  1198. comboEffect.setBounds (rectChoice.withSizeKeepingCentre (200, 24));
  1199. rect.reduce (80, 0);
  1200. rectEffects.reduce (20, 0);
  1201. basicControls.setBounds (rect);
  1202. forEach ([&] (Component& comp) { comp.setBounds (rectEffects); },
  1203. distortionControls,
  1204. multibandControls,
  1205. compressorControls,
  1206. noiseGateControls,
  1207. limiterControls,
  1208. directDelayControls,
  1209. delayEffectControls,
  1210. phaserControls,
  1211. chorusControls,
  1212. ladderControls);
  1213. }
  1214. private:
  1215. class AttachedSlider : public Component
  1216. {
  1217. public:
  1218. AttachedSlider (AudioProcessorValueTreeState& state, StringRef strID)
  1219. : label ("", state.getParameter (strID)->name),
  1220. attachment (state, strID, slider)
  1221. {
  1222. addAllAndMakeVisible (*this, slider, label);
  1223. slider.setTextValueSuffix (" " + state.getParameter (strID)->label);
  1224. label.attachToComponent (&slider, false);
  1225. label.setJustificationType (Justification::centred);
  1226. }
  1227. void resized() override { slider.setBounds (getLocalBounds().reduced (0, 40)); }
  1228. private:
  1229. Slider slider { Slider::RotaryVerticalDrag, Slider::TextBoxBelow };
  1230. Label label;
  1231. AudioProcessorValueTreeState::SliderAttachment attachment;
  1232. };
  1233. class AttachedToggle : public Component
  1234. {
  1235. public:
  1236. AttachedToggle (AudioProcessorValueTreeState& state, StringRef strID)
  1237. : toggle (state.getParameter (strID)->name),
  1238. attachment (state, strID, toggle)
  1239. {
  1240. addAndMakeVisible (toggle);
  1241. }
  1242. void resized() override { toggle.setBounds (getLocalBounds()); }
  1243. private:
  1244. ToggleButton toggle;
  1245. AudioProcessorValueTreeState::ButtonAttachment attachment;
  1246. };
  1247. class AttachedCombo : public Component
  1248. {
  1249. public:
  1250. AttachedCombo (AudioProcessorValueTreeState& state, StringRef strID)
  1251. : combo (state, strID),
  1252. label ("", state.getParameter (strID)->name),
  1253. attachment (state, strID, combo)
  1254. {
  1255. addAllAndMakeVisible (*this, combo, label);
  1256. label.attachToComponent (&combo, false);
  1257. label.setJustificationType (Justification::centred);
  1258. }
  1259. void resized() override
  1260. {
  1261. combo.setBounds (getLocalBounds().withSizeKeepingCentre (jmin (getWidth(), 150), 24));
  1262. }
  1263. private:
  1264. struct ComboWithItems : public ComboBox
  1265. {
  1266. ComboWithItems (AudioProcessorValueTreeState& state, StringRef strID)
  1267. {
  1268. // Adding the list here in the constructor means that the combo
  1269. // is already populated when we construct the attachment below
  1270. addItemList (dynamic_cast<AudioParameterChoice*> (state.getParameter (strID))->choices, 1);
  1271. }
  1272. };
  1273. ComboWithItems combo;
  1274. Label label;
  1275. AudioProcessorValueTreeState::ComboBoxAttachment attachment;
  1276. };
  1277. //==============================================================================
  1278. void updateVisibility()
  1279. {
  1280. const auto indexEffect = comboEffect.getSelectedId();
  1281. const auto op = [&] (const std::tuple<Component&, int>& tup)
  1282. {
  1283. Component& comp = std::get<0> (tup);
  1284. const int tabIndex = std::get<1> (tup);
  1285. comp.setVisible (tabIndex == indexEffect);
  1286. };
  1287. forEach (op,
  1288. std::forward_as_tuple (distortionControls, TabDistortion),
  1289. std::forward_as_tuple (multibandControls, TabMultiBand),
  1290. std::forward_as_tuple (compressorControls, TabCompressor),
  1291. std::forward_as_tuple (noiseGateControls, TabNoiseGate),
  1292. std::forward_as_tuple (limiterControls, TabLimiter),
  1293. std::forward_as_tuple (directDelayControls, TabDelayLineDirect),
  1294. std::forward_as_tuple (delayEffectControls, TabDelayLineEffect),
  1295. std::forward_as_tuple (phaserControls, TabPhaser),
  1296. std::forward_as_tuple (chorusControls, TabChorus),
  1297. std::forward_as_tuple (ladderControls, TabLadder));
  1298. }
  1299. enum EffectsTabs
  1300. {
  1301. TabDistortion = 1,
  1302. TabMultiBand,
  1303. TabCompressor,
  1304. TabNoiseGate,
  1305. TabLimiter,
  1306. TabDelayLineDirect,
  1307. TabDelayLineEffect,
  1308. TabPhaser,
  1309. TabChorus,
  1310. TabLadder
  1311. };
  1312. //==============================================================================
  1313. ComboBox comboEffect;
  1314. Label labelEffect { "Audio effect: " };
  1315. struct GetTrackInfo
  1316. {
  1317. // Combo boxes need a lot of room
  1318. Grid::TrackInfo operator() (AttachedCombo&) const { return 120_px; }
  1319. // Toggles are a bit smaller
  1320. Grid::TrackInfo operator() (AttachedToggle&) const { return 80_px; }
  1321. // Sliders take up as much room as they can
  1322. Grid::TrackInfo operator() (AttachedSlider&) const { return 1_fr; }
  1323. };
  1324. template <typename... Components>
  1325. static void performLayout (const Rectangle<int>& bounds, Components&... components)
  1326. {
  1327. Grid grid;
  1328. using Track = Grid::TrackInfo;
  1329. grid.autoColumns = Track (1_fr);
  1330. grid.autoRows = Track (1_fr);
  1331. grid.columnGap = Grid::Px (10);
  1332. grid.rowGap = Grid::Px (0);
  1333. grid.autoFlow = Grid::AutoFlow::column;
  1334. grid.templateColumns = { GetTrackInfo{} (components)... };
  1335. grid.items = { GridItem (components)... };
  1336. grid.performLayout (bounds);
  1337. }
  1338. struct BasicControls : public Component
  1339. {
  1340. explicit BasicControls (AudioProcessorValueTreeState& state)
  1341. : pan (state, ID::pan),
  1342. input (state, ID::inputGain),
  1343. output (state, ID::outputGain)
  1344. {
  1345. addAllAndMakeVisible (*this, pan, input, output);
  1346. }
  1347. void resized() override
  1348. {
  1349. performLayout (getLocalBounds(), input, output, pan);
  1350. }
  1351. AttachedSlider pan, input, output;
  1352. };
  1353. struct DistortionControls : public Component
  1354. {
  1355. explicit DistortionControls (AudioProcessorValueTreeState& state)
  1356. : toggle (state, ID::distortionEnabled),
  1357. lowpass (state, ID::distortionLowpass),
  1358. highpass (state, ID::distortionHighpass),
  1359. mix (state, ID::distortionMix),
  1360. gain (state, ID::distortionInGain),
  1361. compv (state, ID::distortionCompGain),
  1362. type (state, ID::distortionType),
  1363. oversampling (state, ID::distortionOversampler)
  1364. {
  1365. addAllAndMakeVisible (*this, toggle, type, lowpass, highpass, mix, gain, compv, oversampling);
  1366. }
  1367. void resized() override
  1368. {
  1369. performLayout (getLocalBounds(), toggle, type, gain, highpass, lowpass, compv, mix, oversampling);
  1370. }
  1371. AttachedToggle toggle;
  1372. AttachedSlider lowpass, highpass, mix, gain, compv;
  1373. AttachedCombo type, oversampling;
  1374. };
  1375. struct MultiBandControls : public Component
  1376. {
  1377. explicit MultiBandControls (AudioProcessorValueTreeState& state)
  1378. : toggle (state, ID::multiBandEnabled),
  1379. low (state, ID::multiBandLowVolume),
  1380. high (state, ID::multiBandHighVolume),
  1381. lRFreq (state, ID::multiBandFreq)
  1382. {
  1383. addAllAndMakeVisible (*this, toggle, low, high, lRFreq);
  1384. }
  1385. void resized() override
  1386. {
  1387. performLayout (getLocalBounds(), toggle, lRFreq, low, high);
  1388. }
  1389. AttachedToggle toggle;
  1390. AttachedSlider low, high, lRFreq;
  1391. };
  1392. struct CompressorControls : public Component
  1393. {
  1394. explicit CompressorControls (AudioProcessorValueTreeState& state)
  1395. : toggle (state, ID::compressorEnabled),
  1396. threshold (state, ID::compressorThreshold),
  1397. ratio (state, ID::compressorRatio),
  1398. attack (state, ID::compressorAttack),
  1399. release (state, ID::compressorRelease)
  1400. {
  1401. addAllAndMakeVisible (*this, toggle, threshold, ratio, attack, release);
  1402. }
  1403. void resized() override
  1404. {
  1405. performLayout (getLocalBounds(), toggle, threshold, ratio, attack, release);
  1406. }
  1407. AttachedToggle toggle;
  1408. AttachedSlider threshold, ratio, attack, release;
  1409. };
  1410. struct NoiseGateControls : public Component
  1411. {
  1412. explicit NoiseGateControls (AudioProcessorValueTreeState& state)
  1413. : toggle (state, ID::noiseGateEnabled),
  1414. threshold (state, ID::noiseGateThreshold),
  1415. ratio (state, ID::noiseGateRatio),
  1416. attack (state, ID::noiseGateAttack),
  1417. release (state, ID::noiseGateRelease)
  1418. {
  1419. addAllAndMakeVisible (*this, toggle, threshold, ratio, attack, release);
  1420. }
  1421. void resized() override
  1422. {
  1423. performLayout (getLocalBounds(), toggle, threshold, ratio, attack, release);
  1424. }
  1425. AttachedToggle toggle;
  1426. AttachedSlider threshold, ratio, attack, release;
  1427. };
  1428. struct LimiterControls : public Component
  1429. {
  1430. explicit LimiterControls (AudioProcessorValueTreeState& state)
  1431. : toggle (state, ID::limiterEnabled),
  1432. threshold (state, ID::limiterThreshold),
  1433. release (state, ID::limiterRelease)
  1434. {
  1435. addAllAndMakeVisible (*this, toggle, threshold, release);
  1436. }
  1437. void resized() override
  1438. {
  1439. performLayout (getLocalBounds(), toggle, threshold, release);
  1440. }
  1441. AttachedToggle toggle;
  1442. AttachedSlider threshold, release;
  1443. };
  1444. struct DirectDelayControls : public Component
  1445. {
  1446. explicit DirectDelayControls (AudioProcessorValueTreeState& state)
  1447. : toggle (state, ID::directDelayEnabled),
  1448. type (state, ID::directDelayType),
  1449. delay (state, ID::directDelayValue),
  1450. smooth (state, ID::directDelaySmoothing),
  1451. mix (state, ID::directDelayMix)
  1452. {
  1453. addAllAndMakeVisible (*this, toggle, type, delay, smooth, mix);
  1454. }
  1455. void resized() override
  1456. {
  1457. performLayout (getLocalBounds(), toggle, type, delay, smooth, mix);
  1458. }
  1459. AttachedToggle toggle;
  1460. AttachedCombo type;
  1461. AttachedSlider delay, smooth, mix;
  1462. };
  1463. struct DelayEffectControls : public Component
  1464. {
  1465. explicit DelayEffectControls (AudioProcessorValueTreeState& state)
  1466. : toggle (state, ID::delayEffectEnabled),
  1467. type (state, ID::delayEffectType),
  1468. value (state, ID::delayEffectValue),
  1469. smooth (state, ID::delayEffectSmoothing),
  1470. lowpass (state, ID::delayEffectLowpass),
  1471. feedback (state, ID::delayEffectFeedback),
  1472. mix (state, ID::delayEffectMix)
  1473. {
  1474. addAllAndMakeVisible (*this, toggle, type, value, smooth, lowpass, feedback, mix);
  1475. }
  1476. void resized() override
  1477. {
  1478. performLayout (getLocalBounds(), toggle, type, value, smooth, lowpass, feedback, mix);
  1479. }
  1480. AttachedToggle toggle;
  1481. AttachedCombo type;
  1482. AttachedSlider value, smooth, lowpass, feedback, mix;
  1483. };
  1484. struct PhaserControls : public Component
  1485. {
  1486. explicit PhaserControls (AudioProcessorValueTreeState& state)
  1487. : toggle (state, ID::phaserEnabled),
  1488. rate (state, ID::phaserRate),
  1489. depth (state, ID::phaserDepth),
  1490. centre (state, ID::phaserCentreFrequency),
  1491. feedback (state, ID::phaserFeedback),
  1492. mix (state, ID::phaserMix)
  1493. {
  1494. addAllAndMakeVisible (*this, toggle, rate, depth, centre, feedback, mix);
  1495. }
  1496. void resized() override
  1497. {
  1498. performLayout (getLocalBounds(), toggle, rate, depth, centre, feedback, mix);
  1499. }
  1500. AttachedToggle toggle;
  1501. AttachedSlider rate, depth, centre, feedback, mix;
  1502. };
  1503. struct ChorusControls : public Component
  1504. {
  1505. explicit ChorusControls (AudioProcessorValueTreeState& state)
  1506. : toggle (state, ID::chorusEnabled),
  1507. rate (state, ID::chorusRate),
  1508. depth (state, ID::chorusDepth),
  1509. centre (state, ID::chorusCentreDelay),
  1510. feedback (state, ID::chorusFeedback),
  1511. mix (state, ID::chorusMix)
  1512. {
  1513. addAllAndMakeVisible (*this, toggle, rate, depth, centre, feedback, mix);
  1514. }
  1515. void resized() override
  1516. {
  1517. performLayout (getLocalBounds(), toggle, rate, depth, centre, feedback, mix);
  1518. }
  1519. AttachedToggle toggle;
  1520. AttachedSlider rate, depth, centre, feedback, mix;
  1521. };
  1522. struct LadderControls : public Component
  1523. {
  1524. explicit LadderControls (AudioProcessorValueTreeState& state)
  1525. : toggle (state, ID::ladderEnabled),
  1526. mode (state, ID::ladderMode),
  1527. freq (state, ID::ladderCutoff),
  1528. resonance (state, ID::ladderResonance),
  1529. drive (state, ID::ladderDrive)
  1530. {
  1531. addAllAndMakeVisible (*this, toggle, mode, freq, resonance, drive);
  1532. }
  1533. void resized() override
  1534. {
  1535. performLayout (getLocalBounds(), toggle, mode, freq, resonance, drive);
  1536. }
  1537. AttachedToggle toggle;
  1538. AttachedCombo mode;
  1539. AttachedSlider freq, resonance, drive;
  1540. };
  1541. //==============================================================================
  1542. static constexpr auto topSize = 40,
  1543. bottomSize = 40,
  1544. midSize = 40,
  1545. tabSize = 155;
  1546. //==============================================================================
  1547. DspModulePluginDemo& proc;
  1548. BasicControls basicControls { proc.apvts };
  1549. DistortionControls distortionControls { proc.apvts };
  1550. MultiBandControls multibandControls { proc.apvts };
  1551. CompressorControls compressorControls { proc.apvts };
  1552. NoiseGateControls noiseGateControls { proc.apvts };
  1553. LimiterControls limiterControls { proc.apvts };
  1554. DirectDelayControls directDelayControls { proc.apvts };
  1555. DelayEffectControls delayEffectControls { proc.apvts };
  1556. PhaserControls phaserControls { proc.apvts };
  1557. ChorusControls chorusControls { proc.apvts };
  1558. LadderControls ladderControls { proc.apvts };
  1559. //==============================================================================
  1560. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DspModulePluginDemoEditor)
  1561. };
  1562. struct DspModulePluginDemoAudioProcessor : public DspModulePluginDemo
  1563. {
  1564. AudioProcessorEditor* createEditor() override
  1565. {
  1566. return new DspModulePluginDemoEditor (*this);
  1567. }
  1568. bool hasEditor() const override { return true; }
  1569. };