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.

190 lines
7.2KB

  1. /*
  2. ==============================================================================
  3. This file was auto-generated by the Jucer!
  4. It contains the basic startup code for a Juce application.
  5. ==============================================================================
  6. */
  7. #include "PluginProcessor.h"
  8. #include "PluginEditor.h"
  9. //==============================================================================
  10. // This is a handy slider subclass that controls an AudioProcessorParameter
  11. // (may move this class into the library itself at some point in the future..)
  12. class JuceDemoPluginAudioProcessorEditor::ParameterSlider : public Slider,
  13. private Timer
  14. {
  15. public:
  16. ParameterSlider (AudioProcessorParameter& p)
  17. : Slider (p.getName (256)), param (p)
  18. {
  19. setRange (0.0, 1.0, 0.0);
  20. startTimerHz (30);
  21. updateSliderPos();
  22. }
  23. void valueChanged() override
  24. {
  25. param.setValue ((float) Slider::getValue());
  26. }
  27. void timerCallback() override { updateSliderPos(); }
  28. void startedDragging() override { param.beginChangeGesture(); }
  29. void stoppedDragging() override { param.endChangeGesture(); }
  30. double getValueFromText (const String& text) override { return param.getValueForText (text); }
  31. String getTextFromValue (double value) override { return param.getText ((float) value, 1024); }
  32. void updateSliderPos()
  33. {
  34. const float newValue = param.getValue();
  35. if (newValue != (float) Slider::getValue())
  36. Slider::setValue (newValue);
  37. }
  38. AudioProcessorParameter& param;
  39. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterSlider)
  40. };
  41. //==============================================================================
  42. JuceDemoPluginAudioProcessorEditor::JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor& owner)
  43. : AudioProcessorEditor (owner),
  44. midiKeyboard (owner.keyboardState, MidiKeyboardComponent::horizontalKeyboard),
  45. timecodeDisplayLabel (String::empty),
  46. gainLabel (String::empty, "Throughput level:"),
  47. delayLabel (String::empty, "Delay:")
  48. {
  49. // add some sliders..
  50. addAndMakeVisible (gainSlider = new ParameterSlider (*owner.gainParam));
  51. gainSlider->setSliderStyle (Slider::Rotary);
  52. addAndMakeVisible (delaySlider = new ParameterSlider (*owner.delayParam));
  53. delaySlider->setSliderStyle (Slider::Rotary);
  54. // add some labels for the sliders..
  55. gainLabel.attachToComponent (gainSlider, false);
  56. gainLabel.setFont (Font (11.0f));
  57. delayLabel.attachToComponent (delaySlider, false);
  58. delayLabel.setFont (Font (11.0f));
  59. // add the midi keyboard component..
  60. addAndMakeVisible (midiKeyboard);
  61. // add a label that will display the current timecode and status..
  62. addAndMakeVisible (timecodeDisplayLabel);
  63. timecodeDisplayLabel.setColour (Label::textColourId, Colours::blue);
  64. timecodeDisplayLabel.setFont (Font (Font::getDefaultMonospacedFontName(), 15.0f, Font::plain));
  65. // add the triangular resizer component for the bottom-right of the UI
  66. addAndMakeVisible (resizer = new ResizableCornerComponent (this, &resizeLimits));
  67. resizeLimits.setSizeLimits (150, 150, 800, 300);
  68. // set our component's initial size to be the last one that was stored in the filter's settings
  69. setSize (owner.lastUIWidth,
  70. owner.lastUIHeight);
  71. // start a timer which will keep our timecode display updated
  72. startTimerHz (30);
  73. }
  74. JuceDemoPluginAudioProcessorEditor::~JuceDemoPluginAudioProcessorEditor()
  75. {
  76. }
  77. //==============================================================================
  78. void JuceDemoPluginAudioProcessorEditor::paint (Graphics& g)
  79. {
  80. g.setGradientFill (ColourGradient (Colours::white, 0, 0,
  81. Colours::lightgrey, 0, (float) getHeight(), false));
  82. g.fillAll();
  83. }
  84. void JuceDemoPluginAudioProcessorEditor::resized()
  85. {
  86. // This lays out our child components...
  87. Rectangle<int> r (getLocalBounds().reduced (8));
  88. timecodeDisplayLabel.setBounds (r.removeFromTop (26));
  89. midiKeyboard.setBounds (r.removeFromBottom (70));
  90. r.removeFromTop (30);
  91. Rectangle<int> sliderArea (r.removeFromTop (50));
  92. gainSlider->setBounds (sliderArea.removeFromLeft (jmin (180, sliderArea.getWidth() / 2)));
  93. delaySlider->setBounds (sliderArea.removeFromLeft (jmin (180, sliderArea.getWidth())));
  94. resizer->setBounds (getWidth() - 16, getHeight() - 16, 16, 16);
  95. getProcessor().lastUIWidth = getWidth();
  96. getProcessor().lastUIHeight = getHeight();
  97. }
  98. //==============================================================================
  99. void JuceDemoPluginAudioProcessorEditor::timerCallback()
  100. {
  101. updateTimecodeDisplay (getProcessor().lastPosInfo);
  102. }
  103. //==============================================================================
  104. // quick-and-dirty function to format a timecode string
  105. static String timeToTimecodeString (double seconds)
  106. {
  107. const int millisecs = roundToInt (std::abs (seconds * 1000.0));
  108. return String::formatted ("%s%02d:%02d:%02d.%03d",
  109. seconds < 0 ? "-" : "",
  110. millisecs / 360000,
  111. (millisecs / 60000) % 60,
  112. (millisecs / 1000) % 60,
  113. millisecs % 1000);
  114. }
  115. // quick-and-dirty function to format a bars/beats string
  116. static String quarterNotePositionToBarsBeatsString (double quarterNotes, int numerator, int denominator)
  117. {
  118. if (numerator == 0 || denominator == 0)
  119. return "1|1|000";
  120. const int quarterNotesPerBar = (numerator * 4 / denominator);
  121. const double beats = (fmod (quarterNotes, quarterNotesPerBar) / quarterNotesPerBar) * numerator;
  122. const int bar = ((int) quarterNotes) / quarterNotesPerBar + 1;
  123. const int beat = ((int) beats) + 1;
  124. const int ticks = ((int) (fmod (beats, 1.0) * 960.0 + 0.5));
  125. return String::formatted ("%d|%d|%03d", bar, beat, ticks);
  126. }
  127. // Updates the text in our position label.
  128. void JuceDemoPluginAudioProcessorEditor::updateTimecodeDisplay (AudioPlayHead::CurrentPositionInfo pos)
  129. {
  130. if (lastDisplayedPosition != pos)
  131. {
  132. lastDisplayedPosition = pos;
  133. MemoryOutputStream displayText;
  134. displayText << "[" << SystemStats::getJUCEVersion() << "] "
  135. << String (pos.bpm, 2) << " bpm, "
  136. << pos.timeSigNumerator << '/' << pos.timeSigDenominator
  137. << " - " << timeToTimecodeString (pos.timeInSeconds)
  138. << " - " << quarterNotePositionToBarsBeatsString (pos.ppqPosition,
  139. pos.timeSigNumerator,
  140. pos.timeSigDenominator);
  141. if (pos.isRecording)
  142. displayText << " (recording)";
  143. else if (pos.isPlaying)
  144. displayText << " (playing)";
  145. timecodeDisplayLabel.setText (displayText.toString(), dontSendNotification);
  146. }
  147. }