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.

240 lines
6.5KB

  1. /* Copyright 2013-2019 Matt Tytel
  2. *
  3. * pylon is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * pylon is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with pylon. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "synth_plugin.h"
  17. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  18. #include "synth_editor.h"
  19. #endif
  20. #include "sound_engine.h"
  21. #include "load_save.h"
  22. SynthPlugin::SynthPlugin() {
  23. last_seconds_time_ = 0.0;
  24. int num_params = vital::Parameters::getNumParameters();
  25. for (int i = 0; i < num_params; ++i) {
  26. const vital::ValueDetails* details = vital::Parameters::getDetails(i);
  27. if (controls_.count(details->name) == 0)
  28. continue;
  29. ValueBridge* bridge = new ValueBridge(details->name, controls_[details->name]);
  30. bridge->setListener(this);
  31. bridge_lookup_[details->name] = bridge;
  32. addParameter(bridge);
  33. }
  34. bypass_parameter_ = bridge_lookup_["bypass"];
  35. }
  36. SynthPlugin::~SynthPlugin() {
  37. midi_manager_ = nullptr;
  38. keyboard_state_ = nullptr;
  39. }
  40. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  41. SynthGuiInterface* SynthPlugin::getGuiInterface() {
  42. AudioProcessorEditor* editor = getActiveEditor();
  43. if (editor)
  44. return dynamic_cast<SynthGuiInterface*>(editor);
  45. return nullptr;
  46. }
  47. void SynthPlugin::beginChangeGesture(const std::string& name) {
  48. if (bridge_lookup_.count(name))
  49. bridge_lookup_[name]->beginChangeGesture();
  50. }
  51. void SynthPlugin::endChangeGesture(const std::string& name) {
  52. if (bridge_lookup_.count(name))
  53. bridge_lookup_[name]->endChangeGesture();
  54. }
  55. void SynthPlugin::setValueNotifyHost(const std::string& name, vital::mono_float value) {
  56. if (bridge_lookup_.count(name)) {
  57. vital::mono_float plugin_value = bridge_lookup_[name]->convertToPluginValue(value);
  58. bridge_lookup_[name]->setValueNotifyHost(plugin_value);
  59. }
  60. }
  61. #endif
  62. const CriticalSection& SynthPlugin::getCriticalSection() {
  63. return getCallbackLock();
  64. }
  65. void SynthPlugin::pauseProcessing(bool pause) {
  66. suspendProcessing(pause);
  67. }
  68. const String SynthPlugin::getName() const {
  69. return JucePlugin_Name;
  70. }
  71. const String SynthPlugin::getInputChannelName(int channel_index) const {
  72. return String(channel_index + 1);
  73. }
  74. const String SynthPlugin::getOutputChannelName(int channel_index) const {
  75. return String(channel_index + 1);
  76. }
  77. bool SynthPlugin::isInputChannelStereoPair(int index) const {
  78. return true;
  79. }
  80. bool SynthPlugin::isOutputChannelStereoPair(int index) const {
  81. return true;
  82. }
  83. bool SynthPlugin::acceptsMidi() const {
  84. #if JucePlugin_WantsMidiInput
  85. return true;
  86. #else
  87. return false;
  88. #endif
  89. }
  90. bool SynthPlugin::producesMidi() const {
  91. #if JucePlugin_ProducesMidiOutput
  92. return true;
  93. #else
  94. return false;
  95. #endif
  96. }
  97. bool SynthPlugin::silenceInProducesSilenceOut() const {
  98. return false;
  99. }
  100. double SynthPlugin::getTailLengthSeconds() const {
  101. return 0.0;
  102. }
  103. const String SynthPlugin::getProgramName(int index) {
  104. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  105. SynthGuiInterface* editor = getGuiInterface();
  106. if (editor == nullptr || editor->getSynth() == nullptr)
  107. return "";
  108. return editor->getSynth()->getPresetName();
  109. #else
  110. return "";
  111. #endif
  112. }
  113. void SynthPlugin::prepareToPlay(double sample_rate, int buffer_size) {
  114. engine_->setSampleRate(sample_rate);
  115. engine_->updateAllModulationSwitches();
  116. }
  117. void SynthPlugin::releaseResources() {
  118. }
  119. void SynthPlugin::processBlock(AudioSampleBuffer& buffer, MidiBuffer& midi_messages) {
  120. static constexpr double kSecondsPerMinute = 60.0f;
  121. if (bypass_parameter_->getValue()) {
  122. processBlockBypassed(buffer, midi_messages);
  123. return;
  124. }
  125. int total_samples = buffer.getNumSamples();
  126. int num_channels = getTotalNumOutputChannels();
  127. AudioPlayHead* play_head = getPlayHead();
  128. if (play_head) {
  129. play_head->getCurrentPosition(position_info_);
  130. if (position_info_.bpm)
  131. engine_->setBpm(position_info_.bpm);
  132. if (position_info_.isPlaying) {
  133. double bps = position_info_.bpm / kSecondsPerMinute;
  134. last_seconds_time_ = position_info_.ppqPosition / bps;
  135. }
  136. }
  137. processModulationChanges();
  138. if (total_samples)
  139. processKeyboardEvents(midi_messages, total_samples);
  140. double sample_time = 1.0 / AudioProcessor::getSampleRate();
  141. for (int sample_offset = 0; sample_offset < total_samples;) {
  142. int num_samples = std::min<int>(total_samples - sample_offset, vital::kMaxBufferSize);
  143. engine_->correctToTime(last_seconds_time_);
  144. processMidi(midi_messages, sample_offset, sample_offset + num_samples);
  145. processAudio(&buffer, num_channels, num_samples, sample_offset);
  146. last_seconds_time_ += num_samples * sample_time;
  147. sample_offset += num_samples;
  148. }
  149. }
  150. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  151. bool SynthPlugin::hasEditor() const {
  152. return true;
  153. }
  154. AudioProcessorEditor* SynthPlugin::createEditor() {
  155. return new SynthEditor(*this);
  156. }
  157. #endif
  158. void SynthPlugin::parameterChanged(std::string name, vital::mono_float value) {
  159. valueChangedExternal(name, value);
  160. }
  161. void SynthPlugin::getStateInformation(MemoryBlock& dest_data) {
  162. json data = LoadSave::stateToJson(this, getCallbackLock());
  163. data["tuning"] = getTuning()->stateToJson();
  164. String data_string = data.dump();
  165. MemoryOutputStream stream;
  166. stream.writeString(data_string);
  167. dest_data.append(stream.getData(), stream.getDataSize());
  168. }
  169. void SynthPlugin::setStateInformation(const void* data, int size_in_bytes) {
  170. MemoryInputStream stream(data, size_in_bytes, false);
  171. String data_string = stream.readEntireStreamAsString();
  172. pauseProcessing(true);
  173. try {
  174. json json_data = json::parse(data_string.toStdString());
  175. LoadSave::jsonToState(this, save_info_, json_data);
  176. if (json_data.count("tuning"))
  177. getTuning()->jsonToState(json_data["tuning"]);
  178. }
  179. catch (const json::exception& e) {
  180. std::string error = "There was an error open the preset. Preset file is corrupted.";
  181. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  182. AlertWindow::showNativeDialogBox("Error opening preset", error, false);
  183. #else
  184. std::cerr << error << std::endl;
  185. #endif
  186. }
  187. pauseProcessing(false);
  188. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  189. SynthGuiInterface* editor = getGuiInterface();
  190. if (editor)
  191. editor->updateFullGui();
  192. #endif
  193. }
  194. AudioProcessor* JUCE_CALLTYPE createPluginFilter() {
  195. return new SynthPlugin();
  196. }