Initial ProjectModel implementation

This commit is contained in:
Jack Andersen 2018-07-16 18:48:38 -10:00
parent 7a38fd0676
commit 3f265cdb46
29 changed files with 1337 additions and 224 deletions

View File

@ -54,4 +54,4 @@ target_link_libraries(amuse-gui ${PLAT_LIBS}
${Qt5Network_LIBRARIES} ${Qt5Network_LIBRARIES}
${Qt5Xml_LIBRARIES} ${Qt5Xml_LIBRARIES}
${Qt5Svg_LIBRARIES} ${Qt5Svg_LIBRARIES}
amuse boo ${BOO_SYS_LIBS} logvisor zeus athena-core athena-libyaml xxhash ${ZLIB_LIBRARIES} ${LZO_LIB}) amuse boo ${BOO_SYS_LIBS} logvisor athena-core athena-libyaml xxhash ${ZLIB_LIBRARIES} ${LZO_LIB})

View File

@ -20,18 +20,18 @@ QString SysStringToQString(const boo::SystemString& str)
#endif #endif
} }
bool MkPath(const QString& path, QWidget* parent) bool MkPath(const QString& path, UIMessenger& messenger)
{ {
QFileInfo fInfo(path); QFileInfo fInfo(path);
return MkPath(fInfo.dir(), fInfo.fileName(), parent); return MkPath(fInfo.dir(), fInfo.fileName(), messenger);
} }
bool MkPath(const QDir& dir, const QString& file, QWidget* parent) bool MkPath(const QDir& dir, const QString& file, UIMessenger& messenger)
{ {
if (!dir.mkpath(file)) if (!dir.mkpath(file))
{ {
QString msg = QString(parent->tr("A directory at '%1/%2' could not be created.")).arg(dir.path()).arg(file); QString msg = QString(QObject::tr("A directory at '%1/%2' could not be created.")).arg(dir.path()).arg(file);
QMessageBox::critical(parent, parent->tr("Unable to create directory"), msg); messenger.critical(QObject::tr("Unable to create directory"), msg);
return false; return false;
} }
return true; return true;

View File

@ -4,11 +4,33 @@
#include "boo/System.hpp" #include "boo/System.hpp"
#include <QString> #include <QString>
#include <QDir> #include <QDir>
#include <QMessageBox>
class UIMessenger : public QObject
{
Q_OBJECT
public:
using QObject::QObject;
signals:
QMessageBox::StandardButton information(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
QMessageBox::StandardButton question(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons =
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
QMessageBox::StandardButton warning(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
QMessageBox::StandardButton critical(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
};
boo::SystemString QStringToSysString(const QString& str); boo::SystemString QStringToSysString(const QString& str);
QString SysStringToQString(const boo::SystemString& str); QString SysStringToQString(const boo::SystemString& str);
bool MkPath(const QString& path, QWidget* parent); bool MkPath(const QString& path, UIMessenger& messenger);
bool MkPath(const QDir& dir, const QString& file, QWidget* parent); bool MkPath(const QDir& dir, const QString& file, UIMessenger& messenger);
#endif //AMUSE_COMMON_HPP #endif //AMUSE_COMMON_HPP

View File

@ -3,15 +3,27 @@
#include <QMessageBox> #include <QMessageBox>
#include <QLineEdit> #include <QLineEdit>
#include <QInputDialog> #include <QInputDialog>
#include <QProgressDialog>
#include <QtSvg/QtSvg> #include <QtSvg/QtSvg>
#include "amuse/ContainerRegistry.hpp" #include "amuse/ContainerRegistry.hpp"
#include "Common.hpp" #include "Common.hpp"
static void connectMessenger(UIMessenger* messenger, Qt::ConnectionType type)
{
}
MainWindow::MainWindow(QWidget* parent) MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent), : QMainWindow(parent),
m_undoStack(new QUndoStack(this)) m_mainMessenger(this),
m_undoStack(new QUndoStack(this)),
m_backgroundThread(this)
{ {
m_backgroundThread.start();
m_ui.setupUi(this); m_ui.setupUi(this);
connectMessenger(&m_mainMessenger, Qt::DirectConnection);
m_ui.actionNew_Project->setShortcut(QKeySequence::New); m_ui.actionNew_Project->setShortcut(QKeySequence::New);
connect(m_ui.actionNew_Project, SIGNAL(triggered()), this, SLOT(newAction())); connect(m_ui.actionNew_Project, SIGNAL(triggered()), this, SLOT(newAction()));
m_ui.actionOpen_Project->setShortcut(QKeySequence::Open); m_ui.actionOpen_Project->setShortcut(QKeySequence::Open);
@ -55,9 +67,39 @@ MainWindow::MainWindow(QWidget* parent)
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
m_backgroundThread.quit();
m_backgroundThread.wait();
printf("IM DYING\n"); printf("IM DYING\n");
} }
void MainWindow::connectMessenger(UIMessenger* messenger, Qt::ConnectionType type)
{
connect(messenger, SIGNAL(information(const QString&,
const QString&, QMessageBox::StandardButtons,
QMessageBox::StandardButton)),
this, SLOT(msgInformation(const QString&,
const QString&, QMessageBox::StandardButtons,
QMessageBox::StandardButton)), type);
connect(messenger, SIGNAL(question(const QString&,
const QString&, QMessageBox::StandardButtons,
QMessageBox::StandardButton)),
this, SLOT(msgQuestion(const QString&,
const QString&, QMessageBox::StandardButtons,
QMessageBox::StandardButton)), type);
connect(messenger, SIGNAL(warning(const QString&,
const QString&, QMessageBox::StandardButtons,
QMessageBox::StandardButton)),
this, SLOT(msgWarning(const QString&,
const QString&, QMessageBox::StandardButtons,
QMessageBox::StandardButton)), type);
connect(messenger, SIGNAL(critical(const QString&,
const QString&, QMessageBox::StandardButtons,
QMessageBox::StandardButton)),
this, SLOT(msgCritical(const QString&,
const QString&, QMessageBox::StandardButtons,
QMessageBox::StandardButton)), type);
}
bool MainWindow::setProjectPath(const QString& path) bool MainWindow::setProjectPath(const QString& path)
{ {
if (m_projectModel && m_projectModel->path() == path) if (m_projectModel && m_projectModel->path() == path)
@ -138,14 +180,52 @@ void MainWindow::refreshMIDIIO()
m_ui.menuMIDI->addAction(tr("No MIDI Devices Found"))->setEnabled(false); m_ui.menuMIDI->addAction(tr("No MIDI Devices Found"))->setEnabled(false);
} }
void MainWindow::startBackgroundTask(const QString& windowTitle, const QString& label,
std::function<void(BackgroundTask&)>&& task)
{
assert(m_backgroundTask == nullptr && "existing background process");
setEnabled(false);
m_backgroundTask = new BackgroundTask(std::move(task));
m_backgroundTask->moveToThread(&m_backgroundThread);
m_backgroundDialog = new QProgressDialog(this);
m_backgroundDialog->setWindowTitle(windowTitle);
m_backgroundDialog->setLabelText(label);
m_backgroundDialog->setMinimumWidth(300);
m_backgroundDialog->setAutoClose(false);
m_backgroundDialog->setAutoReset(false);
m_backgroundDialog->setMinimumDuration(0);
m_backgroundDialog->setMinimum(0);
m_backgroundDialog->setMaximum(0);
m_backgroundDialog->setValue(0);
connect(m_backgroundTask, SIGNAL(setMinimum(int)),
m_backgroundDialog, SLOT(setMinimum(int)), Qt::QueuedConnection);
connect(m_backgroundTask, SIGNAL(setMaximum(int)),
m_backgroundDialog, SLOT(setMaximum(int)), Qt::QueuedConnection);
connect(m_backgroundTask, SIGNAL(setValue(int)),
m_backgroundDialog, SLOT(setValue(int)), Qt::QueuedConnection);
connect(m_backgroundTask, SIGNAL(setLabelText(const QString&)),
m_backgroundDialog, SLOT(setLabelText(const QString&)), Qt::QueuedConnection);
connect(m_backgroundTask, SIGNAL(finished()),
this, SLOT(onBackgroundTaskFinished()), Qt::QueuedConnection);
m_backgroundDialog->open(m_backgroundTask, SLOT(cancel()));
connectMessenger(&m_backgroundTask->uiMessenger(), Qt::BlockingQueuedConnection);
QMetaObject::invokeMethod(m_backgroundTask, "run", Qt::QueuedConnection);
}
void MainWindow::newAction() void MainWindow::newAction()
{ {
QString path = QFileDialog::getSaveFileName(this, tr("New Project")); QString path = QFileDialog::getSaveFileName(this, tr("New Project"));
if (path.isEmpty()) if (path.isEmpty())
return; return;
if (!MkPath(path, this)) if (!MkPath(path, m_mainMessenger))
return;
if (!setProjectPath(path))
return; return;
setProjectPath(path);
} }
void MainWindow::openAction() void MainWindow::openAction()
@ -153,7 +233,10 @@ void MainWindow::openAction()
QString path = QFileDialog::getExistingDirectory(this, tr("Open Project")); QString path = QFileDialog::getExistingDirectory(this, tr("Open Project"));
if (path.isEmpty()) if (path.isEmpty())
return; return;
setProjectPath(path); if (!setProjectPath(path))
return;
} }
void MainWindow::importAction() void MainWindow::importAction()
@ -176,8 +259,8 @@ void MainWindow::importAction()
int impMode = QMessageBox::question(this, tr("Sample Import Mode"), int impMode = QMessageBox::question(this, tr("Sample Import Mode"),
tr("Amuse can import samples as WAV files for ease of editing, " tr("Amuse can import samples as WAV files for ease of editing, "
"import original compressed data for lossless repacking, or both. " "import original compressed data for lossless repacking, or both. "
"Exporting the project will prefer compressed files over WAVs, so " "Exporting the project will prefer whichever version was modified "
"be sure to delete the compressed version if you edit the WAV."), "most recently."),
tr("Import Compressed"), tr("Import WAVs"), tr("Import Both")); tr("Import Compressed"), tr("Import WAVs"), tr("Import Both"));
switch (impMode) switch (impMode)
@ -189,6 +272,7 @@ void MainWindow::importAction()
default: default:
return; return;
} }
ProjectModel::ImportMode importMode = ProjectModel::ImportMode(impMode);
/* Special handling for raw groups - gather sibling groups in filesystem */ /* Special handling for raw groups - gather sibling groups in filesystem */
if (tp == amuse::ContainerRegistry::Type::Raw4) if (tp == amuse::ContainerRegistry::Type::Raw4)
@ -211,12 +295,16 @@ void MainWindow::importAction()
QFileInfo fInfo(path); QFileInfo fInfo(path);
QString newPath = QFileInfo(fInfo.dir(), newName).filePath(); QString newPath = QFileInfo(fInfo.dir(), newName).filePath();
if (!MkPath(fInfo.dir(), newName, this)) if (!MkPath(fInfo.dir(), newName, m_mainMessenger))
return; return;
if (!setProjectPath(newPath)) if (!setProjectPath(newPath))
return; return;
} }
ProjectModel* model = m_projectModel;
startBackgroundTask(tr("Importing"), tr("Scanning Project"),
[model, path, importMode](BackgroundTask& task)
{
QDir dir = QFileInfo(path).dir(); QDir dir = QFileInfo(path).dir();
QStringList filters; QStringList filters;
filters << "*.proj" << "*.pro"; filters << "*.proj" << "*.pro";
@ -225,11 +313,18 @@ void MainWindow::importAction()
{ {
auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(dir.filePath(fPath)).c_str()); auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(dir.filePath(fPath)).c_str());
for (auto& p : data) for (auto& p : data)
if (!m_projectModel->importGroupData(SysStringToQString(p.first), std::move(p.second))) {
task.setLabelText(tr("Importing %1").arg(SysStringToQString(p.first)));
if (task.isCanceled())
return;
if (!model->importGroupData(SysStringToQString(p.first), p.second,
importMode, task.uiMessenger()))
return; return;
} }
m_projectModel->extractSamples(ProjectModel::ImportMode(impMode), this); }
m_projectModel->saveToFile(this); });
return; return;
} }
else if (scanMode == QMessageBox::No) else if (scanMode == QMessageBox::No)
@ -245,20 +340,31 @@ void MainWindow::importAction()
{ {
QFileInfo fInfo(path); QFileInfo fInfo(path);
QString newPath = QFileInfo(fInfo.dir(), fInfo.completeBaseName()).filePath(); QString newPath = QFileInfo(fInfo.dir(), fInfo.completeBaseName()).filePath();
if (!MkPath(fInfo.dir(), fInfo.completeBaseName(), this)) if (!MkPath(fInfo.dir(), fInfo.completeBaseName(), m_mainMessenger))
return; return;
if (!setProjectPath(newPath)) if (!setProjectPath(newPath))
return; return;
} }
ProjectModel* model = m_projectModel;
startBackgroundTask(tr("Importing"), tr("Scanning Project"),
[model, path, importMode](BackgroundTask& task)
{
/* Handle single container */ /* Handle single container */
auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(path).c_str()); auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(path).c_str());
task.setMaximum(int(data.size()));
int curVal = 0;
for (auto& p : data) for (auto& p : data)
if (!m_projectModel->importGroupData(SysStringToQString(p.first), std::move(p.second))) {
task.setLabelText(tr("Importing %1").arg(SysStringToQString(p.first)));
if (task.isCanceled())
return; return;
if (!model->importGroupData(SysStringToQString(p.first), p.second,
m_projectModel->extractSamples(ProjectModel::ImportMode(impMode), this); importMode, task.uiMessenger()))
m_projectModel->saveToFile(this); return;
task.setValue(++curVal);
}
});
} }
void MainWindow::exportAction() void MainWindow::exportAction()
@ -395,3 +501,42 @@ void MainWindow::onTextDelete()
le->del(); le->del();
} }
} }
void MainWindow::onBackgroundTaskFinished()
{
m_backgroundDialog->reset();
m_backgroundDialog->deleteLater();
m_backgroundDialog = nullptr;
m_backgroundTask->deleteLater();
m_backgroundTask = nullptr;
m_projectModel->ensureModelData();
setEnabled(true);
}
QMessageBox::StandardButton MainWindow::msgInformation(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton)
{
return QMessageBox::information(this, title, text, buttons, defaultButton);
}
QMessageBox::StandardButton MainWindow::msgQuestion(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton)
{
return QMessageBox::question(this, title, text, buttons, defaultButton);
}
QMessageBox::StandardButton MainWindow::msgWarning(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton)
{
return QMessageBox::warning(this, title, text, buttons, defaultButton);
}
QMessageBox::StandardButton MainWindow::msgCritical(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton)
{
return QMessageBox::critical(this, title, text, buttons, defaultButton);
}

View File

@ -3,6 +3,8 @@
#include <QMainWindow> #include <QMainWindow>
#include <QUndoStack> #include <QUndoStack>
#include <QProgressDialog>
#include <QThread>
#include "ui_MainWindow.h" #include "ui_MainWindow.h"
#include "amuse/Engine.hpp" #include "amuse/Engine.hpp"
#include "amuse/BooBackend.hpp" #include "amuse/BooBackend.hpp"
@ -15,10 +17,35 @@ class MainWindow;
class AudioGroupModel; class AudioGroupModel;
class BackgroundTask : public QObject
{
Q_OBJECT
std::function<void(BackgroundTask&)> m_task;
UIMessenger m_threadMessenger;
bool m_cancelled = false;
public:
explicit BackgroundTask(std::function<void(BackgroundTask&)>&& task)
: m_task(std::move(task)), m_threadMessenger(this) {}
bool isCanceled() const { QCoreApplication::processEvents(); return m_cancelled; }
UIMessenger& uiMessenger() { return m_threadMessenger; }
signals:
void setMinimum(int minimum);
void setMaximum(int maximum);
void setValue(int value);
void setLabelText(const QString& text);
void finished();
public slots:
void run() { m_task(*this); emit finished(); }
void cancel() { m_cancelled = true; }
};
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
Ui::MainWindow m_ui; Ui::MainWindow m_ui;
UIMessenger m_mainMessenger;
ProjectModel* m_projectModel = nullptr; ProjectModel* m_projectModel = nullptr;
AudioGroupModel* m_focusAudioGroup = nullptr; AudioGroupModel* m_focusAudioGroup = nullptr;
@ -38,11 +65,20 @@ class MainWindow : public QMainWindow
QMetaObject::Connection m_deleteConn; QMetaObject::Connection m_deleteConn;
QMetaObject::Connection m_canEditConn; QMetaObject::Connection m_canEditConn;
BackgroundTask* m_backgroundTask = nullptr;
QProgressDialog* m_backgroundDialog = nullptr;
QThread m_backgroundThread;
void connectMessenger(UIMessenger* messenger, Qt::ConnectionType type);
bool setProjectPath(const QString& path); bool setProjectPath(const QString& path);
void setFocusAudioGroup(AudioGroupModel* group); void setFocusAudioGroup(AudioGroupModel* group);
void refreshAudioIO(); void refreshAudioIO();
void refreshMIDIIO(); void refreshMIDIIO();
void startBackgroundTask(const QString& windowTitle, const QString& label,
std::function<void(BackgroundTask&)>&& task);
public: public:
explicit MainWindow(QWidget* parent = Q_NULLPTR); explicit MainWindow(QWidget* parent = Q_NULLPTR);
~MainWindow(); ~MainWindow();
@ -70,6 +106,22 @@ public slots:
void onTextSelect(); void onTextSelect();
void onTextDelete(); void onTextDelete();
void onBackgroundTaskFinished();
QMessageBox::StandardButton msgInformation(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
QMessageBox::StandardButton msgQuestion(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons =
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
QMessageBox::StandardButton msgWarning(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
QMessageBox::StandardButton msgCritical(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
}; };

View File

@ -52,6 +52,9 @@
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget> </widget>
<widget class="QTableView" name="propertyEditor"> <widget class="QTableView" name="propertyEditor">
<property name="sizePolicy"> <property name="sizePolicy">

View File

@ -4,111 +4,250 @@
#include "Common.hpp" #include "Common.hpp"
#include "athena/YAMLDocWriter.hpp" #include "athena/YAMLDocWriter.hpp"
QIcon ProjectModel::GroupNode::Icon;
QIcon ProjectModel::SongGroupNode::Icon;
QIcon ProjectModel::SoundGroupNode::Icon;
ProjectModel::ProjectModel(const QString& path, QObject* parent) ProjectModel::ProjectModel(const QString& path, QObject* parent)
: QAbstractItemModel(parent), m_dir(path) : QAbstractItemModel(parent), m_dir(path)
{ {
m_root = std::make_unique<RootNode>();
GroupNode::Icon = QIcon(":/icons/IconGroup.svg");
SongGroupNode::Icon = QIcon(":/icons/IconSongGroup.svg");
SoundGroupNode::Icon = QIcon(":/icons/IconSoundGroup.svg");
} }
ProjectModel::ProjectGroup::ProjectGroup(amuse::IntrusiveAudioGroupData&& data) bool ProjectModel::importGroupData(const QString& groupName, const amuse::AudioGroupData& data,
: m_data(std::move(data)), ImportMode mode, UIMessenger& messenger)
m_proj(amuse::AudioGroupProject::CreateAudioGroupProject(m_data)),
m_pool(amuse::AudioGroupPool::CreateAudioGroupPool(m_data)),
m_sdir(amuse::AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(m_data))
{}
bool ProjectModel::importGroupData(const QString& groupName, amuse::IntrusiveAudioGroupData&& data)
{ {
setIdDatabases(); m_projectDatabase.setIdDatabases();
ProjectGroup& grp = m_groups.insert(std::make_pair(groupName, std::move(data))).first->second; amuse::AudioGroupDatabase& grp = m_groups.insert(std::make_pair(groupName, data)).first->second;
grp.setIdDatabases(); grp.setIdDatabases();
amuse::AudioGroupProject::BootstrapObjectIDs(grp.m_data); amuse::AudioGroupProject::BootstrapObjectIDs(data);
return true; if (!MkPath(m_dir.path(), messenger))
}
bool ProjectModel::extractSamples(ImportMode mode, QWidget* parent)
{
setIdDatabases();
if (!MkPath(m_dir.path(), parent))
return false; return false;
QDir dir(QFileInfo(m_dir, groupName).filePath());
for (auto& g : m_groups) if (!MkPath(dir.path(), messenger))
{
g.second.setIdDatabases();
QDir dir(QFileInfo(m_dir, g.first).filePath());
if (!MkPath(dir.path(), parent))
return false; return false;
amuse::SystemString sysDir = QStringToSysString(dir.path()); amuse::SystemString sysDir = QStringToSysString(dir.path());
switch (mode) switch (mode)
{ {
case ImportMode::Original: case ImportMode::Original:
g.second.m_sdir.extractAllCompressed(sysDir, g.second.m_data.getSamp()); grp.getSdir().extractAllCompressed(sysDir, data.getSamp());
break; break;
case ImportMode::WAVs: case ImportMode::WAVs:
g.second.m_sdir.extractAllWAV(sysDir, g.second.m_data.getSamp()); grp.getSdir().extractAllWAV(sysDir, data.getSamp());
break; break;
case ImportMode::Both: case ImportMode::Both:
g.second.m_sdir.extractAllCompressed(sysDir, g.second.m_data.getSamp()); grp.getSdir().extractAllWAV(sysDir, data.getSamp());
g.second.m_sdir.extractAllWAV(sysDir, g.second.m_data.getSamp()); grp.getSdir().extractAllCompressed(sysDir, data.getSamp());
break; break;
default: default:
break; break;
} }
}
grp.getProj().toYAML(sysDir);
grp.getPool().toYAML(sysDir);
m_needsReset = true;
return true; return true;
} }
bool ProjectModel::saveToFile(QWidget* parent) bool ProjectModel::saveToFile(UIMessenger& messenger)
{ {
setIdDatabases(); m_projectDatabase.setIdDatabases();
if (!MkPath(m_dir.path(), parent)) if (!MkPath(m_dir.path(), messenger))
return false; return false;
for (auto& g : m_groups) for (auto& g : m_groups)
{ {
QDir dir(QFileInfo(m_dir, g.first).filePath()); QDir dir(QFileInfo(m_dir, g.first).filePath());
if (!MkPath(dir.path(), parent)) if (!MkPath(dir.path(), messenger))
return false; return false;
g.second.setIdDatabases(); g.second.setIdDatabases();
amuse::SystemString groupPath = QStringToSysString(dir.path()); amuse::SystemString groupPath = QStringToSysString(dir.path());
g.second.m_proj.toYAML(groupPath); g.second.getProj().toYAML(groupPath);
g.second.m_pool.toYAML(groupPath); g.second.getPool().toYAML(groupPath);
} }
return true; return true;
} }
QModelIndex ProjectModel::index(int row, int column, const QModelIndex& parent) const void ProjectModel::_resetModelData()
{ {
return createIndex(row, column, nullptr); beginResetModel();
m_projectDatabase.setIdDatabases();
m_root = std::make_unique<RootNode>();
m_root->reserve(m_groups.size());
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
{
it->second.setIdDatabases();
GroupNode& gn = m_root->makeChild<GroupNode>(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();
gn.reserve(songGroups.size() + sfxGroups.size() + 4);
for (const auto& grp : SortUnorderedMap(songGroups))
gn.makeChild<SongGroupNode>(grp.first, grp.second.get());
for (const auto& grp : SortUnorderedMap(sfxGroups))
gn.makeChild<SoundGroupNode>(grp.first, grp.second.get());
if (soundMacros.size())
{
CollectionNode& col =
gn.makeChild<CollectionNode>(tr("Sound Macros"), QIcon(":/icons/IconSoundMacro.svg"));
col.reserve(soundMacros.size());
for (const auto& macro : SortUnorderedMap(soundMacros))
col.makeChild<PoolObjectNode<amuse::SoundMacroId, amuse::SoundMacro>>(macro.first, macro.second.get());
}
if (tables.size())
{
auto tablesSort = SortUnorderedMap(tables);
size_t ADSRCount = 0;
size_t curveCount = 0;
for (auto& t : tablesSort)
{
amuse::ITable::Type tp = t.second.get()->Isa();
if (tp == amuse::ITable::Type::ADSR || tp == amuse::ITable::Type::ADSRDLS)
ADSRCount += 1;
else if (tp == amuse::ITable::Type::Curve)
curveCount += 1;
}
if (ADSRCount)
{
CollectionNode& col =
gn.makeChild<CollectionNode>(tr("ADSRs"), QIcon(":/icons/IconADSR.svg"));
col.reserve(ADSRCount);
for (auto& t : tablesSort)
{
amuse::ITable::Type tp = t.second.get()->Isa();
if (tp == amuse::ITable::Type::ADSR || tp == amuse::ITable::Type::ADSRDLS)
col.makeChild<PoolObjectNode<amuse::TableId, amuse::ITable>>(t.first, *t.second.get());
}
}
if (curveCount)
{
CollectionNode& col =
gn.makeChild<CollectionNode>(tr("Curves"), QIcon(":/icons/IconCurve.svg"));
col.reserve(curveCount);
for (auto& t : tablesSort)
{
amuse::ITable::Type tp = t.second.get()->Isa();
if (tp == amuse::ITable::Type::Curve)
col.makeChild<PoolObjectNode<amuse::TableId, amuse::Curve>>(t.first, static_cast<amuse::Curve&>(*t.second.get()));
}
}
}
if (keymaps.size())
{
CollectionNode& col =
gn.makeChild<CollectionNode>(tr("Keymaps"), QIcon(":/icons/IconKeymap.svg"));
col.reserve(keymaps.size());
for (auto& keymap : SortUnorderedMap(keymaps))
col.makeChild<PoolObjectNode<amuse::KeymapId, amuse::Keymap>>(keymap.first, keymap.second.get());
}
if (layers.size())
{
CollectionNode& col =
gn.makeChild<CollectionNode>(tr("Layers"), QIcon(":/icons/IconLayers.svg"));
col.reserve(layers.size());
for (auto& keymap : SortUnorderedMap(layers))
col.makeChild<PoolObjectNode<amuse::LayersId, std::vector<amuse::LayerMapping>>>(keymap.first, keymap.second.get());
}
}
endResetModel();
} }
QModelIndex ProjectModel::parent(const QModelIndex& child) const void ProjectModel::ensureModelData()
{ {
return {}; if (m_needsReset)
{
_resetModelData();
m_needsReset = false;
}
}
QModelIndex ProjectModel::index(int row, int column, const QModelIndex& parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
INode* parentItem;
if (!parent.isValid())
parentItem = m_root.get();
else
parentItem = static_cast<INode*>(parent.internalPointer());
INode* childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex ProjectModel::parent(const QModelIndex& index) const
{
if (!index.isValid())
return QModelIndex();
INode* childItem = static_cast<INode*>(index.internalPointer());
INode* parentItem = childItem->parent();
if (parentItem == m_root.get())
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
} }
int ProjectModel::rowCount(const QModelIndex& parent) const int ProjectModel::rowCount(const QModelIndex& parent) const
{ {
return 0; INode* parentItem;
if (!parent.isValid())
parentItem = m_root.get();
else
parentItem = static_cast<INode*>(parent.internalPointer());
return parentItem->childCount();
} }
int ProjectModel::columnCount(const QModelIndex& parent) const int ProjectModel::columnCount(const QModelIndex& parent) const
{ {
return 0; return 1;
} }
QVariant ProjectModel::data(const QModelIndex& index, int role) const QVariant ProjectModel::data(const QModelIndex& index, int role) const
{ {
if (!index.isValid())
return QVariant();
INode* item = static_cast<INode*>(index.internalPointer());
switch (role)
{
case Qt::DisplayRole:
return item->text();
case Qt::DecorationRole:
return item->icon();
default:
return {}; return {};
}
}
Qt::ItemFlags ProjectModel::flags(const QModelIndex& index) const
{
if (!index.isValid())
return 0;
return QAbstractItemModel::flags(index);
} }
bool ProjectModel::canDelete() const bool ProjectModel::canDelete() const

View File

@ -3,7 +3,10 @@
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include <QDir> #include <QDir>
#include <QIcon>
#include <map> #include <map>
#include "Common.hpp"
#include "amuse/AudioGroup.hpp"
#include "amuse/AudioGroupData.hpp" #include "amuse/AudioGroupData.hpp"
#include "amuse/AudioGroupProject.hpp" #include "amuse/AudioGroupProject.hpp"
#include "amuse/AudioGroupPool.hpp" #include "amuse/AudioGroupPool.hpp"
@ -19,54 +22,134 @@ public:
WAVs, WAVs,
Both Both
}; };
struct ProjectGroup
{
amuse::IntrusiveAudioGroupData m_data;
amuse::AudioGroupProject m_proj;
amuse::AudioGroupPool m_pool;
amuse::AudioGroupSampleDirectory m_sdir;
amuse::NameDB m_soundMacroDb;
amuse::NameDB m_sampleDb;
amuse::NameDB m_tableDb;
amuse::NameDB m_keymapDb;
amuse::NameDB m_layersDb;
explicit ProjectGroup(amuse::IntrusiveAudioGroupData&& data);
void setIdDatabases()
{
amuse::SoundMacroId::CurNameDB = &m_soundMacroDb;
amuse::SampleId::CurNameDB = &m_sampleDb;
amuse::TableId::CurNameDB = &m_tableDb;
amuse::KeymapId::CurNameDB = &m_keymapDb;
amuse::LayersId::CurNameDB = &m_layersDb;
}
};
private: private:
QDir m_dir; QDir m_dir;
amuse::NameDB m_songDb; amuse::ProjectDatabase m_projectDatabase;
amuse::NameDB m_sfxDb; std::map<QString, amuse::AudioGroupDatabase> m_groups;
std::map<QString, ProjectGroup> m_groups;
void setIdDatabases() class INode
{ {
amuse::SongId::CurNameDB = &m_songDb; enum class Type
amuse::SFXId::CurNameDB = &m_sfxDb; {
Group, // Top-level group
SongGroup,
SfxGroup,
Collection, // Classified object collection, one of the following:
SoundMacro,
ADSR,
Curve,
Keymap,
Layer
};
INode* m_parent;
std::vector<std::unique_ptr<INode>> m_children;
int m_row;
public:
virtual ~INode() = default;
INode(INode* parent, int row) : m_parent(parent), m_row(row) {}
int childCount() const { return int(m_children.size()); }
INode* child(int row) const { return m_children[row].get(); }
INode* parent() const { return m_parent; }
int row() const { return m_row; }
void reserve(size_t sz) { m_children.reserve(sz); }
template<class T, class... _Args>
T& makeChild(_Args&&... args)
{
m_children.push_back(std::make_unique<T>(this, m_children.size(), std::forward<_Args>(args)...));
return static_cast<T&>(*m_children.back());
} }
virtual QString text() const = 0;
virtual QIcon icon() const = 0;
};
struct RootNode : INode
{
RootNode() : INode(nullptr, 0) {}
QString text() const { return {}; }
QIcon icon() const { return {}; }
};
struct GroupNode : INode
{
std::map<QString, amuse::AudioGroupDatabase>::iterator m_it;
GroupNode(INode* parent, int row, std::map<QString, amuse::AudioGroupDatabase>::iterator it)
: INode(parent, row), m_it(it) {}
static QIcon Icon;
QString text() const { return m_it->first; }
QIcon icon() const { return Icon; }
};
struct SongGroupNode : INode
{
amuse::GroupId m_id;
QString m_name;
amuse::SongGroupIndex& m_index;
SongGroupNode(INode* parent, int row, amuse::GroupId id, amuse::SongGroupIndex& index)
: INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {}
static QIcon Icon;
QString text() const { return m_name; }
QIcon icon() const { return Icon; }
};
struct SoundGroupNode : INode
{
amuse::GroupId m_id;
QString m_name;
amuse::SFXGroupIndex& m_index;
SoundGroupNode(INode* parent, int row, amuse::GroupId id, amuse::SFXGroupIndex& index)
: INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {}
static QIcon Icon;
QString text() const { return m_name; }
QIcon icon() const { return Icon; }
};
struct CollectionNode : INode
{
QString m_name;
QIcon m_icon;
CollectionNode(INode* parent, int row, const QString& name, const QIcon& icon)
: INode(parent, row), m_name(name), m_icon(icon) {}
QString text() const { return m_name; }
QIcon icon() const { return m_icon; }
};
template <class ID, class T>
struct PoolObjectNode : INode
{
ID m_id;
QString m_name;
T& m_obj;
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) {}
QString text() const { return m_name; }
QIcon icon() const { return {}; }
};
std::unique_ptr<RootNode> m_root;
bool m_needsReset = false;
void _resetModelData();
public: public:
explicit ProjectModel(const QString& path, QObject* parent = Q_NULLPTR); explicit ProjectModel(const QString& path, QObject* parent = Q_NULLPTR);
bool importGroupData(const QString& groupName, amuse::IntrusiveAudioGroupData&& data); bool importGroupData(const QString& groupName, const amuse::AudioGroupData& data,
bool extractSamples(ImportMode mode, QWidget* parent); ImportMode mode, UIMessenger& messenger);
bool saveToFile(QWidget* parent); bool saveToFile(UIMessenger& messenger);
void ensureModelData();
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex& child) const; QModelIndex parent(const QModelIndex& child) const;
int rowCount(const QModelIndex& parent = QModelIndex()) const; int rowCount(const QModelIndex& parent = QModelIndex()) const;
int columnCount(const QModelIndex& parent = QModelIndex()) const; int columnCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
Qt::ItemFlags flags(const QModelIndex& index) const;
QString path() const { return m_dir.path(); } QString path() const { return m_dir.path(); }
bool canDelete() const; bool canDelete() const;

View File

@ -0,0 +1,81 @@
<?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="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
id="svg2"
version="1.1"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconADSR.svg">
<sodipodi:namedview
id="base"
pagecolor="#393939"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="30.086227"
inkscape:cx="7.2902772"
inkscape:cy="8.0995259"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="1260"
inkscape:window-height="787"
inkscape:window-x="267"
inkscape:window-y="1022"
inkscape:window-maximized="0"
showborder="false"
objecttolerance="4"
gridtolerance="4"
guidetolerance="5">
<inkscape:grid
visible="true"
empspacing="1"
id="grid4173"
type="xygrid" />
</sodipodi:namedview>
<defs
id="defs4" />
<metadata
id="metadata7">
<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
transform="translate(0,-292.76665)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<rect
style="fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.39687499;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="rect1235"
width="3.7041667"
height="3.7041805"
x="0.26458335"
y="293.03122" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 0.26458333,296.7354 1.0583334,293.47246 1.5875,294.35415 H 2.9104167 L 3.96875,296.7354"
id="path1834"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,87 @@
<?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="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
id="svg2"
version="1.1"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconCurve.svg">
<sodipodi:namedview
id="base"
pagecolor="#393939"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="30.086227"
inkscape:cx="-2.7199818"
inkscape:cy="9.4290379"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="1260"
inkscape:window-height="787"
inkscape:window-x="267"
inkscape:window-y="1022"
inkscape:window-maximized="0"
showborder="false"
objecttolerance="4"
gridtolerance="4"
guidetolerance="5">
<inkscape:grid
visible="true"
empspacing="1"
id="grid4173"
type="xygrid" />
</sodipodi:namedview>
<defs
id="defs4" />
<metadata
id="metadata7">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-292.76665)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<rect
style="fill:#00ffcc;fill-opacity:1;stroke:none;stroke-width:0.39687499;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="rect1235"
width="3.7041667"
height="3.7041805"
x="0.26458335"
y="293.03122" />
<path
style="fill:none;stroke:#808080;stroke-width:0.52916667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916667, 0.52916666999999995;stroke-opacity:1;stroke-dashoffset:0"
d="m 0.26458333,292.76665 0,3.96875 H 4.2333333"
id="path1231"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 0,296.7354 c 2.0787582,0 3.96875,-2.11667 3.96875,-3.96875"
id="path1233"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,74 @@
<?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="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
id="svg2"
version="1.1"
inkscape:version="0.91+devel+osxmenu r12922"
sodipodi:docname="IconSoundGroup.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#393939"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="19.66"
inkscape:cx="6.046968"
inkscape:cy="6.9530957"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="1260"
inkscape:window-height="787"
inkscape:window-x="231"
inkscape:window-y="82"
inkscape:window-maximized="0"
showborder="true"
objecttolerance="4"
gridtolerance="4"
guidetolerance="5">
<inkscape:grid
type="xygrid"
id="grid4173"
empspacing="1"
visible="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<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,-292.76665)">
<path
style="opacity:1;fill:#fbd365;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
id="rect4141"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccssssscccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 4.2333332 4.2333335" viewBox="0 0 4.2333332 4.2333335"
id="svg2" id="svg2"
version="1.1" version="1.1"
inkscape:version="0.91+devel+osxmenu r12922" inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconLayers.svg"> sodipodi:docname="IconLayers.svg">
<defs <defs
id="defs4" /> id="defs4" />
@ -26,7 +26,7 @@
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="4.92" inkscape:zoom="4.92"
inkscape:cx="19.961362" inkscape:cx="-13.575223"
inkscape:cy="7.1823475" inkscape:cy="7.1823475"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
@ -34,8 +34,8 @@
units="px" units="px"
inkscape:window-width="1260" inkscape:window-width="1260"
inkscape:window-height="787" inkscape:window-height="787"
inkscape:window-x="131" inkscape:window-x="1749"
inkscape:window-y="148" inkscape:window-y="677"
inkscape:window-maximized="0" inkscape:window-maximized="0"
showborder="false" showborder="false"
objecttolerance="4" objecttolerance="4"
@ -55,7 +55,7 @@
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title> <dc:title />
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,86 @@
<?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="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
id="svg2"
version="1.1"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconNewADSR.svg">
<sodipodi:namedview
id="base"
pagecolor="#393939"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="30.086227"
inkscape:cx="7.2902772"
inkscape:cy="8.0995259"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="1260"
inkscape:window-height="787"
inkscape:window-x="341"
inkscape:window-y="1113"
inkscape:window-maximized="0"
showborder="false"
objecttolerance="4"
gridtolerance="4"
guidetolerance="5">
<inkscape:grid
visible="true"
empspacing="1"
id="grid4173"
type="xygrid" />
</sodipodi:namedview>
<defs
id="defs4" />
<metadata
id="metadata7">
<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
transform="translate(0,-292.76665)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<rect
style="fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.39687499;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="rect1235"
width="3.7041667"
height="3.7041805"
x="0.26458335"
y="293.03122" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 0.26458333,296.7354 1.0583334,293.47246 1.5875,294.35415 H 2.9104167 L 3.96875,296.7354"
id="path1834"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
inkscape:connector-curvature="0"
id="path5323"
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.8386428,295.34071 0.9362114,0.93622 m -0.9362104,-10e-6 0.9362094,-0.9362 m -1.1301062,0.4681 H 3.96875 m -0.6620015,0.662 v -1.324" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,92 @@
<?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="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
id="svg2"
version="1.1"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconNewCurve.svg">
<sodipodi:namedview
id="base"
pagecolor="#393939"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="30.086227"
inkscape:cx="8.2484922"
inkscape:cy="9.4290379"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="1260"
inkscape:window-height="787"
inkscape:window-x="459"
inkscape:window-y="172"
inkscape:window-maximized="0"
showborder="false"
objecttolerance="4"
gridtolerance="4"
guidetolerance="5">
<inkscape:grid
visible="true"
empspacing="1"
id="grid4173"
type="xygrid" />
</sodipodi:namedview>
<defs
id="defs4" />
<metadata
id="metadata7">
<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
transform="translate(0,-292.76665)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<rect
style="fill:#00ffcc;fill-opacity:1;stroke:none;stroke-width:0.39687499;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="rect1235"
width="3.7041667"
height="3.7041805"
x="0.26458335"
y="293.03122" />
<path
style="fill:none;stroke:#808080;stroke-width:0.52916667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916667, 0.52916666999999995;stroke-opacity:1;stroke-dashoffset:0"
d="m 0.26458333,292.76665 0,3.96875 H 4.2333333"
id="path1231"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 0,296.7354 c 2.0787582,0 3.96875,-2.11667 3.96875,-3.96875"
id="path1233"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path5323"
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.8386428,295.34071 0.9362114,0.93622 m -0.9362104,-10e-6 0.9362094,-0.9362 m -1.1301062,0.4681 H 3.96875 m -0.6620015,0.662 v -1.324" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,78 @@
<?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="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
id="svg2"
version="1.1"
inkscape:version="0.91+devel+osxmenu r12922"
sodipodi:docname="NewSoundGroup.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#393939"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="19.66"
inkscape:cx="6.046968"
inkscape:cy="6.9530957"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="1260"
inkscape:window-height="787"
inkscape:window-x="231"
inkscape:window-y="82"
inkscape:window-maximized="0"
showborder="true"
objecttolerance="4"
gridtolerance="4"
guidetolerance="5">
<inkscape:grid
type="xygrid"
id="grid4173"
empspacing="1"
visible="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<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,-292.76665)">
<path
style="opacity:1;fill:#fbd365;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
id="rect4141"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccssssscccc" />
<path
id="path5876"
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.8386428,295.07809 0.9362114,0.93622 m -0.9362104,-1e-5 0.9362094,-0.9362 m -1.1301062,0.4681 1.324003,0 m -0.6620015,0.662 0,-1.324" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -14,8 +14,8 @@
viewBox="0 0 4.2333332 4.2333335" viewBox="0 0 4.2333332 4.2333335"
id="svg2" id="svg2"
version="1.1" version="1.1"
inkscape:version="0.91+devel+osxmenu r12922" inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="NewSongGroup.svg"> sodipodi:docname="IconNewSongGroup.svg">
<defs <defs
id="defs4" /> id="defs4" />
<sodipodi:namedview <sodipodi:namedview
@ -26,7 +26,7 @@
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="29.730996" inkscape:zoom="29.730996"
inkscape:cx="3.7002328" inkscape:cx="3.0052979"
inkscape:cy="9.0045012" inkscape:cy="9.0045012"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
@ -35,7 +35,7 @@
inkscape:window-width="1260" inkscape:window-width="1260"
inkscape:window-height="787" inkscape:window-height="787"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="23" inkscape:window-y="40"
inkscape:window-maximized="0" inkscape:window-maximized="0"
showborder="false" showborder="false"
objecttolerance="4" objecttolerance="4"
@ -55,7 +55,7 @@
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title> <dc:title />
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
@ -65,11 +65,16 @@
id="layer1" id="layer1"
transform="translate(0,-292.76665)"> transform="translate(0,-292.76665)">
<path <path
style="opacity:1;fill:#04e2ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="opacity:1;fill:#ff5599;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z" d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
id="rect4141" id="rect4141"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="cccssssscccc" /> sodipodi:nodetypes="cccssssscccc" />
<path
inkscape:connector-curvature="0"
id="path868"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-miterlimit:4;stroke-dasharray:none"
d="m 1.8675862,295.87272 a 0.57456181,0.36088177 0 0 1 -0.5745618,0.36089 0.57456181,0.36088177 0 0 1 -0.57456172,-0.36089 0.57456181,0.36088177 0 0 1 0.57456172,-0.36088 0.57456181,0.36088177 0 0 1 0.5745618,0.36088 z m 1.3298265,-0.001 a 0.57456181,0.36088177 0 0 1 -0.5745619,0.36089 0.57456181,0.36088177 0 0 1 -0.5745618,-0.36089 0.57456181,0.36088177 0 0 1 0.5745618,-0.36088 0.57456181,0.36088177 0 0 1 0.5745619,0.36088 z m -0.253445,-1.78193 0.253445,0.006 v 1.77617 c -0.2177221,0.0701 -0.286996,-0.0173 -0.3755473,-0.1676 l 0.00387,-0.79478 H 1.868454 v 0.95424 c -0.2323614,-0.008 -0.2369279,-0.14254 -0.3755412,-0.22458 v -1.54879 z" />
<path <path
id="path5323" id="path5323"
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -14,8 +14,8 @@
viewBox="0 0 4.2333332 4.2333335" viewBox="0 0 4.2333332 4.2333335"
id="svg2" id="svg2"
version="1.1" version="1.1"
inkscape:version="0.91+devel+osxmenu r12922" inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="NewSoundGroup.svg"> sodipodi:docname="IconNewSoundGroup.svg">
<defs <defs
id="defs4" /> id="defs4" />
<sodipodi:namedview <sodipodi:namedview
@ -25,17 +25,17 @@
borderopacity="1.0" borderopacity="1.0"
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="19.66" inkscape:zoom="31.94"
inkscape:cx="6.046968" inkscape:cx="9.7896878"
inkscape:cy="6.9530957" inkscape:cy="6.9530957"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
showgrid="true" showgrid="true"
units="px" units="px"
inkscape:window-width="1260" inkscape:window-width="1260"
inkscape:window-height="787" inkscape:window-height="777"
inkscape:window-x="231" inkscape:window-x="2038"
inkscape:window-y="82" inkscape:window-y="1136"
inkscape:window-maximized="0" inkscape:window-maximized="0"
showborder="true" showborder="true"
objecttolerance="4" objecttolerance="4"
@ -55,7 +55,7 @@
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title> <dc:title />
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
@ -65,11 +65,17 @@
id="layer1" id="layer1"
transform="translate(0,-292.76665)"> transform="translate(0,-292.76665)">
<path <path
style="opacity:1;fill:#fbd365;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="opacity:1;fill:#04e2ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z" d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
id="rect4141" id="rect4141"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="cccssssscccc" /> sodipodi:nodetypes="cccssssscccc" />
<path
id="path1184"
title="sin(x*4*pi)*sin(x*pi)"
d="m 0.52916699,295.1479 c 0.11759258,-1.5e-4 0.23518516,-0.18652 0.35277774,-0.31191 0.11759258,-0.1254 0.23518517,-0.1236 0.35277777,0.10832 0.1175926,0.23193 0.2351851,0.66463 0.3527777,0.89812 0.1175926,0.23349 0.2351852,0.20457 0.3527778,-0.10832 0.1175925,-0.3129 0.2351851,-0.85907 0.3527777,-1.17242 0.1175926,-0.31334 0.2351852,-0.3414 0.3527777,-0.10832 0.1175926,0.23308 0.2351852,0.66584 0.3527778,0.89812 0.1175926,0.23228 0.2351851,0.23355 0.3527778,0.10832 0.1175925,-0.12522 0.235185,-0.31176 0.3527777,-0.31191"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
inkscape:connector-curvature="0" />
<path <path
id="path5876" id="path5876"
style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="fill:#ff0000;fill-rule:evenodd;stroke:#df0000;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 4.2333332 4.2333335" viewBox="0 0 4.2333332 4.2333335"
id="svg2" id="svg2"
version="1.1" version="1.1"
inkscape:version="0.91+devel+osxmenu r12922" inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconSongGroup.svg"> sodipodi:docname="IconSongGroup.svg">
<defs <defs
id="defs4" /> id="defs4" />
@ -25,17 +25,17 @@
borderopacity="1.0" borderopacity="1.0"
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="29.730996" inkscape:zoom="34.350339"
inkscape:cx="3.7002328" inkscape:cx="8.8858389"
inkscape:cy="9.0045012" inkscape:cy="8.8343343"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
showgrid="true" showgrid="true"
units="px" units="px"
inkscape:window-width="1260" inkscape:window-width="1260"
inkscape:window-height="787" inkscape:window-height="787"
inkscape:window-x="0" inkscape:window-x="1944"
inkscape:window-y="23" inkscape:window-y="288"
inkscape:window-maximized="0" inkscape:window-maximized="0"
showborder="false" showborder="false"
objecttolerance="4" objecttolerance="4"
@ -45,7 +45,7 @@
type="xygrid" type="xygrid"
id="grid4173" id="grid4173"
empspacing="1" empspacing="1"
visible="false" /> visible="true" />
</sodipodi:namedview> </sodipodi:namedview>
<metadata <metadata
id="metadata7"> id="metadata7">
@ -65,10 +65,19 @@
id="layer1" id="layer1"
transform="translate(0,-292.76665)"> transform="translate(0,-292.76665)">
<path <path
style="opacity:1;fill:#04e2ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="opacity:1;fill:#ff5599;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z" d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
id="rect4141" id="rect4141"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="cccssssscccc" /> sodipodi:nodetypes="cccssssscccc" />
<g
aria-label="♬"
style="font-style:normal;font-weight:normal;font-size:1.66674709px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.31251505"
id="text820"
transform="matrix(1.1529095,0,0,1.1529095,-0.32840767,-44.985003)" />
<path
id="path868"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-miterlimit:4;stroke-dasharray:none"
d="m 1.8675862,295.87272 a 0.57456183,0.36088178 0 0 1 -0.5745618,0.36089 0.57456183,0.36088178 0 0 1 -0.57456171,-0.36089 0.57456183,0.36088178 0 0 1 0.57456171,-0.36088 0.57456183,0.36088178 0 0 1 0.5745618,0.36088 z m 1.3298265,-0.001 a 0.57456183,0.36088178 0 0 1 -0.5745619,0.36089 0.57456183,0.36088178 0 0 1 -0.5745618,-0.36089 0.57456183,0.36088178 0 0 1 0.5745618,-0.36088 0.57456183,0.36088178 0 0 1 0.5745619,0.36088 z m -0.253445,-1.78193 0.253445,0.006 v 1.77617 c -0.2177221,0.0701 -0.286996,-0.0173 -0.3755473,-0.1676 l 0.00387,-0.79478 H 1.868454 v 0.95424 c -0.2323614,-0.008 -0.2369279,-0.14254 -0.3755412,-0.22458 v -1.54879 z" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -14,10 +14,8 @@
viewBox="0 0 4.2333332 4.2333335" viewBox="0 0 4.2333332 4.2333335"
id="svg2" id="svg2"
version="1.1" version="1.1"
inkscape:version="0.91+devel+osxmenu r12922" inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconSoundGroup.svg"> sodipodi:docname="IconSoundGroup.svg">
<defs
id="defs4" />
<sodipodi:namedview <sodipodi:namedview
id="base" id="base"
pagecolor="#393939" pagecolor="#393939"
@ -25,28 +23,30 @@
borderopacity="1.0" borderopacity="1.0"
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="19.66" inkscape:zoom="34.25"
inkscape:cx="6.046968" inkscape:cx="8.0808195"
inkscape:cy="6.9530957" inkscape:cy="8.452632"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
showgrid="true" showgrid="true"
units="px" units="px"
inkscape:window-width="1260" inkscape:window-width="1258"
inkscape:window-height="787" inkscape:window-height="787"
inkscape:window-x="231" inkscape:window-x="1970"
inkscape:window-y="82" inkscape:window-y="1150"
inkscape:window-maximized="0" inkscape:window-maximized="0"
showborder="true" showborder="false"
objecttolerance="4" objecttolerance="4"
gridtolerance="4" gridtolerance="4"
guidetolerance="5"> guidetolerance="5">
<inkscape:grid <inkscape:grid
type="xygrid" visible="true"
id="grid4173"
empspacing="1" empspacing="1"
visible="true" /> id="grid4173"
type="xygrid" />
</sodipodi:namedview> </sodipodi:namedview>
<defs
id="defs4" />
<metadata <metadata
id="metadata7"> id="metadata7">
<rdf:RDF> <rdf:RDF>
@ -60,15 +60,21 @@
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
<g <g
inkscape:label="Layer 1" transform="translate(0,-292.76665)"
inkscape:groupmode="layer"
id="layer1" id="layer1"
transform="translate(0,-292.76665)"> inkscape:groupmode="layer"
inkscape:label="Layer 1">
<path <path
style="opacity:1;fill:#fbd365;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" sodipodi:nodetypes="cccssssscccc"
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
id="rect4141"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="cccssssscccc" /> id="rect4141"
d="m 1.3229167,293.04538 c 0.2645833,0 0.5291666,0.25044 0.5291666,0.51502 l 0,0.26458 1.8488138,0.0102 c 0.3165926,0.002 0.5239173,0.20975 0.5245413,0.52471 l 0.00313,1.57936 c 6.239e-4,0.31495 -0.2079439,0.53411 -0.5245413,0.53411 l -3.17666623,0 C 0.21076252,296.47339 0,296.2566 0,295.94165 c 4.054e-5,-0.82258 0,-2.38125 0,-2.38125 0,-0.26458 0.26458333,-0.51612 0.52916667,-0.51612 z"
style="opacity:1;fill:#04e2ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.67643285;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path1184"
title="sin(x*4*pi)*sin(x*pi)"
d="m 0.52916698,295.1479 c 0.11759258,-1.5e-4 0.23518516,-0.18652 0.35277775,-0.31191 0.11759258,-0.1254 0.23518517,-0.1236 0.35277777,0.10832 0.1175926,0.23193 0.2351851,0.66463 0.3527777,0.89812 0.1175926,0.23349 0.2351852,0.20457 0.3527778,-0.10832 0.1175925,-0.3129 0.2351851,-0.85907 0.3527777,-1.17242 0.1175926,-0.31334 0.2351852,-0.3414 0.3527777,-0.10832 0.1175926,0.23308 0.2351852,0.66584 0.3527778,0.89812 0.1175926,0.23228 0.2351852,0.23355 0.3527777,0.10832 0.1175926,-0.12522 0.2351852,-0.31176 0.3527778,-0.31191"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;stroke-linecap:round;paint-order:normal"
inkscape:connector-curvature="0" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -13,6 +13,12 @@
<file>IconSongGroup.svg</file> <file>IconSongGroup.svg</file>
<file>IconSoundGroup.svg</file> <file>IconSoundGroup.svg</file>
<file>IconSoundMacro.svg</file> <file>IconSoundMacro.svg</file>
<file>IconGroup.svg</file>
<file>IconNewGroup.svg</file>
<file>IconADSR.svg</file>
<file>IconNewADSR.svg</file>
<file>IconCurve.svg</file>
<file>IconNewCurve.svg</file>
</qresource> </qresource>
<qresource prefix="/bg"> <qresource prefix="/bg">
<file>FaceGrey.svg</file> <file>FaceGrey.svg</file>

View File

@ -29,6 +29,48 @@ public:
const AudioGroupProject& getProj() const { return m_proj; } const AudioGroupProject& getProj() const { return m_proj; }
const AudioGroupPool& getPool() const { return m_pool; } const AudioGroupPool& getPool() const { return m_pool; }
const AudioGroupSampleDirectory& getSdir() const { return m_sdir; } const AudioGroupSampleDirectory& getSdir() const { return m_sdir; }
AudioGroupProject& getProj() { return m_proj; }
AudioGroupPool& getPool() { return m_pool; }
AudioGroupSampleDirectory& getSdir() { return m_sdir; }
};
class AudioGroupDatabase : public AudioGroup
{
amuse::NameDB m_soundMacroDb;
amuse::NameDB m_sampleDb;
amuse::NameDB m_tableDb;
amuse::NameDB m_keymapDb;
amuse::NameDB m_layersDb;
public:
explicit AudioGroupDatabase(const AudioGroupData& data)
: AudioGroup(data) {}
explicit AudioGroupDatabase(SystemStringView groupPath)
: AudioGroup(groupPath) {}
void setIdDatabases()
{
amuse::SoundMacroId::CurNameDB = &m_soundMacroDb;
amuse::SampleId::CurNameDB = &m_sampleDb;
amuse::TableId::CurNameDB = &m_tableDb;
amuse::KeymapId::CurNameDB = &m_keymapDb;
amuse::LayersId::CurNameDB = &m_layersDb;
}
};
class ProjectDatabase
{
amuse::NameDB m_songDb;
amuse::NameDB m_sfxDb;
amuse::NameDB m_groupDb;
public:
void setIdDatabases()
{
amuse::SongId::CurNameDB = &m_songDb;
amuse::SFXId::CurNameDB = &m_sfxDb;
amuse::GroupId::CurNameDB = &m_groupDb;
}
}; };
} }

View File

@ -664,7 +664,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -676,7 +676,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -688,7 +688,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -700,7 +700,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -712,7 +712,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -724,7 +724,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -736,7 +736,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -748,7 +748,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -760,7 +760,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -772,7 +772,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -784,7 +784,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -796,7 +796,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -808,7 +808,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -820,7 +820,7 @@ struct SoundMacro
AT_DECL_DNAV AT_DECL_DNAV
Value<atUint8> midiControl; Value<atUint8> midiControl;
Value<atUint16> scalingPercentage; Value<atUint16> scalingPercentage;
Value<bool> combine; Value<atInt8> combine;
Value<bool> isVar; Value<bool> isVar;
Value<atUint8> fineScaling; Value<atUint8> fineScaling;
bool Do(SoundMacroState& st, Voice& vox) const; bool Do(SoundMacroState& st, Voice& vox) const;
@ -1156,6 +1156,15 @@ public:
static AudioGroupPool CreateAudioGroupPool(const AudioGroupData& data); static AudioGroupPool CreateAudioGroupPool(const AudioGroupData& data);
static AudioGroupPool CreateAudioGroupPool(SystemStringView groupPath); static AudioGroupPool CreateAudioGroupPool(SystemStringView groupPath);
const std::unordered_map<SoundMacroId, SoundMacro>& soundMacros() const { return m_soundMacros; }
const std::unordered_map<TableId, std::unique_ptr<ITable>>& tables() const { return m_tables; }
const std::unordered_map<KeymapId, Keymap>& keymaps() const { return m_keymaps; }
const std::unordered_map<LayersId, std::vector<LayerMapping>>& layers() const { return m_layers; }
std::unordered_map<SoundMacroId, SoundMacro>& soundMacros() { return m_soundMacros; }
std::unordered_map<TableId, std::unique_ptr<ITable>>& tables() { return m_tables; }
std::unordered_map<KeymapId, Keymap>& keymaps() { return m_keymaps; }
std::unordered_map<LayersId, std::vector<LayerMapping>>& layers() { return m_layers; }
const SoundMacro* soundMacro(ObjectId id) const; const SoundMacro* soundMacro(ObjectId id) const;
const Keymap* keymap(ObjectId id) const; const Keymap* keymap(ObjectId id) const;
const std::vector<LayerMapping>* layer(ObjectId id) const; const std::vector<LayerMapping>* layer(ObjectId id) const;
@ -1164,6 +1173,11 @@ public:
const Curve* tableAsCurves(ObjectId id) const; const Curve* tableAsCurves(ObjectId id) const;
bool toYAML(SystemStringView groupPath) const; bool toYAML(SystemStringView groupPath) const;
AudioGroupPool(const AudioGroupPool&) = delete;
AudioGroupPool& operator=(const AudioGroupPool&) = delete;
AudioGroupPool(AudioGroupPool&&) = default;
AudioGroupPool& operator=(AudioGroupPool&&) = default;
}; };
} }

View File

@ -25,7 +25,7 @@ GroupHeader : BigDNA
{ {
AT_DECL_DNA AT_DECL_DNA
Value<atUint32, DNAEn> groupEndOff; Value<atUint32, DNAEn> groupEndOff;
Value<atUint16, DNAEn> groupId; GroupIdDNA<DNAEn> groupId;
Value<GroupType, DNAEn> type; Value<GroupType, DNAEn> type;
Value<atUint32, DNAEn> soundMacroIdsOff; Value<atUint32, DNAEn> soundMacroIdsOff;
Value<atUint32, DNAEn> samplIdsOff; Value<atUint32, DNAEn> samplIdsOff;
@ -180,8 +180,8 @@ struct SFXGroupIndex : AudioGroupIndex
/** Collection of SongGroup and SFXGroup indexes */ /** Collection of SongGroup and SFXGroup indexes */
class AudioGroupProject class AudioGroupProject
{ {
std::unordered_map<int, SongGroupIndex> m_songGroups; std::unordered_map<GroupId, SongGroupIndex> m_songGroups;
std::unordered_map<int, SFXGroupIndex> m_sfxGroups; std::unordered_map<GroupId, SFXGroupIndex> m_sfxGroups;
AudioGroupProject() = default; AudioGroupProject() = default;
AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag); AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag);
@ -199,10 +199,17 @@ public:
const SongGroupIndex* getSongGroupIndex(int groupId) const; const SongGroupIndex* getSongGroupIndex(int groupId) const;
const SFXGroupIndex* getSFXGroupIndex(int groupId) const; const SFXGroupIndex* getSFXGroupIndex(int groupId) const;
const std::unordered_map<int, SongGroupIndex>& songGroups() const { return m_songGroups; } const std::unordered_map<GroupId, SongGroupIndex>& songGroups() const { return m_songGroups; }
const std::unordered_map<int, SFXGroupIndex>& sfxGroups() const { return m_sfxGroups; } const std::unordered_map<GroupId, SFXGroupIndex>& sfxGroups() const { return m_sfxGroups; }
std::unordered_map<GroupId, SongGroupIndex>& songGroups() { return m_songGroups; }
std::unordered_map<GroupId, SFXGroupIndex>& sfxGroups() { return m_sfxGroups; }
bool toYAML(SystemStringView groupPath) const; bool toYAML(SystemStringView groupPath) const;
AudioGroupProject(const AudioGroupProject&) = delete;
AudioGroupProject& operator=(const AudioGroupProject&) = delete;
AudioGroupProject(AudioGroupProject&&) = default;
AudioGroupProject& operator=(AudioGroupProject&&) = default;
}; };
} }

View File

@ -268,6 +268,11 @@ public:
void extractAllWAV(amuse::SystemStringView destDir, const unsigned char* samp) const; void extractAllWAV(amuse::SystemStringView destDir, const unsigned char* samp) const;
void extractCompressed(SampleId id, amuse::SystemStringView destDir, const unsigned char* samp) const; void extractCompressed(SampleId id, amuse::SystemStringView destDir, const unsigned char* samp) const;
void extractAllCompressed(amuse::SystemStringView destDir, const unsigned char* samp) const; void extractAllCompressed(amuse::SystemStringView destDir, const unsigned char* samp) const;
AudioGroupSampleDirectory(const AudioGroupSampleDirectory&) = delete;
AudioGroupSampleDirectory& operator=(const AudioGroupSampleDirectory&) = delete;
AudioGroupSampleDirectory(AudioGroupSampleDirectory&&) = default;
AudioGroupSampleDirectory& operator=(AudioGroupSampleDirectory&&) = default;
}; };
} }

View File

@ -86,6 +86,7 @@ DECL_ID_TYPE(KeymapId)
DECL_ID_TYPE(LayersId) DECL_ID_TYPE(LayersId)
DECL_ID_TYPE(SongId) DECL_ID_TYPE(SongId)
DECL_ID_TYPE(SFXId) DECL_ID_TYPE(SFXId)
DECL_ID_TYPE(GroupId)
/* MusyX has object polymorphism between Keymaps and Layers when /* MusyX has object polymorphism between Keymaps and Layers when
* referenced by a song group's page object. When the upper bit is set, * referenced by a song group's page object. When the upper bit is set,
@ -417,12 +418,26 @@ struct PCDataTag
{ {
}; };
template <class T>
static std::vector<std::pair<typename T::key_type,
std::reference_wrapper<typename T::mapped_type>>> SortUnorderedMap(T& um)
{
std::vector<std::pair<typename T::key_type, std::reference_wrapper<typename T::mapped_type>>> ret;
ret.reserve(um.size());
for (auto& p : um)
ret.emplace_back(p.first, p.second);
std::sort(ret.begin(), ret.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
return ret;
}
template <class T> template <class T>
static std::vector<std::pair<typename T::key_type, static std::vector<std::pair<typename T::key_type,
std::reference_wrapper<const typename T::mapped_type>>> SortUnorderedMap(const T& um) std::reference_wrapper<const typename T::mapped_type>>> SortUnorderedMap(const T& um)
{ {
std::vector<std::pair<typename T::key_type, std::vector<std::pair<typename T::key_type, std::reference_wrapper<const typename T::mapped_type>>> ret;
std::reference_wrapper<const typename T::mapped_type>>> ret(um.cbegin(), um.cend()); ret.reserve(um.size());
for (const auto& p : um)
ret.emplace_back(p.first, p.second);
std::sort(ret.begin(), ret.end(), [](const auto& a, const auto& b) { return a.first < b.first; }); std::sort(ret.begin(), ret.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
return ret; return ret;
} }
@ -444,6 +459,7 @@ DECL_ID_HASH(KeymapId)
DECL_ID_HASH(LayersId) DECL_ID_HASH(LayersId)
DECL_ID_HASH(SongId) DECL_ID_HASH(SongId)
DECL_ID_HASH(SFXId) DECL_ID_HASH(SFXId)
DECL_ID_HASH(GroupId)
} }
namespace amuse namespace amuse
@ -458,6 +474,7 @@ struct NameDB
Layer, Layer,
Song, Song,
SFX, SFX,
Group,
Sample Sample
}; };

View File

@ -210,6 +210,15 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(const AudioGroupDat
} }
} }
std::string ParseStringSlashId(const std::string& str, uint16_t& idOut)
{
size_t slashPos = str.find('/');
if (slashPos == std::string::npos)
return {};
idOut = uint16_t(strtoul(str.data() + slashPos + 1, nullptr, 0));
return {str.begin(), str.begin() + slashPos};
}
AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView groupPath) AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView groupPath)
{ {
AudioGroupProject ret; AudioGroupProject ret;
@ -222,15 +231,20 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr
athena::io::YAMLDocReader r; athena::io::YAMLDocReader r;
if (r.parse(&fi) && r.ValidateClassType("amuse::Project")) if (r.parse(&fi) && r.ValidateClassType("amuse::Project"))
{ {
size_t songGroupCount; if (auto __v = r.enterSubRecord("songGroups"))
if (auto __v = r.enterSubVector("songGroups", songGroupCount))
{ {
ret.m_songGroups.reserve(songGroupCount); ret.m_songGroups.reserve(r.getCurNode()->m_mapChildren.size());
for (int g = 0; g < songGroupCount; ++g) for (const auto& grp : r.getCurNode()->m_mapChildren)
{ {
if (auto __r = r.enterSubRecord(nullptr)) if (auto __r = r.enterSubRecord(grp.first.c_str()))
{ {
SongGroupIndex& idx = ret.m_songGroups[g]; uint16_t groupId;
std::string groupName = ParseStringSlashId(grp.first, groupId);
if (groupName.empty() || groupId == 0xffff)
continue;
GroupId::CurNameDB->registerPair(groupName, groupId);
SongGroupIndex& idx = ret.m_songGroups[groupId];
if (auto __v2 = r.enterSubRecord("normPages")) if (auto __v2 = r.enterSubRecord("normPages"))
{ {
idx.m_normPages.reserve(r.getCurNode()->m_mapChildren.size()); idx.m_normPages.reserve(r.getCurNode()->m_mapChildren.size());
@ -253,8 +267,12 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr
size_t chanCount; size_t chanCount;
if (auto __v3 = r.enterSubVector(song.first.c_str(), chanCount)) if (auto __v3 = r.enterSubVector(song.first.c_str(), chanCount))
{ {
ObjectId songId = SongId::CurNameDB->generateId(NameDB::Type::Song); uint16_t songId;
SongId::CurNameDB->registerPair(song.first, songId); std::string songName = ParseStringSlashId(song.first, songId);
if (songName.empty() || songId == 0xffff)
continue;
SongId::CurNameDB->registerPair(songName, songId);
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId]; std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
for (int i = 0; i < 16 && i < chanCount; ++i) for (int i = 0; i < 16 && i < chanCount; ++i)
if (auto __r2 = r.enterSubRecord(nullptr)) if (auto __r2 = r.enterSubRecord(nullptr))
@ -266,20 +284,28 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr
} }
} }
size_t sfxGroupCount; if (auto __v = r.enterSubRecord("sfxGroups"))
if (auto __v = r.enterSubVector("sfxGroups", sfxGroupCount))
{ {
ret.m_sfxGroups.reserve(sfxGroupCount); ret.m_sfxGroups.reserve(r.getCurNode()->m_mapChildren.size());
for (int g = 0; g < sfxGroupCount; ++g) for (const auto& grp : r.getCurNode()->m_mapChildren)
{ {
if (auto __r = r.enterSubRecord(nullptr)) if (auto __r = r.enterSubRecord(nullptr))
{ {
SFXGroupIndex& idx = ret.m_sfxGroups[g]; uint16_t groupId;
std::string groupName = ParseStringSlashId(grp.first, groupId);
if (groupName.empty() || groupId == 0xffff)
continue;
GroupId::CurNameDB->registerPair(groupName, groupId);
SFXGroupIndex& idx = ret.m_sfxGroups[groupId];
for (const auto& sfx : r.getCurNode()->m_mapChildren) for (const auto& sfx : r.getCurNode()->m_mapChildren)
if (auto __r2 = r.enterSubRecord(sfx.first.c_str())) if (auto __r2 = r.enterSubRecord(sfx.first.c_str()))
{ {
ObjectId sfxId = SFXId::CurNameDB->generateId(NameDB::Type::SFX); uint16_t sfxId;
SFXId::CurNameDB->registerPair(sfx.first, sfxId); std::string sfxName = ParseStringSlashId(sfx.first, sfxId);
if (sfxName.empty() || sfxId == 0xffff)
continue;
SFXId::CurNameDB->registerPair(sfxName, sfxId);
idx.m_sfxEntries[sfxId].read(r); idx.m_sfxEntries[sfxId].read(r);
} }
} }
@ -321,6 +347,8 @@ void AudioGroupProject::BootstrapObjectIDs(athena::io::IStreamReader& r, GCNData
GroupHeader<athena::Big> header; GroupHeader<athena::Big> header;
header.read(r); header.read(r);
GroupId::CurNameDB->registerPair(NameDB::generateName(header.groupId, NameDB::Type::Group), header.groupId);
/* Sound Macros */ /* Sound Macros */
r.seek(header.soundMacroIdsOff, athena::Begin); r.seek(header.soundMacroIdsOff, athena::Begin);
while (!AtEnd16(r)) while (!AtEnd16(r))
@ -386,6 +414,8 @@ void AudioGroupProject::BootstrapObjectIDs(athena::io::IStreamReader& r, bool ab
GroupHeader<DNAE> header; GroupHeader<DNAE> header;
header.read(r); header.read(r);
GroupId::CurNameDB->registerPair(NameDB::generateName(header.groupId, NameDB::Type::Group), header.groupId);
/* Sound Macros */ /* Sound Macros */
r.seek(subDataOff + header.soundMacroIdsOff, athena::Begin); r.seek(subDataOff + header.soundMacroIdsOff, athena::Begin);
while (!AtEnd16(r)) while (!AtEnd16(r))
@ -501,11 +531,13 @@ bool AudioGroupProject::toYAML(SystemStringView groupPath) const
if (!m_songGroups.empty()) if (!m_songGroups.empty())
{ {
if (auto __v = w.enterSubVector("songGroups")) if (auto __v = w.enterSubRecord("songGroups"))
{ {
for (const auto& p : SortUnorderedMap(m_songGroups)) for (const auto& p : SortUnorderedMap(m_songGroups))
{ {
if (auto __r = w.enterSubRecord(nullptr)) char groupString[64];
snprintf(groupString, 64, "%s/0x%04X", GroupId::CurNameDB->resolveNameFromId(p.first).data(), int(p.first.id));
if (auto __r = w.enterSubRecord(groupString))
{ {
if (!p.second.get().m_normPages.empty()) if (!p.second.get().m_normPages.empty())
{ {
@ -545,7 +577,9 @@ bool AudioGroupProject::toYAML(SystemStringView groupPath) const
{ {
for (const auto& song : SortUnorderedMap(p.second.get().m_midiSetups)) for (const auto& song : SortUnorderedMap(p.second.get().m_midiSetups))
{ {
if (auto __v3 = w.enterSubVector(SongId::CurNameDB->resolveNameFromId(song.first).data())) char songString[64];
snprintf(songString, 64, "%s/0x%04X", SongId::CurNameDB->resolveNameFromId(song.first).data(), int(song.first.id));
if (auto __v3 = w.enterSubVector(songString))
for (int i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i)
if (auto __r2 = w.enterSubRecord(nullptr)) if (auto __r2 = w.enterSubRecord(nullptr))
{ {
@ -562,15 +596,19 @@ bool AudioGroupProject::toYAML(SystemStringView groupPath) const
if (!m_sfxGroups.empty()) if (!m_sfxGroups.empty())
{ {
if (auto __v = w.enterSubVector("sfxGroups")) if (auto __v = w.enterSubRecord("sfxGroups"))
{ {
for (const auto& p : SortUnorderedMap(m_sfxGroups)) for (const auto& p : SortUnorderedMap(m_sfxGroups))
{ {
if (auto __r = w.enterSubRecord(nullptr)) char groupString[64];
snprintf(groupString, 64, "%s/0x%04X", GroupId::CurNameDB->resolveNameFromId(p.first).data(), int(p.first.id));
if (auto __r = w.enterSubRecord(groupString))
{ {
for (const auto& sfx : SortUnorderedMap(p.second.get().m_sfxEntries)) for (const auto& sfx : SortUnorderedMap(p.second.get().m_sfxEntries))
{ {
if (auto __r2 = w.enterSubRecord(SFXId::CurNameDB->resolveNameFromId(sfx.first).data())) char sfxString[64];
snprintf(sfxString, 64, "%s/0x%04X", SFXId::CurNameDB->resolveNameFromId(sfx.first).data(), int(sfx.first.id));
if (auto __r2 = w.enterSubRecord(sfxString))
{ {
w.setStyle(athena::io::YAMLNodeStyle::Flow); w.setStyle(athena::io::YAMLNodeStyle::Flow);
sfx.second.get().write(w); sfx.second.get().write(w);

View File

@ -146,11 +146,23 @@ static uint32_t DSPNibbleToSample(uint32_t nibble)
void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath) void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath)
{ {
Sstat theStat; SystemString wavPath = SystemString(basePath) + _S(".wav");
SystemString filePath = SystemString(basePath) + _S(".dsp"); SystemString dspPath = SystemString(basePath) + _S(".dsp");
if (!Stat(filePath.c_str(), &theStat) && (!m_looseData || theStat.st_mtime > m_looseModTime)) Sstat wavStat, dspStat;
bool wavValid = !Stat(wavPath.c_str(), &wavStat) && S_ISREG(wavStat.st_mode);
bool dspValid = !Stat(dspPath.c_str(), &dspStat) && S_ISREG(dspStat.st_mode);
if (wavValid && dspValid)
{ {
athena::io::FileReader r(filePath); if (wavStat.st_mtime > dspStat.st_mtime)
dspValid = false;
else
wavValid = false;
}
if (dspValid && (!m_looseData || dspStat.st_mtime > m_looseModTime))
{
athena::io::FileReader r(dspPath);
if (!r.hasError()) if (!r.hasError())
{ {
DSPADPCMHeader header; DSPADPCMHeader header;
@ -175,13 +187,14 @@ void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath)
m_looseData.reset(new uint8_t[dataLen]); m_looseData.reset(new uint8_t[dataLen]);
r.readUBytesToBuf(m_looseData.get(), dataLen); r.readUBytesToBuf(m_looseData.get(), dataLen);
m_looseModTime = theStat.st_mtime; m_looseModTime = dspStat.st_mtime;
return; return;
} }
} }
if (!Stat(filePath.c_str(), &theStat) && (!m_looseData || theStat.st_mtime > m_looseModTime))
if (wavValid && (!m_looseData || wavStat.st_mtime > m_looseModTime))
{ {
athena::io::FileReader r(filePath); athena::io::FileReader r(wavPath);
if (!r.hasError()) if (!r.hasError())
{ {
atUint32 riffMagic = r.readUint32Little(); atUint32 riffMagic = r.readUint32Little();
@ -216,7 +229,6 @@ void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath)
m_loopStartSample = loop.start; m_loopStartSample = loop.start;
m_loopLengthSamples = loop.end - loop.start + 1; m_loopLengthSamples = loop.end - loop.start + 1;
} }
} }
else if (chunkMagic == SBIG('data')) else if (chunkMagic == SBIG('data'))
{ {
@ -227,7 +239,7 @@ void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath)
r.seek(startPos + chunkSize, athena::Begin); r.seek(startPos + chunkSize, athena::Begin);
} }
m_looseModTime = theStat.st_mtime; m_looseModTime = wavStat.st_mtime;
return; return;
} }
} }

View File

@ -96,6 +96,7 @@ DEFINE_ID_TYPE(KeymapId, "keymap")
DEFINE_ID_TYPE(LayersId, "layers") DEFINE_ID_TYPE(LayersId, "layers")
DEFINE_ID_TYPE(SongId, "song") DEFINE_ID_TYPE(SongId, "song")
DEFINE_ID_TYPE(SFXId, "sfx") DEFINE_ID_TYPE(SFXId, "sfx")
DEFINE_ID_TYPE(GroupId, "group")
template<> template<> template<> template<>
void PageObjectIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) void PageObjectIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
@ -225,6 +226,9 @@ std::string NameDB::generateName(ObjectId id, Type tp)
case Type::SFX: case Type::SFX:
snprintf(name, 32, "sfx%04X", id.id); snprintf(name, 32, "sfx%04X", id.id);
break; break;
case Type::Group:
snprintf(name, 32, "group%04X", id.id);
break;
case Type::Sample: case Type::Sample:
snprintf(name, 32, "sample%04X", id.id); snprintf(name, 32, "sample%04X", id.id);
break; break;

View File

@ -236,8 +236,8 @@ void Voice::_procSamplePre(int16_t& samp)
float start = m_envelopeStart; float start = m_envelopeStart;
float end = m_envelopeEnd; float end = m_envelopeEnd;
float t = clamp(0.f, float(m_envelopeTime / m_envelopeDur), 1.f); float t = clamp(0.f, float(m_envelopeTime / m_envelopeDur), 1.f);
if (m_envelopeCurve) if (m_envelopeCurve && m_envelopeCurve->data.size() >= 128)
t = m_envelopeCurve->data.at(t * 127.f) / 127.f; t = m_envelopeCurve->data[t * 127.f] / 127.f;
m_curVol = clamp(0.f, (start * (1.0f - t)) + (end * t), 1.f); m_curVol = clamp(0.f, (start * (1.0f - t)) + (end * t), 1.f);
// printf("%d %f\n", m_vid, m_curVol); // printf("%d %f\n", m_vid, m_curVol);