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.

199 lines
7.0KB

  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. JuceDemoPluginAudioProcessorEditor::JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor& owner)
  11. : AudioProcessorEditor (owner),
  12. midiKeyboard (owner.keyboardState, MidiKeyboardComponent::horizontalKeyboard),
  13. infoLabel (String::empty),
  14. gainLabel ("", "Throughput level:"),
  15. delayLabel ("", "Delay:"),
  16. gainSlider ("gain"),
  17. delaySlider ("delay")
  18. {
  19. // add some sliders..
  20. addAndMakeVisible (gainSlider);
  21. gainSlider.setSliderStyle (Slider::Rotary);
  22. gainSlider.addListener (this);
  23. gainSlider.setRange (0.0, 1.0, 0.01);
  24. addAndMakeVisible (delaySlider);
  25. delaySlider.setSliderStyle (Slider::Rotary);
  26. delaySlider.addListener (this);
  27. delaySlider.setRange (0.0, 1.0, 0.01);
  28. // add some labels for the sliders..
  29. gainLabel.attachToComponent (&gainSlider, false);
  30. gainLabel.setFont (Font (11.0f));
  31. delayLabel.attachToComponent (&delaySlider, false);
  32. delayLabel.setFont (Font (11.0f));
  33. // add the midi keyboard component..
  34. addAndMakeVisible (midiKeyboard);
  35. // add a label that will display the current timecode and status..
  36. addAndMakeVisible (infoLabel);
  37. infoLabel.setColour (Label::textColourId, Colours::blue);
  38. // add the triangular resizer component for the bottom-right of the UI
  39. addAndMakeVisible (resizer = new ResizableCornerComponent (this, &resizeLimits));
  40. resizeLimits.setSizeLimits (150, 150, 800, 300);
  41. // set our component's initial size to be the last one that was stored in the filter's settings
  42. setSize (owner.lastUIWidth,
  43. owner.lastUIHeight);
  44. startTimer (50);
  45. }
  46. JuceDemoPluginAudioProcessorEditor::~JuceDemoPluginAudioProcessorEditor()
  47. {
  48. }
  49. //==============================================================================
  50. void JuceDemoPluginAudioProcessorEditor::paint (Graphics& g)
  51. {
  52. g.setGradientFill (ColourGradient (Colours::white, 0, 0,
  53. Colours::grey, 0, (float) getHeight(), false));
  54. g.fillAll();
  55. }
  56. void JuceDemoPluginAudioProcessorEditor::resized()
  57. {
  58. infoLabel.setBounds (10, 4, 400, 25);
  59. gainSlider.setBounds (20, 60, 150, 40);
  60. delaySlider.setBounds (200, 60, 150, 40);
  61. const int keyboardHeight = 70;
  62. midiKeyboard.setBounds (4, getHeight() - keyboardHeight - 4, getWidth() - 8, keyboardHeight);
  63. resizer->setBounds (getWidth() - 16, getHeight() - 16, 16, 16);
  64. getProcessor().lastUIWidth = getWidth();
  65. getProcessor().lastUIHeight = getHeight();
  66. }
  67. //==============================================================================
  68. // This timer periodically checks whether any of the filter's parameters have changed...
  69. void JuceDemoPluginAudioProcessorEditor::timerCallback()
  70. {
  71. JuceDemoPluginAudioProcessor& ourProcessor = getProcessor();
  72. AudioPlayHead::CurrentPositionInfo newPos (ourProcessor.lastPosInfo);
  73. if (lastDisplayedPosition != newPos)
  74. displayPositionInfo (newPos);
  75. gainSlider.setValue (ourProcessor.gain->getValue(), dontSendNotification);
  76. delaySlider.setValue (ourProcessor.delay->getValue(), dontSendNotification);
  77. }
  78. // This is our Slider::Listener callback, when the user drags a slider.
  79. void JuceDemoPluginAudioProcessorEditor::sliderValueChanged (Slider* slider)
  80. {
  81. if (AudioProcessorParameter* param = getParameterFromSlider (slider))
  82. {
  83. // It's vital to use setValueNotifyingHost to change any parameters that are automatable
  84. // by the host, rather than just modifying them directly, otherwise the host won't know
  85. // that they've changed.
  86. param->setValueNotifyingHost ((float) slider->getValue());
  87. }
  88. }
  89. void JuceDemoPluginAudioProcessorEditor::sliderDragStarted (Slider* slider)
  90. {
  91. if (AudioProcessorParameter* param = getParameterFromSlider (slider))
  92. {
  93. param->beginChangeGesture();
  94. }
  95. }
  96. void JuceDemoPluginAudioProcessorEditor::sliderDragEnded (Slider* slider)
  97. {
  98. if (AudioProcessorParameter* param = getParameterFromSlider (slider))
  99. {
  100. param->endChangeGesture();
  101. }
  102. }
  103. //==============================================================================
  104. // quick-and-dirty function to format a timecode string
  105. static String timeToTimecodeString (const double seconds)
  106. {
  107. const double absSecs = std::abs (seconds);
  108. const int hours = (int) (absSecs / (60.0 * 60.0));
  109. const int mins = ((int) (absSecs / 60.0)) % 60;
  110. const int secs = ((int) absSecs) % 60;
  111. String s (seconds < 0 ? "-" : "");
  112. s << String (hours).paddedLeft ('0', 2) << ":"
  113. << String (mins) .paddedLeft ('0', 2) << ":"
  114. << String (secs) .paddedLeft ('0', 2) << ":"
  115. << String (roundToInt (absSecs * 1000) % 1000).paddedLeft ('0', 3);
  116. return s;
  117. }
  118. // quick-and-dirty function to format a bars/beats string
  119. static String ppqToBarsBeatsString (double ppq, double /*lastBarPPQ*/, int numerator, int denominator)
  120. {
  121. if (numerator == 0 || denominator == 0)
  122. return "1|1|0";
  123. const int ppqPerBar = (numerator * 4 / denominator);
  124. const double beats = (fmod (ppq, ppqPerBar) / ppqPerBar) * numerator;
  125. const int bar = ((int) ppq) / ppqPerBar + 1;
  126. const int beat = ((int) beats) + 1;
  127. const int ticks = ((int) (fmod (beats, 1.0) * 960.0 + 0.5));
  128. String s;
  129. s << bar << '|' << beat << '|' << ticks;
  130. return s;
  131. }
  132. AudioProcessorParameter* JuceDemoPluginAudioProcessorEditor::getParameterFromSlider (const Slider* slider) const
  133. {
  134. if (slider == &gainSlider)
  135. return getProcessor().gain;
  136. if (slider == &delaySlider)
  137. return getProcessor().delay;
  138. return nullptr;
  139. }
  140. // Updates the text in our position label.
  141. void JuceDemoPluginAudioProcessorEditor::displayPositionInfo (const AudioPlayHead::CurrentPositionInfo& pos)
  142. {
  143. lastDisplayedPosition = pos;
  144. String displayText;
  145. displayText.preallocateBytes (128);
  146. displayText << String (pos.bpm, 2) << " bpm, "
  147. << pos.timeSigNumerator << '/' << pos.timeSigDenominator
  148. << " - " << timeToTimecodeString (pos.timeInSeconds)
  149. << " - " << ppqToBarsBeatsString (pos.ppqPosition, pos.ppqPositionOfLastBarStart,
  150. pos.timeSigNumerator, pos.timeSigDenominator);
  151. if (pos.isRecording)
  152. displayText << " (recording)";
  153. else if (pos.isPlaying)
  154. displayText << " (playing)";
  155. infoLabel.setText ("[" + SystemStats::getJUCEVersion() + "] " + displayText, dontSendNotification);
  156. }