mirror of
https://codeberg.org/armin/justasample.git
synced 2026-09-01 04:10:48 +02:00
init
This commit is contained in:
commit
d21bc831e1
178 changed files with 24136 additions and 0 deletions
250
Source/PluginEditor.h
Normal file
250
Source/PluginEditor.h
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
PluginProcessor.cpp
|
||||
Created: 5 Sep 2023
|
||||
Author: binya
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <JuceHeader.h>
|
||||
|
||||
#include "PluginProcessor.h"
|
||||
#include "CustomLookAndFeel.h"
|
||||
#include "Components/Buttons.h"
|
||||
#include "Components/InputDeviceSelector.h"
|
||||
#include "Components/SampleEditor.h"
|
||||
#include "Components/FxChain.h"
|
||||
#include "Components/Prompt.h"
|
||||
#include "Components/SampleNavigator.h"
|
||||
|
||||
/** Painting ordering requires a separate component... */
|
||||
class EditorOverlay final : public CustomComponent
|
||||
{
|
||||
public:
|
||||
void setWaveformMode(bool isWaveformMode)
|
||||
{
|
||||
if (waveformModeAvailable != isWaveformMode)
|
||||
{
|
||||
waveformModeAvailable = isWaveformMode;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void setWaveformModeDisabled(bool disabled)
|
||||
{
|
||||
if (waveformModeDisabled != disabled)
|
||||
{
|
||||
waveformModeDisabled = disabled;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void paint(juce::Graphics& g) override;
|
||||
void resized() override;
|
||||
void lookAndFeelChanged() override;
|
||||
|
||||
float scale(float value) const { return value * getWidth() / Layout::figmaWidth; }
|
||||
float scale(int value) const { return scale(float(value)); }
|
||||
|
||||
//==============================================================================
|
||||
melatonin::DropShadow sampleControlShadow{ defaultTheme.slate.withAlpha(0.125f), 3, {2, 2} };
|
||||
melatonin::DropShadow navControlShadow{ defaultTheme.slate.withAlpha(0.125f), 3, {-2, -2} };
|
||||
|
||||
bool waveformModeAvailable{ false };
|
||||
bool waveformModeDisabled{ false };
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class JustaSampleAudioProcessorEditor final : public juce::AudioProcessorEditor, public juce::Timer, public juce::FileDragAndDropTarget,
|
||||
public juce::FilenameComponentListener, public CustomHelpTextDisplay, public ThemeProvider
|
||||
{
|
||||
public:
|
||||
explicit JustaSampleAudioProcessorEditor(JustaSampleAudioProcessor& audioProcessor);
|
||||
~JustaSampleAudioProcessorEditor() override;
|
||||
|
||||
private:
|
||||
void timerCallback() override;
|
||||
void paint(juce::Graphics&) override;
|
||||
void resized() override;
|
||||
void lookAndFeelChanged() override;
|
||||
|
||||
void mouseDown(const juce::MouseEvent& event) override;
|
||||
void mouseUp(const juce::MouseEvent& event) override;
|
||||
void mouseDrag(const juce::MouseEvent& event) override;
|
||||
|
||||
void mouseWheelMove(const juce::MouseEvent& event, const juce::MouseWheelDetails& wheel) override;
|
||||
|
||||
void helpTextChanged(const juce::String&) override {}
|
||||
|
||||
void setTheme(Colors newTheme) override;
|
||||
Colors getTheme() const override;
|
||||
|
||||
juce::Rectangle<int> getConstrainedBounds() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Update the Editor to fit with the processor's sample. On the initial load, the
|
||||
SampleNavigator will not update the viewing bounds.
|
||||
*/
|
||||
void loadSample();
|
||||
|
||||
/** Handles the incoming recording messages from the recorder queue */
|
||||
void handleActiveRecording();
|
||||
|
||||
/** If permitted, toggles whether the plugin state will use a file reference or store the
|
||||
samples directly. If necessary, this will prompt the user to save the current sample.
|
||||
*/
|
||||
void toggleLinkSample();
|
||||
|
||||
/** Signals to the processor to start recording, or first opens the device settings prompt if
|
||||
no valid input device is selected. Note that no editor changes occur here, instead it polls
|
||||
for changes in the timer callback (simpler than registering as a listener to the recorder).
|
||||
*/
|
||||
void startRecording(bool promptSettings = true);
|
||||
|
||||
/** Starts a pitch detection prompt */
|
||||
void promptPitchDetection();
|
||||
|
||||
/** Opens the device settings prompt */
|
||||
void promptDeviceSettings(bool recordOnClose = false);
|
||||
|
||||
/** We use this as a place to update the enablement and display of our plugin controls. */
|
||||
void enablementChanged() override;
|
||||
void fxEnablementChanged();
|
||||
|
||||
//==============================================================================
|
||||
/** Whether the editor is interested in a file */
|
||||
bool isInterestedInFile(const juce::String& file) const;
|
||||
bool isInterestedInFileDrag(const juce::StringArray& files) override;
|
||||
void filesDropped(const juce::StringArray& files, int x, int y) override;
|
||||
void filenameComponentChanged(juce::FilenameComponent* fileComponentThatHasChanged) override;
|
||||
|
||||
void fileDragEnter(const juce::StringArray& files, int x, int y) override;
|
||||
void fileDragExit(const juce::StringArray& files) override;
|
||||
|
||||
void updateLabel(const juce::String& text = "");
|
||||
|
||||
//==============================================================================
|
||||
/** Scaling the sizes in our Figma demo to percentages of width.
|
||||
This rounding operation is important to ensure consistent spacing with JUCE's integer component bounds.
|
||||
Otherwise, we'd just do a simple division.
|
||||
*/
|
||||
float scalei(int value) const { return scalei(float(value)); }
|
||||
float scalei(float value) const { return std::roundf(value * prompt.getWidth() / Layout::figmaWidth); }
|
||||
float scalef(float value) const { return value * prompt.getWidth() / Layout::figmaWidth; }
|
||||
|
||||
//==============================================================================
|
||||
JustaSampleAudioProcessor& p;
|
||||
PluginParameters::State& pluginState;
|
||||
UIDummyParam dummyParam;
|
||||
const juce::OwnedArray<CustomSamplerVoice>& synthVoices;
|
||||
bool currentlyPlaying{ false };
|
||||
|
||||
/** Some thought is needed to keep the editor synchronized when changes to the sample occur
|
||||
or files are loaded. I decided the easiest way is to have the processor and editor both
|
||||
keep track of the buffer's hash.
|
||||
*/
|
||||
juce::String expectedHash{ 0 };
|
||||
|
||||
bool userDraggedSample{ false }; // We use this to reset the UI only when a sample loads as result of a user selection
|
||||
|
||||
//==============================================================================
|
||||
juce::AudioBuffer<float> pendingRecordingBuffer;
|
||||
int recordingBufferSize{ 0 };
|
||||
|
||||
//==============================================================================
|
||||
// Modules
|
||||
juce::Label tuningLabel, attackLabel, releaseLabel, playbackLabel, loopingLabel, masterLabel;
|
||||
juce::Array<juce::Slider*> rotaries;
|
||||
|
||||
// Tuning module
|
||||
CustomRotary semitoneRotary, centRotary, waveformSemitoneRotary, waveformCentRotary;
|
||||
CustomRotaryAttachment semitoneRotaryAttachment, centRotaryAttachment, waveformSemitoneRotaryAttachment, waveformCentRotaryAttachment;
|
||||
|
||||
juce::Label tuningDetectLabel;
|
||||
CustomShapeButton tuningDetectButton;
|
||||
|
||||
// Attack and release modules
|
||||
CustomRotary attackTimeRotary, attackCurve, releaseTimeRotary, releaseCurve;
|
||||
CustomRotaryAttachment attackTimeAttachment, attackCurveAttachment, releaseTimeAttachment, releaseCurveAttachment;
|
||||
EnvelopeSliderLookAndFeel<EnvelopeSlider::attack> attackCurveLNF;
|
||||
EnvelopeSliderLookAndFeel<EnvelopeSlider::release> releaseCurveLNF;
|
||||
|
||||
// Playback module
|
||||
CustomToggleableButton lofiModeButton;
|
||||
APVTS::ButtonAttachment lofiModeAttachment;
|
||||
CustomChoiceButton playbackModeButton;
|
||||
juce::ParameterAttachment playbackModeAttachment;
|
||||
CustomRotary playbackSpeedRotary;
|
||||
CustomRotaryAttachment playbackSpeedAttachment;
|
||||
|
||||
// Loop module
|
||||
CustomToggleableButton loopButton, loopStartButton, loopEndButton;
|
||||
APVTS::ButtonAttachment loopAttachment, loopStartAttachment, loopEndAttachment;
|
||||
|
||||
// Mixing module
|
||||
CustomToggleableButton monoOutputButton;
|
||||
APVTS::ButtonAttachment monoOutputAttachment;
|
||||
CustomRotary gainSlider;
|
||||
CustomRotaryAttachment gainSliderAttachment;
|
||||
VolumeSliderLookAndFeel gainSliderLNF;
|
||||
|
||||
// Sample controls
|
||||
EditorOverlay editorOverlay;
|
||||
juce::FilenameComponent filenameComponent;
|
||||
CustomToggleableButton linkSampleToggle; // Whether the sample should be stored in the plugin state
|
||||
|
||||
CustomToggleableButton waveformModeLabel;
|
||||
juce::ButtonParameterAttachment waveformModeLabelAttachment;
|
||||
|
||||
CustomShapeButton playStopButton;
|
||||
juce::Path playPath, stopPath;
|
||||
const juce::String playHelpText{ "Play sample" }, stopHelpText{ "Halt voices" };
|
||||
CustomShapeButton recordButton;
|
||||
CustomShapeButton deviceSettingsButton;
|
||||
InputDeviceSelector audioDeviceSettings;
|
||||
|
||||
// Nav controls
|
||||
CustomShapeButton fitButton;
|
||||
CustomToggleableButton pinButton;
|
||||
ToggleButtonAttachment pinButtonAttachment;
|
||||
|
||||
// Main components
|
||||
SampleEditor sampleEditor;
|
||||
SampleNavigator sampleNavigator; // Note that SampleNavigator manages ViewStart and ViewEnd
|
||||
FxChain fxChain;
|
||||
|
||||
juce::Label statusLabel;
|
||||
bool fileDragging{ false };
|
||||
|
||||
// Some variables to help detect scroll gestures
|
||||
const int maxCallbacksSinceInZoomGesture{ 20 };
|
||||
int zoomGestureEndCallbacks{ 0 };
|
||||
bool mouseWheelDetected{ false };
|
||||
int lastViewStart{ 0 }, lastViewEnd{ 0 };
|
||||
|
||||
// Footer
|
||||
juce::Label versionInfo;
|
||||
CustomToggleableButton preFXButton;
|
||||
APVTS::ButtonAttachment preFXAttachment;
|
||||
CustomToggleableButton showFXButton;
|
||||
ToggleButtonAttachment showFXAttachment;
|
||||
juce::ParameterAttachment eqEnablementAttachment, reverbEnablementAttachment, distortionEnablementAttachment, chorusEnablementAttachment;
|
||||
bool eqEnabled{ false }, reverbEnabled{ false }, distortionEnabled{ false }, chorusEnabled{ false };
|
||||
|
||||
Prompt prompt;
|
||||
|
||||
CustomLookAndFeel& lnf;
|
||||
Colors theme{ defaultTheme };
|
||||
juce::OpenGLContext openGLContext;
|
||||
juce::PluginHostType hostType;
|
||||
|
||||
#if JUCE_DEBUG
|
||||
melatonin::Inspector inspector{ *this, false };
|
||||
#endif
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JustaSampleAudioProcessorEditor)
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue