Vital
Loading...
Searching...
No Matches
sample_section.cpp
Go to the documentation of this file.
1#include "sample_section.h"
2
3#include "load_save.h"
4#include "skin.h"
5#include "fonts.h"
6#include "paths.h"
7#include "sample_viewer.h"
8#include "synth_button.h"
10#include "synth_slider.h"
11#include "synth_strings.h"
12#include "text_look_and_feel.h"
13
14SampleSection::SampleSection(String name) : SynthSection(std::move(name)), sample_(nullptr) {
15 transpose_quantize_button_ = std::make_unique<TransposeQuantizeButton>();
16 addOpenGlComponent(transpose_quantize_button_.get());
17 transpose_quantize_button_->addQuantizeListener(this);
18
19 transpose_ = std::make_unique<SynthSlider>("sample_transpose");
20 addSlider(transpose_.get());
21 transpose_->setLookAndFeel(TextLookAndFeel::instance());
22 transpose_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
23 transpose_->setSensitivity(kTransposeMouseSensitivity);
24 transpose_->setTextEntrySizePercent(1.0f, 0.7f);
25 transpose_->setShiftIndexAmount(vital::kNotesPerOctave);
26 transpose_->overrideValue(Skin::kTextComponentOffset, 0.0f);
27 transpose_->setModulationBarRight(false);
28
29 tune_ = std::make_unique<SynthSlider>("sample_tune");
30 addSlider(tune_.get());
31 tune_->setLookAndFeel(TextLookAndFeel::instance());
32 tune_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
33 tune_->setMaxDisplayCharacters(3);
34 tune_->setMaxDecimalPlaces(0);
35 tune_->setTextEntrySizePercent(1.0f, 0.7f);
36 tune_->overrideValue(Skin::kTextComponentOffset, 0.0f);
37
38 level_ = std::make_unique<SynthSlider>("sample_level");
39 addSlider(level_.get());
40 level_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
41
42 pan_ = std::make_unique<SynthSlider>("sample_pan");
43 addSlider(pan_.get());
44 pan_->setBipolar();
45 pan_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
46
47 sample_viewer_ = std::make_unique<SampleViewer>();
48 addOpenGlComponent(sample_viewer_.get());
49 addAndMakeVisible(sample_viewer_.get());
50 sample_viewer_->addListener(this);
51
52 preset_selector_ = std::make_unique<PresetSelector>();
53 addSubSection(preset_selector_.get());
54 preset_selector_->addListener(this);
55 setPresetSelector(preset_selector_.get());
56
57 destination_selector_ = std::make_unique<ShapeButton>("Destination", Colour(0xff666666),
58 Colour(0xffaaaaaa), Colour(0xff888888));
59
60 current_destination_ = 0;
61 destination_control_name_ = "sample_destination";
62 destination_text_ = std::make_unique<PlainTextComponent>("Destination Text", "---");
63 addOpenGlComponent(destination_text_.get());
64
65 addAndMakeVisible(destination_selector_.get());
66 destination_selector_->addListener(this);
67 destination_selector_->setTriggeredOnMouseDown(true);
68 destination_selector_->setShape(Path(), true, true, true);
69
70 prev_destination_ = std::make_unique<OpenGlShapeButton>("Prev Destination");
71 addAndMakeVisible(prev_destination_.get());
72 addOpenGlComponent(prev_destination_->getGlComponent());
73 prev_destination_->addListener(this);
74 prev_destination_->setShape(Paths::prev());
75
76 next_destination_ = std::make_unique<OpenGlShapeButton>("Next Destination");
77 addAndMakeVisible(next_destination_.get());
78 addOpenGlComponent(next_destination_->getGlComponent());
79 next_destination_->addListener(this);
80 next_destination_->setShape(Paths::next());
81
82 keytrack_ = std::make_unique<OpenGlShapeButton>("sample_keytrack");
83 keytrack_->useOnColors(true);
84 keytrack_->setClickingTogglesState(true);
85 addButton(keytrack_.get());
86 keytrack_->addListener(this);
87 keytrack_->setShape(Paths::keyboard());
88
89 random_phase_ = std::make_unique<OpenGlShapeButton>("sample_random_phase");
90 random_phase_->useOnColors(true);
91 random_phase_->setClickingTogglesState(true);
92 addButton(random_phase_.get());
93 random_phase_->addListener(this);
94 random_phase_->addListener(this);
95 random_phase_->setShape(Paths::shuffle());
96
97 loop_ = std::make_unique<OpenGlShapeButton>("sample_loop");
98 loop_->useOnColors(true);
99 loop_->setClickingTogglesState(true);
100 addButton(loop_.get());
101 loop_->addListener(this);
102 loop_->setShape(Paths::loop());
103
104 bounce_ = std::make_unique<OpenGlShapeButton>("sample_bounce");
105 bounce_->useOnColors(true);
106 bounce_->setClickingTogglesState(true);
107 addButton(bounce_.get());
108 bounce_->addListener(this);
109 bounce_->setShape(Paths::bounce());
110
111 on_ = std::make_unique<SynthButton>("sample_on");
112 addButton(on_.get());
113 setActivator(on_.get());
115}
116
118
120 SynthGuiInterface* parent = findParentComponentOfClass<SynthGuiInterface>();
121
122 if (sample_ == nullptr && parent) {
123 sample_ = parent->getSynth()->getSample();
124 sample_viewer_->setSample(sample_);
125 sample_viewer_->repaintAudio();
126 reset();
127 }
128}
129
131 if (getWidth() == 0)
132 return;
133
136
138
139 setLabelFont(g);
140 drawLabelForComponent(g, TRANS("PAN"), pan_.get());
141 drawLabelForComponent(g, TRANS("LEVEL"), level_.get());
142
143 int widget_margin = findValue(Skin::kWidgetMargin);
144 int section_width = getWidth() * 0.19f;
145 int component_width = section_width - 2 * widget_margin;
146
147 int pitch_x = findValue(Skin::kTitleWidth);
148 int section2_x = getWidth() - 2 * section_width + widget_margin;
149 int label_height = findValue(Skin::kLabelBackgroundHeight);
150 int top_row_y = widget_margin;
151 int text_component_height = destination_selector_->getY() - top_row_y - widget_margin;
152 paintJointControl(g, pitch_x + widget_margin, top_row_y, component_width, text_component_height, "");
153
154 g.drawText("PITCH", pitch_x + widget_margin, widget_margin, component_width, label_height,
155 Justification::centred, false);
156
157 float label_rounding = findValue(Skin::kLabelBackgroundRounding);
158 g.setColour(findColour(Skin::kTextComponentBackground, true));
159
160 g.fillRoundedRectangle(destination_selector_->getBounds().toFloat(), label_rounding);
161
162 int buttons_x = section2_x + section_width;
163 g.fillRoundedRectangle(buttons_x, widget_margin, component_width, getHeight() - 2 * widget_margin, label_rounding);
164
165 g.setColour(findColour(Skin::kWidgetBackground, true));
166 g.fillRoundedRectangle(sample_viewer_->getX(), widget_margin,
167 sample_viewer_->getWidth(), getHeight() - 2 * widget_margin,
169
171 paintBorder(g);
172}
173
174void SampleSection::setActive(bool active) {
175 sample_viewer_->setActive(active);
177}
178
181
182 preset_selector_->setColour(Skin::kIconButtonOff, findColour(Skin::kUiButton, true));
183 preset_selector_->setColour(Skin::kIconButtonOffHover, findColour(Skin::kUiButtonHover, true));
184 preset_selector_->setColour(Skin::kIconButtonOffPressed, findColour(Skin::kUiButtonPressed, true));
185
186 destination_text_->setColor(findColour(Skin::kBodyText, true));
187
188 int title_width = getTitleWidth();
189 int widget_margin = findValue(Skin::kWidgetMargin);
190 int pitch_x = title_width;
191 int pitch_width = getWidth() * 0.19f;
192 int sample_x = pitch_x + pitch_width;
193 int section2_x = getWidth() - 2 * pitch_width + widget_margin;
194 int slider_x = section2_x + widget_margin - getSliderWidth() + getSliderOverlapWithSpace();
195
196 int sample_width = slider_x - sample_x + getSliderOverlapWithSpace();
197 int label_height = findValue(Skin::kLabelBackgroundHeight);
198 int top_row_y = widget_margin;
199 int level_pan_width = pitch_width;
200
201 int destination_x = pitch_x + widget_margin;
202 int destination_y = getHeight() - label_height - widget_margin;
203 destination_selector_->setBounds(destination_x, destination_y, pitch_width - 2 * widget_margin, label_height);
204 destination_text_->setBounds(destination_selector_->getBounds());
205 destination_text_->setTextSize(findValue(Skin::kLabelHeight));
206
207 prev_destination_->setBounds(destination_x, destination_y, label_height, label_height);
208 next_destination_->setBounds(destination_selector_->getRight() - label_height, destination_y,
209 label_height, label_height);
210
211 int text_component_height = destination_selector_->getY() - top_row_y - widget_margin;
212 placeJointControls(pitch_x + widget_margin, top_row_y, pitch_width - 2 * widget_margin, text_component_height,
213 transpose_.get(), tune_.get(), transpose_quantize_button_.get());
214
215 placeKnobsInArea(Rectangle<int>(section2_x, 0, level_pan_width, getHeight()), { level_.get(), pan_.get() });
216
217 sample_viewer_->setBounds(sample_x, title_width - widget_margin, sample_width, getHeight() - title_width);
218 preset_selector_->setBounds(sample_x, widget_margin, sample_width, title_width - 2 * widget_margin);
219
220 destination_text_->setBounds(destination_selector_->getBounds());
221 destination_text_->setTextSize(findValue(Skin::kLabelHeight));
222
223 int buttons_x = section2_x + level_pan_width;
224 int buttons_width = getWidth() - buttons_x - widget_margin;
225 int buttons_height = getHeight() - 2 * widget_margin;
226 int button_width = std::min(buttons_height / 2, buttons_width / 2);
227 int button_padding_x = (buttons_width - 2 * button_width) / 3;
228
229 int button_x1 = buttons_x + button_padding_x;
230 int button_x2 = buttons_x + buttons_width - button_width - button_padding_x;
231 keytrack_->setBounds(button_x1, widget_margin, button_width, button_width);
232 loop_->setBounds(button_x1, widget_margin + buttons_height / 2, button_width, button_width);
233 random_phase_->setBounds(button_x2, widget_margin, button_width, button_width);
234 bounce_->setBounds(button_x2, widget_margin + buttons_height / 2, button_width, button_width);
235}
236
239 preset_selector_->setText(sample_viewer_->getName());
240 sample_viewer_->repaintAudio();
241}
242
243void SampleSection::loadFile(const File& file) {
244 static constexpr int kMaxFileSamples = 17640000;
245 preset_selector_->setText(file.getFileNameWithoutExtension());
246 sample_->setLastBrowsedFile(file.getFullPathName().toStdString());
247
248 std::unique_ptr<AudioFormatReader> format_reader(sample_viewer_->formatManager().createReaderFor(file));
249
250 if (format_reader) {
251 int num_samples = (int)std::min<long long>(format_reader->lengthInSamples, kMaxFileSamples);
252 sample_buffer_.setSize(format_reader->numChannels, num_samples);
253 format_reader->read(&sample_buffer_, 0, num_samples, 0, true, true);
254 if (sample_buffer_.getNumChannels() > 1) {
255 sample_->loadSample(sample_buffer_.getReadPointer(0), sample_buffer_.getReadPointer(1),
256 num_samples, format_reader->sampleRate);
257 }
258 else
259 sample_->loadSample(sample_buffer_.getReadPointer(0), num_samples, format_reader->sampleRate);
260 sample_->setName(file.getFileNameWithoutExtension().toStdString());
261 }
262
263 preset_selector_->setText(sample_viewer_->getName());
264 sample_viewer_->repaintAudio();
265}
266
268 preset_selector_->setText(sample_viewer_->getName());
269 transpose_quantize_button_->setValue(static_cast<int>(controls["sample_transpose_quantize"]->value()));
271
272 current_destination_ = controls[destination_control_name_]->value();
274}
275
276void SampleSection::buttonClicked(Button* clicked_button) {
277 if (clicked_button == destination_selector_.get()) {
278 PopupItems options;
279 int num_source_destinations = vital::constants::kNumSourceDestinations;
280 for (int i = 0; i < num_source_destinations; ++i)
282
283 showPopupSelector(this, Point<int>(clicked_button->getX(), clicked_button->getBottom()),options,
284 [=](int selection) { setDestinationSelected(selection); });
285 }
286 else if (clicked_button == prev_destination_.get()) {
287 int new_destination = current_destination_ - 1 + vital::constants::kNumSourceDestinations;
289 }
290 else if (clicked_button == next_destination_.get()) {
291 int new_destination = (current_destination_ + 1) % vital::constants::kNumSourceDestinations;
292 setDestinationSelected(new_destination);
293 }
294 else
295 SynthSection::buttonClicked(clicked_button);
296}
297
299 current_destination_ = selection;
301
302 SynthGuiInterface* parent = findParentComponentOfClass<SynthGuiInterface>();
303 if (parent)
304 parent->getSynth()->valueChangedInternal(destination_control_name_, current_destination_);
305}
306
308 for (Listener* listener : listeners_)
309 listener->sampleDestinationChanged(this, current_destination_);
310
311 destination_text_->setText(strings::kDestinationNames[current_destination_]);
312}
313
314void SampleSection::toggleFilterInput(int filter_index, bool on) {
315 vital::constants::SourceDestination current_destination = (vital::constants::SourceDestination)current_destination_;
316 if (filter_index == 0)
317 setDestinationSelected(vital::constants::toggleFilter1(current_destination, on));
318 else
319 setDestinationSelected(vital::constants::toggleFilter2(current_destination, on));
320}
321
330
339
340void SampleSection::textMouseDown(const MouseEvent& e) {
341 static constexpr int kBrowserWidth = 450;
342 static constexpr int kBrowserHeight = 300;
343
344 Rectangle<int> bounds(preset_selector_->getRight(), preset_selector_->getY(),
345 kBrowserWidth * size_ratio_, kBrowserHeight * size_ratio_);
346 bounds = getLocalArea(this, bounds);
349}
350
352 int value = transpose_quantize_button_->getValue();
353 SynthGuiInterface* parent = findParentComponentOfClass<SynthGuiInterface>();
354 if (parent)
355 parent->getSynth()->valueChangedInternal("sample_transpose_quantize", value);
356}
static const std::string kSampleFolderName
Definition load_save.h:77
static File getShiftedFile(const String directory_name, const String &extensions, const std::string &additional_folders_name, const File &current_file, int shift)
Given a directory name and extensions, returns a file shifted by some offset from the current file.
Definition load_save.cpp:1921
static std::vector< File > getSampleDirectories()
Gets directories that should contain samples.
Definition load_save.cpp:1776
static const std::string kAdditionalSampleFoldersName
Definition load_save.h:80
static Path bounce()
Definition paths.h:647
static Path shuffle()
Definition paths.h:690
static Path next()
Creates a 'next' arrow icon path.
Definition paths.h:176
static Path loop()
Definition paths.h:630
static Path keyboard()
Definition paths.h:454
static Path prev()
Creates a 'previous' arrow icon path.
Definition paths.h:157
Interface for receiving events when the sample destination changes.
Definition sample_section.h:30
void nextClicked() override
Called when the "next" button is clicked to cycle through samples.
Definition sample_section.cpp:331
void setupDestination()
Configures the destination text and notifies listeners of the new destination.
Definition sample_section.cpp:307
void buttonClicked(Button *clicked_button) override
Handles button click events for this section.
Definition sample_section.cpp:276
void quantizeUpdated() override
Called when quantization is updated from the TransposeQuantizeButton.
Definition sample_section.cpp:351
void parentHierarchyChanged() override
Called when the parent hierarchy changes. Used to acquire a pointer to the synth and associated sampl...
Definition sample_section.cpp:119
void paintBackground(Graphics &g) override
Paints the background of the sample section, including labels and visual layouts.
Definition sample_section.cpp:130
void loadFile(const File &file) override
Loads a sample file and updates the sample viewer and presets.
Definition sample_section.cpp:243
void prevClicked() override
Called when the "previous" button is clicked to cycle through samples.
Definition sample_section.cpp:322
~SampleSection()
Destructor.
void reset() override
Resets the sample section, updating display and reloading the sample if needed.
Definition sample_section.cpp:237
void setActive(bool active) override
Activates or deactivates the section.
Definition sample_section.cpp:174
void textMouseDown(const MouseEvent &e) override
Called when the user clicks on the text area (e.g., preset name) to browse samples.
Definition sample_section.cpp:340
void toggleFilterInput(int filter_index, bool on)
Toggles the filter input routing on or off for a particular filter index.
Definition sample_section.cpp:314
File getCurrentFile() override
Gets the currently loaded sample file.
Definition sample_section.h:130
void resized() override
Called when the component is resized to lay out children and controls.
Definition sample_section.cpp:179
void setAllValues(vital::control_map &controls) override
Sets all control values from a given control map.
Definition sample_section.cpp:267
SampleSection(String name)
Constructs a SampleSection with a given name.
Definition sample_section.cpp:14
void setDestinationSelected(int selection)
Sets the sample output routing destination and updates the UI.
Definition sample_section.cpp:298
@ kWidgetMargin
Definition skin.h:103
@ kLabelBackgroundHeight
Definition skin.h:73
@ kLabelHeight
Definition skin.h:72
@ kTitleWidth
Definition skin.h:80
@ kTextComponentOffset
Definition skin.h:85
@ kLabelBackgroundRounding
Definition skin.h:74
@ kWidgetRoundedCorner
Definition skin.h:104
@ kUiButtonPressed
Definition skin.h:195
@ kIconButtonOff
Definition skin.h:185
@ kUiButtonHover
Definition skin.h:194
@ kIconButtonOffHover
Definition skin.h:186
@ kWidgetBackground
Definition skin.h:173
@ kBodyText
Definition skin.h:133
@ kUiButton
Definition skin.h:192
@ kIconButtonOffPressed
Definition skin.h:187
@ kTextComponentBackground
Definition skin.h:147
@ kSample
Definition skin.h:36
void valueChangedInternal(const std::string &name, vital::mono_float value)
Handles internal value changes, updating the parameter and optionally notifying the host.
Definition synth_base.cpp:54
vital::Sample * getSample()
Gets the Sample object used by the engine.
Definition synth_base.cpp:274
An interface class linking the Vital synthesizer backend (SynthBase) with a GUI.
Definition synth_gui_interface.h:56
SynthBase * getSynth()
Returns the SynthBase instance this interface is managing.
Definition synth_gui_interface.h:85
Base class for all synthesizer sections, providing UI layout, painting, and interaction logic.
Definition synth_section.h:193
virtual void buttonClicked(Button *clicked_button) override
Called when a button is clicked. Updates the synth parameter accordingly.
Definition synth_section.cpp:398
float getSliderWidth()
Definition synth_section.cpp:637
void placeKnobsInArea(Rectangle< int > area, std::vector< Component * > knobs)
Definition synth_section.cpp:601
void addSlider(SynthSlider *slider, bool show=true, bool listen=true)
Definition synth_section.cpp:445
void paintJointControl(Graphics &g, int x, int y, int width, int height, const std::string &name)
Definition synth_section.cpp:564
void addSubSection(SynthSection *section, bool show=true)
Adds a subsection (another SynthSection) as a child.
Definition synth_section.cpp:457
virtual void resized() override
Called when the component is resized. Arranges layout of child components.
Definition synth_section.cpp:35
static constexpr double kTransposeMouseSensitivity
Definition synth_section.h:204
void paintChildrenBackgrounds(Graphics &g)
Paints the backgrounds for all child sections.
Definition synth_section.cpp:274
void updatePopupBrowser(SynthSection *owner)
Updates the currently visible popup browser if any.
Definition synth_section.cpp:113
void paintKnobShadows(Graphics &g)
Paints knob shadows for all sliders.
Definition synth_section.cpp:253
virtual void setActive(bool active)
Sets the active state of this section and sub-sections.
Definition synth_section.cpp:806
void drawLabelForComponent(Graphics &g, String text, Component *component, bool text_component=false)
Draws a label for a given component.
Definition synth_section.h:548
void setLabelFont(Graphics &g)
Sets the Graphics context font and color for labels.
Definition synth_section.cpp:740
virtual void paintHeadingText(Graphics &g)
Paints the heading text for this section, either sideways or horizontally.
Definition synth_section.cpp:66
void showPopupSelector(Component *source, Point< int > position, const PopupItems &options, std::function< void(int)> callback, std::function< void()> cancel={ })
Shows a popup selector with options.
Definition synth_section.cpp:119
float size_ratio_
Definition synth_section.h:821
void addButton(OpenGlToggleButton *button, bool show=true)
Definition synth_section.cpp:428
float findValue(Skin::ValueId value_id) const
Finds a value in the skin overrides or from the parent if not found locally.
Definition synth_section.cpp:18
virtual void paintBorder(Graphics &g, Rectangle< int > bounds)
Paints the border around given bounds.
Definition synth_section.cpp:170
void setActivator(SynthButton *activator)
Definition synth_section.cpp:504
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
virtual void setAllValues(vital::control_map &controls)
Sets values for all known parameters from a control map.
Definition synth_section.cpp:827
virtual void reset()
Resets the section and all sub-sections.
Definition synth_section.cpp:30
float getSliderOverlapWithSpace()
Definition synth_section.cpp:648
void setPresetSelector(PresetSelector *preset_selector, bool half=false)
Definition synth_section.h:779
float getTitleWidth()
Definition synth_section.cpp:629
void setSkinOverride(Skin::SectionOverride skin_override)
Definition synth_section.h:303
void placeJointControls(int x, int y, int width, int height, SynthSlider *left, SynthSlider *right, Component *widget=nullptr)
Definition synth_section.cpp:572
virtual void paintContainer(Graphics &g)
Paints the container background, body, heading, etc.
Definition synth_section.cpp:146
void showPopupBrowser(SynthSection *owner, Rectangle< int > bounds, std::vector< File > directories, String extensions, std::string passthrough_name, std::string additional_folders_name)
Shows a file browser popup (e.g., for loading samples or wavetables).
Definition synth_section.cpp:105
static TextLookAndFeel * instance()
Singleton instance access.
Definition text_look_and_feel.h:106
void setLastBrowsedFile(const std::string &path)
Sets the last browsed file path (if applicable).
Definition sample_source.h:94
void loadSample(const mono_float *buffer, int size, int sample_rate)
Loads a mono sample from raw float data.
Definition sample_source.cpp:295
void setName(const std::string &name)
Sets the user-facing name of the sample.
Definition sample_source.h:89
const std::string kDestinationNames[vital::constants::kNumSourceDestinations+vital::constants::kNumEffects]
Names of possible audio routing destinations (filters, effects).
Definition synth_strings.h:387
const std::string kDestinationMenuNames[vital::constants::kNumSourceDestinations+vital::constants::kNumEffects]
Names for destinations as displayed in menus.
Definition synth_strings.h:408
SourceDestination
Represents routing destinations for oscillators and other sound sources through the signal chain.
Definition synth_constants.h:115
@ kNumSourceDestinations
Definition synth_constants.h:121
const std::string kSampleExtensionsList
A semicolon-separated list of supported sample file formats (e.g., wav and flac).
Definition synth_constants.h:94
constexpr int kNotesPerOctave
Number of semitones per octave.
Definition common.h:51
std::map< std::string, Value * > control_map
Maps parameter names to Value pointers representing synth control parameters.
Definition synth_types.h:214
Declares the SampleViewer class that displays and animates a waveform sample.
A hierarchical structure of popup menu items for a selector component.
Definition synth_section.h:29
void addItem(int sub_id, const std::string &sub_name, bool sub_selected=false)
Adds a new item as a submenu entry.
Definition synth_section.h:51
Declares classes for OpenGL-based buttons used in the Vital synth UI.
Declares the SynthSlider and related classes, providing various slider styles and functionality in th...