33dff96a20
This commit contains changes required for MuseScore to compile under MSVC with no warnings. MuseScore is being compiled with the /W4 setting (warning level 4), which is similar to -wall -wextra on clang. This generates lots of warnings on MSVC, mainly for non-standard constructs and for constructs which might be bugs or might lead to bugs. Most warnings are in the following categories: - Name hiding: a variable hides a variable with the same name on a larger scope (or a field, or a function parameter). This can easily lead to bugs, and it is a best practice to avoid hiding variable names (see recommendation ES.12 in the C++ Core Guidelines by Stroustrop & Sutter (http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-reuse : ES.12: Do not reuse names in nested scopes) - Narrowing conversion: a numeric conversion results in loss of significant digits (for example, double -> float). The general recommendation is to use a cast to indicate this is designed behaviour. - Unreachable code: in several instances, there is unreachable code. The unreachable code is commented out. - (Potentially) uninitialized local variable. Just initialized the vars. - foreach(,) -> for(:): this does not generate a warning per-se (only a few of these generate warnings due to name hiding), but changed in keeping with "MuseScore Coding Rules" (https://musescore.org/en/handbook/musescore-coding-rules#Loops), which tells explicitly "Use C++11's "for" instead of Qt's "foreach":" ... "If you happen to be fixing some code and see a "foreach", please change that loop into a "for"." Most changes are in the categories indicated above. The next listing shows detailed changes for files which are *not* of the aforementioned types. - all.h: Disable warning C4127 (conditional expression is constant - generated in Qt header file qvector.h) - awl/aslider.h: unreachable code. - awl/knob.cpp: name hiding - awl/mslider.cpp: name hiding - awl/slider.cpp: name hiding - bww2mxml/parser.cpp: name hiding - effects/compressor/compressor.cpp: narrowing conversion - effects/zita1/zitagui.cpp: name hiding - fluid/fluid.cpp: foreach replacement. Name hiding. - fluid/mod.cpp: name hiding. - fluid/sfont.cpp: foreach replacement. Name hiding. Initialize vars. - fluid/voice.cpp: Name hiding. - libmscore/accidental.cpp: Name hiding. - libmscore/ambitus.cpp: Initialize vars. - libmscore/barline.cpp: Name hiding. Unreachable code. - libmscore/beam.cpp: Name hiding. - libmscore/chordrest.cpp: Unreachable code. - libmscore/scorefile.cpp: Name hiding. - manual/genManual.cpp: Name hiding. foreach replacement. - midi/midifile.cpp: Name hiding. Unreachable code. - omr/importpdf.cpp: Name hiding. foreach replacement. - omr/omr.cpp: Name hiding. foreach replacement. - omr/omrpage.cpp: Name hiding. foreach replacement. - omr/omrview.cpp: Name hiding. foreach replacement. - synthesizer/event.cpp: Unreachable code. - zerberus\channel.cpp: Narrowing conversion. - zerberus\instrument.cpp: Name hiding. - zerberus\sfz.cpp: Name hiding. - zerberus\voice.h: Suppress warning C4201: "nonstandard extension used: nameless struct/union" - zerberus\zerberus.cpp: Name hiding. Unreferenced parameter. - zerberus\zerberusgui.cpp: Name hiding.
349 lines
11 KiB
C++
349 lines
11 KiB
C++
//=============================================================================
|
|
// Zerberus
|
|
// Zample player
|
|
//
|
|
// Copyright (C) 2013 Werner Schweer
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2
|
|
// as published by the Free Software Foundation and appearing in
|
|
// the file LICENCE.GPL
|
|
//=============================================================================
|
|
|
|
#include "zerberusgui.h"
|
|
|
|
#include "mscore/preferences.h"
|
|
#include "mscore/extension.h"
|
|
|
|
//---------------------------------------------------------
|
|
// SfzListDialog
|
|
//---------------------------------------------------------
|
|
|
|
SfzListDialog::SfzListDialog(QWidget* parent)
|
|
: QDialog(parent)
|
|
{
|
|
setWindowTitle(tr("SFZ Files"));
|
|
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
list = new QListWidget;
|
|
list->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
|
|
okButton = new QPushButton;
|
|
cancelButton = new QPushButton;
|
|
okButton->setText(tr("Load"));
|
|
cancelButton->setText(tr("Cancel"));
|
|
|
|
QVBoxLayout* layout = new QVBoxLayout;
|
|
buttonBox = new QDialogButtonBox;
|
|
layout->addWidget(list);
|
|
layout->addWidget(buttonBox);
|
|
buttonBox->addButton(okButton, QDialogButtonBox::AcceptRole);
|
|
buttonBox->addButton(cancelButton, QDialogButtonBox::RejectRole);
|
|
setLayout(layout);
|
|
connect(okButton, SIGNAL(clicked()), SLOT(okClicked()));
|
|
connect(cancelButton, SIGNAL(clicked()), SLOT(cancelClicked()));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// add
|
|
//---------------------------------------------------------
|
|
|
|
void SfzListDialog::add(const QString& name, const QString& path)
|
|
{
|
|
QListWidgetItem* item = new QListWidgetItem;
|
|
item->setText(name);
|
|
item->setData(Qt::UserRole, path);
|
|
list->addItem(item);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// okClicked
|
|
//---------------------------------------------------------
|
|
|
|
void SfzListDialog::okClicked()
|
|
{
|
|
for (auto item : list->selectedItems()) {
|
|
_namePaths.push_back({item->text(), item->data(Qt::UserRole).toString()});
|
|
}
|
|
accept();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// cancelClicked
|
|
//---------------------------------------------------------
|
|
|
|
void SfzListDialog::cancelClicked()
|
|
{
|
|
reject();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// gui
|
|
//---------------------------------------------------------
|
|
|
|
Ms::SynthesizerGui* Zerberus::gui()
|
|
{
|
|
if (_gui == 0)
|
|
_gui = new ZerberusGui(this);
|
|
return _gui;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// Zerberusgui
|
|
//---------------------------------------------------------
|
|
|
|
ZerberusGui::ZerberusGui(Ms::Synthesizer* s)
|
|
: SynthesizerGui(s)
|
|
{
|
|
setupUi(this);
|
|
connect(soundFontUp, SIGNAL(clicked()), SLOT(soundFontUpClicked()));
|
|
connect(soundFontDown, SIGNAL(clicked()), SLOT(soundFontDownClicked()));
|
|
connect(soundFontAdd, SIGNAL(clicked()), SLOT(soundFontAddClicked()));
|
|
connect(soundFontDelete, SIGNAL(clicked()), SLOT(soundFontDeleteClicked()));
|
|
connect(&_futureWatcher, SIGNAL(finished()), this, SLOT(onSoundFontLoaded()));
|
|
_progressDialog = new QProgressDialog(tr("Loading..."), tr("Cancel"), 0, 100, 0, Qt::FramelessWindowHint);
|
|
_progressDialog->reset(); // required for Qt 5.5, see QTBUG-47042
|
|
connect(_progressDialog, SIGNAL(canceled()), this, SLOT(cancelLoadClicked()));
|
|
_progressTimer = new QTimer(this);
|
|
connect(_progressTimer, SIGNAL(timeout()), this, SLOT(updateProgress()));
|
|
connect(files, SIGNAL(itemSelectionChanged()), this, SLOT(updateButtons()));
|
|
updateButtons();
|
|
}
|
|
|
|
void ZerberusGui::soundFontUpClicked()
|
|
{
|
|
int row = files->currentRow();
|
|
if (row <= 0)
|
|
return;
|
|
|
|
QStringList sfonts = zerberus()->soundFonts();
|
|
sfonts.swap(row, row-1);
|
|
zerberus()->removeSoundFonts(zerberus()->soundFonts());
|
|
|
|
loadSoundFontsAsync(sfonts);
|
|
files->setCurrentRow(row-1);
|
|
emit sfChanged();
|
|
}
|
|
|
|
void ZerberusGui::soundFontDownClicked()
|
|
{
|
|
int rows = files->count();
|
|
int row = files->currentRow();
|
|
if (row + 1 >= rows)
|
|
return;
|
|
|
|
QStringList sfonts = zerberus()->soundFonts();
|
|
sfonts.swap(row, row + 1);
|
|
zerberus()->removeSoundFonts(zerberus()->soundFonts());
|
|
|
|
loadSoundFontsAsync(sfonts);
|
|
files->setCurrentRow(row + 1);
|
|
emit sfChanged();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// loadSounfFontsAsync
|
|
//---------------------------------------------------------
|
|
|
|
void ZerberusGui::loadSoundFontsAsync(QStringList sfonts)
|
|
{
|
|
QFuture<bool> future = QtConcurrent::run(zerberus(), &Zerberus::loadSoundFonts, sfonts);
|
|
_futureWatcher.setFuture(future);
|
|
_progressTimer->start(1000);
|
|
_progressDialog->exec();
|
|
|
|
synthesizerChanged();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// collectFiles
|
|
//---------------------------------------------------------
|
|
|
|
static void collectFiles(QFileInfoList* l, const QString& path)
|
|
{
|
|
// printf("collect files <%s>\n", qPrintable(path));
|
|
|
|
QDir dir(path);
|
|
foreach (const QFileInfo& s, dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot)) {
|
|
if (path == s.absoluteFilePath())
|
|
return;
|
|
|
|
if (s.isDir() && !s.isHidden())
|
|
collectFiles(l, s.absoluteFilePath());
|
|
else {
|
|
if (s.suffix().toLower() == "sfz")
|
|
l->append(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// sfzFiles
|
|
//---------------------------------------------------------
|
|
|
|
QFileInfoList Zerberus::sfzFiles()
|
|
{
|
|
QFileInfoList l;
|
|
|
|
QStringList pl = Ms::preferences.getString(PREF_APP_PATHS_MYSOUNDFONTS).split(";");
|
|
pl.prepend(QFileInfo(QString("%1%2").arg(Ms::mscoreGlobalShare).arg("sound")).absoluteFilePath());
|
|
|
|
// append extensions directory
|
|
QStringList extensionsDir = Ms::Extension::getDirectoriesByType(Ms::Extension::sfzsDir);
|
|
pl.append(extensionsDir);
|
|
|
|
foreach (const QString& s, pl) {
|
|
QString ss(s);
|
|
if (!s.isEmpty() && s[0] == '~')
|
|
ss = QDir::homePath() + s.mid(1);
|
|
collectFiles(&l, ss);
|
|
}
|
|
return l;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// loadSfz
|
|
//---------------------------------------------------------
|
|
|
|
void ZerberusGui::loadSfz() {
|
|
|
|
if (_sfzToLoad.empty())
|
|
return;
|
|
|
|
struct SfNamePath item = _sfzToLoad.front();
|
|
QString sfName = item.name;
|
|
QString sfPath = item.path;
|
|
_sfzToLoad.pop_front();
|
|
|
|
QStringList sl;
|
|
for (int i = 0; i < files->count(); ++i) {
|
|
QListWidgetItem* item1 = files->item(i);
|
|
sl.append(item1->text());
|
|
}
|
|
|
|
if (sl.contains(sfName)) {
|
|
QMessageBox::warning(this,
|
|
tr("MuseScore"),
|
|
tr("SoundFont %1 already loaded").arg(sfPath));
|
|
}
|
|
else {
|
|
_loadedSfName = sfName;
|
|
_loadedSfPath = sfPath;
|
|
QFuture<bool> future = QtConcurrent::run(zerberus(), &Zerberus::addSoundFont, sfName);
|
|
_futureWatcher.setFuture(future);
|
|
_progressTimer->start(1000);
|
|
_progressDialog->exec();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// addClicked
|
|
//---------------------------------------------------------
|
|
|
|
void ZerberusGui::soundFontAddClicked()
|
|
{
|
|
zerberus()->setLoadWasCanceled(false);
|
|
|
|
QFileInfoList l = Zerberus::sfzFiles();
|
|
|
|
SfzListDialog ld(this);
|
|
foreach (const QFileInfo& fi, l)
|
|
ld.add(fi.fileName(), fi.absoluteFilePath());
|
|
if (!ld.exec())
|
|
return;
|
|
|
|
for (auto item : ld.getNamePaths()) {
|
|
_sfzToLoad.push_back(item);
|
|
}
|
|
loadSfz();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// cancelLoad
|
|
//---------------------------------------------------------
|
|
|
|
void ZerberusGui::cancelLoadClicked()
|
|
{
|
|
zerberus()->setLoadWasCanceled(true);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateProgress
|
|
//---------------------------------------------------------
|
|
|
|
void ZerberusGui::updateProgress()
|
|
{
|
|
_progressDialog->setValue(zerberus()->loadProgress());
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateButtons
|
|
//---------------------------------------------------------
|
|
|
|
void ZerberusGui::updateButtons()
|
|
{
|
|
int row = files->currentRow();
|
|
soundFontDelete->setEnabled(row != -1);
|
|
soundFontUp->setEnabled(row != -1);
|
|
soundFontDown->setEnabled(row != -1);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// onSoundFontLoaded
|
|
//---------------------------------------------------------
|
|
|
|
void ZerberusGui::onSoundFontLoaded()
|
|
{
|
|
bool loaded = _futureWatcher.result();
|
|
bool wasNotCanceled = !_progressDialog->wasCanceled();
|
|
_progressTimer->stop();
|
|
_progressDialog->reset();
|
|
if (loaded) {
|
|
QListWidgetItem* item = new QListWidgetItem;
|
|
item->setText(_loadedSfName);
|
|
item->setData(Qt::UserRole, _loadedSfPath);
|
|
//files->insertItem(0, item);
|
|
files->addItem(item);
|
|
emit valueChanged();
|
|
emit sfChanged();
|
|
}
|
|
else if (wasNotCanceled) {
|
|
QMessageBox::warning(this,
|
|
tr("MuseScore"),
|
|
tr("Cannot load SoundFont %1").arg(_loadedSfPath));
|
|
}
|
|
loadSfz();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// removeClicked
|
|
//---------------------------------------------------------
|
|
|
|
void ZerberusGui::soundFontDeleteClicked()
|
|
{
|
|
int row = files->currentRow();
|
|
if (row >= 0) {
|
|
QString path(files->item(row)->data(Qt::UserRole).toString());
|
|
if (!zerberus()->removeSoundFont(path))
|
|
qDebug("ZerberusGui::removeClicked: cannot remove sf %s", qPrintable(files->item(row)->text()));
|
|
delete files->takeItem(row);
|
|
emit valueChanged();
|
|
emit sfChanged();
|
|
updateButtons();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// synthesizerChanged
|
|
//---------------------------------------------------------
|
|
|
|
void ZerberusGui::synthesizerChanged()
|
|
{
|
|
files->clear();
|
|
QStringList sfonts = zerberus()->soundFonts();
|
|
for (QString path : sfonts) {
|
|
QListWidgetItem* item = new QListWidgetItem;
|
|
item->setText(QFileInfo(path).fileName());
|
|
item->setData(Qt::UserRole, path);
|
|
files->addItem(item);
|
|
}
|
|
}
|