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.

1637 lines
52KB

  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 <array>
  15. #include "RenderSettingsComponent.h"
  16. static void handleSettingsMenuModalCallback(int choice, PaulstretchpluginAudioProcessorEditor* ed)
  17. {
  18. ed->executeModalMenuAction(0,choice);
  19. }
  20. //==============================================================================
  21. PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(PaulstretchpluginAudioProcessor& p)
  22. : AudioProcessorEditor(&p),
  23. m_wavecomponent(p.m_afm,p.m_thumb.get(), p.getStretchSource()),
  24. processor(p), m_perfmeter(&p),
  25. m_free_filter_component(&p),
  26. m_wavefilter_tab(p.m_cur_tab_index),
  27. m_filefilter(p.m_afm->getWildcardForAllFormats(),String(),String())
  28. {
  29. setWantsKeyboardFocus(true);
  30. m_wave_container = new Component;
  31. m_free_filter_component.getEnvelopeComponent()->set_envelope(processor.m_free_filter_envelope);
  32. m_free_filter_component.getEnvelopeComponent()->XFromNormalized = [this](double x)
  33. {
  34. //return jmap<double>(pow(x, 3.0), 0.0, 1.0, 30.0, processor.getSampleRateChecked()/2.0);
  35. return 30.0*pow(1.05946309436, x*115.0);
  36. };
  37. m_free_filter_component.getEnvelopeComponent()->YFromNormalized = [this](double x)
  38. {
  39. return jmap<double>(x, 0.0, 1.0, -48.0, 12.0);
  40. };
  41. m_wavefilter_tab.setTabBarDepth(20);
  42. addAndMakeVisible(&m_perfmeter);
  43. addAndMakeVisible(&m_import_button);
  44. m_import_button.setButtonText("Show browser");
  45. m_import_button.onClick = [this]()
  46. {
  47. toggleFileBrowser();
  48. };
  49. addAndMakeVisible(&m_settings_button);
  50. m_settings_button.setButtonText("Settings...");
  51. m_settings_button.onClick = [this]() { showSettingsMenu(); };
  52. if (processor.wrapperType == AudioProcessor::wrapperType_Standalone)
  53. {
  54. addAndMakeVisible(&m_render_button);
  55. m_render_button.setButtonText("Render...");
  56. m_render_button.onClick = [this]() { showRenderDialog(); };
  57. }
  58. addAndMakeVisible(m_rewind_button);
  59. m_rewind_button.setButtonText("<<");
  60. m_rewind_button.onClick = [this]()
  61. {
  62. *processor.getBoolParameter(cpi_rewind) = true;
  63. //processor.getStretchSource()->seekPercent(processor.getStretchSource()->getPlayRange().getStart());
  64. };
  65. addAndMakeVisible(&m_info_label);
  66. m_info_label.setJustificationType(Justification::centredRight);
  67. m_wavecomponent.GetFileCallback = [this]() { return processor.getAudioFile(); };
  68. const auto& pars = processor.getParameters();
  69. for (int i=0;i<pars.size();++i)
  70. {
  71. AudioProcessorParameterWithID* parid = dynamic_cast<AudioProcessorParameterWithID*>(pars[i]);
  72. jassert(parid);
  73. bool notifyonlyonrelease = false;
  74. if (parid->paramID.startsWith("fftsize") || parid->paramID.startsWith("numoutchans")
  75. || parid->paramID.startsWith("numinchans"))
  76. notifyonlyonrelease = true;
  77. int group_id = -1;
  78. if (i == cpi_harmonicsbw || i == cpi_harmonicsfreq || i == cpi_harmonicsgauss || i == cpi_numharmonics)
  79. group_id = 0;
  80. if (i == cpi_octavesm2 || i == cpi_octavesm1 || i == cpi_octaves0 || i == cpi_octaves1 || i == cpi_octaves15 ||
  81. i == cpi_octaves2 || i==cpi_octaves_extra1 || i==cpi_octaves_extra2)
  82. group_id = -2; // -2 for not included in the main parameters page
  83. if (i >= cpi_octaves_ratio0 && i <= cpi_octaves_ratio7)
  84. group_id = -2;
  85. if ((i >= cpi_enable_spec_module0 && i <= cpi_enable_spec_module8))
  86. group_id = -2;
  87. if (i == cpi_tonalvsnoisebw || i == cpi_tonalvsnoisepreserve)
  88. group_id = 1;
  89. if (i == cpi_filter_low || i == cpi_filter_high)
  90. group_id = 6;
  91. if (i == cpi_compress)
  92. group_id = 8;
  93. if (i == cpi_spreadamount)
  94. group_id = 5;
  95. if (i == cpi_frequencyshift)
  96. group_id = 2;
  97. if (i == cpi_pitchshift)
  98. group_id = 3;
  99. if (i == cpi_freefilter_scaley || i == cpi_freefilter_shiftx || i == cpi_freefilter_shifty ||
  100. i == cpi_freefilter_tilty || i == cpi_freefilter_randomy_amount || i == cpi_freefilter_randomy_numbands
  101. || i == cpi_freefilter_randomy_rate)
  102. group_id = -2;
  103. if (group_id >= -1)
  104. {
  105. m_parcomps.emplace_back(std::make_unique<ParameterComponent>(pars[i], notifyonlyonrelease));
  106. m_parcomps.back()->m_group_id = group_id;
  107. if (group_id >= -1)
  108. addAndMakeVisible(m_parcomps.back().get());
  109. }
  110. else
  111. {
  112. m_parcomps.push_back(nullptr);
  113. }
  114. }
  115. //m_parcomps[cpi_dryplayrate]->getSlider()->setSkewFactorFromMidPoint(1.0);
  116. //addAndMakeVisible(&m_specvis);
  117. m_wave_container->addAndMakeVisible(&m_zs);
  118. m_zs.RangeChanged = [this](Range<double> r)
  119. {
  120. m_wavecomponent.setViewRange(r);
  121. processor.m_wave_view_range = r;
  122. };
  123. m_zs.setRange(processor.m_wave_view_range, true);
  124. m_wavecomponent.ViewRangeChangedCallback = [this](Range<double> rng)
  125. {
  126. m_zs.setRange(rng, false);
  127. };
  128. m_wavecomponent.TimeSelectionChangedCallback = [this](Range<double> range, int which)
  129. {
  130. *processor.getFloatParameter(cpi_soundstart) = range.getStart();
  131. *processor.getFloatParameter(cpi_soundend) = range.getEnd();
  132. };
  133. m_wavecomponent.CursorPosCallback = [this]()
  134. {
  135. return processor.getStretchSource()->getInfilePositionPercent();
  136. };
  137. m_wavecomponent.SeekCallback = [this](double pos)
  138. {
  139. if (processor.getStretchSource()->getPlayRange().contains(pos))
  140. processor.getStretchSource()->seekPercent(pos);
  141. };
  142. m_spec_order_ed.setSource(processor.getStretchSource());
  143. addAndMakeVisible(&m_spec_order_ed);
  144. m_spec_order_ed.ModuleSelectedCallback = [this](int id)
  145. {
  146. for (int i = 0; i < m_parcomps.size(); ++i)
  147. {
  148. if (m_parcomps[i] != nullptr)
  149. {
  150. if (m_parcomps[i]->m_group_id == id)
  151. m_parcomps[i]->setHighLighted(true);
  152. else
  153. m_parcomps[i]->setHighLighted(false);
  154. }
  155. }
  156. };
  157. m_spec_order_ed.ModuleOrderOrEnabledChangedCallback = [this]()
  158. {
  159. processor.setDirty();
  160. };
  161. m_ratiomixeditor.GetParameterValue = [this](int which, int index)
  162. {
  163. if (which == 0)
  164. return (double)*processor.getFloatParameter((int)cpi_octaves_ratio0 + index);
  165. if (which == 1)
  166. {
  167. if (index == 0)
  168. return (double)*processor.getFloatParameter(cpi_octavesm2);
  169. if (index == 1)
  170. return (double)*processor.getFloatParameter(cpi_octavesm1);
  171. if (index == 2)
  172. return (double)*processor.getFloatParameter(cpi_octaves0);
  173. if (index == 3)
  174. return (double)*processor.getFloatParameter(cpi_octaves1);
  175. if (index == 4)
  176. return (double)*processor.getFloatParameter(cpi_octaves15);
  177. if (index == 5)
  178. return (double)*processor.getFloatParameter(cpi_octaves2);
  179. if (index == 6)
  180. return (double)*processor.getFloatParameter(cpi_octaves_extra1);
  181. if (index == 7)
  182. return (double)*processor.getFloatParameter(cpi_octaves_extra2);
  183. }
  184. return 0.0;
  185. };
  186. m_ratiomixeditor.OnRatioLevelChanged = [this](int index, double val)
  187. {
  188. if (index == 0)
  189. *processor.getFloatParameter(cpi_octavesm2) = val;
  190. if (index == 1)
  191. *processor.getFloatParameter(cpi_octavesm1) = val;
  192. if (index == 2)
  193. *processor.getFloatParameter(cpi_octaves0) = val;
  194. if (index == 3)
  195. *processor.getFloatParameter(cpi_octaves1) = val;
  196. if (index == 4)
  197. *processor.getFloatParameter(cpi_octaves15) = val;
  198. if (index == 5)
  199. *processor.getFloatParameter(cpi_octaves2) = val;
  200. if (index == 6)
  201. *processor.getFloatParameter(cpi_octaves_extra1) = val;
  202. if (index == 7)
  203. *processor.getFloatParameter(cpi_octaves_extra2) = val;
  204. };
  205. m_ratiomixeditor.OnRatioChanged = [this](int index, double val)
  206. {
  207. *processor.getFloatParameter((int)cpi_octaves_ratio0 + index) = val;
  208. };
  209. m_wave_container->addAndMakeVisible(&m_wavecomponent);
  210. m_wavefilter_tab.addTab("Waveform", Colours::white, m_wave_container, true);
  211. m_wavefilter_tab.addTab("Ratio mixer", Colours::white, &m_ratiomixeditor, false);
  212. m_wavefilter_tab.addTab("Free filter", Colours::white, &m_free_filter_component, false);
  213. //m_wavefilter_tab.addTab("Spectrum", Colours::white, &m_sonogram, false);
  214. addAndMakeVisible(&m_wavefilter_tab);
  215. setSize (1200, 320+14*25);
  216. startTimer(1, 100);
  217. startTimer(2, 1000);
  218. startTimer(3, 200);
  219. m_wavecomponent.startTimer(100);
  220. }
  221. PaulstretchpluginAudioProcessorEditor::~PaulstretchpluginAudioProcessorEditor()
  222. {
  223. //Logger::writeToLog("PaulX Editor destroyed");
  224. }
  225. void PaulstretchpluginAudioProcessorEditor::showRenderDialog()
  226. {
  227. auto contentraw = new RenderSettingsComponent(&processor);
  228. contentraw->setSize(contentraw->getWidth(), contentraw->getPreferredHeight());
  229. std::unique_ptr<Component> content(contentraw);
  230. CallOutBox::launchAsynchronously(std::move(content), m_render_button.getBounds(), this);
  231. }
  232. void PaulstretchpluginAudioProcessorEditor::executeModalMenuAction(int menuid, int r)
  233. {
  234. if (r >= 200 && r < 210)
  235. {
  236. int caplen = m_capturelens[r - 200];
  237. *processor.getFloatParameter(cpi_max_capture_len) = (float)caplen;
  238. }
  239. if (r == 1)
  240. {
  241. toggleBool(processor.m_play_when_host_plays);
  242. }
  243. if (r == 2)
  244. {
  245. toggleBool(processor.m_capture_when_host_plays);
  246. }
  247. if (r == 8)
  248. {
  249. toggleBool(processor.m_mute_while_capturing);
  250. }
  251. if (r == 4)
  252. {
  253. processor.resetParameters();
  254. }
  255. if (r == 5)
  256. {
  257. toggleBool(processor.m_load_file_with_state);
  258. }
  259. if (r == 9)
  260. {
  261. toggleBool(processor.m_save_captured_audio);
  262. }
  263. if (r == 3)
  264. {
  265. showAbout();
  266. }
  267. if (r == 6)
  268. {
  269. ValueTree tree = processor.getStateTree(true, true);
  270. MemoryBlock destData;
  271. MemoryOutputStream stream(destData, true);
  272. tree.writeToStream(stream);
  273. String txt = Base64::toBase64(destData.getData(), destData.getSize());
  274. SystemClipboard::copyTextToClipboard(txt);
  275. }
  276. if (r == 7)
  277. {
  278. toggleBool(processor.m_show_technical_info);
  279. processor.m_propsfile->m_props_file->setValue("showtechnicalinfo", processor.m_show_technical_info);
  280. }
  281. }
  282. void PaulstretchpluginAudioProcessorEditor::paint (Graphics& g)
  283. {
  284. g.fillAll(Colours::darkgrey);
  285. }
  286. void PaulstretchpluginAudioProcessorEditor::resized()
  287. {
  288. m_import_button.setBounds(1, 1, 60, 24);
  289. m_import_button.changeWidthToFitText();
  290. m_settings_button.setBounds(m_import_button.getRight() + 1, 1, 60, 24);
  291. m_settings_button.changeWidthToFitText();
  292. int yoffs = m_settings_button.getRight() + 1;
  293. if (processor.wrapperType == AudioProcessor::wrapperType_Standalone)
  294. {
  295. m_render_button.setBounds(yoffs, 1, 60, 24);
  296. m_render_button.changeWidthToFitText();
  297. yoffs = m_render_button.getRight() + 1;
  298. }
  299. m_rewind_button.setBounds(yoffs, 1, 30, 24);
  300. yoffs = m_rewind_button.getRight() + 1;
  301. m_perfmeter.setBounds(yoffs, 1, 150, 24);
  302. m_info_label.setBounds(m_perfmeter.getRight() + 1, m_settings_button.getY(),
  303. getWidth()- m_perfmeter.getRight()-1, 24);
  304. int w = getWidth();
  305. int xoffs = 1;
  306. yoffs = 30;
  307. int div = w / 6;
  308. //std::vector<std::vector<int>> layout;
  309. //layout.emplace_back(cpi_capture_enabled, cpi_passthrough, cpi_pause_enabled, cpi_freeze);
  310. //layout.emplace_back(cpi_main_volume, cpi_num_inchans, cpi_num_outchans);
  311. m_parcomps[cpi_capture_trigger]->setBounds(xoffs, yoffs, div-1, 24);
  312. //xoffs += div;
  313. //m_parcomps[cpi_max_capture_len]->setBounds(xoffs, yoffs, div - 1, 24);
  314. xoffs += div;
  315. m_parcomps[cpi_passthrough]->setBounds(xoffs, yoffs, div - 1, 24);
  316. xoffs += div;
  317. m_parcomps[cpi_pause_enabled]->setBounds(xoffs, yoffs, div-1, 24);
  318. xoffs += div;
  319. m_parcomps[cpi_freeze]->setBounds(xoffs, yoffs, div - 1, 24);
  320. xoffs += div;
  321. m_parcomps[cpi_bypass_stretch]->setBounds(xoffs, yoffs, div - 1, 24);
  322. xoffs += div;
  323. m_parcomps[cpi_looping_enabled]->setBounds(xoffs, yoffs, div - 1, 24);
  324. xoffs = 1;
  325. yoffs += 25;
  326. div = w / 3;
  327. m_parcomps[cpi_main_volume]->setBounds(xoffs, yoffs, div-1, 24);
  328. xoffs += div;
  329. m_parcomps[cpi_num_inchans]->setBounds(xoffs, yoffs, div - 1, 24);
  330. xoffs += div;
  331. m_parcomps[cpi_num_outchans]->setBounds(xoffs, yoffs, div-1, 24);
  332. div = w / 2;
  333. xoffs = 1;
  334. yoffs += 25;
  335. m_parcomps[cpi_fftsize]->setBounds(xoffs, yoffs, div - 1, 24);
  336. xoffs += div;
  337. m_parcomps[cpi_stretchamount]->setBounds(xoffs, yoffs, div - 1, 24);
  338. m_parcomps[cpi_dryplayrate]->setBounds(xoffs, yoffs, div - 1, 24);
  339. xoffs = 1;
  340. yoffs += 25;
  341. m_parcomps[cpi_pitchshift]->setBounds(xoffs, yoffs, div - 1, 24);
  342. xoffs += div;
  343. m_parcomps[cpi_frequencyshift]->setBounds(xoffs, yoffs, div - 1, 24);
  344. xoffs = 1;
  345. yoffs += 25;
  346. m_parcomps[cpi_numharmonics]->setBounds(xoffs, yoffs, div - 1, 24);
  347. xoffs += div;
  348. m_parcomps[cpi_harmonicsfreq]->setBounds(xoffs, yoffs, div - 1, 24);
  349. xoffs = 1;
  350. yoffs += 25;
  351. m_parcomps[cpi_harmonicsbw]->setBounds(xoffs, yoffs, div - 1, 24);
  352. xoffs += div;
  353. m_parcomps[cpi_harmonicsgauss]->setBounds(xoffs, yoffs, div - 1, 24);
  354. xoffs = 1;
  355. yoffs += 25;
  356. m_parcomps[cpi_spreadamount]->setBounds(xoffs, yoffs, div - 1, 24);
  357. xoffs += div;
  358. m_parcomps[cpi_compress]->setBounds(xoffs, yoffs, div - 1, 24);
  359. xoffs = 1;
  360. yoffs += 25;
  361. m_parcomps[cpi_tonalvsnoisebw]->setBounds(xoffs, yoffs, div - 1, 24);
  362. xoffs += div;
  363. m_parcomps[cpi_tonalvsnoisepreserve]->setBounds(xoffs, yoffs, div - 1, 24);
  364. xoffs = 1;
  365. yoffs += 25;
  366. // filter here
  367. m_parcomps[cpi_filter_low]->setBounds(xoffs, yoffs, div - 1, 24);
  368. xoffs += div;
  369. m_parcomps[cpi_filter_high]->setBounds(xoffs, yoffs, div - 1, 24);
  370. xoffs = 1;
  371. yoffs += 25;
  372. m_parcomps[cpi_loopxfadelen]->setBounds(xoffs, yoffs, div - 1, 24);
  373. xoffs += div;
  374. m_parcomps[cpi_onsetdetection]->setBounds(xoffs, yoffs, div - 1, 24);
  375. xoffs = 1;
  376. yoffs += 25;
  377. m_parcomps[cpi_soundstart]->setBounds(xoffs, yoffs, div - 1, 24);
  378. xoffs += div;
  379. m_parcomps[cpi_soundend]->setBounds(xoffs, yoffs, div - 1, 24);
  380. //yoffs += 25;
  381. //xoffs = 1;
  382. yoffs += 25;
  383. int remain_h = getHeight() - 1 - yoffs;
  384. m_spec_order_ed.setBounds(1, yoffs, getWidth() - 2, remain_h / 9 * 1);
  385. m_wavefilter_tab.setBounds(1, m_spec_order_ed.getBottom() + 1, getWidth() - 2, remain_h / 9 * 8);
  386. m_wavecomponent.setBounds(m_wave_container->getX(), 0, m_wave_container->getWidth(),
  387. m_wave_container->getHeight()-16);
  388. m_zs.setBounds(m_wave_container->getX(), m_wavecomponent.getBottom(), m_wave_container->getWidth(), 15);
  389. //m_wavecomponent.setBounds(1, m_spec_order_ed.getBottom()+1, getWidth()-2, remain_h/5*4);
  390. }
  391. void PaulstretchpluginAudioProcessorEditor::timerCallback(int id)
  392. {
  393. if (id == 1)
  394. {
  395. for (int i = 0; i < m_parcomps.size(); ++i)
  396. {
  397. if (m_parcomps[i]!=nullptr)
  398. m_parcomps[i]->updateComponent();
  399. }
  400. m_free_filter_component.updateParameterComponents();
  401. if (processor.isRecordingEnabled())
  402. {
  403. m_wavecomponent.setRecordingPosition(processor.getRecordingPositionPercent());
  404. } else
  405. m_wavecomponent.setRecordingPosition(-1.0);
  406. m_wavecomponent.setAudioInfo(processor.getSampleRateChecked(), processor.getStretchSource()->getLastSeekPos(),
  407. processor.getStretchSource()->getFFTSize());
  408. String infotext;
  409. String waveinfotext;
  410. if (processor.m_show_technical_info)
  411. {
  412. double sr = processor.getStretchSource()->getInfileSamplerate();
  413. if (sr>0.0)
  414. waveinfotext += String(processor.getStretchSource()->getDiskReadSampleCount()/sr) + " seconds read from disk\n";
  415. waveinfotext += String(processor.m_prepare_count)+" prepareToPlay calls\n";
  416. waveinfotext += String(processor.getStretchSource()->m_param_change_count)+" parameter changes handled\n";
  417. waveinfotext += String(m_wavecomponent.m_image_init_count) + " waveform image inits\n"
  418. + String(m_wavecomponent.m_image_update_count) + " waveform image updates\n";
  419. m_wavecomponent.m_infotext = waveinfotext;
  420. }
  421. else
  422. m_wavecomponent.m_infotext = {};
  423. infotext += m_last_err + " [FFT size " +
  424. String(processor.getStretchSource()->getFFTSize())+"]";
  425. double outlen = processor.getStretchSource()->getOutputDurationSecondsForRange(processor.getStretchSource()->getPlayRange(),
  426. processor.getStretchSource()->getFFTSize());
  427. infotext += " [Output length " + secondsToString2(outlen)+"]";
  428. if (processor.m_abnormal_output_samples > 0)
  429. infotext += " " + String(processor.m_abnormal_output_samples) + " invalid sample values";
  430. if (processor.isNonRealtime())
  431. infotext += " (offline rendering)";
  432. if (processor.m_playposinfo.isPlaying)
  433. infotext += " "+String(processor.m_playposinfo.timeInSeconds,1);
  434. if (processor.m_offline_render_state >= 0 && processor.m_offline_render_state <= 100)
  435. infotext += String(processor.m_offline_render_state)+"%";
  436. if (processor.m_capture_save_state == 1)
  437. infotext += "Saving captured audio...";
  438. m_info_label.setText(infotext, dontSendNotification);
  439. }
  440. if (id == 2)
  441. {
  442. m_wavecomponent.setTimeSelection(processor.getTimeSelection());
  443. if (processor.m_state_dirty)
  444. {
  445. //m_spec_order_ed.setSource(processor.getStretchSource());
  446. processor.m_state_dirty = false;
  447. }
  448. }
  449. if (id == 3)
  450. {
  451. processor.m_free_filter_envelope->updateMinMaxValues();
  452. m_free_filter_component.repaint();
  453. m_spec_order_ed.repaint();
  454. m_parcomps[cpi_dryplayrate]->setVisible(*processor.getBoolParameter(cpi_bypass_stretch));
  455. m_parcomps[cpi_stretchamount]->setVisible(!(*processor.getBoolParameter(cpi_bypass_stretch)));
  456. //if (m_wavefilter_tab.getCurrentTabIndex() != processor.m_cur_tab_index)
  457. // m_wavefilter_tab.setCurrentTabIndex(processor.m_cur_tab_index, false);
  458. }
  459. }
  460. bool PaulstretchpluginAudioProcessorEditor::isInterestedInFileDrag(const StringArray & files)
  461. {
  462. if (files.size() == 0)
  463. return false;
  464. File f(files[0]);
  465. String extension = f.getFileExtension().toLowerCase();
  466. if (processor.m_afm->getWildcardForAllFormats().containsIgnoreCase(extension))
  467. return true;
  468. return false;
  469. }
  470. void PaulstretchpluginAudioProcessorEditor::filesDropped(const StringArray & files, int x, int y)
  471. {
  472. if (files.size() > 0)
  473. {
  474. File f(files[0]);
  475. processor.setAudioFile(f);
  476. toFront(true);
  477. }
  478. }
  479. bool PaulstretchpluginAudioProcessorEditor::keyPressed(const KeyPress & press)
  480. {
  481. std::function<bool(void)> action;
  482. if (press == 'I')
  483. action = [this]() { m_import_button.onClick(); ; return true; };
  484. return action && action();
  485. }
  486. void PaulstretchpluginAudioProcessorEditor::showSettingsMenu()
  487. {
  488. PopupMenu m_settings_menu;
  489. m_settings_menu.addItem(4, "Reset parameters", true, false);
  490. m_settings_menu.addItem(5, "Load file with plugin state", true, processor.m_load_file_with_state);
  491. m_settings_menu.addItem(1, "Play when host transport running", true, processor.m_play_when_host_plays);
  492. m_settings_menu.addItem(2, "Capture when host transport running", true, processor.m_capture_when_host_plays);
  493. m_settings_menu.addItem(8, "Mute audio while capturing", true, processor.m_mute_while_capturing);
  494. m_settings_menu.addItem(9, "Save captured audio to disk", true, processor.m_save_captured_audio);
  495. int capturelen = *processor.getFloatParameter(cpi_max_capture_len);
  496. PopupMenu capturelenmenu;
  497. for (int i=0;i<m_capturelens.size();++i)
  498. capturelenmenu.addItem(200+i, String(m_capturelens[i])+" seconds", true, capturelen == m_capturelens[i]);
  499. m_settings_menu.addSubMenu("Capture buffer length", capturelenmenu);
  500. m_settings_menu.addItem(3, "About...", true, false);
  501. #ifdef JUCE_DEBUG
  502. m_settings_menu.addItem(6, "Dump preset to clipboard", true, false);
  503. #endif
  504. m_settings_menu.addItem(7, "Show technical info", true, processor.m_show_technical_info);
  505. m_settings_menu.showMenuAsync(PopupMenu::Options(),
  506. ModalCallbackFunction::forComponent(handleSettingsMenuModalCallback, this));
  507. }
  508. void PaulstretchpluginAudioProcessorEditor::showAbout()
  509. {
  510. String fftlib = fftwf_version;
  511. String juceversiontxt = String("JUCE ") + String(JUCE_MAJOR_VERSION) + "." + String(JUCE_MINOR_VERSION);
  512. String title = g_plugintitle;
  513. #ifdef JUCE_DEBUG
  514. title += " (DEBUG)";
  515. #endif
  516. String vstInfo;
  517. if (processor.wrapperType == AudioProcessor::wrapperType_VST ||
  518. processor.wrapperType == AudioProcessor::wrapperType_VST3)
  519. vstInfo = "VST Plug-In Technology by Steinberg.\n\n";
  520. PluginHostType host;
  521. AlertWindow::showMessageBoxAsync(AlertWindow::InfoIcon,
  522. title,
  523. "Plugin for extreme time stretching and other sound processing\nBuilt on " + String(__DATE__) + " " + String(__TIME__) + "\n"
  524. "Copyright (C) 2006-2011 Nasca Octavian Paul, Tg. Mures, Romania\n"
  525. "(C) 2017-2019 Xenakios\n\n"+vstInfo+
  526. "Using " + fftlib + " for FFT\n\n"
  527. + juceversiontxt + " (c) Roli. Used under the GPL license.\n\n"
  528. "GPL licensed source code for this plugin at : https://bitbucket.org/xenakios/paulstretchplugin/overview\n"
  529. "Running in : "+host.getHostDescription()+"\n"
  530. , "OK",
  531. this);
  532. }
  533. void PaulstretchpluginAudioProcessorEditor::toggleFileBrowser()
  534. {
  535. if (m_filechooser == nullptr)
  536. {
  537. m_filechooser = std::make_unique<MyFileBrowserComponent>(processor);
  538. addChildComponent(m_filechooser.get());
  539. }
  540. m_filechooser->setBounds(0, 26, getWidth()/2, getHeight() - 75);
  541. m_filechooser->setVisible(!m_filechooser->isVisible());
  542. if (m_filechooser->isVisible())
  543. m_import_button.setButtonText("Hide browser");
  544. else
  545. m_import_button.setButtonText("Show browser");
  546. }
  547. WaveformComponent::WaveformComponent(AudioFormatManager* afm, AudioThumbnail* thumb, StretchAudioSource* sas)
  548. : m_sas(sas)
  549. {
  550. TimeSelectionChangedCallback = [](Range<double>, int) {};
  551. #ifdef JUCE_MODULE_AVAILABLE_juce_opengl
  552. if (m_use_opengl == true)
  553. m_ogl.attachTo(*this);
  554. #endif
  555. m_thumbnail = thumb;
  556. m_thumbnail->addChangeListener(this);
  557. setOpaque(true);
  558. }
  559. WaveformComponent::~WaveformComponent()
  560. {
  561. #ifdef JUCE_MODULE_AVAILABLE_juce_opengl
  562. if (m_use_opengl == true)
  563. m_ogl.detach();
  564. #endif
  565. m_thumbnail->removeChangeListener(this);
  566. }
  567. void WaveformComponent::changeListenerCallback(ChangeBroadcaster * /*cb*/)
  568. {
  569. jassert(MessageManager::getInstance()->isThisTheMessageThread());
  570. m_image_dirty = true;
  571. //repaint();
  572. }
  573. void WaveformComponent::updateCachedImage()
  574. {
  575. Graphics tempg(m_waveimage);
  576. tempg.fillAll(Colours::black);
  577. tempg.setColour(Colours::darkgrey);
  578. double thumblen = m_thumbnail->getTotalLength();
  579. m_thumbnail->drawChannels(tempg, { 0,0,getWidth(),getHeight() - m_topmargin },
  580. thumblen*m_view_range.getStart(), thumblen*m_view_range.getEnd(), 1.0f);
  581. m_image_dirty = false;
  582. ++m_image_update_count;
  583. }
  584. void WaveformComponent::paint(Graphics & g)
  585. {
  586. jassert(GetFileCallback);
  587. //Logger::writeToLog("Waveform component paint");
  588. g.fillAll(Colours::black);
  589. g.setColour(Colours::darkgrey);
  590. g.fillRect(0, 0, getWidth(), m_topmargin);
  591. if (m_thumbnail == nullptr || m_thumbnail->getTotalLength() < 0.01)
  592. {
  593. g.setColour(Colours::aqua.darker());
  594. g.drawText("No file loaded", 2, m_topmargin + 2, getWidth(), 20, Justification::topLeft);
  595. return;
  596. }
  597. g.setColour(Colours::lightslategrey);
  598. double thumblen = m_thumbnail->getTotalLength();
  599. double tick_interval = 1.0;
  600. if (thumblen > 60.0)
  601. tick_interval = 5.0;
  602. for (double secs = 0.0; secs < thumblen; secs += tick_interval)
  603. {
  604. float tickxcor = (float)jmap<double>(secs,
  605. thumblen*m_view_range.getStart(), thumblen*m_view_range.getEnd(), 0.0f, (float)getWidth());
  606. g.drawLine(tickxcor, 0.0, tickxcor, (float)m_topmargin, 1.0f);
  607. }
  608. bool m_use_cached_image = true;
  609. if (m_use_cached_image == true)
  610. {
  611. if (m_image_dirty == true || m_waveimage.getWidth() != getWidth()
  612. || m_waveimage.getHeight() != getHeight() - m_topmargin)
  613. {
  614. if (m_waveimage.getWidth() != getWidth()
  615. || m_waveimage.getHeight() != getHeight() - m_topmargin)
  616. {
  617. m_waveimage = Image(Image::ARGB, getWidth(), getHeight() - m_topmargin, true);
  618. ++m_image_init_count;
  619. }
  620. updateCachedImage();
  621. }
  622. g.drawImage(m_waveimage, 0, m_topmargin, getWidth(), getHeight() - m_topmargin, 0, 0, getWidth(), getHeight() - m_topmargin);
  623. }
  624. else
  625. {
  626. g.setColour(Colours::darkgrey);
  627. m_thumbnail->drawChannels(g, { 0,m_topmargin,getWidth(),getHeight() - m_topmargin },
  628. thumblen*m_view_range.getStart(), thumblen*m_view_range.getEnd(), 1.0f);
  629. }
  630. if (m_sr > 0.0 && m_fft_size > 0 && m_time_sel_start>=0.0)
  631. {
  632. tick_interval = 1.0 / m_sr * m_fft_size;
  633. /*
  634. for (double secs = m_time_sel_start*thumblen; secs < m_time_sel_end*thumblen; secs += tick_interval)
  635. {
  636. float tickxcor = (float)jmap<double>(fmod(secs, thumblen),
  637. thumblen*m_view_range.getStart(), thumblen*m_view_range.getEnd(), 0.0f, (float)getWidth());
  638. g.drawLine(tickxcor, (float)m_topmargin, tickxcor, (float)50, 2.0f);
  639. }
  640. */
  641. }
  642. if (m_is_at_selection_drag_area)
  643. g.setColour(Colours::white.withAlpha(0.6f));
  644. else
  645. g.setColour(Colours::white.withAlpha(0.5f));
  646. double sel_len = m_time_sel_end - m_time_sel_start;
  647. //if (sel_len > 0.0 && sel_len < 1.0)
  648. {
  649. int xcorleft = normalizedToViewX<int>(m_time_sel_start);
  650. int xcorright = normalizedToViewX<int>(m_time_sel_end);
  651. g.fillRect(xcorleft, m_topmargin, xcorright - xcorleft, getHeight() - m_topmargin);
  652. }
  653. if (m_file_cached.first.getLength() > 0.0 && m_infotext.isEmpty() == false)
  654. {
  655. g.setColour(Colours::red.withAlpha(0.2f));
  656. int xcorleft = (int)jmap<double>(m_file_cached.first.getStart(), m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  657. int xcorright = (int)jmap<double>(m_file_cached.first.getEnd(), m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  658. g.fillRect(xcorleft, 0, xcorright - xcorleft, getHeight());
  659. xcorleft = (int)jmap<double>(m_file_cached.second.getStart(), m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  660. xcorright = (int)jmap<double>(m_file_cached.second.getEnd(), m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  661. if (xcorright - xcorleft>0)
  662. {
  663. g.setColour(Colours::blue.withAlpha(0.2f));
  664. g.fillRect(xcorleft, m_topmargin / 2, xcorright - xcorleft, getHeight());
  665. }
  666. g.setColour(Colours::white);
  667. //g.drawText(toString(m_file_cached.first), 0, 30, 200, 30, Justification::centredLeft);
  668. g.drawMultiLineText(m_infotext, 0, 30, getWidth(), Justification::topLeft);
  669. }
  670. g.setColour(Colours::white);
  671. if (CursorPosCallback)
  672. {
  673. double timediff = (Time::getMillisecondCounterHiRes() - m_last_source_pos_update_time)*(1.0/m_sas->getRate());
  674. double curpos = ((double)m_last_source_pos / m_sas->getOutputSamplerate());
  675. double prebufoffset = (double)m_sas->m_prebuffersize / m_sas->getOutputSamplerate();
  676. curpos -= prebufoffset;
  677. curpos = 1.0 / m_sas->getInfileLengthSeconds()*(curpos+(timediff / 1000.0));
  678. //g.fillRect(normalizedToViewX<int>(curpos), m_topmargin, 1, getHeight() - m_topmargin);
  679. //g.drawText(String(curpos), 1, 30, 200,30, Justification::left);
  680. g.fillRect(normalizedToViewX<int>(CursorPosCallback()), m_topmargin, 1, getHeight() - m_topmargin);
  681. }
  682. if (m_rec_pos >= 0.0)
  683. {
  684. g.setColour(Colours::lightpink);
  685. g.fillRect(normalizedToViewX<int>(m_rec_pos), m_topmargin, 1, getHeight() - m_topmargin);
  686. }
  687. g.setColour(Colours::aqua);
  688. g.drawText(GetFileCallback().getFileName(), 2, m_topmargin + 2, getWidth(), 20, Justification::topLeft);
  689. g.drawText(secondsToString2(thumblen), getWidth() - 200, m_topmargin + 2, 200, 20, Justification::topRight);
  690. }
  691. void WaveformComponent::timerCallback()
  692. {
  693. if (m_sas->getLastSourcePosition() != m_last_source_pos)
  694. {
  695. m_last_source_pos = m_sas->getLastSourcePosition();
  696. m_last_source_pos_update_time = Time::getMillisecondCounterHiRes();
  697. }
  698. m_file_cached = m_sas->getFileCachedRangesNormalized();
  699. repaint();
  700. }
  701. void WaveformComponent::setFileCachedRange(std::pair<Range<double>, Range<double>> rng)
  702. {
  703. m_file_cached = rng;
  704. }
  705. void WaveformComponent::setTimerEnabled(bool b)
  706. {
  707. if (b == true)
  708. startTimer(100);
  709. else
  710. stopTimer();
  711. }
  712. void WaveformComponent::setViewRange(Range<double> rng)
  713. {
  714. m_view_range = rng;
  715. m_waveimage = Image();
  716. repaint();
  717. }
  718. void WaveformComponent::mouseDown(const MouseEvent & e)
  719. {
  720. m_mousedown = true;
  721. m_lock_timesel_set = true;
  722. double pos = viewXToNormalized(e.x);
  723. if (e.y < m_topmargin || e.mods.isCommandDown())
  724. {
  725. if (SeekCallback)
  726. {
  727. SeekCallback(pos);
  728. m_last_startpos = pos;
  729. }
  730. m_didseek = true;
  731. }
  732. else
  733. {
  734. m_time_sel_drag_target = getTimeSelectionEdge(e.x, e.y);
  735. m_drag_time_start = pos;
  736. if (m_time_sel_drag_target == 0)
  737. {
  738. //m_time_sel_start = 0.0;
  739. //m_time_sel_end = 1.0;
  740. }
  741. }
  742. repaint();
  743. }
  744. void WaveformComponent::mouseUp(const MouseEvent & /*e*/)
  745. {
  746. m_is_dragging_selection = false;
  747. m_lock_timesel_set = false;
  748. m_mousedown = false;
  749. m_didseek = false;
  750. if (m_didchangetimeselection)
  751. {
  752. TimeSelectionChangedCallback(Range<double>(m_time_sel_start, m_time_sel_end), 1);
  753. m_didchangetimeselection = false;
  754. }
  755. }
  756. void WaveformComponent::mouseDrag(const MouseEvent & e)
  757. {
  758. if (m_didseek == true)
  759. return;
  760. if (m_time_sel_drag_target == 0 && e.y>=50 && m_is_dragging_selection==false)
  761. {
  762. m_time_sel_start = m_drag_time_start;
  763. m_time_sel_end = viewXToNormalized(e.x);
  764. }
  765. double curlen = m_time_sel_end - m_time_sel_start;
  766. if (m_time_sel_drag_target == 0 && m_is_at_selection_drag_area)
  767. {
  768. m_is_dragging_selection = true;
  769. double diff = m_drag_time_start - viewXToNormalized(e.x);
  770. m_time_sel_start = jlimit<double>(0.0, 1.0-curlen, m_time_sel_start - diff);
  771. m_time_sel_end = jlimit<double>(curlen, 1.0, m_time_sel_end - diff);
  772. m_drag_time_start -= diff;
  773. }
  774. curlen = m_time_sel_end - m_time_sel_start;
  775. if (m_time_sel_drag_target == 1)
  776. {
  777. m_time_sel_start = viewXToNormalized(e.x);
  778. }
  779. if (m_time_sel_drag_target == 2)
  780. {
  781. m_time_sel_end = viewXToNormalized(e.x);
  782. }
  783. if (m_time_sel_start > m_time_sel_end)
  784. {
  785. std::swap(m_time_sel_start, m_time_sel_end);
  786. if (m_time_sel_drag_target == 1)
  787. m_time_sel_drag_target = 2;
  788. else if (m_time_sel_drag_target == 2)
  789. m_time_sel_drag_target = 1;
  790. }
  791. m_time_sel_start = jlimit(0.0, 1.0, m_time_sel_start);
  792. m_time_sel_end = jlimit(0.0, 1.0, m_time_sel_end);
  793. if (TimeSelectionChangedCallback)
  794. {
  795. if (m_time_sel_end>m_time_sel_start)
  796. TimeSelectionChangedCallback(Range<double>(m_time_sel_start, m_time_sel_end), 0);
  797. else
  798. TimeSelectionChangedCallback(Range<double>(0.0, 1.0), 0);
  799. }
  800. m_didchangetimeselection = true;
  801. repaint();
  802. }
  803. void WaveformComponent::mouseMove(const MouseEvent & e)
  804. {
  805. m_time_sel_drag_target = getTimeSelectionEdge(e.x, e.y);
  806. if (m_time_sel_drag_target == 0)
  807. setMouseCursor(MouseCursor::NormalCursor);
  808. if (m_time_sel_drag_target == 1)
  809. setMouseCursor(MouseCursor::LeftRightResizeCursor);
  810. if (m_time_sel_drag_target == 2)
  811. setMouseCursor(MouseCursor::LeftRightResizeCursor);
  812. Range<int> temp(normalizedToViewX<int>(m_time_sel_start), normalizedToViewX<int>(m_time_sel_end));
  813. m_is_at_selection_drag_area = temp.contains(e.x) == true && e.y < 50;
  814. }
  815. void WaveformComponent::mouseDoubleClick(const MouseEvent & e)
  816. {
  817. m_time_sel_start = 0.0;
  818. m_time_sel_end = 1.0;
  819. TimeSelectionChangedCallback({ 0.0,1.0 }, 0);
  820. repaint();
  821. }
  822. void WaveformComponent::mouseWheelMove(const MouseEvent & e, const MouseWheelDetails & wd)
  823. {
  824. return;
  825. /*
  826. double factor = 0.9;
  827. if (wd.deltaY < 0.0)
  828. factor = 1.11111;
  829. double normt = viewXToNormalized(e.x);
  830. double curlen = m_view_range.getLength();
  831. double newlen = curlen * factor;
  832. double oldt0 = m_view_range.getStart();
  833. double oldt1 = m_view_range.getEnd();
  834. double t0 = jlimit(0.0,1.0, normt + (curlen - newlen));
  835. double t1 = jlimit(0.0,1.0, t0+newlen);
  836. jassert(t1 > t0);
  837. m_view_range = { t0,t1 };
  838. //m_view_range = m_view_range.constrainRange({ 0.0, 1.0 });
  839. jassert(m_view_range.getStart() >= 0.0 && m_view_range.getEnd() <= 1.0);
  840. jassert(m_view_range.getLength() > 0.001);
  841. if (ViewRangeChangedCallback)
  842. ViewRangeChangedCallback(m_view_range);
  843. m_image_dirty = true;
  844. repaint();
  845. */
  846. }
  847. void WaveformComponent::setAudioInfo(double sr, double seekpos, int fftsize)
  848. {
  849. m_sr = sr;
  850. m_fft_size = fftsize;
  851. m_last_startpos = seekpos;
  852. }
  853. Range<double> WaveformComponent::getTimeSelection()
  854. {
  855. if (m_time_sel_start >= 0.0 && m_time_sel_end>m_time_sel_start + 0.001)
  856. return { m_time_sel_start, m_time_sel_end };
  857. return { 0.0, 1.0 };
  858. }
  859. void WaveformComponent::setTimeSelection(Range<double> rng)
  860. {
  861. if (m_lock_timesel_set == true)
  862. return;
  863. if (rng.isEmpty())
  864. rng = { -1.0,1.0 };
  865. m_time_sel_start = rng.getStart();
  866. m_time_sel_end = rng.getEnd();
  867. repaint();
  868. }
  869. int WaveformComponent::getTimeSelectionEdge(int x, int y)
  870. {
  871. int xcorleft = (int)jmap<double>(m_time_sel_start, m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  872. int xcorright = (int)jmap<double>(m_time_sel_end, m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  873. if (juce::Rectangle<int>(xcorleft - 5, m_topmargin, 10, getHeight() - m_topmargin).contains(x, y))
  874. return 1;
  875. if (juce::Rectangle<int>(xcorright - 5, m_topmargin, 10, getHeight() - m_topmargin).contains(x, y))
  876. return 2;
  877. return 0;
  878. }
  879. SpectralVisualizer::SpectralVisualizer()
  880. {
  881. m_img = Image(Image::RGB, 500, 200, true);
  882. }
  883. void SpectralVisualizer::setState(const ProcessParameters & pars, int nfreqs, double samplerate)
  884. {
  885. double t0 = Time::getMillisecondCounterHiRes();
  886. double hz = 440.0;
  887. int numharmonics = 40;
  888. double scaler = 1.0 / numharmonics;
  889. if (m_img.getWidth()!=getWidth() || m_img.getHeight()!=getHeight())
  890. m_img = Image(Image::RGB, getWidth(), getHeight(), true);
  891. if (m_nfreqs == 0 || nfreqs != m_nfreqs)
  892. {
  893. m_nfreqs = nfreqs;
  894. m_insamples = std::vector<REALTYPE>(nfreqs * 2);
  895. m_freqs1 = std::vector<REALTYPE>(nfreqs);
  896. m_freqs2 = std::vector<REALTYPE>(nfreqs);
  897. m_freqs3 = std::vector<REALTYPE>(nfreqs);
  898. m_fft = std::make_unique<FFT>(nfreqs*2);
  899. std::fill(m_insamples.begin(), m_insamples.end(), 0.0f);
  900. for (int i = 0; i < nfreqs; ++i)
  901. {
  902. for (int j = 0; j < numharmonics; ++j)
  903. {
  904. double oscgain = 1.0 - (1.0 / numharmonics)*j;
  905. m_insamples[i] += scaler * oscgain * sin(2 * c_PI / samplerate * i* (hz + hz * j));
  906. }
  907. }
  908. }
  909. //std::fill(m_freqs1.begin(), m_freqs1.end(), 0.0f);
  910. //std::fill(m_freqs2.begin(), m_freqs2.end(), 0.0f);
  911. //std::fill(m_freqs3.begin(), m_freqs3.end(), 0.0f);
  912. //std::fill(m_fft->freq.begin(), m_fft->freq.end(), 0.0f);
  913. for (int i = 0; i < nfreqs; ++i)
  914. {
  915. m_fft->smp[i] = m_insamples[i];
  916. }
  917. m_fft->applywindow(W_HAMMING);
  918. m_fft->smp2freq();
  919. double ratio = pow(2.0f, pars.pitch_shift.cents / 1200.0f);
  920. spectrum_do_pitch_shift(pars, nfreqs, m_fft->freq.data(), m_freqs2.data(), ratio);
  921. spectrum_do_freq_shift(pars, nfreqs, samplerate, m_freqs2.data(), m_freqs1.data());
  922. spectrum_do_compressor(pars, nfreqs, m_freqs1.data(), m_freqs2.data());
  923. spectrum_spread(nfreqs, samplerate, m_freqs3, m_freqs2.data(), m_freqs1.data(), pars.spread.bandwidth);
  924. //if (pars.harmonics.enabled)
  925. // spectrum_do_harmonics(pars, m_freqs3, nfreqs, samplerate, m_freqs1.data(), m_freqs2.data());
  926. //else spectrum_copy(nfreqs, m_freqs1.data(), m_freqs2.data());
  927. Graphics g(m_img);
  928. g.fillAll(Colours::black);
  929. g.setColour(Colours::white);
  930. for (int i = 0; i < nfreqs; ++i)
  931. {
  932. double binfreq = (samplerate / 2 / nfreqs)*i;
  933. double xcor = jmap<double>(binfreq, 0.0, samplerate / 2.0, 0.0, getWidth());
  934. double ycor = getHeight()- jmap<double>(m_freqs2[i], 0.0, nfreqs/128, 0.0, getHeight());
  935. ycor = jlimit<double>(0.0, getHeight(), ycor);
  936. g.drawLine(xcor, getHeight(), xcor, ycor, 1.0);
  937. }
  938. double t1 = Time::getMillisecondCounterHiRes();
  939. m_elapsed = t1 - t0;
  940. repaint();
  941. }
  942. void SpectralVisualizer::paint(Graphics & g)
  943. {
  944. g.drawImage(m_img, 0, 0, getWidth(), getHeight(), 0, 0, m_img.getWidth(), m_img.getHeight());
  945. g.setColour(Colours::yellow);
  946. g.drawText(String(m_elapsed, 1)+" ms", 1, 1, getWidth(), 30, Justification::topLeft);
  947. }
  948. void SpectralChainEditor::paint(Graphics & g)
  949. {
  950. g.fillAll(Colours::black);
  951. if (m_src == nullptr)
  952. return;
  953. int box_w = getWidth() / m_order.size();
  954. int box_h = getHeight();
  955. for (int i = 0; i < m_order.size(); ++i)
  956. {
  957. //if (i!=m_cur_index)
  958. drawBox(g, i, i*box_w, 0, box_w - 20, box_h);
  959. if (i<m_order.size() - 1)
  960. g.drawArrow(juce::Line<float>(i*box_w + (box_w - 20), box_h / 2, i*box_w + box_w, box_h / 2), 2.0f, 12.0f, 12.0f);
  961. }
  962. if (m_drag_x>=0 && m_drag_x<getWidth() && m_cur_index>=0)
  963. drawBox(g, m_cur_index, m_drag_x, 0, box_w - 30, box_h);
  964. }
  965. void SpectralChainEditor::setSource(StretchAudioSource * src)
  966. {
  967. m_src = src;
  968. m_order = m_src->getSpectrumProcessOrder();
  969. repaint();
  970. }
  971. void SpectralChainEditor::mouseDown(const MouseEvent & ev)
  972. {
  973. m_did_drag = false;
  974. int box_w = getWidth() / m_order.size();
  975. int box_h = getHeight();
  976. m_cur_index = ev.x / box_w;
  977. if (m_cur_index >= 0)
  978. {
  979. if (ModuleSelectedCallback)
  980. ModuleSelectedCallback(m_order[m_cur_index].m_index);
  981. juce::Rectangle<int> r(box_w*m_cur_index, 1, 12, 12);
  982. if (r.contains(ev.x, ev.y))
  983. {
  984. toggleBool(m_order[m_cur_index].m_enabled);
  985. repaint();
  986. return;
  987. }
  988. }
  989. m_drag_x = ev.x;
  990. repaint();
  991. }
  992. void SpectralChainEditor::mouseDrag(const MouseEvent & ev)
  993. {
  994. int box_w = getWidth() / m_order.size();
  995. juce::Rectangle<int> r(box_w*m_cur_index, 1, 12, 12);
  996. if (r.contains(ev.x, ev.y))
  997. return;
  998. if (m_cur_index >= 0 && m_cur_index < m_order.size())
  999. {
  1000. int box_h = getHeight();
  1001. int new_index = ev.x / box_w;
  1002. if (new_index >= 0 && new_index < m_order.size() && new_index != m_cur_index)
  1003. {
  1004. swapSpectrumProcesses(m_order[m_cur_index], m_order[new_index]);
  1005. m_cur_index = new_index;
  1006. m_did_drag = true;
  1007. m_src->setSpectrumProcessOrder(m_order);
  1008. if (ModuleOrderOrEnabledChangedCallback)
  1009. ModuleOrderOrEnabledChangedCallback();
  1010. }
  1011. int diff = m_drag_x - ev.x;
  1012. m_drag_x -= diff;
  1013. repaint();
  1014. }
  1015. }
  1016. void SpectralChainEditor::mouseUp(const MouseEvent & ev)
  1017. {
  1018. m_drag_x = -1;
  1019. //m_cur_index = -1;
  1020. repaint();
  1021. }
  1022. void SpectralChainEditor::setModuleSelected(int id)
  1023. {
  1024. if (id != m_cur_index)
  1025. {
  1026. m_cur_index = id;
  1027. repaint();
  1028. }
  1029. }
  1030. void SpectralChainEditor::moveModule(int old_id, int new_id)
  1031. {
  1032. if (old_id == m_cur_index)
  1033. return;
  1034. std::swap(m_order[old_id], m_order[new_id]);
  1035. m_cur_index = new_id;
  1036. m_src->setSpectrumProcessOrder(m_order);
  1037. repaint();
  1038. if (ModuleOrderOrEnabledChangedCallback)
  1039. ModuleOrderOrEnabledChangedCallback();
  1040. }
  1041. void SpectralChainEditor::drawBox(Graphics & g, int index, int x, int y, int w, int h)
  1042. {
  1043. jassert(m_order[index].m_enabled != nullptr);
  1044. String txt;
  1045. if (m_order[index].m_index == 0)
  1046. txt = "Harmonics";
  1047. if (m_order[index].m_index == 1)
  1048. txt = "Tonal vs Noise";
  1049. if (m_order[index].m_index == 2)
  1050. txt = "Frequency shift";
  1051. if (m_order[index].m_index == 3)
  1052. txt = "Pitch shift";
  1053. if (m_order[index].m_index == 4)
  1054. txt = "Ratios";
  1055. if (m_order[index].m_index == 5)
  1056. txt = "Spread";
  1057. if (m_order[index].m_index == 6)
  1058. txt = "Filter";
  1059. if (m_order[index].m_index == 8)
  1060. txt = "Compressor";
  1061. if (m_order[index].m_index == 7)
  1062. txt = "Free filter";
  1063. if (index == m_cur_index)
  1064. {
  1065. g.setColour(Colours::darkgrey);
  1066. //g.fillRect(i*box_w, 0, box_w - 30, box_h - 1);
  1067. g.fillRect(x, y, w, h);
  1068. }
  1069. g.setColour(Colours::white);
  1070. g.drawRect(x, y, w, h);
  1071. g.drawFittedText(txt, x,y,w,h-5, Justification::centredBottom, 3);
  1072. //g.drawFittedText(m_order[index].m_enabled->name, x, y, w, h, Justification::centred, 3);
  1073. g.setColour(Colours::gold);
  1074. g.drawRect(x + 2, y + 2, 12, 12);
  1075. if ((bool)*m_order[index].m_enabled == true)
  1076. {
  1077. g.drawLine(x+2, y+2, x+14, y+14);
  1078. g.drawLine(x+2, y+14, x+14, y+2);
  1079. }
  1080. g.setColour(Colours::white);
  1081. }
  1082. ParameterComponent::ParameterComponent(AudioProcessorParameter * par, bool notifyOnlyOnRelease) : m_par(par)
  1083. {
  1084. addAndMakeVisible(&m_label);
  1085. m_labeldefcolor = m_label.findColour(Label::textColourId);
  1086. m_label.setText(par->getName(50), dontSendNotification);
  1087. AudioParameterFloat* floatpar = dynamic_cast<AudioParameterFloat*>(par);
  1088. if (floatpar)
  1089. {
  1090. m_slider = XenUtils::makeAddAndMakeVisible<MySlider>(*this,&floatpar->range);
  1091. m_notify_only_on_release = notifyOnlyOnRelease;
  1092. m_slider->setRange(floatpar->range.start, floatpar->range.end, floatpar->range.interval);
  1093. m_slider->setValue(*floatpar, dontSendNotification);
  1094. m_slider->addListener(this);
  1095. m_slider->setDoubleClickReturnValue(true, floatpar->range.convertFrom0to1(par->getDefaultValue()));
  1096. }
  1097. AudioParameterInt* intpar = dynamic_cast<AudioParameterInt*>(par);
  1098. if (intpar)
  1099. {
  1100. m_slider = XenUtils::makeAddAndMakeVisible<MySlider>(*this);
  1101. m_notify_only_on_release = notifyOnlyOnRelease;
  1102. m_slider->setRange(intpar->getRange().getStart(), intpar->getRange().getEnd(), 1.0);
  1103. m_slider->setValue(*intpar, dontSendNotification);
  1104. m_slider->addListener(this);
  1105. }
  1106. AudioParameterChoice* choicepar = dynamic_cast<AudioParameterChoice*>(par);
  1107. if (choicepar)
  1108. {
  1109. }
  1110. AudioParameterBool* boolpar = dynamic_cast<AudioParameterBool*>(par);
  1111. if (boolpar)
  1112. {
  1113. m_togglebut = std::make_unique<ToggleButton>();
  1114. m_togglebut->setToggleState(*boolpar, dontSendNotification);
  1115. m_togglebut->addListener(this);
  1116. m_togglebut->setButtonText(par->getName(50));
  1117. addAndMakeVisible(m_togglebut.get());
  1118. }
  1119. }
  1120. void ParameterComponent::resized()
  1121. {
  1122. if (m_slider)
  1123. {
  1124. int labw = 200;
  1125. if (getWidth() < 400)
  1126. labw = 100;
  1127. m_label.setBounds(0, 0, labw, 24);
  1128. m_slider->setBounds(m_label.getRight() + 1, 0, getWidth() - 2 - m_label.getWidth(), 24);
  1129. }
  1130. if (m_togglebut)
  1131. m_togglebut->setBounds(1, 0, getWidth() - 1, 24);
  1132. }
  1133. void ParameterComponent::sliderValueChanged(Slider * slid)
  1134. {
  1135. if (m_notify_only_on_release == true)
  1136. return;
  1137. AudioParameterFloat* floatpar = dynamic_cast<AudioParameterFloat*>(m_par);
  1138. if (floatpar != nullptr)
  1139. *floatpar = slid->getValue();
  1140. AudioParameterInt* intpar = dynamic_cast<AudioParameterInt*>(m_par);
  1141. if (intpar != nullptr)
  1142. *intpar = slid->getValue();
  1143. }
  1144. void ParameterComponent::sliderDragStarted(Slider * slid)
  1145. {
  1146. m_dragging = true;
  1147. }
  1148. void ParameterComponent::sliderDragEnded(Slider * slid)
  1149. {
  1150. m_dragging = false;
  1151. if (m_notify_only_on_release == false)
  1152. return;
  1153. AudioParameterFloat* floatpar = dynamic_cast<AudioParameterFloat*>(m_par);
  1154. if (floatpar != nullptr)
  1155. *floatpar = slid->getValue();
  1156. AudioParameterInt* intpar = dynamic_cast<AudioParameterInt*>(m_par);
  1157. if (intpar != nullptr)
  1158. *intpar = slid->getValue();
  1159. }
  1160. void ParameterComponent::buttonClicked(Button * but)
  1161. {
  1162. AudioParameterBool* boolpar = dynamic_cast<AudioParameterBool*>(m_par);
  1163. if (m_togglebut != nullptr)
  1164. {
  1165. if (m_togglebut->getToggleState()!=*boolpar)
  1166. *boolpar = m_togglebut->getToggleState();
  1167. }
  1168. }
  1169. void ParameterComponent::updateComponent()
  1170. {
  1171. AudioParameterFloat* floatpar = dynamic_cast<AudioParameterFloat*>(m_par);
  1172. if (floatpar != nullptr && m_slider != nullptr && m_dragging == false && (float)m_slider->getValue() != *floatpar)
  1173. {
  1174. m_slider->setValue(*floatpar, dontSendNotification);
  1175. }
  1176. AudioParameterInt* intpar = dynamic_cast<AudioParameterInt*>(m_par);
  1177. if (intpar != nullptr && m_slider != nullptr && m_dragging == false && (int)m_slider->getValue() != *intpar)
  1178. {
  1179. m_slider->setValue(*intpar, dontSendNotification);
  1180. }
  1181. AudioParameterBool* boolpar = dynamic_cast<AudioParameterBool*>(m_par);
  1182. if (boolpar!=nullptr && m_togglebut != nullptr)
  1183. {
  1184. if (m_togglebut->getToggleState() != *boolpar)
  1185. m_togglebut->setToggleState(*boolpar, dontSendNotification);
  1186. }
  1187. }
  1188. void ParameterComponent::setHighLighted(bool b)
  1189. {
  1190. if (b == false)
  1191. {
  1192. m_label.setColour(Label::textColourId, m_labeldefcolor);
  1193. if (m_togglebut)
  1194. m_togglebut->setColour(ToggleButton::textColourId, m_labeldefcolor);
  1195. }
  1196. else
  1197. {
  1198. m_label.setColour(Label::textColourId, Colours::yellow);
  1199. if (m_togglebut)
  1200. m_togglebut->setColour(ToggleButton::textColourId, Colours::yellow);
  1201. }
  1202. }
  1203. MySlider::MySlider(NormalisableRange<float>* range) : m_range(range)
  1204. {
  1205. }
  1206. double MySlider::proportionOfLengthToValue(double x)
  1207. {
  1208. if (m_range)
  1209. return m_range->convertFrom0to1(x);
  1210. return Slider::proportionOfLengthToValue(x);
  1211. }
  1212. double MySlider::valueToProportionOfLength(double x)
  1213. {
  1214. if (m_range)
  1215. return m_range->convertTo0to1(x);
  1216. return Slider::valueToProportionOfLength(x);
  1217. }
  1218. PerfMeterComponent::PerfMeterComponent(PaulstretchpluginAudioProcessor * p)
  1219. : m_proc(p)
  1220. {
  1221. m_gradient.isRadial = false;
  1222. m_gradient.addColour(0.0, Colours::red);
  1223. m_gradient.addColour(0.25, Colours::yellow);
  1224. m_gradient.addColour(1.0, Colours::green);
  1225. startTimer(30);
  1226. }
  1227. void PerfMeterComponent::paint(Graphics & g)
  1228. {
  1229. m_gradient.point1 = {0.0f,0.0f};
  1230. m_gradient.point2 = {(float)getWidth(),0.0f};
  1231. g.fillAll(Colours::grey);
  1232. double amt = m_proc->getPreBufferingPercent();
  1233. g.setColour(Colours::green);
  1234. int w = amt * getWidth();
  1235. //g.setGradientFill(m_gradient);
  1236. g.fillRect(0, 0, w, getHeight());
  1237. g.setColour(Colours::white);
  1238. g.drawRect(0, 0, getWidth(), getHeight());
  1239. g.setFont(10.0f);
  1240. if (m_proc->getPreBufferAmount()>0)
  1241. g.drawText("PREBUFFER", 0, 0, getWidth(), getHeight(), Justification::centred);
  1242. else
  1243. g.drawText("NO PREBUFFER", 0, 0, getWidth(), getHeight(), Justification::centred);
  1244. }
  1245. void PerfMeterComponent::mouseDown(const MouseEvent & ev)
  1246. {
  1247. PopupMenu bufferingmenu;
  1248. int curbufamount = m_proc->getPreBufferAmount();
  1249. bufferingmenu.addItem(100, "None", true, curbufamount == -1);
  1250. bufferingmenu.addItem(101, "Small", true, curbufamount == 1);
  1251. bufferingmenu.addItem(102, "Medium", true, curbufamount == 2);
  1252. bufferingmenu.addItem(103, "Large", true, curbufamount == 3);
  1253. bufferingmenu.addItem(104, "Very large", true, curbufamount == 4);
  1254. bufferingmenu.addItem(105, "Huge", true, curbufamount == 5);
  1255. int r = bufferingmenu.show();
  1256. if (r >= 100 && r < 200)
  1257. {
  1258. if (r == 100)
  1259. m_proc->m_use_backgroundbuffering = false;
  1260. if (r > 100)
  1261. m_proc->setPreBufferAmount(r - 100);
  1262. }
  1263. }
  1264. void PerfMeterComponent::timerCallback()
  1265. {
  1266. repaint();
  1267. }
  1268. void zoom_scrollbar::mouseDown(const MouseEvent &e)
  1269. {
  1270. m_drag_start_x = e.x;
  1271. }
  1272. void zoom_scrollbar::mouseMove(const MouseEvent &e)
  1273. {
  1274. auto ha = get_hot_area(e.x, e.y);
  1275. if (ha == ha_left_edge || m_hot_area == ha_right_edge)
  1276. setMouseCursor(MouseCursor::LeftRightResizeCursor);
  1277. else
  1278. setMouseCursor(MouseCursor::NormalCursor);
  1279. if (ha != m_hot_area)
  1280. {
  1281. m_hot_area = ha;
  1282. repaint();
  1283. }
  1284. }
  1285. void zoom_scrollbar::mouseDrag(const MouseEvent &e)
  1286. {
  1287. if (m_hot_area == ha_none)
  1288. return;
  1289. if (m_hot_area == ha_left_edge)
  1290. {
  1291. double new_left_edge = 1.0 / getWidth()*e.x;
  1292. m_therange.setStart(jlimit(0.0, m_therange.getEnd() - 0.01, new_left_edge));
  1293. repaint();
  1294. }
  1295. if (m_hot_area == ha_right_edge)
  1296. {
  1297. double new_right_edge = 1.0 / getWidth()*e.x;
  1298. m_therange.setEnd(jlimit(m_therange.getStart() + 0.01, 1.0, new_right_edge));
  1299. repaint();
  1300. }
  1301. if (m_hot_area == ha_handle)
  1302. {
  1303. double delta = 1.0 / getWidth()*(e.x - m_drag_start_x);
  1304. //double old_start = m_start;
  1305. //double old_end = m_end;
  1306. double old_len = m_therange.getLength();
  1307. m_therange.setStart(jlimit(0.0, 1.0 - old_len, m_therange.getStart() + delta));
  1308. m_therange.setEnd(jlimit(old_len, m_therange.getStart() + old_len, m_therange.getEnd() + delta));
  1309. m_drag_start_x = e.x;
  1310. repaint();
  1311. }
  1312. if (RangeChanged)
  1313. RangeChanged(m_therange);
  1314. }
  1315. void zoom_scrollbar::mouseEnter(const MouseEvent & event)
  1316. {
  1317. m_hot_area = get_hot_area(event.x, event.y);
  1318. repaint();
  1319. }
  1320. void zoom_scrollbar::mouseExit(const MouseEvent &)
  1321. {
  1322. m_hot_area = ha_none;
  1323. repaint();
  1324. }
  1325. void zoom_scrollbar::paint(Graphics &g)
  1326. {
  1327. g.setColour(Colours::darkgrey);
  1328. g.fillRect(0, 0, getWidth(), getHeight());
  1329. int x0 = (int)(getWidth()*m_therange.getStart());
  1330. int x1 = (int)(getWidth()*m_therange.getEnd());
  1331. if (m_hot_area != ha_none)
  1332. g.setColour(Colours::white);
  1333. else g.setColour(Colours::lightgrey);
  1334. g.fillRect(x0, 0, x1 - x0, getHeight());
  1335. }
  1336. void zoom_scrollbar::setRange(Range<double> rng, bool docallback)
  1337. {
  1338. if (rng.isEmpty())
  1339. return;
  1340. m_therange = rng.constrainRange({ 0.0,1.0 });
  1341. if (RangeChanged && docallback)
  1342. RangeChanged(m_therange);
  1343. repaint();
  1344. }
  1345. zoom_scrollbar::hot_area zoom_scrollbar::get_hot_area(int x, int)
  1346. {
  1347. int x0 = (int)(getWidth()*m_therange.getStart());
  1348. int x1 = (int)(getWidth()*m_therange.getEnd());
  1349. if (is_in_range(x, x0 - 5, x0 + 5))
  1350. return ha_left_edge;
  1351. if (is_in_range(x, x1 - 5, x1 + 5))
  1352. return ha_right_edge;
  1353. if (is_in_range(x, x0 + 5, x1 - 5))
  1354. return ha_handle;
  1355. return ha_none;
  1356. }
  1357. RatioMixerEditor::RatioMixerEditor(int numratios)
  1358. {
  1359. for (int i = 0; i < numratios; ++i)
  1360. {
  1361. auto ratslid = std::make_unique<Slider>(Slider::LinearHorizontal,Slider::TextBoxBelow);
  1362. ratslid->setRange(0.125, 8.0);
  1363. ratslid->onValueChange = [this,i]() {OnRatioChanged(i, m_ratio_sliders[i]->getValue()); };
  1364. addAndMakeVisible(ratslid.get());
  1365. m_ratio_sliders.emplace_back(std::move(ratslid));
  1366. auto ratlevslid = std::make_unique<Slider>();
  1367. ratlevslid->setRange(0.0, 1.0);
  1368. ratlevslid->setSliderStyle(Slider::LinearVertical);
  1369. if (i==3)
  1370. ratlevslid->setValue(1.0,dontSendNotification);
  1371. else ratlevslid->setValue(0.0,dontSendNotification);
  1372. ratlevslid->onValueChange = [this, i]() { OnRatioLevelChanged(i, m_ratio_level_sliders[i]->getValue()); };
  1373. addAndMakeVisible(ratlevslid.get());
  1374. m_ratio_level_sliders.emplace_back(std::move(ratlevslid));
  1375. }
  1376. startTimer(200);
  1377. setOpaque(true);
  1378. }
  1379. void RatioMixerEditor::resized()
  1380. {
  1381. int nsliders = m_ratio_sliders.size();
  1382. int slidw = getWidth() / nsliders;
  1383. for (int i = 0; i < nsliders; ++i)
  1384. {
  1385. m_ratio_level_sliders[i]->setBounds(slidw/2+slidw * i-10, 15, 20, getHeight() - 55);
  1386. m_ratio_sliders[i]->setBounds(slidw * i, getHeight() - 48, slidw - 5, 47);
  1387. }
  1388. }
  1389. void RatioMixerEditor::timerCallback()
  1390. {
  1391. if (!GetParameterValue)
  1392. return;
  1393. for (int i = 0; i < m_ratio_level_sliders.size(); ++i)
  1394. {
  1395. double v = GetParameterValue(0, i);
  1396. if (v!=m_ratio_sliders[i]->getValue())
  1397. m_ratio_sliders[i]->setValue(v, dontSendNotification);
  1398. v = GetParameterValue(1, i);
  1399. if (v!=m_ratio_level_sliders[i]->getValue())
  1400. m_ratio_level_sliders[i]->setValue(v, dontSendNotification);
  1401. }
  1402. }
  1403. void RatioMixerEditor::paint(Graphics & g)
  1404. {
  1405. g.fillAll(Colours::grey);
  1406. g.setColour(Colours::white);
  1407. auto nsliders = m_ratio_sliders.size();
  1408. int slidw = getWidth() / nsliders;
  1409. for (int i = 0; i < 8; ++i)
  1410. g.drawText(String(i + 1), slidw / 2 + slidw * i - 8, 1, 15, 15, Justification::centred);
  1411. }
  1412. FreeFilterComponent::FreeFilterComponent(PaulstretchpluginAudioProcessor* proc)
  1413. : m_env(proc->getStretchSource()->getMutex()), m_cs(proc->getStretchSource()->getMutex()), m_proc(proc)
  1414. {
  1415. addAndMakeVisible(m_env);
  1416. const auto& pars = m_proc->getParameters();
  1417. m_parcomps.emplace_back(std::make_unique<ParameterComponent>(pars[cpi_freefilter_shiftx],false));
  1418. addAndMakeVisible(m_parcomps.back().get());
  1419. m_parcomps.emplace_back(std::make_unique<ParameterComponent>(pars[cpi_freefilter_shifty], false));
  1420. addAndMakeVisible(m_parcomps.back().get());
  1421. m_parcomps.emplace_back(std::make_unique<ParameterComponent>(pars[cpi_freefilter_scaley], false));
  1422. addAndMakeVisible(m_parcomps.back().get());
  1423. m_parcomps.emplace_back(std::make_unique<ParameterComponent>(pars[cpi_freefilter_tilty], false));
  1424. addAndMakeVisible(m_parcomps.back().get());
  1425. m_parcomps.emplace_back(std::make_unique<ParameterComponent>(pars[cpi_freefilter_randomy_numbands], false));
  1426. addAndMakeVisible(m_parcomps.back().get());
  1427. m_parcomps.emplace_back(std::make_unique<ParameterComponent>(pars[cpi_freefilter_randomy_rate], false));
  1428. addAndMakeVisible(m_parcomps.back().get());
  1429. m_parcomps.emplace_back(std::make_unique<ParameterComponent>(pars[cpi_freefilter_randomy_amount], false));
  1430. addAndMakeVisible(m_parcomps.back().get());
  1431. }
  1432. void FreeFilterComponent::resized()
  1433. {
  1434. m_env.setBounds(m_slidwidth, 0, getWidth() - m_slidwidth, getHeight());
  1435. for (int i = 0; i < m_parcomps.size(); ++i)
  1436. {
  1437. m_parcomps[i]->setBounds(1, 1+25*i, m_slidwidth - 2, 24);
  1438. }
  1439. }
  1440. void FreeFilterComponent::paint(Graphics & g)
  1441. {
  1442. g.setColour(Colours::grey);
  1443. g.fillRect(0, 0, m_slidwidth, getHeight());
  1444. }
  1445. void FreeFilterComponent::updateParameterComponents()
  1446. {
  1447. for (auto& e : m_parcomps)
  1448. e->updateComponent();
  1449. }
  1450. void AudioFilePreviewComponent::processBlock(double sr, AudioBuffer<float>& buf)
  1451. {
  1452. if (m_reader != nullptr)
  1453. {
  1454. m_reader->read(&buf, 0, buf.getNumSamples(), m_playpos, true, true);
  1455. m_playpos += buf.getNumSamples();
  1456. if (m_playpos >= m_reader->lengthInSamples)
  1457. m_playpos = 0;
  1458. }
  1459. }
  1460. MyFileBrowserComponent::MyFileBrowserComponent(PaulstretchpluginAudioProcessor & p) :
  1461. m_proc(p), m_filefilter(p.m_afm->getWildcardForAllFormats(),String(),String())
  1462. {
  1463. String initiallocfn = m_proc.m_propsfile->m_props_file->getValue("importfilefolder",
  1464. File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
  1465. File initialloc(initiallocfn);
  1466. m_fbcomp = std::make_unique<FileBrowserComponent>(1 | 4,
  1467. initialloc, &m_filefilter, nullptr);
  1468. m_fbcomp->addListener(this);
  1469. addAndMakeVisible(m_fbcomp.get());
  1470. setLookAndFeel(&m_filebwlookandfeel);
  1471. }
  1472. MyFileBrowserComponent::~MyFileBrowserComponent()
  1473. {
  1474. setLookAndFeel(nullptr);
  1475. }
  1476. void MyFileBrowserComponent::resized()
  1477. {
  1478. m_fbcomp->setBounds(0, 0, getWidth(), getHeight());
  1479. }
  1480. void MyFileBrowserComponent::paint(Graphics & g)
  1481. {
  1482. g.fillAll(Colours::black.withAlpha(0.8f));
  1483. }
  1484. void MyFileBrowserComponent::selectionChanged()
  1485. {
  1486. }
  1487. void MyFileBrowserComponent::fileClicked(const File & file, const MouseEvent & e)
  1488. {
  1489. }
  1490. void MyFileBrowserComponent::fileDoubleClicked(const File & file)
  1491. {
  1492. m_proc.setAudioFile(file);
  1493. m_proc.m_propsfile->m_props_file->setValue("importfilefolder", file.getParentDirectory().getFullPathName());
  1494. }
  1495. void MyFileBrowserComponent::browserRootChanged(const File & newRoot)
  1496. {
  1497. m_proc.m_propsfile->m_props_file->setValue("importfilefolder", newRoot.getFullPathName());
  1498. }