diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index ebff1a3..daf5fa3 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -2,12 +2,12 @@ cmake_minimum_required(VERSION 3.10) set(CMAKE_INCLUDE_CURRENT_DIR ON) -find_package(Qt5Widgets) -find_package(Qt5Network) -find_package(Qt5Xml) -find_package(Qt5Svg) -find_package(Qt5Script) -find_package(Qt5LinguistTools) +find_package(Qt5Widgets REQUIRED) +find_package(Qt5Network REQUIRED) +find_package(Qt5Xml REQUIRED) +find_package(Qt5Svg REQUIRED) +find_package(Qt5Qml REQUIRED) +find_package(Qt5LinguistTools REQUIRED) if(WIN32) list(APPEND PLAT_SRCS platforms/win/amuse-gui.rc platforms/win/amuse-gui.manifest) @@ -83,5 +83,5 @@ target_link_libraries(amuse-gui ${PLAT_LIBS} ${Qt5Network_LIBRARIES} ${Qt5Xml_LIBRARIES} ${Qt5Svg_LIBRARIES} - ${Qt5Script_LIBRARIES} + ${Qt5Qml_LIBRARIES} amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml xxhash ${ZLIB_LIBRARIES} ${LZO_LIB}) diff --git a/Editor/Common.cpp b/Editor/Common.cpp index 4be663a..c3afc04 100644 --- a/Editor/Common.cpp +++ b/Editor/Common.cpp @@ -44,7 +44,17 @@ void ShowInGraphicalShell(QWidget* parent, const QString& pathIn) const QFileInfo fileInfo(pathIn); // Mac, Windows support folder or file. #if defined(Q_OS_WIN) - const FileName explorer = Environment::systemEnvironment().searchInPath(QLatin1String("explorer.exe")); + QString paths = QProcessEnvironment::systemEnvironment().value(QStringLiteral("Path")); + QString explorer; + for (QString path : paths.split(QStringLiteral(";"))) + { + QFileInfo finfo(QDir(path), QStringLiteral("explorer.exe")); + if (finfo.exists()) + { + explorer = finfo.filePath(); + break; + } + } if (explorer.isEmpty()) { QMessageBox::warning(parent, MainWindow::tr("Launching Windows Explorer Failed"), @@ -55,7 +65,7 @@ void ShowInGraphicalShell(QWidget* parent, const QString& pathIn) if (!fileInfo.isDir()) param += QLatin1String("/select,"); param += QDir::toNativeSeparators(fileInfo.canonicalFilePath()); - QProcess::startDetached(explorer.toString(), param); + QProcess::startDetached(explorer, param); #elif defined(Q_OS_MAC) QStringList scriptArgs; scriptArgs << QLatin1String("-e") diff --git a/Editor/CurveEditor.cpp b/Editor/CurveEditor.cpp index 32c239d..23b62e9 100644 --- a/Editor/CurveEditor.cpp +++ b/Editor/CurveEditor.cpp @@ -3,8 +3,8 @@ #include #include #include -#include #include +#include class CurveEditUndoCommand : public EditorUndoCommand { @@ -199,24 +199,21 @@ void CurveControls::exprCommit() return; amuse::Curve& curve = static_cast(table); - QScriptSyntaxCheckResult res = QScriptEngine::checkSyntax(m_lineEdit->text()); - if (res.state() != QScriptSyntaxCheckResult::Valid) - { - m_errLabel->setText(res.errorMessage()); - return; - } - m_errLabel->setText(QString()); - + QString progText = m_lineEdit->text(); curve.data.resize(128); uint8_t newData[128]; std::memcpy(newData, curve.data.data(), 128); - QScriptProgram prog(m_lineEdit->text()); bool notANumber = false; for (int i = 0; i < 128; ++i) { m_engine.globalObject().setProperty(QStringLiteral("x"), i / 127.0); - QScriptValue val = m_engine.evaluate(prog); - if (val.isNumber()) + QJSValue val = m_engine.evaluate(progText); + if (val.isError()) + { + m_errLabel->setText(val.toString()); + return; + } + else if (val.isNumber()) { newData[i] = uint8_t(amuse::clamp(0, int(std::round(val.toNumber() * 127.0)), 127)); } @@ -284,7 +281,7 @@ CurveControls::CurveControls(QWidget* parent) mainLayout->addLayout(leftLayout); setLayout(mainLayout); - QScriptValueIterator it(m_engine.globalObject().property(QStringLiteral("Math"))); + QJSValueIterator it(m_engine.globalObject().property(QStringLiteral("Math"))); QString docStr = tr("Expression interpreter mapping x:[0,1] to y:[0,1] with the following constants and functions available:\n"); bool needsComma = false; while (it.hasNext()) diff --git a/Editor/CurveEditor.hpp b/Editor/CurveEditor.hpp index 6470d74..e0cdba3 100644 --- a/Editor/CurveEditor.hpp +++ b/Editor/CurveEditor.hpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include class CurveEditor; @@ -38,7 +38,7 @@ Q_OBJECT QLineEdit* m_lineEdit; QLabel* m_errLabel; QPushButton* m_setExpr; - QScriptEngine m_engine; + QJSEngine m_engine; CurveEditor* getEditor() const; public: explicit CurveControls(QWidget* parent = Q_NULLPTR); diff --git a/Editor/MainWindow.cpp b/Editor/MainWindow.cpp index ce6d738..b0c6adb 100644 --- a/Editor/MainWindow.cpp +++ b/Editor/MainWindow.cpp @@ -107,6 +107,9 @@ MainWindow::MainWindow(QWidget* parent) m_ui.actionDelete->setShortcut(QKeySequence::Delete); onFocusChanged(nullptr, this); + connect(m_ui.actionAbout_Amuse, SIGNAL(triggered()), this, SLOT(aboutAmuseAction())); + connect(m_ui.actionAbout_Qt, SIGNAL(triggered()), this, SLOT(aboutQtAction())); + QGridLayout* faceLayout = new QGridLayout; QSvgWidget* faceSvg = new QSvgWidget(QStringLiteral(":/bg/FaceGrey.svg")); faceSvg->setGeometry(0, 0, 256, 256); @@ -292,6 +295,7 @@ bool MainWindow::setProjectPath(const QString& path) while (files.size() > MaxRecentFiles) files.removeLast(); settings.setValue("recentFileList", files); + settings.sync(); updateRecentFileActions(); @@ -782,6 +786,7 @@ void MainWindow::openRecentFileAction() QStringList files = settings.value("recentFileList").toStringList(); files.removeAll(path); settings.setValue("recentFileList", files); + settings.sync(); updateRecentFileActions(); } } @@ -790,6 +795,7 @@ void MainWindow::clearRecentFilesAction() { QSettings settings; settings.setValue("recentFileList", QStringList()); + settings.sync(); updateRecentFileActions(); } @@ -1053,7 +1059,8 @@ ProjectModel::GroupNode* MainWindow::getSelectedGroupNode() const return nullptr; if (!m_ui.projectOutline->selectionModel()->currentIndex().isValid()) return nullptr; - return m_projectModel->getGroupNode(m_projectModel->node(m_ui.projectOutline->selectionModel()->currentIndex())); + return m_projectModel->getGroupNode(m_projectModel->node( + m_filterProjectModel.mapToSource(m_ui.projectOutline->selectionModel()->currentIndex()))); } QString MainWindow::getSelectedGroupName() const @@ -1271,6 +1278,62 @@ void MainWindow::setMIDIIO(bool checked) } } +void MainWindow::aboutAmuseAction() +{ +#ifdef Q_OS_MAC + static QPointer oldMsgBox; + + if (oldMsgBox) { + oldMsgBox->show(); + oldMsgBox->raise(); + oldMsgBox->activateWindow(); + return; + } +#endif + + QString translatedTextAboutAmuseCaption; + translatedTextAboutAmuseCaption = QMessageBox::tr( + "

About Amuse

" + ); + QString translatedTextAboutAmuseText; + translatedTextAboutAmuseText = QMessageBox::tr( + "

Amuse is an alternate editor and runtime library for MusyX sound groups.

" + "

MusyX originally served as a widely-deployed audio system for " + "developing games on the Nintendo 64, GameCube, and GameBoy Advance.

" + "

Amuse is available under the MIT license.
" + "Please see " + "https://gitlab.axiodl.com/AxioDL/amuse/blob/master/LICENSE for futher information.

" + "

Copyright (C) 2015-2018 Antidote / Jackoalan.

" + "

MusyX is a trademark of Factor 5, LLC.

" + "

Nintendo 64, GameCube, and GameBoy Advance are trademarks of Nintendo Co., Ltd.

" + ); + QMessageBox *msgBox = new QMessageBox(this); + msgBox->setAttribute(Qt::WA_DeleteOnClose); + msgBox->setWindowTitle(tr("About Amuse")); + msgBox->setText(translatedTextAboutAmuseCaption); + msgBox->setInformativeText(translatedTextAboutAmuseText); + msgBox->setIconPixmap(windowIcon().pixmap(64, 64)); + + // should perhaps be a style hint +#ifdef Q_OS_MAC + oldMsgBox = msgBox; +#if 0 + // ### doesn't work until close button is enabled in title bar + msgBox->d_func()->autoAddOkButton = false; +#else + msgBox->d_func()->buttonBox->setCenterButtons(true); +#endif + msgBox->show(); +#else + msgBox->exec(); +#endif +} + +void MainWindow::aboutQtAction() +{ + QMessageBox::aboutQt(this); +} + void MainWindow::notePressed(int key) { if (m_engine) diff --git a/Editor/MainWindow.hpp b/Editor/MainWindow.hpp index 900d111..ddb446d 100644 --- a/Editor/MainWindow.hpp +++ b/Editor/MainWindow.hpp @@ -206,6 +206,9 @@ public slots: void setAudioIO(); void setMIDIIO(bool checked); + void aboutAmuseAction(); + void aboutQtAction(); + void notePressed(int key); void noteReleased(); void velocityChanged(int vel); diff --git a/Editor/MainWindow.ui b/Editor/MainWindow.ui index fb6da0d..7a38249 100644 --- a/Editor/MainWindow.ui +++ b/Editor/MainWindow.ui @@ -257,7 +257,7 @@ 0 0 1501 - 85 + 83 @@ -294,7 +294,7 @@ 0 0 1360 - 27 + 25 @@ -358,11 +358,19 @@ + + + Help + + + + + @@ -420,7 +428,7 @@ false - + :/icons/IconNewSoundGroup.svg:/icons/IconNewSoundGroup.svg @@ -432,7 +440,7 @@ false - + :/icons/IconNewSongGroup.svg:/icons/IconNewSongGroup.svg @@ -444,7 +452,7 @@ false - + :/icons/IconNewSoundMacro.svg:/icons/IconNewSoundMacro.svg @@ -456,7 +464,7 @@ false - + :/icons/IconNewKeymap.svg:/icons/IconNewKeymap.svg @@ -468,7 +476,7 @@ false - + :/icons/IconNewLayers.svg:/icons/IconNewLayers.svg @@ -507,7 +515,7 @@ false - + :/icons/IconNewGroup.svg:/icons/IconNewGroup.svg @@ -519,7 +527,7 @@ false - + :/icons/IconNewADSR.svg:/icons/IconNewADSR.svg @@ -531,7 +539,7 @@ false - + :/icons/IconNewCurve.svg:/icons/IconNewCurve.svg @@ -570,6 +578,22 @@ I&mport Songs + + + About Amuse + + + QAction::AboutRole + + + + + About Qt + + + QAction::AboutQtRole + + @@ -599,6 +623,8 @@
KeyboardWidget.hpp
- + + + diff --git a/Editor/ProjectModel.cpp b/Editor/ProjectModel.cpp index 11437dd..b95a00c 100644 --- a/Editor/ProjectModel.cpp +++ b/Editor/ProjectModel.cpp @@ -405,7 +405,7 @@ bool ProjectModel::openGroupData(const QString& groupName, UIMessenger& messenge { m_projectDatabase.setIdDatabases(); QString path = QFileInfo(m_dir, groupName).filePath(); - m_groups.insert(std::make_pair(groupName, QStringToSysString(path))); + m_groups.insert(std::make_pair(groupName, std::make_unique(QStringToSysString(path)))); m_needsReset = true; return true; @@ -416,7 +416,7 @@ void ProjectModel::_resetSongRefCount() for (auto& song : m_midiFiles) song.second.m_refCount = 0; for (const auto& g : m_groups) - for (const auto& g2 : g.second.getProj().songGroups()) + for (const auto& g2 : g.second->getProj().songGroups()) for (const auto& m : g2.second->m_midiSetups) ++m_midiFiles[m.first].m_refCount; for (auto it = m_midiFiles.begin(); it != m_midiFiles.end();) @@ -471,7 +471,7 @@ void ProjectModel::importSongsData(const QString& path) amuse::SongConverter::SongToMIDI(song.second.m_data.get(), version, isBig); if (!midiData.empty()) { - QFileInfo fi(m_dir, SysStringToQString(song.first + ".mid")); + QFileInfo fi(m_dir, SysStringToQString(song.first + _S(".mid"))); QFile f(fi.filePath()); if (f.open(QFile::WriteOnly)) { @@ -486,15 +486,15 @@ void ProjectModel::importSongsData(const QString& path) _resetSongRefCount(); } -bool ProjectModel::reloadSampleData(const QString& groupName, UIMessenger& messenger) +bool ProjectModel::reloadSampleData(const QString& groupName, UIMessenger&) { m_projectDatabase.setIdDatabases(); QString path = QFileInfo(m_dir, groupName).filePath(); auto search = m_groups.find(groupName); if (search != m_groups.end()) { - search->second.setIdDatabases(); - search->second.getSdir().reloadSampleData(QStringToSysString(path)); + search->second->setIdDatabases(); + search->second->getSdir().reloadSampleData(QStringToSysString(path)); } m_needsReset = true; @@ -506,7 +506,8 @@ bool ProjectModel::importGroupData(const QString& groupName, const amuse::AudioG { m_projectDatabase.setIdDatabases(); - amuse::AudioGroupDatabase& grp = m_groups.insert(std::make_pair(groupName, data)).first->second; + amuse::AudioGroupDatabase& grp = *m_groups.insert(std::make_pair(groupName, + std::make_unique(data))).first->second; if (!MkPath(m_dir.path(), messenger)) return false; @@ -570,10 +571,10 @@ bool ProjectModel::saveToFile(UIMessenger& messenger) if (!MkPath(dir.path(), messenger)) return false; - g.second.setIdDatabases(); + g.second->setIdDatabases(); amuse::SystemString groupPath = QStringToSysString(dir.path()); - g.second.getProj().toYAML(groupPath); - g.second.getPool().toYAML(groupPath); + g.second->getProj().toYAML(groupPath); + g.second->getPool().toYAML(groupPath); } saveSongsIndex(); @@ -601,7 +602,7 @@ bool ProjectModel::exportGroup(const QString& path, const QString& groupName, UI messenger.critical(tr("Export Error"), tr("Unable to find group %1").arg(groupName)); return false; } - const amuse::AudioGroupDatabase& group = search->second; + const amuse::AudioGroupDatabase& group = *search->second; m_projectDatabase.setIdDatabases(); auto basePath = QStringToSysString(QFileInfo(QDir(path), groupName).filePath()); group.setIdDatabases(); @@ -623,9 +624,20 @@ bool ProjectModel::exportGroup(const QString& path, const QString& groupName, UI return true; } +void ProjectModel::_buildGroupNodeCollections(GroupNode& gn) +{ + gn.reserve(6); + gn._appendChild(tr("Sound Macros"), QIcon(":/icons/IconSoundMacro.svg"), INode::Type::SoundMacro); + gn._appendChild(tr("ADSRs"), QIcon(":/icons/IconADSR.svg"), INode::Type::ADSR); + gn._appendChild(tr("Curves"), QIcon(":/icons/IconCurve.svg"), INode::Type::Curve); + gn._appendChild(tr("Keymaps"), QIcon(":/icons/IconKeymap.svg"), INode::Type::Keymap); + gn._appendChild(tr("Layers"), QIcon(":/icons/IconLayers.svg"), INode::Type::Layer); + gn._appendChild(tr("Samples"), QIcon(":/icons/IconSample.svg"), INode::Type::Sample); +} + void ProjectModel::_buildGroupNode(GroupNode& gn) { - amuse::AudioGroup& group = gn.m_it->second; + amuse::AudioGroup& group = *gn.m_it->second; auto& songGroups = group.getProj().songGroups(); auto& sfxGroups = group.getProj().sfxGroups(); auto& soundMacros = group.getPool().soundMacros(); @@ -633,14 +645,14 @@ void ProjectModel::_buildGroupNode(GroupNode& gn) auto& keymaps = group.getPool().keymaps(); auto& layers = group.getPool().layers(); auto& samples = group.getSdir().sampleEntries(); - gn.reserve(songGroups.size() + sfxGroups.size() + 4); + gn.reserve(songGroups.size() + sfxGroups.size() + 6); + _buildGroupNodeCollections(gn); for (const auto& grp : SortUnorderedMap(songGroups)) gn.makeChild(grp.first, grp.second.get()); for (const auto& grp : SortUnorderedMap(sfxGroups)) gn.makeChild(grp.first, grp.second.get()); { - CollectionNode& col = - gn._appendChild(tr("Sound Macros"), QIcon(":/icons/IconSoundMacro.svg"), INode::Type::SoundMacro); + CollectionNode& col = *gn.getCollectionOfType(INode::Type::SoundMacro); col.reserve(soundMacros.size()); for (const auto& macro : SortUnorderedMap(soundMacros)) col.makeChild(macro.first, macro.second.get()); @@ -658,8 +670,7 @@ void ProjectModel::_buildGroupNode(GroupNode& gn) curveCount += 1; } { - CollectionNode& col = - gn._appendChild(tr("ADSRs"), QIcon(":/icons/IconADSR.svg"), INode::Type::ADSR); + CollectionNode& col = *gn.getCollectionOfType(INode::Type::ADSR); col.reserve(ADSRCount); for (auto& t : tablesSort) { @@ -669,8 +680,7 @@ void ProjectModel::_buildGroupNode(GroupNode& gn) } } { - CollectionNode& col = - gn._appendChild(tr("Curves"), QIcon(":/icons/IconCurve.svg"), INode::Type::Curve); + CollectionNode& col = *gn.getCollectionOfType(INode::Type::Curve); col.reserve(curveCount); for (auto& t : tablesSort) { @@ -681,22 +691,19 @@ void ProjectModel::_buildGroupNode(GroupNode& gn) } } { - CollectionNode& col = - gn._appendChild(tr("Keymaps"), QIcon(":/icons/IconKeymap.svg"), INode::Type::Keymap); + CollectionNode& col = *gn.getCollectionOfType(INode::Type::Keymap); col.reserve(keymaps.size()); for (auto& keymap : SortUnorderedMap(keymaps)) col.makeChild(keymap.first, keymap.second.get()); } { - CollectionNode& col = - gn._appendChild(tr("Layers"), QIcon(":/icons/IconLayers.svg"), INode::Type::Layer); + CollectionNode& col = *gn.getCollectionOfType(INode::Type::Layer); col.reserve(layers.size()); for (auto& keymap : SortUnorderedMap(layers)) col.makeChild(keymap.first, keymap.second.get()); } { - CollectionNode& col = - gn._appendChild(tr("Samples"), QIcon(":/icons/IconSample.svg"), INode::Type::Sample); + CollectionNode& col = *gn.getCollectionOfType(INode::Type::Sample); col.reserve(samples.size()); for (auto& sample : SortUnorderedMap(samples)) col.makeChild(sample.first, sample.second.get()); @@ -711,7 +718,7 @@ void ProjectModel::_resetModelData() m_root->reserve(m_groups.size()); for (auto it = m_groups.begin(); it != m_groups.end(); ++it) { - it->second.setIdDatabases(); + it->second->setIdDatabases(); GroupNode& gn = m_root->makeChild(it); _buildGroupNode(gn); } @@ -890,6 +897,86 @@ void ProjectModel::_preDelNode(INode* n, NameUndoRegistry& registry) }); } +class GroupNodeUndoCommand : public QUndoCommand +{ +protected: + std::unique_ptr m_data; + amuse::ObjToken m_node; + ProjectModel::NameUndoRegistry m_nameReg; + void add() + { + g_MainWindow->projectModel()->_addNode(m_node.get(), std::move(m_data), m_nameReg); + g_MainWindow->recursiveExpandAndSelectOutline(g_MainWindow->projectModel()->index(m_node.get())); + } + void del() + { + m_data = g_MainWindow->projectModel()->_delNode(m_node.get(), m_nameReg); + } +public: + explicit GroupNodeUndoCommand(const QString& text, std::unique_ptr&& data, ProjectModel::GroupNode* node) + : QUndoCommand(text.arg(node->text())), m_data(std::move(data)), m_node(node) {} +}; + +class GroupNodeAddUndoCommand : public GroupNodeUndoCommand +{ + using base = GroupNodeUndoCommand; +public: + explicit GroupNodeAddUndoCommand(const QString& text, std::unique_ptr&& data, ProjectModel::GroupNode* node) + : GroupNodeUndoCommand(text, std::move(data), node) {} + void undo() { base::del(); } + void redo() { base::add(); } +}; + +class GroupNodeDelUndoCommand : public GroupNodeUndoCommand +{ + using base = GroupNodeUndoCommand; +public: + explicit GroupNodeDelUndoCommand(const QString& text, ProjectModel::GroupNode* node) + : GroupNodeUndoCommand(text, {}, node) {} + void undo() { base::add(); } + void redo() { base::del(); } +}; + +void ProjectModel::_addNode(GroupNode* node, std::unique_ptr&& data, const NameUndoRegistry& registry) +{ + int idx = m_root->hypotheticalIndex(node->name()); + beginInsertRows(QModelIndex(), idx, idx); + QDir dir(QFileInfo(m_dir, node->name()).filePath()); + node->m_it = m_groups.emplace(std::make_pair(node->name(), std::move(data))).first; + m_root->insertChild(node); + _postAddNode(node, registry); + endInsertRows(); +} + +std::unique_ptr ProjectModel::_delNode(GroupNode* node, NameUndoRegistry& registry) +{ + int idx = node->row(); + beginRemoveRows(QModelIndex(), idx, idx); + _preDelNode(node, registry); + std::unique_ptr ret = std::move(node->m_it->second); + m_groups.erase(node->m_it); + node->m_it = {}; + m_root->removeChild(node); + endRemoveRows(); + return ret; +} + +ProjectModel::GroupNode* ProjectModel::newSubproject(const QString& name) +{ + if (m_groups.find(name) != m_groups.cend()) + { + g_MainWindow->uiMessenger(). + critical(tr("Subproject Conflict"), tr("The subproject %1 is already defined").arg(name)); + return nullptr; + } + QString path = QFileInfo(m_dir, name).filePath(); + auto data = std::make_unique(QStringToSysString(path)); + auto node = amuse::MakeObj(name); + _buildGroupNodeCollections(*node); + g_MainWindow->pushUndoCommand(new GroupNodeAddUndoCommand(tr("Add Subproject %1"), std::move(data), node.get())); + return node.get(); +} + template class NodeUndoCommand : public QUndoCommand { @@ -933,43 +1020,6 @@ public: void redo() { base::del(); } }; -void ProjectModel::_addNode(GroupNode* node, GroupNode*, const NameUndoRegistry& registry) -{ - int idx = m_root->hypotheticalIndex(node->name()); - beginInsertRows(QModelIndex(), idx, idx); - QDir dir(QFileInfo(m_dir, node->name()).filePath()); - node->m_it = m_groups.emplace(std::make_pair(node->name(), - amuse::AudioGroupDatabase(QStringToSysString(dir.path())))).first; - m_root->insertChild(node); - _postAddNode(node, registry); - endInsertRows(); -} - -void ProjectModel::_delNode(GroupNode* node, GroupNode*, NameUndoRegistry& registry) -{ - int idx = node->row(); - beginRemoveRows(QModelIndex(), idx, idx); - _preDelNode(node, registry); - m_groups.erase(node->m_it); - node->m_it = {}; - m_root->removeChild(node); - endRemoveRows(); -} - -ProjectModel::GroupNode* ProjectModel::newSubproject(const QString& name) -{ - if (m_groups.find(name) != m_groups.cend()) - { - g_MainWindow->uiMessenger(). - critical(tr("Subproject Conflict"), tr("The subproject %1 is already defined").arg(name)); - return nullptr; - } - auto node = amuse::MakeObj(name); - _buildGroupNode(*node); - g_MainWindow->pushUndoCommand(new NodeAddUndoCommand(tr("Add Subproject %1"), node.get(), nullptr)); - return node.get(); -} - template void ProjectModel::_addGroupNode(NT* node, GroupNode* parent, const NameUndoRegistry& registry, T& container) { @@ -1256,7 +1306,7 @@ void ProjectModel::del(const QModelIndex& index) switch (n->type()) { case INode::Type::Group: - cmd = new NodeDelUndoCommand(tr("Delete Subproject %1"), static_cast(n)); + cmd = new GroupNodeDelUndoCommand(tr("Delete Subproject %1"), static_cast(n)); break; case INode::Type::SongGroup: cmd = new NodeDelUndoCommand(tr("Delete SongGroup %1"), static_cast(n)); diff --git a/Editor/ProjectModel.hpp b/Editor/ProjectModel.hpp index 5dbddb2..d80be1d 100644 --- a/Editor/ProjectModel.hpp +++ b/Editor/ProjectModel.hpp @@ -74,7 +74,7 @@ private: PageObjectProxyModel m_pageObjectProxy; amuse::ProjectDatabase m_projectDatabase; - std::unordered_map m_groups; + std::unordered_map> m_groups; struct Song { @@ -220,9 +220,9 @@ public: struct BasePoolObjectNode; struct GroupNode : INode { - std::unordered_map::iterator m_it; + std::unordered_map>::iterator m_it; GroupNode(const QString& name) : INode(name) {} - GroupNode(std::unordered_map::iterator it) + GroupNode(std::unordered_map>::iterator it) : INode(it->first), m_it(it) {} int hypotheticalIndex(const QString& name) const; @@ -233,7 +233,7 @@ public: QIcon icon() const { return Icon; } CollectionNode* getCollectionOfType(Type tp) const; - amuse::AudioGroupDatabase* getAudioGroup() const { return &m_it->second; } + amuse::AudioGroupDatabase* getAudioGroup() const { return m_it->second.get(); } BasePoolObjectNode* pageObjectNodeOfId(amuse::ObjectId id) const; }; struct SongGroupNode : INode @@ -347,6 +347,7 @@ public: amuse::ObjToken m_root; bool m_needsReset = false; + void _buildGroupNodeCollections(GroupNode& gn); void _buildGroupNode(GroupNode& gn); void _resetModelData(); void _resetSongRefCount(); @@ -383,8 +384,8 @@ public: void _postAddNode(INode* n, const NameUndoRegistry& registry); void _preDelNode(INode* n, NameUndoRegistry& registry); - void _addNode(GroupNode* node, GroupNode* parent, const NameUndoRegistry& registry); - void _delNode(GroupNode* node, GroupNode* parent, NameUndoRegistry& registry); + void _addNode(GroupNode* node, std::unique_ptr&& data, const NameUndoRegistry& registry); + std::unique_ptr _delNode(GroupNode* node, NameUndoRegistry& registry); GroupNode* newSubproject(const QString& name); template void _addGroupNode(NT* node, GroupNode* parent, const NameUndoRegistry& registry, T& container); diff --git a/Editor/SoundMacroEditor.cpp b/Editor/SoundMacroEditor.cpp index 36db78d..b5611e1 100644 --- a/Editor/SoundMacroEditor.cpp +++ b/Editor/SoundMacroEditor.cpp @@ -101,7 +101,7 @@ FieldSoundMacroStep::~FieldSoundMacroStep() } FieldSoundMacroStep::FieldSoundMacroStep(FieldProjectNode* macroField, QWidget* parent) -: QWidget(parent), m_macroField(macroField) +: QWidget(parent), m_macroField(macroField), m_spinBox(this), m_targetButton(this) { QHBoxLayout* layout = new QHBoxLayout; layout->setContentsMargins(QMargins()); @@ -118,15 +118,15 @@ FieldSoundMacroStep::FieldSoundMacroStep(FieldProjectNode* macroField, QWidget* setLayout(layout); } -CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::CmdOp op, SoundMacroListing* listing) -: QWidget(nullptr), m_cmd(cmd), m_introspection(amuse::SoundMacro::GetCmdIntrospection(op)) +CommandWidget::CommandWidget(QWidget* parent, amuse::SoundMacro::ICmd* cmd, + amuse::SoundMacro::CmdOp op, SoundMacroListing* listing) +: QWidget(parent), m_titleLabel(this), m_deleteButton(this), m_cmd(cmd), + m_introspection(amuse::SoundMacro::GetCmdIntrospection(op)) { QFont titleFont = m_titleLabel.font(); titleFont.setWeight(QFont::Bold); m_titleLabel.setFont(titleFont); m_titleLabel.setForegroundRole(QPalette::Background); - //m_titleLabel.setAutoFillBackground(true); - //m_titleLabel.setBackgroundRole(QPalette::Text); m_titleLabel.setContentsMargins(46, 0, 0, 0); m_titleLabel.setFixedHeight(20); m_numberText.setTextOption(QTextOption(Qt::AlignRight)); @@ -171,12 +171,12 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm if (!field.m_name.empty()) { QString fieldName = tr(field.m_name.data()); - layout->addWidget(new QLabel(fieldName), 0, f); + layout->addWidget(new QLabel(fieldName, this), 0, f); switch (field.m_tp) { case amuse::SoundMacro::CmdIntrospection::Field::Type::Bool: { - QCheckBox* cb = new QCheckBox; + QCheckBox* cb = new QCheckBox(this); cb->setProperty("fieldIndex", f); cb->setProperty("fieldName", fieldName); cb->setCheckState(amuse::AccessField(m_cmd, field) ? Qt::Checked : Qt::Unchecked); @@ -191,7 +191,7 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm case amuse::SoundMacro::CmdIntrospection::Field::Type::Int32: case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt32: { - FieldSpinBox* sb = new FieldSpinBox; + FieldSpinBox* sb = new FieldSpinBox(this); sb->setProperty("fieldIndex", f); sb->setProperty("fieldName", fieldName); sb->setMinimum(int(field.m_min)); @@ -246,7 +246,7 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm } auto* collection = g_MainWindow->projectModel()->getGroupNode(listing->currentNode())-> getCollectionOfType(collectionType); - nf = new FieldProjectNode(collection); + nf = new FieldProjectNode(collection, this); nf->setProperty("fieldIndex", f); nf->setProperty("fieldName", fieldName); int index = collection->indexOfId( @@ -258,7 +258,7 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm } case amuse::SoundMacro::CmdIntrospection::Field::Type::SoundMacroStep: { - FieldSoundMacroStep* sb = new FieldSoundMacroStep(nf); + FieldSoundMacroStep* sb = new FieldSoundMacroStep(nf, this); sb->setProperty("fieldIndex", f); sb->setProperty("fieldName", fieldName); sb->m_spinBox.setValue(amuse::AccessField>(m_cmd, field).step); @@ -269,7 +269,7 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm } case amuse::SoundMacro::CmdIntrospection::Field::Type::Choice: { - FieldComboBox* cb = new FieldComboBox; + FieldComboBox* cb = new FieldComboBox(this); cb->setProperty("fieldIndex", f); cb->setProperty("fieldName", fieldName); for (int j = 0; j < 4; ++j) @@ -295,11 +295,11 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm setLayout(mainLayout); } -CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, SoundMacroListing* listing) -: CommandWidget(cmd, cmd->Isa(), listing) {} +CommandWidget::CommandWidget(QWidget* parent, amuse::SoundMacro::ICmd* cmd, SoundMacroListing* listing) +: CommandWidget(parent, cmd, cmd->Isa(), listing) {} -CommandWidget::CommandWidget(amuse::SoundMacro::CmdOp op, SoundMacroListing* listing) -: CommandWidget(nullptr, op, listing) {} +CommandWidget::CommandWidget(QWidget* parent, amuse::SoundMacro::CmdOp op, SoundMacroListing* listing) +: CommandWidget(parent, nullptr, op, listing) {} class ValChangedUndoCommand : public EditorUndoCommand { @@ -557,8 +557,9 @@ void CommandWidgetContainer::animationDestroyed() m_animation = nullptr; } -CommandWidgetContainer::CommandWidgetContainer(CommandWidget* child, QWidget* parent) -: QWidget(parent), m_commandWidget(child) +template +CommandWidgetContainer::CommandWidgetContainer(QWidget* parent, _Args&&... args) +: QWidget(parent), m_commandWidget(new CommandWidget(this, std::forward<_Args>(args)...)) { setMinimumHeight(100); setContentsMargins(QMargins()); @@ -566,7 +567,7 @@ CommandWidgetContainer::CommandWidgetContainer(CommandWidget* child, QWidget* pa outerLayout->setAlignment(Qt::AlignBottom); outerLayout->setContentsMargins(QMargins()); outerLayout->setSpacing(0); - outerLayout->addWidget(child); + outerLayout->addWidget(m_commandWidget); setLayout(outerLayout); } @@ -809,7 +810,7 @@ void SoundMacroListing::insert(amuse::SoundMacro::CmdOp op, const QString& text) g_MainWindow->pushUndoCommand(new InsertCommandUndoCommand(insertIdx, text, m_node)); m_layout->insertWidget(insertIdx, - new CommandWidgetContainer(new CommandWidget(m_node->m_obj->insertNewCmd(insertIdx, op), this))); + new CommandWidgetContainer(this, m_node->m_obj->insertNewCmd(insertIdx, op), this)); stopAutoscroll(); reindex(); @@ -875,7 +876,7 @@ bool SoundMacroListing::loadData(ProjectModel::SoundMacroNode* node) { if (cmd->Isa() == amuse::SoundMacro::CmdOp::End) break; - m_layout->insertWidget(i++, new CommandWidgetContainer(new CommandWidget(cmd.get(), this))); + m_layout->insertWidget(i++, new CommandWidgetContainer(this, cmd.get(), this)); } reindex(); update(); @@ -898,7 +899,7 @@ ProjectModel::INode* SoundMacroListing::currentNode() const SoundMacroListing::SoundMacroListing(QWidget* parent) : QWidget(parent), m_layout(new QVBoxLayout) { - m_layout->addWidget(new CommandWidgetContainer(new CommandWidget(amuse::SoundMacro::CmdOp::End, this))); + m_layout->addWidget(new CommandWidgetContainer(this, amuse::SoundMacro::CmdOp::End, this)); m_layout->addStretch(); setLayout(m_layout); reindex(); @@ -970,7 +971,7 @@ SoundMacroCatalogue::SoundMacroCatalogue(QWidget* parent) { rootItems[i] = new QTreeWidgetItem(this); setItemWidget(rootItems[i], 0, new CatalogueItem(amuse::SoundMacro::CmdOp::Invalid, - tr(CategoryStrings[i]), tr(CategoryDocStrings[i]))); + tr(CategoryStrings[i]), tr(CategoryDocStrings[i]), this)); } for (int i = 1; i < int(amuse::SoundMacro::CmdOp::CmdOpMAX); ++i) @@ -981,7 +982,7 @@ SoundMacroCatalogue::SoundMacroCatalogue(QWidget* parent) { QTreeWidgetItem* item = new QTreeWidgetItem(rootItems[int(cmd->m_tp)]); setItemWidget(item, 0, new CatalogueItem(amuse::SoundMacro::CmdOp(i), tr(cmd->m_name.data()), - tr(cmd->m_description.data()))); + tr(cmd->m_description.data()), this)); } } } diff --git a/Editor/SoundMacroEditor.hpp b/Editor/SoundMacroEditor.hpp index 0fbbe00..5686283 100644 --- a/Editor/SoundMacroEditor.hpp +++ b/Editor/SoundMacroEditor.hpp @@ -69,10 +69,10 @@ private slots: void nodeChanged(int); void deleteClicked(); private: - CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::CmdOp op, SoundMacroListing* listing); + CommandWidget(QWidget* parent, amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::CmdOp op, SoundMacroListing* listing); public: - CommandWidget(amuse::SoundMacro::ICmd* cmd, SoundMacroListing* listing); - CommandWidget(amuse::SoundMacro::CmdOp op, SoundMacroListing* listing); + CommandWidget(QWidget* parent, amuse::SoundMacro::ICmd* cmd, SoundMacroListing* listing); + CommandWidget(QWidget* parent, amuse::SoundMacro::CmdOp op, SoundMacroListing* listing); void paintEvent(QPaintEvent* event); QString getText() const { return m_titleLabel.text(); } }; @@ -90,7 +90,8 @@ class CommandWidgetContainer : public QWidget private slots: void animationDestroyed(); public: - CommandWidgetContainer(CommandWidget* child, QWidget* parent = Q_NULLPTR); + template + CommandWidgetContainer(QWidget* parent, _Args&&... args); }; class SoundMacroListing : public QWidget diff --git a/Editor/StudioSetupWidget.cpp b/Editor/StudioSetupWidget.cpp index 5f77fb8..c1c8df3 100644 --- a/Editor/StudioSetupWidget.cpp +++ b/Editor/StudioSetupWidget.cpp @@ -277,7 +277,7 @@ Uint32X8Popup::Uint32X8Popup(int min, int max, QWidget* parent) for (int i = 0; i < 8; ++i) { layout->addWidget(new QLabel(tr(ChanNames[i])), i, 0); - FieldSlider* slider = new FieldSlider; + FieldSlider* slider = new FieldSlider(this); m_sliders[i] = slider; slider->setToolTip(QStringLiteral("[%1,%2]").arg(min).arg(max)); slider->setProperty("chanIdx", i); @@ -336,8 +336,9 @@ void Uint32X8Button::onPressed() m_popup->show(); } -EffectWidget::EffectWidget(amuse::EffectBaseTypeless* effect, amuse::EffectType type) -: QWidget(nullptr), m_effect(effect), m_introspection(GetEffectIntrospection(type)) +EffectWidget::EffectWidget(QWidget* parent, amuse::EffectBaseTypeless* effect, amuse::EffectType type) +: QWidget(parent), m_titleLabel(this), m_deleteButton(this), + m_effect(effect), m_introspection(GetEffectIntrospection(type)) { QFont titleFont = m_titleLabel.font(); titleFont.setWeight(QFont::Bold); @@ -384,12 +385,12 @@ EffectWidget::EffectWidget(amuse::EffectBaseTypeless* effect, amuse::EffectType if (!field.m_name.empty()) { QString fieldName = tr(field.m_name.data()); - layout->addWidget(new QLabel(fieldName), 0, f); + layout->addWidget(new QLabel(fieldName, this), 0, f); switch (field.m_tp) { case EffectIntrospection::Field::Type::UInt32: { - FieldSlider* sb = new FieldSlider; + FieldSlider* sb = new FieldSlider(this); sb->setProperty("fieldIndex", f); sb->setRange(int(field.m_min), int(field.m_max)); sb->setToolTip(QStringLiteral("[%1,%2]").arg(int(field.m_min)).arg(int(field.m_max))); @@ -400,7 +401,7 @@ EffectWidget::EffectWidget(amuse::EffectBaseTypeless* effect, amuse::EffectType } case EffectIntrospection::Field::Type::UInt32x8: { - Uint32X8Button* sb = new Uint32X8Button(int(field.m_min), int(field.m_max)); + Uint32X8Button* sb = new Uint32X8Button(int(field.m_min), int(field.m_max), this); sb->popup()->setProperty("fieldIndex", f); for (int i = 0; i < 8; ++i) sb->popup()->setValue(i, GetEffectParm(m_effect, f, i)); @@ -410,7 +411,7 @@ EffectWidget::EffectWidget(amuse::EffectBaseTypeless* effect, amuse::EffectType } case EffectIntrospection::Field::Type::Float: { - FieldDoubleSlider* sb = new FieldDoubleSlider; + FieldDoubleSlider* sb = new FieldDoubleSlider(this); sb->setProperty("fieldIndex", f); sb->setRange(field.m_min, field.m_max); sb->setToolTip(QStringLiteral("[%1,%2]").arg(field.m_min).arg(field.m_max)); @@ -474,11 +475,11 @@ void EffectWidget::paintEvent(QPaintEvent* event) painter.drawStaticText(-15, 10, m_numberText); } -EffectWidget::EffectWidget(amuse::EffectBaseTypeless* cmd) -: EffectWidget(cmd, cmd->Isa()) {} +EffectWidget::EffectWidget(QWidget* parent, amuse::EffectBaseTypeless* cmd) +: EffectWidget(parent, cmd, cmd->Isa()) {} -EffectWidget::EffectWidget(amuse::EffectType type) -: EffectWidget(nullptr, type) {} +EffectWidget::EffectWidget(QWidget* parent, amuse::EffectType type) +: EffectWidget(parent, nullptr, type) {} void EffectWidget::numChanged(int value) { @@ -558,8 +559,9 @@ void EffectWidgetContainer::animationDestroyed() m_animation = nullptr; } -EffectWidgetContainer::EffectWidgetContainer(EffectWidget* child, QWidget* parent) - : QWidget(parent), m_effectWidget(child) +template +EffectWidgetContainer::EffectWidgetContainer(QWidget* parent, _Args&&... args) +: QWidget(parent), m_effectWidget(new EffectWidget(this, std::forward<_Args>(args)...)) { setMinimumHeight(100); setContentsMargins(QMargins()); @@ -567,7 +569,7 @@ EffectWidgetContainer::EffectWidgetContainer(EffectWidget* child, QWidget* paren outerLayout->setAlignment(Qt::AlignBottom); outerLayout->setContentsMargins(QMargins()); outerLayout->setSpacing(0); - outerLayout->addWidget(child); + outerLayout->addWidget(m_effectWidget); setLayout(outerLayout); } @@ -779,7 +781,7 @@ void EffectListing::insert(amuse::EffectType type, const QString& text) break; } auto it = m_submix->getEffectStack().insert(m_submix->getEffectStack().begin() + insertIdx, std::move(newEffect)); - m_layout->insertWidget(insertIdx, new EffectWidgetContainer(new EffectWidget(it->get()))); + m_layout->insertWidget(insertIdx, new EffectWidgetContainer(this, it->get())); stopAutoscroll(); reindex(); @@ -818,7 +820,7 @@ bool EffectListing::loadData(amuse::Submix* submix) clear(); int i = 0; for (auto& effect : submix->getEffectStack()) - m_layout->insertWidget(i++, new EffectWidgetContainer(new EffectWidget(effect.get()))); + m_layout->insertWidget(i++, new EffectWidgetContainer(this, effect.get())); reindex(); update(); return true; @@ -842,7 +844,7 @@ EffectListing::EffectListing(QWidget* parent) EffectCatalogueItem::EffectCatalogueItem(amuse::EffectType type, const QString& name, const QString& doc, QWidget* parent) -: QWidget(parent), m_type(type), m_label(name) +: QWidget(parent), m_type(type), m_iconLab(this), m_label(name, this) { QHBoxLayout* layout = new QHBoxLayout; QString iconPath = QStringLiteral(":/commands/%1.svg").arg(name); @@ -899,7 +901,7 @@ EffectCatalogue::EffectCatalogue(QWidget* parent) { QTreeWidgetItem* item = new QTreeWidgetItem(this); setItemWidget(item, 0, new EffectCatalogueItem(amuse::EffectType(i), - tr(EffectStrings[i-1]), tr(EffectDocStrings[i-1]))); + tr(EffectStrings[i-1]), tr(EffectDocStrings[i-1]), this)); } } diff --git a/Editor/StudioSetupWidget.hpp b/Editor/StudioSetupWidget.hpp index c11732c..953ce9c 100644 --- a/Editor/StudioSetupWidget.hpp +++ b/Editor/StudioSetupWidget.hpp @@ -80,11 +80,11 @@ private slots: void chanNumChanged(int, int); void deleteClicked(); private: - explicit EffectWidget(amuse::EffectBaseTypeless* effect, amuse::EffectType type); + explicit EffectWidget(QWidget* parent, amuse::EffectBaseTypeless* effect, amuse::EffectType type); public: EffectListing* getParent() const; - explicit EffectWidget(amuse::EffectBaseTypeless* effect); - explicit EffectWidget(amuse::EffectType op); + explicit EffectWidget(QWidget* parent, amuse::EffectBaseTypeless* effect); + explicit EffectWidget(QWidget* parent, amuse::EffectType op); void paintEvent(QPaintEvent* event); QString getText() const { return m_titleLabel.text(); } }; @@ -102,7 +102,8 @@ class EffectWidgetContainer : public QWidget private slots: void animationDestroyed(); public: - EffectWidgetContainer(EffectWidget* child, QWidget* parent = Q_NULLPTR); + template + EffectWidgetContainer(QWidget* parent, _Args&&... args); }; class EffectListing : public QWidget diff --git a/Editor/main.cpp b/Editor/main.cpp index 0a94624..0e7027d 100644 --- a/Editor/main.cpp +++ b/Editor/main.cpp @@ -66,6 +66,9 @@ int main(int argc, char* argv[]) QApplication a(argc, argv); QApplication::setWindowIcon(MakeAppIcon()); + a.setOrganizationName("AxioDL"); + a.setApplicationName("Amuse"); + QPalette darkPalette; darkPalette.setColor(QPalette::Window, QColor(53,53,53)); darkPalette.setColor(QPalette::WindowText, Qt::white); diff --git a/Editor/resources/lang_de.ts b/Editor/resources/lang_de.ts index 4cc0c4e..3bfb078 100644 --- a/Editor/resources/lang_de.ts +++ b/Editor/resources/lang_de.ts @@ -125,22 +125,22 @@ - + Did not evaluate as a number - + Expression - + Apply - + Expression interpreter mapping x:[0,1] to y:[0,1] with the following constants and functions available: @@ -148,27 +148,27 @@ EffectCatalogue - - - - Reverb Standard - - - - - - Reverb High - - - Delay + Reverb Standard + Reverb High + + + + + + Delay + + + + + Chorus @@ -404,125 +404,141 @@ - + + Help + + + + &New Project - + &Open Project - + &Cut - + C&opy - + &Paste - + &Delete - + &Import Groups - + Ctrl+I - + New SF&X Group - + New Son&g Group - + New Sound &Macro - + New &Keymap - + New &Layers - + &Output Device: - + &Input Device: - + &Export GameCube Groups - + Ctrl+E - + &New Subproject - + New &ADSR - + New &Curve - + &Save Project - + &Revert Project - + Reload Sample &Data - + I&mport Songs + + + + About Amuse + + + + + About Qt + + A directory at '%1/%2' could not be created. @@ -534,27 +550,27 @@ - + Launching Windows Explorer Failed - + Could not find explorer.exe in path to launch Windows Explorer. - + Show in Explorer - + Show in Finder - + Show in Browser @@ -569,300 +585,300 @@ - + Amuse[*] - + %1/%2/%3[*] - Amuse - + %1[*] - Amuse - - + + The directory at '%1' must not be empty. - - + + Directory empty - + The directory at '%1' must exist for the Amuse editor. - + Directory does not exist - + __amuse_test__ - + The directory at '%1' must be writable for the Amuse editor: %2 - + Unable to write to directory - + No Audio Devices Found - + Virtual MIDI-In - + No MIDI Devices Found - + SUSTAIN - + Unsaved Changes - + Save Changes in %1? - + New Project - + The directory at '%1' does not exist. - + Bad Directory - + Opening - - - - - + + + + + Scanning Project - + Opening %1 - + Open Project - + Reloading Samples - + Scanning %1 - + Import Project - + The file at '%1' could not be interpreted as a MusyX container. - + Unsupported MusyX Container - + Sample Import Mode - + Amuse can import samples as WAV files for ease of editing, import original compressed data for lossless repacking, or both. Exporting the project will prefer whichever version was modified most recently. - + Import Compressed - + Import WAVs - + Import Both - + Raw Import Mode - + Would you like to scan for all MusyX group files in this directory? - + Project Name - + What should this project be named? - - + + Importing - - + + Importing %1 - + Import Songs - + Exporting - + Exporting %1 - + Export Complete - + %1? - + New Subproject - + New SFX Group - + What should the new SFX group in %1 be named? - + New Song Group - + What should the new Song group in %1 be named? - + New ADSR - + What should the new ADSR in %1 be named? - + New Curve - + What should the new Curve in %1 be named? - + New Keymap - + What should the new Keymap in %1 be named? - + New Layers - + What should the new Layers in %1 be named? - + What should this subproject be named? @@ -1080,220 +1096,233 @@ ProjectModel - - - - + + + + Export Error - + Unable to find group %1 - + Unable to export %1.proj - + Unable to export %1.pool - + Unable to export %1.sdir - + Sound Macros - + ADSRs - + Curves - + Keymaps - + Layers - + Samples - + Subproject Conflict - + The subproject %1 is already defined - + Add Subproject %1 - + Sound Group Conflict - - + + The group %1 is already defined - + Add Sound Group %1 - + Song Group Conflict - + Add Song Group %1 - + Sound Macro Conflict - + The macro %1 is already defined - + Add Sound Macro %1 - + ADSR Conflict - + The ADSR %1 is already defined - + Add ADSR %1 - + Curve Conflict - + The Curve %1 is already defined - + Add Curve %1 - + Keymap Conflict - + The Keymap %1 is already defined - + Add Keymap %1 - + Layers Conflict - + Layers %1 is already defined - + Add Layers %1 - + Delete Subproject %1 - + Delete SongGroup %1 - + Delete SFXGroup %1 - + Delete SoundMacro %1 - + Delete ADSR %1 - + Delete Curve %1 - + Delete Keymap %1 - + Delete Layers %1 + + QMessageBox + + + <h3>About Amuse</h3> + + + + + <p>Amuse is an alternate editor and runtime library for MusyX sound groups.</p><p>MusyX originally served as a widely-deployed audio system for developing games on the Nintendo 64, GameCube, and GameBoy Advance.</p><p>Amuse is available under the MIT license.<br>Please see <a href="https://gitlab.axiodl.com/AxioDL/amuse/blob/master/LICENSE">https://gitlab.axiodl.com/AxioDL/amuse/blob/master/LICENSE</a> for futher information.</p><p>Copyright (C) 2015-2018 Antidote / Jackoalan.</p><p>MusyX is a trademark of Factor 5, LLC.</p><p>Nintendo 64, GameCube, and GameBoy Advance are trademarks of Nintendo Co., Ltd.</p> + + + SFXModel @@ -1591,72 +1620,72 @@ SoundMacroCatalogue - + Control - + Pitch - + Sample - + Setup - + Special - + Structure - + Volume - + Commands to control the voice - + Commands to control the voice's pitch - + Commands to control the voice's sample playback - + Commands to setup the voice's mixing process - + Miscellaneous commands - + Commands to control macro branching - + Commands to control the voice's volume @@ -1672,17 +1701,17 @@ SoundMacroListing - + Reorder %1 - + Insert %1 - + Delete %1 @@ -1713,17 +1742,17 @@ StudioSetupWidget - + Studio Setup - + Aux A - + Aux B diff --git a/LICENSE b/LICENSE index 4dabaa9..39efd69 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2015-2016 Amuse Contributors +Copyright (c) 2015-2018 Antidote / Jackoalan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/include/amuse/AudioGroupPool.hpp b/include/amuse/AudioGroupPool.hpp index 306e91a..9ce3ea0 100644 --- a/include/amuse/AudioGroupPool.hpp +++ b/include/amuse/AudioGroupPool.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "Entity.hpp" #include "Common.hpp" #include "athena/MemoryReader.hpp" diff --git a/include/amuse/Common.hpp b/include/amuse/Common.hpp index 047ca95..971b137 100644 --- a/include/amuse/Common.hpp +++ b/include/amuse/Common.hpp @@ -65,6 +65,7 @@ ObjectIdDNA : BigDNA struct type : ObjectId \ { \ using ObjectId::ObjectId; \ + type() = default; \ type(const ObjectId& id) : ObjectId(id) {} \ static thread_local NameDB* CurNameDB; \ }; \ @@ -186,6 +187,7 @@ class ObjToken : public ObjTokenBase IObj*const& _obj() const { return ObjTokenBase::m_obj; } public: using ObjTokenBase::ObjTokenBase; + ObjToken() = default; ObjToken(ObjWrapper* obj) : ObjTokenBase(obj) {} ObjToken& operator=(ObjWrapper* obj) { if (_obj()) _obj()->decrement(); _obj() = obj; if (_obj()) _obj()->increment(); return *this; } @@ -201,6 +203,7 @@ class ObjToken IObj*const& _obj() const { return ObjTokenBase::m_obj; } public: using ObjTokenBase::ObjTokenBase; + ObjToken() = default; ObjToken(IObj* obj) : ObjTokenBase(obj) {} ObjToken& operator=(IObj* obj) { if (_obj()) _obj()->decrement(); _obj() = obj; if (_obj()) _obj()->increment(); return *this; } @@ -220,6 +223,7 @@ class IObjToken : public ObjTokenBase IObj*const& _obj() const { return ObjTokenBase::m_obj; } public: using ObjTokenBase::ObjTokenBase; + IObjToken() = default; IObjToken(IObj* obj) : ObjTokenBase(obj) {} IObjToken& operator=(IObj* obj) { if (_obj()) _obj()->decrement(); _obj() = obj; if (_obj()) _obj()->increment(); return *this; } diff --git a/include/amuse/Voice.hpp b/include/amuse/Voice.hpp index 6a49d41..df1512a 100644 --- a/include/amuse/Voice.hpp +++ b/include/amuse/Voice.hpp @@ -34,15 +34,15 @@ class Voice : public Entity friend struct SoundMacroState; friend class Envelope; friend class Emitter; - friend class SoundMacro::CmdScaleVolume; - friend class SoundMacro::CmdKeyOff; - friend class SoundMacro::CmdScaleVolumeDLS; - friend class SoundMacro::CmdReturn; - friend class SoundMacro::CmdGoSub; - friend class SoundMacro::CmdTrapEvent; - friend class SoundMacro::CmdUntrapEvent; - friend class SoundMacro::CmdGetMessage; - friend class SoundMacro::CmdModeSelect; + friend struct SoundMacro::CmdScaleVolume; + friend struct SoundMacro::CmdKeyOff; + friend struct SoundMacro::CmdScaleVolumeDLS; + friend struct SoundMacro::CmdReturn; + friend struct SoundMacro::CmdGoSub; + friend struct SoundMacro::CmdTrapEvent; + friend struct SoundMacro::CmdUntrapEvent; + friend struct SoundMacro::CmdGetMessage; + friend struct SoundMacro::CmdModeSelect; struct VolumeCache { diff --git a/lib/AudioGroup.cpp b/lib/AudioGroup.cpp index d0fbea4..1627b44 100644 --- a/lib/AudioGroup.cpp +++ b/lib/AudioGroup.cpp @@ -50,7 +50,7 @@ std::pair, const unsigned char*> const_cast(sample)->loadLooseData(basePath); return {sample->m_data, sample->m_data->m_looseData.get()}; } - return {{}, m_samp + sample->m_data->m_sampleOff}; + return std::make_pair(ObjToken(), m_samp + sample->m_data->m_sampleOff); } SampleFileState AudioGroup::getSampleFileState(SampleId sfxId, const SampleEntry* sample, SystemString* pathOut) const diff --git a/lib/AudioGroupSampleDirectory.cpp b/lib/AudioGroupSampleDirectory.cpp index b595b23..7081aaf 100644 --- a/lib/AudioGroupSampleDirectory.cpp +++ b/lib/AudioGroupSampleDirectory.cpp @@ -11,6 +11,8 @@ #include #ifndef _WIN32 #include +#else +#include #endif namespace amuse @@ -507,8 +509,13 @@ void AudioGroupSampleDirectory::EntryData::patchMetadataWAV(SystemStringView wav /* File timestamps reflect actual audio content, not loop/pitch data */ static void SetAudioFileTime(const SystemString& path, const Sstat& stat) { +#if _WIN32 + __utimbuf64 times = { stat.st_atime, stat.st_mtime }; + _wutime64(path.c_str(), ×); +#else struct timespec times[] = { stat.st_atim, stat.st_mtim }; utimensat(AT_FDCWD, path.c_str(), times, 0); +#endif } void AudioGroupSampleDirectory::Entry::patchSampleMetadata(SystemStringView basePath) const diff --git a/lib/DSPCodec.cpp b/lib/DSPCodec.cpp index 7a89839..9ada90f 100644 --- a/lib/DSPCodec.cpp +++ b/lib/DSPCodec.cpp @@ -1,4 +1,5 @@ #include "amuse/DSPCodec.hpp" +#include #undef min #undef max