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.

467 lines
13KB

  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. #pragma once
  13. #include "../JuceLibraryCode/JuceHeader.h"
  14. #include "PluginProcessor.h"
  15. #include <memory>
  16. #include <vector>
  17. #include "envelope_component.h"
  18. class zoom_scrollbar : public Component
  19. {
  20. public:
  21. enum hot_area
  22. {
  23. ha_none,
  24. ha_left_edge,
  25. ha_right_edge,
  26. ha_handle
  27. };
  28. void mouseDown(const MouseEvent& e) override;
  29. void mouseMove(const MouseEvent& e) override;
  30. void mouseDrag(const MouseEvent& e) override;
  31. void mouseEnter(const MouseEvent &event) override;
  32. void mouseExit(const MouseEvent &event) override;
  33. void paint(Graphics &g) override;
  34. std::function<void(Range<double>)> RangeChanged;
  35. Range<double> get_range() const { return m_therange; }
  36. void setRange(Range<double> rng, bool docallback);
  37. private:
  38. Range<double> m_therange{ 0.0,1.0 };
  39. hot_area m_hot_area = ha_none;
  40. hot_area get_hot_area(int x, int y);
  41. int m_drag_start_x = 0;
  42. };
  43. class SpectralVisualizer : public Component
  44. {
  45. public:
  46. SpectralVisualizer();
  47. void setState(const ProcessParameters& pars, int nfreqs, double samplerate);
  48. void paint(Graphics& g) override;
  49. private:
  50. Image m_img;
  51. std::vector<REALTYPE> m_insamples,m_freqs1, m_freqs2, m_freqs3;
  52. std::unique_ptr<FFT> m_fft;
  53. int m_nfreqs = 0;
  54. double m_elapsed = 0.0;
  55. };
  56. class MySlider : public Slider
  57. {
  58. public:
  59. MySlider() {}
  60. MySlider(NormalisableRange<float>* range);
  61. double proportionOfLengthToValue(double x) override;
  62. double valueToProportionOfLength(double x) override;
  63. private:
  64. NormalisableRange<float>* m_range = nullptr;
  65. };
  66. class ParameterComponent : public Component,
  67. public Slider::Listener, public Button::Listener
  68. {
  69. public:
  70. ParameterComponent(AudioProcessorParameter* par, bool notifyOnlyOnRelease);
  71. void resized() override;
  72. void sliderValueChanged(Slider* slid) override;
  73. void sliderDragStarted(Slider* slid) override;
  74. void sliderDragEnded(Slider* slid) override;
  75. void buttonClicked(Button* but) override;
  76. void updateComponent();
  77. void setHighLighted(bool b);
  78. int m_group_id = -1;
  79. Slider* getSlider() { return m_slider.get(); }
  80. bool* m_nonparamstate = nullptr;
  81. private:
  82. Label m_label;
  83. AudioProcessorParameter* m_par = nullptr;
  84. std::unique_ptr<MySlider> m_slider;
  85. std::unique_ptr<ComboBox> m_combobox;
  86. std::unique_ptr<ToggleButton> m_togglebut;
  87. bool m_notify_only_on_release = false;
  88. bool m_dragging = false;
  89. Colour m_labeldefcolor;
  90. };
  91. class PerfMeterComponent : public Component, public Timer
  92. {
  93. public:
  94. PerfMeterComponent(PaulstretchpluginAudioProcessor* p);
  95. void paint(Graphics& g) override;
  96. void mouseDown(const MouseEvent& ev) override;
  97. void timerCallback() override;
  98. PaulstretchpluginAudioProcessor* m_proc = nullptr;
  99. private:
  100. ColourGradient m_gradient;
  101. };
  102. class MyThumbCache : public AudioThumbnailCache
  103. {
  104. public:
  105. MyThumbCache() : AudioThumbnailCache(200)
  106. {
  107. // The default priority of 2 is a bit too low in some cases, it seems...
  108. getTimeSliceThread().setPriority(3);
  109. }
  110. ~MyThumbCache() {}
  111. };
  112. class WaveformComponent : public Component, public ChangeListener, public Timer
  113. {
  114. public:
  115. WaveformComponent(AudioFormatManager* afm, AudioThumbnail* thumb, StretchAudioSource* sas);
  116. ~WaveformComponent();
  117. void changeListenerCallback(ChangeBroadcaster* cb) override;
  118. void paint(Graphics& g) override;
  119. void timerCallback() override;
  120. std::function<double()> CursorPosCallback;
  121. std::function<void(double)> SeekCallback;
  122. std::function<void(Range<double>, int)> TimeSelectionChangedCallback;
  123. std::function<File()> GetFileCallback;
  124. std::function<void(Range<double>)> ViewRangeChangedCallback;
  125. void mouseDown(const MouseEvent& e) override;
  126. void mouseUp(const MouseEvent& e) override;
  127. void mouseDrag(const MouseEvent& e) override;
  128. void mouseMove(const MouseEvent& e) override;
  129. void mouseDoubleClick(const MouseEvent& e) override;
  130. void mouseWheelMove(const MouseEvent& e, const MouseWheelDetails& wd) override;
  131. void setAudioInfo(double sr, double seekpos, int fftsize);
  132. Range<double> getTimeSelection();
  133. void setTimeSelection(Range<double> rng);
  134. void setFileCachedRange(std::pair<Range<double>, Range<double>> rng);
  135. void setTimerEnabled(bool b);
  136. void setViewRange(Range<double> rng);
  137. Value ShowFileCacheRange;
  138. void setRecordingPosition(double pos) { m_rec_pos = pos; }
  139. int m_image_init_count = 0;
  140. int m_image_update_count = 0;
  141. private:
  142. AudioThumbnail* m_thumbnail = nullptr;
  143. Range<double> m_view_range{ 0.0,1.0 };
  144. int m_time_sel_drag_target = 0;
  145. double m_time_sel_start = -1.0;
  146. double m_time_sel_end = -1.0;
  147. double m_drag_time_start = 0.0;
  148. bool m_mousedown = false;
  149. bool m_didseek = false;
  150. bool m_didchangetimeselection = false;
  151. int m_topmargin = 0;
  152. int getTimeSelectionEdge(int x, int y);
  153. std::pair<Range<double>, Range<double>> m_file_cached;
  154. bool m_image_dirty = false;
  155. double m_sr = 0.0;
  156. int m_fft_size = 0;
  157. double m_last_startpos = 0.0;
  158. int64_t m_last_source_pos = -1;
  159. double m_last_source_pos_update_time = 0.0;
  160. Image m_waveimage;
  161. StretchAudioSource* m_sas = nullptr;
  162. #ifdef JUCE_MODULE_AVAILABLE_juce_opengl
  163. OpenGLContext m_ogl;
  164. bool m_use_opengl = false;
  165. #endif
  166. double m_rec_pos = 0.0;
  167. bool m_lock_timesel_set = false;
  168. bool m_using_audio_buffer = false;
  169. bool m_is_at_selection_drag_area = false;
  170. bool m_is_dragging_selection = false;
  171. void updateCachedImage();
  172. double viewXToNormalized(double xcor)
  173. {
  174. return jmap<double>(xcor, 0, getWidth(), m_view_range.getStart(), m_view_range.getEnd());
  175. }
  176. template<typename T>
  177. inline T normalizedToViewX(double norm)
  178. {
  179. return static_cast<T>(jmap<double>(norm, m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth()));
  180. }
  181. };
  182. class SpectralChainEditor : public Component
  183. {
  184. public:
  185. SpectralChainEditor() {}
  186. void paint(Graphics& g) override;
  187. void setSource(StretchAudioSource* src);
  188. void mouseDown(const MouseEvent& ev) override;
  189. void mouseDrag(const MouseEvent& ev) override;
  190. void mouseUp(const MouseEvent& ev) override;
  191. std::function<void(int)> ModuleSelectedCallback;
  192. std::function<void(void)> ModuleOrderOrEnabledChangedCallback;
  193. const std::vector <SpectrumProcess>& getOrder() const { return m_order; }
  194. void setModuleSelected(int id);
  195. void moveModule(int old_id, int new_id);
  196. private:
  197. StretchAudioSource * m_src = nullptr;
  198. bool m_did_drag = false;
  199. int m_cur_index = -1;
  200. int m_drag_x = 0;
  201. std::vector<SpectrumProcess> m_order;
  202. void drawBox(Graphics& g, int index, int x, int y, int w, int h);
  203. };
  204. class RatioMixerEditor : public Component, public Timer
  205. {
  206. public:
  207. RatioMixerEditor(int numratios);
  208. void resized() override;
  209. std::function<void(int, double)> OnRatioChanged;
  210. std::function<void(int, double)> OnRatioLevelChanged;
  211. std::function<double(int which, int index)> GetParameterValue;
  212. void timerCallback() override;
  213. void paint(Graphics& g) override;
  214. private:
  215. uptrvec<Slider> m_ratio_sliders;
  216. uptrvec<Slider> m_ratio_level_sliders;
  217. };
  218. class FreeFilterComponent : public Component
  219. {
  220. public:
  221. FreeFilterComponent(PaulstretchpluginAudioProcessor* proc);
  222. void resized() override;
  223. EnvelopeComponent* getEnvelopeComponent() { return &m_env; }
  224. void paint(Graphics &g) override;
  225. void updateParameterComponents();
  226. private:
  227. EnvelopeComponent m_env;
  228. uptrvec<ParameterComponent> m_parcomps;
  229. CriticalSection* m_cs = nullptr;
  230. PaulstretchpluginAudioProcessor* m_proc = nullptr;
  231. int m_slidwidth = 400;
  232. };
  233. class MyTabComponent : public TabbedComponent
  234. {
  235. public:
  236. MyTabComponent(int& curtab) : TabbedComponent(TabbedButtonBar::TabsAtTop), m_cur_tab(curtab) {}
  237. void currentTabChanged(int newCurrentTabIndex, const String&) override
  238. {
  239. //m_cur_tab = newCurrentTabIndex;
  240. }
  241. private:
  242. int& m_cur_tab;
  243. };
  244. class SimpleFFTComponent : public Component,
  245. private Timer
  246. {
  247. public:
  248. SimpleFFTComponent() :
  249. forwardFFT(fftOrder),
  250. spectrogramImage(Image::RGB, 512, 512, true)
  251. {
  252. setOpaque(true);
  253. startTimerHz(60);
  254. }
  255. ~SimpleFFTComponent()
  256. {
  257. }
  258. void addAudioBlock(const AudioBuffer<float>& bufferToFill)
  259. {
  260. if (bufferToFill.getNumChannels() > 0)
  261. {
  262. const auto* channelData = bufferToFill.getReadPointer(0);
  263. for (auto i = 0; i < bufferToFill.getNumSamples(); ++i)
  264. pushNextSampleIntoFifo(channelData[i]);
  265. }
  266. }
  267. void resized() override
  268. {
  269. spectrogramImage = Image(Image::RGB, getWidth(), getHeight(), true);
  270. }
  271. void paint(Graphics& g) override
  272. {
  273. g.fillAll(Colours::black);
  274. g.setOpacity(1.0f);
  275. g.drawImage(spectrogramImage, getLocalBounds().toFloat());
  276. }
  277. void timerCallback() override
  278. {
  279. if (nextFFTBlockReady)
  280. {
  281. drawNextLineOfSpectrogram();
  282. nextFFTBlockReady = false;
  283. repaint();
  284. }
  285. }
  286. void pushNextSampleIntoFifo(float sample) noexcept
  287. {
  288. // if the fifo contains enough data, set a flag to say
  289. // that the next line should now be rendered..
  290. if (fifoIndex == fftSize)
  291. {
  292. if (!nextFFTBlockReady)
  293. {
  294. zeromem(fftData, sizeof(fftData));
  295. memcpy(fftData, fifo, sizeof(fifo));
  296. nextFFTBlockReady = true;
  297. }
  298. fifoIndex = 0;
  299. }
  300. fifo[fifoIndex++] = sample;
  301. }
  302. void drawNextLineOfSpectrogram()
  303. {
  304. auto rightHandEdge = spectrogramImage.getWidth() - 1;
  305. auto imageHeight = spectrogramImage.getHeight();
  306. // first, shuffle our image leftwards by 1 pixel..
  307. spectrogramImage.moveImageSection(0, 0, 1, 0, rightHandEdge, imageHeight);
  308. // then render our FFT data..
  309. forwardFFT.performFrequencyOnlyForwardTransform(fftData);
  310. // find the range of values produced, so we can scale our rendering to
  311. // show up the detail clearly
  312. auto maxLevel = FloatVectorOperations::findMinAndMax(fftData, fftSize / 2);
  313. for (auto y = 1; y < imageHeight; ++y)
  314. {
  315. auto skewedProportionY = 1.0f - std::exp(std::log(y / (float)imageHeight) * 0.2f);
  316. auto fftDataIndex = jlimit(0, fftSize / 2, (int)(skewedProportionY * fftSize / 2));
  317. auto level = jmap(fftData[fftDataIndex], 0.0f, jmax(maxLevel.getEnd(), 1e-5f), 0.0f, 1.0f);
  318. spectrogramImage.setPixelAt(rightHandEdge, y, Colour::fromHSV(level, 1.0f, level, 1.0f));
  319. }
  320. }
  321. enum
  322. {
  323. fftOrder = 10,
  324. fftSize = 1 << fftOrder
  325. };
  326. private:
  327. dsp::FFT forwardFFT;
  328. Image spectrogramImage;
  329. float fifo[fftSize];
  330. float fftData[8 * fftSize];
  331. int fifoIndex = 0;
  332. bool nextFFTBlockReady = false;
  333. };
  334. class AudioFilePreviewComponent : public FilePreviewComponent
  335. {
  336. public:
  337. AudioFilePreviewComponent(PaulstretchpluginAudioProcessor* p) : m_proc(p)
  338. {
  339. addAndMakeVisible(m_playbut);
  340. m_playbut.setButtonText("Play");
  341. m_playbut.onClick = [this]()
  342. {
  343. };
  344. setSize(100, 30);
  345. }
  346. void selectedFileChanged(const File &newSelectedFile) override
  347. {
  348. ScopedLock locker(m_proc->getCriticalSection());
  349. m_reader = unique_from_raw(m_proc->m_afm->createReaderFor(newSelectedFile));
  350. m_playpos = 0;
  351. }
  352. void resized() override
  353. {
  354. m_playbut.setBounds(0, 0, getWidth(), getHeight());
  355. }
  356. void togglePlay()
  357. {
  358. }
  359. void processBlock(double sr, AudioBuffer<float>& buf);
  360. private:
  361. TextButton m_playbut;
  362. PaulstretchpluginAudioProcessor* m_proc = nullptr;
  363. std::unique_ptr<AudioFormatReader> m_reader;
  364. int64 m_playpos = 0;
  365. };
  366. class PaulstretchpluginAudioProcessorEditor : public AudioProcessorEditor,
  367. public MultiTimer, public FileDragAndDropTarget, public DragAndDropContainer
  368. {
  369. public:
  370. PaulstretchpluginAudioProcessorEditor (PaulstretchpluginAudioProcessor&);
  371. ~PaulstretchpluginAudioProcessorEditor();
  372. void paint (Graphics&) override;
  373. void resized() override;
  374. void timerCallback(int id) override;
  375. bool isInterestedInFileDrag(const StringArray &files) override;
  376. void filesDropped(const StringArray &files, int x, int y) override;
  377. bool keyPressed(const KeyPress& press) override;
  378. WaveformComponent m_wavecomponent;
  379. void chooseFile();
  380. void showRenderDialog();
  381. void executeModalMenuAction(int menuid, int actionid);
  382. SimpleFFTComponent m_sonogram;
  383. String m_last_err;
  384. private:
  385. PaulstretchpluginAudioProcessor& processor;
  386. uptrvec<ParameterComponent> m_parcomps;
  387. //SpectralVisualizer m_specvis;
  388. PerfMeterComponent m_perfmeter;
  389. TextButton m_import_button;
  390. TextButton m_settings_button;
  391. TextButton m_render_button;
  392. TextButton m_rewind_button;
  393. Label m_info_label;
  394. SpectralChainEditor m_spec_order_ed;
  395. void showSettingsMenu();
  396. zoom_scrollbar m_zs;
  397. RatioMixerEditor m_ratiomixeditor{ 8 };
  398. FreeFilterComponent m_free_filter_component;
  399. MyTabComponent m_wavefilter_tab;
  400. Component* m_wave_container=nullptr;
  401. void showAbout();
  402. std::vector<int> m_capturelens{ 2,5,10,30,60,120 };
  403. std::unique_ptr<FileChooser> m_filechooser;
  404. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PaulstretchpluginAudioProcessorEditor)
  405. };