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.

769 lines
25KB

  1. /* Copyright 2013-2019 Matt Tytel
  2. *
  3. * vital 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. * vital 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 vital. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "synth_base.h"
  17. #include "sample_source.h"
  18. #include "sound_engine.h"
  19. #include "load_save.h"
  20. #include "memory.h"
  21. #include "modulation_connection_processor.h"
  22. #include "startup.h"
  23. #include "synth_gui_interface.h"
  24. #include "synth_parameters.h"
  25. #include "utils.h"
  26. SynthBase::SynthBase() : expired_(false) {
  27. expired_ = LoadSave::isExpired();
  28. self_reference_ = std::make_shared<SynthBase*>();
  29. *self_reference_ = this;
  30. engine_ = std::make_unique<vital::SoundEngine>();
  31. engine_->setTuning(&tuning_);
  32. mod_connections_.reserve(vital::kMaxModulationConnections);
  33. for (int i = 0; i < vital::kNumOscillators; ++i) {
  34. vital::Wavetable* wavetable = engine_->getWavetable(i);
  35. if (wavetable) {
  36. wavetable_creators_[i] = std::make_unique<WavetableCreator>(wavetable);
  37. wavetable_creators_[i]->init();
  38. }
  39. }
  40. keyboard_state_ = std::make_unique<MidiKeyboardState>();
  41. midi_manager_ = std::make_unique<MidiManager>(this, keyboard_state_.get(), &save_info_, this);
  42. last_played_note_ = 0.0f;
  43. last_num_pressed_ = 0;
  44. audio_memory_ = std::make_unique<vital::StereoMemory>(vital::kAudioMemorySamples);
  45. memset(oscilloscope_memory_, 0, 2 * vital::kOscilloscopeMemoryResolution * sizeof(vital::poly_float));
  46. memset(oscilloscope_memory_write_, 0, 2 * vital::kOscilloscopeMemoryResolution * sizeof(vital::poly_float));
  47. memory_reset_period_ = vital::kOscilloscopeMemoryResolution;
  48. memory_input_offset_ = 0;
  49. memory_index_ = 0;
  50. controls_ = engine_->getControls();
  51. Startup::doStartupChecks();
  52. }
  53. SynthBase::~SynthBase() { }
  54. void SynthBase::valueChanged(const std::string& name, vital::mono_float value) {
  55. controls_[name]->set(value);
  56. }
  57. void SynthBase::valueChangedInternal(const std::string& name, vital::mono_float value) {
  58. valueChanged(name, value);
  59. setValueNotifyHost(name, value);
  60. }
  61. void SynthBase::valueChangedThroughMidi(const std::string& name, vital::mono_float value) {
  62. controls_[name]->set(value);
  63. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  64. ValueChangedCallback* callback = new ValueChangedCallback(self_reference_, name, value);
  65. setValueNotifyHost(name, value);
  66. callback->post();
  67. #endif
  68. }
  69. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  70. void SynthBase::pitchWheelMidiChanged(vital::mono_float value) {
  71. ValueChangedCallback* callback = new ValueChangedCallback(self_reference_, "pitch_wheel", value);
  72. callback->post();
  73. }
  74. void SynthBase::modWheelMidiChanged(vital::mono_float value) {
  75. ValueChangedCallback* callback = new ValueChangedCallback(self_reference_, "mod_wheel", value);
  76. callback->post();
  77. }
  78. #endif
  79. void SynthBase::pitchWheelGuiChanged(vital::mono_float value) {
  80. engine_->setZonedPitchWheel(value, 0, vital::kNumMidiChannels - 1);
  81. }
  82. void SynthBase::modWheelGuiChanged(vital::mono_float value) {
  83. engine_->setModWheelAllChannels(value);
  84. }
  85. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  86. void SynthBase::presetChangedThroughMidi(File preset) {
  87. SynthGuiInterface* gui_interface = getGuiInterface();
  88. if (gui_interface) {
  89. gui_interface->updateFullGui();
  90. gui_interface->notifyFresh();
  91. }
  92. }
  93. #endif
  94. void SynthBase::valueChangedExternal(const std::string& name, vital::mono_float value) {
  95. valueChanged(name, value);
  96. if (name == "mod_wheel")
  97. engine_->setModWheelAllChannels(value);
  98. else if (name == "pitch_wheel")
  99. engine_->setZonedPitchWheel(value, 0, vital::kNumMidiChannels - 1);
  100. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  101. ValueChangedCallback* callback = new ValueChangedCallback(self_reference_, name, value);
  102. callback->post();
  103. #endif
  104. }
  105. vital::ModulationConnection* SynthBase::getConnection(const std::string& source, const std::string& destination) {
  106. for (vital::ModulationConnection* connection : mod_connections_) {
  107. if (connection->source_name == source && connection->destination_name == destination)
  108. return connection;
  109. }
  110. return nullptr;
  111. }
  112. int SynthBase::getConnectionIndex(const std::string& source, const std::string& destination) {
  113. vital::ModulationConnectionBank& modulation_bank = getModulationBank();
  114. for (int i = 0; i < vital::kMaxModulationConnections; ++i) {
  115. vital::ModulationConnection* connection = modulation_bank.atIndex(i);
  116. if (connection->source_name == source && connection->destination_name == destination)
  117. return i;
  118. }
  119. return -1;
  120. }
  121. vital::modulation_change SynthBase::createModulationChange(vital::ModulationConnection* connection) {
  122. vital::modulation_change change;
  123. change.source = engine_->getModulationSource(connection->source_name);
  124. change.mono_destination = engine_->getMonoModulationDestination(connection->destination_name);
  125. change.mono_modulation_switch = engine_->getMonoModulationSwitch(connection->destination_name);
  126. VITAL_ASSERT(change.source != nullptr);
  127. VITAL_ASSERT(change.mono_destination != nullptr);
  128. VITAL_ASSERT(change.mono_modulation_switch != nullptr);
  129. change.destination_scale = vital::Parameters::getParameterRange(connection->destination_name);
  130. change.poly_modulation_switch = engine_->getPolyModulationSwitch(connection->destination_name);
  131. change.poly_destination = engine_->getPolyModulationDestination(connection->destination_name);
  132. change.modulation_processor = connection->modulation_processor.get();
  133. int num_audio_rate = 0;
  134. vital::ModulationConnectionBank& modulation_bank = getModulationBank();
  135. for (int i = 0; i < vital::kMaxModulationConnections; ++i) {
  136. if (modulation_bank.atIndex(i)->source_name == connection->source_name &&
  137. modulation_bank.atIndex(i)->destination_name != connection->destination_name &&
  138. !modulation_bank.atIndex(i)->modulation_processor->isControlRate()) {
  139. num_audio_rate++;
  140. }
  141. }
  142. change.num_audio_rate = num_audio_rate;
  143. return change;
  144. }
  145. bool SynthBase::isInvalidConnection(const vital::modulation_change& change) {
  146. return change.poly_destination && change.poly_destination->router() == change.modulation_processor;
  147. }
  148. void SynthBase::connectModulation(vital::ModulationConnection* connection) {
  149. vital::modulation_change change = createModulationChange(connection);
  150. if (isInvalidConnection(change)) {
  151. connection->destination_name = "";
  152. connection->source_name = "";
  153. }
  154. else if (mod_connections_.count(connection) == 0) {
  155. change.disconnecting = false;
  156. mod_connections_.push_back(connection);
  157. modulation_change_queue_.enqueue(change);
  158. }
  159. }
  160. bool SynthBase::connectModulation(const std::string& source, const std::string& destination) {
  161. vital::ModulationConnection* connection = getConnection(source, destination);
  162. bool create = connection == nullptr;
  163. if (create)
  164. connection = getModulationBank().createConnection(source, destination);
  165. if (connection)
  166. connectModulation(connection);
  167. return create;
  168. }
  169. void SynthBase::disconnectModulation(vital::ModulationConnection* connection) {
  170. if (mod_connections_.count(connection) == 0)
  171. return;
  172. vital::modulation_change change = createModulationChange(connection);
  173. connection->source_name = "";
  174. connection->destination_name = "";
  175. mod_connections_.remove(connection);
  176. change.disconnecting = true;
  177. modulation_change_queue_.enqueue(change);
  178. }
  179. void SynthBase::disconnectModulation(const std::string& source, const std::string& destination) {
  180. vital::ModulationConnection* connection = getConnection(source, destination);
  181. if (connection)
  182. disconnectModulation(connection);
  183. }
  184. void SynthBase::clearModulations() {
  185. clearModulationQueue();
  186. while (mod_connections_.size()) {
  187. vital::ModulationConnection* connection = *mod_connections_.begin();
  188. mod_connections_.remove(connection);
  189. vital::modulation_change change = createModulationChange(connection);
  190. change.disconnecting = true;
  191. engine_->disconnectModulation(change);
  192. connection->source_name = "";
  193. connection->destination_name = "";
  194. }
  195. int num_connections = static_cast<int>(getModulationBank().numConnections());
  196. for (int i = 0; i < num_connections; ++i)
  197. getModulationBank().atIndex(i)->modulation_processor->lineMapGenerator()->initLinear();
  198. engine_->disableUnnecessaryModSources();
  199. }
  200. void SynthBase::forceShowModulation(const std::string& source, bool force) {
  201. if (force)
  202. engine_->enableModSource(source);
  203. else if (!isSourceConnected(source))
  204. engine_->disableModSource(source);
  205. }
  206. bool SynthBase::isModSourceEnabled(const std::string& source) {
  207. return engine_->isModSourceEnabled(source);
  208. }
  209. int SynthBase::getNumModulations(const std::string& destination) {
  210. int connections = 0;
  211. for (vital::ModulationConnection* connection : mod_connections_) {
  212. if (connection->destination_name == destination)
  213. connections++;
  214. }
  215. return connections;
  216. }
  217. std::vector<vital::ModulationConnection*> SynthBase::getSourceConnections(const std::string& source) {
  218. std::vector<vital::ModulationConnection*> connections;
  219. for (vital::ModulationConnection* connection : mod_connections_) {
  220. if (connection->source_name == source)
  221. connections.push_back(connection);
  222. }
  223. return connections;
  224. }
  225. bool SynthBase::isSourceConnected(const std::string& source) {
  226. for (vital::ModulationConnection* connection : mod_connections_) {
  227. if (connection->source_name == source)
  228. return true;
  229. }
  230. return false;
  231. }
  232. std::vector<vital::ModulationConnection*> SynthBase::getDestinationConnections(const std::string& destination) {
  233. std::vector<vital::ModulationConnection*> connections;
  234. for (vital::ModulationConnection* connection : mod_connections_) {
  235. if (connection->destination_name == destination)
  236. connections.push_back(connection);
  237. }
  238. return connections;
  239. }
  240. const vital::StatusOutput* SynthBase::getStatusOutput(const std::string& name) {
  241. return engine_->getStatusOutput(name);
  242. }
  243. vital::Wavetable* SynthBase::getWavetable(int index) {
  244. return engine_->getWavetable(index);
  245. }
  246. WavetableCreator* SynthBase::getWavetableCreator(int index) {
  247. return wavetable_creators_[index].get();
  248. }
  249. vital::Sample* SynthBase::getSample() {
  250. return engine_->getSample();
  251. }
  252. LineGenerator* SynthBase::getLfoSource(int index) {
  253. return engine_->getLfoSource(index);
  254. }
  255. json SynthBase::saveToJson() {
  256. return LoadSave::stateToJson(this, getCriticalSection());
  257. }
  258. int SynthBase::getSampleRate() {
  259. return engine_->getSampleRate();
  260. }
  261. void SynthBase::initEngine() {
  262. clearModulations();
  263. if (getWavetableCreator(0)) {
  264. for (int i = 0; i < vital::kNumOscillators; ++i)
  265. getWavetableCreator(i)->init();
  266. engine_->getSample()->init();
  267. }
  268. for (int i = 0; i < vital::kNumLfos; ++i)
  269. getLfoSource(i)->initTriangle();
  270. vital::control_map controls = engine_->getControls();
  271. for (auto& control : controls) {
  272. vital::ValueDetails details = vital::Parameters::getDetails(control.first);
  273. control.second->set(details.default_value);
  274. }
  275. checkOversampling();
  276. clearActiveFile();
  277. }
  278. void SynthBase::loadTuningFile(const File& file) {
  279. tuning_.loadFile(file);
  280. }
  281. void SynthBase::loadInitPreset() {
  282. pauseProcessing(true);
  283. engine_->allSoundsOff();
  284. initEngine();
  285. LoadSave::initSaveInfo(save_info_);
  286. pauseProcessing(false);
  287. }
  288. bool SynthBase::loadFromJson(const json& data) {
  289. pauseProcessing(true);
  290. engine_->allSoundsOff();
  291. try {
  292. bool result = LoadSave::jsonToState(this, save_info_, data);
  293. pauseProcessing(false);
  294. return result;
  295. }
  296. catch (const json::exception& e) {
  297. pauseProcessing(false);
  298. throw e;
  299. }
  300. }
  301. bool SynthBase::loadFromFile(File preset, std::string& error) {
  302. if (!preset.exists())
  303. return false;
  304. try {
  305. json parsed_json_state = json::parse(preset.loadFileAsString().toStdString(), nullptr);
  306. if (!loadFromJson(parsed_json_state)) {
  307. error = "Preset was created with a newer version.";
  308. return false;
  309. }
  310. active_file_ = preset;
  311. }
  312. catch (const json::exception& e) {
  313. error = "Preset file is corrupted.";
  314. return false;
  315. }
  316. setPresetName(preset.getFileNameWithoutExtension());
  317. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  318. SynthGuiInterface* gui_interface = getGuiInterface();
  319. if (gui_interface) {
  320. gui_interface->updateFullGui();
  321. gui_interface->notifyFresh();
  322. }
  323. #endif
  324. return true;
  325. }
  326. void SynthBase::renderAudioToFile(File file, float seconds, float bpm, std::vector<int> notes, bool render_images) {
  327. static constexpr int kSampleRate = 44100;
  328. static constexpr int kPreProcessSamples = 44100;
  329. static constexpr int kFadeSamples = 200;
  330. static constexpr int kBufferSize = 64;
  331. static constexpr int kVideoRate = 30;
  332. static constexpr int kImageNumberPlaces = 3;
  333. static constexpr int kImageWidth = 500;
  334. static constexpr int kImageHeight = 250;
  335. static constexpr int kOscilloscopeResolution = 512;
  336. static constexpr float kFadeRatio = 0.3f;
  337. ScopedLock lock(getCriticalSection());
  338. processModulationChanges();
  339. engine_->setSampleRate(kSampleRate);
  340. engine_->setBpm(bpm);
  341. engine_->updateAllModulationSwitches();
  342. double sample_time = 1.0 / getSampleRate();
  343. double current_time = -kPreProcessSamples * sample_time;
  344. for (int samples = 0; samples < kPreProcessSamples; samples += kBufferSize) {
  345. engine_->correctToTime(current_time);
  346. current_time += kBufferSize * sample_time;
  347. engine_->process(kBufferSize);
  348. }
  349. for (int note : notes)
  350. engine_->noteOn(note, 0.7f, 0, 0);
  351. file.deleteFile();
  352. std::unique_ptr<FileOutputStream> file_stream = file.createOutputStream();
  353. WavAudioFormat wav_format;
  354. std::unique_ptr<AudioFormatWriter> writer(wav_format.createWriterFor(file_stream.get(), kSampleRate, 2, 16, {}, 0));
  355. int on_samples = seconds * kSampleRate;
  356. int total_samples = on_samples + seconds * kSampleRate * kFadeRatio;
  357. std::unique_ptr<float[]> left_buffer = std::make_unique<float[]>(kBufferSize);
  358. std::unique_ptr<float[]> right_buffer = std::make_unique<float[]>(kBufferSize);
  359. float* buffers[2] = { left_buffer.get(), right_buffer.get() };
  360. const vital::mono_float* engine_output = (const vital::mono_float*)engine_->output(0)->buffer;
  361. #if JUCE_MODULE_AVAILABLE_juce_graphics
  362. int current_image_index = -1;
  363. PNGImageFormat png;
  364. File images_folder = File::getCurrentWorkingDirectory().getChildFile("images");
  365. if (!images_folder.exists() && render_images)
  366. images_folder.createDirectory();
  367. const vital::poly_float* memory = getOscilloscopeMemory();
  368. #endif
  369. for (int samples = 0; samples < total_samples; samples += kBufferSize) {
  370. engine_->correctToTime(current_time);
  371. current_time += kBufferSize * sample_time;
  372. engine_->process(kBufferSize);
  373. updateMemoryOutput(kBufferSize, engine_->output(0)->buffer);
  374. if (on_samples > samples && on_samples <= samples + kBufferSize) {
  375. for (int note : notes)
  376. engine_->noteOff(note, 0.5f, 0, 0);
  377. }
  378. for (int i = 0; i < kBufferSize; ++i) {
  379. vital::mono_float t = (total_samples - samples) / (1.0f * kFadeSamples);
  380. t = vital::utils::min(t, 1.0f);
  381. left_buffer[i] = t * engine_output[vital::poly_float::kSize * i];
  382. right_buffer[i] = t * engine_output[vital::poly_float::kSize * i + 1];
  383. }
  384. writer->writeFromFloatArrays(buffers, 2, kBufferSize);
  385. #if JUCE_MODULE_AVAILABLE_juce_graphics
  386. int image_index = (samples * kVideoRate) / kSampleRate;
  387. if (image_index > current_image_index && render_images) {
  388. current_image_index = image_index;
  389. String number(image_index);
  390. while (number.length() < kImageNumberPlaces)
  391. number = "0" + number;
  392. File image_file = images_folder.getChildFile("rendered_image" + number + ".png");
  393. FileOutputStream image_file_stream(image_file);
  394. Image image(Image::RGB, kImageWidth, kImageHeight, true);
  395. Graphics g(image);
  396. g.fillAll(Colour(0xff1d2125));
  397. Path left_path;
  398. Path right_path;
  399. left_path.startNewSubPath(-2.0f, kImageHeight / 2);
  400. right_path.startNewSubPath(-2.0f, kImageHeight / 2);
  401. for (int i = 0; i < kOscilloscopeResolution; ++i) {
  402. float t = i / (kOscilloscopeResolution - 1.0f);
  403. float memory_spot = (1.0f * i * vital::kOscilloscopeMemoryResolution) / kOscilloscopeResolution;
  404. int memory_index = memory_spot;
  405. float remainder = memory_spot - memory_index;
  406. vital::poly_float from = memory[memory_index];
  407. vital::poly_float to = memory[memory_index + 1];
  408. vital::poly_float y = -vital::utils::interpolate(from, to, remainder) * kImageHeight / 2.0f + kImageHeight / 2;
  409. left_path.lineTo(t * kImageWidth, y[0]);
  410. right_path.lineTo(t * kImageWidth, y[1]);
  411. }
  412. left_path.lineTo(kImageWidth + 2.0f, kImageHeight / 2.0f);
  413. right_path.lineTo(kImageWidth + 2.0f, kImageHeight / 2.0f);
  414. g.setColour(Colour(0x64aa88ff));
  415. g.fillPath(left_path);
  416. g.fillPath(right_path);
  417. g.setColour(Colour(0xffaa88ff));
  418. g.strokePath(left_path, PathStrokeType(2.0f, PathStrokeType::curved, PathStrokeType::rounded));
  419. g.strokePath(right_path, PathStrokeType(2.0f, PathStrokeType::curved, PathStrokeType::rounded));
  420. png.writeImageToStream(image, image_file_stream);
  421. }
  422. #endif
  423. }
  424. writer->flush();
  425. file_stream->flush();
  426. writer = nullptr;
  427. file_stream.release();
  428. }
  429. void SynthBase::renderAudioForResynthesis(float* data, int samples, int note) {
  430. static constexpr int kPreProcessSamples = 44100;
  431. static constexpr int kBufferSize = 64;
  432. ScopedLock lock(getCriticalSection());
  433. double sample_time = 1.0 / getSampleRate();
  434. double current_time = -kPreProcessSamples * sample_time;
  435. engine_->allSoundsOff();
  436. for (int s = 0; s < kPreProcessSamples; s += kBufferSize) {
  437. engine_->correctToTime(current_time);
  438. current_time += kBufferSize * sample_time;
  439. engine_->process(kBufferSize);
  440. }
  441. engine_->noteOn(note, 0.7f, 0, 0);
  442. const vital::poly_float* engine_output = engine_->output(0)->buffer;
  443. float max_value = 0.01f;
  444. for (int s = 0; s < samples; s += kBufferSize) {
  445. int num_samples = std::min(samples - s, kBufferSize);
  446. engine_->correctToTime(current_time);
  447. current_time += num_samples * sample_time;
  448. engine_->process(num_samples);
  449. for (int i = 0; i < num_samples; ++i) {
  450. float sample = engine_output[i][0];
  451. data[s + i] = sample;
  452. max_value = std::max(max_value, fabsf(sample));
  453. }
  454. }
  455. float scale = 1.0f / max_value;
  456. for (int s = 0; s < samples; ++s)
  457. data[s] *= scale;
  458. engine_->allSoundsOff();
  459. }
  460. bool SynthBase::saveToFile(File preset) {
  461. preset = preset.withFileExtension(String(vital::kPresetExtension));
  462. File parent = preset.getParentDirectory();
  463. if (!parent.exists()) {
  464. if (!parent.createDirectory().wasOk() || !parent.hasWriteAccess())
  465. return false;
  466. }
  467. setPresetName(preset.getFileNameWithoutExtension());
  468. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  469. SynthGuiInterface* gui_interface = getGuiInterface();
  470. if (gui_interface)
  471. gui_interface->notifyFresh();
  472. #endif
  473. if (preset.replaceWithText(saveToJson().dump())) {
  474. active_file_ = preset;
  475. return true;
  476. }
  477. return false;
  478. }
  479. bool SynthBase::saveToActiveFile() {
  480. if (!active_file_.exists() || !active_file_.hasWriteAccess())
  481. return false;
  482. return saveToFile(active_file_);
  483. }
  484. void SynthBase::setMpeEnabled(bool enabled) {
  485. midi_manager_->setMpeEnabled(enabled);
  486. }
  487. void SynthBase::processAudio(AudioSampleBuffer* buffer, int channels, int samples, int offset) {
  488. if (expired_)
  489. return;
  490. engine_->process(samples);
  491. writeAudio(buffer, channels, samples, offset);
  492. }
  493. void SynthBase::processAudioWithInput(AudioSampleBuffer* buffer, const vital::poly_float* input_buffer,
  494. int channels, int samples, int offset) {
  495. if (expired_)
  496. return;
  497. engine_->processWithInput(input_buffer, samples);
  498. writeAudio(buffer, channels, samples, offset);
  499. }
  500. void SynthBase::writeAudio(AudioSampleBuffer* buffer, int channels, int samples, int offset) {
  501. const vital::mono_float* engine_output = (const vital::mono_float*)engine_->output(0)->buffer;
  502. for (int channel = 0; channel < channels; ++channel) {
  503. float* channel_data = buffer->getWritePointer(channel, offset);
  504. for (int i = 0; i < samples; ++i) {
  505. channel_data[i] = engine_output[vital::poly_float::kSize * i + channel];
  506. VITAL_ASSERT(std::isfinite(channel_data[i]));
  507. }
  508. }
  509. updateMemoryOutput(samples, engine_->output(0)->buffer);
  510. }
  511. void SynthBase::processMidi(MidiBuffer& midi_messages, int start_sample, int end_sample) {
  512. bool process_all = end_sample == 0;
  513. for (const MidiMessageMetadata message : midi_messages) {
  514. int midi_sample = message.samplePosition;
  515. if (process_all || (midi_sample >= start_sample && midi_sample < end_sample))
  516. midi_manager_->processMidiMessage(message.getMessage(), midi_sample - start_sample);
  517. }
  518. }
  519. void SynthBase::processKeyboardEvents(MidiBuffer& buffer, int num_samples) {
  520. midi_manager_->replaceKeyboardMessages(buffer, num_samples);
  521. }
  522. void SynthBase::processModulationChanges() {
  523. vital::modulation_change change;
  524. while (getNextModulationChange(change)) {
  525. if (change.disconnecting)
  526. engine_->disconnectModulation(change);
  527. else
  528. engine_->connectModulation(change);
  529. }
  530. }
  531. void SynthBase::updateMemoryOutput(int samples, const vital::poly_float* audio) {
  532. for (int i = 0; i < samples; ++i)
  533. audio_memory_->push(audio[i]);
  534. vital::mono_float last_played = engine_->getLastActiveNote();
  535. last_played = vital::utils::clamp(last_played, kOutputWindowMinNote, kOutputWindowMaxNote);
  536. int num_pressed = engine_->getNumPressedNotes();
  537. int output_inc = std::max<int>(1, engine_->getSampleRate() / vital::kOscilloscopeMemorySampleRate);
  538. int oscilloscope_samples = 2 * vital::kOscilloscopeMemoryResolution;
  539. if (last_played && (last_played_note_ != last_played || num_pressed > last_num_pressed_)) {
  540. last_played_note_ = last_played;
  541. vital::mono_float frequency = vital::utils::midiNoteToFrequency(last_played_note_);
  542. vital::mono_float period = engine_->getSampleRate() / frequency;
  543. int window_length = output_inc * vital::kOscilloscopeMemoryResolution;
  544. memory_reset_period_ = period;
  545. while (memory_reset_period_ < window_length)
  546. memory_reset_period_ += memory_reset_period_;
  547. memory_reset_period_ = std::min(memory_reset_period_, 2.0f * window_length);
  548. memory_index_ = 0;
  549. vital::utils::copyBuffer(oscilloscope_memory_, oscilloscope_memory_write_, oscilloscope_samples);
  550. }
  551. last_num_pressed_ = num_pressed;
  552. for (; memory_input_offset_ < samples; memory_input_offset_ += output_inc) {
  553. int input_index = vital::utils::iclamp(memory_input_offset_, 0, samples);
  554. memory_index_ = vital::utils::iclamp(memory_index_, 0, oscilloscope_samples - 1);
  555. VITAL_ASSERT(input_index >= 0);
  556. VITAL_ASSERT(input_index < samples);
  557. VITAL_ASSERT(memory_index_ >= 0);
  558. VITAL_ASSERT(memory_index_ < oscilloscope_samples);
  559. oscilloscope_memory_write_[memory_index_++] = audio[input_index];
  560. if (memory_index_ * output_inc >= memory_reset_period_) {
  561. memory_input_offset_ += memory_reset_period_ - memory_index_ * output_inc;
  562. memory_index_ = 0;
  563. vital::utils::copyBuffer(oscilloscope_memory_, oscilloscope_memory_write_, oscilloscope_samples);
  564. }
  565. }
  566. memory_input_offset_ -= samples;
  567. }
  568. void SynthBase::setAuthor(const String& author) {
  569. save_info_["author"] = author;
  570. }
  571. void SynthBase::setComments(const String& comments) {
  572. save_info_["comments"] = comments;
  573. }
  574. void SynthBase::setStyle(const String& style) {
  575. save_info_["style"] = style;
  576. }
  577. void SynthBase::setPresetName(const String& preset_name) {
  578. save_info_["preset_name"] = preset_name;
  579. }
  580. void SynthBase::setMacroName(int index, const String& macro_name) {
  581. save_info_["macro" + std::to_string(index + 1)] = macro_name;
  582. }
  583. String SynthBase::getAuthor() {
  584. return save_info_["author"];
  585. }
  586. String SynthBase::getComments() {
  587. return save_info_["comments"];
  588. }
  589. String SynthBase::getStyle() {
  590. return save_info_["style"];
  591. }
  592. String SynthBase::getPresetName() {
  593. return save_info_["preset_name"];
  594. }
  595. String SynthBase::getMacroName(int index) {
  596. String name = save_info_["macro" + std::to_string(index + 1)];
  597. if (name.trim().isEmpty())
  598. return "MACRO " + String(index + 1);
  599. return name;
  600. }
  601. const vital::StereoMemory* SynthBase::getEqualizerMemory() {
  602. if (engine_)
  603. return engine_->getEqualizerMemory();
  604. return nullptr;
  605. }
  606. vital::ModulationConnectionBank& SynthBase::getModulationBank() {
  607. return engine_->getModulationBank();
  608. }
  609. void SynthBase::notifyOversamplingChanged() {
  610. pauseProcessing(true);
  611. engine_->allSoundsOff();
  612. checkOversampling();
  613. pauseProcessing(false);
  614. }
  615. void SynthBase::checkOversampling() {
  616. return engine_->checkOversampling();
  617. }
  618. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  619. void SynthBase::ValueChangedCallback::messageCallback() {
  620. if (auto synth_base = listener.lock()) {
  621. SynthGuiInterface* gui_interface = (*synth_base)->getGuiInterface();
  622. if (gui_interface) {
  623. gui_interface->updateGuiControl(control_name, value);
  624. if (control_name != "pitch_wheel")
  625. gui_interface->notifyChange();
  626. }
  627. }
  628. }
  629. #endif