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.

179 lines
6.5KB

  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* ownerFilter)
  11. : AudioProcessorEditor (ownerFilter),
  12. midiKeyboard (ownerFilter->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 (ownerFilter->lastUIWidth,
  43. ownerFilter->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, Colours::grey, 0, (float) getHeight(), false));
  53. g.fillAll();
  54. }
  55. void JuceDemoPluginAudioProcessorEditor::resized()
  56. {
  57. infoLabel.setBounds (10, 4, 400, 25);
  58. gainSlider.setBounds (20, 60, 150, 40);
  59. delaySlider.setBounds (200, 60, 150, 40);
  60. const int keyboardHeight = 70;
  61. midiKeyboard.setBounds (4, getHeight() - keyboardHeight - 4, getWidth() - 8, keyboardHeight);
  62. resizer->setBounds (getWidth() - 16, getHeight() - 16, 16, 16);
  63. getProcessor()->lastUIWidth = getWidth();
  64. getProcessor()->lastUIHeight = getHeight();
  65. }
  66. //==============================================================================
  67. // This timer periodically checks whether any of the filter's parameters have changed...
  68. void JuceDemoPluginAudioProcessorEditor::timerCallback()
  69. {
  70. JuceDemoPluginAudioProcessor* ourProcessor = getProcessor();
  71. AudioPlayHead::CurrentPositionInfo newPos (ourProcessor->lastPosInfo);
  72. if (lastDisplayedPosition != newPos)
  73. displayPositionInfo (newPos);
  74. gainSlider.setValue (ourProcessor->gain, false);
  75. delaySlider.setValue (ourProcessor->delay, false);
  76. }
  77. // This is our Slider::Listener callback, when the user drags a slider.
  78. void JuceDemoPluginAudioProcessorEditor::sliderValueChanged (Slider* slider)
  79. {
  80. if (slider == &gainSlider)
  81. {
  82. // It's vital to use setParameterNotifyingHost to change any parameters that are automatable
  83. // by the host, rather than just modifying them directly, otherwise the host won't know
  84. // that they've changed.
  85. getProcessor()->setParameterNotifyingHost (JuceDemoPluginAudioProcessor::gainParam,
  86. (float) gainSlider.getValue());
  87. }
  88. else if (slider == &delaySlider)
  89. {
  90. getProcessor()->setParameterNotifyingHost (JuceDemoPluginAudioProcessor::delayParam,
  91. (float) delaySlider.getValue());
  92. }
  93. }
  94. //==============================================================================
  95. // quick-and-dirty function to format a timecode string
  96. static const String timeToTimecodeString (const double seconds)
  97. {
  98. const double absSecs = fabs (seconds);
  99. const int hours = (int) (absSecs / (60.0 * 60.0));
  100. const int mins = ((int) (absSecs / 60.0)) % 60;
  101. const int secs = ((int) absSecs) % 60;
  102. String s;
  103. if (seconds < 0)
  104. s = "-";
  105. s << String (hours).paddedLeft ('0', 2) << ":"
  106. << String (mins).paddedLeft ('0', 2) << ":"
  107. << String (secs).paddedLeft ('0', 2) << ":"
  108. << String (roundToInt (absSecs * 1000) % 1000).paddedLeft ('0', 3);
  109. return s;
  110. }
  111. // quick-and-dirty function to format a bars/beats string
  112. static const String ppqToBarsBeatsString (double ppq, double /*lastBarPPQ*/, int numerator, int denominator)
  113. {
  114. if (numerator == 0 || denominator == 0)
  115. return "1|1|0";
  116. const int ppqPerBar = (numerator * 4 / denominator);
  117. const double beats = (fmod (ppq, ppqPerBar) / ppqPerBar) * numerator;
  118. const int bar = ((int) ppq) / ppqPerBar + 1;
  119. const int beat = ((int) beats) + 1;
  120. const int ticks = ((int) (fmod (beats, 1.0) * 960.0));
  121. String s;
  122. s << bar << '|' << beat << '|' << ticks;
  123. return s;
  124. }
  125. // Updates the text in our position label.
  126. void JuceDemoPluginAudioProcessorEditor::displayPositionInfo (const AudioPlayHead::CurrentPositionInfo& pos)
  127. {
  128. lastDisplayedPosition = pos;
  129. String displayText;
  130. displayText.preallocateBytes (128);
  131. displayText << String (pos.bpm, 2) << " bpm, "
  132. << pos.timeSigNumerator << '/' << pos.timeSigDenominator
  133. << " - " << timeToTimecodeString (pos.timeInSeconds)
  134. << " - " << ppqToBarsBeatsString (pos.ppqPosition, pos.ppqPositionOfLastBarStart,
  135. pos.timeSigNumerator, pos.timeSigDenominator);
  136. if (pos.isRecording)
  137. displayText << " (recording)";
  138. else if (pos.isPlaying)
  139. displayText << " (playing)";
  140. infoLabel.setText (displayText, false);
  141. }