Implement LayersEditor

This commit is contained in:
Jack Andersen 2018-08-06 21:09:23 -10:00
parent 2b45f69ff4
commit 32deea8341
22 changed files with 911 additions and 72 deletions

View File

@ -17,6 +17,12 @@ public:
virtual bool valid() const { return true; } virtual bool valid() const { return true; }
virtual void unloadData() {} virtual void unloadData() {}
virtual ProjectModel::INode* currentNode() const { return nullptr; } virtual ProjectModel::INode* currentNode() const { return nullptr; }
public slots:
virtual bool isItemEditEnabled() const { return false; }
virtual void itemCutAction() {}
virtual void itemCopyAction() {}
virtual void itemPasteAction() {}
virtual void itemDeleteAction() {}
}; };
class EditorUndoCommand : public QUndoCommand class EditorUndoCommand : public QUndoCommand

View File

@ -483,7 +483,7 @@ int KeymapEditor::allocateConfigIdx(uint64_t key)
++search->second.second; ++search->second.second;
return search->second.first; return search->second.first;
} }
for (int i = 0; i < 128; ++i) for (int i = 0; i < 129; ++i)
if (!m_idxBitmap[i]) if (!m_idxBitmap[i])
{ {
m_configToIdx[key] = std::make_pair(i, 1); m_configToIdx[key] = std::make_pair(i, 1);
@ -514,7 +514,7 @@ int KeymapEditor::getConfigIdx(uint64_t key) const
auto search = m_configToIdx.find(key); auto search = m_configToIdx.find(key);
if (search != m_configToIdx.end()) if (search != m_configToIdx.end())
return search->second.first; return search->second.first;
for (int i = 0; i < 128; ++i) for (int i = 0; i < 129; ++i)
if (!m_idxBitmap[i]) if (!m_idxBitmap[i])
return i; return i;
Q_UNREACHABLE(); Q_UNREACHABLE();
@ -585,7 +585,7 @@ KeymapEditor::KeymapEditor(QWidget* parent)
int k = 0; int k = 0;
for (int i = 0; i < 13; ++i) for (int i = 0; i < 13; ++i)
for (int j = 0; j < 10 && k < 128; ++j) for (int j = 0; j < 10 && k < 129; ++j)
m_paintPalette[k++].setHsv(HueTable[j], SaturationTable[i], ValueTable[i]); m_paintPalette[k++].setHsv(HueTable[j], SaturationTable[i], ValueTable[i]);
m_scrollArea->setWidget(m_kmView); m_scrollArea->setWidget(m_kmView);

View File

@ -87,10 +87,10 @@ Q_OBJECT
QScrollArea* m_scrollArea; QScrollArea* m_scrollArea;
KeymapView* m_kmView; KeymapView* m_kmView;
KeymapControls* m_controls; KeymapControls* m_controls;
QColor m_paintPalette[128]; QColor m_paintPalette[129];
amuse::Keymap m_controlKeymap; amuse::Keymap m_controlKeymap;
std::unordered_map<uint64_t, std::pair<int, int>> m_configToIdx; std::unordered_map<uint64_t, std::pair<int, int>> m_configToIdx;
std::bitset<128> m_idxBitmap; std::bitset<129> m_idxBitmap;
bool m_inPaint = false; bool m_inPaint = false;
void _touch(); void _touch();
void touchKey(int key, bool bulk = false); void touchKey(int key, bool bulk = false);

View File

@ -1,12 +1,470 @@
#include "LayersEditor.hpp" #include "LayersEditor.hpp"
#include "MainWindow.hpp"
#include <QVBoxLayout>
#include <QScrollBar>
#include <QMimeData>
bool LayersEditor::loadData(ProjectModel::LayersNode* node) QWidget* SignedValueFactory::createEditor(int userType, QWidget *parent) const
{ {
QSpinBox* sb = new QSpinBox(parent);
sb->setFrame(false);
sb->setMinimum(-128);
sb->setMaximum(127);
return sb;
}
QWidget* UnsignedValueFactory::createEditor(int userType, QWidget *parent) const
{
QSpinBox* sb = new QSpinBox(parent);
sb->setFrame(false);
sb->setMinimum(0);
sb->setMaximum(127);
return sb;
}
EditorFieldProjectNode::EditorFieldProjectNode(ProjectModel::CollectionNode* collection, QWidget* parent)
: FieldProjectNode(collection, parent)
{}
SoundMacroDelegate::SoundMacroDelegate(QObject* parent)
: QStyledItemDelegate(parent) {}
QWidget* SoundMacroDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
const LayersModel* model = static_cast<const LayersModel*>(index.model());
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
EditorFieldProjectNode* cb =
new EditorFieldProjectNode(group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro), parent);
connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(smIndexChanged()));
return cb;
}
void SoundMacroDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
const LayersModel* model = static_cast<const LayersModel*>(index.model());
const amuse::LayerMapping& layer = (*model->m_node->m_obj)[index.row()];
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
ProjectModel::CollectionNode* smColl = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
static_cast<EditorFieldProjectNode*>(editor)->setCurrentIndex(smColl->indexOfId(layer.macro.id) + 1);
if (static_cast<EditorFieldProjectNode*>(editor)->shouldPopupOpen())
static_cast<EditorFieldProjectNode*>(editor)->showPopup();
}
void SoundMacroDelegate::setModelData(QWidget* editor, QAbstractItemModel* m, const QModelIndex& index) const
{
const LayersModel* model = static_cast<const LayersModel*>(m);
amuse::LayerMapping& layer = (*model->m_node->m_obj)[index.row()];
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
ProjectModel::CollectionNode* smColl = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
int idx = static_cast<EditorFieldProjectNode*>(editor)->currentIndex();
if (idx == 0)
layer.macro.id = amuse::SoundMacroId();
else
layer.macro.id = smColl->idOfIndex(idx - 1);
}
void SoundMacroDelegate::smIndexChanged()
{
emit commitData(static_cast<QWidget*>(sender()));
}
void LayersModel::loadData(ProjectModel::LayersNode* node)
{
beginResetModel();
m_node = node;
endResetModel();
}
void LayersModel::unloadData()
{
beginResetModel();
m_node.reset();
endResetModel();
}
int LayersModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid())
return 0;
if (!m_node)
return 0;
return int(m_node->m_obj->size()) + 1;
}
int LayersModel::columnCount(const QModelIndex& parent) const
{
if (parent.isValid())
return 0;
return 8;
}
QVariant LayersModel::data(const QModelIndex& index, int role) const
{
if (!m_node)
return QVariant();
if (index.row() == m_node->m_obj->size())
return QVariant();
const amuse::LayerMapping& layer = (*m_node->m_obj)[index.row()];
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
switch (index.column())
{
case 0:
{
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(m_node.get());
ProjectModel::CollectionNode* smColl = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
if (ProjectModel::BasePoolObjectNode* node = smColl->nodeOfId(layer.macro.id))
return node->text();
return QVariant();
}
case 1:
return layer.keyLo;
case 2:
return layer.keyHi;
case 3:
return layer.transpose;
case 4:
return layer.volume;
case 5:
return layer.prioOffset;
case 6:
return layer.span;
case 7:
return layer.pan;
default:
break;
}
}
return QVariant();
}
bool LayersModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (!m_node || role != Qt::EditRole)
return false;
amuse::LayerMapping& layer = (*m_node->m_obj)[index.row()];
switch (index.column())
{
case 1:
layer.keyLo = value.toInt();
return true;
case 2:
layer.keyHi = value.toInt();
return true;
case 3:
layer.transpose = value.toInt();
return true;
case 4:
layer.volume = value.toInt();
return true;
case 5:
layer.prioOffset = value.toInt();
return true;
case 6:
layer.span = value.toInt();
return true;
case 7:
layer.pan = value.toInt();
return true;
default:
break;
}
return false; return false;
} }
LayersEditor::LayersEditor(QWidget* parent) QVariant LayersModel::headerData(int section, Qt::Orientation orientation, int role) const
: EditorWidget(parent) {
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch (section)
{
case 0:
return tr("SoundMacro");
case 1:
return tr("Key Lo");
case 2:
return tr("Key Hi");
case 3:
return tr("Transpose");
case 4:
return tr("Volume");
case 5:
return tr("Prio Off");
case 6:
return tr("Span");
case 7:
return tr("Pan");
default:
break;
}
}
return QVariant();
}
Qt::ItemFlags LayersModel::flags(const QModelIndex& index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
if (index.row() == m_node->m_obj->size())
return Qt::NoItemFlags;
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
}
Qt::DropActions LayersModel::supportedDropActions() const
{
return Qt::MoveAction;
}
Qt::DropActions LayersModel::supportedDragActions() const
{
return Qt::MoveAction;
}
bool LayersModel::dropMimeData(const QMimeData* data, Qt::DropAction action,
int row, int column, const QModelIndex& parent)
{
// check if the action is supported
if (!data || action != Qt::MoveAction)
return false;
// check if the format is supported
QStringList types = mimeTypes();
if (types.isEmpty())
return false;
QString format = types.at(0);
if (!data->hasFormat(format))
return false;
// decode and insert
QByteArray encoded = data->data(format);
QDataStream stream(&encoded, QIODevice::ReadOnly);
std::unordered_set<int> rows;
int lastRow = -1;
while (!stream.atEnd()) {
int r, c;
QMap<int, QVariant> v;
stream >> r >> c >> v;
rows.insert(r);
lastRow = r;
}
if (lastRow == -1)
return false;
int start = lastRow;
while (rows.find(start - 1) != rows.cend())
start -= 1;
int count = lastRow - start + 1;
while (rows.find(start + count) != rows.cend())
count += 1;
int dest = parent.row();
if (dest >= start)
{
if (dest - start < count)
return false;
dest += 1;
}
moveRows(QModelIndex(), start, count, QModelIndex(), dest);
return true;
}
bool LayersModel::insertRows(int row, int count, const QModelIndex& parent)
{
if (!m_node)
return false;
beginInsertRows(parent, row, row + count - 1);
std::vector<amuse::LayerMapping>& layers = *m_node->m_obj;
layers.insert(layers.begin() + row, count, amuse::LayerMapping());
endInsertRows();
return true;
}
bool LayersModel::moveRows(const QModelIndex& sourceParent, int sourceRow, int count,
const QModelIndex& destinationParent, int destinationChild)
{
if (!m_node)
return false;
beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild);
std::vector<amuse::LayerMapping>& layers = *m_node->m_obj;
if (destinationChild < sourceRow)
{
for (int i = 0; i < count; ++i)
{
amuse::LayerMapping tmp = std::move(layers[sourceRow]);
for (int j = sourceRow; j != destinationChild; --j)
layers[j] = std::move(layers[j - 1]);
layers[destinationChild] = std::move(tmp);
++sourceRow;
++destinationChild;
}
}
else if (destinationChild > sourceRow)
{
for (int i = 0; i < count; ++i)
{
amuse::LayerMapping tmp = std::move(layers[sourceRow]);
for (int j = sourceRow; j != destinationChild - 1; ++j)
layers[j] = std::move(layers[j + 1]);
layers[destinationChild - 1] = std::move(tmp);
}
}
endMoveRows();
return true;
}
bool LayersModel::removeRows(int row, int count, const QModelIndex& parent)
{
if (!m_node)
return false;
beginRemoveRows(parent, row, row + count - 1);
std::vector<amuse::LayerMapping>& layers = *m_node->m_obj;
layers.erase(layers.begin() + row, layers.begin() + row + count);
endRemoveRows();
return true;
}
LayersModel::LayersModel(QObject* parent)
: QAbstractTableModel(parent)
{}
void LayersTableView::deleteSelection()
{
QModelIndexList list;
while (!(list = selectionModel()->selectedRows()).isEmpty())
model()->removeRow(list.back().row());
}
void LayersTableView::doItemsLayout()
{
horizontalHeader()->setMinimumSectionSize(75);
horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
horizontalHeader()->resizeSection(1, 75);
horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
horizontalHeader()->resizeSection(2, 75);
horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
horizontalHeader()->resizeSection(3, 75);
horizontalHeader()->setSectionResizeMode(4, QHeaderView::Fixed);
horizontalHeader()->resizeSection(4, 75);
horizontalHeader()->setSectionResizeMode(5, QHeaderView::Fixed);
horizontalHeader()->resizeSection(5, 75);
horizontalHeader()->setSectionResizeMode(6, QHeaderView::Fixed);
horizontalHeader()->resizeSection(6, 75);
horizontalHeader()->setSectionResizeMode(7, QHeaderView::Fixed);
horizontalHeader()->resizeSection(7, 75);
QTableView::doItemsLayout();
}
LayersTableView::LayersTableView(QWidget* parent)
: QTableView(parent)
{
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::ExtendedSelection);
setDragDropMode(QAbstractItemView::InternalMove);
setDefaultDropAction(Qt::MoveAction);
setDragEnabled(true);
setGridStyle(Qt::NoPen);
}
bool LayersEditor::loadData(ProjectModel::LayersNode* node)
{
m_model.loadData(node);
return true;
}
void LayersEditor::unloadData()
{
m_model.unloadData();
}
ProjectModel::INode* LayersEditor::currentNode() const
{
return m_model.m_node.get();
}
void LayersEditor::resizeEvent(QResizeEvent* ev)
{
m_tableView.setGeometry(QRect({}, ev->size()));
m_addButton.move(0, ev->size().height() - 32);
m_removeButton.move(32, ev->size().height() - 32);
}
void LayersEditor::doAdd()
{
QModelIndex idx = m_tableView.selectionModel()->currentIndex();
if (!idx.isValid())
m_model.insertRow(m_model.rowCount() - 1);
else
m_model.insertRow(idx.row());
}
void LayersEditor::doSelectionChanged(const QItemSelection& selected)
{
m_removeAction.setDisabled(selected.isEmpty());
g_MainWindow->updateFocus();
}
bool LayersEditor::isItemEditEnabled() const
{
return !m_tableView.selectionModel()->selectedRows().isEmpty();
}
void LayersEditor::itemCutAction()
{ {
} }
void LayersEditor::itemCopyAction()
{
}
void LayersEditor::itemPasteAction()
{
}
void LayersEditor::itemDeleteAction()
{
m_tableView.deleteSelection();
}
LayersEditor::LayersEditor(QWidget* parent)
: EditorWidget(parent), m_tableView(this),
m_addAction(tr("Add Row")), m_addButton(this), m_removeAction(tr("Remove Row")), m_removeButton(this)
{
m_signedDelegate.setItemEditorFactory(&m_signedFactory);
m_unsignedDelegate.setItemEditorFactory(&m_unsignedFactory);
m_tableView.setItemDelegateForColumn(1, &m_unsignedDelegate);
m_tableView.setItemDelegateForColumn(2, &m_unsignedDelegate);
m_tableView.setItemDelegateForColumn(3, &m_signedDelegate);
m_tableView.setItemDelegateForColumn(4, &m_unsignedDelegate);
m_tableView.setItemDelegateForColumn(5, &m_signedDelegate);
m_tableView.setItemDelegateForColumn(6, &m_unsignedDelegate);
m_tableView.setItemDelegateForColumn(7, &m_unsignedDelegate);
m_tableView.setModel(&m_model);
m_tableView.setItemDelegateForColumn(0, &m_smDelegate);
connect(m_tableView.selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
this, SLOT(doSelectionChanged(const QItemSelection&)));
m_addAction.setIcon(QIcon(QStringLiteral(":/icons/IconAdd.svg")));
m_addButton.setDefaultAction(&m_addAction);
m_addButton.setFixedSize(32, 32);
connect(&m_addAction, SIGNAL(triggered(bool)), this, SLOT(doAdd()));
m_removeAction.setIcon(QIcon(QStringLiteral(":/icons/IconRemove.svg")));
m_removeButton.setDefaultAction(&m_removeAction);
m_removeButton.setFixedSize(32, 32);
connect(&m_removeAction, SIGNAL(triggered(bool)), this, SLOT(itemDeleteAction()));
m_removeAction.setEnabled(false);
}

View File

@ -2,14 +2,116 @@
#define AMUSE_LAYERS_EDITOR_HPP #define AMUSE_LAYERS_EDITOR_HPP
#include "EditorWidget.hpp" #include "EditorWidget.hpp"
#include <QAbstractTableModel>
#include <QTableView>
#include <QAction>
#include <QToolButton>
#include <QStyledItemDelegate>
#include <QItemEditorFactory>
class SignedValueFactory : public QItemEditorFactory
{
public:
QWidget* createEditor(int userType, QWidget *parent) const;
};
class UnsignedValueFactory : public QItemEditorFactory
{
public:
QWidget* createEditor(int userType, QWidget *parent) const;
};
class EditorFieldProjectNode : public FieldProjectNode
{
Q_OBJECT
bool m_deferPopupOpen = true;
public:
explicit EditorFieldProjectNode(ProjectModel::CollectionNode* collection = Q_NULLPTR, QWidget* parent = Q_NULLPTR);
bool shouldPopupOpen()
{
bool ret = m_deferPopupOpen;
m_deferPopupOpen = false;
return ret;
}
};
class SoundMacroDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit SoundMacroDelegate(QObject* parent = Q_NULLPTR);
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
void setEditorData(QWidget* editor, const QModelIndex& index) const;
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
private slots:
void smIndexChanged();
};
class LayersModel : public QAbstractTableModel
{
Q_OBJECT
friend class LayersEditor;
friend class SoundMacroDelegate;
amuse::ObjToken<ProjectModel::LayersNode> m_node;
public:
explicit LayersModel(QObject* parent = Q_NULLPTR);
void loadData(ProjectModel::LayersNode* node);
void unloadData();
int rowCount(const QModelIndex& parent = QModelIndex()) const;
int columnCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
Qt::ItemFlags flags(const QModelIndex& index) const;
Qt::DropActions supportedDropActions() const;
Qt::DropActions supportedDragActions() const;
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent);
bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex());
bool moveRows(const QModelIndex& sourceParent, int sourceRow, int count,
const QModelIndex& destinationParent, int destinationChild);
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex());
};
class LayersTableView : public QTableView
{
Q_OBJECT
public:
explicit LayersTableView(QWidget* parent = Q_NULLPTR);
void doItemsLayout();
void deleteSelection();
};
class LayersEditor : public EditorWidget class LayersEditor : public EditorWidget
{ {
Q_OBJECT Q_OBJECT
LayersModel m_model;
SoundMacroDelegate m_smDelegate;
SignedValueFactory m_signedFactory;
UnsignedValueFactory m_unsignedFactory;
QStyledItemDelegate m_signedDelegate, m_unsignedDelegate;
LayersTableView m_tableView;
QAction m_addAction;
QToolButton m_addButton;
QAction m_removeAction;
QToolButton m_removeButton;
public: public:
explicit LayersEditor(QWidget* parent = Q_NULLPTR); explicit LayersEditor(QWidget* parent = Q_NULLPTR);
bool loadData(ProjectModel::LayersNode* node); bool loadData(ProjectModel::LayersNode* node);
void unloadData();
ProjectModel::INode* currentNode() const;
void resizeEvent(QResizeEvent* ev);
public slots:
void doAdd();
void doSelectionChanged(const QItemSelection& selected);
bool isItemEditEnabled() const;
void itemCutAction();
void itemCopyAction();
void itemPasteAction();
void itemDeleteAction();
}; };
#endif //AMUSE_LAYERS_EDITOR_HPP #endif //AMUSE_LAYERS_EDITOR_HPP

View File

@ -256,7 +256,7 @@ bool MainWindow::setProjectPath(const QString& path)
m_ui.actionExport_GameCube_Groups->setEnabled(true); m_ui.actionExport_GameCube_Groups->setEnabled(true);
setWindowFilePath(path); setWindowFilePath(path);
updateWindowTitle(); updateWindowTitle();
onFocusChanged(nullptr, focusWidget()); updateFocus();
m_undoStack->clear(); m_undoStack->clear();
QSettings settings; QSettings settings;
@ -314,7 +314,7 @@ void MainWindow::timerEvent(QTimerEvent* ev)
if (m_voxEngine && m_engine) if (m_voxEngine && m_engine)
{ {
m_voxEngine->pumpAndMixVoices(); m_voxEngine->pumpAndMixVoices();
m_ui.statusbar->setVoiceCount(int(m_engine->getActiveVoices().size())); m_ui.statusbar->setVoiceCount(int(m_engine->getNumTotalActiveVoices()));
if (m_engine->getActiveVoices().empty() && m_uiDisabled) if (m_engine->getActiveVoices().empty() && m_uiDisabled)
{ {
m_ui.projectOutline->setEnabled(true); m_ui.projectOutline->setEnabled(true);
@ -548,6 +548,11 @@ void MainWindow::pushUndoCommand(QUndoCommand* cmd)
m_undoStack->push(cmd); m_undoStack->push(cmd);
} }
void MainWindow::updateFocus()
{
onFocusChanged(nullptr, focusWidget());
}
void MainWindow::aboutToDeleteNode(ProjectModel::INode* node) void MainWindow::aboutToDeleteNode(ProjectModel::INode* node)
{ {
if (getEditorNode() == node) if (getEditorNode() == node)
@ -1000,7 +1005,7 @@ void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
if (now == m_ui.projectOutline || m_ui.projectOutline->isAncestorOf(now)) if (now == m_ui.projectOutline || m_ui.projectOutline->isAncestorOf(now))
{ {
setOutlineEditEnabled(canEditOutline()); setItemEditEnabled(canEditOutline());
if (m_projectModel) if (m_projectModel)
{ {
m_cutConn = connect(m_ui.actionCut, SIGNAL(triggered()), this, SLOT(outlineCutAction())); m_cutConn = connect(m_ui.actionCut, SIGNAL(triggered()), this, SLOT(outlineCutAction()));
@ -1011,12 +1016,23 @@ void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
} }
else if (now == m_ui.editorContents || m_ui.editorContents->isAncestorOf(now)) else if (now == m_ui.editorContents || m_ui.editorContents->isAncestorOf(now))
{ {
setOutlineEditEnabled(false); setItemEditEnabled(false);
if (EditorWidget* editor = getEditorWidget())
{
if (editor->isItemEditEnabled())
{
setItemEditEnabled(true);
m_cutConn = connect(m_ui.actionCut, SIGNAL(triggered()), editor, SLOT(itemCutAction()));
m_copyConn = connect(m_ui.actionCopy, SIGNAL(triggered()), editor, SLOT(itemCopyAction()));
m_pasteConn = connect(m_ui.actionPaste, SIGNAL(triggered()), editor, SLOT(itemPasteAction()));
m_deleteConn = connect(m_ui.actionDelete, SIGNAL(triggered()), editor, SLOT(itemDeleteAction()));
}
}
} }
} }
void MainWindow::setOutlineEditEnabled(bool enabled) void MainWindow::setItemEditEnabled(bool enabled)
{ {
m_ui.actionCut->setEnabled(enabled); m_ui.actionCut->setEnabled(enabled);
m_ui.actionCopy->setEnabled(enabled); m_ui.actionCopy->setEnabled(enabled);
@ -1040,10 +1056,10 @@ void MainWindow::onOutlineSelectionChanged(const QItemSelection& selected, const
return; return;
if (selected.indexes().empty()) if (selected.indexes().empty())
{ {
setOutlineEditEnabled(false); setItemEditEnabled(false);
return; return;
} }
setOutlineEditEnabled(m_projectModel->canEdit(selected.indexes().front())); setItemEditEnabled(m_projectModel->canEdit(selected.indexes().front()));
} }
void MainWindow::onTextSelect() void MainWindow::onTextSelect()

View File

@ -147,6 +147,7 @@ public:
EditorWidget* getEditorWidget() const; EditorWidget* getEditorWidget() const;
amuse::ObjToken<amuse::Voice> startEditorVoice(uint8_t key, uint8_t vel); amuse::ObjToken<amuse::Voice> startEditorVoice(uint8_t key, uint8_t vel);
void pushUndoCommand(QUndoCommand* cmd); void pushUndoCommand(QUndoCommand* cmd);
void updateFocus();
void aboutToDeleteNode(ProjectModel::INode* node); void aboutToDeleteNode(ProjectModel::INode* node);
ProjectModel* projectModel() const { return m_projectModel; } ProjectModel* projectModel() const { return m_projectModel; }
@ -190,7 +191,7 @@ public slots:
void outlineDeleteAction(); void outlineDeleteAction();
void onFocusChanged(QWidget* old, QWidget* now); void onFocusChanged(QWidget* old, QWidget* now);
void setOutlineEditEnabled(bool enabled); void setItemEditEnabled(bool enabled);
bool canEditOutline(); bool canEditOutline();
void onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); void onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
void onTextSelect(); void onTextSelect();

View File

@ -94,6 +94,14 @@ ProjectModel::BasePoolObjectNode* ProjectModel::CollectionNode::nodeOfIndex(int
return static_cast<BasePoolObjectNode*>(m_children[idx].get()); return static_cast<BasePoolObjectNode*>(m_children[idx].get());
} }
ProjectModel::BasePoolObjectNode* ProjectModel::CollectionNode::nodeOfId(amuse::ObjectId id) const
{
int idx = indexOfId(id);
if (idx < 0)
return nullptr;
return nodeOfIndex(idx);
}
ProjectModel::ProjectModel(const QString& path, QObject* parent) ProjectModel::ProjectModel(const QString& path, QObject* parent)
: QAbstractItemModel(parent), m_dir(path), m_nullProxy(this) : QAbstractItemModel(parent), m_dir(path), m_nullProxy(this)
{ {

View File

@ -207,6 +207,7 @@ public:
int indexOfId(amuse::ObjectId id) const; int indexOfId(amuse::ObjectId id) const;
amuse::ObjectId idOfIndex(int idx) const; amuse::ObjectId idOfIndex(int idx) const;
BasePoolObjectNode* nodeOfIndex(int idx) const; BasePoolObjectNode* nodeOfIndex(int idx) const;
BasePoolObjectNode* nodeOfId(amuse::ObjectId id) const;
}; };
struct BasePoolObjectNode : INode struct BasePoolObjectNode : INode
{ {

View File

@ -6,6 +6,7 @@
#include "boo/IApplication.hpp" #include "boo/IApplication.hpp"
#include <QResource> #include <QResource>
#include <QCommandLineParser> #include <QCommandLineParser>
#include <logvisor/logvisor.hpp>
using namespace std::literals; using namespace std::literals;
@ -91,6 +92,9 @@ int main(int argc, char* argv[])
MacOSSetDarkAppearance(); MacOSSetDarkAppearance();
#endif #endif
logvisor::RegisterConsoleLogger();
logvisor::RegisterStandardExceptions();
BooInterface booApp; BooInterface booApp;
boo::APP = &booApp; boo::APP = &booApp;

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
viewBox="0 0 6.3499998 6.3500004"
version="1.1"
id="svg8"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconAdd.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#353535"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="111.23937"
inkscape:cx="14.81887"
inkscape:cy="16.006269"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2079"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="1"
gridtolerance="4"
showguides="false"
showborder="true"
objecttolerance="13">
<inkscape:grid
type="xygrid"
id="grid817"
empspacing="0"
spacingx="0.52916666"
spacingy="0.52916666"
visible="true" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-290.64999)">
<path
style="fill:#66ff00;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 0,292.76666 h 2.1166667 v -2.11667 h 2.1166667 v 2.11667 h 2.1166665 v 2.11666 H 4.2333334 v 2.11667 H 2.1166667 v -2.11667 H 0 Z"
id="path846"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
viewBox="0 0 6.3499998 6.3500004"
version="1.1"
id="svg8"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconRemove.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#353535"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="39.327341"
inkscape:cx="14.81887"
inkscape:cy="14.927514"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2079"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="1"
gridtolerance="4"
showguides="false"
showborder="true"
objecttolerance="13">
<inkscape:grid
type="xygrid"
id="grid817"
empspacing="0"
spacingx="0.52916666"
spacingy="0.52916666"
visible="true" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-290.64999)">
<path
style="fill:#ff0000;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 0,292.76666 v 2.11666 h 6.3499999 v -2.11666 z"
id="path867"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -181,6 +181,62 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>LayersEditor</name>
<message>
<location filename="../LayersEditor.cpp" line="442"/>
<source>Add Row</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../LayersEditor.cpp" line="442"/>
<source>Remove Row</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>LayersModel</name>
<message>
<location filename="../LayersEditor.cpp" line="186"/>
<source>SoundMacro</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../LayersEditor.cpp" line="188"/>
<source>Key Lo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../LayersEditor.cpp" line="190"/>
<source>Key Hi</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../LayersEditor.cpp" line="192"/>
<source>Transpose</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../LayersEditor.cpp" line="194"/>
<source>Volume</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../LayersEditor.cpp" line="196"/>
<source>Prio Off</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../LayersEditor.cpp" line="198"/>
<source>Span</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../LayersEditor.cpp" line="200"/>
<source>Pan</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
@ -396,13 +452,13 @@
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="225"/> <location filename="../MainWindow.cpp" line="225"/>
<location filename="../MainWindow.cpp" line="576"/> <location filename="../MainWindow.cpp" line="581"/>
<source>The directory at &apos;%1&apos; must not be empty.</source> <source>The directory at &apos;%1&apos; must not be empty.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="226"/> <location filename="../MainWindow.cpp" line="226"/>
<location filename="../MainWindow.cpp" line="577"/> <location filename="../MainWindow.cpp" line="582"/>
<source>Directory empty</source> <source>Directory empty</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -447,122 +503,122 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="559"/> <location filename="../MainWindow.cpp" line="564"/>
<source>New Project</source> <source>New Project</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="582"/> <location filename="../MainWindow.cpp" line="587"/>
<source>The directory at &apos;%1&apos; does not exist.</source> <source>The directory at &apos;%1&apos; does not exist.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="583"/> <location filename="../MainWindow.cpp" line="588"/>
<source>Bad Directory</source> <source>Bad Directory</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="598"/> <location filename="../MainWindow.cpp" line="603"/>
<source>Opening</source> <source>Opening</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="598"/> <location filename="../MainWindow.cpp" line="603"/>
<location filename="../MainWindow.cpp" line="676"/> <location filename="../MainWindow.cpp" line="681"/>
<location filename="../MainWindow.cpp" line="759"/> <location filename="../MainWindow.cpp" line="764"/>
<location filename="../MainWindow.cpp" line="804"/> <location filename="../MainWindow.cpp" line="809"/>
<source>Scanning Project</source> <source>Scanning Project</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="610"/> <location filename="../MainWindow.cpp" line="615"/>
<source>Opening %1</source> <source>Opening %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="622"/> <location filename="../MainWindow.cpp" line="627"/>
<source>Open Project</source> <source>Open Project</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="676"/> <location filename="../MainWindow.cpp" line="681"/>
<source>Reloading Samples</source> <source>Reloading Samples</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="688"/> <location filename="../MainWindow.cpp" line="693"/>
<source>Scanning %1</source> <source>Scanning %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="698"/> <location filename="../MainWindow.cpp" line="703"/>
<source>Import Project</source> <source>Import Project</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="707"/> <location filename="../MainWindow.cpp" line="712"/>
<source>The file at &apos;%1&apos; could not be interpreted as a MusyX container.</source> <source>The file at &apos;%1&apos; could not be interpreted as a MusyX container.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="708"/> <location filename="../MainWindow.cpp" line="713"/>
<source>Unsupported MusyX Container</source> <source>Unsupported MusyX Container</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="713"/> <location filename="../MainWindow.cpp" line="718"/>
<source>Sample Import Mode</source> <source>Sample Import Mode</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="714"/> <location filename="../MainWindow.cpp" line="719"/>
<source>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.</source> <source>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.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="718"/> <location filename="../MainWindow.cpp" line="723"/>
<source>Import Compressed</source> <source>Import Compressed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="718"/> <location filename="../MainWindow.cpp" line="723"/>
<source>Import WAVs</source> <source>Import WAVs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="718"/> <location filename="../MainWindow.cpp" line="723"/>
<source>Import Both</source> <source>Import Both</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="734"/> <location filename="../MainWindow.cpp" line="739"/>
<source>Raw Import Mode</source> <source>Raw Import Mode</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="735"/> <location filename="../MainWindow.cpp" line="740"/>
<source>Would you like to scan for all MusyX group files in this directory?</source> <source>Would you like to scan for all MusyX group files in this directory?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="745"/> <location filename="../MainWindow.cpp" line="750"/>
<source>Project Name</source> <source>Project Name</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="745"/> <location filename="../MainWindow.cpp" line="750"/>
<source>What should this project be named?</source> <source>What should this project be named?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="759"/> <location filename="../MainWindow.cpp" line="764"/>
<location filename="../MainWindow.cpp" line="804"/> <location filename="../MainWindow.cpp" line="809"/>
<source>Importing</source> <source>Importing</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="771"/> <location filename="../MainWindow.cpp" line="776"/>
<location filename="../MainWindow.cpp" line="813"/> <location filename="../MainWindow.cpp" line="818"/>
<source>Importing %1</source> <source>Importing %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -594,37 +650,37 @@
<context> <context>
<name>ProjectModel</name> <name>ProjectModel</name>
<message> <message>
<location filename="../ProjectModel.cpp" line="226"/> <location filename="../ProjectModel.cpp" line="234"/>
<source>Sound Macros</source> <source>Sound Macros</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="245"/> <location filename="../ProjectModel.cpp" line="253"/>
<source>ADSRs</source> <source>ADSRs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="256"/> <location filename="../ProjectModel.cpp" line="264"/>
<source>Curves</source> <source>Curves</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="268"/> <location filename="../ProjectModel.cpp" line="276"/>
<source>Keymaps</source> <source>Keymaps</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="275"/> <location filename="../ProjectModel.cpp" line="283"/>
<source>Layers</source> <source>Layers</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="282"/> <location filename="../ProjectModel.cpp" line="290"/>
<source>Samples</source> <source>Samples</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="434"/> <location filename="../ProjectModel.cpp" line="442"/>
<source>Delete %1</source> <source>Delete %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View File

@ -26,6 +26,8 @@
<file>IconKill.svg</file> <file>IconKill.svg</file>
<file>IconSample.svg</file> <file>IconSample.svg</file>
<file>IconPaintbrush.svg</file> <file>IconPaintbrush.svg</file>
<file>IconAdd.svg</file>
<file>IconRemove.svg</file>
</qresource> </qresource>
<qresource prefix="/bg"> <qresource prefix="/bg">
<file>FaceGrey.svg</file> <file>FaceGrey.svg</file>

View File

@ -1358,13 +1358,13 @@ struct LayerMapping : BigDNA
{ {
AT_DECL_DNA_YAML AT_DECL_DNA_YAML
SoundMacroIdDNA<athena::Big> macro; SoundMacroIdDNA<athena::Big> macro;
Value<atInt8> keyLo; Value<atInt8> keyLo = 0;
Value<atInt8> keyHi; Value<atInt8> keyHi = 127;
Value<atInt8> transpose; Value<atInt8> transpose = 0;
Value<atInt8> volume; Value<atInt8> volume = 127;
Value<atInt8> prioOffset; Value<atInt8> prioOffset = 0;
Value<atInt8> span; Value<atInt8> span = 0;
Value<atInt8> pan; Value<atInt8> pan = 64;
LayerMapping() = default; LayerMapping() = default;

View File

@ -162,6 +162,9 @@ public:
/** Obtain list of active voices */ /** Obtain list of active voices */
std::list<ObjToken<Voice>>& getActiveVoices() { return m_activeVoices; } std::list<ObjToken<Voice>>& getActiveVoices() { return m_activeVoices; }
/** Obtain total active voice count (including child voices) */
size_t getNumTotalActiveVoices() const;
/** Obtain list of active sequencers */ /** Obtain list of active sequencers */
std::list<ObjToken<Sequencer>>& getActiveSequencers() { return m_activeSequencers; } std::list<ObjToken<Sequencer>>& getActiveSequencers() { return m_activeSequencers; }

View File

@ -351,6 +351,8 @@ public:
{ {
m_ctrlValsSelf.reset(); m_ctrlValsSelf.reset();
m_extCtrlVals = cvs; m_extCtrlVals = cvs;
for (ObjToken<Voice>& vox : m_childVoices)
vox->installCtrlValues(cvs);
} }
/** Get MIDI pitch wheel value on voice */ /** Get MIDI pitch wheel value on voice */

View File

@ -353,11 +353,6 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
} }
} }
amuse::KeymapId id = 42;
amuse::KeymapId::CurNameDB->registerPair("test", id);
auto& kmOut = ret.m_keymaps[id];
kmOut = MakeObj<std::array<Keymap, 128>>();
return ret; return ret;
} }

View File

@ -35,11 +35,17 @@ static void ReadRangedObjectIds(NameDB* db, athena::io::IStreamReader& r, NameDB
ObjectId useId = i; ObjectId useId = i;
if (tp == NameDB::Type::Layer) if (tp == NameDB::Type::Layer)
useId.id |= 0x8000; useId.id |= 0x8000;
else if (tp == NameDB::Type::Keymap)
useId.id |= 0x4000;
db->registerPair(NameDB::generateName(useId, tp), useId); db->registerPair(NameDB::generateName(useId, tp), useId);
} }
} }
else else
{ {
if (tp == NameDB::Type::Layer)
id |= 0x8000;
else if (tp == NameDB::Type::Keymap)
id |= 0x4000;
db->registerPair(NameDB::generateName(id, tp), id); db->registerPair(NameDB::generateName(id, tp), id);
} }
} }

View File

@ -1,6 +1,8 @@
#include "amuse/Common.hpp" #include "amuse/Common.hpp"
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
using namespace std::literals;
namespace amuse namespace amuse
{ {
static logvisor::Module Log("amuse"); static logvisor::Module Log("amuse");
@ -180,11 +182,16 @@ void PageObjectIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
std::string_view name = LayersId::CurNameDB->resolveNameFromId(id); std::string_view name = LayersId::CurNameDB->resolveNameFromId(id);
w.writeString(nullptr, name); w.writeString(nullptr, name);
} }
else else if (id.id & 0x4000)
{ {
std::string_view name = KeymapId::CurNameDB->resolveNameFromId(id); std::string_view name = KeymapId::CurNameDB->resolveNameFromId(id);
w.writeString(nullptr, name); w.writeString(nullptr, name);
} }
else
{
std::string_view name = SoundMacroId::CurNameDB->resolveNameFromId(id);
w.writeString(nullptr, name);
}
} }
template <athena::Endian DNAE> template <athena::Endian DNAE>
const char* PageObjectIdDNA<DNAE>::DNAType() const char* PageObjectIdDNA<DNAE>::DNAType()
@ -307,7 +314,10 @@ std::string_view NameDB::resolveNameFromId(ObjectId id) const
{ {
auto search = m_idToString.find(id); auto search = m_idToString.find(id);
if (search == m_idToString.cend()) if (search == m_idToString.cend())
Log.report(logvisor::Fatal, "Unable to resolve ID 0x%04X", id.id); {
Log.report(logvisor::Error, "Unable to resolve ID 0x%04X", id.id);
return ""sv;
}
return search->second; return search->second;
} }
@ -315,7 +325,10 @@ ObjectId NameDB::resolveIdFromName(std::string_view str) const
{ {
auto search = m_stringToId.find(std::string(str)); auto search = m_stringToId.find(std::string(str));
if (search == m_stringToId.cend()) if (search == m_stringToId.cend())
Log.report(logvisor::Fatal, "Unable to resolve name %s", str.data()); {
Log.report(logvisor::Error, "Unable to resolve name %s", str.data());
return {};
}
return search->second; return search->second;
} }

View File

@ -496,4 +496,12 @@ void Engine::sendMacroMessage(ObjectId macroId, int32_t val)
for (ObjToken<Sequencer>& seq : m_activeSequencers) for (ObjToken<Sequencer>& seq : m_activeSequencers)
seq->sendMacroMessage(macroId, val); seq->sendMacroMessage(macroId, val);
} }
size_t Engine::getNumTotalActiveVoices() const
{
size_t ret = 0;
for (const auto& vox : m_activeVoices)
ret += vox->getTotalVoices();
return ret;
}
} }

View File

@ -776,6 +776,8 @@ ObjToken<Voice> Voice::_startChildMacro(ObjectId macroId, int macroStep, double
(*vox)->setVolume(m_targetUserVol); (*vox)->setVolume(m_targetUserVol);
(*vox)->setPan(m_curPan); (*vox)->setPan(m_curPan);
(*vox)->setSurroundPan(m_curSpan); (*vox)->setSurroundPan(m_curSpan);
if (m_extCtrlVals)
(*vox)->installCtrlValues(m_extCtrlVals);
return *vox; return *vox;
} }
@ -835,7 +837,7 @@ bool Voice::_loadLayer(const std::vector<LayerMapping>& layer, double ticksPerSe
if (m_voxState != VoiceState::Playing) if (m_voxState != VoiceState::Playing)
{ {
ret |= loadMacroObject(mapping.macro.id, 0, ticksPerSec, mappingKey, midiVel, midiMod, pushPc); ret |= loadMacroObject(mapping.macro.id, 0, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
m_curVol = mapping.volume / 127.f; m_curUserVol = m_targetUserVol = mapping.volume / 127.f;
_setPan((mapping.pan - 64) / 64.f); _setPan((mapping.pan - 64) / 64.f);
_setSurroundPan((mapping.span - 64) / 64.f); _setSurroundPan((mapping.span - 64) / 64.f);
} }
@ -845,7 +847,7 @@ bool Voice::_loadLayer(const std::vector<LayerMapping>& layer, double ticksPerSe
_startChildMacro(mapping.macro.id, 0, ticksPerSec, mappingKey, midiVel, midiMod, pushPc); _startChildMacro(mapping.macro.id, 0, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
if (vox) if (vox)
{ {
vox->m_curVol = mapping.volume / 127.f; vox->m_curUserVol = vox->m_targetUserVol = mapping.volume / 127.f;
vox->_setPan((mapping.pan - 64) / 64.f); vox->_setPan((mapping.pan - 64) / 64.f);
vox->_setSurroundPan((mapping.span - 64) / 64.f); vox->_setSurroundPan((mapping.span - 64) / 64.f);
ret = true; ret = true;
@ -892,12 +894,18 @@ bool Voice::loadPageObject(ObjectId objectId, double ticksPerSec, uint8_t midiKe
if (layer) if (layer)
return _loadLayer(*layer, ticksPerSec, midiKey, midiVel, midiMod); return _loadLayer(*layer, ticksPerSec, midiKey, midiVel, midiMod);
} }
else else if (objectId.id & 0x4000)
{ {
const Keymap* keymap = m_audioGroup.getPool().keymap(objectId); const Keymap* keymap = m_audioGroup.getPool().keymap(objectId);
if (keymap) if (keymap)
return _loadKeymap(keymap, ticksPerSec, midiKey, midiVel, midiMod); return _loadKeymap(keymap, ticksPerSec, midiKey, midiVel, midiMod);
} }
else
{
const SoundMacro* sm = m_audioGroup.getPool().soundMacro(objectId);
if (sm)
return _loadSoundMacro(objectId, sm, 0, ticksPerSec, midiKey, midiVel, midiMod);
}
return false; return false;
} }