The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

267 lines
8.2KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. #pragma once
  20. #include "../JuceLibraryCode/JuceHeader.h"
  21. //==============================================================================
  22. class AudioThumbnailComponent : public Component,
  23. public FileDragAndDropTarget,
  24. public ChangeBroadcaster,
  25. private ChangeListener,
  26. private Timer
  27. {
  28. public:
  29. AudioThumbnailComponent (AudioDeviceManager& adm, AudioFormatManager& afm)
  30. : audioDeviceManager (adm),
  31. thumbnailCache (5),
  32. thumbnail (128, afm, thumbnailCache)
  33. {
  34. thumbnail.addChangeListener (this);
  35. }
  36. ~AudioThumbnailComponent()
  37. {
  38. thumbnail.removeChangeListener (this);
  39. }
  40. void paint (Graphics& g) override
  41. {
  42. g.fillAll (Colour (0xff495358));
  43. g.setColour (Colours::white);
  44. if (thumbnail.getTotalLength() > 0.0)
  45. {
  46. thumbnail.drawChannels (g, getLocalBounds().reduced (2),
  47. 0.0, thumbnail.getTotalLength(), 1.0f);
  48. g.setColour (Colours::black);
  49. g.fillRect (static_cast<float> (currentPosition * getWidth()), 0.0f,
  50. 1.0f, static_cast<float> (getHeight()));
  51. }
  52. else
  53. {
  54. g.drawFittedText ("No audio file loaded.\nDrop a file here or click the \"Load File...\" button.", getLocalBounds(),
  55. Justification::centred, 2);
  56. }
  57. }
  58. bool isInterestedInFileDrag (const StringArray&) override { return true; }
  59. void filesDropped (const StringArray& files, int, int) override { loadFile (File (files[0]), true); }
  60. void setCurrentFile (const File& f)
  61. {
  62. if (currentFile == f)
  63. return;
  64. loadFile (f);
  65. }
  66. File getCurrentFile() { return currentFile; }
  67. void setTransportSource (AudioTransportSource* newSource)
  68. {
  69. transportSource = newSource;
  70. struct ResetCallback : public CallbackMessage
  71. {
  72. ResetCallback (AudioThumbnailComponent& o) : owner (o) {}
  73. void messageCallback() override { owner.reset(); }
  74. AudioThumbnailComponent& owner;
  75. };
  76. (new ResetCallback (*this))->post();
  77. }
  78. private:
  79. AudioDeviceManager& audioDeviceManager;
  80. AudioThumbnailCache thumbnailCache;
  81. AudioThumbnail thumbnail;
  82. AudioTransportSource* transportSource = nullptr;
  83. File currentFile;
  84. double currentPosition = 0.0;
  85. //==============================================================================
  86. void changeListenerCallback (ChangeBroadcaster*) override { repaint(); }
  87. void reset()
  88. {
  89. currentPosition = 0.0;
  90. repaint();
  91. if (transportSource == nullptr)
  92. stopTimer();
  93. else
  94. startTimerHz (25);
  95. }
  96. void loadFile (const File& f, bool notify = false)
  97. {
  98. if (currentFile == f || ! f.existsAsFile())
  99. return;
  100. currentFile = f;
  101. thumbnail.setSource (new FileInputSource (f));
  102. if (notify)
  103. sendChangeMessage();
  104. }
  105. void timerCallback() override
  106. {
  107. if (transportSource != nullptr)
  108. {
  109. currentPosition = transportSource->getCurrentPosition() / thumbnail.getTotalLength();
  110. repaint();
  111. }
  112. }
  113. void mouseDrag (const MouseEvent& e) override
  114. {
  115. if (transportSource != nullptr)
  116. {
  117. const ScopedLock sl (audioDeviceManager.getAudioCallbackLock());
  118. transportSource->setPosition ((jmax (static_cast<double> (e.x), 0.0) / getWidth())
  119. * thumbnail.getTotalLength());
  120. }
  121. }
  122. };
  123. //==============================================================================
  124. class AudioPlayerHeader : public Component,
  125. private Button::Listener,
  126. private ChangeListener,
  127. private Value::Listener
  128. {
  129. public:
  130. AudioPlayerHeader();
  131. ~AudioPlayerHeader();
  132. void paint (Graphics&) override;
  133. void resized() override;
  134. AudioThumbnailComponent thumbnailComp;
  135. private:
  136. //==============================================================================
  137. void buttonClicked (Button*) override;
  138. void changeListenerCallback (ChangeBroadcaster*) override;
  139. void valueChanged (Value& value) override;
  140. //==============================================================================
  141. TextButton loadButton { "Load File..." }, playButton { "Play" };
  142. ToggleButton loopButton { "Loop File" };
  143. };
  144. //==============================================================================
  145. class DemoParametersComponent : public Component
  146. {
  147. public:
  148. DemoParametersComponent (const std::vector<DSPDemoParameterBase*>& demoParams)
  149. {
  150. parameters = demoParams;
  151. for (auto demoParameter : parameters)
  152. {
  153. addAndMakeVisible (demoParameter->getComponent());
  154. auto* paramLabel = new Label ({}, demoParameter->name);
  155. paramLabel->attachToComponent (demoParameter->getComponent(), true);
  156. paramLabel->setJustificationType (Justification::centredLeft);
  157. addAndMakeVisible (paramLabel);
  158. labels.add (paramLabel);
  159. }
  160. }
  161. void resized() override
  162. {
  163. auto bounds = getLocalBounds();
  164. bounds.removeFromLeft (100);
  165. for (auto* p : parameters)
  166. {
  167. auto* comp = p->getComponent();
  168. comp->setSize (jmin (bounds.getWidth(), p->getPreferredWidth()), p->getPreferredHeight());
  169. auto compBounds = bounds.removeFromTop (p->getPreferredHeight());
  170. comp->setCentrePosition (compBounds.getCentre());
  171. }
  172. }
  173. int getHeightNeeded()
  174. {
  175. auto height = 0;
  176. for (auto* p : parameters)
  177. height += p->getPreferredHeight();
  178. return height + 10;
  179. }
  180. private:
  181. std::vector<DSPDemoParameterBase*> parameters;
  182. OwnedArray<Label> labels;
  183. };
  184. //==============================================================================
  185. class MainContentComponent : public Component,
  186. private ListBoxModel
  187. {
  188. public:
  189. MainContentComponent();
  190. void paint (Graphics&) override;
  191. void resized() override;
  192. AudioThumbnailComponent& getThumbnailComponent() { return header.thumbnailComp; }
  193. void initParameters();
  194. private:
  195. //==============================================================================
  196. void paintListBoxItem (int rowNumber, Graphics&, int width, int height, bool rowIsSelected) override;
  197. int getNumRows() override;
  198. void selectedRowsChanged (int lastRowSelected) override;
  199. void setupDemoColours();
  200. //==============================================================================
  201. AudioPlayerHeader header;
  202. ListBox demoList { "Demo List" };
  203. CPlusPlusCodeTokeniser cppTokeniser;
  204. CodeDocument codeDocument;
  205. CodeEditorComponent codeEditor { codeDocument, &cppTokeniser };
  206. ScopedPointer<DemoParametersComponent> parametersComponent;
  207. };