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.

345 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file was auto-generated!
  4. It contains the basic framework code for a JUCE plugin editor.
  5. ==============================================================================
  6. */
  7. #include "PluginProcessor.h"
  8. #include "PluginEditor.h"
  9. //==============================================================================
  10. PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor (PaulstretchpluginAudioProcessor& p)
  11. : AudioProcessorEditor (&p), processor (p), m_wavecomponent(p.m_afm.get())
  12. {
  13. addAndMakeVisible(&m_info_label);
  14. addAndMakeVisible(&m_wavecomponent);
  15. const auto& pars = processor.getParameters();
  16. for (int i=0;i<pars.size();++i)
  17. {
  18. m_parcomps.push_back(std::make_shared<ParameterComponent>(pars[i]));
  19. m_parcomps.back()->setBounds(1, i * 25, 598, 24);
  20. addAndMakeVisible(m_parcomps.back().get());
  21. }
  22. addAndMakeVisible(&m_rec_enable);
  23. m_rec_enable.setButtonText("Capture");
  24. m_rec_enable.addListener(this);
  25. setSize (700, pars.size()*25+200);
  26. m_wavecomponent.TimeSelectionChangedCallback = [this](Range<double> range, int which)
  27. {
  28. *processor.getFloatParameter(5) = range.getStart();
  29. *processor.getFloatParameter(6) = range.getEnd();
  30. };
  31. m_wavecomponent.ShowFileCacheRange = true;
  32. startTimer(1, 100);
  33. }
  34. PaulstretchpluginAudioProcessorEditor::~PaulstretchpluginAudioProcessorEditor()
  35. {
  36. }
  37. void PaulstretchpluginAudioProcessorEditor::buttonClicked(Button * but)
  38. {
  39. if (but == &m_rec_enable)
  40. {
  41. processor.setRecordingEnabled(but->getToggleState());
  42. }
  43. }
  44. //==============================================================================
  45. void PaulstretchpluginAudioProcessorEditor::paint (Graphics& g)
  46. {
  47. g.fillAll(Colours::darkgrey);
  48. }
  49. void PaulstretchpluginAudioProcessorEditor::resized()
  50. {
  51. m_rec_enable.setBounds(1, m_parcomps.back()->getBottom()+1, 10, 24);
  52. m_rec_enable.changeWidthToFitText();
  53. m_info_label.setBounds(m_rec_enable.getRight() + 1, m_rec_enable.getY(), 60, 24);
  54. m_wavecomponent.setBounds(1, m_info_label.getBottom()+1, getWidth()-2, getHeight()-1-m_info_label.getBottom());
  55. }
  56. void PaulstretchpluginAudioProcessorEditor::timerCallback(int id)
  57. {
  58. if (id == 1)
  59. {
  60. for (auto& e : m_parcomps)
  61. e->updateComponent();
  62. if (processor.isRecordingEnabled() != m_rec_enable.getToggleState())
  63. m_rec_enable.setToggleState(processor.isRecordingEnabled(), dontSendNotification);
  64. m_info_label.setText(String(processor.getRecordingPositionPercent()*100.0, 1),dontSendNotification);
  65. }
  66. }
  67. void PaulstretchpluginAudioProcessorEditor::setAudioFile(File f)
  68. {
  69. m_wavecomponent.setAudioFile(f);
  70. }
  71. void PaulstretchpluginAudioProcessorEditor::setAudioBuffer(AudioBuffer<float>* buf, int samplerate, int len)
  72. {
  73. MessageManager::callAsync([this,buf, samplerate, len]()
  74. {
  75. m_wavecomponent.setAudioBuffer(buf, samplerate, len);
  76. });
  77. }
  78. WaveformComponent::WaveformComponent(AudioFormatManager* afm) : m_thumbcache(100)
  79. {
  80. TimeSelectionChangedCallback = [](Range<double>, int) {};
  81. if (m_use_opengl == true)
  82. m_ogl.attachTo(*this);
  83. // The default priority of 2 is a bit too low in some cases, it seems...
  84. m_thumbcache.getTimeSliceThread().setPriority(3);
  85. m_thumb = std::make_unique<AudioThumbnail>(512, *afm, m_thumbcache);
  86. m_thumb->addChangeListener(this);
  87. setOpaque(true);
  88. }
  89. WaveformComponent::~WaveformComponent()
  90. {
  91. if (m_use_opengl == true)
  92. m_ogl.detach();
  93. }
  94. void WaveformComponent::changeListenerCallback(ChangeBroadcaster * /*cb*/)
  95. {
  96. m_waveimage = Image();
  97. repaint();
  98. }
  99. void WaveformComponent::paint(Graphics & g)
  100. {
  101. //Logger::writeToLog("Waveform component paint");
  102. g.fillAll(Colours::black);
  103. g.setColour(Colours::darkgrey);
  104. g.fillRect(0, 0, getWidth(), m_topmargin);
  105. if (m_thumb == nullptr || m_thumb->getTotalLength() < 0.1)
  106. {
  107. g.setColour(Colours::aqua.darker());
  108. g.drawText("No file loaded", 2, m_topmargin + 2, getWidth(), 20, Justification::topLeft);
  109. return;
  110. }
  111. g.setColour(Colours::lightslategrey);
  112. double thumblen = m_thumb->getTotalLength();
  113. double tick_interval = 1.0;
  114. if (thumblen > 60.0)
  115. tick_interval = 5.0;
  116. for (double secs = 0.0; secs < thumblen; secs += tick_interval)
  117. {
  118. float tickxcor = (float)jmap<double>(secs,
  119. thumblen*m_view_range.getStart(), thumblen*m_view_range.getEnd(), 0.0f, (float)getWidth());
  120. g.drawLine(tickxcor, 0.0, tickxcor, (float)m_topmargin, 1.0f);
  121. }
  122. bool m_use_cached_image = true;
  123. if (m_use_cached_image == true)
  124. {
  125. if (m_waveimage.isValid() == false || m_waveimage.getWidth() != getWidth()
  126. || m_waveimage.getHeight() != getHeight() - m_topmargin)
  127. {
  128. //Logger::writeToLog("updating cached waveform image");
  129. m_waveimage = Image(Image::ARGB, getWidth(), getHeight() - m_topmargin, true);
  130. Graphics tempg(m_waveimage);
  131. tempg.fillAll(Colours::black);
  132. tempg.setColour(Colours::darkgrey);
  133. m_thumb->drawChannels(tempg, { 0,0,getWidth(),getHeight() - m_topmargin },
  134. thumblen*m_view_range.getStart(), thumblen*m_view_range.getEnd(), 1.0f);
  135. }
  136. g.drawImage(m_waveimage, 0, m_topmargin, getWidth(), getHeight() - m_topmargin, 0, 0, getWidth(), getHeight() - m_topmargin);
  137. }
  138. else
  139. {
  140. //g.fillAll(Colours::black);
  141. g.setColour(Colours::darkgrey);
  142. m_thumb->drawChannels(g, { 0,m_topmargin,getWidth(),getHeight() - m_topmargin },
  143. thumblen*m_view_range.getStart(), thumblen*m_view_range.getEnd(), 1.0f);
  144. }
  145. //g.setColour(Colours::darkgrey);
  146. //m_thumb->drawChannels(g, { 0,m_topmargin,getWidth(),getHeight()-m_topmargin },
  147. // 0.0, thumblen, 1.0f);
  148. g.setColour(Colours::white.withAlpha(0.5f));
  149. int xcorleft = (int)jmap<double>(m_time_sel_start, m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  150. int xcorright = (int)jmap<double>(m_time_sel_end, m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  151. g.fillRect(xcorleft, m_topmargin, xcorright - xcorleft, getHeight() - m_topmargin);
  152. if (m_file_cached.first.getLength() > 0.0 &&
  153. (bool)ShowFileCacheRange.getValue())
  154. {
  155. g.setColour(Colours::red.withAlpha(0.2f));
  156. xcorleft = (int)jmap<double>(m_file_cached.first.getStart(), m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  157. xcorright = (int)jmap<double>(m_file_cached.first.getEnd(), m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  158. g.fillRect(xcorleft, 0, xcorright - xcorleft, m_topmargin / 2);
  159. xcorleft = (int)jmap<double>(m_file_cached.second.getStart(), m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  160. xcorright = (int)jmap<double>(m_file_cached.second.getEnd(), m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  161. if (xcorright - xcorleft>0)
  162. {
  163. g.setColour(Colours::blue.withAlpha(0.2f));
  164. g.fillRect(xcorleft, m_topmargin / 2, xcorright - xcorleft, m_topmargin / 2);
  165. }
  166. }
  167. g.setColour(Colours::white);
  168. if (CursorPosCallback)
  169. {
  170. double pos = jmap<double>(CursorPosCallback(), m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  171. g.fillRect((int)pos, m_topmargin, 1, getHeight() - m_topmargin);
  172. }
  173. g.setColour(Colours::aqua.darker());
  174. g.drawText(m_curfile.getFullPathName(), 2, m_topmargin + 2, getWidth(), 20, Justification::topLeft);
  175. }
  176. void WaveformComponent::setAudioFile(File f)
  177. {
  178. if (f.existsAsFile())
  179. {
  180. m_waveimage = Image();
  181. if (m_thumb != nullptr && f == m_curfile) // reloading same file, might happen that the overview needs to be redone...
  182. m_thumbcache.removeThumb(m_thumb->getHashCode());
  183. m_thumb->setSource(new FileInputSource(f));
  184. m_curfile = f;
  185. }
  186. else
  187. {
  188. m_thumb->setSource(nullptr);
  189. }
  190. }
  191. void WaveformComponent::setAudioBuffer(AudioBuffer<float>* buf, int samplerate, int len)
  192. {
  193. m_waveimage = Image();
  194. m_curfile = File();
  195. m_thumb->reset(buf->getNumChannels(), samplerate, len);
  196. m_thumb->addBlock(0, *buf, 0, len);
  197. }
  198. void WaveformComponent::timerCallback()
  199. {
  200. repaint();
  201. }
  202. void WaveformComponent::setFileCachedRange(std::pair<Range<double>, Range<double>> rng)
  203. {
  204. m_file_cached = rng;
  205. //repaint();
  206. }
  207. void WaveformComponent::setTimerEnabled(bool b)
  208. {
  209. if (b == true)
  210. startTimer(100);
  211. else
  212. stopTimer();
  213. }
  214. void WaveformComponent::setViewRange(Range<double> rng)
  215. {
  216. m_view_range = rng;
  217. m_waveimage = Image();
  218. repaint();
  219. }
  220. void WaveformComponent::mouseDown(const MouseEvent & e)
  221. {
  222. m_mousedown = true;
  223. double pos = jmap<double>(e.x, 0, getWidth(), m_view_range.getStart(), m_view_range.getEnd());
  224. if (e.y < m_topmargin)
  225. {
  226. if (SeekCallback)
  227. SeekCallback(pos);
  228. m_didseek = true;
  229. }
  230. else
  231. {
  232. m_time_sel_drag_target = getTimeSelectionEdge(e.x, e.y);
  233. m_drag_time_start = pos;
  234. if (m_time_sel_drag_target == 0)
  235. {
  236. m_time_sel_start = -1.0;
  237. m_time_sel_end = -1.0;
  238. }
  239. }
  240. repaint();
  241. }
  242. void WaveformComponent::mouseUp(const MouseEvent & /*e*/)
  243. {
  244. m_mousedown = false;
  245. m_didseek = false;
  246. if (m_didchangetimeselection)
  247. {
  248. TimeSelectionChangedCallback(Range<double>(m_time_sel_start, m_time_sel_end), 1);
  249. m_didchangetimeselection = false;
  250. }
  251. }
  252. void WaveformComponent::mouseDrag(const MouseEvent & e)
  253. {
  254. if (m_didseek == true)
  255. return;
  256. if (m_time_sel_drag_target == 0)
  257. {
  258. m_time_sel_start = m_drag_time_start;
  259. m_time_sel_end = jmap<double>(e.x, 0, getWidth(), m_view_range.getStart(), m_view_range.getEnd());
  260. }
  261. if (m_time_sel_drag_target == 1)
  262. {
  263. m_time_sel_start = jmap<double>(e.x, 0, getWidth(), m_view_range.getStart(), m_view_range.getEnd());
  264. }
  265. if (m_time_sel_drag_target == 2)
  266. {
  267. m_time_sel_end = jmap<double>(e.x, 0, getWidth(), m_view_range.getStart(), m_view_range.getEnd());
  268. }
  269. if (m_time_sel_start > m_time_sel_end)
  270. {
  271. std::swap(m_time_sel_start, m_time_sel_end);
  272. if (m_time_sel_drag_target == 1)
  273. m_time_sel_drag_target = 2;
  274. else if (m_time_sel_drag_target == 2)
  275. m_time_sel_drag_target = 1;
  276. }
  277. m_time_sel_start = jlimit(0.0, 1.0, m_time_sel_start);
  278. m_time_sel_end = jlimit(0.0, 1.0, m_time_sel_end);
  279. if (TimeSelectionChangedCallback)
  280. {
  281. if (m_time_sel_end>m_time_sel_start)
  282. TimeSelectionChangedCallback(Range<double>(m_time_sel_start, m_time_sel_end), 0);
  283. else
  284. TimeSelectionChangedCallback(Range<double>(0.0, 1.0), 0);
  285. }
  286. m_didchangetimeselection = true;
  287. repaint();
  288. }
  289. void WaveformComponent::mouseMove(const MouseEvent & e)
  290. {
  291. m_time_sel_drag_target = getTimeSelectionEdge(e.x, e.y);
  292. if (m_time_sel_drag_target == 0)
  293. setMouseCursor(MouseCursor::NormalCursor);
  294. if (m_time_sel_drag_target == 1)
  295. setMouseCursor(MouseCursor::LeftRightResizeCursor);
  296. if (m_time_sel_drag_target == 2)
  297. setMouseCursor(MouseCursor::LeftRightResizeCursor);
  298. }
  299. int WaveformComponent::getTimeSelectionEdge(int x, int y)
  300. {
  301. int xcorleft = (int)jmap<double>(m_time_sel_start, m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  302. int xcorright = (int)jmap<double>(m_time_sel_end, m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth());
  303. if (juce::Rectangle<int>(xcorleft - 5, m_topmargin, 10, getHeight() - m_topmargin).contains(x, y))
  304. return 1;
  305. if (juce::Rectangle<int>(xcorright - 5, m_topmargin, 10, getHeight() - m_topmargin).contains(x, y))
  306. return 2;
  307. return 0;
  308. }