1 //=============================================================================
2 // Zerberus
3 // Zample player
4 //
5 // Copyright (C) 2013 Werner Schweer
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENCE.GPL
11 //=============================================================================
12
13 #include "zerberusgui.h"
14
15 #include "mscore/preferences.h"
16 #include "mscore/extension.h"
17 #include "mscore/icons.h"
18
19 //---------------------------------------------------------
20 // SfzListDialog
21 //---------------------------------------------------------
22
SfzListDialog(QWidget * parent)23 SfzListDialog::SfzListDialog(QWidget* parent)
24 : QDialog(parent)
25 {
26 setWindowTitle(tr("SFZ Files"));
27 setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
28 list = new QListWidget;
29 list->setSelectionMode(QAbstractItemView::ExtendedSelection);
30
31 okButton = new QPushButton;
32 cancelButton = new QPushButton;
33 okButton->setText(tr("Load"));
34 cancelButton->setText(tr("Cancel"));
35
36 QVBoxLayout* layout = new QVBoxLayout;
37 buttonBox = new QDialogButtonBox;
38 layout->addWidget(list);
39 layout->addWidget(buttonBox);
40 buttonBox->addButton(okButton, QDialogButtonBox::AcceptRole);
41 buttonBox->addButton(cancelButton, QDialogButtonBox::RejectRole);
42 setLayout(layout);
43 connect(okButton, SIGNAL(clicked()), SLOT(okClicked()));
44 connect(cancelButton, SIGNAL(clicked()), SLOT(cancelClicked()));
45 }
46
47 //---------------------------------------------------------
48 // add
49 //---------------------------------------------------------
50
add(const QString & name,const QString & path)51 void SfzListDialog::add(const QString& name, const QString& path)
52 {
53 QListWidgetItem* item = new QListWidgetItem;
54 item->setText(name);
55 item->setData(Qt::UserRole, path);
56 list->addItem(item);
57 }
58
59 //---------------------------------------------------------
60 // okClicked
61 //---------------------------------------------------------
62
okClicked()63 void SfzListDialog::okClicked()
64 {
65 for (auto item : list->selectedItems()) {
66 _namePaths.push_back({item->text(), item->data(Qt::UserRole).toString()});
67 }
68 accept();
69 }
70
71 //---------------------------------------------------------
72 // cancelClicked
73 //---------------------------------------------------------
74
cancelClicked()75 void SfzListDialog::cancelClicked()
76 {
77 reject();
78 }
79
80 //---------------------------------------------------------
81 // gui
82 //---------------------------------------------------------
83
gui()84 Ms::SynthesizerGui* Zerberus::gui()
85 {
86 if (_gui == 0)
87 _gui = new ZerberusGui(this);
88 return _gui;
89 }
90
91 //---------------------------------------------------------
92 // Zerberusgui
93 //---------------------------------------------------------
94
ZerberusGui(Ms::Synthesizer * s)95 ZerberusGui::ZerberusGui(Ms::Synthesizer* s)
96 : SynthesizerGui(s)
97 {
98 setupUi(this);
99 connect(soundFontTop, SIGNAL(clicked()), SLOT(soundFontTopClicked()));
100 connect(soundFontUp, SIGNAL(clicked()), SLOT(soundFontUpClicked()));
101 connect(soundFontDown, SIGNAL(clicked()), SLOT(soundFontDownClicked()));
102 connect(soundFontBottom, SIGNAL(clicked()), SLOT(soundFontBottomClicked()));
103 connect(soundFontAdd, SIGNAL(clicked()), SLOT(soundFontAddClicked()));
104 connect(soundFontDelete, SIGNAL(clicked()), SLOT(soundFontDeleteClicked()));
105 connect(&_futureWatcher, SIGNAL(finished()), this, SLOT(onSoundFontLoaded()));
106 _progressDialog = new QProgressDialog(tr("Loading…"), tr("Cancel"), 0, 100, 0, Qt::FramelessWindowHint);
107 _progressDialog->reset(); // required for Qt 5.5, see QTBUG-47042
108 connect(_progressDialog, SIGNAL(canceled()), this, SLOT(cancelLoadClicked()));
109 _progressTimer = new QTimer(this);
110 connect(_progressTimer, SIGNAL(timeout()), this, SLOT(updateProgress()));
111 connect(files, SIGNAL(itemSelectionChanged()), this, SLOT(updateButtons()));
112
113 soundFontTop->setIcon(*Ms::icons[int(Ms::Icons::arrowsMoveToTop_ICON)]);
114 soundFontUp->setIcon(*Ms::icons[int(Ms::Icons::arrowUp_ICON)]);
115 soundFontDown->setIcon(*Ms::icons[int(Ms::Icons::arrowDown_ICON)]);
116 soundFontBottom->setIcon(*Ms::icons[int(Ms::Icons::arrowsMoveToBottom_ICON)]);
117
118 updateButtons();
119 }
120
121 //---------------------------------------------------------
122 // moveSoundfontInTheList
123 //---------------------------------------------------------
124
moveSoundfontInTheList(int currentIdx,int targetIdx)125 void ZerberusGui::moveSoundfontInTheList(int currentIdx, int targetIdx)
126 {
127 QStringList sfonts = zerberus()->soundFonts();
128 sfonts.move(currentIdx, targetIdx);
129 zerberus()->removeSoundFonts(zerberus()->soundFonts());
130
131 loadSoundFontsAsync(sfonts);
132 files->setCurrentRow(targetIdx);
133 emit sfChanged();
134 }
135
soundFontTopClicked()136 void ZerberusGui::soundFontTopClicked()
137 {
138 int row = files->currentRow();
139 if (row <= 0)
140 return;
141
142 moveSoundfontInTheList(row, 0);
143 }
144
soundFontBottomClicked()145 void ZerberusGui::soundFontBottomClicked()
146 {
147 int rows = files->count();
148 int row = files->currentRow();
149 if (row + 1 >= rows)
150 return;
151
152 moveSoundfontInTheList(row, rows - 1);
153 }
154
155 //---------------------------------------------------------
156 // soundFontUpClicked
157 //---------------------------------------------------------
158
soundFontUpClicked()159 void ZerberusGui::soundFontUpClicked()
160 {
161 int row = files->currentRow();
162 if (row <= 0)
163 return;
164
165 moveSoundfontInTheList(row, row - 1);
166 }
167
168 //---------------------------------------------------------
169 // soundFontDownClicked
170 //---------------------------------------------------------
171
soundFontDownClicked()172 void ZerberusGui::soundFontDownClicked()
173 {
174 int rows = files->count();
175 int row = files->currentRow();
176 if (row + 1 >= rows)
177 return;
178
179 moveSoundfontInTheList(row, row + 1);
180 }
181
182 //---------------------------------------------------------
183 // loadSoundFontsAsync
184 //---------------------------------------------------------
185
loadSoundFontsAsync(QStringList sfonts)186 void ZerberusGui::loadSoundFontsAsync(QStringList sfonts)
187 {
188 QFuture<bool> future = QtConcurrent::run(zerberus(), &Zerberus::loadSoundFonts, sfonts);
189 _futureWatcher.setFuture(future);
190 _progressTimer->start(1000);
191 _progressDialog->exec();
192
193 synthesizerChanged();
194 }
195
196 //---------------------------------------------------------
197 // collectFiles
198 //---------------------------------------------------------
199
collectFiles(QFileInfoList * l,const QString & path)200 static void collectFiles(QFileInfoList* l, const QString& path)
201 {
202 //printf("collect files <%s>\n", qPrintable(path));
203
204 QDir dir(path);
205 foreach (const QFileInfo& s, dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot)) {
206 if (path == s.absoluteFilePath())
207 return;
208
209 if (s.isDir() && !s.isHidden())
210 collectFiles(l, s.absoluteFilePath());
211 else {
212 if (s.suffix().toLower() == "sfz")
213 l->append(s);
214 }
215 }
216 }
217
218 //---------------------------------------------------------
219 // sfzFiles
220 //---------------------------------------------------------
221
sfzFiles()222 QFileInfoList Zerberus::sfzFiles()
223 {
224 QFileInfoList l;
225
226 QStringList pl = Ms::preferences.getString(PREF_APP_PATHS_MYSOUNDFONTS).split(";");
227 pl.prepend(QFileInfo(QString("%1%2").arg(Ms::mscoreGlobalShare).arg("sound")).absoluteFilePath());
228
229 // append extensions directory
230 QStringList extensionsDir = Ms::Extension::getDirectoriesByType(Ms::Extension::sfzsDir);
231 pl.append(extensionsDir);
232
233 foreach (const QString& s, pl) {
234 QString ss(s);
235 if (!s.isEmpty() && s[0] == '~')
236 ss = QDir::homePath() + s.mid(1);
237 collectFiles(&l, ss);
238 }
239 return l;
240 }
241
242 //---------------------------------------------------------
243 // loadSfz
244 //---------------------------------------------------------
245
loadSfz()246 void ZerberusGui::loadSfz() {
247
248 if (_sfzToLoad.empty())
249 return;
250
251 struct SfzNamePath item = _sfzToLoad.front();
252 QString sfName = item.name;
253 QString sfPath = item.path;
254 _sfzToLoad.pop_front();
255
256 QStringList sl;
257 for (int i = 0; i < files->count(); ++i) {
258 QListWidgetItem* item1 = files->item(i);
259 sl.append(item1->text());
260 }
261
262 if (sl.contains(sfName)) {
263 QMessageBox::warning(this,
264 tr("MuseScore"),
265 tr("SoundFont %1 already loaded").arg(sfPath));
266 }
267 else {
268 _loadedSfName = sfName;
269 _loadedSfPath = sfPath;
270 QFuture<bool> future = QtConcurrent::run(zerberus(), &Zerberus::addSoundFont, sfName);
271 _futureWatcher.setFuture(future);
272 _progressTimer->start(1000);
273 _progressDialog->exec();
274 }
275 }
276
277 //---------------------------------------------------------
278 // addClicked
279 //---------------------------------------------------------
280
soundFontAddClicked()281 void ZerberusGui::soundFontAddClicked()
282 {
283 zerberus()->setLoadWasCanceled(false);
284
285 QFileInfoList l = Zerberus::sfzFiles();
286
287 SfzListDialog ld(this);
288 for (const QFileInfo& fi : l)
289 ld.add(fi.fileName(), fi.absoluteFilePath());
290 if (!ld.exec())
291 return;
292
293 for (auto item : ld.getNamePaths()) {
294 _sfzToLoad.push_back(item);
295 }
296 loadSfz();
297 }
298
299 //---------------------------------------------------------
300 // cancelLoad
301 //---------------------------------------------------------
302
cancelLoadClicked()303 void ZerberusGui::cancelLoadClicked()
304 {
305 zerberus()->setLoadWasCanceled(true);
306 }
307
308 //---------------------------------------------------------
309 // updateProgress
310 //---------------------------------------------------------
311
updateProgress()312 void ZerberusGui::updateProgress()
313 {
314 _progressDialog->setValue(zerberus()->loadProgress());
315 }
316
317 //---------------------------------------------------------
318 // updateButtons
319 //---------------------------------------------------------
320
updateButtons()321 void ZerberusGui::updateButtons()
322 {
323 int rows = zerberus()->soundFonts().count();
324 int row = files->currentRow();
325 soundFontTop->setEnabled(row > 0);
326 soundFontUp->setEnabled(row > 0);
327 soundFontDown->setEnabled((row != -1) && (row < (rows - 1)));
328 soundFontBottom->setEnabled((row != -1) && row < (rows - 1));
329 soundFontDelete->setEnabled(row != -1);
330 }
331
332 //---------------------------------------------------------
333 // onSoundFontLoaded
334 //---------------------------------------------------------
335
onSoundFontLoaded()336 void ZerberusGui::onSoundFontLoaded()
337 {
338 bool loaded = _futureWatcher.result();
339 bool wasNotCanceled = !_progressDialog->wasCanceled();
340 _progressTimer->stop();
341 _progressDialog->reset();
342 if (loaded) {
343 QListWidgetItem* item = new QListWidgetItem;
344 item->setText(_loadedSfName);
345 item->setData(Qt::UserRole, _loadedSfPath);
346 //files->insertItem(0, item);
347 files->addItem(item);
348 emit valueChanged();
349 emit sfChanged();
350 }
351 else if (wasNotCanceled) {
352 QMessageBox::warning(this,
353 tr("MuseScore"),
354 tr("Cannot load SoundFont %1").arg(_loadedSfPath));
355 }
356 loadSfz();
357 }
358
359 //---------------------------------------------------------
360 // removeClicked
361 //---------------------------------------------------------
362
soundFontDeleteClicked()363 void ZerberusGui::soundFontDeleteClicked()
364 {
365 int row = files->currentRow();
366 if (row >= 0) {
367 QString path(files->item(row)->data(Qt::UserRole).toString());
368 if (!zerberus()->removeSoundFont(path))
369 qDebug("ZerberusGui::removeClicked: cannot remove sf %s", qPrintable(files->item(row)->text()));
370 delete files->takeItem(row);
371 emit valueChanged();
372 emit sfChanged();
373 updateButtons();
374 }
375 }
376
377 //---------------------------------------------------------
378 // synthesizerChanged
379 //---------------------------------------------------------
380
synthesizerChanged()381 void ZerberusGui::synthesizerChanged()
382 {
383 files->clear();
384 QStringList sfonts = zerberus()->soundFonts();
385 for (QString path : sfonts) {
386 QListWidgetItem* item = new QListWidgetItem;
387 item->setText(QFileInfo(path).fileName());
388 item->setData(Qt::UserRole, path);
389 files->addItem(item);
390 }
391 }
392