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.

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