2022-04-22 03:04:30 +00:00
|
|
|
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
|
|
|
|
// Copyright (C) 2017 Xenakios
|
|
|
|
// Copyright (C) 2020 Jesse Chappell
|
2017-11-13 15:06:08 +00:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "../JuceLibraryCode/JuceHeader.h"
|
|
|
|
#include "PluginProcessor.h"
|
2017-11-13 18:45:23 +00:00
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
2022-04-11 17:23:10 +00:00
|
|
|
#include <map>
|
2018-02-27 00:33:41 +00:00
|
|
|
#include "envelope_component.h"
|
2022-04-11 17:23:10 +00:00
|
|
|
#include "CustomLookAndFeel.h"
|
2017-11-13 15:06:08 +00:00
|
|
|
|
2022-06-14 23:11:57 +00:00
|
|
|
class OptionsView;
|
|
|
|
|
2018-02-14 13:18:35 +00:00
|
|
|
class zoom_scrollbar : public Component
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum hot_area
|
|
|
|
{
|
|
|
|
ha_none,
|
|
|
|
ha_left_edge,
|
|
|
|
ha_right_edge,
|
|
|
|
ha_handle
|
|
|
|
};
|
|
|
|
void mouseDown(const MouseEvent& e) override;
|
|
|
|
void mouseMove(const MouseEvent& e) override;
|
|
|
|
void mouseDrag(const MouseEvent& e) override;
|
|
|
|
void mouseEnter(const MouseEvent &event) override;
|
|
|
|
void mouseExit(const MouseEvent &event) override;
|
2022-04-12 22:47:43 +00:00
|
|
|
void mouseDoubleClick (const MouseEvent&) override;
|
2022-04-22 03:04:30 +00:00
|
|
|
void mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wd) override;
|
2022-04-12 22:47:43 +00:00
|
|
|
|
2018-02-14 13:18:35 +00:00
|
|
|
void paint(Graphics &g) override;
|
|
|
|
std::function<void(Range<double>)> RangeChanged;
|
|
|
|
Range<double> get_range() const { return m_therange; }
|
|
|
|
void setRange(Range<double> rng, bool docallback);
|
|
|
|
private:
|
|
|
|
Range<double> m_therange{ 0.0,1.0 };
|
|
|
|
|
|
|
|
hot_area m_hot_area = ha_none;
|
|
|
|
hot_area get_hot_area(int x, int y);
|
|
|
|
int m_drag_start_x = 0;
|
2022-04-22 03:04:30 +00:00
|
|
|
int m_handle_off_x = 0;
|
2018-02-14 13:18:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-12-03 20:00:40 +00:00
|
|
|
class SpectralVisualizer : public Component
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SpectralVisualizer();
|
2017-12-03 21:28:54 +00:00
|
|
|
void setState(const ProcessParameters& pars, int nfreqs, double samplerate);
|
2017-12-03 20:00:40 +00:00
|
|
|
void paint(Graphics& g) override;
|
|
|
|
|
|
|
|
private:
|
|
|
|
Image m_img;
|
2017-12-03 20:51:57 +00:00
|
|
|
std::vector<REALTYPE> m_insamples,m_freqs1, m_freqs2, m_freqs3;
|
|
|
|
std::unique_ptr<FFT> m_fft;
|
|
|
|
int m_nfreqs = 0;
|
|
|
|
double m_elapsed = 0.0;
|
2017-12-03 20:00:40 +00:00
|
|
|
};
|
|
|
|
|
2017-11-24 22:22:07 +00:00
|
|
|
class MySlider : public Slider
|
|
|
|
{
|
|
|
|
public:
|
2017-12-13 22:19:46 +00:00
|
|
|
MySlider() {}
|
2018-01-03 17:32:53 +00:00
|
|
|
MySlider(NormalisableRange<float>* range);
|
|
|
|
double proportionOfLengthToValue(double x) override;
|
|
|
|
double valueToProportionOfLength(double x) override;
|
2017-11-24 22:22:07 +00:00
|
|
|
private:
|
|
|
|
NormalisableRange<float>* m_range = nullptr;
|
|
|
|
};
|
|
|
|
|
2017-11-13 18:45:23 +00:00
|
|
|
class ParameterComponent : public Component,
|
2022-04-28 02:52:40 +00:00
|
|
|
public Slider::Listener, public Button::Listener, public ComboBox::Listener
|
2017-11-13 18:45:23 +00:00
|
|
|
{
|
|
|
|
public:
|
2022-04-14 07:26:26 +00:00
|
|
|
ParameterComponent(AudioProcessorParameter* par, bool notifyOnlyOnRelease, bool useDrawableToggle=false);
|
2017-12-22 20:59:45 +00:00
|
|
|
void resized() override;
|
|
|
|
void sliderValueChanged(Slider* slid) override;
|
|
|
|
void sliderDragStarted(Slider* slid) override;
|
|
|
|
void sliderDragEnded(Slider* slid) override;
|
|
|
|
void buttonClicked(Button* but) override;
|
2022-04-28 02:52:40 +00:00
|
|
|
void comboBoxChanged (ComboBox* comboBoxThatHasChanged);
|
2017-12-22 20:59:45 +00:00
|
|
|
void updateComponent();
|
2018-02-01 13:11:41 +00:00
|
|
|
void setHighLighted(bool b);
|
|
|
|
int m_group_id = -1;
|
2022-04-14 07:26:26 +00:00
|
|
|
Slider* getSlider() const { return m_slider.get(); }
|
|
|
|
|
|
|
|
DrawableButton* getDrawableButton() const { return m_drawtogglebut.get(); }
|
|
|
|
ToggleButton* getToggleButton() const { return m_togglebut.get(); }
|
2022-04-28 02:52:40 +00:00
|
|
|
ComboBox* getComboBox() const { return m_combobox.get(); }
|
2022-04-14 07:26:26 +00:00
|
|
|
|
2017-11-13 18:45:23 +00:00
|
|
|
private:
|
|
|
|
Label m_label;
|
|
|
|
AudioProcessorParameter* m_par = nullptr;
|
2017-11-24 22:22:07 +00:00
|
|
|
std::unique_ptr<MySlider> m_slider;
|
2017-11-13 18:45:23 +00:00
|
|
|
std::unique_ptr<ComboBox> m_combobox;
|
|
|
|
std::unique_ptr<ToggleButton> m_togglebut;
|
2022-04-14 07:26:26 +00:00
|
|
|
std::unique_ptr<DrawableButton> m_drawtogglebut;
|
2017-11-17 14:41:33 +00:00
|
|
|
bool m_notify_only_on_release = false;
|
|
|
|
bool m_dragging = false;
|
2018-02-01 13:11:41 +00:00
|
|
|
Colour m_labeldefcolor;
|
2017-11-13 18:45:23 +00:00
|
|
|
};
|
2017-11-13 15:06:08 +00:00
|
|
|
|
2022-04-11 17:23:10 +00:00
|
|
|
class ParameterGroupComponent : public Component
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ParameterGroupComponent(const String & name, int groupid, PaulstretchpluginAudioProcessor* proc, bool showtoggle=true);
|
|
|
|
|
|
|
|
void resized() override;
|
|
|
|
void paint(Graphics &g) override;
|
|
|
|
|
|
|
|
//void addParameterComponent(std::unique_ptr<ParameterComponent> pcomp);
|
|
|
|
void addParameterComponent(ParameterComponent * pcomp);
|
2022-04-11 22:50:55 +00:00
|
|
|
void replaceParameterComponent(ParameterComponent * oldcomp, ParameterComponent * newcomp);
|
2022-04-11 17:23:10 +00:00
|
|
|
|
|
|
|
void updateParameterComponents();
|
|
|
|
|
|
|
|
void setBackgroundColor(Colour col) { m_bgcolor = col; }
|
|
|
|
Colour getBackgroundColor() const { return m_bgcolor; }
|
|
|
|
|
2022-04-28 02:52:40 +00:00
|
|
|
void setSelectedBackgroundColor(Colour col) { m_selbgcolor = col; }
|
|
|
|
Colour getSelectedBBackgroundColor() const { return m_selbgcolor; }
|
|
|
|
|
2022-04-14 07:26:26 +00:00
|
|
|
void setToggleEnabled(bool flag){ if (m_enableButton) m_enableButton->setToggleState(flag, dontSendNotification); }
|
|
|
|
bool getToggleEnabled() const { if (m_enableButton) return m_enableButton->getToggleState(); return false; }
|
|
|
|
|
2022-04-11 17:23:10 +00:00
|
|
|
String name;
|
|
|
|
int groupId = -1;
|
2022-04-28 02:52:40 +00:00
|
|
|
bool allowDisableFade = true;
|
2022-04-11 17:23:10 +00:00
|
|
|
|
|
|
|
int getMinimumHeight(int forWidth);
|
|
|
|
|
|
|
|
std::function<void(void)> EnabledChangedCallback;
|
|
|
|
|
|
|
|
private:
|
2022-04-14 20:31:54 +00:00
|
|
|
int doLayout(juce::Rectangle<int> bounds); // returns min height
|
2022-04-11 17:23:10 +00:00
|
|
|
|
|
|
|
//uptrvec<ParameterComponent> m_parcomps;
|
|
|
|
std::vector<ParameterComponent*> m_parcomps;
|
|
|
|
std::unique_ptr<Label> m_namelabel;
|
2022-04-12 22:47:43 +00:00
|
|
|
std::unique_ptr<DrawableButton> m_enableButton;
|
|
|
|
//std::unique_ptr<ToggleButton> m_enableButton;
|
2022-04-11 17:23:10 +00:00
|
|
|
|
|
|
|
CriticalSection* m_cs = nullptr;
|
|
|
|
PaulstretchpluginAudioProcessor* m_proc = nullptr;
|
|
|
|
int m_slidwidth = 400;
|
|
|
|
|
|
|
|
Colour m_bgcolor;
|
2022-04-12 22:47:43 +00:00
|
|
|
Colour m_selbgcolor;
|
2022-04-11 17:23:10 +00:00
|
|
|
|
|
|
|
int m_minHeight = 0;
|
|
|
|
int m_lastForWidth = -1;
|
|
|
|
int m_lastCompSize = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-05-01 15:35:00 +00:00
|
|
|
class PerfMeterComponent : public Component, public Timer
|
2018-01-31 18:58:16 +00:00
|
|
|
{
|
|
|
|
public:
|
2018-02-02 10:23:57 +00:00
|
|
|
PerfMeterComponent(PaulstretchpluginAudioProcessor* p);
|
|
|
|
void paint(Graphics& g) override;
|
2018-02-07 13:12:10 +00:00
|
|
|
void mouseDown(const MouseEvent& ev) override;
|
2018-05-01 15:35:00 +00:00
|
|
|
void timerCallback() override;
|
2018-01-31 18:58:16 +00:00
|
|
|
PaulstretchpluginAudioProcessor* m_proc = nullptr;
|
2022-04-12 22:47:43 +00:00
|
|
|
|
|
|
|
bool enabled = true;
|
2018-02-15 23:55:33 +00:00
|
|
|
private:
|
|
|
|
ColourGradient m_gradient;
|
2018-01-31 18:58:16 +00:00
|
|
|
};
|
|
|
|
|
2017-11-23 17:36:46 +00:00
|
|
|
class MyThumbCache : public AudioThumbnailCache
|
|
|
|
{
|
|
|
|
public:
|
2018-05-18 18:19:07 +00:00
|
|
|
MyThumbCache() : AudioThumbnailCache(200)
|
|
|
|
{
|
|
|
|
// The default priority of 2 is a bit too low in some cases, it seems...
|
|
|
|
getTimeSliceThread().setPriority(3);
|
|
|
|
}
|
|
|
|
~MyThumbCache() {}
|
2017-11-23 17:36:46 +00:00
|
|
|
};
|
|
|
|
|
2017-11-13 21:42:13 +00:00
|
|
|
class WaveformComponent : public Component, public ChangeListener, public Timer
|
|
|
|
{
|
|
|
|
public:
|
2018-09-13 10:47:19 +00:00
|
|
|
WaveformComponent(AudioFormatManager* afm, AudioThumbnail* thumb, StretchAudioSource* sas);
|
2017-11-13 21:42:13 +00:00
|
|
|
~WaveformComponent();
|
|
|
|
void changeListenerCallback(ChangeBroadcaster* cb) override;
|
|
|
|
void paint(Graphics& g) override;
|
2018-01-20 19:50:24 +00:00
|
|
|
void timerCallback() override;
|
2017-11-13 21:42:13 +00:00
|
|
|
std::function<double()> CursorPosCallback;
|
|
|
|
std::function<void(double)> SeekCallback;
|
|
|
|
std::function<void(Range<double>, int)> TimeSelectionChangedCallback;
|
2022-04-13 17:48:09 +00:00
|
|
|
std::function<URL()> GetFileCallback;
|
2018-03-02 20:49:32 +00:00
|
|
|
std::function<void(Range<double>)> ViewRangeChangedCallback;
|
2017-11-13 21:42:13 +00:00
|
|
|
void mouseDown(const MouseEvent& e) override;
|
|
|
|
void mouseUp(const MouseEvent& e) override;
|
|
|
|
void mouseDrag(const MouseEvent& e) override;
|
|
|
|
void mouseMove(const MouseEvent& e) override;
|
2018-01-20 20:21:26 +00:00
|
|
|
void mouseDoubleClick(const MouseEvent& e) override;
|
2018-03-02 20:49:32 +00:00
|
|
|
void mouseWheelMove(const MouseEvent& e, const MouseWheelDetails& wd) override;
|
2022-04-18 19:11:22 +00:00
|
|
|
void mouseMagnify (const MouseEvent& event, float scaleFactor) override;
|
2018-05-11 13:45:34 +00:00
|
|
|
void setAudioInfo(double sr, double seekpos, int fftsize);
|
2018-01-03 17:32:53 +00:00
|
|
|
Range<double> getTimeSelection();
|
|
|
|
void setTimeSelection(Range<double> rng);
|
2017-11-13 21:42:13 +00:00
|
|
|
void setFileCachedRange(std::pair<Range<double>, Range<double>> rng);
|
|
|
|
void setTimerEnabled(bool b);
|
|
|
|
void setViewRange(Range<double> rng);
|
2019-02-28 14:44:14 +00:00
|
|
|
String m_infotext;
|
2017-11-15 15:52:47 +00:00
|
|
|
void setRecordingPosition(double pos) { m_rec_pos = pos; }
|
2018-02-12 18:51:05 +00:00
|
|
|
int m_image_init_count = 0;
|
|
|
|
int m_image_update_count = 0;
|
2017-11-13 21:42:13 +00:00
|
|
|
private:
|
2018-01-17 16:57:56 +00:00
|
|
|
AudioThumbnail* m_thumbnail = nullptr;
|
2017-11-13 21:42:13 +00:00
|
|
|
Range<double> m_view_range{ 0.0,1.0 };
|
|
|
|
int m_time_sel_drag_target = 0;
|
|
|
|
double m_time_sel_start = -1.0;
|
|
|
|
double m_time_sel_end = -1.0;
|
|
|
|
double m_drag_time_start = 0.0;
|
|
|
|
bool m_mousedown = false;
|
|
|
|
bool m_didseek = false;
|
|
|
|
bool m_didchangetimeselection = false;
|
|
|
|
int m_topmargin = 0;
|
2022-04-15 18:29:23 +00:00
|
|
|
bool m_timedrag_started = false;
|
2017-11-13 21:42:13 +00:00
|
|
|
int getTimeSelectionEdge(int x, int y);
|
|
|
|
std::pair<Range<double>, Range<double>> m_file_cached;
|
2018-02-12 18:51:05 +00:00
|
|
|
bool m_image_dirty = false;
|
2018-05-11 13:45:34 +00:00
|
|
|
double m_sr = 0.0;
|
|
|
|
int m_fft_size = 0;
|
|
|
|
double m_last_startpos = 0.0;
|
2018-09-13 10:47:19 +00:00
|
|
|
int64_t m_last_source_pos = -1;
|
|
|
|
double m_last_source_pos_update_time = 0.0;
|
2017-11-13 21:42:13 +00:00
|
|
|
Image m_waveimage;
|
2018-09-13 10:47:19 +00:00
|
|
|
StretchAudioSource* m_sas = nullptr;
|
2018-04-02 17:07:55 +00:00
|
|
|
#ifdef JUCE_MODULE_AVAILABLE_juce_opengl
|
2017-11-13 21:42:13 +00:00
|
|
|
OpenGLContext m_ogl;
|
|
|
|
bool m_use_opengl = false;
|
2018-04-02 17:07:55 +00:00
|
|
|
#endif
|
2017-11-15 15:52:47 +00:00
|
|
|
double m_rec_pos = 0.0;
|
2017-11-16 14:58:04 +00:00
|
|
|
bool m_lock_timesel_set = false;
|
2017-12-13 03:23:57 +00:00
|
|
|
bool m_using_audio_buffer = false;
|
2018-02-23 15:43:29 +00:00
|
|
|
bool m_is_at_selection_drag_area = false;
|
2018-02-23 16:21:28 +00:00
|
|
|
bool m_is_dragging_selection = false;
|
2018-02-12 18:51:05 +00:00
|
|
|
void updateCachedImage();
|
2018-02-22 12:22:06 +00:00
|
|
|
double viewXToNormalized(double xcor)
|
|
|
|
{
|
|
|
|
return jmap<double>(xcor, 0, getWidth(), m_view_range.getStart(), m_view_range.getEnd());
|
|
|
|
}
|
|
|
|
template<typename T>
|
|
|
|
inline T normalizedToViewX(double norm)
|
|
|
|
{
|
|
|
|
return static_cast<T>(jmap<double>(norm, m_view_range.getStart(), m_view_range.getEnd(), 0, getWidth()));
|
|
|
|
}
|
2017-11-13 21:42:13 +00:00
|
|
|
};
|
|
|
|
|
2017-12-13 17:55:35 +00:00
|
|
|
class SpectralChainEditor : public Component
|
|
|
|
{
|
|
|
|
public:
|
2022-04-13 23:24:44 +00:00
|
|
|
SpectralChainEditor();
|
2017-12-13 17:55:35 +00:00
|
|
|
void paint(Graphics& g) override;
|
2018-01-03 17:32:53 +00:00
|
|
|
void setSource(StretchAudioSource* src);
|
2017-12-13 17:55:35 +00:00
|
|
|
void mouseDown(const MouseEvent& ev) override;
|
|
|
|
void mouseDrag(const MouseEvent& ev) override;
|
|
|
|
void mouseUp(const MouseEvent& ev) override;
|
2018-02-01 13:11:41 +00:00
|
|
|
std::function<void(int)> ModuleSelectedCallback;
|
2018-02-09 11:02:10 +00:00
|
|
|
std::function<void(void)> ModuleOrderOrEnabledChangedCallback;
|
2018-03-02 17:33:47 +00:00
|
|
|
const std::vector <SpectrumProcess>& getOrder() const { return m_order; }
|
2018-03-03 20:48:24 +00:00
|
|
|
void setModuleSelected(int id);
|
2018-03-03 21:06:06 +00:00
|
|
|
void moveModule(int old_id, int new_id);
|
2017-12-13 17:55:35 +00:00
|
|
|
private:
|
|
|
|
StretchAudioSource * m_src = nullptr;
|
|
|
|
bool m_did_drag = false;
|
|
|
|
int m_cur_index = -1;
|
2017-12-13 19:25:42 +00:00
|
|
|
int m_drag_x = 0;
|
2022-04-11 17:23:10 +00:00
|
|
|
int m_downoffset_x = 0;
|
2018-01-31 22:06:32 +00:00
|
|
|
std::vector<SpectrumProcess> m_order;
|
2022-04-13 23:24:44 +00:00
|
|
|
std::unique_ptr<Drawable> m_enabledImage;
|
|
|
|
std::unique_ptr<Drawable> m_disabledImage;
|
|
|
|
Colour m_bgcolor;
|
|
|
|
Colour m_selbgcolor;
|
|
|
|
Colour m_dragbgcolor;
|
|
|
|
|
2017-12-13 19:25:42 +00:00
|
|
|
void drawBox(Graphics& g, int index, int x, int y, int w, int h);
|
2017-12-13 17:55:35 +00:00
|
|
|
};
|
|
|
|
|
2018-04-03 13:34:20 +00:00
|
|
|
class RatioMixerEditor : public Component, public Timer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RatioMixerEditor(int numratios);
|
|
|
|
void resized() override;
|
|
|
|
std::function<void(int, double)> OnRatioChanged;
|
|
|
|
std::function<void(int, double)> OnRatioLevelChanged;
|
|
|
|
std::function<double(int which, int index)> GetParameterValue;
|
|
|
|
void timerCallback() override;
|
2018-04-03 19:04:10 +00:00
|
|
|
void paint(Graphics& g) override;
|
2022-04-15 23:13:55 +00:00
|
|
|
void setSlidersSnap(bool flag);
|
2018-04-03 13:34:20 +00:00
|
|
|
private:
|
|
|
|
uptrvec<Slider> m_ratio_sliders;
|
|
|
|
uptrvec<Slider> m_ratio_level_sliders;
|
2022-04-15 18:29:23 +00:00
|
|
|
uptrvec<Label> m_labels;
|
2018-04-03 13:34:20 +00:00
|
|
|
};
|
|
|
|
|
2018-06-29 11:23:48 +00:00
|
|
|
class FreeFilterComponent : public Component
|
|
|
|
{
|
|
|
|
public:
|
2018-06-29 11:49:11 +00:00
|
|
|
FreeFilterComponent(PaulstretchpluginAudioProcessor* proc);
|
2018-06-29 11:23:48 +00:00
|
|
|
void resized() override;
|
|
|
|
EnvelopeComponent* getEnvelopeComponent() { return &m_env; }
|
2018-06-29 11:49:11 +00:00
|
|
|
void paint(Graphics &g) override;
|
|
|
|
void updateParameterComponents();
|
2022-04-15 23:13:55 +00:00
|
|
|
void setSlidersSnap(bool flag);
|
2018-06-29 11:23:48 +00:00
|
|
|
private:
|
|
|
|
EnvelopeComponent m_env;
|
|
|
|
uptrvec<ParameterComponent> m_parcomps;
|
2022-04-14 07:26:26 +00:00
|
|
|
std::unique_ptr<Viewport> m_viewport;
|
|
|
|
Component m_container;
|
|
|
|
CriticalSection* m_cs = nullptr;
|
2018-06-29 11:49:11 +00:00
|
|
|
PaulstretchpluginAudioProcessor* m_proc = nullptr;
|
2022-04-11 17:23:10 +00:00
|
|
|
int m_slidwidth = 350;
|
2018-06-29 11:23:48 +00:00
|
|
|
};
|
|
|
|
|
2018-06-29 12:13:49 +00:00
|
|
|
class MyTabComponent : public TabbedComponent
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MyTabComponent(int& curtab) : TabbedComponent(TabbedButtonBar::TabsAtTop), m_cur_tab(curtab) {}
|
|
|
|
void currentTabChanged(int newCurrentTabIndex, const String&) override
|
|
|
|
{
|
2018-06-29 17:53:34 +00:00
|
|
|
//m_cur_tab = newCurrentTabIndex;
|
2018-08-07 21:10:27 +00:00
|
|
|
|
2018-06-29 12:13:49 +00:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
int& m_cur_tab;
|
2018-08-07 21:10:27 +00:00
|
|
|
|
2018-06-29 12:13:49 +00:00
|
|
|
};
|
|
|
|
|
2019-01-17 16:30:40 +00:00
|
|
|
class SimpleFFTComponent : public Component,
|
|
|
|
private Timer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SimpleFFTComponent() :
|
|
|
|
|
|
|
|
forwardFFT(fftOrder),
|
|
|
|
spectrogramImage(Image::RGB, 512, 512, true)
|
|
|
|
{
|
|
|
|
setOpaque(true);
|
|
|
|
startTimerHz(60);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
~SimpleFFTComponent()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void addAudioBlock(const AudioBuffer<float>& bufferToFill)
|
|
|
|
{
|
|
|
|
if (bufferToFill.getNumChannels() > 0)
|
|
|
|
{
|
|
|
|
const auto* channelData = bufferToFill.getReadPointer(0);
|
|
|
|
|
|
|
|
for (auto i = 0; i < bufferToFill.getNumSamples(); ++i)
|
|
|
|
pushNextSampleIntoFifo(channelData[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void resized() override
|
|
|
|
{
|
|
|
|
spectrogramImage = Image(Image::RGB, getWidth(), getHeight(), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void paint(Graphics& g) override
|
|
|
|
{
|
|
|
|
g.fillAll(Colours::black);
|
|
|
|
|
|
|
|
g.setOpacity(1.0f);
|
|
|
|
g.drawImage(spectrogramImage, getLocalBounds().toFloat());
|
|
|
|
}
|
|
|
|
|
|
|
|
void timerCallback() override
|
|
|
|
{
|
|
|
|
if (nextFFTBlockReady)
|
|
|
|
{
|
|
|
|
drawNextLineOfSpectrogram();
|
|
|
|
nextFFTBlockReady = false;
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void pushNextSampleIntoFifo(float sample) noexcept
|
|
|
|
{
|
|
|
|
// if the fifo contains enough data, set a flag to say
|
|
|
|
// that the next line should now be rendered..
|
|
|
|
if (fifoIndex == fftSize)
|
|
|
|
{
|
|
|
|
if (!nextFFTBlockReady)
|
|
|
|
{
|
|
|
|
zeromem(fftData, sizeof(fftData));
|
|
|
|
memcpy(fftData, fifo, sizeof(fifo));
|
|
|
|
nextFFTBlockReady = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
fifoIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fifo[fifoIndex++] = sample;
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawNextLineOfSpectrogram()
|
|
|
|
{
|
|
|
|
auto rightHandEdge = spectrogramImage.getWidth() - 1;
|
|
|
|
auto imageHeight = spectrogramImage.getHeight();
|
|
|
|
|
|
|
|
// first, shuffle our image leftwards by 1 pixel..
|
|
|
|
spectrogramImage.moveImageSection(0, 0, 1, 0, rightHandEdge, imageHeight);
|
|
|
|
|
|
|
|
// then render our FFT data..
|
|
|
|
forwardFFT.performFrequencyOnlyForwardTransform(fftData);
|
|
|
|
|
|
|
|
// find the range of values produced, so we can scale our rendering to
|
|
|
|
// show up the detail clearly
|
|
|
|
auto maxLevel = FloatVectorOperations::findMinAndMax(fftData, fftSize / 2);
|
|
|
|
|
|
|
|
for (auto y = 1; y < imageHeight; ++y)
|
|
|
|
{
|
|
|
|
auto skewedProportionY = 1.0f - std::exp(std::log(y / (float)imageHeight) * 0.2f);
|
|
|
|
auto fftDataIndex = jlimit(0, fftSize / 2, (int)(skewedProportionY * fftSize / 2));
|
|
|
|
auto level = jmap(fftData[fftDataIndex], 0.0f, jmax(maxLevel.getEnd(), 1e-5f), 0.0f, 1.0f);
|
|
|
|
|
|
|
|
spectrogramImage.setPixelAt(rightHandEdge, y, Colour::fromHSV(level, 1.0f, level, 1.0f));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
fftOrder = 10,
|
|
|
|
fftSize = 1 << fftOrder
|
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
dsp::FFT forwardFFT;
|
|
|
|
Image spectrogramImage;
|
|
|
|
|
|
|
|
float fifo[fftSize];
|
|
|
|
float fftData[8 * fftSize];
|
|
|
|
int fifoIndex = 0;
|
|
|
|
bool nextFFTBlockReady = false;
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-09-26 16:19:10 +00:00
|
|
|
class AudioFilePreviewComponent : public FilePreviewComponent
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AudioFilePreviewComponent(PaulstretchpluginAudioProcessor* p) : m_proc(p)
|
|
|
|
{
|
|
|
|
addAndMakeVisible(m_playbut);
|
|
|
|
m_playbut.setButtonText("Play");
|
|
|
|
m_playbut.onClick = [this]()
|
|
|
|
{
|
|
|
|
|
|
|
|
};
|
|
|
|
setSize(100, 30);
|
|
|
|
}
|
|
|
|
void selectedFileChanged(const File &newSelectedFile) override
|
|
|
|
{
|
|
|
|
ScopedLock locker(m_proc->getCriticalSection());
|
|
|
|
m_reader = unique_from_raw(m_proc->m_afm->createReaderFor(newSelectedFile));
|
|
|
|
m_playpos = 0;
|
|
|
|
}
|
|
|
|
void resized() override
|
|
|
|
{
|
|
|
|
m_playbut.setBounds(0, 0, getWidth(), getHeight());
|
|
|
|
}
|
|
|
|
void togglePlay()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
void processBlock(double sr, AudioBuffer<float>& buf);
|
|
|
|
private:
|
|
|
|
TextButton m_playbut;
|
|
|
|
PaulstretchpluginAudioProcessor* m_proc = nullptr;
|
|
|
|
std::unique_ptr<AudioFormatReader> m_reader;
|
|
|
|
int64 m_playpos = 0;
|
|
|
|
};
|
|
|
|
|
2019-01-23 12:38:48 +00:00
|
|
|
class MyFileBrowserComponent : public Component, public FileBrowserListener
|
2019-01-21 19:17:05 +00:00
|
|
|
{
|
|
|
|
public:
|
2019-01-23 12:38:48 +00:00
|
|
|
MyFileBrowserComponent(PaulstretchpluginAudioProcessor& p);
|
2019-02-19 18:25:24 +00:00
|
|
|
~MyFileBrowserComponent();
|
2019-01-23 12:38:48 +00:00
|
|
|
void resized() override;
|
|
|
|
void paint(Graphics& g) override;
|
|
|
|
std::function<void(int, File)> OnAction;
|
|
|
|
void selectionChanged() override;
|
2019-01-21 19:17:05 +00:00
|
|
|
|
2019-01-23 12:38:48 +00:00
|
|
|
/** Callback when the user clicks on a file in the browser. */
|
|
|
|
void fileClicked(const File& file, const MouseEvent& e) override;
|
|
|
|
|
|
|
|
/** Callback when the user double-clicks on a file in the browser. */
|
|
|
|
void fileDoubleClicked(const File& file) override;
|
|
|
|
|
|
|
|
/** Callback when the browser's root folder changes. */
|
|
|
|
void browserRootChanged(const File& newRoot) override;
|
2019-01-21 19:17:05 +00:00
|
|
|
private:
|
|
|
|
std::unique_ptr<FileBrowserComponent> m_fbcomp;
|
2019-01-23 12:38:48 +00:00
|
|
|
WildcardFileFilter m_filefilter;
|
|
|
|
PaulstretchpluginAudioProcessor& m_proc;
|
2019-02-19 18:25:24 +00:00
|
|
|
LookAndFeel_V3 m_filebwlookandfeel;
|
2019-01-21 19:17:05 +00:00
|
|
|
};
|
|
|
|
|
2017-11-13 18:54:08 +00:00
|
|
|
class PaulstretchpluginAudioProcessorEditor : public AudioProcessorEditor,
|
2022-06-14 23:11:57 +00:00
|
|
|
public MultiTimer, public FileDragAndDropTarget, public DragAndDropContainer, public ComponentListener
|
|
|
|
|
2017-11-13 15:06:08 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
PaulstretchpluginAudioProcessorEditor (PaulstretchpluginAudioProcessor&);
|
|
|
|
~PaulstretchpluginAudioProcessorEditor();
|
2020-12-11 02:02:36 +00:00
|
|
|
/*
|
|
|
|
void parentHierarchyChanged() override {
|
|
|
|
if (JUCEApplicationBase::isStandaloneApp()) {
|
|
|
|
auto* comp = getTopLevelComponent();
|
|
|
|
|
|
|
|
if (auto window = dynamic_cast<DocumentWindow*>(comp)) {
|
|
|
|
window->setUsingNativeTitleBar(true);
|
|
|
|
window->setResizable(true, false);
|
|
|
|
window->setTitleBarButtonsRequired(DocumentWindow::TitleBarButtons::allButtons, false);
|
|
|
|
window->setSize(800, 600);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
2017-11-16 15:38:59 +00:00
|
|
|
void paint (Graphics&) override;
|
2017-11-13 15:06:08 +00:00
|
|
|
void resized() override;
|
2017-11-13 18:54:08 +00:00
|
|
|
void timerCallback(int id) override;
|
2018-01-18 04:56:23 +00:00
|
|
|
|
2017-12-27 14:56:37 +00:00
|
|
|
bool isInterestedInFileDrag(const StringArray &files) override;
|
|
|
|
void filesDropped(const StringArray &files, int x, int y) override;
|
|
|
|
|
2018-10-07 11:29:50 +00:00
|
|
|
bool keyPressed(const KeyPress& press) override;
|
|
|
|
|
2022-06-14 23:11:57 +00:00
|
|
|
void componentParentHierarchyChanged (Component& component) override;
|
|
|
|
|
|
|
|
|
2017-11-15 19:47:26 +00:00
|
|
|
WaveformComponent m_wavecomponent;
|
2019-01-21 17:25:27 +00:00
|
|
|
|
2018-05-07 17:21:42 +00:00
|
|
|
void showRenderDialog();
|
2019-02-12 12:59:51 +00:00
|
|
|
//SimpleFFTComponent m_sonogram;
|
2019-01-21 14:10:17 +00:00
|
|
|
String m_last_err;
|
2022-04-11 17:23:10 +00:00
|
|
|
|
2022-04-11 22:50:55 +00:00
|
|
|
void urlOpened(const URL& url);
|
|
|
|
|
2022-04-11 17:23:10 +00:00
|
|
|
std::function<AudioDeviceManager*()> getAudioDeviceManager;
|
|
|
|
std::function<void(Component*,Component*)> showAudioSettingsDialog;
|
|
|
|
|
2017-11-13 15:06:08 +00:00
|
|
|
private:
|
2022-04-11 17:23:10 +00:00
|
|
|
|
|
|
|
bool isSpectrumProcGroupEnabled(int groupid);
|
2022-04-11 22:50:55 +00:00
|
|
|
void setSpectrumProcGroupEnabled(int groupid, bool enabled);
|
2022-04-11 17:23:10 +00:00
|
|
|
|
2022-04-15 23:13:55 +00:00
|
|
|
void updateAllSliders();
|
|
|
|
|
2022-06-14 23:11:57 +00:00
|
|
|
void toggleOutputRecording();
|
|
|
|
|
2022-04-11 17:23:10 +00:00
|
|
|
CustomLookAndFeel m_lookandfeel;
|
|
|
|
|
2018-11-13 20:18:05 +00:00
|
|
|
PaulstretchpluginAudioProcessor& processor;
|
2018-04-03 13:34:20 +00:00
|
|
|
uptrvec<ParameterComponent> m_parcomps;
|
2022-04-11 17:23:10 +00:00
|
|
|
std::map<int, std::unique_ptr<ParameterGroupComponent> > m_pargroups;
|
|
|
|
std::unique_ptr<ParameterGroupComponent> m_posgroup;
|
|
|
|
std::unique_ptr<ParameterGroupComponent> m_stretchgroup;
|
2022-04-28 02:52:40 +00:00
|
|
|
std::unique_ptr<ParameterGroupComponent> m_binauralgroup;
|
2022-04-11 17:23:10 +00:00
|
|
|
|
|
|
|
std::unique_ptr<Viewport> m_groupviewport;
|
|
|
|
std::unique_ptr<Component> m_groupcontainer;
|
|
|
|
|
|
|
|
|
2017-12-17 16:16:39 +00:00
|
|
|
//SpectralVisualizer m_specvis;
|
2018-01-31 18:58:16 +00:00
|
|
|
PerfMeterComponent m_perfmeter;
|
2017-11-14 16:14:14 +00:00
|
|
|
TextButton m_import_button;
|
2017-12-19 22:50:47 +00:00
|
|
|
TextButton m_settings_button;
|
2018-05-07 17:21:42 +00:00
|
|
|
TextButton m_render_button;
|
2022-04-14 07:26:26 +00:00
|
|
|
std::unique_ptr<DrawableButton> m_rewind_button;
|
2017-11-13 20:35:36 +00:00
|
|
|
Label m_info_label;
|
2017-12-13 17:55:35 +00:00
|
|
|
SpectralChainEditor m_spec_order_ed;
|
2022-04-11 22:50:55 +00:00
|
|
|
double m_lastspec_select_time = 0.0;
|
|
|
|
int m_lastspec_select_group = -1;
|
2022-04-13 23:24:44 +00:00
|
|
|
bool m_shortMode = false;
|
2022-06-14 23:11:57 +00:00
|
|
|
File m_lastRecordedFile;
|
|
|
|
std::unique_ptr<Label> m_fileRecordingLabel;
|
|
|
|
std::unique_ptr<DrawableButton> m_recordingButton;
|
|
|
|
|
|
|
|
bool settingsWasShownOnDown = false;
|
|
|
|
uint32 settingsClosedTimestamp = 0;
|
|
|
|
WeakReference<Component> settingsCalloutBox;
|
|
|
|
std::unique_ptr<OptionsView> m_optionsView;
|
2022-04-11 22:50:55 +00:00
|
|
|
|
2019-01-21 14:10:17 +00:00
|
|
|
|
2018-02-14 13:18:35 +00:00
|
|
|
zoom_scrollbar m_zs;
|
2018-04-03 13:34:20 +00:00
|
|
|
RatioMixerEditor m_ratiomixeditor{ 8 };
|
2018-06-29 11:23:48 +00:00
|
|
|
FreeFilterComponent m_free_filter_component;
|
2019-01-17 16:30:40 +00:00
|
|
|
|
2018-06-29 12:13:49 +00:00
|
|
|
MyTabComponent m_wavefilter_tab;
|
2018-02-27 20:15:14 +00:00
|
|
|
Component* m_wave_container=nullptr;
|
2022-04-11 17:23:10 +00:00
|
|
|
void showAudioSetup();
|
2022-06-14 23:11:57 +00:00
|
|
|
void showSettings(bool flag);
|
2019-01-21 22:09:28 +00:00
|
|
|
void toggleFileBrowser();
|
2018-11-13 20:18:05 +00:00
|
|
|
std::vector<int> m_capturelens{ 2,5,10,30,60,120 };
|
2019-01-21 14:10:17 +00:00
|
|
|
|
2019-01-23 12:38:48 +00:00
|
|
|
std::unique_ptr<MyFileBrowserComponent> m_filechooser;
|
2022-04-11 22:50:55 +00:00
|
|
|
std::unique_ptr<FileChooser> fileChooser;
|
2019-01-21 17:25:27 +00:00
|
|
|
WildcardFileFilter m_filefilter;
|
2022-04-14 07:26:26 +00:00
|
|
|
|
|
|
|
class CustomTooltipWindow : public TooltipWindow
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CustomTooltipWindow(PaulstretchpluginAudioProcessorEditor * parent_, Component * viewparent) : TooltipWindow(viewparent), parent(parent_) {}
|
|
|
|
virtual ~CustomTooltipWindow() {
|
|
|
|
if (parent) {
|
|
|
|
// reset our smart pointer without a delete! someone else is deleting it
|
|
|
|
parent->tooltipWindow.release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
String getTipFor (Component& c) override
|
|
|
|
{
|
|
|
|
if (parent->popTip && parent->popTip->isShowing()) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
return TooltipWindow::getTipFor(c);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
PaulstretchpluginAudioProcessorEditor * parent;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::unique_ptr<CustomTooltipWindow> tooltipWindow;
|
|
|
|
|
2018-02-22 12:22:06 +00:00
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PaulstretchpluginAudioProcessorEditor)
|
2017-11-13 15:06:08 +00:00
|
|
|
};
|
2017-11-23 17:12:29 +00:00
|
|
|
|