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.

145 lines
6.2KB

  1. #pragma once
  2. #include <memory>
  3. #include <deque>
  4. #include "PluginSplitter.hpp"
  5. #include "General/AudioSpinMutex.h"
  6. #include "SplitterProcessors.hpp"
  7. #include "CloneableSources.hpp"
  8. #include "WEFilters/PerlinSource.hpp"
  9. namespace ModelInterface {
  10. struct SplitterState {
  11. // Internal representation of the data model
  12. std::shared_ptr<PluginSplitter> splitter;
  13. // We store the crossover frequencies so they can be restored if the user switches from a
  14. // multiband split to another type and back again
  15. std::optional<std::vector<float>> cachedcrossoverFrequencies;
  16. SplitterState(HostConfiguration config,
  17. std::function<float(int, MODULATION_TYPE)> getModulationValueCallback,
  18. std::function<void(int)> latencyChangeCallback) {
  19. splitter.reset(
  20. new PluginSplitterSeries(config, getModulationValueCallback, latencyChangeCallback)
  21. );
  22. SplitterProcessors::prepareToPlay(*splitter.get(), config.sampleRate, config.blockSize, config.layout);
  23. }
  24. SplitterState* clone() const {
  25. return new SplitterState(*this);
  26. }
  27. private:
  28. SplitterState(const SplitterState& other) : splitter(other.splitter->clone()) {
  29. if (other.cachedcrossoverFrequencies.has_value()) {
  30. cachedcrossoverFrequencies = other.cachedcrossoverFrequencies;
  31. }
  32. }
  33. };
  34. struct EnvelopeWrapper {
  35. std::shared_ptr<CloneableEnvelopeFollower> envelope;
  36. float amount;
  37. bool useSidechainInput;
  38. EnvelopeWrapper() : envelope(new CloneableEnvelopeFollower()), amount(0), useSidechainInput(false) { }
  39. EnvelopeWrapper* clone() const {
  40. return new EnvelopeWrapper(*this);
  41. }
  42. private:
  43. EnvelopeWrapper(const EnvelopeWrapper& other) : envelope(other.envelope->clone()), amount(other.amount), useSidechainInput(other.useSidechainInput) {
  44. }
  45. };
  46. struct ModulationSourcesState {
  47. std::vector<std::shared_ptr<CloneableLFO>> lfos;
  48. std::vector<std::shared_ptr<EnvelopeWrapper>> envelopes;
  49. std::vector<std::shared_ptr<WECore::Perlin::PerlinSource>> randomSources;
  50. // Needed for the envelope followers to figure out which buffers to read from
  51. HostConfiguration hostConfig;
  52. std::function<float(int, MODULATION_TYPE)> getModulationValueCallback;
  53. ModulationSourcesState(std::function<float(int, MODULATION_TYPE)> newGetModulationValueCallback) :
  54. getModulationValueCallback(newGetModulationValueCallback) { }
  55. ModulationSourcesState* clone() const {
  56. return new ModulationSourcesState(*this);
  57. }
  58. private:
  59. ModulationSourcesState(const ModulationSourcesState& other) : hostConfig(other.hostConfig), getModulationValueCallback(other.getModulationValueCallback) {
  60. for (std::shared_ptr<CloneableLFO> lfo : other.lfos) {
  61. lfos.emplace_back(lfo->clone());
  62. }
  63. for (std::shared_ptr<EnvelopeWrapper> env : other.envelopes) {
  64. envelopes.emplace_back(env->clone());
  65. }
  66. for (std::shared_ptr<WECore::Perlin::PerlinSource> source : other.randomSources) {
  67. randomSources.emplace_back(source->clone());
  68. }
  69. }
  70. };
  71. struct StateWrapper {
  72. std::shared_ptr<SplitterState> splitterState;
  73. std::shared_ptr<ModulationSourcesState> modulationSourcesState;
  74. // String representation of the operation that was performed to get to this state
  75. juce::String operation;
  76. StateWrapper(HostConfiguration config,
  77. std::function<float(int, MODULATION_TYPE)> getModulationValueCallback,
  78. std::function<void(int)> latencyChangeCallback) :
  79. splitterState(new SplitterState(config, getModulationValueCallback, latencyChangeCallback)),
  80. modulationSourcesState(new ModulationSourcesState(getModulationValueCallback)),
  81. operation("") { }
  82. StateWrapper(std::shared_ptr<SplitterState> newSplitterState,
  83. std::shared_ptr<ModulationSourcesState> newModulationSourcesState,
  84. juce::String newOperation) : splitterState(newSplitterState),
  85. modulationSourcesState(newModulationSourcesState),
  86. operation(newOperation) { }
  87. };
  88. struct StateManager {
  89. std::deque<std::shared_ptr<StateWrapper>> undoHistory;
  90. std::deque<std::shared_ptr<StateWrapper>> redoHistory;
  91. // This mutex must be locked by all mutators before attempting to read or write to or from
  92. // data model. Its purpose is to stop a mutator being called on one thread from changing the
  93. // data model in a way that would crash a mutator being called on another thread.
  94. //
  95. // Recursive because the application code may call something via the mutator forEach methods
  96. // that tries to take the lock on the same thread as the forEach method itself
  97. std::recursive_mutex mutatorsMutex;
  98. // This mutex must be locked by mutators which change the structure of the data model, and
  99. // also by the processors. Its purpose is to stop a mutator being called on one thread from
  100. // changing the data model in a way that would crash a processor being called on another
  101. // thread.
  102. //
  103. // Mutators reading from the data model or writing only primitive values don't need to lock
  104. // this
  105. WECore::AudioSpinMutex sharedMutex;
  106. StateManager(HostConfiguration config,
  107. std::function<float(int, MODULATION_TYPE)> getModulationValueCallback,
  108. std::function<void(int)> latencyChangeCallback) {
  109. undoHistory.push_back(std::make_shared<StateWrapper>(config, getModulationValueCallback, latencyChangeCallback));
  110. }
  111. // TODO remove this once all functions are migrated
  112. SplitterState& getSplitterStateUnsafe() { return *(undoHistory.back()->splitterState); }
  113. std::shared_ptr<ModulationSourcesState> getSourcesStateUnsafe() { return undoHistory.back()->modulationSourcesState; }
  114. };
  115. }