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.

797 lines
26KB

  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. std::map<std::string, float> old_values;
  284. for (const auto &i: controls_) {
  285. old_values.insert(std::pair<std::string, float>(i.first, i.second->value()));
  286. }
  287. engine_->allSoundsOff();
  288. initEngine();
  289. LoadSave::initSaveInfo(save_info_);
  290. for (auto i = controls_.begin(); i != controls_.end(); i++) {
  291. if (old_values.count(i->first) && old_values[i->first] != i->second->value()
  292. && i->first != "bypass") {
  293. setValueNotifyHost(i->first, i->second->value());
  294. }
  295. }
  296. pauseProcessing(false);
  297. }
  298. bool SynthBase::loadFromJson(const json& data) {
  299. pauseProcessing(true);
  300. std::map<std::string, float> old_values;
  301. for (const auto &i: controls_) {
  302. old_values.insert(std::pair<std::string, float>(i.first, i.second->value()));
  303. }
  304. engine_->allSoundsOff();
  305. try {
  306. bool result = LoadSave::jsonToState(this, save_info_, data);
  307. for (auto i = controls_.begin(); i != controls_.end(); i++) {
  308. if (old_values.count(i->first) && old_values[i->first] != i->second->value()
  309. && i->first != "bypass") {
  310. setValueNotifyHost(i->first, i->second->value());
  311. }
  312. }
  313. pauseProcessing(false);
  314. return result;
  315. }
  316. catch (const json::exception& e) {
  317. pauseProcessing(false);
  318. throw e;
  319. }
  320. }
  321. bool SynthBase::loadFromFile(File preset, std::string& error) {
  322. if (!preset.exists())
  323. return false;
  324. try {
  325. json parsed_json_state = json::parse(preset.loadFileAsString().toStdString(), nullptr);
  326. if (!loadFromJson(parsed_json_state)) {
  327. error = "Preset was created with a newer version.";
  328. return false;
  329. }
  330. active_file_ = preset;
  331. }
  332. catch (const json::exception& e) {
  333. error = "Preset file is corrupted.";
  334. return false;
  335. }
  336. setPresetName(preset.getFileNameWithoutExtension());
  337. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  338. SynthGuiInterface* gui_interface = getGuiInterface();
  339. if (gui_interface) {
  340. gui_interface->updateFullGui();
  341. gui_interface->notifyFresh();
  342. }
  343. #endif
  344. return true;
  345. }
  346. void SynthBase::renderAudioToFile(File file, float seconds, float bpm, std::vector<int> notes, bool render_images) {
  347. static constexpr int kSampleRate = 44100;
  348. static constexpr int kPreProcessSamples = 44100;
  349. static constexpr int kFadeSamples = 200;
  350. static constexpr int kBufferSize = 64;
  351. static constexpr int kVideoRate = 30;
  352. static constexpr int kImageNumberPlaces = 3;
  353. static constexpr int kImageWidth = 500;
  354. static constexpr int kImageHeight = 250;
  355. static constexpr int kOscilloscopeResolution = 512;
  356. static constexpr float kFadeRatio = 0.3f;
  357. ScopedLock lock(getCriticalSection());
  358. processModulationChanges();
  359. engine_->setSampleRate(kSampleRate);
  360. engine_->setBpm(bpm);
  361. engine_->updateAllModulationSwitches();
  362. double sample_time = 1.0 / getSampleRate();
  363. double current_time = -kPreProcessSamples * sample_time;
  364. for (int samples = 0; samples < kPreProcessSamples; samples += kBufferSize) {
  365. engine_->correctToTime(current_time);
  366. current_time += kBufferSize * sample_time;
  367. engine_->process(kBufferSize);
  368. }
  369. for (int note : notes)
  370. engine_->noteOn(note, 0.7f, 0, 0);
  371. file.deleteFile();
  372. std::unique_ptr<FileOutputStream> file_stream = file.createOutputStream();
  373. WavAudioFormat wav_format;
  374. std::unique_ptr<AudioFormatWriter> writer(wav_format.createWriterFor(file_stream.get(), kSampleRate, 2, 16, {}, 0));
  375. int on_samples = seconds * kSampleRate;
  376. int total_samples = on_samples + seconds * kSampleRate * kFadeRatio;
  377. std::unique_ptr<float[]> left_buffer = std::make_unique<float[]>(kBufferSize);
  378. std::unique_ptr<float[]> right_buffer = std::make_unique<float[]>(kBufferSize);
  379. float* buffers[2] = { left_buffer.get(), right_buffer.get() };
  380. const vital::mono_float* engine_output = (const vital::mono_float*)engine_->output(0)->buffer;
  381. #if JUCE_MODULE_AVAILABLE_juce_graphics
  382. int current_image_index = -1;
  383. PNGImageFormat png;
  384. File images_folder = File::getCurrentWorkingDirectory().getChildFile("images");
  385. if (!images_folder.exists() && render_images)
  386. images_folder.createDirectory();
  387. const vital::poly_float* memory = getOscilloscopeMemory();
  388. #endif
  389. for (int samples = 0; samples < total_samples; samples += kBufferSize) {
  390. engine_->correctToTime(current_time);
  391. current_time += kBufferSize * sample_time;
  392. engine_->process(kBufferSize);
  393. updateMemoryOutput(kBufferSize, engine_->output(0)->buffer);
  394. if (on_samples > samples && on_samples <= samples + kBufferSize) {
  395. for (int note : notes)
  396. engine_->noteOff(note, 0.5f, 0, 0);
  397. }
  398. for (int i = 0; i < kBufferSize; ++i) {
  399. vital::mono_float t = (total_samples - samples) / (1.0f * kFadeSamples);
  400. t = vital::utils::min(t, 1.0f);
  401. left_buffer[i] = t * engine_output[vital::poly_float::kSize * i];
  402. right_buffer[i] = t * engine_output[vital::poly_float::kSize * i + 1];
  403. }
  404. writer->writeFromFloatArrays(buffers, 2, kBufferSize);
  405. #if JUCE_MODULE_AVAILABLE_juce_graphics
  406. int image_index = (samples * kVideoRate) / kSampleRate;
  407. if (image_index > current_image_index && render_images) {
  408. current_image_index = image_index;
  409. String number(image_index);
  410. while (number.length() < kImageNumberPlaces)
  411. number = "0" + number;
  412. File image_file = images_folder.getChildFile("rendered_image" + number + ".png");
  413. FileOutputStream image_file_stream(image_file);
  414. Image image(Image::RGB, kImageWidth, kImageHeight, true);
  415. Graphics g(image);
  416. g.fillAll(Colour(0xff1d2125));
  417. Path left_path;
  418. Path right_path;
  419. left_path.startNewSubPath(-2.0f, kImageHeight / 2);
  420. right_path.startNewSubPath(-2.0f, kImageHeight / 2);
  421. for (int i = 0; i < kOscilloscopeResolution; ++i) {
  422. float t = i / (kOscilloscopeResolution - 1.0f);
  423. float memory_spot = (1.0f * i * vital::kOscilloscopeMemoryResolution) / kOscilloscopeResolution;
  424. int memory_index = memory_spot;
  425. float remainder = memory_spot - memory_index;
  426. vital::poly_float from = memory[memory_index];
  427. vital::poly_float to = memory[memory_index + 1];
  428. vital::poly_float y = -vital::utils::interpolate(from, to, remainder) * kImageHeight / 2.0f + kImageHeight / 2;
  429. left_path.lineTo(t * kImageWidth, y[0]);
  430. right_path.lineTo(t * kImageWidth, y[1]);
  431. }
  432. left_path.lineTo(kImageWidth + 2.0f, kImageHeight / 2.0f);
  433. right_path.lineTo(kImageWidth + 2.0f, kImageHeight / 2.0f);
  434. g.setColour(Colour(0x64aa88ff));
  435. g.fillPath(left_path);
  436. g.fillPath(right_path);
  437. g.setColour(Colour(0xffaa88ff));
  438. g.strokePath(left_path, PathStrokeType(2.0f, PathStrokeType::curved, PathStrokeType::rounded));
  439. g.strokePath(right_path, PathStrokeType(2.0f, PathStrokeType::curved, PathStrokeType::rounded));
  440. png.writeImageToStream(image, image_file_stream);
  441. }
  442. #endif
  443. }
  444. writer->flush();
  445. file_stream->flush();
  446. writer = nullptr;
  447. file_stream.release();
  448. }
  449. void SynthBase::renderAudioForResynthesis(float* data, int samples, int note) {
  450. static constexpr int kPreProcessSamples = 44100;
  451. static constexpr int kBufferSize = 64;
  452. ScopedLock lock(getCriticalSection());
  453. double sample_time = 1.0 / getSampleRate();
  454. double current_time = -kPreProcessSamples * sample_time;
  455. engine_->allSoundsOff();
  456. for (int s = 0; s < kPreProcessSamples; s += kBufferSize) {
  457. engine_->correctToTime(current_time);
  458. current_time += kBufferSize * sample_time;
  459. engine_->process(kBufferSize);
  460. }
  461. engine_->noteOn(note, 0.7f, 0, 0);
  462. const vital::poly_float* engine_output = engine_->output(0)->buffer;
  463. float max_value = 0.01f;
  464. for (int s = 0; s < samples; s += kBufferSize) {
  465. int num_samples = std::min(samples - s, kBufferSize);
  466. engine_->correctToTime(current_time);
  467. current_time += num_samples * sample_time;
  468. engine_->process(num_samples);
  469. for (int i = 0; i < num_samples; ++i) {
  470. float sample = engine_output[i][0];
  471. data[s + i] = sample;
  472. max_value = std::max(max_value, fabsf(sample));
  473. }
  474. }
  475. float scale = 1.0f / max_value;
  476. for (int s = 0; s < samples; ++s)
  477. data[s] *= scale;
  478. engine_->allSoundsOff();
  479. }
  480. bool SynthBase::saveToFile(File preset) {
  481. preset = preset.withFileExtension(String(vital::kPresetExtension));
  482. File parent = preset.getParentDirectory();
  483. if (!parent.exists()) {
  484. if (!parent.createDirectory().wasOk() || !parent.hasWriteAccess())
  485. return false;
  486. }
  487. setPresetName(preset.getFileNameWithoutExtension());
  488. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  489. SynthGuiInterface* gui_interface = getGuiInterface();
  490. if (gui_interface)
  491. gui_interface->notifyFresh();
  492. #endif
  493. if (preset.replaceWithText(saveToJson().dump())) {
  494. active_file_ = preset;
  495. return true;
  496. }
  497. return false;
  498. }
  499. bool SynthBase::saveToActiveFile() {
  500. if (!active_file_.exists() || !active_file_.hasWriteAccess())
  501. return false;
  502. return saveToFile(active_file_);
  503. }
  504. void SynthBase::setMpeEnabled(bool enabled) {
  505. midi_manager_->setMpeEnabled(enabled);
  506. }
  507. void SynthBase::processAudio(AudioSampleBuffer* buffer, int channels, int samples, int offset) {
  508. if (expired_)
  509. return;
  510. engine_->process(samples);
  511. writeAudio(buffer, channels, samples, offset);
  512. }
  513. void SynthBase::processAudioWithInput(AudioSampleBuffer* buffer, const vital::poly_float* input_buffer,
  514. int channels, int samples, int offset) {
  515. if (expired_)
  516. return;
  517. engine_->processWithInput(input_buffer, samples);
  518. writeAudio(buffer, channels, samples, offset);
  519. }
  520. void SynthBase::writeAudio(AudioSampleBuffer* buffer, int channels, int samples, int offset) {
  521. const vital::mono_float* engine_output = (const vital::mono_float*)engine_->output(0)->buffer;
  522. for (int channel = 0; channel < channels; ++channel) {
  523. float* channel_data = buffer->getWritePointer(channel, offset);
  524. for (int i = 0; i < samples; ++i) {
  525. channel_data[i] = engine_output[vital::poly_float::kSize * i + channel];
  526. VITAL_ASSERT(std::isfinite(channel_data[i]));
  527. }
  528. }
  529. updateMemoryOutput(samples, engine_->output(0)->buffer);
  530. }
  531. void SynthBase::processMidi(MidiBuffer& midi_messages, int start_sample, int end_sample) {
  532. bool process_all = end_sample == 0;
  533. for (const MidiMessageMetadata message : midi_messages) {
  534. int midi_sample = message.samplePosition;
  535. if (process_all || (midi_sample >= start_sample && midi_sample < end_sample))
  536. midi_manager_->processMidiMessage(message.getMessage(), midi_sample - start_sample);
  537. }
  538. }
  539. void SynthBase::processKeyboardEvents(MidiBuffer& buffer, int num_samples) {
  540. midi_manager_->replaceKeyboardMessages(buffer, num_samples);
  541. }
  542. void SynthBase::processModulationChanges() {
  543. vital::modulation_change change;
  544. while (getNextModulationChange(change)) {
  545. if (change.disconnecting)
  546. engine_->disconnectModulation(change);
  547. else
  548. engine_->connectModulation(change);
  549. }
  550. }
  551. void SynthBase::updateMemoryOutput(int samples, const vital::poly_float* audio) {
  552. for (int i = 0; i < samples; ++i)
  553. audio_memory_->push(audio[i]);
  554. vital::mono_float last_played = engine_->getLastActiveNote();
  555. last_played = vital::utils::clamp(last_played, kOutputWindowMinNote, kOutputWindowMaxNote);
  556. int num_pressed = engine_->getNumPressedNotes();
  557. int output_inc = std::max<int>(1, engine_->getSampleRate() / vital::kOscilloscopeMemorySampleRate);
  558. int oscilloscope_samples = 2 * vital::kOscilloscopeMemoryResolution;
  559. if (last_played && (last_played_note_ != last_played || num_pressed > last_num_pressed_)) {
  560. last_played_note_ = last_played;
  561. vital::mono_float frequency = vital::utils::midiNoteToFrequency(last_played_note_);
  562. vital::mono_float period = engine_->getSampleRate() / frequency;
  563. int window_length = output_inc * vital::kOscilloscopeMemoryResolution;
  564. memory_reset_period_ = period;
  565. while (memory_reset_period_ < window_length)
  566. memory_reset_period_ += memory_reset_period_;
  567. memory_reset_period_ = std::min(memory_reset_period_, 2.0f * window_length);
  568. memory_index_ = 0;
  569. vital::utils::copyBuffer(oscilloscope_memory_, oscilloscope_memory_write_, oscilloscope_samples);
  570. }
  571. last_num_pressed_ = num_pressed;
  572. for (; memory_input_offset_ < samples; memory_input_offset_ += output_inc) {
  573. int input_index = vital::utils::iclamp(memory_input_offset_, 0, samples);
  574. memory_index_ = vital::utils::iclamp(memory_index_, 0, oscilloscope_samples - 1);
  575. VITAL_ASSERT(input_index >= 0);
  576. VITAL_ASSERT(input_index < samples);
  577. VITAL_ASSERT(memory_index_ >= 0);
  578. VITAL_ASSERT(memory_index_ < oscilloscope_samples);
  579. oscilloscope_memory_write_[memory_index_++] = audio[input_index];
  580. if (memory_index_ * output_inc >= memory_reset_period_) {
  581. memory_input_offset_ += memory_reset_period_ - memory_index_ * output_inc;
  582. memory_index_ = 0;
  583. vital::utils::copyBuffer(oscilloscope_memory_, oscilloscope_memory_write_, oscilloscope_samples);
  584. }
  585. }
  586. memory_input_offset_ -= samples;
  587. }
  588. void SynthBase::setAuthor(const String& author) {
  589. save_info_["author"] = author;
  590. }
  591. void SynthBase::setComments(const String& comments) {
  592. save_info_["comments"] = comments;
  593. }
  594. void SynthBase::setStyle(const String& style) {
  595. save_info_["style"] = style;
  596. }
  597. void SynthBase::setPresetName(const String& preset_name) {
  598. save_info_["preset_name"] = preset_name;
  599. }
  600. void SynthBase::setMacroName(int index, const String& macro_name) {
  601. save_info_["macro" + std::to_string(index + 1)] = macro_name;
  602. }
  603. String SynthBase::getAuthor() {
  604. return save_info_["author"];
  605. }
  606. String SynthBase::getComments() {
  607. return save_info_["comments"];
  608. }
  609. String SynthBase::getStyle() {
  610. return save_info_["style"];
  611. }
  612. String SynthBase::getPresetName() {
  613. return save_info_["preset_name"];
  614. }
  615. String SynthBase::getMacroName(int index) {
  616. String name = save_info_["macro" + std::to_string(index + 1)];
  617. if (name.trim().isEmpty())
  618. return "MACRO " + String(index + 1);
  619. return name;
  620. }
  621. const vital::StereoMemory* SynthBase::getEqualizerMemory() {
  622. if (engine_)
  623. return engine_->getEqualizerMemory();
  624. return nullptr;
  625. }
  626. vital::ModulationConnectionBank& SynthBase::getModulationBank() {
  627. return engine_->getModulationBank();
  628. }
  629. void SynthBase::notifyOversamplingChanged() {
  630. pauseProcessing(true);
  631. engine_->allSoundsOff();
  632. checkOversampling();
  633. pauseProcessing(false);
  634. }
  635. void SynthBase::checkOversampling() {
  636. return engine_->checkOversampling();
  637. }
  638. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  639. void SynthBase::ValueChangedCallback::messageCallback() {
  640. if (auto synth_base = listener.lock()) {
  641. SynthGuiInterface* gui_interface = (*synth_base)->getGuiInterface();
  642. if (gui_interface) {
  643. gui_interface->updateGuiControl(control_name, value);
  644. if (control_name != "pitch_wheel")
  645. gui_interface->notifyChange();
  646. }
  647. }
  648. }
  649. #endif