1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-18 00:54:19 +00:00
JUCE/examples/audio plugin demo/Source/PluginEditor.cpp

209 lines
7.9 KiB
C++

/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include "PluginProcessor.h"
#include "PluginEditor.h"
//==============================================================================
// This is a handy slider subclass that controls an AudioProcessorParameter
// (may move this class into the library itself at some point in the future..)
class JuceDemoPluginAudioProcessorEditor::ParameterSlider : public Slider,
private Timer
{
public:
ParameterSlider (AudioProcessorParameter& p)
: Slider (p.getName (256)), param (p)
{
setRange (0.0, 1.0, 0.0);
startTimerHz (30);
updateSliderPos();
}
void valueChanged() override { param.setValueNotifyingHost ((float) Slider::getValue()); }
void timerCallback() override { updateSliderPos(); }
void startedDragging() override { param.beginChangeGesture(); }
void stoppedDragging() override { param.endChangeGesture(); }
double getValueFromText (const String& text) override { return param.getValueForText (text); }
String getTextFromValue (double value) override { return param.getText ((float) value, 1024); }
void updateSliderPos()
{
const float newValue = param.getValue();
if (newValue != (float) Slider::getValue() && ! isMouseButtonDown())
Slider::setValue (newValue, NotificationType::dontSendNotification);
}
AudioProcessorParameter& param;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterSlider)
};
//==============================================================================
JuceDemoPluginAudioProcessorEditor::JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor& owner)
: AudioProcessorEditor (owner),
midiKeyboard (owner.keyboardState, MidiKeyboardComponent::horizontalKeyboard),
timecodeDisplayLabel (String()),
gainLabel (String(), "Throughput level:"),
delayLabel (String(), "Delay:")
{
// add some sliders..
addAndMakeVisible (gainSlider = new ParameterSlider (*owner.gainParam));
gainSlider->setSliderStyle (Slider::Rotary);
addAndMakeVisible (delaySlider = new ParameterSlider (*owner.delayParam));
delaySlider->setSliderStyle (Slider::Rotary);
// add some labels for the sliders..
gainLabel.attachToComponent (gainSlider, false);
gainLabel.setFont (Font (11.0f));
delayLabel.attachToComponent (delaySlider, false);
delayLabel.setFont (Font (11.0f));
// add the midi keyboard component..
addAndMakeVisible (midiKeyboard);
// add a label that will display the current timecode and status..
addAndMakeVisible (timecodeDisplayLabel);
timecodeDisplayLabel.setFont (Font (Font::getDefaultMonospacedFontName(), 15.0f, Font::plain));
// set resize limits for this plug-in
setResizeLimits (400, 200, 1024, 700);
// set our component's initial size to be the last one that was stored in the filter's settings
setSize (owner.lastUIWidth,
owner.lastUIHeight);
updateTrackProperties();
// start a timer which will keep our timecode display updated
startTimerHz (30);
}
JuceDemoPluginAudioProcessorEditor::~JuceDemoPluginAudioProcessorEditor()
{
}
//==============================================================================
void JuceDemoPluginAudioProcessorEditor::paint (Graphics& g)
{
g.setColour (backgroundColour);
g.fillAll();
}
void JuceDemoPluginAudioProcessorEditor::resized()
{
// This lays out our child components...
Rectangle<int> r (getLocalBounds().reduced (8));
timecodeDisplayLabel.setBounds (r.removeFromTop (26));
midiKeyboard.setBounds (r.removeFromBottom (70));
r.removeFromTop (20);
Rectangle<int> sliderArea (r.removeFromTop (60));
gainSlider->setBounds (sliderArea.removeFromLeft (jmin (180, sliderArea.getWidth() / 2)));
delaySlider->setBounds (sliderArea.removeFromLeft (jmin (180, sliderArea.getWidth())));
getProcessor().lastUIWidth = getWidth();
getProcessor().lastUIHeight = getHeight();
}
//==============================================================================
void JuceDemoPluginAudioProcessorEditor::timerCallback()
{
updateTimecodeDisplay (getProcessor().lastPosInfo);
}
void JuceDemoPluginAudioProcessorEditor::hostMIDIControllerIsAvailable (bool controllerIsAvailable)
{
midiKeyboard.setVisible (! controllerIsAvailable);
}
void JuceDemoPluginAudioProcessorEditor::updateTrackProperties ()
{
auto trackColour = getProcessor().trackProperties.colour;
auto& lf = getLookAndFeel();
backgroundColour = (trackColour == Colour() ? lf.findColour (ResizableWindow::backgroundColourId)
: trackColour.withAlpha (1.0f).withBrightness (0.266f));
repaint();
}
//==============================================================================
// quick-and-dirty function to format a timecode string
static String timeToTimecodeString (double seconds)
{
const int millisecs = roundToInt (seconds * 1000.0);
const int absMillisecs = std::abs (millisecs);
return String::formatted ("%02d:%02d:%02d.%03d",
millisecs / 3600000,
(absMillisecs / 60000) % 60,
(absMillisecs / 1000) % 60,
absMillisecs % 1000);
}
// quick-and-dirty function to format a bars/beats string
static String quarterNotePositionToBarsBeatsString (double quarterNotes, int numerator, int denominator)
{
if (numerator == 0 || denominator == 0)
return "1|1|000";
const int quarterNotesPerBar = (numerator * 4 / denominator);
const double beats = (fmod (quarterNotes, quarterNotesPerBar) / quarterNotesPerBar) * numerator;
const int bar = ((int) quarterNotes) / quarterNotesPerBar + 1;
const int beat = ((int) beats) + 1;
const int ticks = ((int) (fmod (beats, 1.0) * 960.0 + 0.5));
return String::formatted ("%d|%d|%03d", bar, beat, ticks);
}
// Updates the text in our position label.
void JuceDemoPluginAudioProcessorEditor::updateTimecodeDisplay (AudioPlayHead::CurrentPositionInfo pos)
{
MemoryOutputStream displayText;
displayText << "[" << SystemStats::getJUCEVersion() << "] "
<< String (pos.bpm, 2) << " bpm, "
<< pos.timeSigNumerator << '/' << pos.timeSigDenominator
<< " - " << timeToTimecodeString (pos.timeInSeconds)
<< " - " << quarterNotePositionToBarsBeatsString (pos.ppqPosition,
pos.timeSigNumerator,
pos.timeSigDenominator);
if (pos.isRecording)
displayText << " (recording)";
else if (pos.isPlaying)
displayText << " (playing)";
timecodeDisplayLabel.setText (displayText.toString(), dontSendNotification);
}