diff --git a/Editor/ADSREditor.cpp b/Editor/ADSREditor.cpp new file mode 100644 index 0000000..00d7507 --- /dev/null +++ b/Editor/ADSREditor.cpp @@ -0,0 +1,7 @@ +#include "ADSREditor.hpp" + +ADSREditor::ADSREditor(ProjectModel::ADSRNode* node, QWidget* parent) +: EditorWidget(parent) +{ + +} diff --git a/Editor/ADSREditor.hpp b/Editor/ADSREditor.hpp new file mode 100644 index 0000000..ee866fc --- /dev/null +++ b/Editor/ADSREditor.hpp @@ -0,0 +1,14 @@ +#ifndef AMUSE_ADSR_EDITOR_HPP +#define AMUSE_ADSR_EDITOR_HPP + +#include "EditorWidget.hpp" + +class ADSREditor : public EditorWidget +{ +Q_OBJECT +public: + explicit ADSREditor(ProjectModel::ADSRNode* node, QWidget* parent = Q_NULLPTR); +}; + + +#endif //AMUSE_ADSR_EDITOR_HPP diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index 1d7379f..b706998 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -28,15 +28,17 @@ add_executable(amuse-gui WIN32 MACOSX_BUNDLE Common.hpp Common.cpp MainWindow.ui MainWindow.hpp MainWindow.cpp KeyboardWidget.hpp KeyboardWidget.cpp - StatusBarWidget.hpp StatusBarWidget.cpp + StatusBarWidget.hpp ProjectModel.hpp ProjectModel.cpp ProjectStatistics.hpp ProjectStatistics.cpp EditorWidget.hpp EditorWidget.cpp SoundMacroEditor.hpp SoundMacroEditor.cpp + ADSREditor.hpp ADSREditor.cpp + CurveEditor.hpp CurveEditor.cpp KeymapEditor.hpp KeymapEditor.cpp LayersEditor.hpp LayersEditor.cpp SampleEditor.hpp SampleEditor.cpp - SFXGroupEditor.hpp SFXGroupEditor.cpp + SoundGroupEditor.hpp SoundGroupEditor.cpp SongGroupEditor.hpp SongGroupEditor.cpp AudioGroupModel.hpp AudioGroupModel.cpp resources/resources.qrc qrc_resources.cpp diff --git a/Editor/CurveEditor.cpp b/Editor/CurveEditor.cpp new file mode 100644 index 0000000..63328c5 --- /dev/null +++ b/Editor/CurveEditor.cpp @@ -0,0 +1,7 @@ +#include "CurveEditor.hpp" + +CurveEditor::CurveEditor(ProjectModel::CurveNode* node, QWidget* parent) +: EditorWidget(parent) +{ + +} diff --git a/Editor/CurveEditor.hpp b/Editor/CurveEditor.hpp new file mode 100644 index 0000000..5f1f566 --- /dev/null +++ b/Editor/CurveEditor.hpp @@ -0,0 +1,14 @@ +#ifndef AMUSE_CURVE_EDITOR_HPP +#define AMUSE_CURVE_EDITOR_HPP + +#include "EditorWidget.hpp" + +class CurveEditor : public EditorWidget +{ +Q_OBJECT +public: + explicit CurveEditor(ProjectModel::CurveNode* node, QWidget* parent = Q_NULLPTR); +}; + + +#endif //AMUSE_CURVE_EDITOR_HPP diff --git a/Editor/EditorWidget.hpp b/Editor/EditorWidget.hpp index a356ea4..a3bef2f 100644 --- a/Editor/EditorWidget.hpp +++ b/Editor/EditorWidget.hpp @@ -2,12 +2,14 @@ #define AMUSE_EDITOR_WIDGET_HPP #include +#include "ProjectModel.hpp" class EditorWidget : public QWidget { Q_OBJECT public: explicit EditorWidget(QWidget* parent = Q_NULLPTR); + virtual bool valid() const { return true; } }; diff --git a/Editor/KeyboardWidget.cpp b/Editor/KeyboardWidget.cpp index d1842d2..3b382ad 100644 --- a/Editor/KeyboardWidget.cpp +++ b/Editor/KeyboardWidget.cpp @@ -1,7 +1,203 @@ #include "KeyboardWidget.hpp" +#include +#include +#include +#include + +/* Used for generating transform matrices to map coordinate space */ +static QTransform RectToRect(const QRectF& from, const QRectF& to) +{ + QPolygonF orig(from); + orig.pop_back(); + QPolygonF resize(to); + resize.pop_back(); + QTransform ret; + QTransform::quadToQuad(orig, resize, ret); + return ret; +} + +static const QString NaturalKeyNames[] = +{ + QStringLiteral("C"), + QStringLiteral("D"), + QStringLiteral("E"), + QStringLiteral("F"), + QStringLiteral("G"), + QStringLiteral("A"), + QStringLiteral("B") +}; + +static const QString SharpKeyNames[] = +{ + QStringLiteral("Cs"), + QStringLiteral("Ds"), + QStringLiteral("Fs"), + QStringLiteral("Gs"), + QStringLiteral("As") +}; + +static const QString KeyStrings[] = +{ + QStringLiteral("C"), + QStringLiteral("C#"), + QStringLiteral("D"), + QStringLiteral("D#"), + QStringLiteral("E"), + QStringLiteral("F"), + QStringLiteral("F#"), + QStringLiteral("G"), + QStringLiteral("G#"), + QStringLiteral("A"), + QStringLiteral("A#"), + QStringLiteral("B") +}; + +static const int NaturalKeyNumbers[] = +{ + 0, 2, 4, 5, 7, 9, 11 +}; + +static const int SharpKeyNumbers[] = +{ + 1, 3, 6, 8, 10 +}; + +KeyboardOctave::KeyboardOctave(int octave, const QString& svgPath, QWidget* parent) +: QSvgWidget(svgPath, parent), m_octave(octave) +{ + for (int i = 0; i < 7; ++i) + if (renderer()->elementExists(NaturalKeyNames[i])) + m_natural[i] = renderer()->matrixForElement(NaturalKeyNames[i]). + mapRect(renderer()->boundsOnElement(NaturalKeyNames[i])); + + for (int i = 0; i < 5; ++i) + if (renderer()->elementExists(SharpKeyNames[i])) + m_sharp[i] = renderer()->matrixForElement(SharpKeyNames[i]). + mapRect(renderer()->boundsOnElement(SharpKeyNames[i])); + + /* The parent keyboard manages all mouse events */ + setAttribute(Qt::WA_TransparentForMouseEvents); +} + +int KeyboardOctave::getKey(const QPoint& localPos) const +{ + QPointF localPoint = m_widgetToSvg.map(localPos); + for (int i = 0; i < 5; ++i) + if (m_sharp[i].contains(localPoint)) + return SharpKeyNumbers[i]; + for (int i = 0; i < 7; ++i) + if (m_natural[i].contains(localPoint)) + return NaturalKeyNumbers[i]; + return -1; +} + +void KeyboardOctave::resizeEvent(QResizeEvent *event) +{ + m_widgetToSvg = RectToRect(rect(), renderer()->viewBoxF()); +} KeyboardWidget::KeyboardWidget(QWidget* parent) : QWidget(parent) { + QHBoxLayout* layout = new QHBoxLayout(this); + layout->setContentsMargins(QMargins()); + layout->setSpacing(0); + for (int i = 0; i < 10; ++i) + { + m_widgets[i] = new KeyboardOctave(i, QStringLiteral(":/bg/keyboard.svg"), this); + m_widgets[i]->setGeometry(QRect(0, 0, 141, 50)); + m_widgets[i]->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred)); + layout->addWidget(m_widgets[i]); + } + + m_widgets[10] = new KeyboardOctave(10, QStringLiteral(":/bg/keyboard_last.svg"), this); + m_widgets[10]->setGeometry(QRect(0, 0, 101, 50)); + m_widgets[10]->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred)); + layout->addWidget(m_widgets[10]); + + setLayout(layout); + setMouseTracking(true); +} + +std::pair KeyboardWidget::_getOctaveAndKey(QMouseEvent* event) const +{ + for (KeyboardOctave* oct : m_widgets) + { + QPoint localPos = oct->mapFromParent(event->pos()); + if (oct->rect().contains(localPos)) + return {oct->getOctave(), oct->getKey(localPos)}; + } + return {-1, -1}; +} + +void KeyboardWidget::_startKey(int octave, int key) +{ + printf("START %d %d\n", octave, key); +} + +void KeyboardWidget::_stopKey() +{ + printf("STOP\n"); +} + +void KeyboardWidget::_moveOnKey(int octave, int key) +{ + if (m_lastOctave != octave || m_lastKey != key) + { + m_lastOctave = octave; + m_lastKey = key; + if (m_statusFocus) + m_statusFocus->setMessage(QStringLiteral("%1%2").arg(KeyStrings[key]).arg(octave - 1)); + if (m_holding) + _startKey(octave, key); + } +} + +void KeyboardWidget::_pressOnKey(int octave, int key) +{ + _moveOnKey(octave, key); + m_holding = true; + _startKey(octave, key); +} + +void KeyboardWidget::mouseMoveEvent(QMouseEvent* event) +{ + std::pair ok = _getOctaveAndKey(event); + if (ok.first != -1 && ok.second != -1) + _moveOnKey(ok.first, ok.second); +} + +void KeyboardWidget::mousePressEvent(QMouseEvent* event) +{ + std::pair ok = _getOctaveAndKey(event); + if (ok.first != -1 && ok.second != -1) + _pressOnKey(ok.first, ok.second); +} + +void KeyboardWidget::mouseReleaseEvent(QMouseEvent* event) +{ + _stopKey(); + m_holding = false; +} + +void KeyboardWidget::enterEvent(QEvent* event) +{ + if (m_statusFocus) + m_statusFocus->enter(); +} + +void KeyboardWidget::leaveEvent(QEvent* event) +{ + if (m_statusFocus) + m_statusFocus->exit(); +} + +void KeyboardWidget::showEvent(QShowEvent* event) +{ + if (QScrollArea* scroll = qobject_cast(parentWidget()->parentWidget())) + { + /* Scroll to C3 */ + scroll->ensureVisible(141 * 4 + scroll->width(), 0, 0, 0); + } } diff --git a/Editor/KeyboardWidget.hpp b/Editor/KeyboardWidget.hpp index 06456e0..9627b93 100644 --- a/Editor/KeyboardWidget.hpp +++ b/Editor/KeyboardWidget.hpp @@ -2,12 +2,50 @@ #define AMUSE_KEYBOARD_WIDGET_HPP #include +#include +#include "StatusBarWidget.hpp" + +class KeyboardWidget; + +class KeyboardOctave : public QSvgWidget +{ + Q_OBJECT + int m_octave; + QRectF m_natural[7]; + QRectF m_sharp[5]; + QTransform m_widgetToSvg; +public: + explicit KeyboardOctave(int octave, const QString& svgPath, QWidget* parent = Q_NULLPTR); + int getOctave() const { return m_octave; } + int getKey(const QPoint& localPos) const; + void resizeEvent(QResizeEvent *event); +}; class KeyboardWidget : public QWidget { Q_OBJECT + KeyboardOctave* m_widgets[11]; + StatusBarFocus* m_statusFocus = nullptr; + int m_lastOctave = -1; + int m_lastKey = -1; + bool m_holding = false; + + std::pair _getOctaveAndKey(QMouseEvent* event) const; + void _startKey(int octave, int key); + void _stopKey(); + void _moveOnKey(int octave, int key); + void _pressOnKey(int octave, int key); + public: explicit KeyboardWidget(QWidget* parent = Q_NULLPTR); + void setStatusFocus(StatusBarFocus* statusFocus) { m_statusFocus = statusFocus; } + + void mouseMoveEvent(QMouseEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + void enterEvent(QEvent* event); + void leaveEvent(QEvent* event); + void showEvent(QShowEvent *event); }; diff --git a/Editor/KeymapEditor.cpp b/Editor/KeymapEditor.cpp index 67f9765..d85f68a 100644 --- a/Editor/KeymapEditor.cpp +++ b/Editor/KeymapEditor.cpp @@ -1,6 +1,6 @@ #include "KeymapEditor.hpp" -KeymapEditor::KeymapEditor(QWidget* parent) +KeymapEditor::KeymapEditor(ProjectModel::KeymapNode* node, QWidget* parent) : EditorWidget(parent) { diff --git a/Editor/KeymapEditor.hpp b/Editor/KeymapEditor.hpp index f7170e7..5eeecb0 100644 --- a/Editor/KeymapEditor.hpp +++ b/Editor/KeymapEditor.hpp @@ -7,7 +7,7 @@ class KeymapEditor : public EditorWidget { Q_OBJECT public: - explicit KeymapEditor(QWidget* parent = Q_NULLPTR); + explicit KeymapEditor(ProjectModel::KeymapNode* node, QWidget* parent = Q_NULLPTR); }; diff --git a/Editor/LayersEditor.cpp b/Editor/LayersEditor.cpp index a89999d..53e1ed1 100644 --- a/Editor/LayersEditor.cpp +++ b/Editor/LayersEditor.cpp @@ -1,6 +1,6 @@ #include "LayersEditor.hpp" -LayersEditor::LayersEditor(QWidget* parent) +LayersEditor::LayersEditor(ProjectModel::LayersNode* node, QWidget* parent) : EditorWidget(parent) { diff --git a/Editor/LayersEditor.hpp b/Editor/LayersEditor.hpp index 89b9f9e..080b3a6 100644 --- a/Editor/LayersEditor.hpp +++ b/Editor/LayersEditor.hpp @@ -7,7 +7,7 @@ class LayersEditor : public EditorWidget { Q_OBJECT public: - explicit LayersEditor(QWidget* parent = Q_NULLPTR); + explicit LayersEditor(ProjectModel::LayersNode* node, QWidget* parent = Q_NULLPTR); }; diff --git a/Editor/MainWindow.cpp b/Editor/MainWindow.cpp index ded9bc0..fbe8302 100644 --- a/Editor/MainWindow.cpp +++ b/Editor/MainWindow.cpp @@ -4,9 +4,18 @@ #include #include #include +#include #include #include "amuse/ContainerRegistry.hpp" #include "Common.hpp" +#include "SongGroupEditor.hpp" +#include "SoundGroupEditor.hpp" +#include "SoundGroupEditor.hpp" +#include "SoundMacroEditor.hpp" +#include "ADSREditor.hpp" +#include "CurveEditor.hpp" +#include "KeymapEditor.hpp" +#include "LayersEditor.hpp" static void connectMessenger(UIMessenger* messenger, Qt::ConnectionType type) { @@ -15,6 +24,7 @@ static void connectMessenger(UIMessenger* messenger, Qt::ConnectionType type) MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), + m_treeDelegate(*this, this), m_mainMessenger(this), m_undoStack(new QUndoStack(this)), m_backgroundThread(this) @@ -22,8 +32,11 @@ MainWindow::MainWindow(QWidget* parent) m_backgroundThread.start(); m_ui.setupUi(this); + m_ui.projectOutline->setItemDelegate(&m_treeDelegate); connectMessenger(&m_mainMessenger, Qt::DirectConnection); + m_ui.keyboardContents->setStatusFocus(new StatusBarFocus(m_ui.statusbar)); + m_ui.actionNew_Project->setShortcut(QKeySequence::New); connect(m_ui.actionNew_Project, SIGNAL(triggered()), this, SLOT(newAction())); m_ui.actionOpen_Project->setShortcut(QKeySequence::Open); @@ -45,11 +58,21 @@ MainWindow::MainWindow(QWidget* parent) m_ui.actionDelete->setShortcut(QKeySequence::Delete); onFocusChanged(nullptr, this); - m_ui.editorSvg->load(QStringLiteral(":/bg/FaceGrey.svg")); + QGridLayout* faceLayout = new QGridLayout; + QSvgWidget* faceSvg = new QSvgWidget(QStringLiteral(":/bg/FaceGrey.svg")); + faceSvg->setGeometry(0, 0, 256, 256); + faceSvg->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + faceLayout->addWidget(faceSvg); + m_faceSvg = new QWidget; + m_faceSvg->setLayout(faceLayout); + m_ui.editorContents->addWidget(m_faceSvg); + connect(m_ui.actionNew_Subproject, SIGNAL(triggered()), this, SLOT(newSubprojectAction())); connect(m_ui.actionNew_SFX_Group, SIGNAL(triggered()), this, SLOT(newSFXGroupAction())); connect(m_ui.actionNew_Song_Group, SIGNAL(triggered()), this, SLOT(newSongGroupAction())); connect(m_ui.actionNew_Sound_Macro, SIGNAL(triggered()), this, SLOT(newSoundMacroAction())); + connect(m_ui.actionNew_ADSR, SIGNAL(triggered()), this, SLOT(newADSRAction())); + connect(m_ui.actionNew_Curve, SIGNAL(triggered()), this, SLOT(newCurveAction())); connect(m_ui.actionNew_Keymap, SIGNAL(triggered()), this, SLOT(newKeymapAction())); connect(m_ui.actionNew_Layers, SIGNAL(triggered()), this, SLOT(newLayersAction())); @@ -128,6 +151,9 @@ bool MainWindow::setProjectPath(const QString& path) m_ui.projectOutline->setModel(m_projectModel); m_ui.actionExport_GameCube_Groups->setEnabled(true); setWindowFilePath(path); +#ifndef __APPLE__ + setWindowTitle(QString("Amuse - %1").arg(dir.dirName())); +#endif setFocusAudioGroup(nullptr); onFocusChanged(nullptr, focusWidget()); @@ -217,6 +243,88 @@ void MainWindow::startBackgroundTask(const QString& windowTitle, const QString& QMetaObject::invokeMethod(m_backgroundTask, "run", Qt::QueuedConnection); } +bool MainWindow::_setEditor(EditorWidget* editor) +{ + while (m_ui.editorContents->currentWidget() != m_faceSvg) + { + m_ui.editorContents->currentWidget()->deleteLater(); + m_ui.editorContents->removeWidget(m_ui.editorContents->currentWidget()); + } + if (!editor) + return false; + if (!editor->valid()) + { + editor->deleteLater(); + return false; + } + m_ui.editorContents->addWidget(editor); + m_ui.editorContents->setCurrentWidget(editor); + return true; +} + +bool MainWindow::openEditor(ProjectModel::SongGroupNode* node) +{ + return _setEditor(new SongGroupEditor(node)); +} + +bool MainWindow::openEditor(ProjectModel::SoundGroupNode* node) +{ + return _setEditor(new SoundGroupEditor(node)); +} + +bool MainWindow::openEditor(ProjectModel::SoundMacroNode* node) +{ + return _setEditor(new SoundMacroEditor(node)); +} + +bool MainWindow::openEditor(ProjectModel::ADSRNode* node) +{ + return _setEditor(new ADSREditor(node)); +} + +bool MainWindow::openEditor(ProjectModel::CurveNode* node) +{ + return _setEditor(new CurveEditor(node)); +} + +bool MainWindow::openEditor(ProjectModel::KeymapNode* node) +{ + return _setEditor(new KeymapEditor(node)); +} + +bool MainWindow::openEditor(ProjectModel::LayersNode* node) +{ + return _setEditor(new LayersEditor(node)); +} + +bool MainWindow::openEditor(ProjectModel::INode* node) +{ + switch (node->type()) + { + case ProjectModel::INode::Type::SongGroup: + return openEditor(static_cast(node)); + case ProjectModel::INode::Type::SoundGroup: + return openEditor(static_cast(node)); + case ProjectModel::INode::Type::SoundMacro: + return openEditor(static_cast(node)); + case ProjectModel::INode::Type::ADSR: + return openEditor(static_cast(node)); + case ProjectModel::INode::Type::Curve: + return openEditor(static_cast(node)); + case ProjectModel::INode::Type::Keymap: + return openEditor(static_cast(node)); + case ProjectModel::INode::Type::Layer: + return openEditor(static_cast(node)); + default: + return false; + } +} + +void MainWindow::closeEditor() +{ + _setEditor(nullptr); +} + void MainWindow::newAction() { QString path = QFileDialog::getSaveFileName(this, tr("New Project")); @@ -226,6 +334,9 @@ void MainWindow::newAction() return; if (!setProjectPath(path)) return; + + m_projectModel->clearProjectData(); + m_projectModel->ensureModelData(); } void MainWindow::openAction() @@ -233,10 +344,41 @@ void MainWindow::openAction() QString path = QFileDialog::getExistingDirectory(this, tr("Open Project")); if (path.isEmpty()) return; + + QDir dir(path); + if (!dir.exists()) + { + QString msg = QString(tr("The directory at '%1' does not exist.")).arg(path); + QMessageBox::critical(this, tr("Bad Directory"), msg); + return; + } + + if (QFileInfo(dir, QStringLiteral("!project.yaml")).exists() && + QFileInfo(dir, QStringLiteral("!pool.yaml")).exists()) + dir.cdUp(); + if (!setProjectPath(path)) return; - + ProjectModel* model = m_projectModel; + startBackgroundTask(tr("Opening"), tr("Scanning Project"), + [dir, model](BackgroundTask& task) + { + QStringList childDirs = dir.entryList(QDir::Dirs); + for (const auto& chDir : childDirs) + { + if (task.isCanceled()) + return; + QString chPath = dir.filePath(chDir); + if (QFileInfo(chPath, QStringLiteral("!project.yaml")).exists() && + QFileInfo(chPath, QStringLiteral("!pool.yaml")).exists()) + { + task.setLabelText(tr("Opening %1").arg(chDir)); + if (!model->openGroupData(chDir, task.uiMessenger())) + return; + } + } + }); } void MainWindow::importAction() @@ -372,6 +514,33 @@ void MainWindow::exportAction() } +bool TreeDelegate::editorEvent(QEvent* event, + QAbstractItemModel* _model, + const QStyleOptionViewItem& option, + const QModelIndex& index) +{ + ProjectModel* model = static_cast(_model); + ProjectModel::INode* node = model->node(index); + if (!node) + return false; + + if ((event->type() == QEvent::MouseButtonDblClick && + static_cast(event)->button() == Qt::LeftButton) || + (event->type() == QEvent::KeyPress && + static_cast(event)->key() == Qt::Key_Enter)) + { + // Open in editor + return m_window.openEditor(node); + } + + return false; +} + +void MainWindow::newSubprojectAction() +{ + +} + void MainWindow::newSFXGroupAction() { @@ -387,6 +556,16 @@ void MainWindow::newSoundMacroAction() } +void MainWindow::newADSRAction() +{ + +} + +void MainWindow::newCurveAction() +{ + +} + void MainWindow::newKeymapAction() { diff --git a/Editor/MainWindow.hpp b/Editor/MainWindow.hpp index 84cf248..0b259d7 100644 --- a/Editor/MainWindow.hpp +++ b/Editor/MainWindow.hpp @@ -5,16 +5,19 @@ #include #include #include +#include #include "ui_MainWindow.h" #include "amuse/Engine.hpp" #include "amuse/BooBackend.hpp" #include "boo/audiodev/IAudioVoiceEngine.hpp" #include "ProjectModel.hpp" +#include "EditorWidget.hpp" namespace Ui { class MainWindow; } +class MainWindow; class AudioGroupModel; class BackgroundTask : public QObject @@ -41,13 +44,29 @@ public slots: void cancel() { m_cancelled = true; } }; +class TreeDelegate : public QStyledItemDelegate +{ + Q_OBJECT + MainWindow& m_window; +public: + explicit TreeDelegate(MainWindow& window, QObject* parent = Q_NULLPTR) + : QStyledItemDelegate(parent), m_window(window) {} + + bool editorEvent(QEvent *event, + QAbstractItemModel *model, + const QStyleOptionViewItem &option, + const QModelIndex &index); +}; + class MainWindow : public QMainWindow { Q_OBJECT Ui::MainWindow m_ui; + TreeDelegate m_treeDelegate; UIMessenger m_mainMessenger; ProjectModel* m_projectModel = nullptr; AudioGroupModel* m_focusAudioGroup = nullptr; + QWidget* m_faceSvg; std::unique_ptr m_voxEngine; std::unique_ptr m_voxAllocator; @@ -79,19 +98,34 @@ class MainWindow : public QMainWindow void startBackgroundTask(const QString& windowTitle, const QString& label, std::function&& task); + bool _setEditor(EditorWidget* widget); + public: explicit MainWindow(QWidget* parent = Q_NULLPTR); ~MainWindow(); + bool openEditor(ProjectModel::SongGroupNode* node); + bool openEditor(ProjectModel::SoundGroupNode* node); + bool openEditor(ProjectModel::SoundMacroNode* node); + bool openEditor(ProjectModel::ADSRNode* node); + bool openEditor(ProjectModel::CurveNode* node); + bool openEditor(ProjectModel::KeymapNode* node); + bool openEditor(ProjectModel::LayersNode* node); + bool openEditor(ProjectModel::INode* node); + void closeEditor(); + public slots: void newAction(); void openAction(); void importAction(); void exportAction(); + void newSubprojectAction(); void newSFXGroupAction(); void newSongGroupAction(); void newSoundMacroAction(); + void newADSRAction(); + void newCurveAction(); void newKeymapAction(); void newLayersAction(); diff --git a/Editor/MainWindow.ui b/Editor/MainWindow.ui index c916b8e..f368b5d 100644 --- a/Editor/MainWindow.ui +++ b/Editor/MainWindow.ui @@ -35,41 +35,25 @@ Qt::Horizontal - - - Qt::Vertical + + + + 0 + 3 + - - - - 0 - 3 - - - - - 200 - 0 - - - - false - - - - - - 0 - 2 - - - - - 200 - 0 - - - + + + 200 + 0 + + + + true + + + false + @@ -109,7 +93,7 @@ true - + 0 @@ -118,24 +102,6 @@ 442 - - - - - - 0 - 0 - - - - - 256 - 256 - - - - - @@ -174,10 +140,22 @@ 0 0 - 540 - 100 + 1501 + 85 + + + 0 + 0 + + + + + 1501 + 0 + + 16777215 @@ -213,10 +191,14 @@ P&roject + + + + @@ -418,6 +400,42 @@ Ctrl+E + + + false + + + + :/icons/IconNewGroup.svg:/icons/IconNewGroup.svg + + + N&ew Subproject + + + + + false + + + + :/icons/IconNewADSR.svg:/icons/IconNewADSR.svg + + + Ne&w ADSR + + + + + false + + + + :/icons/IconNewCurve.svg:/icons/IconNewCurve.svg + + + New &Curve + + @@ -431,12 +449,6 @@ QStatusBar
StatusBarWidget.hpp
- - QSvgWidget - QWidget -
QSvgWidget
- 1 -
diff --git a/Editor/ProjectModel.cpp b/Editor/ProjectModel.cpp index a26b439..f0498dd 100644 --- a/Editor/ProjectModel.cpp +++ b/Editor/ProjectModel.cpp @@ -18,6 +18,25 @@ ProjectModel::ProjectModel(const QString& path, QObject* parent) SoundGroupNode::Icon = QIcon(":/icons/IconSoundGroup.svg"); } +bool ProjectModel::clearProjectData() +{ + m_projectDatabase = amuse::ProjectDatabase(); + m_groups.clear(); + + m_needsReset = true; + return true; +} + +bool ProjectModel::openGroupData(const QString& groupName, UIMessenger& messenger) +{ + m_projectDatabase.setIdDatabases(); + QString path = QFileInfo(m_dir, groupName).filePath(); + m_groups.insert(std::make_pair(groupName, QStringToSysString(path))); + + m_needsReset = true; + return true; +} + bool ProjectModel::importGroupData(const QString& groupName, const amuse::AudioGroupData& data, ImportMode mode, UIMessenger& messenger) { @@ -89,12 +108,13 @@ void ProjectModel::_resetModelData() { it->second.setIdDatabases(); GroupNode& gn = m_root->makeChild(it); - auto& songGroups = it->second.getProj().songGroups(); - auto& sfxGroups = it->second.getProj().sfxGroups(); - auto& soundMacros = it->second.getPool().soundMacros(); - auto& tables = it->second.getPool().tables(); - auto& keymaps = it->second.getPool().keymaps(); - auto& layers = it->second.getPool().layers(); + amuse::AudioGroup& group = it->second; + auto& songGroups = group.getProj().songGroups(); + auto& sfxGroups = group.getProj().sfxGroups(); + auto& soundMacros = group.getPool().soundMacros(); + auto& tables = group.getPool().tables(); + auto& keymaps = group.getPool().keymaps(); + auto& layers = group.getPool().layers(); gn.reserve(songGroups.size() + sfxGroups.size() + 4); for (const auto& grp : SortUnorderedMap(songGroups)) gn.makeChild(grp.first, grp.second.get()); @@ -106,7 +126,7 @@ void ProjectModel::_resetModelData() gn.makeChild(tr("Sound Macros"), QIcon(":/icons/IconSoundMacro.svg")); col.reserve(soundMacros.size()); for (const auto& macro : SortUnorderedMap(soundMacros)) - col.makeChild>(macro.first, macro.second.get()); + col.makeChild(macro.first, macro.second.get()); } if (tables.size()) { @@ -130,7 +150,7 @@ void ProjectModel::_resetModelData() { amuse::ITable::Type tp = t.second.get()->Isa(); if (tp == amuse::ITable::Type::ADSR || tp == amuse::ITable::Type::ADSRDLS) - col.makeChild>(t.first, *t.second.get()); + col.makeChild(t.first, *t.second.get()); } } if (curveCount) @@ -142,7 +162,7 @@ void ProjectModel::_resetModelData() { amuse::ITable::Type tp = t.second.get()->Isa(); if (tp == amuse::ITable::Type::Curve) - col.makeChild>(t.first, static_cast(*t.second.get())); + col.makeChild(t.first, static_cast(*t.second.get())); } } } @@ -152,7 +172,7 @@ void ProjectModel::_resetModelData() gn.makeChild(tr("Keymaps"), QIcon(":/icons/IconKeymap.svg")); col.reserve(keymaps.size()); for (auto& keymap : SortUnorderedMap(keymaps)) - col.makeChild>(keymap.first, keymap.second.get()); + col.makeChild(keymap.first, keymap.second.get()); } if (layers.size()) { @@ -160,7 +180,7 @@ void ProjectModel::_resetModelData() gn.makeChild(tr("Layers"), QIcon(":/icons/IconLayers.svg")); col.reserve(layers.size()); for (auto& keymap : SortUnorderedMap(layers)) - col.makeChild>>(keymap.first, keymap.second.get()); + col.makeChild(keymap.first, keymap.second.get()); } } endResetModel(); @@ -250,6 +270,13 @@ Qt::ItemFlags ProjectModel::flags(const QModelIndex& index) const return QAbstractItemModel::flags(index); } +ProjectModel::INode* ProjectModel::node(const QModelIndex& index) const +{ + if (!index.isValid()) + return nullptr; + return static_cast(index.internalPointer()); +} + bool ProjectModel::canDelete() const { return false; diff --git a/Editor/ProjectModel.hpp b/Editor/ProjectModel.hpp index b5065f7..4564a66 100644 --- a/Editor/ProjectModel.hpp +++ b/Editor/ProjectModel.hpp @@ -29,13 +29,16 @@ private: amuse::ProjectDatabase m_projectDatabase; std::map m_groups; +public: class INode { + public: enum class Type { + Root, Group, // Top-level group SongGroup, - SfxGroup, + SoundGroup, Collection, // Classified object collection, one of the following: SoundMacro, ADSR, @@ -43,6 +46,7 @@ private: Keymap, Layer }; + private: INode* m_parent; std::vector> m_children; int m_row; @@ -63,6 +67,7 @@ private: return static_cast(*m_children.back()); } + virtual Type type() const = 0; virtual QString text() const = 0; virtual QIcon icon() const = 0; }; @@ -70,6 +75,7 @@ private: { RootNode() : INode(nullptr, 0) {} + Type type() const { return Type::Root; } QString text() const { return {}; } QIcon icon() const { return {}; } }; @@ -80,6 +86,7 @@ private: : INode(parent, row), m_it(it) {} static QIcon Icon; + Type type() const { return Type::Group; } QString text() const { return m_it->first; } QIcon icon() const { return Icon; } }; @@ -92,6 +99,7 @@ private: : INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {} static QIcon Icon; + Type type() const { return Type::SongGroup; } QString text() const { return m_name; } QIcon icon() const { return Icon; } }; @@ -104,6 +112,7 @@ private: : INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {} static QIcon Icon; + Type type() const { return Type::SoundGroup; } QString text() const { return m_name; } QIcon icon() const { return Icon; } }; @@ -114,10 +123,11 @@ private: CollectionNode(INode* parent, int row, const QString& name, const QIcon& icon) : INode(parent, row), m_name(name), m_icon(icon) {} + Type type() const { return Type::Collection; } QString text() const { return m_name; } QIcon icon() const { return m_icon; } }; - template + template struct PoolObjectNode : INode { ID m_id; @@ -126,9 +136,15 @@ private: PoolObjectNode(INode* parent, int row, ID id, T& obj) : INode(parent, row), m_id(id), m_name(ID::CurNameDB->resolveNameFromId(id).data()), m_obj(obj) {} + Type type() const { return TP; } QString text() const { return m_name; } QIcon icon() const { return {}; } }; + using SoundMacroNode = PoolObjectNode; + using ADSRNode = PoolObjectNode; + using CurveNode = PoolObjectNode; + using KeymapNode = PoolObjectNode; + using LayersNode = PoolObjectNode, INode::Type::Layer>; std::unique_ptr m_root; @@ -138,6 +154,8 @@ private: public: explicit ProjectModel(const QString& path, QObject* parent = Q_NULLPTR); + bool clearProjectData(); + bool openGroupData(const QString& groupName, UIMessenger& messenger); bool importGroupData(const QString& groupName, const amuse::AudioGroupData& data, ImportMode mode, UIMessenger& messenger); bool saveToFile(UIMessenger& messenger); @@ -150,6 +168,7 @@ public: int columnCount(const QModelIndex& parent = QModelIndex()) const; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; Qt::ItemFlags flags(const QModelIndex& index) const; + INode* node(const QModelIndex& index) const; QString path() const { return m_dir.path(); } bool canDelete() const; diff --git a/Editor/SFXGroupEditor.cpp b/Editor/SFXGroupEditor.cpp deleted file mode 100644 index db897c9..0000000 --- a/Editor/SFXGroupEditor.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "SFXGroupEditor.hpp" - -SFXGroupEditor::SFXGroupEditor(QWidget* parent) -: EditorWidget(parent) -{ - -} diff --git a/Editor/SFXGroupEditor.hpp b/Editor/SFXGroupEditor.hpp deleted file mode 100644 index 246087f..0000000 --- a/Editor/SFXGroupEditor.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef AMUSE_SFX_GROUP_EDITOR_HPP -#define AMUSE_SFX_GROUP_EDITOR_HPP - -#include "EditorWidget.hpp" - -class SFXGroupEditor : public EditorWidget -{ - Q_OBJECT -public: - explicit SFXGroupEditor(QWidget* parent = Q_NULLPTR); -}; - - -#endif //AMUSE_SFX_GROUP_EDITOR_HPP diff --git a/Editor/SongGroupEditor.cpp b/Editor/SongGroupEditor.cpp index 31c5124..819fd6d 100644 --- a/Editor/SongGroupEditor.cpp +++ b/Editor/SongGroupEditor.cpp @@ -1,6 +1,6 @@ #include "SongGroupEditor.hpp" -SongGroupEditor::SongGroupEditor(QWidget* parent) +SongGroupEditor::SongGroupEditor(ProjectModel::SongGroupNode* node, QWidget* parent) : EditorWidget(parent) { diff --git a/Editor/SongGroupEditor.hpp b/Editor/SongGroupEditor.hpp index 5206a16..f4af01f 100644 --- a/Editor/SongGroupEditor.hpp +++ b/Editor/SongGroupEditor.hpp @@ -7,7 +7,7 @@ class SongGroupEditor : public EditorWidget { Q_OBJECT public: - explicit SongGroupEditor(QWidget* parent = Q_NULLPTR); + explicit SongGroupEditor(ProjectModel::SongGroupNode* node, QWidget* parent = Q_NULLPTR); }; diff --git a/Editor/SoundGroupEditor.cpp b/Editor/SoundGroupEditor.cpp new file mode 100644 index 0000000..dec851d --- /dev/null +++ b/Editor/SoundGroupEditor.cpp @@ -0,0 +1,7 @@ +#include "SoundGroupEditor.hpp" + +SoundGroupEditor::SoundGroupEditor(ProjectModel::SoundGroupNode* node, QWidget* parent) +: EditorWidget(parent) +{ + +} diff --git a/Editor/SoundGroupEditor.hpp b/Editor/SoundGroupEditor.hpp new file mode 100644 index 0000000..906728f --- /dev/null +++ b/Editor/SoundGroupEditor.hpp @@ -0,0 +1,14 @@ +#ifndef AMUSE_SOUND_GROUP_EDITOR_HPP +#define AMUSE_SOUND_GROUP_EDITOR_HPP + +#include "EditorWidget.hpp" + +class SoundGroupEditor : public EditorWidget +{ + Q_OBJECT +public: + explicit SoundGroupEditor(ProjectModel::SoundGroupNode* node, QWidget* parent = Q_NULLPTR); +}; + + +#endif //AMUSE_SOUND_GROUP_EDITOR_HPP diff --git a/Editor/SoundMacroEditor.cpp b/Editor/SoundMacroEditor.cpp index 7e3fd12..825ce53 100644 --- a/Editor/SoundMacroEditor.cpp +++ b/Editor/SoundMacroEditor.cpp @@ -1,7 +1,10 @@ #include "SoundMacroEditor.hpp" +#include -SoundMacroEditor::SoundMacroEditor(QWidget* parent) +SoundMacroEditor::SoundMacroEditor(ProjectModel::SoundMacroNode* node, QWidget* parent) : EditorWidget(parent) { - + QLabel* lab = new QLabel; + lab->setText(node->m_name); + lab->setParent(this); } diff --git a/Editor/SoundMacroEditor.hpp b/Editor/SoundMacroEditor.hpp index 0388e8c..493b067 100644 --- a/Editor/SoundMacroEditor.hpp +++ b/Editor/SoundMacroEditor.hpp @@ -7,7 +7,7 @@ class SoundMacroEditor : public EditorWidget { Q_OBJECT public: - explicit SoundMacroEditor(QWidget* parent = Q_NULLPTR); + explicit SoundMacroEditor(ProjectModel::SoundMacroNode* node, QWidget* parent = Q_NULLPTR); }; diff --git a/Editor/StatusBarWidget.cpp b/Editor/StatusBarWidget.cpp deleted file mode 100644 index 0f02b87..0000000 --- a/Editor/StatusBarWidget.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "StatusBarWidget.hpp" - -StatusBarWidget::StatusBarWidget(QWidget* parent) -: QStatusBar(parent) -{ - -} diff --git a/Editor/StatusBarWidget.hpp b/Editor/StatusBarWidget.hpp index e79525b..b3930ea 100644 --- a/Editor/StatusBarWidget.hpp +++ b/Editor/StatusBarWidget.hpp @@ -2,13 +2,65 @@ #define AMUSE_STATUSBAR_WIDGET_HPP #include +#include + +class StatusBarFocus; class StatusBarWidget : public QStatusBar { + friend class StatusBarFocus; Q_OBJECT + QLabel* m_normalMessage; + StatusBarFocus* m_curFocus = nullptr; public: - explicit StatusBarWidget(QWidget* parent = Q_NULLPTR); + explicit StatusBarWidget(QWidget* parent = Q_NULLPTR) : QStatusBar(parent) {} + void setNormalMessage(const QString& message) { m_normalMessage->setText(message); } }; +class StatusBarFocus : public QObject +{ +Q_OBJECT + QString m_message; +public: + explicit StatusBarFocus(StatusBarWidget* statusWidget) + : QObject(statusWidget) {} + ~StatusBarFocus() { exit(); } + void setMessage(const QString& message) + { + m_message = message; + if (StatusBarWidget* widget = qobject_cast(parent())) + { + if (widget->m_curFocus == this) + { + if (m_message.isEmpty()) + widget->clearMessage(); + else + widget->showMessage(m_message); + } + } + } + void enter() + { + if (StatusBarWidget* widget = qobject_cast(parent())) + { + widget->m_curFocus = this; + if (m_message.isEmpty()) + widget->clearMessage(); + else + widget->showMessage(m_message); + } + } + void exit() + { + if (StatusBarWidget* widget = qobject_cast(parent())) + { + if (widget->m_curFocus == this) + { + widget->clearMessage(); + widget->m_curFocus = nullptr; + } + } + } +}; #endif //AMUSE_STATUSBAR_WIDGET_HPP diff --git a/Editor/resources/keyboard.svg b/Editor/resources/keyboard.svg new file mode 100644 index 0000000..8c18859 --- /dev/null +++ b/Editor/resources/keyboard.svg @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/Editor/resources/keyboard_last.svg b/Editor/resources/keyboard_last.svg new file mode 100644 index 0000000..fad3489 --- /dev/null +++ b/Editor/resources/keyboard_last.svg @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/Editor/resources/resources.qrc b/Editor/resources/resources.qrc index b23dbdc..ef42ba9 100644 --- a/Editor/resources/resources.qrc +++ b/Editor/resources/resources.qrc @@ -22,5 +22,7 @@ FaceGrey.svg + keyboard.svg + keyboard_last.svg diff --git a/include/amuse/AudioGroup.hpp b/include/amuse/AudioGroup.hpp index ae17471..3bd24f6 100644 --- a/include/amuse/AudioGroup.hpp +++ b/include/amuse/AudioGroup.hpp @@ -21,8 +21,12 @@ class AudioGroup public: operator bool() const { return m_valid; } - explicit AudioGroup(const AudioGroupData& data); - explicit AudioGroup(SystemStringView groupPath); + AudioGroup() = default; + explicit AudioGroup(const AudioGroupData& data) { assign(data); } + explicit AudioGroup(SystemStringView groupPath) { assign(groupPath); } + + void assign(const AudioGroupData& data); + void assign(SystemStringView groupPath); const AudioGroupSampleDirectory::Entry* getSample(SampleId sfxId) const; const unsigned char* getSampleData(SampleId sfxId, const AudioGroupSampleDirectory::Entry* sample) const; @@ -43,10 +47,16 @@ class AudioGroupDatabase : public AudioGroup amuse::NameDB m_layersDb; public: + AudioGroupDatabase() = default; explicit AudioGroupDatabase(const AudioGroupData& data) - : AudioGroup(data) {} + { + assign(data); + } explicit AudioGroupDatabase(SystemStringView groupPath) - : AudioGroup(groupPath) {} + { + setIdDatabases(); + assign(groupPath); + } void setIdDatabases() { diff --git a/include/amuse/AudioGroupPool.hpp b/include/amuse/AudioGroupPool.hpp index 2ef4fa4..fd28749 100644 --- a/include/amuse/AudioGroupPool.hpp +++ b/include/amuse/AudioGroupPool.hpp @@ -118,6 +118,7 @@ struct SoundMacro MulVars, DivVars, AddIVars, + SetVar, IfEqual = 0x70, IfLess, Invalid = 0xff @@ -926,6 +927,17 @@ struct SoundMacro bool Do(SoundMacroState& st, Voice& vox) const; CmdOp Isa() const { return CmdOp::AddIVars; } }; + struct CmdSetVar : ICmd + { + AT_DECL_DNA_YAML + AT_DECL_DNAV + Value varCtrlA; + Value a; + Seek<1, athena::Current> pad; + Value imm; + bool Do(SoundMacroState& st, Voice& vox) const; + CmdOp Isa() const { return CmdOp::SetVar; } + }; struct CmdIfEqual : ICmd { AT_DECL_DNA_YAML @@ -1149,10 +1161,10 @@ class AudioGroupPool std::unordered_map m_keymaps; std::unordered_map> m_layers; - AudioGroupPool() = default; template static AudioGroupPool _AudioGroupPool(athena::io::IStreamReader& r); public: + AudioGroupPool() = default; static AudioGroupPool CreateAudioGroupPool(const AudioGroupData& data); static AudioGroupPool CreateAudioGroupPool(SystemStringView groupPath); diff --git a/include/amuse/AudioGroupProject.hpp b/include/amuse/AudioGroupProject.hpp index 8f02821..44a2e87 100644 --- a/include/amuse/AudioGroupProject.hpp +++ b/include/amuse/AudioGroupProject.hpp @@ -183,7 +183,6 @@ class AudioGroupProject std::unordered_map m_songGroups; std::unordered_map m_sfxGroups; - AudioGroupProject() = default; AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag); template static AudioGroupProject _AudioGroupProject(athena::io::IStreamReader& r, bool absOffs); @@ -192,6 +191,7 @@ class AudioGroupProject template static void BootstrapObjectIDs(athena::io::IStreamReader& r, bool absOffs); public: + AudioGroupProject() = default; static AudioGroupProject CreateAudioGroupProject(const AudioGroupData& data); static AudioGroupProject CreateAudioGroupProject(SystemStringView groupPath); static void BootstrapObjectIDs(const AudioGroupData& data); diff --git a/include/amuse/AudioGroupSampleDirectory.hpp b/include/amuse/AudioGroupSampleDirectory.hpp index 6a69f9f..f872e79 100644 --- a/include/amuse/AudioGroupSampleDirectory.hpp +++ b/include/amuse/AudioGroupSampleDirectory.hpp @@ -253,9 +253,8 @@ private: static void _extractCompressed(SampleId id, const Entry& ent, amuse::SystemStringView destDir, const unsigned char* samp); - AudioGroupSampleDirectory() = default; - public: + AudioGroupSampleDirectory() = default; AudioGroupSampleDirectory(athena::io::IStreamReader& r, GCNDataTag); AudioGroupSampleDirectory(athena::io::IStreamReader& r, const unsigned char* sampData, bool absOffs, N64DataTag); AudioGroupSampleDirectory(athena::io::IStreamReader& r, bool absOffs, PCDataTag); diff --git a/lib/AudioGroup.cpp b/lib/AudioGroup.cpp index 751013d..8ece0d5 100644 --- a/lib/AudioGroup.cpp +++ b/lib/AudioGroup.cpp @@ -4,19 +4,21 @@ namespace amuse { -AudioGroup::AudioGroup(const AudioGroupData& data) -: m_proj(AudioGroupProject::CreateAudioGroupProject(data)) -, m_pool(AudioGroupPool::CreateAudioGroupPool(data)) -, m_sdir(AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(data)) -, m_samp(data.getSamp()) -{} - -AudioGroup::AudioGroup(SystemStringView groupPath) -: m_proj(AudioGroupProject::CreateAudioGroupProject(groupPath)) -, m_pool(AudioGroupPool::CreateAudioGroupPool(groupPath)) -, m_sdir(AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(groupPath)) -, m_groupPath(groupPath) -{} +void AudioGroup::assign(const AudioGroupData& data) +{ + m_proj = AudioGroupProject::CreateAudioGroupProject(data); + m_pool = AudioGroupPool::CreateAudioGroupPool(data); + m_sdir = AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(data); + m_samp = data.getSamp(); +} +void AudioGroup::assign(SystemStringView groupPath) +{ + /* Reverse order when loading intermediates */ + m_sdir = AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(groupPath); + m_pool = AudioGroupPool::CreateAudioGroupPool(groupPath); + m_proj = AudioGroupProject::CreateAudioGroupProject(groupPath); + m_samp = nullptr; +} const AudioGroupSampleDirectory::Entry* AudioGroup::getSample(SampleId sfxId) const { diff --git a/lib/AudioGroupPool.cpp b/lib/AudioGroupPool.cpp index 3e1feb1..3d5a183 100644 --- a/lib/AudioGroupPool.cpp +++ b/lib/AudioGroupPool.cpp @@ -134,7 +134,7 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath) if (!fi.hasError()) { athena::io::YAMLDocReader r; - if (r.parse(&fi) && r.ValidateClassType("amuse::Pool")) + if (r.parse(&fi) && !r.readString("DNAType").compare("amuse::Pool")) { if (auto __r = r.enterSubRecord("soundMacros")) { @@ -518,6 +518,8 @@ std::unique_ptr SoundMacro::MakeCmd(R& r) cmd = _MakeCmd(r); break; case CmdOp::AddIVars: cmd = _MakeCmd(r); break; + case CmdOp::SetVar: + cmd = _MakeCmd(r); break; case CmdOp::IfEqual: cmd = _MakeCmd(r); break; case CmdOp::IfLess: @@ -684,6 +686,8 @@ std::string_view SoundMacro::CmdOpToStr(CmdOp op) return "DivVars"sv; case CmdOp::AddIVars: return "AddIVars"sv; + case CmdOp::SetVar: + return "SetVar"sv; case CmdOp::IfEqual: return "IfEqual"sv; case CmdOp::IfLess: @@ -845,6 +849,8 @@ SoundMacro::CmdOp SoundMacro::CmdStrToOp(std::string_view op) return CmdOp::DivVars; else if (!CompareCaseInsensitive(op.data(), "AddIVars")) return CmdOp::AddIVars; + else if (!CompareCaseInsensitive(op.data(), "SetVar")) + return CmdOp::SetVar; else if (!CompareCaseInsensitive(op.data(), "IfEqual")) return CmdOp::IfEqual; else if (!CompareCaseInsensitive(op.data(), "IfLess")) diff --git a/lib/AudioGroupProject.cpp b/lib/AudioGroupProject.cpp index a0962bb..bf4d4bf 100644 --- a/lib/AudioGroupProject.cpp +++ b/lib/AudioGroupProject.cpp @@ -229,7 +229,7 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr if (!fi.hasError()) { athena::io::YAMLDocReader r; - if (r.parse(&fi) && r.ValidateClassType("amuse::Project")) + if (r.parse(&fi) && !r.readString("DNAType").compare("amuse::Project")) { if (auto __v = r.enterSubRecord("songGroups")) { @@ -289,7 +289,7 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr ret.m_sfxGroups.reserve(r.getCurNode()->m_mapChildren.size()); for (const auto& grp : r.getCurNode()->m_mapChildren) { - if (auto __r = r.enterSubRecord(nullptr)) + if (auto __r = r.enterSubRecord(grp.first.c_str())) { uint16_t groupId; std::string groupName = ParseStringSlashId(grp.first, groupId); diff --git a/lib/SoundMacroState.cpp b/lib/SoundMacroState.cpp index bb73a6a..8d848b8 100644 --- a/lib/SoundMacroState.cpp +++ b/lib/SoundMacroState.cpp @@ -1024,6 +1024,16 @@ bool SoundMacro::CmdAddIVars::Do(SoundMacroState& st, Voice& vox) const return false; } +bool SoundMacro::CmdSetVar::Do(SoundMacroState& st, Voice& vox) const +{ + if (varCtrlA) + vox.setCtrlValue(a, imm); + else + st.m_variables[a] = imm; + + return false; +} + bool SoundMacro::CmdIfEqual::Do(SoundMacroState& st, Voice& vox) const { int32_t useA, useB;