1 /**
2  * File name: SampleBrowser.cpp
3  * Project: Geonkick (A percussion synthesizer)
4  *
5  * Copyright (C) 2020 Iurie Nistor <http://iuriepage.wordpress.com>
6  *
7  * This file is part of Geonkick.
8  *
9  * GeonKick is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23 
24 #include "SampleBrowser.h"
25 #include "file_dialog.h"
26 #include "ViewState.h"
27 #include "BufferView.h"
28 #include "geonkick_button.h"
29 #include "geonkick_slider.h"
30 
31 #include "RkContainer.h"
32 
33 RK_DECLARE_IMAGE_RC(play_preview_sample);
34 RK_DECLARE_IMAGE_RC(play_preview_sample_hover);
35 RK_DECLARE_IMAGE_RC(play_preview_sample_pressed);
36 RK_DECLARE_IMAGE_RC(load_preview_sample);
37 RK_DECLARE_IMAGE_RC(load_preview_sample_hover);
38 RK_DECLARE_IMAGE_RC(load_preview_sample_pressed);
39 RK_DECLARE_IMAGE_RC(osc1_preview_sample);
40 RK_DECLARE_IMAGE_RC(osc1_preview_sample_hover);
41 RK_DECLARE_IMAGE_RC(osc1_preview_sample_pressed);
42 RK_DECLARE_IMAGE_RC(osc2_preview_sample);
43 RK_DECLARE_IMAGE_RC(osc2_preview_sample_hover);
44 RK_DECLARE_IMAGE_RC(osc2_preview_sample_pressed);
45 
SampleBrowser(GeonkickWidget * parent,GeonkickApi * api)46 SampleBrowser::SampleBrowser(GeonkickWidget *parent, GeonkickApi* api)
47         : GeonkickWidget(parent)
48         , geonkickApi{api}
49         , fileBrowser{new FileDialog(this, FileDialog::Type::Browse, std::string())}
50         , samplePreviewWidget{new BufferView(this)}
51         , playButton{nullptr}
52         , loadButton{nullptr}
53         , osc1Button{nullptr}
54         , osc2Button{nullptr}
55         , previewLimiter{nullptr}
56 
57 {
58         setFixedSize(parent->size());
59         fileBrowser->setFilters({".wav", ".WAV", ".flac", ".FLAC", ".ogg", ".OGG"});
60         fileBrowser->setHomeDirectory(geonkickApi->getSettings("GEONKICK_CONFIG/HOME_PATH"));
61         fileBrowser->setCurrentDirectoy(viewState()->samplesBrowserPath());
62         setPreviewSample(viewState()->samplesBrowserPreviewFile());
63         RK_ACT_BIND(fileBrowser,
64                     directoryChanged,
65                     RK_ACT_ARGS(const std::string &path),
66                     viewState(),
67                     setSamplesBrowserPath(path));
68         RK_ACT_BIND(fileBrowser,
69                     currentFileChanged,
70                     RK_ACT_ARGS(const std::string &file),
71                     this,
72                     setPreviewSample(file));
73         RK_ACT_BIND(fileBrowser,
74                     currentFileChanged,
75                     RK_ACT_ARGS(const std::string &file),
76                     viewState(),
77                     setSamplesBrowserPreviewFile(file));
78         RK_ACT_BINDL(fileBrowser,
79                     selectedFile,
80                     RK_ACT_ARGS(const std::string &file),
__anon283eba310102(const std::string &file) 81                      [&](const std::string &file) {
82                              viewState()->setSamplesBrowserPreviewFile(file);
83                              loadSample();
84                     });
85 
86         samplePreviewWidget->setSize(250, 260);
87         samplePreviewWidget->show();
88         RK_ACT_BIND(samplePreviewWidget, graphPressed, RK_ACT_ARGS(), geonkickApi, playSamplePreview());
89 
90         previewLimiter = new GeonkickSlider(this, GeonkickSlider::Orientation::Vertical);
91         previewLimiter->onSetValue(Geonkick::toDecibel(geonkickApi->samplePreviewLimiter()) + 80);
92         RK_ACT_BIND(previewLimiter,
93                     valueUpdated, RK_ACT_ARGS(int val),
94                     geonkickApi,
95                     setSamplePreviewLimiter(Geonkick::fromDecibel(val - 80)));
96 
97         previewLimiter->setSize(16, samplePreviewWidget->height());
98 
99         auto mainLayout = new RkContainer(this);
100         mainLayout->setSize(parent->size());
101         mainLayout->addWidget(fileBrowser);
102 
103         auto previewWidgetContainer = new RkContainer(this, Rk::Orientation::Horizontal);
104         previewWidgetContainer->setSize({samplePreviewWidget->width() + 10 + previewLimiter->width(),
105                                          samplePreviewWidget->height()});
106         previewWidgetContainer->addWidget(samplePreviewWidget);
107         previewWidgetContainer->addSpace(8);
108         previewWidgetContainer->addWidget(previewLimiter);
109 
110         auto previewContainer = new RkContainer(this, Rk::Orientation::Vertical);
111         previewContainer->setSize({previewWidgetContainer->width() + 10, mainLayout->height()});
112         previewContainer->addSpace(35);
113         previewContainer->addContainer(previewWidgetContainer);
114 
115         auto previewMenuContainer = new RkContainer(this);
116         previewMenuContainer->setSize({previewContainer->width(), 25});
117         createPreviewMenu(previewMenuContainer);
118         previewContainer->addSpace(5);
119         previewContainer->addContainer(previewMenuContainer);
120         mainLayout->addSpace(5);
121         mainLayout->addContainer(previewContainer);
122         setOscillator(viewState()->samplesBrowserOscillator());
123         show();
124 }
125 
createPreviewMenu(RkContainer * container)126 void SampleBrowser::createPreviewMenu(RkContainer* container)
127 {
128         playButton = new GeonkickButton(this);
129         playButton->setType(RkButton::ButtonType::ButtonPush);
130         playButton->setSize(33, 18);
131         playButton->setImage(RkImage(playButton->size(), RK_IMAGE_RC(play_preview_sample)),
132                              RkButton::State::Unpressed);
133         playButton->setImage(RkImage(playButton->size(), RK_IMAGE_RC(play_preview_sample_hover)),
134                              RkButton::State::UnpressedHover);
135         playButton->setImage(RkImage(playButton->size(), RK_IMAGE_RC(play_preview_sample_pressed)),
136                              RkButton::State::Pressed);
137         RK_ACT_BIND(playButton, pressed, RK_ACT_ARGS(), geonkickApi, playSamplePreview());
138         container->addSpace(5);
139         container->addWidget(playButton);
140         container->addSpace(3);
141 
142         loadButton = new GeonkickButton(this);
143         loadButton->setType(RkButton::ButtonType::ButtonPush);
144         loadButton->setSize(33, 18);
145         loadButton->setImage(RkImage(loadButton->size(), RK_IMAGE_RC(load_preview_sample)),
146                              RkButton::State::Unpressed);
147         loadButton->setImage(RkImage(loadButton->size(), RK_IMAGE_RC(load_preview_sample_hover)),
148                              RkButton::State::UnpressedHover);
149         loadButton->setImage(RkImage(loadButton->size(), RK_IMAGE_RC(load_preview_sample_pressed)),
150                              RkButton::State::Pressed);
151         RK_ACT_BIND(loadButton, pressed, RK_ACT_ARGS(), this, loadSample());
152         container->addWidget(loadButton);
153         container->addSpace(15);
154 
155         osc1Button = new GeonkickButton(this);
156         osc1Button->setSize(33, 18);
157         osc1Button->setImage(RkImage(osc1Button->size(), RK_IMAGE_RC(osc1_preview_sample)),
158                              RkButton::State::Unpressed);
159         osc1Button->setImage(RkImage(osc1Button->size(), RK_IMAGE_RC(osc1_preview_sample_hover)),
160                              RkButton::State::UnpressedHover);
161         osc1Button->setImage(RkImage(osc1Button->size(), RK_IMAGE_RC(osc1_preview_sample_pressed)),
162                              RkButton::State::Pressed);
163         RK_ACT_BIND(osc1Button, pressed,
164                     RK_ACT_ARGS(), this,
165                     setOscillator(GeonkickApi::OscillatorType::Oscillator1));
166         container->addWidget(osc1Button);
167         container->addSpace(3);
168 
169         osc2Button = new GeonkickButton(this);
170         osc2Button->setSize(33, 18);
171         osc2Button->setImage(RkImage(osc2Button->size(), RK_IMAGE_RC(osc2_preview_sample)),
172                              RkButton::State::Unpressed);
173         osc2Button->setImage(RkImage(osc2Button->size(), RK_IMAGE_RC(osc2_preview_sample_hover)),
174                              RkButton::State::UnpressedHover);
175         osc2Button->setImage(RkImage(osc2Button->size(), RK_IMAGE_RC(osc2_preview_sample_pressed)),
176                              RkButton::State::Pressed);
177         RK_ACT_BIND(osc2Button, pressed,
178                     RK_ACT_ARGS(), this,
179                     setOscillator(GeonkickApi::OscillatorType::Oscillator2));
180         container->addWidget(osc2Button);
181 }
182 
setOscillator(GeonkickApi::OscillatorType osc)183 void SampleBrowser::setOscillator(GeonkickApi::OscillatorType osc)
184 {
185         osc1Button->setPressed(osc == GeonkickApi::OscillatorType::Oscillator1);
186         osc2Button->setPressed(osc == GeonkickApi::OscillatorType::Oscillator2);
187 }
188 
loadSample()189 void SampleBrowser::loadSample()
190 {
191         if (osc1Button->isPressed()) {
192                 geonkickApi->setOscillatorSample(samplePreviewWidget->getData(),
193                                                  static_cast<int>(GeonkickApi::OscillatorType::Oscillator1));
194                 geonkickApi->setOscillatorFunction(static_cast<int>(GeonkickApi::OscillatorType::Oscillator1),
195                                                    GeonkickApi::FunctionType::Sample);
196         } else if (osc2Button->isPressed()) {
197                 geonkickApi->setOscillatorSample(samplePreviewWidget->getData(),
198                                                  static_cast<int>(GeonkickApi::OscillatorType::Oscillator2));
199                 geonkickApi->setOscillatorFunction(static_cast<int>(GeonkickApi::OscillatorType::Oscillator2),
200                                                    GeonkickApi::FunctionType::Sample);
201         }
202 }
203 
setPreviewSample(const std::string & file)204 void SampleBrowser::setPreviewSample(const std::string &file)
205 {
206         try {
207                 if (std::filesystem::exists(file) && !std::filesystem::is_directory(file)) {
208                         std::vector<float> data = geonkickApi->setPreviewSample(file);
209                         if (!data.empty()) {
210                                 samplePreviewWidget->setData(data);
211                                 geonkickApi->playSamplePreview();
212                         }
213                 }
214         }  catch (...) {
215         }
216 }
217