mirror of https://github.com/AxioDL/amuse.git
Lots of foundational work for Amuse editor
This commit is contained in:
parent
1e8b6e599c
commit
4c884d019d
|
@ -16,6 +16,9 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/boo AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
include_directories(athena/include)
|
include_directories(athena/include)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
atdna(atdna_AudioGroupPool.cpp include/amuse/AudioGroupPool.hpp)
|
||||||
|
atdna(atdna_AudioGroupProject.cpp include/amuse/AudioGroupProject.hpp)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
lib/AudioGroup.cpp
|
lib/AudioGroup.cpp
|
||||||
lib/AudioGroupData.cpp
|
lib/AudioGroupData.cpp
|
||||||
|
@ -38,8 +41,11 @@ set(SOURCES
|
||||||
lib/EffectChorus.cpp
|
lib/EffectChorus.cpp
|
||||||
lib/EffectDelay.cpp
|
lib/EffectDelay.cpp
|
||||||
lib/ContainerRegistry.cpp
|
lib/ContainerRegistry.cpp
|
||||||
|
lib/Common.cpp
|
||||||
lib/DSPCodec.cpp
|
lib/DSPCodec.cpp
|
||||||
lib/N64MusyXCodec.cpp)
|
lib/N64MusyXCodec.cpp
|
||||||
|
atdna_AudioGroupPool.cpp
|
||||||
|
atdna_AudioGroupProject.cpp)
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
include/amuse/AudioGroup.hpp
|
include/amuse/AudioGroup.hpp
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
#include "AudioGroupModel.hpp"
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef AMUSE_AUDIO_GROUP_MODEL_HPP
|
||||||
|
#define AMUSE_AUDIO_GROUP_MODEL_HPP
|
||||||
|
|
||||||
|
#include "amuse/AudioGroup.hpp"
|
||||||
|
|
||||||
|
class AudioGroupModel
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class SFXGroupModel : public AudioGroupModel
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class SongGroupModel : public AudioGroupModel
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //AMUSE_AUDIO_GROUP_MODEL_HPP
|
|
@ -8,13 +8,12 @@ set(AUTORCC ON)
|
||||||
find_package(Qt5Widgets)
|
find_package(Qt5Widgets)
|
||||||
find_package(Qt5Network)
|
find_package(Qt5Network)
|
||||||
find_package(Qt5Xml)
|
find_package(Qt5Xml)
|
||||||
|
find_package(Qt5Svg)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
list(APPEND PLAT_SRCS platforms/win/amuse-gui.rc platforms/win/amuse-gui.manifest)
|
list(APPEND PLAT_SRCS platforms/win/amuse-gui.rc platforms/win/amuse-gui.manifest)
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
list(APPEND PLAT_SRCS platforms/mac/mainicon.icns MacOSExtras.mm)
|
list(APPEND PLAT_SRCS platforms/mac/mainicon.icns MacOSExtras.mm)
|
||||||
find_library(APPKIT_LIBRARY AppKit)
|
|
||||||
list(APPEND PLAT_LIBS ${APPKIT_LIBRARY})
|
|
||||||
set_source_files_properties(platforms/mac/mainicon.icns PROPERTIES
|
set_source_files_properties(platforms/mac/mainicon.icns PROPERTIES
|
||||||
MACOSX_PACKAGE_LOCATION Resources)
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
endif()
|
endif()
|
||||||
|
@ -26,20 +25,26 @@ list(APPEND PLAT_SRCS mainicon_qt.cpp)
|
||||||
QT5_ADD_RESOURCES(qrc_resources.cpp resources/resources.qrc)
|
QT5_ADD_RESOURCES(qrc_resources.cpp resources/resources.qrc)
|
||||||
|
|
||||||
add_executable(amuse-gui WIN32 MACOSX_BUNDLE
|
add_executable(amuse-gui WIN32 MACOSX_BUNDLE
|
||||||
|
Common.hpp Common.cpp
|
||||||
MainWindow.ui MainWindow.hpp MainWindow.cpp
|
MainWindow.ui MainWindow.hpp MainWindow.cpp
|
||||||
KeyboardWidget.hpp KeyboardWidget.cpp
|
KeyboardWidget.hpp KeyboardWidget.cpp
|
||||||
StatusBarWidget.hpp StatusBarWidget.cpp
|
StatusBarWidget.hpp StatusBarWidget.cpp
|
||||||
ProjectModel.hpp ProjectModel.cpp
|
ProjectModel.hpp ProjectModel.cpp
|
||||||
ProjectStatistics.hpp ProjectStatistics.cpp
|
ProjectStatistics.hpp ProjectStatistics.cpp
|
||||||
|
EditorWidget.hpp EditorWidget.cpp
|
||||||
SoundMacroEditor.hpp SoundMacroEditor.cpp
|
SoundMacroEditor.hpp SoundMacroEditor.cpp
|
||||||
KeymapEditor.hpp KeymapEditor.cpp
|
KeymapEditor.hpp KeymapEditor.cpp
|
||||||
LayersEditor.hpp LayersEditor.cpp
|
LayersEditor.hpp LayersEditor.cpp
|
||||||
SampleEditor.hpp SampleEditor.cpp
|
SampleEditor.hpp SampleEditor.cpp
|
||||||
SoundGroupEditor.hpp SoundGroupEditor.cpp
|
SFXGroupEditor.hpp SFXGroupEditor.cpp
|
||||||
SongGroupEditor.hpp SongGroupEditor.cpp
|
SongGroupEditor.hpp SongGroupEditor.cpp
|
||||||
|
AudioGroupModel.hpp AudioGroupModel.cpp
|
||||||
resources/resources.qrc qrc_resources.cpp
|
resources/resources.qrc qrc_resources.cpp
|
||||||
${PLAT_SRCS}
|
${PLAT_SRCS}
|
||||||
main.cpp)
|
main.cpp)
|
||||||
|
if(COMMAND add_sanitizers)
|
||||||
|
add_sanitizers(amuse-gui)
|
||||||
|
endif()
|
||||||
|
|
||||||
set_target_properties(amuse-gui PROPERTIES
|
set_target_properties(amuse-gui PROPERTIES
|
||||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/platforms/mac/Info.plist")
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/platforms/mac/Info.plist")
|
||||||
|
@ -48,4 +53,5 @@ target_link_libraries(amuse-gui ${PLAT_LIBS}
|
||||||
${Qt5Widgets_LIBRARIES}
|
${Qt5Widgets_LIBRARIES}
|
||||||
${Qt5Network_LIBRARIES}
|
${Qt5Network_LIBRARIES}
|
||||||
${Qt5Xml_LIBRARIES}
|
${Qt5Xml_LIBRARIES}
|
||||||
boo logvisor zeus athena-core athena-libyaml xxhash z)
|
${Qt5Svg_LIBRARIES}
|
||||||
|
amuse boo ${BOO_SYS_LIBS} logvisor zeus athena-core athena-libyaml xxhash ${ZLIB_LIBRARIES} ${LZO_LIB})
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include "Common.hpp"
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
boo::SystemString QStringToSysString(const QString& str)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return (wchar_t*)str.utf16();
|
||||||
|
#else
|
||||||
|
return str.toUtf8().toStdString();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SysStringToQString(const boo::SystemString& str)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return QString::fromStdWString(str);
|
||||||
|
#else
|
||||||
|
return QString::fromStdString(str);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MkPath(const QString& path, QWidget* parent)
|
||||||
|
{
|
||||||
|
QFileInfo fInfo(path);
|
||||||
|
return MkPath(fInfo.dir(), fInfo.fileName(), parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MkPath(const QDir& dir, const QString& file, QWidget* parent)
|
||||||
|
{
|
||||||
|
if (!dir.mkpath(file))
|
||||||
|
{
|
||||||
|
QString msg = QString(parent->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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef AMUSE_COMMON_HPP
|
||||||
|
#define AMUSE_COMMON_HPP
|
||||||
|
|
||||||
|
#include "boo/System.hpp"
|
||||||
|
#include <QString>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
boo::SystemString QStringToSysString(const QString& str);
|
||||||
|
QString SysStringToQString(const boo::SystemString& str);
|
||||||
|
|
||||||
|
bool MkPath(const QString& path, QWidget* parent);
|
||||||
|
bool MkPath(const QDir& dir, const QString& file, QWidget* parent);
|
||||||
|
|
||||||
|
#endif //AMUSE_COMMON_HPP
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
|
||||||
|
EditorWidget::EditorWidget(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef AMUSE_EDITOR_WIDGET_HPP
|
||||||
|
#define AMUSE_EDITOR_WIDGET_HPP
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class EditorWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit EditorWidget(QWidget* parent = Q_NULLPTR);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //AMUSE_EDITOR_WIDGET_HPP
|
|
@ -1,7 +1,7 @@
|
||||||
#include "KeymapEditor.hpp"
|
#include "KeymapEditor.hpp"
|
||||||
|
|
||||||
KeymapEditor::KeymapEditor(QWidget* parent)
|
KeymapEditor::KeymapEditor(QWidget* parent)
|
||||||
: QWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef AMUSE_KEYMAP_EDITOR_HPP
|
#ifndef AMUSE_KEYMAP_EDITOR_HPP
|
||||||
#define AMUSE_KEYMAP_EDITOR_HPP
|
#define AMUSE_KEYMAP_EDITOR_HPP
|
||||||
|
|
||||||
#include <QWidget>
|
#include "EditorWidget.hpp"
|
||||||
|
|
||||||
class KeymapEditor : public QWidget
|
class KeymapEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "LayersEditor.hpp"
|
#include "LayersEditor.hpp"
|
||||||
|
|
||||||
LayersEditor::LayersEditor(QWidget* parent)
|
LayersEditor::LayersEditor(QWidget* parent)
|
||||||
: QWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef AMUSE_LAYERS_EDITOR_HPP
|
#ifndef AMUSE_LAYERS_EDITOR_HPP
|
||||||
#define AMUSE_LAYERS_EDITOR_HPP
|
#define AMUSE_LAYERS_EDITOR_HPP
|
||||||
|
|
||||||
#include <QWidget>
|
#include "EditorWidget.hpp"
|
||||||
|
|
||||||
class LayersEditor : public QWidget
|
class LayersEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1,10 +1,398 @@
|
||||||
#include "MainWindow.hpp"
|
#include "MainWindow.hpp"
|
||||||
#include "ui_MainWindow.h"
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QtSvg/QtSvg>
|
||||||
|
#include "amuse/ContainerRegistry.hpp"
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget* parent)
|
MainWindow::MainWindow(QWidget* parent)
|
||||||
: QMainWindow(parent),
|
: QMainWindow(parent),
|
||||||
m_ui(new Ui::MainWindow)
|
m_undoStack(new QUndoStack(this))
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
m_ui.actionNew_Project->setShortcut(QKeySequence::New);
|
||||||
|
connect(m_ui.actionNew_Project, SIGNAL(triggered()), this, SLOT(newAction()));
|
||||||
|
m_ui.actionOpen_Project->setShortcut(QKeySequence::Open);
|
||||||
|
connect(m_ui.actionOpen_Project, SIGNAL(triggered()), this, SLOT(openAction()));
|
||||||
|
connect(m_ui.actionImport, SIGNAL(triggered()), this, SLOT(importAction()));
|
||||||
|
connect(m_ui.actionExport_GameCube_Groups, SIGNAL(triggered()), this, SLOT(exportAction()));
|
||||||
|
#ifndef __APPLE__
|
||||||
|
m_ui.menuFile->addSeparator();
|
||||||
|
QAction* quitAction = m_ui.menuFile->addAction(tr("Quit"));
|
||||||
|
quitAction->setShortcut(QKeySequence::Quit);
|
||||||
|
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_ui.actionUndo->setShortcut(QKeySequence::Undo);
|
||||||
|
m_ui.actionRedo->setShortcut(QKeySequence::Redo);
|
||||||
|
m_ui.actionCut->setShortcut(QKeySequence::Cut);
|
||||||
|
m_ui.actionCopy->setShortcut(QKeySequence::Copy);
|
||||||
|
m_ui.actionPaste->setShortcut(QKeySequence::Paste);
|
||||||
|
m_ui.actionDelete->setShortcut(QKeySequence::Delete);
|
||||||
|
onFocusChanged(nullptr, this);
|
||||||
|
|
||||||
|
m_ui.editorSvg->load(QStringLiteral(":/bg/FaceGrey.svg"));
|
||||||
|
|
||||||
|
connect(m_ui.actionNew_SFX_Group, SIGNAL(triggered()), this, SLOT(newSFXGroupAction()));
|
||||||
|
connect(m_ui.actionNew_Song_Group, SIGNAL(triggered()), this, SLOT(newSongGroupAction()));
|
||||||
|
connect(m_ui.actionNew_Sound_Macro, SIGNAL(triggered()), this, SLOT(newSoundMacroAction()));
|
||||||
|
connect(m_ui.actionNew_Keymap, SIGNAL(triggered()), this, SLOT(newKeymapAction()));
|
||||||
|
connect(m_ui.actionNew_Layers, SIGNAL(triggered()), this, SLOT(newLayersAction()));
|
||||||
|
|
||||||
|
connect(m_ui.menuAudio, SIGNAL(aboutToShow()), this, SLOT(aboutToShowAudioIOMenu()));
|
||||||
|
connect(m_ui.menuMIDI, SIGNAL(aboutToShow()), this, SLOT(aboutToShowMIDIIOMenu()));
|
||||||
|
|
||||||
|
connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)), this, SLOT(onFocusChanged(QWidget*,QWidget*)));
|
||||||
|
|
||||||
|
setFocusAudioGroup(nullptr);
|
||||||
|
|
||||||
|
m_voxEngine = boo::NewAudioVoiceEngine();
|
||||||
|
m_voxAllocator = std::make_unique<amuse::BooBackendVoiceAllocator>(*m_voxEngine);
|
||||||
|
m_engine = std::make_unique<amuse::Engine>(*m_voxAllocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
printf("IM DYING\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::setProjectPath(const QString& path)
|
||||||
|
{
|
||||||
|
if (m_projectModel && m_projectModel->path() == path)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
QDir dir(path);
|
||||||
|
if (!dir.exists())
|
||||||
|
{
|
||||||
|
QString msg = QString(tr("The directory at '%1' must exist for the Amuse editor.")).arg(path);
|
||||||
|
QMessageBox::critical(this, tr("Directory does not exist"), msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QString testWritePath = dir.filePath(tr("test"));
|
||||||
|
QFile testWriteFile(testWritePath);
|
||||||
|
if (!testWriteFile.open(QFile::ReadWrite))
|
||||||
|
{
|
||||||
|
QString msg = QString(tr("The directory at '%1' must be writable for the Amuse editor.")).arg(path);
|
||||||
|
QMessageBox::critical(this, tr("Unable to write to directory"), msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
testWriteFile.remove();
|
||||||
|
|
||||||
|
if (m_projectModel)
|
||||||
|
m_projectModel->deleteLater();
|
||||||
|
m_projectModel = new ProjectModel(path, this);
|
||||||
|
m_ui.projectOutline->setModel(m_projectModel);
|
||||||
|
m_ui.actionExport_GameCube_Groups->setEnabled(true);
|
||||||
|
setWindowFilePath(path);
|
||||||
|
setFocusAudioGroup(nullptr);
|
||||||
|
onFocusChanged(nullptr, focusWidget());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::setFocusAudioGroup(AudioGroupModel* group)
|
||||||
|
{
|
||||||
|
m_focusAudioGroup = group;
|
||||||
|
bool active = m_focusAudioGroup != nullptr;
|
||||||
|
m_ui.actionNew_Sound_Macro->setEnabled(active);
|
||||||
|
m_ui.actionNew_Keymap->setEnabled(active);
|
||||||
|
m_ui.actionNew_Layers->setEnabled(active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::refreshAudioIO()
|
||||||
|
{
|
||||||
|
QList<QAction*> audioActions = m_ui.menuAudio->actions();
|
||||||
|
if (audioActions.size() > 3)
|
||||||
|
for (auto it = audioActions.begin() + 3 ; it != audioActions.end() ; ++it)
|
||||||
|
m_ui.menuAudio->removeAction(*it);
|
||||||
|
|
||||||
|
bool addedDev = false;
|
||||||
|
// TODO: Do
|
||||||
|
|
||||||
|
if (!addedDev)
|
||||||
|
m_ui.menuAudio->addAction(tr("No Audio Devices Found"))->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::refreshMIDIIO()
|
||||||
|
{
|
||||||
|
QList<QAction*> midiActions = m_ui.menuMIDI->actions();
|
||||||
|
if (midiActions.size() > 2)
|
||||||
|
for (auto it = midiActions.begin() + 2 ; it != midiActions.end() ; ++it)
|
||||||
|
m_ui.menuMIDI->removeAction(*it);
|
||||||
|
|
||||||
|
bool addedDev = false;
|
||||||
|
if (m_voxEngine)
|
||||||
|
{
|
||||||
|
for (const auto& dev : m_voxEngine->enumerateMIDIDevices())
|
||||||
|
{
|
||||||
|
QAction* act = m_ui.menuMIDI->addAction(QString::fromStdString(dev.second));
|
||||||
|
act->setData(QString::fromStdString(dev.first));
|
||||||
|
connect(act, SIGNAL(triggered()), this, SLOT(setMIDIIO()));
|
||||||
|
addedDev = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!addedDev)
|
||||||
|
m_ui.menuMIDI->addAction(tr("No MIDI Devices Found"))->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::newAction()
|
||||||
|
{
|
||||||
|
QString path = QFileDialog::getSaveFileName(this, tr("New Project"));
|
||||||
|
if (path.isEmpty())
|
||||||
|
return;
|
||||||
|
if (!MkPath(path, this))
|
||||||
|
return;
|
||||||
|
setProjectPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::openAction()
|
||||||
|
{
|
||||||
|
QString path = QFileDialog::getExistingDirectory(this, tr("Open Project"));
|
||||||
|
if (path.isEmpty())
|
||||||
|
return;
|
||||||
|
setProjectPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::importAction()
|
||||||
|
{
|
||||||
|
QString path = QFileDialog::getOpenFileName(this, tr("Import Project"));
|
||||||
|
if (path.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Validate input file */
|
||||||
|
amuse::ContainerRegistry::Type tp =
|
||||||
|
amuse::ContainerRegistry::DetectContainerType(QStringToSysString(path).c_str());
|
||||||
|
if (tp == amuse::ContainerRegistry::Type::Invalid)
|
||||||
|
{
|
||||||
|
QString msg = QString(tr("The file at '%1' could not be interpreted as a MusyX container.")).arg(path);
|
||||||
|
QMessageBox::critical(this, tr("Unsupported MusyX Container"), msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ask user about sample conversion */
|
||||||
|
int impMode = QMessageBox::question(this, tr("Sample Import Mode"),
|
||||||
|
tr("Amuse can import samples as WAV files for ease of editing, "
|
||||||
|
"import original compressed data for lossless repacking, or both. "
|
||||||
|
"Exporting the project will prefer compressed files over WAVs, so "
|
||||||
|
"be sure to delete the compressed version if you edit the WAV."),
|
||||||
|
tr("Import Compressed"), tr("Import WAVs"), tr("Import Both"));
|
||||||
|
|
||||||
|
switch (impMode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special handling for raw groups - gather sibling groups in filesystem */
|
||||||
|
if (tp == amuse::ContainerRegistry::Type::Raw4)
|
||||||
|
{
|
||||||
|
int scanMode = QMessageBox::question(this, tr("Raw Import Mode"),
|
||||||
|
tr("Would you like to scan for all MusyX group files in this directory?"),
|
||||||
|
QMessageBox::Yes, QMessageBox::No);
|
||||||
|
if (scanMode == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
/* Auto-create project */
|
||||||
|
if (m_projectModel == nullptr)
|
||||||
|
{
|
||||||
|
QString newName;
|
||||||
|
bool ok = true;
|
||||||
|
while (ok && newName.isEmpty())
|
||||||
|
newName = QInputDialog::getText(this, tr("Project Name"), tr("What should this project be named?"),
|
||||||
|
QLineEdit::Normal, QString(), &ok);
|
||||||
|
if (!ok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QFileInfo fInfo(path);
|
||||||
|
QString newPath = QFileInfo(fInfo.dir(), newName).filePath();
|
||||||
|
printf("%s\n", newPath.toUtf8().data());
|
||||||
|
if (!MkPath(fInfo.dir(), newName, this))
|
||||||
|
return;
|
||||||
|
if (!setProjectPath(newPath))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir dir = QFileInfo(path).dir();
|
||||||
|
QStringList filters;
|
||||||
|
filters << "*.proj" << "*.pro";
|
||||||
|
QStringList files = dir.entryList(filters, QDir::Files);
|
||||||
|
for (const QString& fPath : files)
|
||||||
|
{
|
||||||
|
auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(dir.filePath(fPath)).c_str());
|
||||||
|
for (auto& p : data)
|
||||||
|
if (!m_projectModel->importGroupData(SysStringToQString(p.first), std::move(p.second),
|
||||||
|
ProjectModel::ImportMode(impMode), this))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_projectModel->saveToFile(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (scanMode == QMessageBox::No)
|
||||||
|
{}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Auto-create project */
|
||||||
|
if (m_projectModel == nullptr)
|
||||||
|
{
|
||||||
|
QFileInfo fInfo(path);
|
||||||
|
QString newPath = QFileInfo(fInfo.dir(), fInfo.completeBaseName()).filePath();
|
||||||
|
if (!MkPath(fInfo.dir(), fInfo.completeBaseName(), this))
|
||||||
|
return;
|
||||||
|
if (!setProjectPath(newPath))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle single container */
|
||||||
|
auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(path).c_str());
|
||||||
|
for (auto& p : data)
|
||||||
|
if (!m_projectModel->importGroupData(SysStringToQString(p.first), std::move(p.second),
|
||||||
|
ProjectModel::ImportMode(impMode), this))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_projectModel->saveToFile(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::exportAction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::newSFXGroupAction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::newSongGroupAction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::newSoundMacroAction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::newKeymapAction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::newLayersAction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::aboutToShowAudioIOMenu()
|
||||||
|
{
|
||||||
|
refreshAudioIO();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::aboutToShowMIDIIOMenu()
|
||||||
|
{
|
||||||
|
refreshMIDIIO();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::setAudioIO()
|
||||||
|
{
|
||||||
|
// TODO: Do
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::setMIDIIO()
|
||||||
|
{
|
||||||
|
// TODO: Do
|
||||||
|
//qobject_cast<QAction*>(sender())->data().toString().toUtf8().constData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
||||||
|
{
|
||||||
|
disconnect(m_undoConn);
|
||||||
|
disconnect(m_canUndoConn);
|
||||||
|
disconnect(m_redoConn);
|
||||||
|
disconnect(m_canRedoConn);
|
||||||
|
disconnect(m_cutConn);
|
||||||
|
disconnect(m_copyConn);
|
||||||
|
disconnect(m_pasteConn);
|
||||||
|
disconnect(m_deleteConn);
|
||||||
|
disconnect(m_canEditConn);
|
||||||
|
|
||||||
|
if (QLineEdit* le = qobject_cast<QLineEdit*>(now))
|
||||||
|
{
|
||||||
|
m_undoConn = connect(m_ui.actionUndo, SIGNAL(triggered()), le, SLOT(undo()));
|
||||||
|
m_canUndoConn = connect(le, SIGNAL(textChanged()), this, SLOT(onTextEdited()));
|
||||||
|
m_ui.actionUndo->setEnabled(le->isUndoAvailable());
|
||||||
|
m_redoConn = connect(m_ui.actionRedo, SIGNAL(triggered()), le, SLOT(redo()));
|
||||||
|
m_ui.actionRedo->setEnabled(le->isRedoAvailable());
|
||||||
|
m_cutConn = connect(m_ui.actionCut, SIGNAL(triggered()), le, SLOT(cut()));
|
||||||
|
m_ui.actionCut->setEnabled(le->hasSelectedText());
|
||||||
|
m_copyConn = connect(m_ui.actionCopy, SIGNAL(triggered()), le, SLOT(copy()));
|
||||||
|
m_ui.actionCopy->setEnabled(le->hasSelectedText());
|
||||||
|
m_pasteConn = connect(m_ui.actionPaste, SIGNAL(triggered()), le, SLOT(paste()));
|
||||||
|
m_ui.actionPaste->setEnabled(true);
|
||||||
|
m_deleteConn = connect(m_ui.actionDelete, SIGNAL(triggered()), this, SLOT(onTextDelete()));
|
||||||
|
m_ui.actionDelete->setEnabled(true);
|
||||||
|
m_canEditConn = connect(le, SIGNAL(selectionChanged()), this, SLOT(onTextSelect()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_undoConn = connect(m_ui.actionUndo, SIGNAL(triggered()), m_undoStack, SLOT(undo()));
|
||||||
|
m_canUndoConn = connect(m_undoStack, SIGNAL(canUndoChanged(bool)), m_ui.actionUndo, SLOT(setEnabled(bool)));
|
||||||
|
m_ui.actionUndo->setEnabled(m_undoStack->canUndo());
|
||||||
|
m_redoConn = connect(m_ui.actionRedo, SIGNAL(triggered()), m_undoStack, SLOT(redo()));
|
||||||
|
m_canRedoConn = connect(m_undoStack, SIGNAL(canRedoChanged(bool)), m_ui.actionRedo, SLOT(setEnabled(bool)));
|
||||||
|
m_ui.actionRedo->setEnabled(m_undoStack->canRedo());
|
||||||
|
|
||||||
|
if (now == m_ui.projectOutline || m_ui.projectOutline->isAncestorOf(now))
|
||||||
|
{
|
||||||
|
m_ui.actionCut->setEnabled(false);
|
||||||
|
m_ui.actionCopy->setEnabled(false);
|
||||||
|
m_ui.actionPaste->setEnabled(false);
|
||||||
|
if (m_projectModel)
|
||||||
|
{
|
||||||
|
m_deleteConn = connect(m_ui.actionDelete, SIGNAL(triggered()), m_projectModel, SLOT(del()));
|
||||||
|
m_ui.actionDelete->setEnabled(m_projectModel->canDelete());
|
||||||
|
m_canEditConn = connect(m_projectModel, SIGNAL(canDeleteChanged(bool)),
|
||||||
|
m_ui.actionDelete, SLOT(setEnabled(bool)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (now == m_ui.editorContents || m_ui.editorContents->isAncestorOf(now))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onTextEdited()
|
||||||
|
{
|
||||||
|
if (QLineEdit* le = qobject_cast<QLineEdit*>(sender()))
|
||||||
|
{
|
||||||
|
m_ui.actionUndo->setEnabled(le->isUndoAvailable());
|
||||||
|
m_ui.actionRedo->setEnabled(le->isRedoAvailable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onTextSelect()
|
||||||
|
{
|
||||||
|
if (QLineEdit* le = qobject_cast<QLineEdit*>(sender()))
|
||||||
|
{
|
||||||
|
m_ui.actionCut->setEnabled(le->hasSelectedText());
|
||||||
|
m_ui.actionCopy->setEnabled(le->hasSelectedText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onTextDelete()
|
||||||
|
{
|
||||||
|
if (QLineEdit* le = qobject_cast<QLineEdit*>(focusWidget()))
|
||||||
|
{
|
||||||
|
le->del();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,16 +2,74 @@
|
||||||
#define AMUSE_MAINWINDOW_HPP
|
#define AMUSE_MAINWINDOW_HPP
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QUndoStack>
|
||||||
|
#include "ui_MainWindow.h"
|
||||||
|
#include "amuse/Engine.hpp"
|
||||||
|
#include "amuse/BooBackend.hpp"
|
||||||
|
#include "boo/audiodev/IAudioVoiceEngine.hpp"
|
||||||
|
#include "ProjectModel.hpp"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AudioGroupModel;
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Ui::MainWindow* m_ui;
|
Ui::MainWindow m_ui;
|
||||||
|
ProjectModel* m_projectModel = nullptr;
|
||||||
|
AudioGroupModel* m_focusAudioGroup = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<boo::IAudioVoiceEngine> m_voxEngine;
|
||||||
|
std::unique_ptr<amuse::BooBackendVoiceAllocator> m_voxAllocator;
|
||||||
|
std::unique_ptr<amuse::Engine> m_engine;
|
||||||
|
|
||||||
|
QUndoStack* m_undoStack;
|
||||||
|
|
||||||
|
QMetaObject::Connection m_undoConn;
|
||||||
|
QMetaObject::Connection m_canUndoConn;
|
||||||
|
QMetaObject::Connection m_redoConn;
|
||||||
|
QMetaObject::Connection m_canRedoConn;
|
||||||
|
QMetaObject::Connection m_cutConn;
|
||||||
|
QMetaObject::Connection m_copyConn;
|
||||||
|
QMetaObject::Connection m_pasteConn;
|
||||||
|
QMetaObject::Connection m_deleteConn;
|
||||||
|
QMetaObject::Connection m_canEditConn;
|
||||||
|
|
||||||
|
bool setProjectPath(const QString& path);
|
||||||
|
void setFocusAudioGroup(AudioGroupModel* group);
|
||||||
|
void refreshAudioIO();
|
||||||
|
void refreshMIDIIO();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MainWindow(QWidget* parent = Q_NULLPTR);
|
explicit MainWindow(QWidget* parent = Q_NULLPTR);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void newAction();
|
||||||
|
void openAction();
|
||||||
|
void importAction();
|
||||||
|
void exportAction();
|
||||||
|
|
||||||
|
void newSFXGroupAction();
|
||||||
|
void newSongGroupAction();
|
||||||
|
void newSoundMacroAction();
|
||||||
|
void newKeymapAction();
|
||||||
|
void newLayersAction();
|
||||||
|
|
||||||
|
void aboutToShowAudioIOMenu();
|
||||||
|
void aboutToShowMIDIIOMenu();
|
||||||
|
|
||||||
|
void setAudioIO();
|
||||||
|
void setMIDIIO();
|
||||||
|
|
||||||
|
void onFocusChanged(QWidget* old, QWidget* now);
|
||||||
|
void onTextEdited();
|
||||||
|
void onTextSelect();
|
||||||
|
void onTextDelete();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,18 @@
|
||||||
<height>400</height>
|
<height>400</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="midLineWidth">
|
||||||
|
<number>-2</number>
|
||||||
|
</property>
|
||||||
<property name="widgetResizable">
|
<property name="widgetResizable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
@ -99,10 +111,28 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>538</width>
|
<width>540</width>
|
||||||
<height>450</height>
|
<height>442</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSvgWidget" name="editorSvg" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>256</width>
|
||||||
|
<height>256</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QScrollArea" name="keyboardScrollArea">
|
<widget class="QScrollArea" name="keyboardScrollArea">
|
||||||
|
@ -124,6 +154,15 @@
|
||||||
<height>100</height>
|
<height>100</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
<property name="widgetResizable">
|
<property name="widgetResizable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
@ -132,8 +171,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>538</width>
|
<width>540</width>
|
||||||
<height>98</height>
|
<height>100</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
|
@ -155,23 +194,23 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>800</width>
|
||||||
<height>22</height>
|
<height>27</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>File</string>
|
<string>Fi&le</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionNew_Project"/>
|
<addaction name="actionNew_Project"/>
|
||||||
<addaction name="actionOpen_Project"/>
|
<addaction name="actionOpen_Project"/>
|
||||||
<addaction name="actionImport_Project"/>
|
<addaction name="actionImport"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="actionExport_GameCube_Groups"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuProject">
|
<widget class="QMenu" name="menuProject">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Project</string>
|
<string>P&roject</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionNew_Sound_Group"/>
|
<addaction name="actionNew_SFX_Group"/>
|
||||||
<addaction name="actionNew_Song_Group"/>
|
<addaction name="actionNew_Song_Group"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionNew_Sound_Macro"/>
|
<addaction name="actionNew_Sound_Macro"/>
|
||||||
|
@ -180,7 +219,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuAudio">
|
<widget class="QMenu" name="menuAudio">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Audio</string>
|
<string>A&udio</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionAuto_Play"/>
|
<addaction name="actionAuto_Play"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
@ -188,7 +227,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuMIDI">
|
<widget class="QMenu" name="menuMIDI">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>MIDI</string>
|
<string>&MIDI</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionInput_Device"/>
|
<addaction name="actionInput_Device"/>
|
||||||
|
@ -214,129 +253,128 @@
|
||||||
<widget class="StatusBarWidget" name="statusbar"/>
|
<widget class="StatusBarWidget" name="statusbar"/>
|
||||||
<action name="actionNew_Project">
|
<action name="actionNew_Project">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>New Project</string>
|
<string>&New Project</string>
|
||||||
</property>
|
|
||||||
<property name="shortcut">
|
|
||||||
<string>Ctrl+N</string>
|
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionOpen_Project">
|
<action name="actionOpen_Project">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Open Project</string>
|
<string>&Open Project</string>
|
||||||
</property>
|
|
||||||
<property name="shortcut">
|
|
||||||
<string>Ctrl+O</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionDuplicate_Project">
|
|
||||||
<property name="text">
|
|
||||||
<string>Duplicate Project</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionQuit">
|
|
||||||
<property name="text">
|
|
||||||
<string>Quit</string>
|
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionUndo">
|
<action name="actionUndo">
|
||||||
<property name="text">
|
<property name="enabled">
|
||||||
<string>Undo</string>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="text">
|
||||||
<string>Ctrl+Z</string>
|
<string>&Undo</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionRedo">
|
<action name="actionRedo">
|
||||||
<property name="text">
|
<property name="enabled">
|
||||||
<string>Redo</string>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="text">
|
||||||
<string>Ctrl+Shift+Z</string>
|
<string>&Redo</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionCut">
|
<action name="actionCut">
|
||||||
<property name="text">
|
<property name="enabled">
|
||||||
<string>Cut</string>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="text">
|
||||||
<string>Ctrl+X</string>
|
<string>&Cut</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionCopy">
|
<action name="actionCopy">
|
||||||
<property name="text">
|
<property name="enabled">
|
||||||
<string>Copy</string>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="text">
|
||||||
<string>Ctrl+C</string>
|
<string>C&opy</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionPaste">
|
<action name="actionPaste">
|
||||||
<property name="text">
|
<property name="enabled">
|
||||||
<string>Paste</string>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="text">
|
||||||
<string>Ctrl+V</string>
|
<string>&Paste</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDelete">
|
<action name="actionDelete">
|
||||||
<property name="text">
|
<property name="enabled">
|
||||||
<string>Delete</string>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="text">
|
||||||
<string>Del</string>
|
<string>&Delete</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionImport_Project">
|
<action name="actionImport">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Import Project</string>
|
<string>&Import</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+I</string>
|
<string>Ctrl+I</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionNew_Sound_Group">
|
<action name="actionNew_SFX_Group">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset>
|
||||||
<normaloff>:/icons/IconNewSoundGroup.svg</normaloff>:/icons/IconNewSoundGroup.svg</iconset>
|
<normaloff>:/icons/IconNewSoundGroup.svg</normaloff>:/icons/IconNewSoundGroup.svg</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>New Sound Group</string>
|
<string>&New SFX Group</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionNew_Song_Group">
|
<action name="actionNew_Song_Group">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset>
|
||||||
<normaloff>:/icons/IconNewSongGroup.svg</normaloff>:/icons/IconNewSongGroup.svg</iconset>
|
<normaloff>:/icons/IconNewSongGroup.svg</normaloff>:/icons/IconNewSongGroup.svg</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>New Song Group</string>
|
<string>New &Song Group</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionNew_Sound_Macro">
|
<action name="actionNew_Sound_Macro">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset>
|
||||||
<normaloff>:/icons/IconNewSoundMacro.svg</normaloff>:/icons/IconNewSoundMacro.svg</iconset>
|
<normaloff>:/icons/IconNewSoundMacro.svg</normaloff>:/icons/IconNewSoundMacro.svg</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>New Sound Macro</string>
|
<string>New Sound &Macro</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionNew_Keymap">
|
<action name="actionNew_Keymap">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset>
|
||||||
<normaloff>:/icons/IconNewKeymap.svg</normaloff>:/icons/IconNewKeymap.svg</iconset>
|
<normaloff>:/icons/IconNewKeymap.svg</normaloff>:/icons/IconNewKeymap.svg</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>New Keymap</string>
|
<string>New &Keymap</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionNew_Layers">
|
<action name="actionNew_Layers">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset>
|
||||||
<normaloff>:/icons/IconNewLayers.svg</normaloff>:/icons/IconNewLayers.svg</iconset>
|
<normaloff>:/icons/IconNewLayers.svg</normaloff>:/icons/IconNewLayers.svg</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>New Layers</string>
|
<string>New &Layers</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionAuto_Play">
|
<action name="actionAuto_Play">
|
||||||
|
@ -347,7 +385,7 @@
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Auto-Play</string>
|
<string>&Auto-Play</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionSelect_Output_Device">
|
<action name="actionSelect_Output_Device">
|
||||||
|
@ -355,7 +393,7 @@
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Output Device:</string>
|
<string>&Output Device:</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionInput_Device">
|
<action name="actionInput_Device">
|
||||||
|
@ -363,7 +401,18 @@
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Input Device:</string>
|
<string>&Input Device:</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExport_GameCube_Groups">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Export GameCube Groups</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+E</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -379,6 +428,12 @@
|
||||||
<extends>QStatusBar</extends>
|
<extends>QStatusBar</extends>
|
||||||
<header>StatusBarWidget.hpp</header>
|
<header>StatusBarWidget.hpp</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>QSvgWidget</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">QSvgWidget</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|
|
@ -1,7 +1,163 @@
|
||||||
|
#include <athena/FileWriter.hpp>
|
||||||
|
#include <athena/FileReader.hpp>
|
||||||
#include "ProjectModel.hpp"
|
#include "ProjectModel.hpp"
|
||||||
|
#include "Common.hpp"
|
||||||
|
#include "athena/YAMLDocWriter.hpp"
|
||||||
|
|
||||||
ProjectModel::ProjectModel(QObject* parent)
|
ProjectModel::ProjectModel(const QString& path, QObject* parent)
|
||||||
: QAbstractItemModel(parent)
|
: QAbstractItemModel(parent), m_dir(path)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::ProjectGroup::ProjectGroup(amuse::IntrusiveAudioGroupData&& data)
|
||||||
|
: m_data(std::move(data)),
|
||||||
|
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,
|
||||||
|
ImportMode mode, QWidget* parent)
|
||||||
|
{
|
||||||
|
amuse::SongId::CurNameDB = &m_songDb;
|
||||||
|
amuse::SongId::CurNameDB = &m_sfxDb;
|
||||||
|
|
||||||
|
ProjectGroup& grp = m_groups.insert(std::make_pair(groupName, std::move(data))).first->second;
|
||||||
|
|
||||||
|
for (const auto& p : grp.m_proj.songGroups())
|
||||||
|
{
|
||||||
|
for (const auto& song : p.second.m_midiSetups)
|
||||||
|
{
|
||||||
|
char name[16];
|
||||||
|
snprintf(name, 16, "song%d", song.first.id);
|
||||||
|
m_songDb.registerPair(name, song.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& p : grp.m_proj.sfxGroups())
|
||||||
|
{
|
||||||
|
for (const auto& sfx : p.second.m_sfxEntries)
|
||||||
|
{
|
||||||
|
char name[16];
|
||||||
|
snprintf(name, 16, "sfx%d", sfx.first.id);
|
||||||
|
m_sfxDb.registerPair(name, sfx.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProjectModel::saveToFile(QWidget* parent)
|
||||||
|
{
|
||||||
|
amuse::SongId::CurNameDB = &m_songDb;
|
||||||
|
amuse::SongId::CurNameDB = &m_sfxDb;
|
||||||
|
|
||||||
|
if (!MkPath(m_dir.path(), parent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto& g : m_groups)
|
||||||
|
{
|
||||||
|
athena::io::YAMLDocWriter w("amuse::Group");
|
||||||
|
|
||||||
|
QDir dir(QFileInfo(m_dir, g.first).filePath());
|
||||||
|
if (!MkPath(dir.path(), parent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (auto __v = w.enterSubVector("songGroups"))
|
||||||
|
{
|
||||||
|
for (const auto& p : g.second.m_proj.songGroups())
|
||||||
|
{
|
||||||
|
if (auto __r = w.enterSubRecord(nullptr))
|
||||||
|
{
|
||||||
|
if (auto __v2 = w.enterSubRecord("normPages"))
|
||||||
|
{
|
||||||
|
for (const auto& pg : p.second.m_normPages)
|
||||||
|
{
|
||||||
|
char name[16];
|
||||||
|
snprintf(name, 16, "%d", pg.first);
|
||||||
|
if (auto __r2 = w.enterSubRecord(name))
|
||||||
|
pg.second.toDNA<athena::Big>(pg.first).write(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (auto __v2 = w.enterSubRecord("drumPages"))
|
||||||
|
{
|
||||||
|
for (const auto& pg : p.second.m_drumPages)
|
||||||
|
{
|
||||||
|
char name[16];
|
||||||
|
snprintf(name, 16, "%d", pg.first);
|
||||||
|
if (auto __r2 = w.enterSubRecord(name))
|
||||||
|
pg.second.toDNA<athena::Big>(pg.first).write(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (auto __v2 = w.enterSubRecord("songs"))
|
||||||
|
{
|
||||||
|
for (const auto& song : p.second.m_midiSetups)
|
||||||
|
{
|
||||||
|
if (auto __v3 = w.enterSubVector(m_songDb.resolveNameFromId(song.first).data()))
|
||||||
|
for (int i = 0; i < 16; ++i)
|
||||||
|
if (auto __r2 = w.enterSubRecord(nullptr))
|
||||||
|
song.second[i].write(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto __v = w.enterSubVector("sfxGroups"))
|
||||||
|
{
|
||||||
|
for (const auto& p : g.second.m_proj.sfxGroups())
|
||||||
|
{
|
||||||
|
if (auto __r = w.enterSubRecord(nullptr))
|
||||||
|
{
|
||||||
|
for (const auto& sfx : p.second.m_sfxEntries)
|
||||||
|
{
|
||||||
|
if (auto __r2 = w.enterSubRecord(m_sfxDb.resolveNameFromId(sfx.first).data()))
|
||||||
|
sfx.second.toDNA<athena::Big>(sfx.first).write(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
athena::io::FileWriter fo(QStringToSysString(dir.filePath("project.yaml")));
|
||||||
|
w.finish(&fo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex ProjectModel::index(int row, int column, const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
return createIndex(row, column, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex ProjectModel::parent(const QModelIndex& child) const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
int ProjectModel::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ProjectModel::columnCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ProjectModel::data(const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProjectModel::canDelete() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectModel::del()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,61 @@
|
||||||
#define AMUSE_PROJECT_MODEL_HPP
|
#define AMUSE_PROJECT_MODEL_HPP
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
|
#include <QDir>
|
||||||
|
#include <map>
|
||||||
|
#include "amuse/AudioGroupData.hpp"
|
||||||
|
#include "amuse/AudioGroupProject.hpp"
|
||||||
|
#include "amuse/AudioGroupPool.hpp"
|
||||||
|
#include "amuse/AudioGroupSampleDirectory.hpp"
|
||||||
|
|
||||||
class ProjectModel : public QAbstractItemModel
|
class ProjectModel : public QAbstractItemModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit ProjectModel(QObject* parent = Q_NULLPTR);
|
enum class ImportMode
|
||||||
|
{
|
||||||
|
Original,
|
||||||
|
WAVs,
|
||||||
|
Both
|
||||||
|
};
|
||||||
|
struct ProjectGroup
|
||||||
|
{
|
||||||
|
amuse::IntrusiveAudioGroupData m_data;
|
||||||
|
amuse::AudioGroupProject m_proj;
|
||||||
|
amuse::AudioGroupPool m_pool;
|
||||||
|
amuse::AudioGroupSampleDirectory m_sdir;
|
||||||
|
|
||||||
|
explicit ProjectGroup(amuse::IntrusiveAudioGroupData&& data);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
QDir m_dir;
|
||||||
|
|
||||||
|
amuse::NameDB m_songDb;
|
||||||
|
amuse::NameDB m_sfxDb;
|
||||||
|
std::map<QString, ProjectGroup> m_groups;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ProjectModel(const QString& path, QObject* parent = Q_NULLPTR);
|
||||||
|
|
||||||
|
bool importGroupData(const QString& groupName, amuse::IntrusiveAudioGroupData&& data,
|
||||||
|
ImportMode mode, QWidget* parent);
|
||||||
|
bool saveToFile(QWidget* parent);
|
||||||
|
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QModelIndex parent(const QModelIndex& child) const;
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
|
QString path() const { return m_dir.path(); }
|
||||||
|
bool canDelete() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void del();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void canDeleteChanged(bool canDelete);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "SFXGroupEditor.hpp"
|
||||||
|
|
||||||
|
SFXGroupEditor::SFXGroupEditor(QWidget* parent)
|
||||||
|
: EditorWidget(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef AMUSE_SFX_GROUP_EDITOR_HPP
|
||||||
|
#define AMUSE_SFX_GROUP_EDITOR_HPP
|
||||||
|
|
||||||
|
#include "EditorWidget.hpp"
|
||||||
|
|
||||||
|
class SFXGroupEditor : public EditorWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SFXGroupEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //AMUSE_SFX_GROUP_EDITOR_HPP
|
|
@ -1,7 +1,7 @@
|
||||||
#include "SampleEditor.hpp"
|
#include "SampleEditor.hpp"
|
||||||
|
|
||||||
SampleEditor::SampleEditor(QWidget* parent)
|
SampleEditor::SampleEditor(QWidget* parent)
|
||||||
: QWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef AMUSE_SAMPLE_EDITOR_HPP
|
#ifndef AMUSE_SAMPLE_EDITOR_HPP
|
||||||
#define AMUSE_SAMPLE_EDITOR_HPP
|
#define AMUSE_SAMPLE_EDITOR_HPP
|
||||||
|
|
||||||
#include <QWidget>
|
#include "EditorWidget.hpp"
|
||||||
|
|
||||||
class SampleEditor : public QWidget
|
class SampleEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "SongGroupEditor.hpp"
|
#include "SongGroupEditor.hpp"
|
||||||
|
|
||||||
SongGroupEditor::SongGroupEditor(QWidget* parent)
|
SongGroupEditor::SongGroupEditor(QWidget* parent)
|
||||||
: QWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef AMUSE_SONG_GROUP_EDITOR_HPP
|
#ifndef AMUSE_SONG_GROUP_EDITOR_HPP
|
||||||
#define AMUSE_SONG_GROUP_EDITOR_HPP
|
#define AMUSE_SONG_GROUP_EDITOR_HPP
|
||||||
|
|
||||||
#include <QWidget>
|
#include "EditorWidget.hpp"
|
||||||
|
|
||||||
class SongGroupEditor : public QWidget
|
class SongGroupEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
#include "SoundGroupEditor.hpp"
|
|
||||||
|
|
||||||
SoundGroupEditor::SoundGroupEditor(QWidget* parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
#ifndef AMUSE_SOUND_GROUP_EDITOR_HPP
|
|
||||||
#define AMUSE_SOUND_GROUP_EDITOR_HPP
|
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
class SoundGroupEditor : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit SoundGroupEditor(QWidget* parent = Q_NULLPTR);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //AMUSE_SOUND_GROUP_EDITOR_HPP
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "SoundMacroEditor.hpp"
|
#include "SoundMacroEditor.hpp"
|
||||||
|
|
||||||
SoundMacroEditor::SoundMacroEditor(QWidget* parent)
|
SoundMacroEditor::SoundMacroEditor(QWidget* parent)
|
||||||
: QWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef AMUSE_SOUND_MACRO_EDITOR_HPP
|
#ifndef AMUSE_SOUND_MACRO_EDITOR_HPP
|
||||||
#define AMUSE_SOUND_MACRO_EDITOR_HPP
|
#define AMUSE_SOUND_MACRO_EDITOR_HPP
|
||||||
|
|
||||||
#include <QWidget>
|
#include "EditorWidget.hpp"
|
||||||
|
|
||||||
class SoundMacroEditor : public QWidget
|
class SoundMacroEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
#include "MainWindow.hpp"
|
#include "MainWindow.hpp"
|
||||||
|
#include "boo/IApplication.hpp"
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
void MacOSSetDarkAppearance();
|
void MacOSSetDarkAppearance();
|
||||||
|
@ -28,6 +31,24 @@ static QIcon MakeAppIcon()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is for adapting the get*Name methods */
|
||||||
|
class BooInterface : public boo::IApplication
|
||||||
|
{
|
||||||
|
std::vector<boo::SystemString> m_args;
|
||||||
|
void _deletedWindow(boo::IWindow* window) {}
|
||||||
|
public:
|
||||||
|
EPlatformType getPlatformType() const { return EPlatformType::Qt; }
|
||||||
|
|
||||||
|
int run() { return 0; }
|
||||||
|
boo::SystemStringView getUniqueName() const { return _S("amuse-gui"sv); }
|
||||||
|
boo::SystemStringView getFriendlyName() const { return _S("Amuse"sv); }
|
||||||
|
boo::SystemStringView getProcessName() const { return _S("amuse-gui"sv); }
|
||||||
|
const std::vector<boo::SystemString>& getArgs() const { return m_args; }
|
||||||
|
|
||||||
|
/* Constructors/initializers for sub-objects */
|
||||||
|
std::shared_ptr<boo::IWindow> newWindow(boo::SystemStringView title) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||||
|
@ -48,6 +69,7 @@ int main(int argc, char* argv[])
|
||||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, QColor(255,255,255,120));
|
darkPalette.setColor(QPalette::Disabled, QPalette::Text, QColor(255,255,255,120));
|
||||||
|
darkPalette.setColor(QPalette::Disabled, QPalette::Light, QColor(0,0,0,0));
|
||||||
darkPalette.setColor(QPalette::Button, QColor(53,53,53));
|
darkPalette.setColor(QPalette::Button, QColor(53,53,53));
|
||||||
darkPalette.setColor(QPalette::Disabled, QPalette::Button, QColor(53,53,53,53));
|
darkPalette.setColor(QPalette::Disabled, QPalette::Button, QColor(53,53,53,53));
|
||||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||||
|
@ -64,6 +86,9 @@ int main(int argc, char* argv[])
|
||||||
MacOSSetDarkAppearance();
|
MacOSSetDarkAppearance();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
BooInterface booApp;
|
||||||
|
boo::APP = &booApp;
|
||||||
|
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
w.show();
|
w.show();
|
||||||
return a.exec();
|
return a.exec();
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="1024"
|
width="247.54231"
|
||||||
height="1024"
|
height="247.54233"
|
||||||
viewBox="0 0 270.93 270.93333"
|
viewBox="0 0 261.98227 261.98229"
|
||||||
id="svg2"
|
id="svg2"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
sodipodi:docname="faceGrey.svg"
|
sodipodi:docname="FaceGrey.svg"
|
||||||
inkscape:export-filename="/Users/jacko/Desktop/amuse-logo/face1024.png"
|
inkscape:export-filename="/Users/jacko/Desktop/amuse-logo/face1024.png"
|
||||||
inkscape:export-xdpi="96.000008"
|
inkscape:export-xdpi="96.000008"
|
||||||
inkscape:export-ydpi="96.000008">
|
inkscape:export-ydpi="96.000008">
|
||||||
|
@ -27,19 +27,19 @@
|
||||||
<stop
|
<stop
|
||||||
id="stop4353"
|
id="stop4353"
|
||||||
offset="0"
|
offset="0"
|
||||||
style="stop-color:#5f5f5f;stop-opacity:1;" />
|
style="stop-color:#858585;stop-opacity:1;" />
|
||||||
<stop
|
<stop
|
||||||
style="stop-color:#424242;stop-opacity:1;"
|
style="stop-color:#4f4f4f;stop-opacity:1;"
|
||||||
offset="0.27903292"
|
offset="0.27903292"
|
||||||
id="stop4351" />
|
id="stop4351" />
|
||||||
<stop
|
<stop
|
||||||
id="stop4349"
|
id="stop4349"
|
||||||
offset="0.56446373"
|
offset="0.56446373"
|
||||||
style="stop-color:#4e4e4e;stop-opacity:1;" />
|
style="stop-color:#606060;stop-opacity:1;" />
|
||||||
<stop
|
<stop
|
||||||
id="stop4347"
|
id="stop4347"
|
||||||
offset="1"
|
offset="1"
|
||||||
style="stop-color:#212121;stop-opacity:1;" />
|
style="stop-color:#484848;stop-opacity:1;" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
id="linearGradient4315">
|
id="linearGradient4315">
|
||||||
|
@ -334,23 +334,28 @@
|
||||||
</defs>
|
</defs>
|
||||||
<sodipodi:namedview
|
<sodipodi:namedview
|
||||||
id="base"
|
id="base"
|
||||||
pagecolor="#2a2a2a"
|
pagecolor="#3a3a3a"
|
||||||
bordercolor="#666666"
|
bordercolor="#666666"
|
||||||
borderopacity="1.0"
|
borderopacity="1.0"
|
||||||
inkscape:pageopacity="0"
|
inkscape:pageopacity="0.00392157"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="0.63234634"
|
inkscape:zoom="2.5293854"
|
||||||
inkscape:cx="247.50409"
|
inkscape:cx="57.159723"
|
||||||
inkscape:cy="571.18657"
|
inkscape:cy="115.45029"
|
||||||
inkscape:document-units="mm"
|
inkscape:document-units="mm"
|
||||||
inkscape:current-layer="layer3"
|
inkscape:current-layer="layer3"
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
units="px"
|
units="px"
|
||||||
inkscape:window-width="1680"
|
inkscape:window-width="1555"
|
||||||
inkscape:window-height="1005"
|
inkscape:window-height="1280"
|
||||||
inkscape:window-x="0"
|
inkscape:window-x="1890"
|
||||||
inkscape:window-y="0"
|
inkscape:window-y="286"
|
||||||
inkscape:window-maximized="0" />
|
inkscape:window-maximized="0"
|
||||||
|
scale-x="4"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0" />
|
||||||
<metadata
|
<metadata
|
||||||
id="metadata7">
|
id="metadata7">
|
||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
|
@ -367,7 +372,7 @@
|
||||||
inkscape:label="source"
|
inkscape:label="source"
|
||||||
inkscape:groupmode="layer"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"
|
id="layer1"
|
||||||
transform="translate(0,-26.06665)"
|
transform="translate(-4.3711946,-30.440026)"
|
||||||
style="display:none"
|
style="display:none"
|
||||||
sodipodi:insensitive="true">
|
sodipodi:insensitive="true">
|
||||||
<text
|
<text
|
||||||
|
@ -412,7 +417,8 @@
|
||||||
id="layer2"
|
id="layer2"
|
||||||
inkscape:label="path"
|
inkscape:label="path"
|
||||||
style="display:inline;opacity:0.76700003"
|
style="display:inline;opacity:0.76700003"
|
||||||
sodipodi:insensitive="true">
|
sodipodi:insensitive="true"
|
||||||
|
transform="translate(-4.3711946,-4.3733763)">
|
||||||
<g
|
<g
|
||||||
id="g4360"
|
id="g4360"
|
||||||
style="fill:url(#linearGradient4375);fill-opacity:1"
|
style="fill:url(#linearGradient4375);fill-opacity:1"
|
||||||
|
@ -453,7 +459,8 @@
|
||||||
id="layer5"
|
id="layer5"
|
||||||
inkscape:label="path 1"
|
inkscape:label="path 1"
|
||||||
style="display:inline;opacity:0.24734982"
|
style="display:inline;opacity:0.24734982"
|
||||||
sodipodi:insensitive="true">
|
sodipodi:insensitive="true"
|
||||||
|
transform="translate(-4.3711946,-4.3733763)">
|
||||||
<path
|
<path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
id="path4439"
|
id="path4439"
|
||||||
|
@ -466,7 +473,8 @@
|
||||||
inkscape:label="path 2"
|
inkscape:label="path 2"
|
||||||
id="g4512"
|
id="g4512"
|
||||||
inkscape:groupmode="layer"
|
inkscape:groupmode="layer"
|
||||||
sodipodi:insensitive="true">
|
sodipodi:insensitive="true"
|
||||||
|
transform="translate(-4.3711946,-4.3733763)">
|
||||||
<g
|
<g
|
||||||
transform="matrix(1.0065636,0,0,1.0065636,-0.88913164,-0.88914604)"
|
transform="matrix(1.0065636,0,0,1.0065636,-0.88913164,-0.88914604)"
|
||||||
style="fill:url(#linearGradient4530);fill-opacity:1"
|
style="fill:url(#linearGradient4530);fill-opacity:1"
|
||||||
|
@ -507,7 +515,8 @@
|
||||||
inkscape:label="path 3"
|
inkscape:label="path 3"
|
||||||
id="g4538"
|
id="g4538"
|
||||||
inkscape:groupmode="layer"
|
inkscape:groupmode="layer"
|
||||||
sodipodi:insensitive="true">
|
sodipodi:insensitive="true"
|
||||||
|
transform="translate(-4.3711946,-4.3733763)">
|
||||||
<g
|
<g
|
||||||
transform="matrix(1.0065636,0,0,1.0065636,-0.88913164,-0.88914604)"
|
transform="matrix(1.0065636,0,0,1.0065636,-0.88913164,-0.88914604)"
|
||||||
style="fill:url(#linearGradient4556);fill-opacity:1"
|
style="fill:url(#linearGradient4556);fill-opacity:1"
|
||||||
|
@ -547,19 +556,20 @@
|
||||||
inkscape:groupmode="layer"
|
inkscape:groupmode="layer"
|
||||||
id="layer3"
|
id="layer3"
|
||||||
inkscape:label="light"
|
inkscape:label="light"
|
||||||
style="display:inline;opacity:1">
|
style="display:inline;opacity:1"
|
||||||
|
transform="translate(-4.3711946,-4.3733763)">
|
||||||
<g
|
<g
|
||||||
id="g4360-5"
|
id="g4360-5"
|
||||||
style="display:inline;fill:url(#linearGradient4332);fill-opacity:1.0"
|
style="display:inline;fill:url(#linearGradient4332);fill-opacity:1"
|
||||||
transform="matrix(1.002648,0,0,1.002648,-1.0727108,-1.0727166)">
|
transform="matrix(1.002648,0,0,1.002648,-1.0727108,-1.0727166)">
|
||||||
<g
|
<g
|
||||||
id="text4141-2-9"
|
id="text4141-2-9"
|
||||||
aria-label=":D"
|
aria-label=":D"
|
||||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4187);fill-opacity:1.0;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4187);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
transform="rotate(90)">
|
transform="rotate(90)">
|
||||||
<path
|
<path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4184);fill-opacity:1.0;stroke-width:0.99999994px"
|
style="font-size:176.3888855px;letter-spacing:-26.45833206px;fill:url(#linearGradient4184);fill-opacity:1;stroke-width:0.99999994px"
|
||||||
d="M 512,20.529297 C 240.58464,20.529297 20.527344,240.58461 20.527344,512 c 0,271.41536 220.057296,491.4727 491.472656,491.4727 271.4154,0 491.4707,-220.05734 491.4707,-491.4727 C 1003.4707,240.58461 783.4154,20.529297 512,20.529297 Z m 0,2.605469 c 270.00802,0 488.8652,218.857204 488.8652,488.865234 0,270.00802 -218.85718,488.8652 -488.8652,488.8652 C 241.992,1000.8652 23.132813,782.00802 23.132812,512 23.132812,241.99197 241.992,23.134766 512,23.134766 Z m 0,32.326172 C 259.91593,55.460938 55.458984,259.9159 55.458984,512 55.458984,764.08406 259.91593,968.54102 512,968.54102 764.0841,968.54102 968.53906,764.08406 968.53906,512 968.53906,259.9159 764.0841,55.460938 512,55.460938 Z m 0,9.367187 C 759.02055,64.828125 959.17188,264.97946 959.17188,512 959.17188,759.02051 759.02055,959.17383 512,959.17383 264.97949,959.17383 64.826172,759.02051 64.826172,512 64.826172,264.97946 264.97949,64.828125 512,64.828125 Z M 512,96.5625 C 282.67144,96.5625 96.568359,282.67142 96.568359,512 96.568359,741.32854 282.67144,927.43164 512,927.43164 741.32858,927.43164 927.4375,741.32854 927.4375,512 927.4375,282.67142 741.32858,96.5625 512,96.5625 Z m 0,18.47656 C 731.34481,115.03906 908.96094,292.6552 908.96094,512 908.96094,731.34477 731.34481,908.96094 512,908.96094 292.65523,908.96094 115.03906,731.34477 115.03906,512 115.03906,292.6552 292.65523,115.03906 512,115.03906 Z m 0,32.90235 C 311.12038,147.94141 147.93945,311.12036 147.93945,512 147.93945,712.87962 311.12038,876.06055 512,876.06055 712.87966,876.06055 876.05859,712.87962 876.05859,512 876.05859,311.12036 712.87966,147.94141 512,147.94141 Z m 0,31.16601 c 184.03556,0 332.89258,148.85702 332.89258,332.89258 0,184.03552 -148.85702,332.89453 -332.89258,332.89453 -184.03553,0 -332.89453,-148.85901 -332.89453,-332.89453 0,-184.03556 148.859,-332.89258 332.89453,-332.89258 z m -129.66602,71.68946 c -15.55555,0 -28.44574,5.11176 -38.66796,15.33398 -10.22223,10.22222 -15.33204,22.88889 -15.33204,38 0,15.55555 5.10981,28.44379 15.33204,38.66602 10.22222,10.22222 23.11241,15.33398 38.66796,15.33398 15.11111,0 27.77777,-5.11176 38,-15.33398 10.66666,-10.22223 16,-23.11047 16,-38.66602 0,-15.11111 -5.33334,-27.77778 -16,-38 -10.66668,-10.22222 -23.33334,-15.33398 -38,-15.33398 z m 240.66602,0 c -15.11111,0 -27.99933,5.11176 -38.66602,15.33398 -10.66665,10.22222 -16,22.88889 -16,38 0,15.55555 5.33335,28.44379 16,38.66602 10.66669,10.22222 23.55491,15.33398 38.66602,15.33398 14.66666,0 27.11175,-5.11176 37.33398,-15.33398 10.66666,-10.22223 16,-23.11047 16,-38.66602 0,-15.11111 -5.33334,-27.77778 -16,-38 C 650.11175,255.90864 637.66666,250.79688 623,250.79688 Z M 282.33398,459.86914 v 105.33398 c 0,58.66666 16.88824,108 50.66602,148 33.77778,40.00001 94.22288,60 181.33398,60 86.66666,0 146.22157,-19.77843 178.66602,-59.33398 32.44445,-39.55555 48.66602,-91.55555 48.66602,-156 v -98 z m 46.66602,58 h 365.33398 v 54 c 0,25.77779 -4.44509,48.66797 -13.33398,68.66797 -8.44445,20 -25.99936,36.66668 -52.66602,50 -26.22221,13.77779 -64.22221,20.66601 -114,20.66601 -68.88889,0 -117.11242,-13.33331 -144.66796,-40 C 342.5549,644.98091 329,612.09266 329,572.53711 Z"
|
d="M 512,20.529297 C 240.58464,20.529297 20.527344,240.58461 20.527344,512 c 0,271.41536 220.057296,491.4727 491.472656,491.4727 271.4154,0 491.4707,-220.05734 491.4707,-491.4727 C 1003.4707,240.58461 783.4154,20.529297 512,20.529297 Z m 0,2.605469 c 270.00802,0 488.8652,218.857204 488.8652,488.865234 0,270.00802 -218.85718,488.8652 -488.8652,488.8652 C 241.992,1000.8652 23.132813,782.00802 23.132812,512 23.132812,241.99197 241.992,23.134766 512,23.134766 Z m 0,32.326172 C 259.91593,55.460938 55.458984,259.9159 55.458984,512 55.458984,764.08406 259.91593,968.54102 512,968.54102 764.0841,968.54102 968.53906,764.08406 968.53906,512 968.53906,259.9159 764.0841,55.460938 512,55.460938 Z m 0,9.367187 C 759.02055,64.828125 959.17188,264.97946 959.17188,512 959.17188,759.02051 759.02055,959.17383 512,959.17383 264.97949,959.17383 64.826172,759.02051 64.826172,512 64.826172,264.97946 264.97949,64.828125 512,64.828125 Z M 512,96.5625 C 282.67144,96.5625 96.568359,282.67142 96.568359,512 96.568359,741.32854 282.67144,927.43164 512,927.43164 741.32858,927.43164 927.4375,741.32854 927.4375,512 927.4375,282.67142 741.32858,96.5625 512,96.5625 Z m 0,18.47656 C 731.34481,115.03906 908.96094,292.6552 908.96094,512 908.96094,731.34477 731.34481,908.96094 512,908.96094 292.65523,908.96094 115.03906,731.34477 115.03906,512 115.03906,292.6552 292.65523,115.03906 512,115.03906 Z m 0,32.90235 C 311.12038,147.94141 147.93945,311.12036 147.93945,512 147.93945,712.87962 311.12038,876.06055 512,876.06055 712.87966,876.06055 876.05859,712.87962 876.05859,512 876.05859,311.12036 712.87966,147.94141 512,147.94141 Z m 0,31.16601 c 184.03556,0 332.89258,148.85702 332.89258,332.89258 0,184.03552 -148.85702,332.89453 -332.89258,332.89453 -184.03553,0 -332.89453,-148.85901 -332.89453,-332.89453 0,-184.03556 148.859,-332.89258 332.89453,-332.89258 z m -129.66602,71.68946 c -15.55555,0 -28.44574,5.11176 -38.66796,15.33398 -10.22223,10.22222 -15.33204,22.88889 -15.33204,38 0,15.55555 5.10981,28.44379 15.33204,38.66602 10.22222,10.22222 23.11241,15.33398 38.66796,15.33398 15.11111,0 27.77777,-5.11176 38,-15.33398 10.66666,-10.22223 16,-23.11047 16,-38.66602 0,-15.11111 -5.33334,-27.77778 -16,-38 -10.66668,-10.22222 -23.33334,-15.33398 -38,-15.33398 z m 240.66602,0 c -15.11111,0 -27.99933,5.11176 -38.66602,15.33398 -10.66665,10.22222 -16,22.88889 -16,38 0,15.55555 5.33335,28.44379 16,38.66602 10.66669,10.22222 23.55491,15.33398 38.66602,15.33398 14.66666,0 27.11175,-5.11176 37.33398,-15.33398 10.66666,-10.22223 16,-23.11047 16,-38.66602 0,-15.11111 -5.33334,-27.77778 -16,-38 C 650.11175,255.90864 637.66666,250.79688 623,250.79688 Z M 282.33398,459.86914 v 105.33398 c 0,58.66666 16.88824,108 50.66602,148 33.77778,40.00001 94.22288,60 181.33398,60 86.66666,0 146.22157,-19.77843 178.66602,-59.33398 32.44445,-39.55555 48.66602,-91.55555 48.66602,-156 v -98 z m 46.66602,58 h 365.33398 v 54 c 0,25.77779 -4.44509,48.66797 -13.33398,68.66797 -8.44445,20 -25.99936,36.66668 -52.66602,50 -26.22221,13.77779 -64.22221,20.66601 -114,20.66601 -68.88889,0 -117.11242,-13.33331 -144.66796,-40 C 342.5549,644.98091 329,612.09266 329,572.53711 Z"
|
||||||
transform="matrix(0,-0.26458333,0.26458333,0,0,0.001665)"
|
transform="matrix(0,-0.26458333,0.26458333,0,0,0.001665)"
|
||||||
id="path4247-2" />
|
id="path4247-2" />
|
||||||
|
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 30 KiB |
|
@ -14,4 +14,7 @@
|
||||||
<file>IconSoundGroup.svg</file>
|
<file>IconSoundGroup.svg</file>
|
||||||
<file>IconSoundMacro.svg</file>
|
<file>IconSoundMacro.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
<qresource prefix="/bg">
|
||||||
|
<file>FaceGrey.svg</file>
|
||||||
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,58 +12,167 @@ namespace amuse
|
||||||
{
|
{
|
||||||
class AudioGroupData;
|
class AudioGroupData;
|
||||||
|
|
||||||
/** Common index members of SongGroups and SFXGroups */
|
enum class GroupType : atUint16
|
||||||
struct AudioGroupIndex
|
|
||||||
{
|
{
|
||||||
const uint16_t* m_soundMacroIndex;
|
Song,
|
||||||
const uint16_t* m_tablesIndex;
|
SFX
|
||||||
const uint16_t* m_keymapsIndex;
|
|
||||||
const uint16_t* m_layersIndex;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Header at top of project file */
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
|
||||||
|
GroupHeader : BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA
|
||||||
|
Value<atUint32, DNAEn> groupEndOff;
|
||||||
|
Value<atUint16, DNAEn> groupId;
|
||||||
|
Value<GroupType, DNAEn> type;
|
||||||
|
Value<atUint32, DNAEn> soundMacroIdsOff;
|
||||||
|
Value<atUint32, DNAEn> samplIdsOff;
|
||||||
|
Value<atUint32, DNAEn> tableIdsOff;
|
||||||
|
Value<atUint32, DNAEn> keymapIdsOff;
|
||||||
|
Value<atUint32, DNAEn> layerIdsOff;
|
||||||
|
Value<atUint32, DNAEn> pageTableOff;
|
||||||
|
Value<atUint32, DNAEn> drumTableOff;
|
||||||
|
Value<atUint32, DNAEn> midiSetupsOff;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Common index members of SongGroups and SFXGroups */
|
||||||
|
struct AudioGroupIndex {};
|
||||||
|
|
||||||
/** Root index of SongGroup */
|
/** Root index of SongGroup */
|
||||||
struct SongGroupIndex : AudioGroupIndex
|
struct SongGroupIndex : AudioGroupIndex
|
||||||
{
|
{
|
||||||
/** Maps GM program numbers to sound entities */
|
/** Maps GM program numbers to sound entities */
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
|
||||||
|
PageEntryDNA : BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA_YAML
|
||||||
|
ObjectIdDNA<DNAEn> objId;
|
||||||
|
Value<atUint8> priority;
|
||||||
|
Value<atUint8> maxVoices;
|
||||||
|
Value<atUint8> programNo;
|
||||||
|
Seek<1, athena::Current> pad;
|
||||||
|
};
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
|
||||||
|
MusyX1PageEntryDNA : BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA_YAML
|
||||||
|
ObjectIdDNA<DNAEn> objId;
|
||||||
|
Value<atUint8> priority;
|
||||||
|
Value<atUint8> maxVoices;
|
||||||
|
Value<atUint8> unk;
|
||||||
|
Value<atUint8> programNo;
|
||||||
|
Seek<2, athena::Current> pad;
|
||||||
|
};
|
||||||
struct PageEntry
|
struct PageEntry
|
||||||
{
|
{
|
||||||
ObjectId objId;
|
ObjectId objId;
|
||||||
uint8_t priority;
|
atUint8 priority;
|
||||||
uint8_t maxVoices;
|
atUint8 maxVoices;
|
||||||
uint8_t programNo;
|
|
||||||
uint8_t pad;
|
PageEntry() = default;
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
PageEntry(const PageEntryDNA<DNAE>& in)
|
||||||
|
: objId(in.objId.id), priority(in.priority), maxVoices(in.maxVoices) {}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
PageEntry(const MusyX1PageEntryDNA<DNAE>& in)
|
||||||
|
: objId(in.objId.id), priority(in.priority), maxVoices(in.maxVoices) {}
|
||||||
|
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
PageEntryDNA<DNAEn> toDNA(uint8_t programNo) const
|
||||||
|
{
|
||||||
|
PageEntryDNA<DNAEn> ret;
|
||||||
|
ret.objId.id = objId;
|
||||||
|
ret.priority = priority;
|
||||||
|
ret.maxVoices = maxVoices;
|
||||||
|
ret.programNo = programNo;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
std::unordered_map<uint8_t, const PageEntry*> m_normPages;
|
std::unordered_map<uint8_t, PageEntry> m_normPages;
|
||||||
std::unordered_map<uint8_t, const PageEntry*> m_drumPages;
|
std::unordered_map<uint8_t, PageEntry> m_drumPages;
|
||||||
|
|
||||||
/** Maps SongID to 16 MIDI channel numbers to GM program numbers and settings */
|
/** Maps SongID to 16 MIDI channel numbers to GM program numbers and settings */
|
||||||
struct MIDISetup
|
struct MusyX1MIDISetup : BigDNA
|
||||||
{
|
{
|
||||||
uint8_t programNo;
|
AT_DECL_DNA_YAML
|
||||||
uint8_t volume;
|
Value<atUint8> programNo;
|
||||||
uint8_t panning;
|
Value<atUint8> volume;
|
||||||
uint8_t reverb;
|
Value<atUint8> panning;
|
||||||
uint8_t chorus;
|
Value<atUint8> reverb;
|
||||||
|
Value<atUint8> chorus;
|
||||||
|
Seek<3, athena::Current> pad;
|
||||||
};
|
};
|
||||||
std::unordered_map<int, const std::array<MIDISetup, 16>*> m_midiSetups;
|
struct MIDISetup : BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA_YAML
|
||||||
|
Value<atUint8> programNo;
|
||||||
|
Value<atUint8> volume;
|
||||||
|
Value<atUint8> panning;
|
||||||
|
Value<atUint8> reverb;
|
||||||
|
Value<atUint8> chorus;
|
||||||
|
MIDISetup() = default;
|
||||||
|
MIDISetup(const MusyX1MIDISetup& setup)
|
||||||
|
: programNo(setup.programNo), volume(setup.volume), panning(setup.panning),
|
||||||
|
reverb(setup.reverb), chorus(setup.chorus) {}
|
||||||
|
};
|
||||||
|
std::unordered_map<SongId, std::array<MIDISetup, 16>> m_midiSetups;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Root index of SFXGroup */
|
/** Root index of SFXGroup */
|
||||||
struct SFXGroupIndex : AudioGroupIndex
|
struct SFXGroupIndex : AudioGroupIndex
|
||||||
{
|
{
|
||||||
/** Maps game-side SFX define IDs to sound entities */
|
/** Maps game-side SFX define IDs to sound entities */
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
|
||||||
|
SFXEntryDNA : BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA_YAML
|
||||||
|
SFXIdDNA<DNAEn> defineId;
|
||||||
|
ObjectIdDNA<DNAEn> objId;
|
||||||
|
Value<atUint8> priority;
|
||||||
|
Value<atUint8> maxVoices;
|
||||||
|
Value<atUint8> defVel;
|
||||||
|
Value<atUint8> panning;
|
||||||
|
Value<atUint8> defKey;
|
||||||
|
Seek<1, athena::Current> pad;
|
||||||
|
};
|
||||||
struct SFXEntry
|
struct SFXEntry
|
||||||
{
|
{
|
||||||
uint16_t defineId;
|
|
||||||
ObjectId objId;
|
ObjectId objId;
|
||||||
uint8_t priority;
|
atUint8 priority;
|
||||||
uint8_t maxVoices;
|
atUint8 maxVoices;
|
||||||
uint8_t defVel;
|
atUint8 defVel;
|
||||||
uint8_t panning;
|
atUint8 panning;
|
||||||
uint8_t defKey;
|
atUint8 defKey;
|
||||||
uint8_t pad;
|
|
||||||
|
SFXEntry() = default;
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
SFXEntry(const SFXEntryDNA<DNAE>& in)
|
||||||
|
: objId(in.objId.id), priority(in.priority), maxVoices(in.maxVoices),
|
||||||
|
defVel(in.defVel), panning(in.panning), defKey(in.defKey) {}
|
||||||
|
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
SFXEntryDNA<DNAEn> toDNA(SFXId defineId) const
|
||||||
|
{
|
||||||
|
SFXEntryDNA<DNAEn> ret;
|
||||||
|
ret.defineId.id = defineId;
|
||||||
|
ret.objId.id = objId;
|
||||||
|
ret.priority = priority;
|
||||||
|
ret.maxVoices = maxVoices;
|
||||||
|
ret.defVel = defVel;
|
||||||
|
ret.panning = panning;
|
||||||
|
ret.defKey = defKey;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
std::unordered_map<uint16_t, const SFXEntry*> m_sfxEntries;
|
std::unordered_map<SFXId, SFXEntry> m_sfxEntries;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Collection of SongGroup and SFXGroup indexes */
|
/** Collection of SongGroup and SFXGroup indexes */
|
||||||
|
@ -72,17 +181,11 @@ class AudioGroupProject
|
||||||
std::unordered_map<int, SongGroupIndex> m_songGroups;
|
std::unordered_map<int, SongGroupIndex> m_songGroups;
|
||||||
std::unordered_map<int, SFXGroupIndex> m_sfxGroups;
|
std::unordered_map<int, SFXGroupIndex> m_sfxGroups;
|
||||||
|
|
||||||
/* MusyX 1.0 structures converted to MusyX 2.0 structures for pointer-compatible access */
|
AudioGroupProject() = default;
|
||||||
std::unique_ptr<SongGroupIndex::PageEntry[]> m_convNormalPages;
|
AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag);
|
||||||
std::unique_ptr<SongGroupIndex::PageEntry[]> m_convDrumPages;
|
template <athena::Endian DNAE>
|
||||||
std::unique_ptr<std::array<SongGroupIndex::MIDISetup, 16>[]> m_convMidiSetups;
|
static AudioGroupProject _AudioGroupProject(athena::io::IStreamReader& r, bool absOffs);
|
||||||
void _allocateConvBuffers(const unsigned char* data, N64DataTag);
|
|
||||||
void _allocateConvBuffers(const unsigned char* data, PCDataTag);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioGroupProject(const unsigned char* data, GCNDataTag);
|
|
||||||
AudioGroupProject(const unsigned char* data, bool absOffs, N64DataTag);
|
|
||||||
AudioGroupProject(const unsigned char* data, bool absOffs, PCDataTag);
|
|
||||||
static AudioGroupProject CreateAudioGroupProject(const AudioGroupData& data);
|
static AudioGroupProject CreateAudioGroupProject(const AudioGroupData& data);
|
||||||
|
|
||||||
const SongGroupIndex* getSongGroupIndex(int groupId) const;
|
const SongGroupIndex* getSongGroupIndex(int groupId) const;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
class AudioGroupData;
|
||||||
|
|
||||||
/** Indexes individual samples in SAMP chunk */
|
/** Indexes individual samples in SAMP chunk */
|
||||||
class AudioGroupSampleDirectory
|
class AudioGroupSampleDirectory
|
||||||
|
@ -52,6 +53,7 @@ public:
|
||||||
AudioGroupSampleDirectory(const unsigned char* data, GCNDataTag);
|
AudioGroupSampleDirectory(const unsigned char* data, GCNDataTag);
|
||||||
AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData, bool absOffs, N64DataTag);
|
AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData, bool absOffs, N64DataTag);
|
||||||
AudioGroupSampleDirectory(const unsigned char* data, bool absOffs, PCDataTag);
|
AudioGroupSampleDirectory(const unsigned char* data, bool absOffs, PCDataTag);
|
||||||
|
static AudioGroupSampleDirectory CreateAudioGroupSampleDirectory(const AudioGroupData& data);
|
||||||
|
|
||||||
const std::unordered_map<uint16_t, std::pair<Entry, ADPCMParms>>& sampleEntries() const { return m_entries; }
|
const std::unordered_map<uint16_t, std::pair<Entry, ADPCMParms>>& sampleEntries() const { return m_entries; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include "athena/DNA.hpp"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
@ -28,6 +29,95 @@ constexpr float NativeSampleRate = 32000.0f;
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
struct NameDB;
|
||||||
|
|
||||||
|
using BigDNA = athena::io::DNA<athena::Big>;
|
||||||
|
using LittleDNA = athena::io::DNA<athena::Little>;
|
||||||
|
using BigDNAV = athena::io::DNAVYaml<athena::Big>;
|
||||||
|
using LittleDNAV = athena::io::DNAVYaml<athena::Little>;
|
||||||
|
|
||||||
|
/** Common ID structure statically tagging
|
||||||
|
* SoundMacros, Tables, Keymaps, Layers */
|
||||||
|
struct ObjectId
|
||||||
|
{
|
||||||
|
uint16_t id = 0xffff;
|
||||||
|
operator uint16_t() const { return id; }
|
||||||
|
ObjectId() = default;
|
||||||
|
ObjectId(uint16_t idIn) : id(idIn) {}
|
||||||
|
ObjectId& operator=(uint16_t idIn) { id = idIn; return *this; }
|
||||||
|
static thread_local NameDB* CurNameDB;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
|
||||||
|
ObjectIdDNA : BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_EXPLICIT_DNA_YAML
|
||||||
|
void _read(athena::io::YAMLDocReader& r);
|
||||||
|
void _write(athena::io::YAMLDocWriter& w);
|
||||||
|
ObjectId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SampleId : ObjectId
|
||||||
|
{
|
||||||
|
using ObjectId::ObjectId;
|
||||||
|
SampleId(const ObjectId& id) : ObjectId(id) {}
|
||||||
|
static thread_local NameDB* CurNameDB;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
|
||||||
|
SampleIdDNA : BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_EXPLICIT_DNA_YAML
|
||||||
|
void _read(athena::io::YAMLDocReader& r);
|
||||||
|
void _write(athena::io::YAMLDocWriter& w);
|
||||||
|
SampleId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SongId : ObjectId
|
||||||
|
{
|
||||||
|
using ObjectId::ObjectId;
|
||||||
|
SongId(const ObjectId& id) : ObjectId(id) {}
|
||||||
|
static thread_local NameDB* CurNameDB;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
|
||||||
|
SongIdDNA : BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_EXPLICIT_DNA_YAML
|
||||||
|
void _read(athena::io::YAMLDocReader& r);
|
||||||
|
void _write(athena::io::YAMLDocWriter& w);
|
||||||
|
SongId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SFXId : ObjectId
|
||||||
|
{
|
||||||
|
using ObjectId::ObjectId;
|
||||||
|
SFXId(const ObjectId& id) : ObjectId(id) {}
|
||||||
|
static thread_local NameDB* CurNameDB;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
|
||||||
|
SFXIdDNA : BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_EXPLICIT_DNA_YAML
|
||||||
|
void _read(athena::io::YAMLDocReader& r);
|
||||||
|
void _write(athena::io::YAMLDocWriter& w);
|
||||||
|
SFXId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LittleUInt24 : LittleDNA
|
||||||
|
{
|
||||||
|
AT_DECL_EXPLICIT_DNA_YAML
|
||||||
|
atUint32 val;
|
||||||
|
operator uint32_t() const { return val; }
|
||||||
|
LittleUInt24() = default;
|
||||||
|
LittleUInt24(uint32_t valIn) : val(valIn) {}
|
||||||
|
LittleUInt24& operator=(uint32_t valIn) { val = valIn; return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
#ifndef PRISize
|
#ifndef PRISize
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -334,4 +424,51 @@ struct PCDataTag
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
struct hash<amuse::ObjectId>
|
||||||
|
{
|
||||||
|
size_t operator()(const amuse::ObjectId& val) const noexcept { return val.id; }
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct hash<amuse::SampleId>
|
||||||
|
{
|
||||||
|
size_t operator()(const amuse::SampleId& val) const noexcept { return val.id; }
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct hash<amuse::SongId>
|
||||||
|
{
|
||||||
|
size_t operator()(const amuse::SongId& val) const noexcept { return val.id; }
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct hash<amuse::SFXId>
|
||||||
|
{
|
||||||
|
size_t operator()(const amuse::SFXId& val) const noexcept { return val.id; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace amuse
|
||||||
|
{
|
||||||
|
struct NameDB
|
||||||
|
{
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
SoundMacro = 0,
|
||||||
|
Table = 1,
|
||||||
|
Keymap = 4,
|
||||||
|
Layer = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, ObjectId> m_stringToId;
|
||||||
|
std::unordered_map<ObjectId, std::string> m_idToString;
|
||||||
|
|
||||||
|
ObjectId generateId(Type tp);
|
||||||
|
static std::string generateName(ObjectId id);
|
||||||
|
std::string_view registerPair(std::string_view str, ObjectId id);
|
||||||
|
std::string_view resolveNameFromId(ObjectId id) const;
|
||||||
|
ObjectId resolveIdFromName(std::string_view str) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#endif // __AMUSE_COMMON_HPP__
|
#endif // __AMUSE_COMMON_HPP__
|
||||||
|
|
|
@ -4,23 +4,20 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
class Engine;
|
class Engine;
|
||||||
class AudioGroup;
|
class AudioGroup;
|
||||||
|
|
||||||
/** Common ID structure statically tagging
|
|
||||||
* SoundMacros, Tables, Keymaps, Layers */
|
|
||||||
using ObjectId = uint16_t;
|
|
||||||
|
|
||||||
/** Common 'engine child' class */
|
/** Common 'engine child' class */
|
||||||
class Entity
|
class Entity
|
||||||
{
|
{
|
||||||
/* Only the Engine will manage Entity lifetimes,
|
/* Only the Engine will manage Entity lifetimes,
|
||||||
* but shared_ptrs are issued to the client so it can safely track state */
|
* but shared_ptrs are issued to the client so it can safely track state */
|
||||||
friend class Engine;
|
friend class Engine;
|
||||||
friend class SoundMacroState;
|
friend struct SoundMacroState;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool m_destroyed = false;
|
bool m_destroyed = false;
|
||||||
|
@ -32,7 +29,7 @@ protected:
|
||||||
Engine& m_engine;
|
Engine& m_engine;
|
||||||
const AudioGroup& m_audioGroup;
|
const AudioGroup& m_audioGroup;
|
||||||
int m_groupId;
|
int m_groupId;
|
||||||
ObjectId m_objectId = 0xffff; /* if applicable */
|
ObjectId m_objectId; /* if applicable */
|
||||||
public:
|
public:
|
||||||
Entity(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid = ObjectId())
|
Entity(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid = ObjectId())
|
||||||
: m_engine(engine), m_audioGroup(group), m_groupId(groupId), m_objectId(oid)
|
: m_engine(engine), m_audioGroup(group), m_groupId(groupId), m_objectId(oid)
|
||||||
|
@ -50,9 +47,6 @@ public:
|
||||||
ObjectId getObjectId() const { return m_objectId; }
|
ObjectId getObjectId() const { return m_objectId; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Curves for mapping velocity to volume and other functional mappings
|
|
||||||
* (defined here for visibility)*/
|
|
||||||
using Curve = uint8_t[128];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __AMUSE_ENTITY_HPP__
|
#endif // __AMUSE_ENTITY_HPP__
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
#include "Entity.hpp"
|
#include "Entity.hpp"
|
||||||
#include "Common.hpp"
|
#include "Common.hpp"
|
||||||
|
#include "AudioGroupPool.hpp"
|
||||||
|
|
||||||
/* Squelch Win32 macro pollution >.< */
|
/* Squelch Win32 macro pollution >.< */
|
||||||
#undef SendMessage
|
#undef SendMessage
|
||||||
|
@ -16,123 +17,13 @@ namespace amuse
|
||||||
class Voice;
|
class Voice;
|
||||||
|
|
||||||
/** Real-time state of SoundMacro execution */
|
/** Real-time state of SoundMacro execution */
|
||||||
class SoundMacroState
|
struct SoundMacroState
|
||||||
{
|
{
|
||||||
friend class Voice;
|
|
||||||
friend class Envelope;
|
|
||||||
|
|
||||||
/** SoundMacro header */
|
|
||||||
struct Header
|
|
||||||
{
|
|
||||||
uint32_t m_size;
|
|
||||||
ObjectId m_macroId;
|
|
||||||
uint8_t m_volume;
|
|
||||||
uint8_t m_pan;
|
|
||||||
void swapBig();
|
|
||||||
} m_header;
|
|
||||||
|
|
||||||
/** SoundMacro command operations */
|
|
||||||
enum class Op : uint8_t
|
|
||||||
{
|
|
||||||
End,
|
|
||||||
Stop,
|
|
||||||
SplitKey,
|
|
||||||
SplitVel,
|
|
||||||
WaitTicks,
|
|
||||||
Loop,
|
|
||||||
Goto,
|
|
||||||
WaitMs,
|
|
||||||
PlayMacro,
|
|
||||||
SendKeyOff,
|
|
||||||
SplitMod,
|
|
||||||
PianoPan,
|
|
||||||
SetAdsr,
|
|
||||||
ScaleVolume,
|
|
||||||
Panning,
|
|
||||||
Envelope,
|
|
||||||
StartSample,
|
|
||||||
StopSample,
|
|
||||||
KeyOff,
|
|
||||||
SplitRnd,
|
|
||||||
FadeIn,
|
|
||||||
Spanning,
|
|
||||||
SetAdsrCtrl,
|
|
||||||
RndNote,
|
|
||||||
AddNote,
|
|
||||||
SetNote,
|
|
||||||
LastNote,
|
|
||||||
Portamento,
|
|
||||||
Vibrato,
|
|
||||||
PitchSweep1,
|
|
||||||
PitchSweep2,
|
|
||||||
SetPitch,
|
|
||||||
SetPitchAdsr,
|
|
||||||
ScaleVolumeDLS,
|
|
||||||
Mod2Vibrange,
|
|
||||||
SetupTremolo,
|
|
||||||
Return,
|
|
||||||
GoSub,
|
|
||||||
TrapEvent = 0x28,
|
|
||||||
UntrapEvent,
|
|
||||||
SendMessage,
|
|
||||||
GetMessage,
|
|
||||||
GetVid,
|
|
||||||
AddAgeCount = 0x30, /* unimplemented */
|
|
||||||
SetAgeCount, /* unimplemented */
|
|
||||||
SendFlag, /* unimplemented */
|
|
||||||
PitchWheelR,
|
|
||||||
SetPriority = 0x36, /* unimplemented */
|
|
||||||
AddPriority, /* unimplemented */
|
|
||||||
AgeCntSpeed, /* unimplemented */
|
|
||||||
AgeCntVel, /* unimplemented */
|
|
||||||
VolSelect = 0x40,
|
|
||||||
PanSelect,
|
|
||||||
PitchWheelSelect,
|
|
||||||
ModWheelSelect,
|
|
||||||
PedalSelect,
|
|
||||||
PortamentoSelect,
|
|
||||||
ReverbSelect, /* serves as PostASelect */
|
|
||||||
SpanSelect,
|
|
||||||
DopplerSelect,
|
|
||||||
TremoloSelect,
|
|
||||||
PreASelect,
|
|
||||||
PreBSelect,
|
|
||||||
PostBSelect,
|
|
||||||
AuxAFXSelect, /* unimplemented */
|
|
||||||
AuxBFXSelect, /* unimplemented */
|
|
||||||
SetupLFO = 0x50,
|
|
||||||
ModeSelect = 0x58,
|
|
||||||
SetKeygroup,
|
|
||||||
SRCmodeSelect, /* unimplemented */
|
|
||||||
AddVars = 0x60,
|
|
||||||
SubVars,
|
|
||||||
MulVars,
|
|
||||||
DivVars,
|
|
||||||
AddIVars,
|
|
||||||
IfEqual = 0x70,
|
|
||||||
IfLess,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** SoundMacro command structure */
|
|
||||||
struct Command
|
|
||||||
{
|
|
||||||
Op m_op;
|
|
||||||
char m_data[7];
|
|
||||||
void swapBig();
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 'program counter' stack for the active SoundMacro */
|
/** 'program counter' stack for the active SoundMacro */
|
||||||
std::vector<std::pair<const unsigned char*, int>> m_pc;
|
std::vector<std::tuple<ObjectId, const SoundMacro*, int>> m_pc;
|
||||||
|
|
||||||
static int _assertPC(int pc, uint32_t size);
|
|
||||||
static int _assertPC(int pc, uint32_t size, bool swapSize)
|
|
||||||
{
|
|
||||||
return _assertPC(pc, swapSize ? SBig(size) : size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _setPC(int pc)
|
void _setPC(int pc)
|
||||||
{
|
{
|
||||||
m_pc.back().second = _assertPC(pc, m_header.m_size);
|
std::get<2>(m_pc.back()) = std::get<1>(m_pc.back())->assertPC(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
double m_ticksPerSec; /**< ratio for resolving ticks in commands that use them */
|
double m_ticksPerSec; /**< ratio for resolving ticks in commands that use them */
|
||||||
|
@ -233,9 +124,9 @@ class SoundMacroState
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** initialize state for SoundMacro data at `ptr` */
|
/** initialize state for SoundMacro data at `ptr` */
|
||||||
void initialize(const unsigned char* ptr, int step, bool swapData);
|
void initialize(ObjectId id, const SoundMacro* macro, int step);
|
||||||
void initialize(const unsigned char* ptr, int step, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
|
void initialize(ObjectId id, const SoundMacro* macro, int step, double ticksPerSec,
|
||||||
uint8_t midiMod, bool swapData);
|
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod);
|
||||||
|
|
||||||
/** advances `dt` seconds worth of commands in the SoundMacro
|
/** advances `dt` seconds worth of commands in the SoundMacro
|
||||||
* @return `true` if END reached
|
* @return `true` if END reached
|
||||||
|
|
|
@ -31,9 +31,20 @@ class Voice : public Entity
|
||||||
{
|
{
|
||||||
friend class Engine;
|
friend class Engine;
|
||||||
friend class Sequencer;
|
friend class Sequencer;
|
||||||
friend class SoundMacroState;
|
friend struct SoundMacroState;
|
||||||
friend class Envelope;
|
friend class Envelope;
|
||||||
friend class Emitter;
|
friend class Emitter;
|
||||||
|
friend class SoundMacro::CmdScaleVolume;
|
||||||
|
friend class SoundMacro::CmdKeyOff;
|
||||||
|
friend class SoundMacro::CmdScaleVolumeDLS;
|
||||||
|
friend class SoundMacro::CmdReturn;
|
||||||
|
friend class SoundMacro::CmdGoSub;
|
||||||
|
friend class SoundMacro::CmdTrapEvent;
|
||||||
|
friend class SoundMacro::CmdUntrapEvent;
|
||||||
|
friend class SoundMacro::CmdGetMessage;
|
||||||
|
|
||||||
|
void _setObjectId(ObjectId id) { m_objectId = id; }
|
||||||
|
|
||||||
int m_vid; /**< VoiceID of this voice instance */
|
int m_vid; /**< VoiceID of this voice instance */
|
||||||
bool m_emitter; /**< Voice is part of an Emitter */
|
bool m_emitter; /**< Voice is part of an Emitter */
|
||||||
std::shared_ptr<Studio> m_studio; /**< Studio this voice outputs to */
|
std::shared_ptr<Studio> m_studio; /**< Studio this voice outputs to */
|
||||||
|
@ -160,12 +171,12 @@ class Voice : public Entity
|
||||||
std::list<std::shared_ptr<Voice>>::iterator _allocateVoice(double sampleRate, bool dynamicPitch);
|
std::list<std::shared_ptr<Voice>>::iterator _allocateVoice(double sampleRate, bool dynamicPitch);
|
||||||
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it);
|
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it);
|
||||||
|
|
||||||
bool _loadSoundMacro(const unsigned char* macroData, int macroStep, double ticksPerSec, uint8_t midiKey,
|
bool _loadSoundMacro(ObjectId id, const SoundMacro* macroData, int macroStep, double ticksPerSec,
|
||||||
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
||||||
bool _loadKeymap(const Keymap* keymap, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
|
bool _loadKeymap(ObjectId id, const Keymap* keymap, int macroStep, double ticksPerSec, uint8_t midiKey,
|
||||||
uint8_t midiMod, bool pushPc = false);
|
|
||||||
bool _loadLayer(const std::vector<const LayerMapping*>& layer, int macroStep, double ticksPerSec, uint8_t midiKey,
|
|
||||||
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
||||||
|
bool _loadLayer(ObjectId id, const std::vector<LayerMapping>& layer, int macroStep, double ticksPerSec,
|
||||||
|
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
||||||
std::shared_ptr<Voice> _startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
|
std::shared_ptr<Voice> _startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
|
||||||
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
AudioGroup::AudioGroup(const AudioGroupData& data, GCNDataTag)
|
AudioGroup::AudioGroup(const AudioGroupData& data, GCNDataTag)
|
||||||
: m_proj(data.getProj(), GCNDataTag{})
|
: m_proj(AudioGroupProject::CreateAudioGroupProject(data))
|
||||||
, m_pool(data.getPool())
|
, m_pool(AudioGroupPool::CreateAudioGroupPool(data))
|
||||||
, m_sdir(data.getSdir(), GCNDataTag{})
|
, m_sdir(data.getSdir(), GCNDataTag{})
|
||||||
, m_samp(data.getSamp())
|
, m_samp(data.getSamp())
|
||||||
, m_fmt(DataFormat::GCN)
|
, m_fmt(DataFormat::GCN)
|
||||||
|
@ -14,8 +14,8 @@ AudioGroup::AudioGroup(const AudioGroupData& data, GCNDataTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag)
|
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag)
|
||||||
: m_proj(data.getProj(), absOffs, N64DataTag{})
|
: m_proj(AudioGroupProject::CreateAudioGroupProject(data))
|
||||||
, m_pool(data.getPool())
|
, m_pool(AudioGroupPool::CreateAudioGroupPool(data))
|
||||||
, m_sdir(data.getSdir(), data.getSamp(), absOffs, N64DataTag{})
|
, m_sdir(data.getSdir(), data.getSamp(), absOffs, N64DataTag{})
|
||||||
, m_samp(data.getSamp())
|
, m_samp(data.getSamp())
|
||||||
, m_fmt(DataFormat::N64)
|
, m_fmt(DataFormat::N64)
|
||||||
|
@ -23,8 +23,8 @@ AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag)
|
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag)
|
||||||
: m_proj(data.getProj(), absOffs, PCDataTag{})
|
: m_proj(AudioGroupProject::CreateAudioGroupProject(data))
|
||||||
, m_pool(data.getPool(), PCDataTag{})
|
, m_pool(AudioGroupPool::CreateAudioGroupPool(data))
|
||||||
, m_sdir(data.getSdir(), absOffs, PCDataTag{})
|
, m_sdir(data.getSdir(), absOffs, PCDataTag{})
|
||||||
, m_samp(data.getSamp())
|
, m_samp(data.getSamp())
|
||||||
, m_fmt(DataFormat::PC)
|
, m_fmt(DataFormat::PC)
|
||||||
|
|
|
@ -1,152 +1,326 @@
|
||||||
#include "amuse/AudioGroupPool.hpp"
|
#include "amuse/AudioGroupPool.hpp"
|
||||||
#include "amuse/Common.hpp"
|
#include "amuse/Common.hpp"
|
||||||
#include "amuse/Entity.hpp"
|
#include "amuse/Entity.hpp"
|
||||||
|
#include "amuse/AudioGroupData.hpp"
|
||||||
|
#include "athena/MemoryReader.hpp"
|
||||||
|
#include "logvisor/logvisor.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
static logvisor::Module Log("amuse::AudioGroupPool");
|
||||||
|
|
||||||
struct Header
|
static bool AtEnd(athena::io::IStreamReader& r)
|
||||||
{
|
{
|
||||||
uint32_t soundMacrosOffset;
|
uint32_t v = r.readUint32Big();
|
||||||
uint32_t tablesOffset;
|
r.seek(-4, athena::Current);
|
||||||
uint32_t keymapsOffset;
|
return v == 0xffffffff;
|
||||||
uint32_t layersOffset;
|
}
|
||||||
void swapBig()
|
|
||||||
{
|
|
||||||
soundMacrosOffset = SBig(soundMacrosOffset);
|
|
||||||
tablesOffset = SBig(tablesOffset);
|
|
||||||
keymapsOffset = SBig(keymapsOffset);
|
|
||||||
layersOffset = SBig(layersOffset);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AudioGroupPool::AudioGroupPool(const unsigned char* data)
|
template <athena::Endian DNAE>
|
||||||
|
AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
|
||||||
{
|
{
|
||||||
Header head = *reinterpret_cast<const Header*>(data);
|
AudioGroupPool ret;
|
||||||
head.swapBig();
|
|
||||||
|
PoolHeader<DNAE> head;
|
||||||
|
head.read(r);
|
||||||
|
|
||||||
if (head.soundMacrosOffset)
|
if (head.soundMacrosOffset)
|
||||||
{
|
{
|
||||||
const unsigned char* cur = data + head.soundMacrosOffset;
|
r.seek(head.soundMacrosOffset, athena::Begin);
|
||||||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
while (!AtEnd(r))
|
||||||
{
|
{
|
||||||
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
|
ObjectHeader<DNAE> objHead;
|
||||||
ObjectId id = SBig(*reinterpret_cast<const ObjectId*>(cur + 4));
|
atInt64 startPos = r.position();
|
||||||
m_soundMacros[id] = cur;
|
objHead.read(r);
|
||||||
cur += size;
|
SoundMacro& macro = ret.m_soundMacros[objHead.objectId.id];
|
||||||
|
macro.readCmds<DNAE>(r, objHead.size - 8);
|
||||||
|
r.seek(startPos + objHead.size, athena::Begin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (head.tablesOffset)
|
if (head.tablesOffset)
|
||||||
{
|
{
|
||||||
const unsigned char* cur = data + head.tablesOffset;
|
r.seek(head.tablesOffset, athena::Begin);
|
||||||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
while (!AtEnd(r))
|
||||||
{
|
{
|
||||||
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
|
ObjectHeader<DNAE> objHead;
|
||||||
ObjectId id = SBig(*reinterpret_cast<const ObjectId*>(cur + 4));
|
atInt64 startPos = r.position();
|
||||||
m_tables[id] = cur + 8;
|
objHead.read(r);
|
||||||
cur += size;
|
auto& ptr = ret.m_tables[objHead.objectId.id];
|
||||||
|
switch (objHead.size)
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
ptr = std::make_unique<ADSR>();
|
||||||
|
static_cast<ADSR&>(*ptr).read(r);
|
||||||
|
break;
|
||||||
|
case 0x14:
|
||||||
|
ptr = std::make_unique<ADSRDLS>();
|
||||||
|
static_cast<ADSRDLS&>(*ptr).read(r);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ptr = std::make_unique<Curve>();
|
||||||
|
static_cast<Curve&>(*ptr).data.resize(objHead.size - 8);
|
||||||
|
r.readUBytesToBuf(&static_cast<Curve&>(*ptr).data[0], objHead.size - 8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r.seek(startPos + objHead.size, athena::Begin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (head.keymapsOffset)
|
if (head.keymapsOffset)
|
||||||
{
|
{
|
||||||
const unsigned char* cur = data + head.keymapsOffset;
|
r.seek(head.keymapsOffset, athena::Begin);
|
||||||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
while (!AtEnd(r))
|
||||||
{
|
{
|
||||||
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
|
ObjectHeader<DNAE> objHead;
|
||||||
ObjectId id = SBig(*reinterpret_cast<const ObjectId*>(cur + 4));
|
atInt64 startPos = r.position();
|
||||||
m_keymaps[id] = reinterpret_cast<const Keymap*>(cur + 8);
|
objHead.read(r);
|
||||||
cur += size;
|
Keymap& km = ret.m_keymaps[objHead.objectId.id];
|
||||||
|
km.read(r);
|
||||||
|
r.seek(startPos + objHead.size, athena::Begin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (head.layersOffset)
|
if (head.layersOffset)
|
||||||
{
|
{
|
||||||
const unsigned char* cur = data + head.layersOffset;
|
r.seek(head.layersOffset, athena::Begin);
|
||||||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
while (!AtEnd(r))
|
||||||
{
|
{
|
||||||
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
|
ObjectHeader<DNAE> objHead;
|
||||||
ObjectId id = SBig(*reinterpret_cast<const ObjectId*>(cur + 4));
|
atInt64 startPos = r.position();
|
||||||
std::vector<const LayerMapping*>& mappingsOut = m_layers[id];
|
objHead.read(r);
|
||||||
|
std::vector<LayerMapping>& lm = ret.m_layers[objHead.objectId.id];
|
||||||
uint32_t count = SBig(*reinterpret_cast<const uint32_t*>(cur + 8));
|
uint32_t count;
|
||||||
mappingsOut.reserve(count);
|
athena::io::Read<athena::io::PropType::None>::Do<decltype(count), DNAE>({}, count, r);
|
||||||
const unsigned char* subcur = cur + 12;
|
lm.reserve(count);
|
||||||
for (uint32_t i = 0; i < count; ++i)
|
for (uint32_t i = 0; i < count; ++i)
|
||||||
mappingsOut.push_back(reinterpret_cast<const LayerMapping*>(subcur + i * 12));
|
{
|
||||||
|
lm.emplace_back();
|
||||||
|
lm.back().read(r);
|
||||||
|
}
|
||||||
|
r.seek(startPos + objHead.size, athena::Begin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cur += size;
|
return ret;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
template AudioGroupPool AudioGroupPool::_AudioGroupPool<athena::Big>(athena::io::IStreamReader& r);
|
||||||
|
template AudioGroupPool AudioGroupPool::_AudioGroupPool<athena::Little>(athena::io::IStreamReader& r);
|
||||||
|
|
||||||
AudioGroupPool::AudioGroupPool(const unsigned char* data, PCDataTag)
|
AudioGroupPool AudioGroupPool::CreateAudioGroupPool(const AudioGroupData& data)
|
||||||
{
|
{
|
||||||
const Header* head = reinterpret_cast<const Header*>(data);
|
athena::io::MemoryReader r(data.getPool(), data.getPoolSize());
|
||||||
|
switch (data.getDataFormat())
|
||||||
if (head->soundMacrosOffset)
|
|
||||||
{
|
{
|
||||||
const unsigned char* cur = data + head->soundMacrosOffset;
|
case DataFormat::PC:
|
||||||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
return _AudioGroupPool<athena::Little>(r);
|
||||||
{
|
default:
|
||||||
uint32_t size = *reinterpret_cast<const uint32_t*>(cur);
|
return _AudioGroupPool<athena::Big>(r);
|
||||||
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
|
|
||||||
m_soundMacros[id] = cur;
|
|
||||||
cur += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (head->tablesOffset)
|
|
||||||
{
|
|
||||||
const unsigned char* cur = data + head->tablesOffset;
|
|
||||||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
|
||||||
{
|
|
||||||
uint32_t size = *reinterpret_cast<const uint32_t*>(cur);
|
|
||||||
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
|
|
||||||
m_tables[id] = cur + 8;
|
|
||||||
cur += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (head->keymapsOffset)
|
|
||||||
{
|
|
||||||
const unsigned char* cur = data + head->keymapsOffset;
|
|
||||||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
|
||||||
{
|
|
||||||
uint32_t size = *reinterpret_cast<const uint32_t*>(cur);
|
|
||||||
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
|
|
||||||
m_keymaps[id] = reinterpret_cast<const Keymap*>(cur + 8);
|
|
||||||
cur += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (head->layersOffset)
|
|
||||||
{
|
|
||||||
const unsigned char* cur = data + head->layersOffset;
|
|
||||||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
|
||||||
{
|
|
||||||
uint32_t size = *reinterpret_cast<const uint32_t*>(cur);
|
|
||||||
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
|
|
||||||
std::vector<const LayerMapping*>& mappingsOut = m_layers[id];
|
|
||||||
|
|
||||||
uint32_t count = *reinterpret_cast<const uint32_t*>(cur + 8);
|
|
||||||
mappingsOut.reserve(count);
|
|
||||||
const unsigned char* subcur = cur + 12;
|
|
||||||
for (uint32_t i = 0; i < count; ++i)
|
|
||||||
mappingsOut.push_back(reinterpret_cast<const LayerMapping*>(subcur + i * 12));
|
|
||||||
|
|
||||||
cur += size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char* AudioGroupPool::soundMacro(ObjectId id) const
|
template <class Tp>
|
||||||
|
static std::unique_ptr<SoundMacro::ICmd> MakeCmd(athena::io::MemoryReader& r)
|
||||||
|
{
|
||||||
|
std::unique_ptr<SoundMacro::ICmd> ret = std::make_unique<Tp>();
|
||||||
|
static_cast<Tp&>(*ret).read(r);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SoundMacro::assertPC(int pc) const
|
||||||
|
{
|
||||||
|
if (pc == -1)
|
||||||
|
return -1;
|
||||||
|
if (pc >= m_cmds.size())
|
||||||
|
{
|
||||||
|
fprintf(stderr, "SoundMacro PC bounds exceeded [%d/%d]\n", pc, int(m_cmds.size()));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
void SoundMacro::readCmds(athena::io::IStreamReader& r, uint32_t size)
|
||||||
|
{
|
||||||
|
uint32_t numCmds = size / 8;
|
||||||
|
m_cmds.reserve(numCmds);
|
||||||
|
for (int i = 0; i < numCmds; ++i)
|
||||||
|
{
|
||||||
|
uint32_t data[2];
|
||||||
|
athena::io::Read<athena::io::PropType::None>::Do<decltype(data), DNAE>({}, data, r);
|
||||||
|
athena::io::MemoryReader r(data, 8);
|
||||||
|
std::unique_ptr<ICmd> cmd;
|
||||||
|
switch (CmdOp(r.readUByte()))
|
||||||
|
{
|
||||||
|
case CmdOp::End:
|
||||||
|
cmd = MakeCmd<CmdEnd>(r); break;
|
||||||
|
case CmdOp::Stop:
|
||||||
|
cmd = MakeCmd<CmdStop>(r); break;
|
||||||
|
case CmdOp::SplitKey:
|
||||||
|
cmd = MakeCmd<CmdSplitKey>(r); break;
|
||||||
|
case CmdOp::SplitVel:
|
||||||
|
cmd = MakeCmd<CmdSplitVel>(r); break;
|
||||||
|
case CmdOp::WaitTicks:
|
||||||
|
cmd = MakeCmd<CmdWaitTicks>(r); break;
|
||||||
|
case CmdOp::Loop:
|
||||||
|
cmd = MakeCmd<CmdLoop>(r); break;
|
||||||
|
case CmdOp::Goto:
|
||||||
|
cmd = MakeCmd<CmdGoto>(r); break;
|
||||||
|
case CmdOp::WaitMs:
|
||||||
|
cmd = MakeCmd<CmdWaitMs>(r); break;
|
||||||
|
case CmdOp::PlayMacro:
|
||||||
|
cmd = MakeCmd<CmdPlayMacro>(r); break;
|
||||||
|
case CmdOp::SendKeyOff:
|
||||||
|
cmd = MakeCmd<CmdSendKeyOff>(r); break;
|
||||||
|
case CmdOp::SplitMod:
|
||||||
|
cmd = MakeCmd<CmdSplitMod>(r); break;
|
||||||
|
case CmdOp::PianoPan:
|
||||||
|
cmd = MakeCmd<CmdPianoPan>(r); break;
|
||||||
|
case CmdOp::SetAdsr:
|
||||||
|
cmd = MakeCmd<CmdSetAdsr>(r); break;
|
||||||
|
case CmdOp::ScaleVolume:
|
||||||
|
cmd = MakeCmd<CmdScaleVolume>(r); break;
|
||||||
|
case CmdOp::Panning:
|
||||||
|
cmd = MakeCmd<CmdPanning>(r); break;
|
||||||
|
case CmdOp::Envelope:
|
||||||
|
cmd = MakeCmd<CmdEnvelope>(r); break;
|
||||||
|
case CmdOp::StartSample:
|
||||||
|
cmd = MakeCmd<CmdStartSample>(r); break;
|
||||||
|
case CmdOp::StopSample:
|
||||||
|
cmd = MakeCmd<CmdStopSample>(r); break;
|
||||||
|
case CmdOp::KeyOff:
|
||||||
|
cmd = MakeCmd<CmdKeyOff>(r); break;
|
||||||
|
case CmdOp::SplitRnd:
|
||||||
|
cmd = MakeCmd<CmdSplitRnd>(r); break;
|
||||||
|
case CmdOp::FadeIn:
|
||||||
|
cmd = MakeCmd<CmdFadeIn>(r); break;
|
||||||
|
case CmdOp::Spanning:
|
||||||
|
cmd = MakeCmd<CmdSpanning>(r); break;
|
||||||
|
case CmdOp::SetAdsrCtrl:
|
||||||
|
cmd = MakeCmd<CmdSetAdsrCtrl>(r); break;
|
||||||
|
case CmdOp::RndNote:
|
||||||
|
cmd = MakeCmd<CmdRndNote>(r); break;
|
||||||
|
case CmdOp::AddNote:
|
||||||
|
cmd = MakeCmd<CmdAddNote>(r); break;
|
||||||
|
case CmdOp::SetNote:
|
||||||
|
cmd = MakeCmd<CmdSetNote>(r); break;
|
||||||
|
case CmdOp::LastNote:
|
||||||
|
cmd = MakeCmd<CmdLastNote>(r); break;
|
||||||
|
case CmdOp::Portamento:
|
||||||
|
cmd = MakeCmd<CmdPortamento>(r); break;
|
||||||
|
case CmdOp::Vibrato:
|
||||||
|
cmd = MakeCmd<CmdVibrato>(r); break;
|
||||||
|
case CmdOp::PitchSweep1:
|
||||||
|
cmd = MakeCmd<CmdPitchSweep1>(r); break;
|
||||||
|
case CmdOp::PitchSweep2:
|
||||||
|
cmd = MakeCmd<CmdPitchSweep2>(r); break;
|
||||||
|
case CmdOp::SetPitch:
|
||||||
|
cmd = MakeCmd<CmdSetPitch>(r); break;
|
||||||
|
case CmdOp::SetPitchAdsr:
|
||||||
|
cmd = MakeCmd<CmdSetPitchAdsr>(r); break;
|
||||||
|
case CmdOp::ScaleVolumeDLS:
|
||||||
|
cmd = MakeCmd<CmdScaleVolumeDLS>(r); break;
|
||||||
|
case CmdOp::Mod2Vibrange:
|
||||||
|
cmd = MakeCmd<CmdMod2Vibrange>(r); break;
|
||||||
|
case CmdOp::SetupTremolo:
|
||||||
|
cmd = MakeCmd<CmdSetupTremolo>(r); break;
|
||||||
|
case CmdOp::Return:
|
||||||
|
cmd = MakeCmd<CmdReturn>(r); break;
|
||||||
|
case CmdOp::GoSub:
|
||||||
|
cmd = MakeCmd<CmdGoSub>(r); break;
|
||||||
|
case CmdOp::TrapEvent:
|
||||||
|
cmd = MakeCmd<CmdTrapEvent>(r); break;
|
||||||
|
case CmdOp::UntrapEvent:
|
||||||
|
cmd = MakeCmd<CmdUntrapEvent>(r); break;
|
||||||
|
case CmdOp::SendMessage:
|
||||||
|
cmd = MakeCmd<CmdSendMessage>(r); break;
|
||||||
|
case CmdOp::GetMessage:
|
||||||
|
cmd = MakeCmd<CmdGetMessage>(r); break;
|
||||||
|
case CmdOp::GetVid:
|
||||||
|
cmd = MakeCmd<CmdGetVid>(r); break;
|
||||||
|
case CmdOp::AddAgeCount:
|
||||||
|
cmd = MakeCmd<CmdAddAgeCount>(r); break;
|
||||||
|
case CmdOp::SetAgeCount:
|
||||||
|
cmd = MakeCmd<CmdSetAgeCount>(r); break;
|
||||||
|
case CmdOp::SendFlag:
|
||||||
|
cmd = MakeCmd<CmdSendFlag>(r); break;
|
||||||
|
case CmdOp::PitchWheelR:
|
||||||
|
cmd = MakeCmd<CmdPitchWheelR>(r); break;
|
||||||
|
case CmdOp::SetPriority:
|
||||||
|
cmd = MakeCmd<CmdSetPriority>(r); break;
|
||||||
|
case CmdOp::AddPriority:
|
||||||
|
cmd = MakeCmd<CmdAddPriority>(r); break;
|
||||||
|
case CmdOp::AgeCntSpeed:
|
||||||
|
cmd = MakeCmd<CmdAgeCntSpeed>(r); break;
|
||||||
|
case CmdOp::AgeCntVel:
|
||||||
|
cmd = MakeCmd<CmdAgeCntVel>(r); break;
|
||||||
|
case CmdOp::VolSelect:
|
||||||
|
cmd = MakeCmd<CmdVolSelect>(r); break;
|
||||||
|
case CmdOp::PanSelect:
|
||||||
|
cmd = MakeCmd<CmdPanSelect>(r); break;
|
||||||
|
case CmdOp::PitchWheelSelect:
|
||||||
|
cmd = MakeCmd<CmdPitchWheelSelect>(r); break;
|
||||||
|
case CmdOp::ModWheelSelect:
|
||||||
|
cmd = MakeCmd<CmdModWheelSelect>(r); break;
|
||||||
|
case CmdOp::PedalSelect:
|
||||||
|
cmd = MakeCmd<CmdPedalSelect>(r); break;
|
||||||
|
case CmdOp::PortamentoSelect:
|
||||||
|
cmd = MakeCmd<CmdPortamentoSelect>(r); break;
|
||||||
|
case CmdOp::ReverbSelect:
|
||||||
|
cmd = MakeCmd<CmdReverbSelect>(r); break;
|
||||||
|
case CmdOp::SpanSelect:
|
||||||
|
cmd = MakeCmd<CmdSpanSelect>(r); break;
|
||||||
|
case CmdOp::DopplerSelect:
|
||||||
|
cmd = MakeCmd<CmdDopplerSelect>(r); break;
|
||||||
|
case CmdOp::TremoloSelect:
|
||||||
|
cmd = MakeCmd<CmdTremoloSelect>(r); break;
|
||||||
|
case CmdOp::PreASelect:
|
||||||
|
cmd = MakeCmd<CmdPreASelect>(r); break;
|
||||||
|
case CmdOp::PreBSelect:
|
||||||
|
cmd = MakeCmd<CmdPreBSelect>(r); break;
|
||||||
|
case CmdOp::PostBSelect:
|
||||||
|
cmd = MakeCmd<CmdPostBSelect>(r); break;
|
||||||
|
case CmdOp::AuxAFXSelect:
|
||||||
|
cmd = MakeCmd<CmdAuxAFXSelect>(r); break;
|
||||||
|
case CmdOp::AuxBFXSelect:
|
||||||
|
cmd = MakeCmd<CmdAuxBFXSelect>(r); break;
|
||||||
|
case CmdOp::SetupLFO:
|
||||||
|
cmd = MakeCmd<CmdSetupLFO>(r); break;
|
||||||
|
case CmdOp::ModeSelect:
|
||||||
|
cmd = MakeCmd<CmdModeSelect>(r); break;
|
||||||
|
case CmdOp::SetKeygroup:
|
||||||
|
cmd = MakeCmd<CmdSetKeygroup>(r); break;
|
||||||
|
case CmdOp::SRCmodeSelect:
|
||||||
|
cmd = MakeCmd<CmdSRCmodeSelect>(r); break;
|
||||||
|
case CmdOp::AddVars:
|
||||||
|
cmd = MakeCmd<CmdAddVars>(r); break;
|
||||||
|
case CmdOp::SubVars:
|
||||||
|
cmd = MakeCmd<CmdSubVars>(r); break;
|
||||||
|
case CmdOp::MulVars:
|
||||||
|
cmd = MakeCmd<CmdMulVars>(r); break;
|
||||||
|
case CmdOp::DivVars:
|
||||||
|
cmd = MakeCmd<CmdDivVars>(r); break;
|
||||||
|
case CmdOp::AddIVars:
|
||||||
|
cmd = MakeCmd<CmdAddIVars>(r); break;
|
||||||
|
case CmdOp::IfEqual:
|
||||||
|
cmd = MakeCmd<CmdIfEqual>(r); break;
|
||||||
|
case CmdOp::IfLess:
|
||||||
|
cmd = MakeCmd<CmdIfLess>(r); break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_cmds.push_back(std::move(cmd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template void SoundMacro::readCmds<athena::Big>(athena::io::IStreamReader& r, uint32_t size);
|
||||||
|
template void SoundMacro::readCmds<athena::Little>(athena::io::IStreamReader& r, uint32_t size);
|
||||||
|
|
||||||
|
const SoundMacro* AudioGroupPool::soundMacro(ObjectId id) const
|
||||||
{
|
{
|
||||||
auto search = m_soundMacros.find(id);
|
auto search = m_soundMacros.find(id);
|
||||||
if (search == m_soundMacros.cend())
|
if (search == m_soundMacros.cend())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return search->second;
|
return &search->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Keymap* AudioGroupPool::keymap(ObjectId id) const
|
const Keymap* AudioGroupPool::keymap(ObjectId id) const
|
||||||
|
@ -154,10 +328,10 @@ const Keymap* AudioGroupPool::keymap(ObjectId id) const
|
||||||
auto search = m_keymaps.find(id);
|
auto search = m_keymaps.find(id);
|
||||||
if (search == m_keymaps.cend())
|
if (search == m_keymaps.cend())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return search->second;
|
return &search->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<const LayerMapping*>* AudioGroupPool::layer(ObjectId id) const
|
const std::vector<LayerMapping>* AudioGroupPool::layer(ObjectId id) const
|
||||||
{
|
{
|
||||||
auto search = m_layers.find(id);
|
auto search = m_layers.find(id);
|
||||||
if (search == m_layers.cend())
|
if (search == m_layers.cend())
|
||||||
|
@ -170,6 +344,41 @@ const ADSR* AudioGroupPool::tableAsAdsr(ObjectId id) const
|
||||||
auto search = m_tables.find(id);
|
auto search = m_tables.find(id);
|
||||||
if (search == m_tables.cend())
|
if (search == m_tables.cend())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return reinterpret_cast<const ADSR*>(search->second);
|
return static_cast<const ADSR*>(search->second.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void amuse::Curve::Enumerate<LittleDNA::Read>(athena::io::IStreamReader& r)
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, "Curve binary DNA read not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void amuse::Curve::Enumerate<LittleDNA::Write>(athena::io::IStreamWriter& w)
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, "Curve binary DNA write not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void amuse::Curve::Enumerate<LittleDNA::BinarySize>(size_t& sz)
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, "Curve binary DNA size not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void amuse::Curve::Enumerate<LittleDNA::ReadYaml>(athena::io::YAMLDocReader& r)
|
||||||
|
{
|
||||||
|
r.enumerate(nullptr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void amuse::Curve::Enumerate<LittleDNA::WriteYaml>(athena::io::YAMLDocWriter& w)
|
||||||
|
{
|
||||||
|
w.enumerate(nullptr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* amuse::Curve::DNAType()
|
||||||
|
{
|
||||||
|
return "amuse::ADSR";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,548 +1,224 @@
|
||||||
#include "amuse/AudioGroupProject.hpp"
|
#include "amuse/AudioGroupProject.hpp"
|
||||||
#include "amuse/AudioGroupData.hpp"
|
#include "amuse/AudioGroupData.hpp"
|
||||||
#include "amuse/Common.hpp"
|
#include "athena/MemoryReader.hpp"
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
enum class GroupType : uint16_t
|
static bool AtEnd32(athena::io::IStreamReader& r)
|
||||||
{
|
{
|
||||||
Song,
|
uint32_t v = r.readUint32Big();
|
||||||
SFX
|
r.seek(-4, athena::Current);
|
||||||
};
|
return v == 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
struct GroupHeader
|
static bool AtEnd16(athena::io::IStreamReader& r)
|
||||||
{
|
{
|
||||||
uint32_t groupEndOff;
|
uint16_t v = r.readUint16Big();
|
||||||
uint16_t groupId;
|
r.seek(-2, athena::Current);
|
||||||
GroupType type;
|
return v == 0xffff;
|
||||||
uint32_t soundMacroIdsOff;
|
}
|
||||||
uint32_t samplIdsOff;
|
|
||||||
uint32_t tableIdsOff;
|
|
||||||
uint32_t keymapIdsOff;
|
|
||||||
uint32_t layerIdsOff;
|
|
||||||
uint32_t pageTableOff;
|
|
||||||
uint32_t drumTableOff;
|
|
||||||
uint32_t midiSetupsOff;
|
|
||||||
|
|
||||||
void swapBig()
|
AudioGroupProject::AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag)
|
||||||
|
{
|
||||||
|
while (!AtEnd32(r))
|
||||||
{
|
{
|
||||||
groupEndOff = SBig(groupEndOff);
|
GroupHeader<athena::Big> header;
|
||||||
groupId = SBig(groupId);
|
header.read(r);
|
||||||
type = GroupType(SBig(uint16_t(type)));
|
|
||||||
soundMacroIdsOff = SBig(soundMacroIdsOff);
|
|
||||||
samplIdsOff = SBig(samplIdsOff);
|
|
||||||
tableIdsOff = SBig(tableIdsOff);
|
|
||||||
keymapIdsOff = SBig(keymapIdsOff);
|
|
||||||
layerIdsOff = SBig(layerIdsOff);
|
|
||||||
pageTableOff = SBig(pageTableOff);
|
|
||||||
drumTableOff = SBig(drumTableOff);
|
|
||||||
midiSetupsOff = SBig(midiSetupsOff);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AudioGroupProject::AudioGroupProject(const unsigned char* data, GCNDataTag)
|
|
||||||
{
|
|
||||||
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
|
|
||||||
while (group->groupEndOff != 0xffffffff)
|
|
||||||
{
|
|
||||||
GroupHeader header = *group;
|
|
||||||
header.swapBig();
|
|
||||||
|
|
||||||
AudioGroupIndex* bIdx = nullptr;
|
|
||||||
|
|
||||||
if (header.type == GroupType::Song)
|
if (header.type == GroupType::Song)
|
||||||
{
|
{
|
||||||
SongGroupIndex& idx = m_songGroups[header.groupId];
|
SongGroupIndex& idx = m_songGroups[header.groupId];
|
||||||
bIdx = &idx;
|
|
||||||
|
|
||||||
/* Normal pages */
|
/* Normal pages */
|
||||||
const SongGroupIndex::PageEntry* normEntries =
|
r.seek(header.pageTableOff, athena::Begin);
|
||||||
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + header.pageTableOff);
|
while (!AtEnd16(r))
|
||||||
while (normEntries->objId != 0xffff)
|
|
||||||
{
|
{
|
||||||
idx.m_normPages[normEntries->programNo] = normEntries;
|
SongGroupIndex::PageEntryDNA<athena::Big> entry;
|
||||||
++normEntries;
|
entry.read(r);
|
||||||
|
idx.m_normPages[entry.programNo] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drum pages */
|
/* Drum pages */
|
||||||
const SongGroupIndex::PageEntry* drumEntries =
|
r.seek(header.drumTableOff, athena::Begin);
|
||||||
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + header.drumTableOff);
|
while (!AtEnd16(r))
|
||||||
while (drumEntries->objId != 0xffff)
|
|
||||||
{
|
{
|
||||||
idx.m_drumPages[drumEntries->programNo] = drumEntries;
|
SongGroupIndex::PageEntryDNA<athena::Big> entry;
|
||||||
++drumEntries;
|
entry.read(r);
|
||||||
|
idx.m_drumPages[entry.programNo] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MIDI setups */
|
/* MIDI setups */
|
||||||
const uint8_t* setupData = data + header.midiSetupsOff;
|
r.seek(header.midiSetupsOff, athena::Begin);
|
||||||
const uint8_t* setupEnd = data + header.groupEndOff;
|
while (r.position() < header.groupEndOff)
|
||||||
while (setupData < setupEnd)
|
|
||||||
{
|
{
|
||||||
uint16_t songId = SBig(*reinterpret_cast<const uint16_t*>(setupData));
|
uint16_t songId = r.readUint16Big();
|
||||||
idx.m_midiSetups[songId] =
|
r.seek(2, athena::Current);
|
||||||
reinterpret_cast<const std::array<SongGroupIndex::MIDISetup, 16>*>(setupData + 4);
|
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
|
||||||
setupData += 5 * 16 + 4;
|
for (int i = 0; i < 16 ; ++i)
|
||||||
|
setup[i].read(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (header.type == GroupType::SFX)
|
else if (header.type == GroupType::SFX)
|
||||||
{
|
{
|
||||||
SFXGroupIndex& idx = m_sfxGroups[header.groupId];
|
SFXGroupIndex& idx = m_sfxGroups[header.groupId];
|
||||||
bIdx = &idx;
|
|
||||||
|
|
||||||
/* SFX entries */
|
/* SFX entries */
|
||||||
uint16_t count = SBig(*reinterpret_cast<const uint16_t*>(data + header.pageTableOff));
|
r.seek(header.pageTableOff, athena::Begin);
|
||||||
|
uint16_t count = r.readUint16Big();
|
||||||
|
r.seek(2, athena::Current);
|
||||||
idx.m_sfxEntries.reserve(count);
|
idx.m_sfxEntries.reserve(count);
|
||||||
const SFXGroupIndex::SFXEntry* entries =
|
|
||||||
reinterpret_cast<const SFXGroupIndex::SFXEntry*>(data + header.pageTableOff + 4);
|
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
idx.m_sfxEntries[SBig(entries->defineId)] = entries;
|
SFXGroupIndex::SFXEntryDNA<athena::Big> entry;
|
||||||
++entries;
|
entry.read(r);
|
||||||
|
idx.m_sfxEntries[entry.defineId.id] = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bIdx)
|
r.seek(header.groupEndOff, athena::Begin);
|
||||||
{
|
|
||||||
bIdx->m_soundMacroIndex = reinterpret_cast<const uint16_t*>(data + header.soundMacroIdsOff);
|
|
||||||
bIdx->m_tablesIndex = reinterpret_cast<const uint16_t*>(data + header.tableIdsOff);
|
|
||||||
bIdx->m_keymapsIndex = reinterpret_cast<const uint16_t*>(data + header.keymapIdsOff);
|
|
||||||
bIdx->m_layersIndex = reinterpret_cast<const uint16_t*>(data + header.layerIdsOff);
|
|
||||||
}
|
|
||||||
|
|
||||||
group = reinterpret_cast<const GroupHeader*>(data + header.groupEndOff);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MusyX1PageEntry
|
template <athena::Endian DNAE>
|
||||||
|
AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReader& r, bool absOffs)
|
||||||
{
|
{
|
||||||
ObjectId objId;
|
AudioGroupProject ret;
|
||||||
uint8_t priority;
|
|
||||||
uint8_t maxVoices;
|
|
||||||
uint8_t unk;
|
|
||||||
uint8_t programNo;
|
|
||||||
uint8_t pad[2];
|
|
||||||
|
|
||||||
void setIntoMusyX2(SongGroupIndex::PageEntry& ent) const
|
while (!AtEnd32(r))
|
||||||
{
|
{
|
||||||
ent.objId = objId;
|
atInt64 groupBegin = r.position();
|
||||||
ent.priority = priority;
|
atInt64 subDataOff = absOffs ? 0 : groupBegin + 8;
|
||||||
ent.maxVoices = maxVoices;
|
GroupHeader<DNAE> header;
|
||||||
ent.programNo = programNo;
|
header.read(r);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MusyX1MIDISetup
|
|
||||||
{
|
|
||||||
uint8_t programNo;
|
|
||||||
uint8_t volume;
|
|
||||||
uint8_t panning;
|
|
||||||
uint8_t reverb;
|
|
||||||
uint8_t chorus;
|
|
||||||
uint8_t pad[3];
|
|
||||||
|
|
||||||
void setIntoMusyX2(SongGroupIndex::MIDISetup& ent) const
|
|
||||||
{
|
|
||||||
ent.programNo = programNo;
|
|
||||||
ent.volume = volume;
|
|
||||||
ent.panning = panning;
|
|
||||||
ent.reverb = reverb;
|
|
||||||
ent.chorus = chorus;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, N64DataTag)
|
|
||||||
{
|
|
||||||
size_t normPageCount = 0;
|
|
||||||
size_t drumPageCount = 0;
|
|
||||||
size_t midiSetupCount = 0;
|
|
||||||
|
|
||||||
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
|
|
||||||
while (group->groupEndOff != 0xffffffff)
|
|
||||||
{
|
|
||||||
const unsigned char* subData = data + 8;
|
|
||||||
GroupHeader header = *group;
|
|
||||||
header.swapBig();
|
|
||||||
|
|
||||||
if (header.type == GroupType::Song)
|
if (header.type == GroupType::Song)
|
||||||
{
|
{
|
||||||
/* Normal pages */
|
SongGroupIndex& idx = ret.m_songGroups[header.groupId];
|
||||||
const MusyX1PageEntry* normEntries =
|
|
||||||
reinterpret_cast<const MusyX1PageEntry*>(subData + header.pageTableOff);
|
|
||||||
while (normEntries->objId != 0xffff)
|
|
||||||
{
|
|
||||||
++normPageCount;
|
|
||||||
++normEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drum pages */
|
|
||||||
const MusyX1PageEntry* drumEntries =
|
|
||||||
reinterpret_cast<const MusyX1PageEntry*>(subData + header.drumTableOff);
|
|
||||||
while (drumEntries->objId != 0xffff)
|
|
||||||
{
|
|
||||||
++drumPageCount;
|
|
||||||
++drumEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MIDI setups */
|
|
||||||
const uint8_t* setupData = subData + header.midiSetupsOff;
|
|
||||||
const uint8_t* setupEnd = subData + header.groupEndOff;
|
|
||||||
while (setupData < setupEnd)
|
|
||||||
{
|
|
||||||
++midiSetupCount;
|
|
||||||
setupData += 8 * 16 + 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data += header.groupEndOff;
|
|
||||||
group = reinterpret_cast<const GroupHeader*>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (normPageCount)
|
|
||||||
m_convNormalPages.reset(new SongGroupIndex::PageEntry[normPageCount]);
|
|
||||||
if (drumPageCount)
|
|
||||||
m_convDrumPages.reset(new SongGroupIndex::PageEntry[drumPageCount]);
|
|
||||||
if (midiSetupCount)
|
|
||||||
m_convMidiSetups.reset(new std::array<SongGroupIndex::MIDISetup, 16>[ midiSetupCount ]);
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, N64DataTag)
|
|
||||||
{
|
|
||||||
if (!absOffs)
|
|
||||||
_allocateConvBuffers(data, N64DataTag{});
|
|
||||||
SongGroupIndex::PageEntry* normPagesBuf = m_convNormalPages.get();
|
|
||||||
SongGroupIndex::PageEntry* drumPagesBuf = m_convDrumPages.get();
|
|
||||||
std::array<SongGroupIndex::MIDISetup, 16>* midiSetupsBuf = m_convMidiSetups.get();
|
|
||||||
|
|
||||||
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
|
|
||||||
while (group->groupEndOff != 0xffffffff)
|
|
||||||
{
|
|
||||||
const unsigned char* subData = absOffs ? data : data + 8;
|
|
||||||
GroupHeader header = *group;
|
|
||||||
header.swapBig();
|
|
||||||
|
|
||||||
AudioGroupIndex* bIdx = nullptr;
|
|
||||||
|
|
||||||
if (header.type == GroupType::Song)
|
|
||||||
{
|
|
||||||
SongGroupIndex& idx = m_songGroups[header.groupId];
|
|
||||||
bIdx = &idx;
|
|
||||||
|
|
||||||
if (absOffs)
|
if (absOffs)
|
||||||
{
|
{
|
||||||
/* Normal pages */
|
/* Normal pages */
|
||||||
const SongGroupIndex::PageEntry* normEntries =
|
r.seek(header.pageTableOff, athena::Begin);
|
||||||
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + header.pageTableOff);
|
while (!AtEnd16(r))
|
||||||
while (normEntries->objId != 0xffff)
|
|
||||||
{
|
{
|
||||||
idx.m_normPages[normEntries->programNo] = normEntries;
|
SongGroupIndex::PageEntryDNA<DNAE> entry;
|
||||||
++normEntries;
|
entry.read(r);
|
||||||
|
idx.m_normPages[entry.programNo] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drum pages */
|
/* Drum pages */
|
||||||
const SongGroupIndex::PageEntry* drumEntries =
|
r.seek(header.drumTableOff, athena::Begin);
|
||||||
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + header.drumTableOff);
|
while (!AtEnd16(r))
|
||||||
while (drumEntries->objId != 0xffff)
|
|
||||||
{
|
{
|
||||||
idx.m_drumPages[drumEntries->programNo] = drumEntries;
|
SongGroupIndex::PageEntryDNA<DNAE> entry;
|
||||||
++drumEntries;
|
entry.read(r);
|
||||||
|
idx.m_drumPages[entry.programNo] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MIDI setups */
|
/* MIDI setups */
|
||||||
const uint8_t* setupData = data + header.midiSetupsOff;
|
r.seek(header.midiSetupsOff, athena::Begin);
|
||||||
const uint8_t* setupEnd = data + header.groupEndOff;
|
while (r.position() < header.groupEndOff)
|
||||||
while (setupData < setupEnd)
|
|
||||||
{
|
{
|
||||||
uint16_t songId = SBig(*reinterpret_cast<const uint16_t*>(setupData));
|
uint16_t songId = r.readUint16Big();
|
||||||
idx.m_midiSetups[songId] =
|
r.seek(2, athena::Current);
|
||||||
reinterpret_cast<const std::array<SongGroupIndex::MIDISetup, 16>*>(setupData + 4);
|
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
|
||||||
setupData += 5 * 16 + 4;
|
for (int i = 0; i < 16 ; ++i)
|
||||||
|
setup[i].read(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Normal pages */
|
/* Normal pages */
|
||||||
const MusyX1PageEntry* normEntries =
|
r.seek(subDataOff + header.pageTableOff, athena::Begin);
|
||||||
reinterpret_cast<const MusyX1PageEntry*>(subData + header.pageTableOff);
|
while (!AtEnd16(r))
|
||||||
while (normEntries->objId != 0xffff)
|
|
||||||
{
|
{
|
||||||
normEntries->setIntoMusyX2(*normPagesBuf);
|
SongGroupIndex::MusyX1PageEntryDNA<DNAE> entry;
|
||||||
idx.m_normPages[normEntries->programNo] = normPagesBuf;
|
entry.read(r);
|
||||||
++normEntries;
|
idx.m_normPages[entry.programNo] = entry;
|
||||||
++normPagesBuf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drum pages */
|
/* Drum pages */
|
||||||
const MusyX1PageEntry* drumEntries =
|
r.seek(subDataOff + header.drumTableOff, athena::Begin);
|
||||||
reinterpret_cast<const MusyX1PageEntry*>(subData + header.drumTableOff);
|
while (!AtEnd16(r))
|
||||||
while (drumEntries->objId != 0xffff)
|
|
||||||
{
|
{
|
||||||
drumEntries->setIntoMusyX2(*drumPagesBuf);
|
SongGroupIndex::MusyX1PageEntryDNA<DNAE> entry;
|
||||||
idx.m_drumPages[drumEntries->programNo] = drumPagesBuf;
|
entry.read(r);
|
||||||
++drumEntries;
|
idx.m_drumPages[entry.programNo] = entry;
|
||||||
++drumPagesBuf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MIDI setups */
|
/* MIDI setups */
|
||||||
const uint8_t* setupData = subData + header.midiSetupsOff;
|
r.seek(subDataOff + header.midiSetupsOff, athena::Begin);
|
||||||
const uint8_t* setupEnd = subData + header.groupEndOff;
|
while (r.position() < groupBegin + header.groupEndOff)
|
||||||
while (setupData < setupEnd)
|
|
||||||
{
|
{
|
||||||
uint16_t songId = SBig(*reinterpret_cast<const uint16_t*>(setupData));
|
uint16_t songId = r.readUint16Big();
|
||||||
const std::array<MusyX1MIDISetup, 16>* midiSetups =
|
r.seek(2, athena::Current);
|
||||||
reinterpret_cast<const std::array<MusyX1MIDISetup, 16>*>(setupData + 4);
|
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
|
||||||
|
for (int i = 0; i < 16 ; ++i)
|
||||||
for (int i = 0; i < 16; ++i)
|
{
|
||||||
(*midiSetups)[i].setIntoMusyX2((*midiSetupsBuf)[i]);
|
SongGroupIndex::MusyX1MIDISetup ent;
|
||||||
|
ent.read(r);
|
||||||
idx.m_midiSetups[songId] = midiSetupsBuf;
|
setup[i] = ent;
|
||||||
setupData += 8 * 16 + 4;
|
}
|
||||||
++midiSetupsBuf;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (header.type == GroupType::SFX)
|
else if (header.type == GroupType::SFX)
|
||||||
{
|
{
|
||||||
SFXGroupIndex& idx = m_sfxGroups[header.groupId];
|
SFXGroupIndex& idx = ret.m_sfxGroups[header.groupId];
|
||||||
bIdx = &idx;
|
|
||||||
|
|
||||||
/* SFX entries */
|
/* SFX entries */
|
||||||
uint16_t count = SBig(*reinterpret_cast<const uint16_t*>(subData + header.pageTableOff));
|
r.seek(subDataOff + header.pageTableOff, athena::Begin);
|
||||||
|
uint16_t count = r.readUint16Big();
|
||||||
|
r.seek(2, athena::Current);
|
||||||
idx.m_sfxEntries.reserve(count);
|
idx.m_sfxEntries.reserve(count);
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
const SFXGroupIndex::SFXEntry* entries =
|
SFXGroupIndex::SFXEntryDNA<DNAE> entry;
|
||||||
reinterpret_cast<const SFXGroupIndex::SFXEntry*>(subData + header.pageTableOff + 4 + i * 12);
|
entry.read(r);
|
||||||
idx.m_sfxEntries[SBig(entries->defineId)] = entries;
|
r.seek(2, athena::Current);
|
||||||
|
idx.m_sfxEntries[entry.defineId.id] = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bIdx)
|
|
||||||
{
|
|
||||||
bIdx->m_soundMacroIndex = reinterpret_cast<const uint16_t*>(subData + header.soundMacroIdsOff);
|
|
||||||
bIdx->m_tablesIndex = reinterpret_cast<const uint16_t*>(subData + header.tableIdsOff);
|
|
||||||
bIdx->m_keymapsIndex = reinterpret_cast<const uint16_t*>(subData + header.keymapIdsOff);
|
|
||||||
bIdx->m_layersIndex = reinterpret_cast<const uint16_t*>(subData + header.layerIdsOff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (absOffs)
|
if (absOffs)
|
||||||
group = reinterpret_cast<const GroupHeader*>(data + header.groupEndOff);
|
r.seek(header.groupEndOff, athena::Begin);
|
||||||
else
|
else
|
||||||
{
|
r.seek(groupBegin + header.groupEndOff, athena::Begin);
|
||||||
data += header.groupEndOff;
|
|
||||||
group = reinterpret_cast<const GroupHeader*>(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, PCDataTag)
|
|
||||||
{
|
|
||||||
size_t normPageCount = 0;
|
|
||||||
size_t drumPageCount = 0;
|
|
||||||
size_t midiSetupCount = 0;
|
|
||||||
|
|
||||||
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
|
|
||||||
while (group->groupEndOff != 0xffffffff)
|
|
||||||
{
|
|
||||||
const unsigned char* subData = data + 8;
|
|
||||||
|
|
||||||
if (group->type == GroupType::Song)
|
|
||||||
{
|
|
||||||
/* Normal pages */
|
|
||||||
const MusyX1PageEntry* normEntries =
|
|
||||||
reinterpret_cast<const MusyX1PageEntry*>(subData + group->pageTableOff);
|
|
||||||
while (normEntries->objId != 0xffff)
|
|
||||||
{
|
|
||||||
++normPageCount;
|
|
||||||
++normEntries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drum pages */
|
return ret;
|
||||||
const MusyX1PageEntry* drumEntries =
|
|
||||||
reinterpret_cast<const MusyX1PageEntry*>(subData + group->drumTableOff);
|
|
||||||
while (drumEntries->objId != 0xffff)
|
|
||||||
{
|
|
||||||
++drumPageCount;
|
|
||||||
++drumEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MIDI setups */
|
|
||||||
const uint8_t* setupData = subData + group->midiSetupsOff;
|
|
||||||
const uint8_t* setupEnd = subData + group->groupEndOff;
|
|
||||||
while (setupData < setupEnd)
|
|
||||||
{
|
|
||||||
++midiSetupCount;
|
|
||||||
setupData += 8 * 16 + 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data += group->groupEndOff;
|
|
||||||
group = reinterpret_cast<const GroupHeader*>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (normPageCount)
|
|
||||||
m_convNormalPages.reset(new SongGroupIndex::PageEntry[normPageCount]);
|
|
||||||
if (drumPageCount)
|
|
||||||
m_convDrumPages.reset(new SongGroupIndex::PageEntry[drumPageCount]);
|
|
||||||
if (midiSetupCount)
|
|
||||||
m_convMidiSetups.reset(new std::array<SongGroupIndex::MIDISetup, 16>[ midiSetupCount ]);
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, PCDataTag)
|
|
||||||
{
|
|
||||||
if (!absOffs)
|
|
||||||
_allocateConvBuffers(data, PCDataTag{});
|
|
||||||
SongGroupIndex::PageEntry* normPagesBuf = m_convNormalPages.get();
|
|
||||||
SongGroupIndex::PageEntry* drumPagesBuf = m_convDrumPages.get();
|
|
||||||
std::array<SongGroupIndex::MIDISetup, 16>* midiSetupsBuf = m_convMidiSetups.get();
|
|
||||||
|
|
||||||
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
|
|
||||||
while (group->groupEndOff != 0xffffffff)
|
|
||||||
{
|
|
||||||
const unsigned char* subData = absOffs ? data : data + 8;
|
|
||||||
|
|
||||||
AudioGroupIndex* bIdx = nullptr;
|
|
||||||
|
|
||||||
if (group->type == GroupType::Song)
|
|
||||||
{
|
|
||||||
SongGroupIndex& idx = m_songGroups[group->groupId];
|
|
||||||
bIdx = &idx;
|
|
||||||
|
|
||||||
if (absOffs)
|
|
||||||
{
|
|
||||||
/* Normal pages */
|
|
||||||
const SongGroupIndex::PageEntry* normEntries =
|
|
||||||
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + group->pageTableOff);
|
|
||||||
while (normEntries->objId != 0xffff)
|
|
||||||
{
|
|
||||||
idx.m_normPages[normEntries->programNo] = normEntries;
|
|
||||||
++normEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drum pages */
|
|
||||||
const SongGroupIndex::PageEntry* drumEntries =
|
|
||||||
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + group->drumTableOff);
|
|
||||||
while (drumEntries->objId != 0xffff)
|
|
||||||
{
|
|
||||||
idx.m_drumPages[drumEntries->programNo] = drumEntries;
|
|
||||||
++drumEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MIDI setups */
|
|
||||||
const uint8_t* setupData = data + group->midiSetupsOff;
|
|
||||||
const uint8_t* setupEnd = data + group->groupEndOff;
|
|
||||||
while (setupData < setupEnd)
|
|
||||||
{
|
|
||||||
uint16_t songId = *reinterpret_cast<const uint16_t*>(setupData);
|
|
||||||
idx.m_midiSetups[songId] =
|
|
||||||
reinterpret_cast<const std::array<SongGroupIndex::MIDISetup, 16>*>(setupData + 4);
|
|
||||||
setupData += 5 * 16 + 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Normal pages */
|
|
||||||
const MusyX1PageEntry* normEntries =
|
|
||||||
reinterpret_cast<const MusyX1PageEntry*>(subData + group->pageTableOff);
|
|
||||||
while (normEntries->objId != 0xffff)
|
|
||||||
{
|
|
||||||
normEntries->setIntoMusyX2(*normPagesBuf);
|
|
||||||
idx.m_normPages[normEntries->programNo] = normPagesBuf;
|
|
||||||
++normEntries;
|
|
||||||
++normPagesBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drum pages */
|
|
||||||
const MusyX1PageEntry* drumEntries =
|
|
||||||
reinterpret_cast<const MusyX1PageEntry*>(subData + group->drumTableOff);
|
|
||||||
while (drumEntries->objId != 0xffff)
|
|
||||||
{
|
|
||||||
drumEntries->setIntoMusyX2(*drumPagesBuf);
|
|
||||||
idx.m_drumPages[drumEntries->programNo] = drumPagesBuf;
|
|
||||||
++drumEntries;
|
|
||||||
++drumPagesBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MIDI setups */
|
|
||||||
const uint8_t* setupData = subData + group->midiSetupsOff;
|
|
||||||
const uint8_t* setupEnd = subData + group->groupEndOff;
|
|
||||||
while (setupData < setupEnd)
|
|
||||||
{
|
|
||||||
uint16_t songId = *reinterpret_cast<const uint16_t*>(setupData);
|
|
||||||
const std::array<MusyX1MIDISetup, 16>* midiSetups =
|
|
||||||
reinterpret_cast<const std::array<MusyX1MIDISetup, 16>*>(setupData + 4);
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; ++i)
|
|
||||||
(*midiSetups)[i].setIntoMusyX2((*midiSetupsBuf)[i]);
|
|
||||||
|
|
||||||
idx.m_midiSetups[songId] = midiSetupsBuf;
|
|
||||||
setupData += 8 * 16 + 4;
|
|
||||||
++midiSetupsBuf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (group->type == GroupType::SFX)
|
|
||||||
{
|
|
||||||
SFXGroupIndex& idx = m_sfxGroups[group->groupId];
|
|
||||||
bIdx = &idx;
|
|
||||||
|
|
||||||
/* SFX entries */
|
|
||||||
uint16_t count = *reinterpret_cast<const uint16_t*>(subData + group->pageTableOff);
|
|
||||||
idx.m_sfxEntries.reserve(count);
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
const SFXGroupIndex::SFXEntry* entries =
|
|
||||||
reinterpret_cast<const SFXGroupIndex::SFXEntry*>(subData + group->pageTableOff + 4 + i * 12);
|
|
||||||
idx.m_sfxEntries[entries->defineId] = entries;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bIdx)
|
|
||||||
{
|
|
||||||
bIdx->m_soundMacroIndex = reinterpret_cast<const uint16_t*>(subData + group->soundMacroIdsOff);
|
|
||||||
bIdx->m_tablesIndex = reinterpret_cast<const uint16_t*>(subData + group->tableIdsOff);
|
|
||||||
bIdx->m_keymapsIndex = reinterpret_cast<const uint16_t*>(subData + group->keymapIdsOff);
|
|
||||||
bIdx->m_layersIndex = reinterpret_cast<const uint16_t*>(subData + group->layerIdsOff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (absOffs)
|
|
||||||
group = reinterpret_cast<const GroupHeader*>(data + group->groupEndOff);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
data += group->groupEndOff;
|
|
||||||
group = reinterpret_cast<const GroupHeader*>(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioGroupProject AudioGroupProject::CreateAudioGroupProject(const AudioGroupData& data)
|
AudioGroupProject AudioGroupProject::CreateAudioGroupProject(const AudioGroupData& data)
|
||||||
{
|
{
|
||||||
|
athena::io::MemoryReader r(data.getProj(), data.getProjSize());
|
||||||
switch (data.getDataFormat())
|
switch (data.getDataFormat())
|
||||||
{
|
{
|
||||||
case DataFormat::GCN:
|
case DataFormat::GCN:
|
||||||
default:
|
default:
|
||||||
return AudioGroupProject(data.getProj(), GCNDataTag{});
|
return AudioGroupProject(r, GCNDataTag{});
|
||||||
case DataFormat::N64:
|
case DataFormat::N64:
|
||||||
return AudioGroupProject(data.getProj(), data.getAbsoluteProjOffsets(), N64DataTag{});
|
return _AudioGroupProject<athena::Big>(r, data.getAbsoluteProjOffsets());
|
||||||
case DataFormat::PC:
|
case DataFormat::PC:
|
||||||
return AudioGroupProject(data.getProj(), data.getAbsoluteProjOffsets(), PCDataTag{});
|
return _AudioGroupProject<athena::Little>(r, data.getAbsoluteProjOffsets());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SongGroupIndex* AudioGroupProject::getSongGroupIndex(int groupId) const
|
const SongGroupIndex* AudioGroupProject::getSongGroupIndex(int groupId) const
|
||||||
{
|
{
|
||||||
auto search = m_songGroups.find(groupId);
|
auto search = m_songGroups.find(groupId);
|
||||||
if (search == m_songGroups.cend())
|
if (search != m_songGroups.cend())
|
||||||
return nullptr;
|
|
||||||
return &search->second;
|
return &search->second;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SFXGroupIndex* AudioGroupProject::getSFXGroupIndex(int groupId) const
|
const SFXGroupIndex* AudioGroupProject::getSFXGroupIndex(int groupId) const
|
||||||
{
|
{
|
||||||
auto search = m_sfxGroups.find(groupId);
|
auto search = m_sfxGroups.find(groupId);
|
||||||
if (search == m_sfxGroups.cend())
|
if (search != m_sfxGroups.cend())
|
||||||
return nullptr;
|
|
||||||
return &search->second;
|
return &search->second;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "amuse/AudioGroupSampleDirectory.hpp"
|
#include "amuse/AudioGroupSampleDirectory.hpp"
|
||||||
#include "amuse/Common.hpp"
|
#include "amuse/Common.hpp"
|
||||||
|
#include "amuse/AudioGroupData.hpp"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
|
@ -195,4 +196,18 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioGroupSampleDirectory AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(const AudioGroupData& data)
|
||||||
|
{
|
||||||
|
switch (data.getDataFormat())
|
||||||
|
{
|
||||||
|
case DataFormat::GCN:
|
||||||
|
default:
|
||||||
|
return AudioGroupSampleDirectory(data.getSdir(), GCNDataTag{});
|
||||||
|
case DataFormat::N64:
|
||||||
|
return AudioGroupSampleDirectory(data.getSdir(), data.getSamp(), data.getAbsoluteProjOffsets(), N64DataTag{});
|
||||||
|
case DataFormat::PC:
|
||||||
|
return AudioGroupSampleDirectory(data.getSdir(), data.getAbsoluteProjOffsets(), PCDataTag{});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,459 @@
|
||||||
|
#include "amuse/Common.hpp"
|
||||||
|
#include "logvisor/logvisor.hpp"
|
||||||
|
|
||||||
|
namespace amuse
|
||||||
|
{
|
||||||
|
static logvisor::Module Log("amuse");
|
||||||
|
|
||||||
|
thread_local NameDB* ObjectId::CurNameDB = nullptr;
|
||||||
|
thread_local NameDB* SampleId::CurNameDB = nullptr;
|
||||||
|
thread_local NameDB* SongId::CurNameDB = nullptr;
|
||||||
|
thread_local NameDB* SFXId::CurNameDB = nullptr;
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void ObjectIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
|
||||||
|
{
|
||||||
|
id = reader.readUint16Little();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void ObjectIdDNA<athena::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeUint16Little(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void ObjectIdDNA<athena::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz)
|
||||||
|
{
|
||||||
|
sz += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void ObjectIdDNA<athena::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
|
||||||
|
{
|
||||||
|
_read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void ObjectIdDNA<athena::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
|
||||||
|
{
|
||||||
|
_write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void ObjectIdDNA<athena::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
|
||||||
|
{
|
||||||
|
id = reader.readUint16Big();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void ObjectIdDNA<athena::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeUint16Big(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void ObjectIdDNA<athena::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz)
|
||||||
|
{
|
||||||
|
sz += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void ObjectIdDNA<athena::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
|
||||||
|
{
|
||||||
|
_read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void ObjectIdDNA<athena::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
|
||||||
|
{
|
||||||
|
_write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
void ObjectIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r)
|
||||||
|
{
|
||||||
|
std::string name = r.readString(nullptr);
|
||||||
|
if (!ObjectId::CurNameDB)
|
||||||
|
Log.report(logvisor::Fatal, "Unable to resolve object name %s, no database present", name.c_str());
|
||||||
|
id = ObjectId::CurNameDB->resolveIdFromName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
void ObjectIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
|
||||||
|
{
|
||||||
|
if (!ObjectId::CurNameDB)
|
||||||
|
Log.report(logvisor::Fatal, "Unable to resolve object ID %d, no database present", id.id);
|
||||||
|
std::string_view name = ObjectId::CurNameDB->resolveNameFromId(id);
|
||||||
|
w.writeString(nullptr, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
const char* ObjectIdDNA<DNAE>::DNAType()
|
||||||
|
{
|
||||||
|
return "amuse::ObjectId";
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SampleIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
|
||||||
|
{
|
||||||
|
id = reader.readUint16Little();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SampleIdDNA<athena::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeUint16Little(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SampleIdDNA<athena::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz)
|
||||||
|
{
|
||||||
|
sz += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SampleIdDNA<athena::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
|
||||||
|
{
|
||||||
|
_read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SampleIdDNA<athena::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
|
||||||
|
{
|
||||||
|
_write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SampleIdDNA<athena::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
|
||||||
|
{
|
||||||
|
id = reader.readUint16Big();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SampleIdDNA<athena::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeUint16Big(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SampleIdDNA<athena::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz)
|
||||||
|
{
|
||||||
|
sz += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SampleIdDNA<athena::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
|
||||||
|
{
|
||||||
|
_read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SampleIdDNA<athena::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
|
||||||
|
{
|
||||||
|
_write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
void SampleIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r)
|
||||||
|
{
|
||||||
|
std::string name = r.readString(nullptr);
|
||||||
|
if (!SampleId::CurNameDB)
|
||||||
|
Log.report(logvisor::Fatal, "Unable to resolve sample name %s, no database present", name.c_str());
|
||||||
|
id = SampleId::CurNameDB->resolveIdFromName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
void SampleIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
|
||||||
|
{
|
||||||
|
if (!SampleId::CurNameDB)
|
||||||
|
Log.report(logvisor::Fatal, "Unable to resolve sample ID %d, no database present", id.id);
|
||||||
|
std::string_view name = SampleId::CurNameDB->resolveNameFromId(id);
|
||||||
|
w.writeString(nullptr, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
const char* SampleIdDNA<DNAE>::DNAType()
|
||||||
|
{
|
||||||
|
return "amuse::SampleId";
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SongIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
|
||||||
|
{
|
||||||
|
id = reader.readUint16Little();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SongIdDNA<athena::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeUint16Little(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SongIdDNA<athena::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz)
|
||||||
|
{
|
||||||
|
sz += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SongIdDNA<athena::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
|
||||||
|
{
|
||||||
|
_read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SongIdDNA<athena::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
|
||||||
|
{
|
||||||
|
_write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SongIdDNA<athena::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
|
||||||
|
{
|
||||||
|
id = reader.readUint16Big();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SongIdDNA<athena::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeUint16Big(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SongIdDNA<athena::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz)
|
||||||
|
{
|
||||||
|
sz += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SongIdDNA<athena::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
|
||||||
|
{
|
||||||
|
_read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SongIdDNA<athena::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
|
||||||
|
{
|
||||||
|
_write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
void SongIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r)
|
||||||
|
{
|
||||||
|
std::string name = r.readString(nullptr);
|
||||||
|
if (!SongId::CurNameDB)
|
||||||
|
Log.report(logvisor::Fatal, "Unable to resolve song name %s, no database present", name.c_str());
|
||||||
|
id = SongId::CurNameDB->resolveIdFromName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
void SongIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
|
||||||
|
{
|
||||||
|
if (!SongId::CurNameDB)
|
||||||
|
Log.report(logvisor::Fatal, "Unable to resolve song ID %d, no database present", id.id);
|
||||||
|
std::string_view name = SongId::CurNameDB->resolveNameFromId(id);
|
||||||
|
w.writeString(nullptr, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
const char* SongIdDNA<DNAE>::DNAType()
|
||||||
|
{
|
||||||
|
return "amuse::SongId";
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SFXIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
|
||||||
|
{
|
||||||
|
id = reader.readUint16Little();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SFXIdDNA<athena::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeUint16Little(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SFXIdDNA<athena::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz)
|
||||||
|
{
|
||||||
|
sz += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SFXIdDNA<athena::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
|
||||||
|
{
|
||||||
|
_read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SFXIdDNA<athena::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
|
||||||
|
{
|
||||||
|
_write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SFXIdDNA<athena::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
|
||||||
|
{
|
||||||
|
id = reader.readUint16Big();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SFXIdDNA<athena::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeUint16Big(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SFXIdDNA<athena::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz)
|
||||||
|
{
|
||||||
|
sz += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SFXIdDNA<athena::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
|
||||||
|
{
|
||||||
|
_read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> template<>
|
||||||
|
void SFXIdDNA<athena::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
|
||||||
|
{
|
||||||
|
_write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
void SFXIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r)
|
||||||
|
{
|
||||||
|
std::string name = r.readString(nullptr);
|
||||||
|
if (!SFXId::CurNameDB)
|
||||||
|
Log.report(logvisor::Fatal, "Unable to resolve song name %s, no database present", name.c_str());
|
||||||
|
id = SFXId::CurNameDB->resolveIdFromName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
void SFXIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
|
||||||
|
{
|
||||||
|
if (!SFXId::CurNameDB)
|
||||||
|
Log.report(logvisor::Fatal, "Unable to resolve song ID %d, no database present", id.id);
|
||||||
|
std::string_view name = SFXId::CurNameDB->resolveNameFromId(id);
|
||||||
|
w.writeString(nullptr, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
const char* SFXIdDNA<DNAE>::DNAType()
|
||||||
|
{
|
||||||
|
return "amuse::SFXId";
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectId NameDB::generateId(Type tp)
|
||||||
|
{
|
||||||
|
uint16_t upperMatch = uint16_t(tp) << 8;
|
||||||
|
uint16_t maxMatch = 0;
|
||||||
|
for (const auto& p : m_idToString)
|
||||||
|
if ((p.first & 0xff00) == upperMatch && (p.first & 0xff) >= maxMatch)
|
||||||
|
maxMatch = (p.first & 0xff) + 1;
|
||||||
|
return upperMatch | maxMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NameDB::generateName(ObjectId id)
|
||||||
|
{
|
||||||
|
Type tp = Type(id.id >> 8);
|
||||||
|
char name[32];
|
||||||
|
switch (tp)
|
||||||
|
{
|
||||||
|
case Type::SoundMacro:
|
||||||
|
snprintf(name, 32, "macro%d", id.id & 0xff);
|
||||||
|
break;
|
||||||
|
case Type::Table:
|
||||||
|
snprintf(name, 32, "table%d", id.id & 0xff);
|
||||||
|
break;
|
||||||
|
case Type::Keymap:
|
||||||
|
snprintf(name, 32, "keymap%d", id.id & 0xff);
|
||||||
|
break;
|
||||||
|
case Type::Layer:
|
||||||
|
snprintf(name, 32, "layers%d", id.id & 0xff);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(name, 32, "obj%04X", id.id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view NameDB::registerPair(std::string_view str, ObjectId id)
|
||||||
|
{
|
||||||
|
m_stringToId[std::string(str)] = id;
|
||||||
|
return m_idToString.insert(std::make_pair(id, str)).first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view NameDB::resolveNameFromId(ObjectId id) const
|
||||||
|
{
|
||||||
|
auto search = m_idToString.find(id);
|
||||||
|
if (search == m_idToString.cend())
|
||||||
|
Log.report(logvisor::Fatal, "Unable to resolve ID %d", id.id);
|
||||||
|
return search->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectId NameDB::resolveIdFromName(std::string_view str) const
|
||||||
|
{
|
||||||
|
auto search = m_stringToId.find(std::string(str));
|
||||||
|
if (search == m_stringToId.cend())
|
||||||
|
Log.report(logvisor::Fatal, "Unable to resolve name %s", str.data());
|
||||||
|
return search->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template struct ObjectIdDNA<athena::Big>;
|
||||||
|
template struct ObjectIdDNA<athena::Little>;
|
||||||
|
|
||||||
|
template struct SampleIdDNA<athena::Big>;
|
||||||
|
template struct SampleIdDNA<athena::Little>;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void LittleUInt24::Enumerate<LittleDNA::Read>(athena::io::IStreamReader& reader)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
atUint32 val;
|
||||||
|
char bytes[4];
|
||||||
|
} data = {};
|
||||||
|
reader.readBytesToBuf(data.bytes, 3);
|
||||||
|
val = SLittle(data.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void LittleUInt24::Enumerate<LittleDNA::Write>(athena::io::IStreamWriter& writer)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
atUint32 val;
|
||||||
|
char bytes[4];
|
||||||
|
} data;
|
||||||
|
data.val = SLittle(val);
|
||||||
|
writer.writeBytes(data.bytes, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void LittleUInt24::Enumerate<LittleDNA::BinarySize>(size_t& sz)
|
||||||
|
{
|
||||||
|
sz += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void LittleUInt24::Enumerate<LittleDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
|
||||||
|
{
|
||||||
|
val = reader.readUint32(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void LittleUInt24::Enumerate<LittleDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeUint32(nullptr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* LittleUInt24::DNAType()
|
||||||
|
{
|
||||||
|
return "amuse::LittleUInt24";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1960,6 +1960,9 @@ std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> ContainerRegistry:
|
||||||
{
|
{
|
||||||
std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> ret;
|
std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> ret;
|
||||||
|
|
||||||
|
const SystemChar* sep = std::max(StrRChr(path, _S('/')), StrRChr(path, _S('\\')));
|
||||||
|
SystemString baseName(sep + 1, dot - sep - 1);
|
||||||
|
|
||||||
/* Project */
|
/* Project */
|
||||||
SystemChar projPath[1024];
|
SystemChar projPath[1024];
|
||||||
SNPrintf(projPath, 1024, _S("%.*s.pro"), int(dot - path), path);
|
SNPrintf(projPath, 1024, _S("%.*s.pro"), int(dot - path), path);
|
||||||
|
@ -2044,15 +2047,15 @@ std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> ContainerRegistry:
|
||||||
|
|
||||||
/* SDIR-based format detection */
|
/* SDIR-based format detection */
|
||||||
if (*reinterpret_cast<uint32_t*>(sdir.get() + 8) == 0x0)
|
if (*reinterpret_cast<uint32_t*>(sdir.get() + 8) == 0x0)
|
||||||
ret.emplace_back(_S("Group"),
|
ret.emplace_back(baseName,
|
||||||
IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen, sdir.release(),
|
IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen, sdir.release(),
|
||||||
sdirLen, samp.release(), sampLen, GCNDataTag{}});
|
sdirLen, samp.release(), sampLen, GCNDataTag{}});
|
||||||
else if (sdir[9] == 0x0)
|
else if (sdir[9] == 0x0)
|
||||||
ret.emplace_back(_S("Group"),
|
ret.emplace_back(baseName,
|
||||||
IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen, sdir.release(),
|
IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen, sdir.release(),
|
||||||
sdirLen, samp.release(), sampLen, false, N64DataTag{}});
|
sdirLen, samp.release(), sampLen, false, N64DataTag{}});
|
||||||
else
|
else
|
||||||
ret.emplace_back(_S("Group"),
|
ret.emplace_back(baseName,
|
||||||
IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen, sdir.release(),
|
IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen, sdir.release(),
|
||||||
sdirLen, samp.release(), sampLen, false, PCDataTag{}});
|
sdirLen, samp.release(), sampLen, false, PCDataTag{}});
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ AudioGroup* Engine::_addAudioGroup(const AudioGroupData& data, std::unique_ptr<A
|
||||||
const SFXGroupIndex& sfxGroup = grp.second;
|
const SFXGroupIndex& sfxGroup = grp.second;
|
||||||
m_sfxLookup.reserve(m_sfxLookup.size() + sfxGroup.m_sfxEntries.size());
|
m_sfxLookup.reserve(m_sfxLookup.size() + sfxGroup.m_sfxEntries.size());
|
||||||
for (const auto& ent : sfxGroup.m_sfxEntries)
|
for (const auto& ent : sfxGroup.m_sfxEntries)
|
||||||
m_sfxLookup[ent.first] = std::make_tuple(ret, grp.first, ent.second);
|
m_sfxLookup[ent.first] = std::make_tuple(ret, grp.first, &ent.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -307,8 +307,7 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, std::wea
|
||||||
std::list<std::shared_ptr<Voice>>::iterator ret =
|
std::list<std::shared_ptr<Voice>>::iterator ret =
|
||||||
_allocateVoice(*grp, std::get<1>(search->second), NativeSampleRate, true, false, smx);
|
_allocateVoice(*grp, std::get<1>(search->second), NativeSampleRate, true, false, smx);
|
||||||
|
|
||||||
ObjectId oid = (grp->getDataFormat() == DataFormat::PC) ? entry->objId : SBig(entry->objId);
|
if (!(*ret)->loadSoundObject(entry->objId, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
||||||
if (!(*ret)->loadSoundObject(oid, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
|
||||||
{
|
{
|
||||||
_destroyVoice(ret);
|
_destroyVoice(ret);
|
||||||
return {};
|
return {};
|
||||||
|
@ -336,8 +335,7 @@ std::shared_ptr<Emitter> Engine::addEmitter(const float* pos, const float* dir,
|
||||||
std::list<std::shared_ptr<Voice>>::iterator vox =
|
std::list<std::shared_ptr<Voice>>::iterator vox =
|
||||||
_allocateVoice(*grp, std::get<1>(search->second), NativeSampleRate, true, true, smx);
|
_allocateVoice(*grp, std::get<1>(search->second), NativeSampleRate, true, true, smx);
|
||||||
|
|
||||||
ObjectId oid = (grp->getDataFormat() == DataFormat::PC) ? entry->objId : SBig(entry->objId);
|
if (!(*vox)->loadSoundObject(entry->objId, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
||||||
if (!(*vox)->loadSoundObject(oid, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
|
||||||
{
|
{
|
||||||
_destroyVoice(vox);
|
_destroyVoice(vox);
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -63,7 +63,7 @@ Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const
|
||||||
{
|
{
|
||||||
auto it = m_songGroup->m_midiSetups.find(setupId);
|
auto it = m_songGroup->m_midiSetups.find(setupId);
|
||||||
if (it != m_songGroup->m_midiSetups.cend())
|
if (it != m_songGroup->m_midiSetups.cend())
|
||||||
m_midiSetup = it->second->data();
|
m_midiSetup = it->second.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SFXGroupIndex* sfxGroup,
|
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SFXGroupIndex* sfxGroup,
|
||||||
|
@ -72,7 +72,7 @@ Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const
|
||||||
{
|
{
|
||||||
std::map<uint16_t, const SFXGroupIndex::SFXEntry*> sortSFX;
|
std::map<uint16_t, const SFXGroupIndex::SFXEntry*> sortSFX;
|
||||||
for (const auto& sfx : sfxGroup->m_sfxEntries)
|
for (const auto& sfx : sfxGroup->m_sfxEntries)
|
||||||
sortSFX[sfx.first] = sfx.second;
|
sortSFX[sfx.first] = &sfx.second;
|
||||||
|
|
||||||
m_sfxMappings.reserve(sortSFX.size());
|
m_sfxMappings.reserve(sortSFX.size());
|
||||||
for (const auto& sfx : sortSFX)
|
for (const auto& sfx : sortSFX)
|
||||||
|
@ -95,7 +95,7 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
|
||||||
auto it = m_parent->m_songGroup->m_drumPages.find(m_setup->programNo);
|
auto it = m_parent->m_songGroup->m_drumPages.find(m_setup->programNo);
|
||||||
if (it != m_parent->m_songGroup->m_drumPages.cend())
|
if (it != m_parent->m_songGroup->m_drumPages.cend())
|
||||||
{
|
{
|
||||||
m_page = it->second;
|
m_page = &it->second;
|
||||||
m_curProgram = m_setup->programNo;
|
m_curProgram = m_setup->programNo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
|
||||||
auto it = m_parent->m_songGroup->m_normPages.find(m_setup->programNo);
|
auto it = m_parent->m_songGroup->m_normPages.find(m_setup->programNo);
|
||||||
if (it != m_parent->m_songGroup->m_normPages.cend())
|
if (it != m_parent->m_songGroup->m_normPages.cend())
|
||||||
{
|
{
|
||||||
m_page = it->second;
|
m_page = &it->second;
|
||||||
m_curProgram = m_setup->programNo;
|
m_curProgram = m_setup->programNo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,13 +120,13 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
|
||||||
{
|
{
|
||||||
auto it = m_parent->m_songGroup->m_drumPages.find(0);
|
auto it = m_parent->m_songGroup->m_drumPages.find(0);
|
||||||
if (it != m_parent->m_songGroup->m_drumPages.cend())
|
if (it != m_parent->m_songGroup->m_drumPages.cend())
|
||||||
m_page = it->second;
|
m_page = &it->second;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto it = m_parent->m_songGroup->m_normPages.find(0);
|
auto it = m_parent->m_songGroup->m_normPages.find(0);
|
||||||
if (it != m_parent->m_songGroup->m_normPages.cend())
|
if (it != m_parent->m_songGroup->m_normPages.cend())
|
||||||
m_page = it->second;
|
m_page = &it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_curVol = 1.f;
|
m_curVol = 1.f;
|
||||||
|
@ -248,12 +248,12 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
|
||||||
|
|
||||||
ObjectId oid;
|
ObjectId oid;
|
||||||
if (m_parent->m_songGroup)
|
if (m_parent->m_songGroup)
|
||||||
oid = (m_parent->m_audioGroup.getDataFormat() == DataFormat::PC) ? m_page->objId : SBig(m_page->objId);
|
oid = m_page->objId;
|
||||||
else if (m_parent->m_sfxMappings.size())
|
else if (m_parent->m_sfxMappings.size())
|
||||||
{
|
{
|
||||||
size_t lookupIdx = note % m_parent->m_sfxMappings.size();
|
size_t lookupIdx = note % m_parent->m_sfxMappings.size();
|
||||||
const SFXGroupIndex::SFXEntry* sfxEntry = m_parent->m_sfxMappings[lookupIdx];
|
const SFXGroupIndex::SFXEntry* sfxEntry = m_parent->m_sfxMappings[lookupIdx];
|
||||||
oid = (m_parent->m_audioGroup.getDataFormat() == DataFormat::PC) ? sfxEntry->objId : SBig(sfxEntry->objId);
|
oid = sfxEntry->objId;
|
||||||
note = sfxEntry->defKey;
|
note = sfxEntry->defKey;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -341,7 +341,7 @@ bool Sequencer::ChannelState::programChange(int8_t prog)
|
||||||
auto it = m_parent->m_songGroup->m_drumPages.find(prog);
|
auto it = m_parent->m_songGroup->m_drumPages.find(prog);
|
||||||
if (it != m_parent->m_songGroup->m_drumPages.cend())
|
if (it != m_parent->m_songGroup->m_drumPages.cend())
|
||||||
{
|
{
|
||||||
m_page = it->second;
|
m_page = &it->second;
|
||||||
m_curProgram = prog;
|
m_curProgram = prog;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -351,7 +351,7 @@ bool Sequencer::ChannelState::programChange(int8_t prog)
|
||||||
auto it = m_parent->m_songGroup->m_normPages.find(prog);
|
auto it = m_parent->m_songGroup->m_normPages.find(prog);
|
||||||
if (it != m_parent->m_songGroup->m_normPages.cend())
|
if (it != m_parent->m_songGroup->m_normPages.cend())
|
||||||
{
|
{
|
||||||
m_page = it->second;
|
m_page = &it->second;
|
||||||
m_curProgram = prog;
|
m_curProgram = prog;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -43,10 +43,9 @@ void Voice::_macroSampleEnd()
|
||||||
{
|
{
|
||||||
if (m_sampleEndTrap.macroId != 0xffff)
|
if (m_sampleEndTrap.macroId != 0xffff)
|
||||||
{
|
{
|
||||||
if (m_sampleEndTrap.macroId == m_state.m_header.m_macroId)
|
if (m_sampleEndTrap.macroId == std::get<0>(m_state.m_pc.back()))
|
||||||
{
|
{
|
||||||
m_state.m_pc.back().second = SoundMacroState::_assertPC(m_sampleEndTrap.macroStep,
|
std::get<2>(m_state.m_pc.back()) = std::get<1>(m_state.m_pc.back())->assertPC(m_sampleEndTrap.macroStep);
|
||||||
m_state.m_header.m_size);
|
|
||||||
m_state.m_inWait = false;
|
m_state.m_inWait = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -238,7 +237,7 @@ void Voice::_procSamplePre(int16_t& samp)
|
||||||
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)
|
||||||
t = (*m_envelopeCurve)[int(t * 127.f)] / 127.f;
|
t = m_envelopeCurve->data.at(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);
|
||||||
|
@ -752,22 +751,16 @@ std::shared_ptr<Voice> Voice::startChildMacro(int8_t addNote, ObjectId macroId,
|
||||||
m_state.m_initMod);
|
m_state.m_initMod);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Voice::_loadSoundMacro(const unsigned char* macroData, int macroStep, double ticksPerSec, uint8_t midiKey,
|
bool Voice::_loadSoundMacro(ObjectId id, const SoundMacro* macroData, int macroStep, double ticksPerSec,
|
||||||
uint8_t midiVel, uint8_t midiMod, bool pushPc)
|
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc)
|
||||||
{
|
{
|
||||||
if (m_state.m_pc.empty())
|
if (m_state.m_pc.empty())
|
||||||
m_state.initialize(macroData, macroStep, ticksPerSec, midiKey, midiVel, midiMod,
|
m_state.initialize(id, macroData, macroStep, ticksPerSec, midiKey, midiVel, midiMod);
|
||||||
m_audioGroup.getDataFormat() != DataFormat::PC);
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!pushPc)
|
if (!pushPc)
|
||||||
m_state.m_pc.clear();
|
m_state.m_pc.clear();
|
||||||
const SoundMacroState::Header& header = reinterpret_cast<const SoundMacroState::Header&>(macroData);
|
m_state.m_pc.emplace_back(id, macroData, macroData->assertPC(macroStep));
|
||||||
const bool swapData = m_audioGroup.getDataFormat() != DataFormat::PC;
|
|
||||||
m_state.m_pc.push_back({macroData, SoundMacroState::_assertPC(macroStep, header.m_size, swapData)});
|
|
||||||
m_state.m_header = header;
|
|
||||||
if (swapData)
|
|
||||||
m_state.m_header.swapBig();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_voxState = VoiceState::Playing;
|
m_voxState = VoiceState::Playing;
|
||||||
|
@ -775,46 +768,43 @@ bool Voice::_loadSoundMacro(const unsigned char* macroData, int macroStep, doubl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Voice::_loadKeymap(const Keymap* keymap, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
|
bool Voice::_loadKeymap(ObjectId id, const Keymap* keymap, int macroStep, double ticksPerSec,
|
||||||
uint8_t midiMod, bool pushPc)
|
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc)
|
||||||
{
|
{
|
||||||
const Keymap& km = keymap[midiKey];
|
const Keymap& km = keymap[midiKey];
|
||||||
ObjectId oid = (m_audioGroup.getDataFormat() == DataFormat::PC) ? km.objectId : SBig(km.objectId);
|
|
||||||
midiKey += km.transpose;
|
midiKey += km.transpose;
|
||||||
bool ret = loadSoundObject(oid, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
bool ret = loadSoundObject(id, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
||||||
m_curVol = 1.f;
|
m_curVol = 1.f;
|
||||||
_setPan((km.pan - 64) / 64.f);
|
_setPan((km.pan - 64) / 64.f);
|
||||||
_setSurroundPan(-1.f);
|
_setSurroundPan(-1.f);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Voice::_loadLayer(const std::vector<const LayerMapping*>& layer, int macroStep, double ticksPerSec,
|
bool Voice::_loadLayer(ObjectId id, const std::vector<LayerMapping>& layer, int macroStep, double ticksPerSec,
|
||||||
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc)
|
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
for (const LayerMapping* mapping : layer)
|
for (const LayerMapping& mapping : layer)
|
||||||
{
|
{
|
||||||
if (midiKey >= mapping->keyLo && midiKey <= mapping->keyHi)
|
if (midiKey >= mapping.keyLo && midiKey <= mapping.keyHi)
|
||||||
{
|
{
|
||||||
ObjectId oid =
|
uint8_t mappingKey = midiKey + mapping.transpose;
|
||||||
(m_audioGroup.getDataFormat() == DataFormat::PC) ? mapping->objectId : SBig(mapping->objectId);
|
|
||||||
uint8_t mappingKey = midiKey + mapping->transpose;
|
|
||||||
if (m_voxState != VoiceState::Playing)
|
if (m_voxState != VoiceState::Playing)
|
||||||
{
|
{
|
||||||
ret |= loadSoundObject(oid, macroStep, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
|
ret |= loadSoundObject(id, macroStep, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
|
||||||
m_curVol = mapping->volume / 127.f;
|
m_curVol = mapping.volume / 127.f;
|
||||||
_setPan((mapping->pan - 64) / 64.f);
|
_setPan((mapping.pan - 64) / 64.f);
|
||||||
_setSurroundPan((mapping->span - 64) / 64.f);
|
_setSurroundPan((mapping.span - 64) / 64.f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> vox =
|
std::shared_ptr<Voice> vox =
|
||||||
_startChildMacro(oid, macroStep, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
|
_startChildMacro(id, macroStep, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
|
||||||
if (vox)
|
if (vox)
|
||||||
{
|
{
|
||||||
vox->m_curVol = mapping->volume / 127.f;
|
vox->m_curVol = mapping.volume / 127.f;
|
||||||
vox->_setPan((mapping->pan - 64) / 64.f);
|
vox->_setPan((mapping.pan - 64) / 64.f);
|
||||||
vox->_setSurroundPan((mapping->span - 64) / 64.f);
|
vox->_setSurroundPan((mapping.span - 64) / 64.f);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -829,25 +819,25 @@ bool Voice::loadSoundObject(ObjectId objectId, int macroStep, double ticksPerSec
|
||||||
if (m_destroyed)
|
if (m_destroyed)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const unsigned char* macroData = m_audioGroup.getPool().soundMacro(objectId);
|
const SoundMacro* macroData = m_audioGroup.getPool().soundMacro(objectId);
|
||||||
if (macroData)
|
if (macroData)
|
||||||
{
|
{
|
||||||
m_objectId = objectId;
|
m_objectId = objectId;
|
||||||
return _loadSoundMacro(macroData, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
return _loadSoundMacro(objectId, macroData, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Keymap* keymap = m_audioGroup.getPool().keymap(objectId);
|
const Keymap* keymap = m_audioGroup.getPool().keymap(objectId);
|
||||||
if (keymap)
|
if (keymap)
|
||||||
{
|
{
|
||||||
m_objectId = objectId;
|
m_objectId = objectId;
|
||||||
return _loadKeymap(keymap, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
return _loadKeymap(objectId, keymap, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<const LayerMapping*>* layer = m_audioGroup.getPool().layer(objectId);
|
const std::vector<LayerMapping>* layer = m_audioGroup.getPool().layer(objectId);
|
||||||
if (layer)
|
if (layer)
|
||||||
{
|
{
|
||||||
m_objectId = objectId;
|
m_objectId = objectId;
|
||||||
return _loadLayer(*layer, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
return _loadLayer(objectId, *layer, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -872,10 +862,9 @@ void Voice::keyOff()
|
||||||
|
|
||||||
if (m_keyoffTrap.macroId != 0xffff)
|
if (m_keyoffTrap.macroId != 0xffff)
|
||||||
{
|
{
|
||||||
if (m_keyoffTrap.macroId == m_state.m_header.m_macroId)
|
if (m_keyoffTrap.macroId == std::get<0>(m_state.m_pc.back()))
|
||||||
{
|
{
|
||||||
m_state.m_pc.back().second = SoundMacroState::_assertPC(m_keyoffTrap.macroStep,
|
std::get<2>(m_state.m_pc.back()) = std::get<1>(m_state.m_pc.back())->assertPC(m_keyoffTrap.macroStep);
|
||||||
m_state.m_header.m_size);
|
|
||||||
m_state.m_inWait = false;
|
m_state.m_inWait = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -898,9 +887,8 @@ void Voice::message(int32_t val)
|
||||||
|
|
||||||
if (m_messageTrap.macroId != 0xffff)
|
if (m_messageTrap.macroId != 0xffff)
|
||||||
{
|
{
|
||||||
if (m_messageTrap.macroId == m_state.m_header.m_macroId)
|
if (m_messageTrap.macroId == std::get<0>(m_state.m_pc.back()))
|
||||||
m_state.m_pc.back().second = SoundMacroState::_assertPC(m_messageTrap.macroStep,
|
std::get<2>(m_state.m_pc.back()) = std::get<1>(m_state.m_pc.back())->assertPC(m_messageTrap.macroStep);
|
||||||
m_state.m_header.m_size);
|
|
||||||
else
|
else
|
||||||
loadSoundObject(m_messageTrap.macroId, m_messageTrap.macroStep, m_state.m_ticksPerSec, m_state.m_initKey,
|
loadSoundObject(m_messageTrap.macroId, m_messageTrap.macroStep, m_state.m_ticksPerSec, m_state.m_initKey,
|
||||||
m_state.m_initVel, m_state.m_initMod);
|
m_state.m_initVel, m_state.m_initMod);
|
||||||
|
|
Loading…
Reference in New Issue