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.

1095 lines
38KB

  1. /*
  2. Copyright (C) 2017 Xenakios
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of version 3 of the GNU General Public License
  5. as published by the Free Software Foundation.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License (version 3) for more details.
  10. www.gnu.org/licenses
  11. */
  12. #include "PluginProcessor.h"
  13. #include "PluginEditor.h"
  14. #include <set>
  15. #include <thread>
  16. #ifdef WIN32
  17. #undef min
  18. #undef max
  19. #endif
  20. int get_optimized_updown(int n, bool up) {
  21. int orig_n = n;
  22. while (true) {
  23. n = orig_n;
  24. while (!(n % 11)) n /= 11;
  25. while (!(n % 7)) n /= 7;
  26. while (!(n % 5)) n /= 5;
  27. while (!(n % 3)) n /= 3;
  28. while (!(n % 2)) n /= 2;
  29. if (n<2) break;
  30. if (up) orig_n++;
  31. else orig_n--;
  32. if (orig_n<4) return 4;
  33. };
  34. return orig_n;
  35. };
  36. int optimizebufsize(int n) {
  37. int n1 = get_optimized_updown(n, false);
  38. int n2 = get_optimized_updown(n, true);
  39. if ((n - n1)<(n2 - n)) return n1;
  40. else return n2;
  41. };
  42. inline AudioParameterFloat* make_floatpar(String id, String name, float minv, float maxv, float defv, float step, float skew)
  43. {
  44. return new AudioParameterFloat(id, name, NormalisableRange<float>(minv, maxv, step, skew), defv);
  45. }
  46. //==============================================================================
  47. PaulstretchpluginAudioProcessor::PaulstretchpluginAudioProcessor()
  48. : m_bufferingthread("pspluginprebufferthread")
  49. {
  50. m_filechoose_callback = [this](const FileChooser& chooser)
  51. {
  52. File resu = chooser.getResult();
  53. String pathname = resu.getFullPathName();
  54. if (pathname.startsWith("/localhost"))
  55. {
  56. pathname = pathname.substring(10);
  57. resu = File(pathname);
  58. }
  59. m_propsfile->m_props_file->setValue("importfilefolder", resu.getParentDirectory().getFullPathName());
  60. String loaderr = setAudioFile(resu);
  61. if (auto ed = dynamic_cast<PaulstretchpluginAudioProcessorEditor*>(getActiveEditor()); ed != nullptr)
  62. {
  63. ed->m_last_err = loaderr;
  64. }
  65. };
  66. m_playposinfo.timeInSeconds = 0.0;
  67. m_free_filter_envelope = std::make_shared<breakpoint_envelope>();
  68. m_free_filter_envelope->SetName("Free filter");
  69. m_free_filter_envelope->AddNode({ 0.0,0.75 });
  70. m_free_filter_envelope->AddNode({ 1.0,0.75 });
  71. m_free_filter_envelope->set_reset_nodes(m_free_filter_envelope->get_all_nodes());
  72. m_recbuffer.setSize(2, 44100);
  73. m_recbuffer.clear();
  74. if (m_afm->getNumKnownFormats()==0)
  75. m_afm->registerBasicFormats();
  76. m_thumb = std::make_unique<AudioThumbnail>(512, *m_afm, *m_thumbcache);
  77. m_sm_enab_pars[0] = new AudioParameterBool("enab_specmodule0", "Enable harmonics", false);
  78. m_sm_enab_pars[1] = new AudioParameterBool("enab_specmodule1", "Enable tonal vs noise", false);
  79. m_sm_enab_pars[2] = new AudioParameterBool("enab_specmodule2", "Enable frequency shift", true);
  80. m_sm_enab_pars[3] = new AudioParameterBool("enab_specmodule3", "Enable pitch shift", true);
  81. m_sm_enab_pars[4] = new AudioParameterBool("enab_specmodule4", "Enable ratios", false);
  82. m_sm_enab_pars[5] = new AudioParameterBool("enab_specmodule5", "Enable spread", false);
  83. m_sm_enab_pars[6] = new AudioParameterBool("enab_specmodule6", "Enable filter", true);
  84. m_sm_enab_pars[7] = new AudioParameterBool("enab_specmodule7", "Enable free filter", true);
  85. m_sm_enab_pars[8] = new AudioParameterBool("enab_specmodule8", "Enable compressor", false);
  86. m_stretch_source = std::make_unique<StretchAudioSource>(2, m_afm,m_sm_enab_pars);
  87. m_stretch_source->setOnsetDetection(0.0);
  88. m_stretch_source->setLoopingEnabled(true);
  89. m_stretch_source->setFFTWindowingType(1);
  90. addParameter(make_floatpar("mainvolume0", "Main volume", -24.0, 12.0, -3.0, 0.1, 1.0));
  91. addParameter(make_floatpar("stretchamount0", "Stretch amount", 0.1, 1024.0, 2.0, 0.1, 0.25));
  92. addParameter(make_floatpar("fftsize0", "FFT size", 0.0, 1.0, 0.7, 0.01, 1.0));
  93. addParameter(make_floatpar("pitchshift0", "Pitch shift", -24.0f, 24.0f, 0.0f, 0.1,1.0)); // 3
  94. addParameter(make_floatpar("freqshift0", "Frequency shift", -1000.0f, 1000.0f, 0.0f, 1.0, 1.0)); // 4
  95. addParameter(make_floatpar("playrange_start0", "Sound start", 0.0f, 1.0f, 0.0f, 0.0001,1.0)); // 5
  96. addParameter(make_floatpar("playrange_end0", "Sound end", 0.0f, 1.0f, 1.0f, 0.0001,1.0)); // 6
  97. addParameter(new AudioParameterBool("freeze0", "Freeze", false)); // 7
  98. addParameter(make_floatpar("spread0", "Frequency spread", 0.0f, 1.0f, 0.0f, 0.001,1.0)); // 8
  99. addParameter(make_floatpar("compress0", "Compress", 0.0f, 1.0f, 0.0f, 0.001,1.0)); // 9
  100. addParameter(make_floatpar("loopxfadelen0", "Loop xfade length", 0.0f, 1.0f, 0.01f, 0.001, 1.0)); // 10
  101. addParameter(new AudioParameterInt("numharmonics0", "Num harmonics", 1, 100, 10)); // 11
  102. addParameter(make_floatpar("harmonicsfreq0", "Harmonics base freq", 1.0, 5000.0, 128.0, 0.1, 0.5));
  103. addParameter(make_floatpar("harmonicsbw0", "Harmonics bandwidth", 0.1f, 200.0f, 25.0f, 0.01, 1.0)); // 13
  104. addParameter(new AudioParameterBool("harmonicsgauss0", "Gaussian harmonics", false)); // 14
  105. addParameter(make_floatpar("octavemixm2_0", "2 octaves down level", 0.0f, 1.0f, 0.0f, 0.001, 1.0)); // 15
  106. addParameter(make_floatpar("octavemixm1_0", "Octave down level", 0.0f, 1.0f, 0.0f, 0.001, 1.0)); // 16
  107. addParameter(make_floatpar("octavemix0_0", "Normal pitch level", 0.0f, 1.0f, 1.0f, 0.001, 1.0)); // 17
  108. addParameter(make_floatpar("octavemix1_0", "1 octave up level", 0.0f, 1.0f, 0.0f, 0.001, 1.0)); // 18
  109. addParameter(make_floatpar("octavemix15_0", "1 octave and fifth up level", 0.0f, 1.0f, 0.0f, 0.001, 1.0)); // 19
  110. addParameter(make_floatpar("octavemix2_0", "2 octaves up level", 0.0f, 1.0f, 0.0f, 0.001, 1.0)); // 20
  111. addParameter(make_floatpar("tonalvsnoisebw_0", "Tonal vs Noise BW", 0.74f, 1.0f, 0.74f, 0.001, 1.0)); // 21
  112. addParameter(make_floatpar("tonalvsnoisepreserve_0", "Tonal vs Noise preserve", -1.0f, 1.0f, 0.5f, 0.001, 1.0)); // 22
  113. auto filt_convertFrom0To1Func = [](float rangemin, float rangemax, float value)
  114. {
  115. if (value < 0.5f)
  116. return jmap<float>(value, 0.0f, 0.5f, 20.0f, 1000.0f);
  117. return jmap<float>(value, 0.5f, 1.0f, 1000.0f, 20000.0f);
  118. };
  119. auto filt_convertTo0To1Func = [](float rangemin, float rangemax, float value)
  120. {
  121. if (value < 1000.0f)
  122. return jmap<float>(value, 20.0f, 1000.0f, 0.0f, 0.5f);
  123. return jmap<float>(value, 1000.0f, 20000.0f, 0.5f, 1.0f);
  124. };
  125. addParameter(new AudioParameterFloat("filter_low_0", "Filter low",
  126. NormalisableRange<float>(20.0f, 20000.0f,
  127. filt_convertFrom0To1Func, filt_convertTo0To1Func), 20.0f)); // 23
  128. addParameter(new AudioParameterFloat("filter_high_0", "Filter high",
  129. NormalisableRange<float>(20.0f, 20000.0f,
  130. filt_convertFrom0To1Func,filt_convertTo0To1Func), 20000.0f));; // 24
  131. addParameter(make_floatpar("onsetdetect_0", "Onset detection", 0.0f, 1.0f, 0.0f, 0.01, 1.0)); // 25
  132. addParameter(new AudioParameterBool("capture_enabled0", "Capture", false)); // 26
  133. m_outchansparam = new AudioParameterInt("numoutchans0", "Num outs", 2, 8, 2); // 27
  134. addParameter(m_outchansparam); // 27
  135. addParameter(new AudioParameterBool("pause_enabled0", "Pause", false)); // 28
  136. addParameter(new AudioParameterFloat("maxcapturelen_0", "Max capture length", 1.0f, 120.0f, 10.0f)); // 29
  137. addParameter(new AudioParameterBool("passthrough0", "Pass input through", false)); // 30
  138. addParameter(new AudioParameterBool("markdirty0", "Internal (don't use)", false)); // 31
  139. m_inchansparam = new AudioParameterInt("numinchans0", "Num ins", 2, 8, 2); // 32
  140. addParameter(m_inchansparam); // 32
  141. addParameter(new AudioParameterBool("bypass_stretch0", "Bypass stretch", false)); // 33
  142. addParameter(new AudioParameterFloat("freefilter_shiftx_0", "Free filter shift X", -1.0f, 1.0f, 0.0f)); // 34
  143. addParameter(new AudioParameterFloat("freefilter_shifty_0", "Free filter shift Y", -1.0f, 1.0f, 0.0f)); // 35
  144. addParameter(new AudioParameterFloat("freefilter_scaley_0", "Free filter scale Y", -1.0f, 1.0f, 1.0f)); // 36
  145. addParameter(new AudioParameterFloat("freefilter_tilty_0", "Free filter tilt Y", -1.0f, 1.0f, 0.0f)); // 37
  146. addParameter(new AudioParameterInt("freefilter_randomybands0", "Random bands", 2, 128, 16)); // 38
  147. addParameter(new AudioParameterInt("freefilter_randomyrate0", "Random rate", 1, 32, 2)); // 39
  148. addParameter(new AudioParameterFloat("freefilter_randomyamount0", "Random amount", 0.0, 1.0, 0.0)); // 40
  149. for (int i = 0; i < 9; ++i) // 41-49
  150. {
  151. addParameter(m_sm_enab_pars[i]);
  152. m_sm_enab_pars[i]->addListener(this);
  153. }
  154. addParameter(make_floatpar("octavemix_extra0_0", "Ratio mix 7 level", 0.0f, 1.0f, 0.0f, 0.001, 1.0)); // 50
  155. addParameter(make_floatpar("octavemix_extra1_0", "Ratio mix 8 level", 0.0f, 1.0f, 0.0f, 0.001, 1.0)); // 51
  156. std::array<double,8> initialratios{ 0.25,0.5,1.0,2.0,3.0,4.0,1.5,1.0 / 1.5 };
  157. // 52-59
  158. for (int i = 0; i < 8; ++i)
  159. {
  160. addParameter(make_floatpar("ratiomix_ratio_"+String(i)+"_0", "Ratio mix ratio "+String(i+1), 0.125f, 8.0f,
  161. initialratios[i],
  162. 0.001,
  163. 1.0));
  164. }
  165. addParameter(new AudioParameterBool("loop_enabled0", "Loop", true)); // 60
  166. addParameter(new AudioParameterBool("rewind0", "Rewind", false)); // 61
  167. auto dprate_convertFrom0To1Func = [](float rangemin, float rangemax, float value)
  168. {
  169. if (value < 0.5f)
  170. return jmap<float>(value, 0.0f, 0.5f, 0.1f, 1.0f);
  171. return jmap<float>(value, 0.5f, 1.0f, 1.0f, 8.0f);
  172. };
  173. auto dprate_convertTo0To1Func = [](float rangemin, float rangemax, float value)
  174. {
  175. if (value < 1.0f)
  176. return jmap<float>(value, 0.1f, 1.0f, 0.0f, 0.5f);
  177. return jmap<float>(value, 1.0f, 8.0f, 0.5f, 1.0f);
  178. };
  179. addParameter(new AudioParameterFloat("dryplayrate0", "Dry playrate",
  180. NormalisableRange<float>(0.1f, 8.0f,
  181. dprate_convertFrom0To1Func, dprate_convertTo0To1Func), 1.0f)); // 62
  182. auto& pars = getParameters();
  183. for (const auto& p : pars)
  184. m_reset_pars.push_back(p->getValue());
  185. setPreBufferAmount(2);
  186. startTimer(1, 50);
  187. m_show_technical_info = m_propsfile->m_props_file->getBoolValue("showtechnicalinfo", false);
  188. }
  189. PaulstretchpluginAudioProcessor::~PaulstretchpluginAudioProcessor()
  190. {
  191. //Logger::writeToLog("PaulX AudioProcessor destroyed");
  192. m_thumb->removeAllChangeListeners();
  193. m_thumb = nullptr;
  194. m_bufferingthread.stopThread(1000);
  195. }
  196. void PaulstretchpluginAudioProcessor::resetParameters()
  197. {
  198. ScopedLock locker(m_cs);
  199. for (int i = 0; i < m_reset_pars.size(); ++i)
  200. {
  201. if (i!=cpi_main_volume && i!=cpi_passthrough)
  202. setParameter(i, m_reset_pars[i]);
  203. }
  204. }
  205. void PaulstretchpluginAudioProcessor::setPreBufferAmount(int x)
  206. {
  207. int temp = jlimit(0, 5, x);
  208. if (temp != m_prebuffer_amount || m_use_backgroundbuffering == false)
  209. {
  210. m_use_backgroundbuffering = true;
  211. m_prebuffer_amount = temp;
  212. m_recreate_buffering_source = true;
  213. ScopedLock locker(m_cs);
  214. m_prebuffering_inited = false;
  215. m_cur_num_out_chans = *m_outchansparam;
  216. //Logger::writeToLog("Switching to use " + String(m_cur_num_out_chans) + " out channels");
  217. String err;
  218. startplay({ *getFloatParameter(cpi_soundstart),*getFloatParameter(cpi_soundend) },
  219. m_cur_num_out_chans, m_curmaxblocksize, err);
  220. m_prebuffering_inited = true;
  221. }
  222. }
  223. int PaulstretchpluginAudioProcessor::getPreBufferAmount()
  224. {
  225. if (m_use_backgroundbuffering == false)
  226. return -1;
  227. return m_prebuffer_amount;
  228. }
  229. ValueTree PaulstretchpluginAudioProcessor::getStateTree(bool ignoreoptions, bool ignorefile)
  230. {
  231. ValueTree paramtree("paulstretch3pluginstate");
  232. storeToTreeProperties(paramtree, nullptr, getParameters());
  233. if (m_current_file != File() && ignorefile == false)
  234. {
  235. paramtree.setProperty("importedfile", m_current_file.getFullPathName(), nullptr);
  236. }
  237. auto specorder = m_stretch_source->getSpectrumProcessOrder();
  238. paramtree.setProperty("numspectralstagesb", (int)specorder.size(), nullptr);
  239. for (int i = 0; i < specorder.size(); ++i)
  240. {
  241. paramtree.setProperty("specorderb" + String(i), specorder[i].m_index, nullptr);
  242. }
  243. if (ignoreoptions == false)
  244. {
  245. if (m_use_backgroundbuffering)
  246. paramtree.setProperty("prebufamount", m_prebuffer_amount, nullptr);
  247. else
  248. paramtree.setProperty("prebufamount", -1, nullptr);
  249. paramtree.setProperty("loadfilewithstate", m_load_file_with_state, nullptr);
  250. storeToTreeProperties(paramtree, nullptr, "playwhenhostrunning", m_play_when_host_plays,
  251. "capturewhenhostrunning", m_capture_when_host_plays,"savecapturedaudio",m_save_captured_audio,
  252. "mutewhilecapturing",m_mute_while_capturing);
  253. }
  254. storeToTreeProperties(paramtree, nullptr, "tabaindex", m_cur_tab_index);
  255. storeToTreeProperties(paramtree, nullptr, "waveviewrange", m_wave_view_range);
  256. ValueTree freefilterstate = m_free_filter_envelope->saveState(Identifier("freefilter_envelope"));
  257. paramtree.addChild(freefilterstate, -1, nullptr);
  258. return paramtree;
  259. }
  260. void PaulstretchpluginAudioProcessor::setStateFromTree(ValueTree tree)
  261. {
  262. if (tree.isValid())
  263. {
  264. {
  265. ScopedLock locker(m_cs);
  266. ValueTree freefilterstate = tree.getChildWithName("freefilter_envelope");
  267. m_free_filter_envelope->restoreState(freefilterstate);
  268. m_load_file_with_state = tree.getProperty("loadfilewithstate", true);
  269. getFromTreeProperties(tree, "playwhenhostrunning", m_play_when_host_plays,
  270. "capturewhenhostrunning", m_capture_when_host_plays,"mutewhilecapturing",m_mute_while_capturing,
  271. "savecapturedaudio",m_save_captured_audio);
  272. getFromTreeProperties(tree, "tabaindex", m_cur_tab_index);
  273. if (tree.hasProperty("numspectralstagesb"))
  274. {
  275. std::vector<SpectrumProcess> old_order = m_stretch_source->getSpectrumProcessOrder();
  276. std::vector<SpectrumProcess> new_order;
  277. int ordersize = tree.getProperty("numspectralstagesb");
  278. if (ordersize == old_order.size())
  279. {
  280. for (int i = 0; i < ordersize; ++i)
  281. {
  282. int index = tree.getProperty("specorderb" + String(i));
  283. new_order.push_back({ (SpectrumProcessType)index, old_order[index].m_enabled });
  284. }
  285. m_stretch_source->setSpectrumProcessOrder(new_order);
  286. }
  287. }
  288. getFromTreeProperties(tree, "waveviewrange", m_wave_view_range);
  289. getFromTreeProperties(tree, getParameters());
  290. }
  291. int prebufamt = tree.getProperty("prebufamount", 2);
  292. if (prebufamt == -1)
  293. m_use_backgroundbuffering = false;
  294. else
  295. setPreBufferAmount(prebufamt);
  296. if (m_load_file_with_state == true)
  297. {
  298. String fn = tree.getProperty("importedfile");
  299. if (fn.isEmpty() == false)
  300. {
  301. setAudioFile(File(fn));
  302. }
  303. }
  304. m_state_dirty = true;
  305. }
  306. }
  307. //==============================================================================
  308. const String PaulstretchpluginAudioProcessor::getName() const
  309. {
  310. return JucePlugin_Name;
  311. }
  312. bool PaulstretchpluginAudioProcessor::acceptsMidi() const
  313. {
  314. #if JucePlugin_WantsMidiInput
  315. return true;
  316. #else
  317. return false;
  318. #endif
  319. }
  320. bool PaulstretchpluginAudioProcessor::producesMidi() const
  321. {
  322. #if JucePlugin_ProducesMidiOutput
  323. return true;
  324. #else
  325. return false;
  326. #endif
  327. }
  328. bool PaulstretchpluginAudioProcessor::isMidiEffect() const
  329. {
  330. #if JucePlugin_IsMidiEffect
  331. return true;
  332. #else
  333. return false;
  334. #endif
  335. }
  336. double PaulstretchpluginAudioProcessor::getTailLengthSeconds() const
  337. {
  338. return 0.0;
  339. //return (double)m_bufamounts[m_prebuffer_amount]/getSampleRate();
  340. }
  341. int PaulstretchpluginAudioProcessor::getNumPrograms()
  342. {
  343. return 1;
  344. }
  345. int PaulstretchpluginAudioProcessor::getCurrentProgram()
  346. {
  347. return 0;
  348. }
  349. void PaulstretchpluginAudioProcessor::setCurrentProgram (int index)
  350. {
  351. }
  352. const String PaulstretchpluginAudioProcessor::getProgramName (int index)
  353. {
  354. return String();
  355. }
  356. void PaulstretchpluginAudioProcessor::changeProgramName (int index, const String& newName)
  357. {
  358. }
  359. void PaulstretchpluginAudioProcessor::parameterValueChanged(int parameterIndex, float newValue)
  360. {
  361. if (parameterIndex >= cpi_enable_spec_module0 && parameterIndex <= cpi_enable_spec_module8)
  362. {
  363. m_stretch_source->setSpectralModuleEnabled(parameterIndex - cpi_enable_spec_module0, newValue >= 0.5);
  364. }
  365. }
  366. void PaulstretchpluginAudioProcessor::parameterGestureChanged(int parameterIndex, bool gestureIsStarting)
  367. {
  368. }
  369. void PaulstretchpluginAudioProcessor::setFFTSize(double size)
  370. {
  371. if (m_prebuffer_amount == 5)
  372. m_fft_size_to_use = pow(2, 7.0 + size * 14.5);
  373. else m_fft_size_to_use = pow(2, 7.0 + size * 10.0); // chicken out from allowing huge FFT sizes if not enough prebuffering
  374. int optim = optimizebufsize(m_fft_size_to_use);
  375. m_fft_size_to_use = optim;
  376. m_stretch_source->setFFTSize(optim);
  377. //Logger::writeToLog(String(m_fft_size_to_use));
  378. }
  379. void PaulstretchpluginAudioProcessor::startplay(Range<double> playrange, int numoutchans, int maxBlockSize, String& err)
  380. {
  381. m_stretch_source->setPlayRange(playrange);
  382. m_stretch_source->setFreeFilterEnvelope(m_free_filter_envelope);
  383. int bufamt = m_bufamounts[m_prebuffer_amount];
  384. if (m_buffering_source != nullptr && numoutchans != m_buffering_source->getNumberOfChannels())
  385. m_recreate_buffering_source = true;
  386. if (m_recreate_buffering_source == true)
  387. {
  388. m_buffering_source = std::make_unique<MyBufferingAudioSource>(m_stretch_source.get(),
  389. m_bufferingthread, false, bufamt, numoutchans, false);
  390. m_recreate_buffering_source = false;
  391. }
  392. if (m_bufferingthread.isThreadRunning() == false)
  393. m_bufferingthread.startThread();
  394. m_stretch_source->setNumOutChannels(numoutchans);
  395. m_stretch_source->setFFTSize(m_fft_size_to_use);
  396. m_stretch_source->setProcessParameters(&m_ppar);
  397. m_stretch_source->m_prebuffersize = bufamt;
  398. m_last_outpos_pos = 0.0;
  399. m_last_in_pos = playrange.getStart()*m_stretch_source->getInfileLengthSeconds();
  400. m_buffering_source->prepareToPlay(maxBlockSize, getSampleRateChecked());
  401. }
  402. void PaulstretchpluginAudioProcessor::setParameters(const std::vector<double>& pars)
  403. {
  404. ScopedLock locker(m_cs);
  405. for (int i = 0; i < getNumParameters(); ++i)
  406. {
  407. if (i<pars.size())
  408. setParameter(i, pars[i]);
  409. }
  410. }
  411. void PaulstretchpluginAudioProcessor::updateStretchParametersFromPluginParameters(ProcessParameters & pars)
  412. {
  413. pars.pitch_shift.cents = *getFloatParameter(cpi_pitchshift) * 100.0;
  414. pars.freq_shift.Hz = *getFloatParameter(cpi_frequencyshift);
  415. pars.spread.bandwidth = *getFloatParameter(cpi_spreadamount);
  416. pars.compressor.power = *getFloatParameter(cpi_compress);
  417. pars.harmonics.nharmonics = *getIntParameter(cpi_numharmonics);
  418. pars.harmonics.freq = *getFloatParameter(cpi_harmonicsfreq);
  419. pars.harmonics.bandwidth = *getFloatParameter(cpi_harmonicsbw);
  420. pars.harmonics.gauss = getParameter(cpi_harmonicsgauss);
  421. pars.octave.om2 = *getFloatParameter(cpi_octavesm2);
  422. pars.octave.om1 = *getFloatParameter(cpi_octavesm1);
  423. pars.octave.o0 = *getFloatParameter(cpi_octaves0);
  424. pars.octave.o1 = *getFloatParameter(cpi_octaves1);
  425. pars.octave.o15 = *getFloatParameter(cpi_octaves15);
  426. pars.octave.o2 = *getFloatParameter(cpi_octaves2);
  427. pars.ratiomix.ratiolevels[0]= *getFloatParameter(cpi_octavesm2);
  428. pars.ratiomix.ratiolevels[1] = *getFloatParameter(cpi_octavesm1);
  429. pars.ratiomix.ratiolevels[2] = *getFloatParameter(cpi_octaves0);
  430. pars.ratiomix.ratiolevels[3] = *getFloatParameter(cpi_octaves1);
  431. pars.ratiomix.ratiolevels[4] = *getFloatParameter(cpi_octaves15);
  432. pars.ratiomix.ratiolevels[5] = *getFloatParameter(cpi_octaves2);
  433. pars.ratiomix.ratiolevels[6] = *getFloatParameter(cpi_octaves_extra1);
  434. pars.ratiomix.ratiolevels[7] = *getFloatParameter(cpi_octaves_extra2);
  435. for (int i = 0; i < 8; ++i)
  436. pars.ratiomix.ratios[i] = *getFloatParameter((int)cpi_octaves_ratio0 + i);
  437. pars.filter.low = *getFloatParameter(cpi_filter_low);
  438. pars.filter.high = *getFloatParameter(cpi_filter_high);
  439. pars.tonal_vs_noise.bandwidth = *getFloatParameter(cpi_tonalvsnoisebw);
  440. pars.tonal_vs_noise.preserve = *getFloatParameter(cpi_tonalvsnoisepreserve);
  441. }
  442. void PaulstretchpluginAudioProcessor::saveCaptureBuffer()
  443. {
  444. auto task = [this]()
  445. {
  446. int inchans = *getIntParameter(cpi_num_inchans);
  447. if (inchans < 1)
  448. return;
  449. Uuid uid;
  450. WavAudioFormat wavformat;
  451. String propsdir = m_propsfile->m_props_file->getFile().getParentDirectory().getFullPathName();
  452. String outfn;
  453. if (m_capture_location.isEmpty())
  454. outfn = propsdir + "/paulxstretchaudiocaptures/" + uid.toString() + ".wav";
  455. else
  456. outfn = m_capture_location + "/pxscapture_" + uid.toString() + ".wav";
  457. File outfile(outfn);
  458. outfile.create();
  459. if (outfile.existsAsFile())
  460. {
  461. m_capture_save_state = 1;
  462. auto outstream = outfile.createOutputStream();
  463. auto writer = unique_from_raw(wavformat.createWriterFor(outstream, getSampleRateChecked(),
  464. inchans, 32, {}, 0));
  465. if (writer != nullptr)
  466. {
  467. auto sourcebuffer = getStretchSource()->getSourceAudioBuffer();
  468. jassert(sourcebuffer->getNumChannels() == inchans);
  469. jassert(sourcebuffer->getNumSamples() > 0);
  470. writer->writeFromAudioSampleBuffer(*sourcebuffer, 0, sourcebuffer->getNumSamples());
  471. m_current_file = outfile;
  472. }
  473. else
  474. {
  475. Logger::writeToLog("Could not create wav writer");
  476. delete outstream;
  477. }
  478. }
  479. else
  480. Logger::writeToLog("Could not create output file");
  481. m_capture_save_state = 0;
  482. };
  483. m_threadpool->addJob(task);
  484. }
  485. String PaulstretchpluginAudioProcessor::offlineRender(OfflineRenderParams renderpars)
  486. {
  487. File outputfiletouse = renderpars.outputfile.getNonexistentSibling();
  488. ValueTree state{ getStateTree(false, false) };
  489. auto processor = std::make_shared<PaulstretchpluginAudioProcessor>();
  490. processor->setStateFromTree(state);
  491. double outsr{ renderpars.outsr };
  492. if (outsr < 10.0)
  493. outsr = processor->getStretchSource()->getInfileSamplerate();
  494. Logger::writeToLog(outputfiletouse.getFullPathName() + " " + String(outsr) + " " + String(renderpars.outputformat));
  495. int blocksize{ 1024 };
  496. int numoutchans = *processor->getIntParameter(cpi_num_outchans);
  497. processor->setPlayConfigDetails(0, numoutchans, outsr, blocksize);
  498. processor->prepareToPlay(renderpars.outsr, blocksize);
  499. double t0 = *processor->getFloatParameter(cpi_soundstart);
  500. double t1 = *processor->getFloatParameter(cpi_soundend);
  501. sanitizeTimeRange(t0, t1);
  502. auto rendertask = [processor,outputfiletouse, renderpars,blocksize,numoutchans, outsr, this]()
  503. {
  504. WavAudioFormat wavformat;
  505. FileOutputStream* outstream = outputfiletouse.createOutputStream();
  506. if (outstream == nullptr)
  507. {
  508. jassert(false);
  509. }
  510. int oformattouse{ 16 };
  511. bool clipoutput{ false };
  512. if (renderpars.outputformat == 1)
  513. oformattouse = 24;
  514. if (renderpars.outputformat == 2)
  515. oformattouse = 32;
  516. if (renderpars.outputformat == 3)
  517. {
  518. oformattouse = 32;
  519. clipoutput = true;
  520. }
  521. auto writer{ unique_from_raw(wavformat.createWriterFor(outstream, getSampleRateChecked(), numoutchans,
  522. oformattouse, StringPairArray(), 0)) };
  523. if (writer == nullptr)
  524. {
  525. delete outstream;
  526. jassert(false);
  527. }
  528. AudioBuffer<float> renderbuffer{ numoutchans, blocksize };
  529. MidiBuffer dummymidi;
  530. auto sc = processor->getStretchSource();
  531. double outlensecs = sc->getInfileLengthSeconds()*sc->getRate();
  532. int64_t outlen = outlensecs * outsr;
  533. int64_t outcounter{ 0 };
  534. m_offline_render_state = 0;
  535. m_offline_render_cancel_requested = false;
  536. processor->setNonRealtime(true);
  537. while (outcounter < outlen)
  538. {
  539. if (m_offline_render_cancel_requested == true)
  540. break;
  541. processor->processBlock(renderbuffer, dummymidi);
  542. writer->writeFromAudioSampleBuffer(renderbuffer, 0, blocksize);
  543. outcounter += blocksize;
  544. m_offline_render_state = 100.0 / outlen * outcounter;
  545. }
  546. m_offline_render_state = 200;
  547. Logger::writeToLog("Rendered ok!");
  548. };
  549. std::thread th(rendertask);
  550. th.detach();
  551. return "Rendered OK";
  552. }
  553. double PaulstretchpluginAudioProcessor::getSampleRateChecked()
  554. {
  555. if (m_cur_sr < 1.0 || m_cur_sr>1000000.0)
  556. return 44100.0;
  557. return m_cur_sr;
  558. }
  559. void PaulstretchpluginAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
  560. {
  561. ++m_prepare_count;
  562. ScopedLock locker(m_cs);
  563. m_adsr.setSampleRate(sampleRate);
  564. m_cur_sr = sampleRate;
  565. m_curmaxblocksize = samplesPerBlock;
  566. m_input_buffer.setSize(getMainBusNumInputChannels(), samplesPerBlock);
  567. *getBoolParameter(cpi_rewind) = false;
  568. m_lastrewind = false;
  569. int numoutchans = *m_outchansparam;
  570. if (numoutchans != m_cur_num_out_chans)
  571. m_prebuffering_inited = false;
  572. if (m_using_memory_buffer == true)
  573. {
  574. int len = jlimit(100,m_recbuffer.getNumSamples(),
  575. int(getSampleRateChecked()*(*getFloatParameter(cpi_max_capture_len))));
  576. m_stretch_source->setAudioBufferAsInputSource(&m_recbuffer,
  577. getSampleRateChecked(),
  578. len);
  579. //m_thumb->reset(m_recbuffer.getNumChannels(), sampleRate, len);
  580. }
  581. if (m_prebuffering_inited == false)
  582. {
  583. setFFTSize(*getFloatParameter(cpi_fftsize));
  584. m_stretch_source->setProcessParameters(&m_ppar);
  585. m_stretch_source->setFFTWindowingType(1);
  586. String err;
  587. startplay({ *getFloatParameter(cpi_soundstart),*getFloatParameter(cpi_soundend) },
  588. numoutchans, samplesPerBlock, err);
  589. m_cur_num_out_chans = numoutchans;
  590. m_prebuffering_inited = true;
  591. }
  592. else
  593. {
  594. m_buffering_source->prepareToPlay(samplesPerBlock, getSampleRateChecked());
  595. }
  596. }
  597. void PaulstretchpluginAudioProcessor::releaseResources()
  598. {
  599. //m_control->stopplay();
  600. //m_ready_to_play = false;
  601. }
  602. #ifndef JucePlugin_PreferredChannelConfigurations
  603. bool PaulstretchpluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
  604. {
  605. #if JucePlugin_IsMidiEffect
  606. ignoreUnused (layouts);
  607. return true;
  608. #else
  609. // This is the place where you check if the layout is supported.
  610. // In this template code we only support mono or stereo.
  611. if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono()
  612. && layouts.getMainOutputChannelSet() != AudioChannelSet::stereo())
  613. return false;
  614. // This checks if the input layout matches the output layout
  615. #if ! JucePlugin_IsSynth
  616. if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
  617. return false;
  618. #endif
  619. return true;
  620. #endif
  621. }
  622. #endif
  623. void copyAudioBufferWrappingPosition(const AudioBuffer<float>& src, AudioBuffer<float>& dest, int destbufpos, int maxdestpos)
  624. {
  625. for (int i = 0; i < dest.getNumChannels(); ++i)
  626. {
  627. int channel_to_copy = i % src.getNumChannels();
  628. if (destbufpos + src.getNumSamples() > maxdestpos)
  629. {
  630. int wrappos = (destbufpos + src.getNumSamples()) % maxdestpos;
  631. int partial_len = src.getNumSamples() - wrappos;
  632. dest.copyFrom(channel_to_copy, destbufpos, src, channel_to_copy, 0, partial_len);
  633. dest.copyFrom(channel_to_copy, partial_len, src, channel_to_copy, 0, wrappos);
  634. }
  635. else
  636. {
  637. dest.copyFrom(channel_to_copy, destbufpos, src, channel_to_copy, 0, src.getNumSamples());
  638. }
  639. }
  640. }
  641. /*
  642. void PaulstretchpluginAudioProcessor::processBlock (AudioBuffer<double>& buffer, MidiBuffer&)
  643. {
  644. jassert(false);
  645. }
  646. */
  647. void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
  648. {
  649. ScopedLock locker(m_cs);
  650. const int totalNumInputChannels = getTotalNumInputChannels();
  651. const int totalNumOutputChannels = getTotalNumOutputChannels();
  652. AudioPlayHead* phead = getPlayHead();
  653. if (phead != nullptr)
  654. {
  655. phead->getCurrentPosition(m_playposinfo);
  656. }
  657. else
  658. m_playposinfo.isPlaying = false;
  659. ScopedNoDenormals noDenormals;
  660. double srtemp = getSampleRate();
  661. if (srtemp != m_cur_sr)
  662. m_cur_sr = srtemp;
  663. m_prebufsmoother.setSlope(0.9, srtemp / buffer.getNumSamples());
  664. m_smoothed_prebuffer_ready = m_prebufsmoother.process(m_buffering_source->getPercentReady());
  665. for (int i = 0; i < totalNumInputChannels; ++i)
  666. m_input_buffer.copyFrom(i, 0, buffer, i, 0, buffer.getNumSamples());
  667. for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
  668. buffer.clear (i, 0, buffer.getNumSamples());
  669. if (m_previewcomponent != nullptr)
  670. {
  671. m_previewcomponent->processBlock(getSampleRate(), buffer);
  672. return;
  673. }
  674. if (m_prebuffering_inited == false)
  675. return;
  676. if (m_is_recording == true)
  677. {
  678. if (m_playposinfo.isPlaying == false && m_capture_when_host_plays == true)
  679. return;
  680. int recbuflenframes = m_max_reclen * getSampleRate();
  681. copyAudioBufferWrappingPosition(buffer, m_recbuffer, m_rec_pos, recbuflenframes);
  682. m_thumb->addBlock(m_rec_pos, buffer, 0, buffer.getNumSamples());
  683. m_rec_pos = (m_rec_pos + buffer.getNumSamples()) % recbuflenframes;
  684. m_rec_count += buffer.getNumSamples();
  685. if (m_rec_count<recbuflenframes)
  686. m_recorded_range = { 0, m_rec_count };
  687. if (m_mute_while_capturing == true)
  688. buffer.clear();
  689. return;
  690. }
  691. jassert(m_buffering_source != nullptr);
  692. jassert(m_bufferingthread.isThreadRunning());
  693. double t0 = *getFloatParameter(cpi_soundstart);
  694. double t1 = *getFloatParameter(cpi_soundend);
  695. sanitizeTimeRange(t0, t1);
  696. m_stretch_source->setPlayRange({ t0,t1 });
  697. if (m_last_host_playing == false && m_playposinfo.isPlaying)
  698. {
  699. m_stretch_source->seekPercent(*getFloatParameter(cpi_soundstart));
  700. m_last_host_playing = true;
  701. }
  702. else if (m_last_host_playing == true && m_playposinfo.isPlaying == false)
  703. {
  704. m_last_host_playing = false;
  705. }
  706. if (m_play_when_host_plays == true && m_playposinfo.isPlaying == false)
  707. return;
  708. m_free_filter_envelope->m_transform_x_shift = *getFloatParameter(cpi_freefilter_shiftx);
  709. m_free_filter_envelope->m_transform_y_shift = *getFloatParameter(cpi_freefilter_shifty);
  710. m_free_filter_envelope->m_transform_y_scale = *getFloatParameter(cpi_freefilter_scaley);
  711. m_free_filter_envelope->m_transform_y_tilt = *getFloatParameter(cpi_freefilter_tilty);
  712. m_free_filter_envelope->m_transform_y_random_bands = *getIntParameter(cpi_freefilter_randomy_numbands);
  713. m_free_filter_envelope->m_transform_y_random_rate = *getIntParameter(cpi_freefilter_randomy_rate);
  714. m_free_filter_envelope->m_transform_y_random_amount = *getFloatParameter(cpi_freefilter_randomy_amount);
  715. //m_stretch_source->setSpectralModulesEnabled(m_sm_enab_pars);
  716. if (m_stretch_source->isLoopEnabled() != *getBoolParameter(cpi_looping_enabled))
  717. m_stretch_source->setLoopingEnabled(*getBoolParameter(cpi_looping_enabled));
  718. bool rew = *getBoolParameter(cpi_rewind);
  719. if (rew != m_lastrewind)
  720. {
  721. if (rew == true)
  722. {
  723. *getBoolParameter(cpi_rewind) = false;
  724. m_stretch_source->seekPercent(m_stretch_source->getPlayRange().getStart());
  725. }
  726. m_lastrewind = rew;
  727. }
  728. m_stretch_source->setMainVolume(*getFloatParameter(cpi_main_volume));
  729. m_stretch_source->setRate(*getFloatParameter(cpi_stretchamount));
  730. m_stretch_source->setPreviewDry(*getBoolParameter(cpi_bypass_stretch));
  731. m_stretch_source->setDryPlayrate(*getFloatParameter(cpi_dryplayrate));
  732. setFFTSize(*getFloatParameter(cpi_fftsize));
  733. updateStretchParametersFromPluginParameters(m_ppar);
  734. m_stretch_source->setOnsetDetection(*getFloatParameter(cpi_onsetdetection));
  735. m_stretch_source->setLoopXFadeLength(*getFloatParameter(cpi_loopxfadelen));
  736. m_stretch_source->setFreezing(getParameter(cpi_freeze));
  737. m_stretch_source->setPaused(getParameter(cpi_pause_enabled));
  738. if (m_midinote_control == true)
  739. {
  740. MidiBuffer::Iterator midi_it(midiMessages);
  741. MidiMessage midi_msg;
  742. int midi_msg_pos;
  743. while (true)
  744. {
  745. if (midi_it.getNextEvent(midi_msg, midi_msg_pos) == false)
  746. break;
  747. if (midi_msg.isNoteOff() && midi_msg.getNoteNumber() == m_midinote_to_use)
  748. {
  749. m_adsr.noteOff();
  750. break;
  751. }
  752. if (midi_msg.isNoteOn())
  753. {
  754. m_midinote_to_use = midi_msg.getNoteNumber();
  755. m_adsr.setParameters({ 1.0,0.5,0.5,1.0 });
  756. m_adsr.noteOn();
  757. break;
  758. }
  759. }
  760. }
  761. if (m_midinote_control == true && m_midinote_to_use >= 0)
  762. {
  763. int note_offset = m_midinote_to_use - 60;
  764. m_ppar.pitch_shift.cents += 100.0*note_offset;
  765. }
  766. m_stretch_source->setProcessParameters(&m_ppar);
  767. AudioSourceChannelInfo aif(buffer);
  768. if (isNonRealtime() || m_use_backgroundbuffering == false)
  769. {
  770. m_stretch_source->getNextAudioBlock(aif);
  771. }
  772. else
  773. {
  774. m_buffering_source->getNextAudioBlock(aif);
  775. }
  776. if (m_is_recording == false && getParameter(cpi_passthrough) > 0.5f)
  777. {
  778. for (int i = 0; i < totalNumInputChannels; ++i)
  779. {
  780. buffer.addFrom(i, 0, m_input_buffer, i, 0, buffer.getNumSamples());
  781. }
  782. }
  783. bool abnordetected = false;
  784. for (int i = 0; i < buffer.getNumChannels(); ++i)
  785. {
  786. for (int j = 0; j < buffer.getNumSamples(); ++j)
  787. {
  788. float sample = buffer.getSample(i,j);
  789. if (std::isnan(sample) || std::isinf(sample))
  790. {
  791. ++m_abnormal_output_samples;
  792. abnordetected = true;
  793. }
  794. }
  795. }
  796. if (abnordetected)
  797. {
  798. buffer.clear();
  799. }
  800. else
  801. {
  802. if (m_midinote_control == true)
  803. {
  804. m_adsr.applyEnvelopeToBuffer(buffer, 0, buffer.getNumSamples());
  805. }
  806. }
  807. auto ed = dynamic_cast<PaulstretchpluginAudioProcessorEditor*>(getActiveEditor());
  808. if (ed != nullptr)
  809. {
  810. ed->m_sonogram.addAudioBlock(buffer);
  811. }
  812. }
  813. //==============================================================================
  814. bool PaulstretchpluginAudioProcessor::hasEditor() const
  815. {
  816. return true; // (change this to false if you choose to not supply an editor)
  817. }
  818. AudioProcessorEditor* PaulstretchpluginAudioProcessor::createEditor()
  819. {
  820. return new PaulstretchpluginAudioProcessorEditor (*this);
  821. }
  822. //==============================================================================
  823. void PaulstretchpluginAudioProcessor::getStateInformation (MemoryBlock& destData)
  824. {
  825. ValueTree paramtree = getStateTree(false,false);
  826. MemoryOutputStream stream(destData,true);
  827. paramtree.writeToStream(stream);
  828. }
  829. void PaulstretchpluginAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
  830. {
  831. ValueTree tree = ValueTree::readFromData(data, sizeInBytes);
  832. setStateFromTree(tree);
  833. }
  834. void PaulstretchpluginAudioProcessor::setDirty()
  835. {
  836. toggleBool(getBoolParameter(cpi_markdirty));
  837. }
  838. void PaulstretchpluginAudioProcessor::setRecordingEnabled(bool b)
  839. {
  840. ScopedLock locker(m_cs);
  841. int lenbufframes = getSampleRateChecked()*m_max_reclen;
  842. if (b == true)
  843. {
  844. m_using_memory_buffer = true;
  845. m_current_file = File();
  846. int numchans = *m_inchansparam;
  847. m_recbuffer.setSize(numchans, m_max_reclen*getSampleRateChecked()+4096,false,false,true);
  848. m_recbuffer.clear();
  849. m_rec_pos = 0;
  850. m_thumb->reset(m_recbuffer.getNumChannels(), getSampleRateChecked(), lenbufframes);
  851. m_is_recording = true;
  852. m_recorded_range = Range<int>();
  853. m_rec_count = 0;
  854. }
  855. else
  856. {
  857. if (m_is_recording == true)
  858. {
  859. finishRecording(lenbufframes);
  860. }
  861. }
  862. }
  863. double PaulstretchpluginAudioProcessor::getRecordingPositionPercent()
  864. {
  865. if (m_is_recording==false)
  866. return 0.0;
  867. return 1.0 / m_recbuffer.getNumSamples()*m_rec_pos;
  868. }
  869. String PaulstretchpluginAudioProcessor::setAudioFile(File f)
  870. {
  871. auto ai = unique_from_raw(m_afm->createReaderFor(f));
  872. if (ai != nullptr)
  873. {
  874. if (ai->numChannels > 8)
  875. {
  876. return "Too many channels in file "+f.getFullPathName();
  877. }
  878. if (ai->bitsPerSample>32)
  879. {
  880. return "Too high bit depth in file " + f.getFullPathName();
  881. }
  882. m_thumb->setSource(new FileInputSource(f));
  883. ScopedLock locker(m_cs);
  884. m_stretch_source->setAudioFile(f);
  885. //Range<double> currange{ *getFloatParameter(cpi_soundstart),*getFloatParameter(cpi_soundend) };
  886. //if (currange.contains(m_stretch_source->getInfilePositionPercent())==false)
  887. m_stretch_source->seekPercent(*getFloatParameter(cpi_soundstart));
  888. m_current_file = f;
  889. m_current_file_date = m_current_file.getLastModificationTime();
  890. m_using_memory_buffer = false;
  891. setDirty();
  892. return String();
  893. }
  894. return "Could not open file " + f.getFullPathName();
  895. }
  896. Range<double> PaulstretchpluginAudioProcessor::getTimeSelection()
  897. {
  898. return { *getFloatParameter(cpi_soundstart),*getFloatParameter(cpi_soundend) };
  899. }
  900. double PaulstretchpluginAudioProcessor::getPreBufferingPercent()
  901. {
  902. if (m_buffering_source==nullptr)
  903. return 0.0;
  904. return m_smoothed_prebuffer_ready;
  905. }
  906. void PaulstretchpluginAudioProcessor::timerCallback(int id)
  907. {
  908. if (id == 1)
  909. {
  910. bool capture = *getBoolParameter(cpi_capture_trigger);
  911. if (capture == false && m_max_reclen != *getFloatParameter(cpi_max_capture_len))
  912. {
  913. m_max_reclen = *getFloatParameter(cpi_max_capture_len);
  914. //Logger::writeToLog("Changing max capture len to " + String(m_max_reclen));
  915. }
  916. if (capture == true && m_is_recording == false)
  917. {
  918. setRecordingEnabled(true);
  919. *getBoolParameter(cpi_capture_trigger)=false;
  920. return;
  921. }
  922. if (capture == true && m_is_recording == true)
  923. {
  924. setRecordingEnabled(false);
  925. *getBoolParameter(cpi_capture_trigger) = false;
  926. return;
  927. }
  928. if (m_cur_num_out_chans != *m_outchansparam)
  929. {
  930. jassert(m_curmaxblocksize > 0);
  931. ScopedLock locker(m_cs);
  932. m_prebuffering_inited = false;
  933. m_cur_num_out_chans = *m_outchansparam;
  934. //Logger::writeToLog("Switching to use " + String(m_cur_num_out_chans) + " out channels");
  935. String err;
  936. startplay({ *getFloatParameter(cpi_soundstart),*getFloatParameter(cpi_soundend) },
  937. m_cur_num_out_chans, m_curmaxblocksize, err);
  938. m_prebuffering_inited = true;
  939. }
  940. }
  941. }
  942. void PaulstretchpluginAudioProcessor::setAudioPreview(AudioFilePreviewComponent * afpc)
  943. {
  944. ScopedLock locker(m_cs);
  945. m_previewcomponent = afpc;
  946. }
  947. pointer_sized_int PaulstretchpluginAudioProcessor::handleVstPluginCanDo(int32 index, pointer_sized_int value, void * ptr, float opt)
  948. {
  949. if (strcmp((char*)ptr, "xenakios") == 0)
  950. {
  951. if (index == 0 && (void*)value!=nullptr)
  952. {
  953. double t0 = *getFloatParameter(cpi_soundstart);
  954. double t1 = *getFloatParameter(cpi_soundend);
  955. double outlen = (t1-t0)*m_stretch_source->getInfileLengthSeconds()*(*getFloatParameter(cpi_stretchamount));
  956. //std::cout << "host requested output length, result " << outlen << "\n";
  957. *((double*)value) = outlen;
  958. }
  959. if (index == 1 && (void*)value!=nullptr)
  960. {
  961. String fn(CharPointer_UTF8((char*)value));
  962. //std::cout << "host requested to set audio file " << fn << "\n";
  963. auto err = setAudioFile(File(fn));
  964. if (err.isEmpty()==false)
  965. std::cout << err << "\n";
  966. }
  967. return 1;
  968. }
  969. return pointer_sized_int();
  970. }
  971. pointer_sized_int PaulstretchpluginAudioProcessor::handleVstManufacturerSpecific(int32 index, pointer_sized_int value, void * ptr, float opt)
  972. {
  973. return pointer_sized_int();
  974. }
  975. void PaulstretchpluginAudioProcessor::finishRecording(int lenrecording)
  976. {
  977. m_is_recording = false;
  978. m_current_file = File();
  979. m_stretch_source->setAudioBufferAsInputSource(&m_recbuffer, getSampleRateChecked(), lenrecording);
  980. *getFloatParameter(cpi_soundstart) = 0.0f;
  981. *getFloatParameter(cpi_soundend) = jlimit<double>(0.01, 1.0, 1.0 / lenrecording * m_rec_count);
  982. if (m_save_captured_audio == true)
  983. {
  984. saveCaptureBuffer();
  985. }
  986. }
  987. AudioProcessor* JUCE_CALLTYPE createPluginFilter()
  988. {
  989. return new PaulstretchpluginAudioProcessor();
  990. }