mirror of https://github.com/AxioDL/amuse.git
ObjToken refactor and Sample nodes
This commit is contained in:
parent
f5984141fd
commit
16745c9bf8
|
@ -10,7 +10,7 @@ void MIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
if (keySearch == m_chanVoxs.cend())
|
if (keySearch == m_chanVoxs.cend())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (keySearch->second == m_lastVoice.lock())
|
if (m_lastVoice->isDestroyed() || keySearch->second == m_lastVoice)
|
||||||
m_lastVoice.reset();
|
m_lastVoice.reset();
|
||||||
keySearch->second->keyOff();
|
keySearch->second->keyOff();
|
||||||
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
||||||
|
@ -19,8 +19,11 @@ void MIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
|
|
||||||
void MIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
void MIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
{
|
{
|
||||||
|
if (m_lastVoice->isDestroyed())
|
||||||
|
m_lastVoice.reset();
|
||||||
|
|
||||||
/* If portamento is enabled for voice, pre-empt spawning new voices */
|
/* If portamento is enabled for voice, pre-empt spawning new voices */
|
||||||
if (std::shared_ptr<amuse::Voice> lastVoice = m_lastVoice.lock())
|
if (amuse::ObjToken<amuse::Voice> lastVoice = m_lastVoice)
|
||||||
{
|
{
|
||||||
uint8_t lastNote = lastVoice->getLastNote();
|
uint8_t lastNote = lastVoice->getLastNote();
|
||||||
if (lastVoice->doPortamento(key))
|
if (lastVoice->doPortamento(key))
|
||||||
|
@ -35,7 +38,7 @@ void MIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
auto keySearch = m_chanVoxs.find(key);
|
auto keySearch = m_chanVoxs.find(key);
|
||||||
if (keySearch != m_chanVoxs.cend())
|
if (keySearch != m_chanVoxs.cend())
|
||||||
{
|
{
|
||||||
if (keySearch->second == m_lastVoice.lock())
|
if (keySearch->second == m_lastVoice)
|
||||||
m_lastVoice.reset();
|
m_lastVoice.reset();
|
||||||
keySearch->second->keyOff();
|
keySearch->second->keyOff();
|
||||||
keySearch->second->setPedal(false);
|
keySearch->second->setPedal(false);
|
||||||
|
@ -48,10 +51,11 @@ void MIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
{
|
{
|
||||||
ProjectModel::SoundMacroNode* cNode = static_cast<ProjectModel::SoundMacroNode*>(node);
|
ProjectModel::SoundMacroNode* cNode = static_cast<ProjectModel::SoundMacroNode*>(node);
|
||||||
amuse::AudioGroupDatabase* group = g_MainWindow->projectModel()->getGroupNode(node)->getAudioGroup();
|
amuse::AudioGroupDatabase* group = g_MainWindow->projectModel()->getGroupNode(node)->getAudioGroup();
|
||||||
std::shared_ptr<amuse::Voice>& vox = m_chanVoxs[key];
|
amuse::ObjToken<amuse::Voice>& vox = m_chanVoxs[key];
|
||||||
vox = m_engine.macroStart(group, cNode->id(), key, velocity, g_MainWindow->m_modulation);
|
vox = m_engine.macroStart(group, cNode->id(), key, velocity, g_MainWindow->m_ctrlVals[1]);
|
||||||
vox->setPedal(g_MainWindow->m_sustain);
|
vox->setPedal(g_MainWindow->m_ctrlVals[64] >= 0x40);
|
||||||
vox->setPitchWheel(g_MainWindow->m_pitch);
|
vox->setPitchWheel(g_MainWindow->m_pitch);
|
||||||
|
vox->installCtrlValues(g_MainWindow->m_ctrlVals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
#define AMUSE_MIDI_READER_HPP
|
#define AMUSE_MIDI_READER_HPP
|
||||||
|
|
||||||
#include "amuse/BooBackend.hpp"
|
#include "amuse/BooBackend.hpp"
|
||||||
|
#include "amuse/Common.hpp"
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
class MIDIReader : public amuse::BooBackendMIDIReader
|
class MIDIReader : public amuse::BooBackendMIDIReader
|
||||||
{
|
{
|
||||||
std::unordered_map<uint8_t, std::shared_ptr<amuse::Voice>> m_chanVoxs;
|
std::unordered_map<uint8_t, amuse::ObjToken<amuse::Voice>> m_chanVoxs;
|
||||||
std::unordered_set<std::shared_ptr<amuse::Voice>> m_keyoffVoxs;
|
std::unordered_set<amuse::ObjToken<amuse::Voice>> m_keyoffVoxs;
|
||||||
std::weak_ptr<amuse::Voice> m_lastVoice;
|
amuse::ObjToken<amuse::Voice> m_lastVoice;
|
||||||
public:
|
public:
|
||||||
MIDIReader(amuse::Engine& engine, const char* name, bool useLock);
|
MIDIReader(amuse::Engine& engine, const char* name, bool useLock);
|
||||||
boo::IMIDIIn* getMidiIn() const { return m_midiIn.get(); }
|
boo::IMIDIIn* getMidiIn() const { return m_midiIn.get(); }
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "CurveEditor.hpp"
|
#include "CurveEditor.hpp"
|
||||||
#include "KeymapEditor.hpp"
|
#include "KeymapEditor.hpp"
|
||||||
#include "LayersEditor.hpp"
|
#include "LayersEditor.hpp"
|
||||||
|
#include "SampleEditor.hpp"
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget* parent)
|
MainWindow::MainWindow(QWidget* parent)
|
||||||
: QMainWindow(parent),
|
: QMainWindow(parent),
|
||||||
|
@ -50,7 +51,8 @@ MainWindow::MainWindow(QWidget* parent)
|
||||||
m_ui.actionSave_Project->setShortcut(QKeySequence::Save);
|
m_ui.actionSave_Project->setShortcut(QKeySequence::Save);
|
||||||
connect(m_ui.actionSave_Project, SIGNAL(triggered()), this, SLOT(saveAction()));
|
connect(m_ui.actionSave_Project, SIGNAL(triggered()), this, SLOT(saveAction()));
|
||||||
connect(m_ui.actionRevert_Project, SIGNAL(triggered()), this, SLOT(revertAction()));
|
connect(m_ui.actionRevert_Project, SIGNAL(triggered()), this, SLOT(revertAction()));
|
||||||
connect(m_ui.actionImport, SIGNAL(triggered()), this, SLOT(importAction()));
|
connect(m_ui.actionReload_Sample_Data, SIGNAL(triggered()), this, SLOT(reloadSampleDataAction()));
|
||||||
|
connect(m_ui.actionImport_Groups, SIGNAL(triggered()), this, SLOT(importAction()));
|
||||||
connect(m_ui.actionExport_GameCube_Groups, SIGNAL(triggered()), this, SLOT(exportAction()));
|
connect(m_ui.actionExport_GameCube_Groups, SIGNAL(triggered()), this, SLOT(exportAction()));
|
||||||
|
|
||||||
for (int i = 0; i < MaxRecentFiles; ++i)
|
for (int i = 0; i < MaxRecentFiles; ++i)
|
||||||
|
@ -109,6 +111,8 @@ MainWindow::MainWindow(QWidget* parent)
|
||||||
m_ui.editorContents->addWidget(m_keymapEditor);
|
m_ui.editorContents->addWidget(m_keymapEditor);
|
||||||
m_layersEditor = new LayersEditor;
|
m_layersEditor = new LayersEditor;
|
||||||
m_ui.editorContents->addWidget(m_layersEditor);
|
m_ui.editorContents->addWidget(m_layersEditor);
|
||||||
|
m_sampleEditor = new SampleEditor;
|
||||||
|
m_ui.editorContents->addWidget(m_sampleEditor);
|
||||||
m_ui.editorContents->setCurrentWidget(m_faceSvg);
|
m_ui.editorContents->setCurrentWidget(m_faceSvg);
|
||||||
|
|
||||||
connect(m_ui.actionNew_Subproject, SIGNAL(triggered()), this, SLOT(newSubprojectAction()));
|
connect(m_ui.actionNew_Subproject, SIGNAL(triggered()), this, SLOT(newSubprojectAction()));
|
||||||
|
@ -129,6 +133,9 @@ MainWindow::MainWindow(QWidget* parent)
|
||||||
m_voxAllocator = std::make_unique<VoiceAllocator>(*m_voxEngine);
|
m_voxAllocator = std::make_unique<VoiceAllocator>(*m_voxEngine);
|
||||||
m_engine = std::make_unique<amuse::Engine>(*m_voxAllocator);
|
m_engine = std::make_unique<amuse::Engine>(*m_voxAllocator);
|
||||||
|
|
||||||
|
m_ctrlVals[7] = 127;
|
||||||
|
m_ctrlVals[10] = 64;
|
||||||
|
|
||||||
startTimer(16);
|
startTimer(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +174,27 @@ void MainWindow::connectMessenger(UIMessenger* messenger, Qt::ConnectionType typ
|
||||||
QMessageBox::StandardButton)), type);
|
QMessageBox::StandardButton)), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateWindowTitle()
|
||||||
|
{
|
||||||
|
if (!m_projectModel)
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Amuse"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir dir(m_projectModel->path());
|
||||||
|
if (m_ui.editorContents->currentWidget() != m_faceSvg)
|
||||||
|
{
|
||||||
|
ProjectModel::BasePoolObjectNode* objNode = static_cast<ProjectModel::BasePoolObjectNode*>(
|
||||||
|
static_cast<EditorWidget*>(m_ui.editorContents->currentWidget())->currentNode());
|
||||||
|
setWindowTitle(tr("Amuse [%1/%2/%3]").arg(dir.dirName()).arg(
|
||||||
|
m_projectModel->getGroupNode(objNode)->text()).arg(objNode->text()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setWindowTitle(tr("Amuse [%1]").arg(dir.dirName()));
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::updateRecentFileActions()
|
void MainWindow::updateRecentFileActions()
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
|
@ -215,6 +243,7 @@ bool MainWindow::setProjectPath(const QString& path)
|
||||||
}
|
}
|
||||||
testWriteFile.remove();
|
testWriteFile.remove();
|
||||||
|
|
||||||
|
closeEditor();
|
||||||
if (m_projectModel)
|
if (m_projectModel)
|
||||||
m_projectModel->deleteLater();
|
m_projectModel->deleteLater();
|
||||||
m_projectModel = new ProjectModel(path, this);
|
m_projectModel = new ProjectModel(path, this);
|
||||||
|
@ -224,9 +253,10 @@ bool MainWindow::setProjectPath(const QString& path)
|
||||||
this, SLOT(onOutlineSelectionChanged(const QItemSelection&, const QItemSelection&)));
|
this, SLOT(onOutlineSelectionChanged(const QItemSelection&, const QItemSelection&)));
|
||||||
m_ui.actionSave_Project->setEnabled(true);
|
m_ui.actionSave_Project->setEnabled(true);
|
||||||
m_ui.actionRevert_Project->setEnabled(true);
|
m_ui.actionRevert_Project->setEnabled(true);
|
||||||
|
m_ui.actionReload_Sample_Data->setEnabled(true);
|
||||||
m_ui.actionExport_GameCube_Groups->setEnabled(true);
|
m_ui.actionExport_GameCube_Groups->setEnabled(true);
|
||||||
setWindowFilePath(path);
|
setWindowFilePath(path);
|
||||||
setWindowTitle(QString("Amuse [%1]").arg(dir.dirName()));
|
updateWindowTitle();
|
||||||
onFocusChanged(nullptr, focusWidget());
|
onFocusChanged(nullptr, focusWidget());
|
||||||
m_undoStack->clear();
|
m_undoStack->clear();
|
||||||
|
|
||||||
|
@ -305,19 +335,19 @@ void MainWindow::timerEvent(QTimerEvent* ev)
|
||||||
|
|
||||||
void MainWindow::setSustain(bool sustain)
|
void MainWindow::setSustain(bool sustain)
|
||||||
{
|
{
|
||||||
if (sustain && !m_sustain)
|
if (sustain && m_ctrlVals[64] < 0x40)
|
||||||
{
|
{
|
||||||
m_ui.statusbar->setNormalMessage(tr("SUSTAIN"));
|
m_ui.statusbar->setNormalMessage(tr("SUSTAIN"));
|
||||||
for (auto& v : m_engine->getActiveVoices())
|
for (auto& v : m_engine->getActiveVoices())
|
||||||
v->setPedal(true);
|
v->setPedal(true);
|
||||||
m_sustain = true;
|
m_ctrlVals[64] = 127;
|
||||||
}
|
}
|
||||||
else if (!sustain && m_sustain)
|
else if (!sustain && m_ctrlVals[64] >= 0x40)
|
||||||
{
|
{
|
||||||
m_ui.statusbar->setNormalMessage({});
|
m_ui.statusbar->setNormalMessage({});
|
||||||
for (auto& v : m_engine->getActiveVoices())
|
for (auto& v : m_engine->getActiveVoices())
|
||||||
v->setPedal(false);
|
v->setPedal(false);
|
||||||
m_sustain = false;
|
m_ctrlVals[64] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,6 +414,7 @@ bool MainWindow::_setEditor(EditorWidget* editor)
|
||||||
}
|
}
|
||||||
m_ui.editorContents->setCurrentWidget(editor);
|
m_ui.editorContents->setCurrentWidget(editor);
|
||||||
m_ui.editorContents->update();
|
m_ui.editorContents->update();
|
||||||
|
updateWindowTitle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,6 +453,11 @@ bool MainWindow::openEditor(ProjectModel::LayersNode* node)
|
||||||
return _setEditor(m_layersEditor->loadData(node) ? m_layersEditor : nullptr);
|
return _setEditor(m_layersEditor->loadData(node) ? m_layersEditor : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::openEditor(ProjectModel::SampleNode* node)
|
||||||
|
{
|
||||||
|
return _setEditor(m_sampleEditor->loadData(node) ? m_sampleEditor : nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
bool MainWindow::openEditor(ProjectModel::INode* node)
|
bool MainWindow::openEditor(ProjectModel::INode* node)
|
||||||
{
|
{
|
||||||
switch (node->type())
|
switch (node->type())
|
||||||
|
@ -440,6 +476,8 @@ bool MainWindow::openEditor(ProjectModel::INode* node)
|
||||||
return openEditor(static_cast<ProjectModel::KeymapNode*>(node));
|
return openEditor(static_cast<ProjectModel::KeymapNode*>(node));
|
||||||
case ProjectModel::INode::Type::Layer:
|
case ProjectModel::INode::Type::Layer:
|
||||||
return openEditor(static_cast<ProjectModel::LayersNode*>(node));
|
return openEditor(static_cast<ProjectModel::LayersNode*>(node));
|
||||||
|
case ProjectModel::INode::Type::Sample:
|
||||||
|
return openEditor(static_cast<ProjectModel::SampleNode*>(node));
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -565,11 +603,43 @@ void MainWindow::saveAction()
|
||||||
void MainWindow::revertAction()
|
void MainWindow::revertAction()
|
||||||
{
|
{
|
||||||
QString path = m_projectModel->path();
|
QString path = m_projectModel->path();
|
||||||
|
closeEditor();
|
||||||
|
m_undoStack->clear();
|
||||||
delete m_projectModel;
|
delete m_projectModel;
|
||||||
m_projectModel = nullptr;
|
m_projectModel = nullptr;
|
||||||
openProject(path);
|
openProject(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::reloadSampleDataAction()
|
||||||
|
{
|
||||||
|
ProjectModel* model = m_projectModel;
|
||||||
|
if (!m_projectModel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QDir dir(m_projectModel->path());
|
||||||
|
if (!dir.exists())
|
||||||
|
return;
|
||||||
|
|
||||||
|
startBackgroundTask(tr("Reloading Samples"), tr("Scanning Project"),
|
||||||
|
[dir, model](BackgroundTask& task)
|
||||||
|
{
|
||||||
|
QStringList childDirs = dir.entryList(QDir::Dirs);
|
||||||
|
for (const auto& chDir : childDirs)
|
||||||
|
{
|
||||||
|
if (task.isCanceled())
|
||||||
|
return;
|
||||||
|
QString chPath = dir.filePath(chDir);
|
||||||
|
if (QFileInfo(chPath, QStringLiteral("!project.yaml")).exists() &&
|
||||||
|
QFileInfo(chPath, QStringLiteral("!pool.yaml")).exists())
|
||||||
|
{
|
||||||
|
task.setLabelText(tr("Scanning %1").arg(chDir));
|
||||||
|
if (!model->reloadSampleData(chDir, task.uiMessenger()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::importAction()
|
void MainWindow::importAction()
|
||||||
{
|
{
|
||||||
QString path = QFileDialog::getOpenFileName(this, tr("Import Project"));
|
QString path = QFileDialog::getOpenFileName(this, tr("Import Project"));
|
||||||
|
@ -795,9 +865,10 @@ void MainWindow::notePressed(int key)
|
||||||
amuse::AudioGroupDatabase* group = m_projectModel->getGroupNode(node)->getAudioGroup();
|
amuse::AudioGroupDatabase* group = m_projectModel->getGroupNode(node)->getAudioGroup();
|
||||||
if (m_lastSound)
|
if (m_lastSound)
|
||||||
m_lastSound->keyOff();
|
m_lastSound->keyOff();
|
||||||
m_lastSound = m_engine->macroStart(group, cNode->id(), key, m_velocity, m_modulation);
|
m_lastSound = m_engine->macroStart(group, cNode->id(), key, m_velocity, m_ctrlVals[1]);
|
||||||
m_lastSound->setPedal(m_sustain);
|
m_lastSound->setPedal(m_ctrlVals[64] >= 0x40);
|
||||||
m_lastSound->setPitchWheel(m_pitch);
|
m_lastSound->setPitchWheel(m_pitch);
|
||||||
|
m_lastSound->installCtrlValues(m_ctrlVals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -818,9 +889,9 @@ void MainWindow::velocityChanged(int vel)
|
||||||
|
|
||||||
void MainWindow::modulationChanged(int mod)
|
void MainWindow::modulationChanged(int mod)
|
||||||
{
|
{
|
||||||
m_modulation = mod;
|
m_ctrlVals[1] = int8_t(mod);
|
||||||
for (auto& v : m_engine->getActiveVoices())
|
for (auto& v : m_engine->getActiveVoices())
|
||||||
v->setCtrlValue(1, int8_t(m_modulation));
|
v->setCtrlValue(1, m_ctrlVals[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::pitchChanged(int pitch)
|
void MainWindow::pitchChanged(int pitch)
|
||||||
|
|
|
@ -28,6 +28,7 @@ class ADSREditor;
|
||||||
class CurveEditor;
|
class CurveEditor;
|
||||||
class KeymapEditor;
|
class KeymapEditor;
|
||||||
class LayersEditor;
|
class LayersEditor;
|
||||||
|
class SampleEditor;
|
||||||
|
|
||||||
class BackgroundTask : public QObject
|
class BackgroundTask : public QObject
|
||||||
{
|
{
|
||||||
|
@ -85,15 +86,15 @@ class MainWindow : public QMainWindow
|
||||||
CurveEditor* m_curveEditor = nullptr;
|
CurveEditor* m_curveEditor = nullptr;
|
||||||
KeymapEditor* m_keymapEditor = nullptr;
|
KeymapEditor* m_keymapEditor = nullptr;
|
||||||
LayersEditor* m_layersEditor = nullptr;
|
LayersEditor* m_layersEditor = nullptr;
|
||||||
|
SampleEditor* m_sampleEditor = nullptr;
|
||||||
|
|
||||||
std::unique_ptr<boo::IAudioVoiceEngine> m_voxEngine;
|
std::unique_ptr<boo::IAudioVoiceEngine> m_voxEngine;
|
||||||
std::unique_ptr<VoiceAllocator> m_voxAllocator;
|
std::unique_ptr<VoiceAllocator> m_voxAllocator;
|
||||||
std::unique_ptr<amuse::Engine> m_engine;
|
std::unique_ptr<amuse::Engine> m_engine;
|
||||||
std::shared_ptr<amuse::Voice> m_lastSound;
|
amuse::ObjToken<amuse::Voice> m_lastSound;
|
||||||
int m_velocity = 90;
|
int m_velocity = 90;
|
||||||
int m_modulation = 0;
|
|
||||||
float m_pitch = 0.f;
|
float m_pitch = 0.f;
|
||||||
bool m_sustain = false;
|
int8_t m_ctrlVals[128] = {};
|
||||||
bool m_uiDisabled = false;
|
bool m_uiDisabled = false;
|
||||||
|
|
||||||
QUndoStack* m_undoStack;
|
QUndoStack* m_undoStack;
|
||||||
|
@ -110,6 +111,7 @@ class MainWindow : public QMainWindow
|
||||||
|
|
||||||
void connectMessenger(UIMessenger* messenger, Qt::ConnectionType type);
|
void connectMessenger(UIMessenger* messenger, Qt::ConnectionType type);
|
||||||
|
|
||||||
|
void updateWindowTitle();
|
||||||
void updateRecentFileActions();
|
void updateRecentFileActions();
|
||||||
bool setProjectPath(const QString& path);
|
bool setProjectPath(const QString& path);
|
||||||
void refreshAudioIO();
|
void refreshAudioIO();
|
||||||
|
@ -137,6 +139,7 @@ public:
|
||||||
bool openEditor(ProjectModel::CurveNode* node);
|
bool openEditor(ProjectModel::CurveNode* node);
|
||||||
bool openEditor(ProjectModel::KeymapNode* node);
|
bool openEditor(ProjectModel::KeymapNode* node);
|
||||||
bool openEditor(ProjectModel::LayersNode* node);
|
bool openEditor(ProjectModel::LayersNode* node);
|
||||||
|
bool openEditor(ProjectModel::SampleNode* node);
|
||||||
bool openEditor(ProjectModel::INode* node);
|
bool openEditor(ProjectModel::INode* node);
|
||||||
void closeEditor();
|
void closeEditor();
|
||||||
|
|
||||||
|
@ -153,6 +156,7 @@ public slots:
|
||||||
void clearRecentFilesAction();
|
void clearRecentFilesAction();
|
||||||
void saveAction();
|
void saveAction();
|
||||||
void revertAction();
|
void revertAction();
|
||||||
|
void reloadSampleDataAction();
|
||||||
void importAction();
|
void importAction();
|
||||||
void exportAction();
|
void exportAction();
|
||||||
|
|
||||||
|
|
|
@ -306,8 +306,9 @@
|
||||||
<addaction name="menuRecent_Projects"/>
|
<addaction name="menuRecent_Projects"/>
|
||||||
<addaction name="actionSave_Project"/>
|
<addaction name="actionSave_Project"/>
|
||||||
<addaction name="actionRevert_Project"/>
|
<addaction name="actionRevert_Project"/>
|
||||||
|
<addaction name="actionReload_Sample_Data"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionImport"/>
|
<addaction name="actionImport_Groups"/>
|
||||||
<addaction name="actionExport_GameCube_Groups"/>
|
<addaction name="actionExport_GameCube_Groups"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuProject">
|
<widget class="QMenu" name="menuProject">
|
||||||
|
@ -398,9 +399,9 @@
|
||||||
<string>&Delete</string>
|
<string>&Delete</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionImport">
|
<action name="actionImport_Groups">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Import</string>
|
<string>&Import Groups</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+I</string>
|
<string>Ctrl+I</string>
|
||||||
|
@ -556,6 +557,14 @@
|
||||||
<string>&Revert Project</string>
|
<string>&Revert Project</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionReload_Sample_Data">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reload Sample &Data</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|
|
@ -122,6 +122,21 @@ bool ProjectModel::openGroupData(const QString& groupName, UIMessenger& messenge
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProjectModel::reloadSampleData(const QString& groupName, UIMessenger& messenger)
|
||||||
|
{
|
||||||
|
m_projectDatabase.setIdDatabases();
|
||||||
|
QString path = QFileInfo(m_dir, groupName).filePath();
|
||||||
|
auto search = m_groups.find(groupName);
|
||||||
|
if (search != m_groups.end())
|
||||||
|
{
|
||||||
|
search->second.setIdDatabases();
|
||||||
|
search->second.getSdir().reloadSampleData(QStringToSysString(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_needsReset = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ProjectModel::importGroupData(const QString& groupName, const amuse::AudioGroupData& data,
|
bool ProjectModel::importGroupData(const QString& groupName, const amuse::AudioGroupData& data,
|
||||||
ImportMode mode, UIMessenger& messenger)
|
ImportMode mode, UIMessenger& messenger)
|
||||||
{
|
{
|
||||||
|
@ -200,6 +215,7 @@ void ProjectModel::_resetModelData()
|
||||||
auto& tables = group.getPool().tables();
|
auto& tables = group.getPool().tables();
|
||||||
auto& keymaps = group.getPool().keymaps();
|
auto& keymaps = group.getPool().keymaps();
|
||||||
auto& layers = group.getPool().layers();
|
auto& layers = group.getPool().layers();
|
||||||
|
auto& samples = group.getSdir().sampleEntries();
|
||||||
gn.reserve(songGroups.size() + sfxGroups.size() + 4);
|
gn.reserve(songGroups.size() + sfxGroups.size() + 4);
|
||||||
for (const auto& grp : SortUnorderedMap(songGroups))
|
for (const auto& grp : SortUnorderedMap(songGroups))
|
||||||
gn.makeChild<SongGroupNode>(grp.first, grp.second.get());
|
gn.makeChild<SongGroupNode>(grp.first, grp.second.get());
|
||||||
|
@ -218,7 +234,7 @@ void ProjectModel::_resetModelData()
|
||||||
size_t curveCount = 0;
|
size_t curveCount = 0;
|
||||||
for (auto& t : tablesSort)
|
for (auto& t : tablesSort)
|
||||||
{
|
{
|
||||||
amuse::ITable::Type tp = t.second.get()->Isa();
|
amuse::ITable::Type tp = (*t.second.get())->Isa();
|
||||||
if (tp == amuse::ITable::Type::ADSR || tp == amuse::ITable::Type::ADSRDLS)
|
if (tp == amuse::ITable::Type::ADSR || tp == amuse::ITable::Type::ADSRDLS)
|
||||||
ADSRCount += 1;
|
ADSRCount += 1;
|
||||||
else if (tp == amuse::ITable::Type::Curve)
|
else if (tp == amuse::ITable::Type::Curve)
|
||||||
|
@ -230,7 +246,7 @@ void ProjectModel::_resetModelData()
|
||||||
col.reserve(ADSRCount);
|
col.reserve(ADSRCount);
|
||||||
for (auto& t : tablesSort)
|
for (auto& t : tablesSort)
|
||||||
{
|
{
|
||||||
amuse::ITable::Type tp = t.second.get()->Isa();
|
amuse::ITable::Type tp = (*t.second.get())->Isa();
|
||||||
if (tp == amuse::ITable::Type::ADSR || tp == amuse::ITable::Type::ADSRDLS)
|
if (tp == amuse::ITable::Type::ADSR || tp == amuse::ITable::Type::ADSRDLS)
|
||||||
col.makeChild<ADSRNode>(t.first, t.second.get());
|
col.makeChild<ADSRNode>(t.first, t.second.get());
|
||||||
}
|
}
|
||||||
|
@ -241,9 +257,9 @@ void ProjectModel::_resetModelData()
|
||||||
col.reserve(curveCount);
|
col.reserve(curveCount);
|
||||||
for (auto& t : tablesSort)
|
for (auto& t : tablesSort)
|
||||||
{
|
{
|
||||||
amuse::ITable::Type tp = t.second.get()->Isa();
|
amuse::ITable::Type tp = (*t.second.get())->Isa();
|
||||||
if (tp == amuse::ITable::Type::Curve)
|
if (tp == amuse::ITable::Type::Curve)
|
||||||
col.makeChild<CurveNode>(t.first, std::static_pointer_cast<amuse::Curve>(t.second.get()));
|
col.makeChild<CurveNode>(t.first, t.second.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,6 +277,13 @@ void ProjectModel::_resetModelData()
|
||||||
for (auto& keymap : SortUnorderedMap(layers))
|
for (auto& keymap : SortUnorderedMap(layers))
|
||||||
col.makeChild<LayersNode>(keymap.first, keymap.second.get());
|
col.makeChild<LayersNode>(keymap.first, keymap.second.get());
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
CollectionNode& col =
|
||||||
|
gn.makeChild<CollectionNode>(tr("Samples"), QIcon(":/icons/IconSample.svg"), INode::Type::Sample);
|
||||||
|
col.reserve(samples.size());
|
||||||
|
for (auto& sample : SortUnorderedMap(samples))
|
||||||
|
col.makeChild<SampleNode>(sample.first, sample.second.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,8 @@ public:
|
||||||
ADSR,
|
ADSR,
|
||||||
Curve,
|
Curve,
|
||||||
Keymap,
|
Keymap,
|
||||||
Layer
|
Layer,
|
||||||
|
Sample
|
||||||
};
|
};
|
||||||
protected:
|
protected:
|
||||||
INode* m_parent;
|
INode* m_parent;
|
||||||
|
@ -168,8 +169,8 @@ public:
|
||||||
{
|
{
|
||||||
amuse::GroupId m_id;
|
amuse::GroupId m_id;
|
||||||
QString m_name;
|
QString m_name;
|
||||||
std::shared_ptr<amuse::SongGroupIndex> m_index;
|
amuse::ObjToken<amuse::SongGroupIndex> m_index;
|
||||||
SongGroupNode(INode* parent, int row, amuse::GroupId id, std::shared_ptr<amuse::SongGroupIndex> index)
|
SongGroupNode(INode* parent, int row, amuse::GroupId id, amuse::ObjToken<amuse::SongGroupIndex> index)
|
||||||
: INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {}
|
: INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {}
|
||||||
|
|
||||||
static QIcon Icon;
|
static QIcon Icon;
|
||||||
|
@ -184,8 +185,8 @@ public:
|
||||||
{
|
{
|
||||||
amuse::GroupId m_id;
|
amuse::GroupId m_id;
|
||||||
QString m_name;
|
QString m_name;
|
||||||
std::shared_ptr<amuse::SFXGroupIndex> m_index;
|
amuse::ObjToken<amuse::SFXGroupIndex> m_index;
|
||||||
SoundGroupNode(INode* parent, int row, amuse::GroupId id, std::shared_ptr<amuse::SFXGroupIndex> index)
|
SoundGroupNode(INode* parent, int row, amuse::GroupId id, amuse::ObjToken<amuse::SFXGroupIndex> index)
|
||||||
: INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {}
|
: INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {}
|
||||||
|
|
||||||
static QIcon Icon;
|
static QIcon Icon;
|
||||||
|
@ -221,30 +222,31 @@ public:
|
||||||
struct BasePoolObjectNode : INode
|
struct BasePoolObjectNode : INode
|
||||||
{
|
{
|
||||||
amuse::ObjectId m_id;
|
amuse::ObjectId m_id;
|
||||||
BasePoolObjectNode(INode* parent, int row, amuse::ObjectId id)
|
QString m_name;
|
||||||
: INode(parent, row), m_id(id) {}
|
BasePoolObjectNode(INode* parent, int row, amuse::ObjectId id, const QString& name)
|
||||||
|
: INode(parent, row), m_id(id), m_name(name) {}
|
||||||
amuse::ObjectId id() const { return m_id; }
|
amuse::ObjectId id() const { return m_id; }
|
||||||
|
QString text() const { return m_name; }
|
||||||
|
QIcon icon() const { return {}; }
|
||||||
};
|
};
|
||||||
template <class ID, class T, INode::Type TP>
|
template <class ID, class T, INode::Type TP>
|
||||||
struct PoolObjectNode : BasePoolObjectNode
|
struct PoolObjectNode : BasePoolObjectNode
|
||||||
{
|
{
|
||||||
QString m_name;
|
amuse::ObjToken<T> m_obj;
|
||||||
std::shared_ptr<T> m_obj;
|
PoolObjectNode(INode* parent, int row, ID id, amuse::ObjToken<T> obj)
|
||||||
PoolObjectNode(INode* parent, int row, ID id, std::shared_ptr<T> obj)
|
: BasePoolObjectNode(parent, row, id, ID::CurNameDB->resolveNameFromId(id).data()), m_obj(obj) {}
|
||||||
: BasePoolObjectNode(parent, row, id), m_name(ID::CurNameDB->resolveNameFromId(id).data()), m_obj(obj) {}
|
|
||||||
|
|
||||||
Type type() const { return TP; }
|
Type type() const { return TP; }
|
||||||
QString text() const { return m_name; }
|
|
||||||
QIcon icon() const { return {}; }
|
|
||||||
|
|
||||||
std::shared_ptr<PoolObjectNode<ID, T, TP>> shared_from_this()
|
std::shared_ptr<PoolObjectNode<ID, T, TP>> shared_from_this()
|
||||||
{ return std::static_pointer_cast<PoolObjectNode<ID, T, TP>>(INode::shared_from_this()); }
|
{ return std::static_pointer_cast<PoolObjectNode<ID, T, TP>>(INode::shared_from_this()); }
|
||||||
};
|
};
|
||||||
using SoundMacroNode = PoolObjectNode<amuse::SoundMacroId, amuse::SoundMacro, INode::Type::SoundMacro>;
|
using SoundMacroNode = PoolObjectNode<amuse::SoundMacroId, amuse::SoundMacro, INode::Type::SoundMacro>;
|
||||||
using ADSRNode = PoolObjectNode<amuse::TableId, amuse::ITable, INode::Type::ADSR>;
|
using ADSRNode = PoolObjectNode<amuse::TableId, std::unique_ptr<amuse::ITable>, INode::Type::ADSR>;
|
||||||
using CurveNode = PoolObjectNode<amuse::TableId, amuse::Curve, INode::Type::Curve>;
|
using CurveNode = PoolObjectNode<amuse::TableId, std::unique_ptr<amuse::ITable>, INode::Type::Curve>;
|
||||||
using KeymapNode = PoolObjectNode<amuse::KeymapId, amuse::Keymap, INode::Type::Keymap>;
|
using KeymapNode = PoolObjectNode<amuse::KeymapId, amuse::Keymap, INode::Type::Keymap>;
|
||||||
using LayersNode = PoolObjectNode<amuse::LayersId, std::vector<amuse::LayerMapping>, INode::Type::Layer>;
|
using LayersNode = PoolObjectNode<amuse::LayersId, std::vector<amuse::LayerMapping>, INode::Type::Layer>;
|
||||||
|
using SampleNode = PoolObjectNode<amuse::SampleId, amuse::SampleEntry, INode::Type::Sample>;
|
||||||
|
|
||||||
std::shared_ptr<RootNode> m_root;
|
std::shared_ptr<RootNode> m_root;
|
||||||
|
|
||||||
|
@ -256,6 +258,7 @@ public:
|
||||||
|
|
||||||
bool clearProjectData();
|
bool clearProjectData();
|
||||||
bool openGroupData(const QString& groupName, UIMessenger& messenger);
|
bool openGroupData(const QString& groupName, UIMessenger& messenger);
|
||||||
|
bool reloadSampleData(const QString& groupName, UIMessenger& messenger);
|
||||||
bool importGroupData(const QString& groupName, const amuse::AudioGroupData& data,
|
bool importGroupData(const QString& groupName, const amuse::AudioGroupData& data,
|
||||||
ImportMode mode, UIMessenger& messenger);
|
ImportMode mode, UIMessenger& messenger);
|
||||||
bool saveToFile(UIMessenger& messenger);
|
bool saveToFile(UIMessenger& messenger);
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
#include "SampleEditor.hpp"
|
#include "SampleEditor.hpp"
|
||||||
|
|
||||||
|
bool SampleEditor::loadData(ProjectModel::SampleNode* node)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
SampleEditor::SampleEditor(QWidget* parent)
|
SampleEditor::SampleEditor(QWidget* parent)
|
||||||
: EditorWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,7 @@ class SampleEditor : public EditorWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit SampleEditor(QWidget* parent = Q_NULLPTR);
|
explicit SampleEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SampleNode* node);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,7 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm
|
||||||
}
|
}
|
||||||
case amuse::SoundMacro::CmdIntrospection::Field::Type::SoundMacroId:
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::SoundMacroId:
|
||||||
case amuse::SoundMacro::CmdIntrospection::Field::Type::TableId:
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::TableId:
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::SampleId:
|
||||||
{
|
{
|
||||||
ProjectModel::INode::Type collectionType;
|
ProjectModel::INode::Type collectionType;
|
||||||
if (field.m_tp == amuse::SoundMacro::CmdIntrospection::Field::Type::SoundMacroId)
|
if (field.m_tp == amuse::SoundMacro::CmdIntrospection::Field::Type::SoundMacroId)
|
||||||
|
@ -250,6 +251,10 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm
|
||||||
else
|
else
|
||||||
collectionType = ProjectModel::INode::Type::Curve;
|
collectionType = ProjectModel::INode::Type::Curve;
|
||||||
}
|
}
|
||||||
|
else if (field.m_tp == amuse::SoundMacro::CmdIntrospection::Field::Type::SampleId)
|
||||||
|
{
|
||||||
|
collectionType = ProjectModel::INode::Type::Sample;
|
||||||
|
}
|
||||||
auto* collection = g_MainWindow->projectModel()->getGroupNode(listing->currentNode())->
|
auto* collection = g_MainWindow->projectModel()->getGroupNode(listing->currentNode())->
|
||||||
getCollectionOfType(collectionType);
|
getCollectionOfType(collectionType);
|
||||||
nf = new FieldProjectNode(collection);
|
nf = new FieldProjectNode(collection);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "MainWindow.hpp"
|
#include "MainWindow.hpp"
|
||||||
#include "boo/IApplication.hpp"
|
#include "boo/IApplication.hpp"
|
||||||
#include <QResource>
|
#include <QResource>
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
|
@ -101,5 +102,12 @@ int main(int argc, char* argv[])
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
g_MainWindow = &w;
|
g_MainWindow = &w;
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
|
QCommandLineParser parser;
|
||||||
|
parser.process(a);
|
||||||
|
QStringList args = parser.positionalArguments();
|
||||||
|
if (!args.empty())
|
||||||
|
w.openProject(args.back());
|
||||||
|
|
||||||
return a.exec();
|
return a.exec();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconSample.svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#393939"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="34.25"
|
||||||
|
inkscape:cx="8.0516224"
|
||||||
|
inkscape:cy="8.452632"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2079"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="40"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showborder="true"
|
||||||
|
objecttolerance="4"
|
||||||
|
gridtolerance="4"
|
||||||
|
guidetolerance="5">
|
||||||
|
<inkscape:grid
|
||||||
|
visible="true"
|
||||||
|
empspacing="1"
|
||||||
|
id="grid4173"
|
||||||
|
type="xygrid" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
transform="translate(0,-292.76665)"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<path
|
||||||
|
id="path1184"
|
||||||
|
title="sin(x*4*pi)*sin(x*pi)"
|
||||||
|
d="m 0.36489826,294.88332 c 0.12976062,-1.7e-4 0.25952124,-0.20582 0.38928188,-0.34418 0.12976062,-0.13838 0.25952116,-0.13639 0.38928186,0.11952 0.1297606,0.25593 0.2595211,0.73341 0.3892818,0.99106 0.1297606,0.25765 0.2595213,0.22574 0.3892819,-0.11953 0.1297606,-0.34528 0.2595212,-0.94796 0.3892819,-1.29374 0.1297606,-0.34576 0.2595213,-0.37673 0.3892818,-0.11953 0.1297606,0.2572 0.2595213,0.73474 0.3892819,0.99106 0.1297607,0.25631 0.2595213,0.25771 0.3892819,0.11953 0.1297606,-0.13818 0.2595212,-0.34402 0.3892819,-0.34419"
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#04e2ff;stroke-width:0.43794215;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -13,6 +13,7 @@
|
||||||
<name>MainWindow</name>
|
<name>MainWindow</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="+14"/>
|
<location filename="../MainWindow.ui" line="+14"/>
|
||||||
|
<location filename="../MainWindow.cpp" line="+181"/>
|
||||||
<source>Amuse</source>
|
<source>Amuse</source>
|
||||||
<translation>Amuse</translation>
|
<translation>Amuse</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -22,7 +23,7 @@
|
||||||
<translation>&Datei</translation>
|
<translation>&Datei</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+21"/>
|
<location line="+22"/>
|
||||||
<source>P&roject</source>
|
<source>P&roject</source>
|
||||||
<translation>Projekt</translation>
|
<translation>Projekt</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -60,12 +61,12 @@
|
||||||
<translation type="vanished">& Wiederholen</translation>
|
<translation type="vanished">& Wiederholen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="-65"/>
|
<location line="-66"/>
|
||||||
<source>Recent &Projects</source>
|
<source>Recent &Projects</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+73"/>
|
<location line="+74"/>
|
||||||
<source>&Cut</source>
|
<source>&Cut</source>
|
||||||
<translation>&Schnitt</translation>
|
<translation>&Schnitt</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -85,9 +86,13 @@
|
||||||
<translation>&Löschen</translation>
|
<translation>&Löschen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+5"/>
|
|
||||||
<source>&Import</source>
|
<source>&Import</source>
|
||||||
<translation>&Einführen</translation>
|
<translation type="vanished">&Einführen</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location line="+5"/>
|
||||||
|
<source>&Import Groups</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+3"/>
|
<location line="+3"/>
|
||||||
|
@ -170,12 +175,17 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="+70"/>
|
<location line="+8"/>
|
||||||
|
<source>Reload Sample &Data</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../MainWindow.cpp" line="-109"/>
|
||||||
<source>Quit</source>
|
<source>Quit</source>
|
||||||
<translation>Verlassen</translation>
|
<translation>Verlassen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+134"/>
|
<location line="+160"/>
|
||||||
<source>The directory at '%1' must exist for the Amuse editor.</source>
|
<source>The directory at '%1' must exist for the Amuse editor.</source>
|
||||||
<translation>Das Verzeichnis unter '% 1' muss für den Amuse-Editor vorhanden sein.</translation>
|
<translation>Das Verzeichnis unter '% 1' muss für den Amuse-Editor vorhanden sein.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -200,7 +210,7 @@
|
||||||
<translation>Es konnte nicht in das Verzeichnis geschrieben werden</translation>
|
<translation>Es konnte nicht in das Verzeichnis geschrieben werden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+44"/>
|
<location line="+46"/>
|
||||||
<source>No Audio Devices Found</source>
|
<source>No Audio Devices Found</source>
|
||||||
<translation>Keine Audiogeräte gefunden</translation>
|
<translation>Keine Audiogeräte gefunden</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -210,7 +220,7 @@
|
||||||
<translation>Keine MIDI-Geräte gefunden</translation>
|
<translation>Keine MIDI-Geräte gefunden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+193"/>
|
<location line="+201"/>
|
||||||
<source>New Project</source>
|
<source>New Project</source>
|
||||||
<translation>Neues Projekt</translation>
|
<translation>Neues Projekt</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -225,29 +235,39 @@
|
||||||
<translation>Das Verzeichnis '% 1' existiert nicht.</translation>
|
<translation>Das Verzeichnis '% 1' existiert nicht.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="-432"/>
|
<location line="-468"/>
|
||||||
<source>Clear Recent Projects</source>
|
<source>Clear Recent Projects</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+134"/>
|
<location line="+124"/>
|
||||||
<location line="+292"/>
|
<source>Amuse [%1/%2/%3]</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location line="+5"/>
|
||||||
|
<source>Amuse [%1]</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location line="+31"/>
|
||||||
|
<location line="+302"/>
|
||||||
<source>The directory at '%1' must not be empty.</source>
|
<source>The directory at '%1' must not be empty.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="-291"/>
|
<location line="-301"/>
|
||||||
<location line="+292"/>
|
<location line="+302"/>
|
||||||
<source>Directory empty</source>
|
<source>Directory empty</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="-181"/>
|
<location line="-189"/>
|
||||||
<source>SUSTAIN</source>
|
<source>SUSTAIN</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+187"/>
|
<location line="+195"/>
|
||||||
<source>Bad Directory</source>
|
<source>Bad Directory</source>
|
||||||
<translation>Schlechtes Verzeichnis</translation>
|
<translation>Schlechtes Verzeichnis</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -258,18 +278,29 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+0"/>
|
<location line="+0"/>
|
||||||
<location line="+127"/>
|
<location line="+76"/>
|
||||||
|
<location line="+83"/>
|
||||||
<location line="+45"/>
|
<location line="+45"/>
|
||||||
<source>Scanning Project</source>
|
<source>Scanning Project</source>
|
||||||
<translation>Projekt scannen</translation>
|
<translation>Projekt scannen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="-160"/>
|
<location line="-192"/>
|
||||||
<source>Opening %1</source>
|
<source>Opening %1</source>
|
||||||
<translation>Eröffnung% 1</translation>
|
<translation>Eröffnung% 1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+54"/>
|
<location line="+64"/>
|
||||||
|
<source>Reloading Samples</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location line="+12"/>
|
||||||
|
<source>Scanning %1</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location line="+10"/>
|
||||||
<source>Import Project</source>
|
<source>Import Project</source>
|
||||||
<translation>Projekt importieren</translation>
|
<translation>Projekt importieren</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -360,7 +391,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ProjectModel</name>
|
<name>ProjectModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ProjectModel.cpp" line="+210"/>
|
<location filename="../ProjectModel.cpp" line="+226"/>
|
||||||
<source>Sound Macros</source>
|
<source>Sound Macros</source>
|
||||||
<translation>Sound-Makros</translation>
|
<translation>Sound-Makros</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -384,6 +415,11 @@
|
||||||
<source>Layers</source>
|
<source>Layers</source>
|
||||||
<translation>Lagen</translation>
|
<translation>Lagen</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location line="+7"/>
|
||||||
|
<source>Samples</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>QObject</name>
|
<name>QObject</name>
|
||||||
|
@ -401,7 +437,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>QUndoStack</name>
|
<name>QUndoStack</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../SoundMacroEditor.cpp" line="+157"/>
|
<location filename="../SoundMacroEditor.cpp" line="+162"/>
|
||||||
<source>Change %1</source>
|
<source>Change %1</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -506,7 +542,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>TargetButton</name>
|
<name>TargetButton</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../SoundMacroEditor.cpp" line="-939"/>
|
<location filename="../SoundMacroEditor.cpp" line="-944"/>
|
||||||
<source>Set step with target click</source>
|
<source>Set step with target click</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
<file>IconSoundMacroTarget.svg</file>
|
<file>IconSoundMacroTarget.svg</file>
|
||||||
<file>IconSoundMacroTargetDisabled.svg</file>
|
<file>IconSoundMacroTargetDisabled.svg</file>
|
||||||
<file>IconKill.svg</file>
|
<file>IconKill.svg</file>
|
||||||
|
<file>IconSample.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/bg">
|
<qresource prefix="/bg">
|
||||||
<file>FaceGrey.svg</file>
|
<file>FaceGrey.svg</file>
|
||||||
|
|
|
@ -66,12 +66,12 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
int m_chanId = 0;
|
int m_chanId = 0;
|
||||||
int8_t m_octave = 4;
|
int8_t m_octave = 4;
|
||||||
int8_t m_velocity = 64;
|
int8_t m_velocity = 64;
|
||||||
std::shared_ptr<amuse::Sequencer> m_seq;
|
amuse::ObjToken<amuse::Sequencer> m_seq;
|
||||||
amuse::ContainerRegistry::SongData* m_arrData = nullptr;
|
amuse::ContainerRegistry::SongData* m_arrData = nullptr;
|
||||||
|
|
||||||
/* SFX playback selection */
|
/* SFX playback selection */
|
||||||
int m_sfxId = -1;
|
int m_sfxId = -1;
|
||||||
std::shared_ptr<amuse::Voice> m_vox;
|
amuse::ObjToken<amuse::Voice> m_vox;
|
||||||
size_t m_lastVoxCount = 0;
|
size_t m_lastVoxCount = 0;
|
||||||
int8_t m_lastChanProg = -1;
|
int8_t m_lastChanProg = -1;
|
||||||
|
|
||||||
|
@ -665,10 +665,10 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
|
|
||||||
std::list<amuse::AudioGroupProject> m_projs;
|
std::list<amuse::AudioGroupProject> m_projs;
|
||||||
std::map<amuse::GroupId, std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*,
|
std::map<amuse::GroupId, std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*,
|
||||||
const amuse::SongGroupIndex*>>
|
amuse::ObjToken<amuse::SongGroupIndex>>>
|
||||||
allSongGroups;
|
allSongGroups;
|
||||||
std::map<amuse::GroupId, std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*,
|
std::map<amuse::GroupId, std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*,
|
||||||
const amuse::SFXGroupIndex*>>
|
amuse::ObjToken<amuse::SFXGroupIndex>>>
|
||||||
allSFXGroups;
|
allSFXGroups;
|
||||||
size_t totalGroups = 0;
|
size_t totalGroups = 0;
|
||||||
|
|
||||||
|
@ -680,10 +680,10 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
totalGroups += proj.sfxGroups().size() + proj.songGroups().size();
|
totalGroups += proj.sfxGroups().size() + proj.songGroups().size();
|
||||||
|
|
||||||
for (auto it = proj.songGroups().begin(); it != proj.songGroups().end(); ++it)
|
for (auto it = proj.songGroups().begin(); it != proj.songGroups().end(); ++it)
|
||||||
allSongGroups[it->first] = std::make_pair(&grp, &it->second);
|
allSongGroups[it->first] = std::make_pair(&grp, it->second);
|
||||||
|
|
||||||
for (auto it = proj.sfxGroups().begin(); it != proj.sfxGroups().end(); ++it)
|
for (auto it = proj.sfxGroups().begin(); it != proj.sfxGroups().end(); ++it)
|
||||||
allSFXGroups[it->first] = std::make_pair(&grp, &it->second);
|
allSFXGroups[it->first] = std::make_pair(&grp, it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (m_running)
|
while (m_running)
|
||||||
|
@ -825,14 +825,14 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
printf("Multiple Audio Groups discovered:\n");
|
printf("Multiple Audio Groups discovered:\n");
|
||||||
for (const auto& pair : allSFXGroups)
|
for (const auto& pair : allSFXGroups)
|
||||||
{
|
{
|
||||||
amuse::Printf(_S(" %d %s (SFXGroup) %" PRISize " sfx-entries\n"), pair.first,
|
amuse::Printf(_S(" %d %s (SFXGroup) %" PRISize " sfx-entries\n"), pair.first.id,
|
||||||
pair.second.first->first.c_str(), pair.second.second->m_sfxEntries.size());
|
pair.second.first->first.c_str(), pair.second.second->m_sfxEntries.size());
|
||||||
}
|
}
|
||||||
for (const auto& pair : allSongGroups)
|
for (const auto& pair : allSongGroups)
|
||||||
{
|
{
|
||||||
amuse::Printf(_S(" %d %s (SongGroup) %" PRISize " normal-pages, %" PRISize
|
amuse::Printf(_S(" %d %s (SongGroup) %" PRISize " normal-pages, %" PRISize
|
||||||
" drum-pages, %" PRISize " MIDI-setups\n"),
|
" drum-pages, %" PRISize " MIDI-setups\n"),
|
||||||
pair.first, pair.second.first->first.c_str(), pair.second.second->m_normPages.size(),
|
pair.first.id, pair.second.first->first.c_str(), pair.second.second->m_normPages.size(),
|
||||||
pair.second.second->m_drumPages.size(), pair.second.second->m_midiSetups.size());
|
pair.second.second->m_drumPages.size(), pair.second.second->m_midiSetups.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,8 +884,8 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
|
|
||||||
/* Make final group selection */
|
/* Make final group selection */
|
||||||
amuse::IntrusiveAudioGroupData* selData = nullptr;
|
amuse::IntrusiveAudioGroupData* selData = nullptr;
|
||||||
const amuse::SongGroupIndex* songIndex = nullptr;
|
amuse::ObjToken<amuse::SongGroupIndex> songIndex;
|
||||||
const amuse::SFXGroupIndex* sfxIndex = nullptr;
|
amuse::ObjToken<amuse::SFXGroupIndex> sfxIndex;
|
||||||
auto songSearch = allSongGroups.find(m_groupId);
|
auto songSearch = allSongGroups.find(m_groupId);
|
||||||
if (songSearch != allSongGroups.end())
|
if (songSearch != allSongGroups.end())
|
||||||
{
|
{
|
||||||
|
|
|
@ -163,10 +163,10 @@ int main(int argc, const boo::SystemChar** argv)
|
||||||
|
|
||||||
std::list<amuse::AudioGroupProject> m_projs;
|
std::list<amuse::AudioGroupProject> m_projs;
|
||||||
std::map<int,
|
std::map<int,
|
||||||
std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*, const amuse::SongGroupIndex*>>
|
std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*, amuse::ObjToken<amuse::SongGroupIndex>>>
|
||||||
allSongGroups;
|
allSongGroups;
|
||||||
std::map<int,
|
std::map<int,
|
||||||
std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*, const amuse::SFXGroupIndex*>>
|
std::pair<std::pair<amuse::SystemString, amuse::IntrusiveAudioGroupData>*, amuse::ObjToken<amuse::SFXGroupIndex>>>
|
||||||
allSFXGroups;
|
allSFXGroups;
|
||||||
size_t totalGroups = 0;
|
size_t totalGroups = 0;
|
||||||
|
|
||||||
|
@ -178,10 +178,10 @@ int main(int argc, const boo::SystemChar** argv)
|
||||||
totalGroups += proj.sfxGroups().size() + proj.songGroups().size();
|
totalGroups += proj.sfxGroups().size() + proj.songGroups().size();
|
||||||
|
|
||||||
for (auto it = proj.songGroups().begin(); it != proj.songGroups().end(); ++it)
|
for (auto it = proj.songGroups().begin(); it != proj.songGroups().end(); ++it)
|
||||||
allSongGroups[it->first] = std::make_pair(&grp, &it->second);
|
allSongGroups[it->first] = std::make_pair(&grp, it->second);
|
||||||
|
|
||||||
for (auto it = proj.sfxGroups().begin(); it != proj.sfxGroups().end(); ++it)
|
for (auto it = proj.sfxGroups().begin(); it != proj.sfxGroups().end(); ++it)
|
||||||
allSFXGroups[it->first] = std::make_pair(&grp, &it->second);
|
allSFXGroups[it->first] = std::make_pair(&grp, it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt loading song */
|
/* Attempt loading song */
|
||||||
|
@ -393,8 +393,8 @@ int main(int argc, const boo::SystemChar** argv)
|
||||||
|
|
||||||
/* Make final group selection */
|
/* Make final group selection */
|
||||||
amuse::IntrusiveAudioGroupData* selData = nullptr;
|
amuse::IntrusiveAudioGroupData* selData = nullptr;
|
||||||
const amuse::SongGroupIndex* songIndex = nullptr;
|
amuse::ObjToken<amuse::SongGroupIndex> songIndex;
|
||||||
const amuse::SFXGroupIndex* sfxIndex = nullptr;
|
amuse::ObjToken<amuse::SFXGroupIndex> sfxIndex;
|
||||||
auto songSearch = allSongGroups.find(m_groupId);
|
auto songSearch = allSongGroups.find(m_groupId);
|
||||||
if (songSearch != allSongGroups.end())
|
if (songSearch != allSongGroups.end())
|
||||||
{
|
{
|
||||||
|
@ -465,7 +465,7 @@ int main(int argc, const boo::SystemChar** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enter playback loop */
|
/* Enter playback loop */
|
||||||
std::shared_ptr<amuse::Sequencer> seq = engine.seqPlay(m_groupId, m_setupId, m_arrData->m_data.get());
|
amuse::ObjToken<amuse::Sequencer> seq = engine.seqPlay(m_groupId, m_setupId, m_arrData->m_data.get());
|
||||||
size_t wroteFrames = 0;
|
size_t wroteFrames = 0;
|
||||||
signal(SIGINT, SIGINTHandler);
|
signal(SIGINT, SIGINTHandler);
|
||||||
do
|
do
|
||||||
|
|
|
@ -28,8 +28,9 @@ public:
|
||||||
void assign(const AudioGroupData& data);
|
void assign(const AudioGroupData& data);
|
||||||
void assign(SystemStringView groupPath);
|
void assign(SystemStringView groupPath);
|
||||||
|
|
||||||
const AudioGroupSampleDirectory::Entry* getSample(SampleId sfxId) const;
|
const SampleEntry* getSample(SampleId sfxId) const;
|
||||||
const unsigned char* getSampleData(SampleId sfxId, const AudioGroupSampleDirectory::Entry* sample) const;
|
std::pair<ObjToken<SampleEntryData>, const unsigned char*>
|
||||||
|
getSampleData(SampleId sfxId, const SampleEntry* sample) const;
|
||||||
const AudioGroupProject& getProj() const { return m_proj; }
|
const AudioGroupProject& getProj() const { return m_proj; }
|
||||||
const AudioGroupPool& getPool() const { return m_pool; }
|
const AudioGroupPool& getPool() const { return m_pool; }
|
||||||
const AudioGroupSampleDirectory& getSdir() const { return m_sdir; }
|
const AudioGroupSampleDirectory& getSdir() const { return m_sdir; }
|
||||||
|
|
|
@ -1338,10 +1338,10 @@ struct LayerMapping : BigDNA
|
||||||
/** Database of functional objects within Audio Group */
|
/** Database of functional objects within Audio Group */
|
||||||
class AudioGroupPool
|
class AudioGroupPool
|
||||||
{
|
{
|
||||||
std::unordered_map<SoundMacroId, std::shared_ptr<SoundMacro>> m_soundMacros;
|
std::unordered_map<SoundMacroId, ObjToken<SoundMacro>> m_soundMacros;
|
||||||
std::unordered_map<TableId, std::shared_ptr<ITable>> m_tables;
|
std::unordered_map<TableId, ObjToken<std::unique_ptr<ITable>>> m_tables;
|
||||||
std::unordered_map<KeymapId, std::shared_ptr<Keymap>> m_keymaps;
|
std::unordered_map<KeymapId, ObjToken<Keymap>> m_keymaps;
|
||||||
std::unordered_map<LayersId, std::shared_ptr<std::vector<LayerMapping>>> m_layers;
|
std::unordered_map<LayersId, ObjToken<std::vector<LayerMapping>>> m_layers;
|
||||||
|
|
||||||
template <athena::Endian DNAE>
|
template <athena::Endian DNAE>
|
||||||
static AudioGroupPool _AudioGroupPool(athena::io::IStreamReader& r);
|
static AudioGroupPool _AudioGroupPool(athena::io::IStreamReader& r);
|
||||||
|
@ -1350,14 +1350,14 @@ public:
|
||||||
static AudioGroupPool CreateAudioGroupPool(const AudioGroupData& data);
|
static AudioGroupPool CreateAudioGroupPool(const AudioGroupData& data);
|
||||||
static AudioGroupPool CreateAudioGroupPool(SystemStringView groupPath);
|
static AudioGroupPool CreateAudioGroupPool(SystemStringView groupPath);
|
||||||
|
|
||||||
const std::unordered_map<SoundMacroId, std::shared_ptr<SoundMacro>>& soundMacros() const { return m_soundMacros; }
|
const std::unordered_map<SoundMacroId, ObjToken<SoundMacro>>& soundMacros() const { return m_soundMacros; }
|
||||||
const std::unordered_map<TableId, std::shared_ptr<ITable>>& tables() const { return m_tables; }
|
const std::unordered_map<TableId, ObjToken<std::unique_ptr<ITable>>>& tables() const { return m_tables; }
|
||||||
const std::unordered_map<KeymapId, std::shared_ptr<Keymap>>& keymaps() const { return m_keymaps; }
|
const std::unordered_map<KeymapId, ObjToken<Keymap>>& keymaps() const { return m_keymaps; }
|
||||||
const std::unordered_map<LayersId, std::shared_ptr<std::vector<LayerMapping>>>& layers() const { return m_layers; }
|
const std::unordered_map<LayersId, ObjToken<std::vector<LayerMapping>>>& layers() const { return m_layers; }
|
||||||
std::unordered_map<SoundMacroId, std::shared_ptr<SoundMacro>>& soundMacros() { return m_soundMacros; }
|
std::unordered_map<SoundMacroId, ObjToken<SoundMacro>>& soundMacros() { return m_soundMacros; }
|
||||||
std::unordered_map<TableId, std::shared_ptr<ITable>>& tables() { return m_tables; }
|
std::unordered_map<TableId, ObjToken<std::unique_ptr<ITable>>>& tables() { return m_tables; }
|
||||||
std::unordered_map<KeymapId, std::shared_ptr<Keymap>>& keymaps() { return m_keymaps; }
|
std::unordered_map<KeymapId, ObjToken<Keymap>>& keymaps() { return m_keymaps; }
|
||||||
std::unordered_map<LayersId, std::shared_ptr<std::vector<LayerMapping>>>& layers() { return m_layers; }
|
std::unordered_map<LayersId, ObjToken<std::vector<LayerMapping>>>& layers() { return m_layers; }
|
||||||
|
|
||||||
const SoundMacro* soundMacro(ObjectId id) const;
|
const SoundMacro* soundMacro(ObjectId id) const;
|
||||||
const Keymap* keymap(ObjectId id) const;
|
const Keymap* keymap(ObjectId id) const;
|
||||||
|
|
|
@ -180,8 +180,8 @@ struct SFXGroupIndex : AudioGroupIndex
|
||||||
/** Collection of SongGroup and SFXGroup indexes */
|
/** Collection of SongGroup and SFXGroup indexes */
|
||||||
class AudioGroupProject
|
class AudioGroupProject
|
||||||
{
|
{
|
||||||
std::unordered_map<GroupId, std::shared_ptr<SongGroupIndex>> m_songGroups;
|
std::unordered_map<GroupId, ObjToken<SongGroupIndex>> m_songGroups;
|
||||||
std::unordered_map<GroupId, std::shared_ptr<SFXGroupIndex>> m_sfxGroups;
|
std::unordered_map<GroupId, ObjToken<SFXGroupIndex>> m_sfxGroups;
|
||||||
|
|
||||||
AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag);
|
AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag);
|
||||||
template <athena::Endian DNAE>
|
template <athena::Endian DNAE>
|
||||||
|
@ -199,10 +199,10 @@ public:
|
||||||
const SongGroupIndex* getSongGroupIndex(int groupId) const;
|
const SongGroupIndex* getSongGroupIndex(int groupId) const;
|
||||||
const SFXGroupIndex* getSFXGroupIndex(int groupId) const;
|
const SFXGroupIndex* getSFXGroupIndex(int groupId) const;
|
||||||
|
|
||||||
const std::unordered_map<GroupId, std::shared_ptr<SongGroupIndex>>& songGroups() const { return m_songGroups; }
|
const std::unordered_map<GroupId, ObjToken<SongGroupIndex>>& songGroups() const { return m_songGroups; }
|
||||||
const std::unordered_map<GroupId, std::shared_ptr<SFXGroupIndex>>& sfxGroups() const { return m_sfxGroups; }
|
const std::unordered_map<GroupId, ObjToken<SFXGroupIndex>>& sfxGroups() const { return m_sfxGroups; }
|
||||||
std::unordered_map<GroupId, std::shared_ptr<SongGroupIndex>>& songGroups() { return m_songGroups; }
|
std::unordered_map<GroupId, ObjToken<SongGroupIndex>>& songGroups() { return m_songGroups; }
|
||||||
std::unordered_map<GroupId, std::shared_ptr<SFXGroupIndex>>& sfxGroups() { return m_sfxGroups; }
|
std::unordered_map<GroupId, ObjToken<SFXGroupIndex>>& sfxGroups() { return m_sfxGroups; }
|
||||||
|
|
||||||
bool toYAML(SystemStringView groupPath) const;
|
bool toYAML(SystemStringView groupPath) const;
|
||||||
|
|
||||||
|
|
|
@ -184,11 +184,11 @@ public:
|
||||||
Value<uint32_t, DNAEn> m_loopStartSample;
|
Value<uint32_t, DNAEn> m_loopStartSample;
|
||||||
Value<uint32_t, DNAEn> m_loopLengthSamples;
|
Value<uint32_t, DNAEn> m_loopLengthSamples;
|
||||||
};
|
};
|
||||||
struct Entry
|
struct EntryData
|
||||||
{
|
{
|
||||||
atUint32 m_sampleOff = 0;
|
atUint32 m_sampleOff = 0;
|
||||||
atUint32 m_unk = 0;
|
atUint32 m_unk = 0;
|
||||||
atUint8 m_pitch = 0;
|
atUint8 m_pitch = 60;
|
||||||
atUint16 m_sampleRate = 0;
|
atUint16 m_sampleRate = 0;
|
||||||
atUint32 m_numSamples = 0; // Top 8 bits is SampleFormat
|
atUint32 m_numSamples = 0; // Top 8 bits is SampleFormat
|
||||||
atUint32 m_loopStartSample = 0;
|
atUint32 m_loopStartSample = 0;
|
||||||
|
@ -204,24 +204,24 @@ public:
|
||||||
time_t m_looseModTime = 0;
|
time_t m_looseModTime = 0;
|
||||||
std::unique_ptr<uint8_t[]> m_looseData;
|
std::unique_ptr<uint8_t[]> m_looseData;
|
||||||
|
|
||||||
Entry() = default;
|
EntryData() = default;
|
||||||
|
|
||||||
template <athena::Endian DNAE>
|
template <athena::Endian DNAE>
|
||||||
Entry(const EntryDNA<DNAE>& in)
|
EntryData(const EntryDNA<DNAE>& in)
|
||||||
: m_sampleOff(in.m_sampleOff), m_unk(in.m_unk), m_pitch(in.m_pitch),
|
: m_sampleOff(in.m_sampleOff), m_unk(in.m_unk), m_pitch(in.m_pitch),
|
||||||
m_sampleRate(in.m_sampleRate), m_numSamples(in.m_numSamples),
|
m_sampleRate(in.m_sampleRate), m_numSamples(in.m_numSamples),
|
||||||
m_loopStartSample(in.m_loopStartSample), m_loopLengthSamples(in.m_loopLengthSamples),
|
m_loopStartSample(in.m_loopStartSample), m_loopLengthSamples(in.m_loopLengthSamples),
|
||||||
m_adpcmParmOffset(in.m_adpcmParmOffset) {}
|
m_adpcmParmOffset(in.m_adpcmParmOffset) {}
|
||||||
|
|
||||||
template <athena::Endian DNAE>
|
template <athena::Endian DNAE>
|
||||||
Entry(const MusyX1SdirEntry<DNAE>& in)
|
EntryData(const MusyX1SdirEntry<DNAE>& in)
|
||||||
: m_sampleOff(in.m_sampleOff), m_unk(0), m_pitch(in.m_pitchSampleRate >> 24),
|
: m_sampleOff(in.m_sampleOff), m_unk(0), m_pitch(in.m_pitchSampleRate >> 24),
|
||||||
m_sampleRate(in.m_pitchSampleRate & 0xffff), m_numSamples(in.m_numSamples),
|
m_sampleRate(in.m_pitchSampleRate & 0xffff), m_numSamples(in.m_numSamples),
|
||||||
m_loopStartSample(in.m_loopStartSample), m_loopLengthSamples(in.m_loopLengthSamples),
|
m_loopStartSample(in.m_loopStartSample), m_loopLengthSamples(in.m_loopLengthSamples),
|
||||||
m_adpcmParmOffset(0) {}
|
m_adpcmParmOffset(0) {}
|
||||||
|
|
||||||
template <athena::Endian DNAE>
|
template <athena::Endian DNAE>
|
||||||
Entry(const MusyX1AbsSdirEntry<DNAE>& in)
|
EntryData(const MusyX1AbsSdirEntry<DNAE>& in)
|
||||||
: m_sampleOff(in.m_sampleOff), m_unk(in.m_unk), m_pitch(in.m_pitchSampleRate >> 24),
|
: m_sampleOff(in.m_sampleOff), m_unk(in.m_unk), m_pitch(in.m_pitchSampleRate >> 24),
|
||||||
m_sampleRate(in.m_pitchSampleRate & 0xffff), m_numSamples(in.m_numSamples),
|
m_sampleRate(in.m_pitchSampleRate & 0xffff), m_numSamples(in.m_numSamples),
|
||||||
m_loopStartSample(in.m_loopStartSample), m_loopLengthSamples(in.m_loopLengthSamples),
|
m_loopStartSample(in.m_loopStartSample), m_loopLengthSamples(in.m_loopLengthSamples),
|
||||||
|
@ -243,14 +243,45 @@ public:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadLooseDSP(SystemStringView dspPath);
|
||||||
|
void loadLooseWAV(SystemStringView wavPath);
|
||||||
|
};
|
||||||
|
/* This double-wrapper allows Voices to keep a strong reference on
|
||||||
|
* a single instance of loaded loose data without being unexpectedly
|
||||||
|
* clobbered */
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
ObjToken<EntryData> m_data;
|
||||||
|
|
||||||
|
Entry()
|
||||||
|
: m_data(MakeObj<EntryData>()) {}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
Entry(const EntryDNA<DNAE>& in)
|
||||||
|
: m_data(MakeObj<EntryData>(in)) {}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
Entry(const MusyX1SdirEntry<DNAE>& in)
|
||||||
|
: m_data(MakeObj<EntryData>(in)) {}
|
||||||
|
|
||||||
|
template <athena::Endian DNAE>
|
||||||
|
Entry(const MusyX1AbsSdirEntry<DNAE>& in)
|
||||||
|
: m_data(MakeObj<EntryData>(in)) {}
|
||||||
|
|
||||||
|
template <athena::Endian DNAEn>
|
||||||
|
EntryDNA<DNAEn> toDNA(SFXId id) const
|
||||||
|
{
|
||||||
|
return m_data->toDNA<DNAEn>(id);
|
||||||
|
}
|
||||||
|
|
||||||
void loadLooseData(SystemStringView basePath);
|
void loadLooseData(SystemStringView basePath);
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<SampleId, Entry> m_entries;
|
std::unordered_map<SampleId, ObjToken<Entry>> m_entries;
|
||||||
static void _extractWAV(SampleId id, const Entry& ent, amuse::SystemStringView destDir,
|
static void _extractWAV(SampleId id, const EntryData& ent, amuse::SystemStringView destDir,
|
||||||
const unsigned char* samp);
|
const unsigned char* samp);
|
||||||
static void _extractCompressed(SampleId id, const Entry& ent, amuse::SystemStringView destDir,
|
static void _extractCompressed(SampleId id, const EntryData& ent, amuse::SystemStringView destDir,
|
||||||
const unsigned char* samp);
|
const unsigned char* samp);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -261,18 +292,23 @@ public:
|
||||||
static AudioGroupSampleDirectory CreateAudioGroupSampleDirectory(const AudioGroupData& data);
|
static AudioGroupSampleDirectory CreateAudioGroupSampleDirectory(const AudioGroupData& data);
|
||||||
static AudioGroupSampleDirectory CreateAudioGroupSampleDirectory(SystemStringView groupPath);
|
static AudioGroupSampleDirectory CreateAudioGroupSampleDirectory(SystemStringView groupPath);
|
||||||
|
|
||||||
const std::unordered_map<SampleId, Entry>& sampleEntries() const { return m_entries; }
|
const std::unordered_map<SampleId, ObjToken<Entry>>& sampleEntries() const { return m_entries; }
|
||||||
|
|
||||||
void extractWAV(SampleId id, amuse::SystemStringView destDir, const unsigned char* samp) const;
|
void extractWAV(SampleId id, amuse::SystemStringView destDir, const unsigned char* samp) const;
|
||||||
void extractAllWAV(amuse::SystemStringView destDir, const unsigned char* samp) const;
|
void extractAllWAV(amuse::SystemStringView destDir, const unsigned char* samp) const;
|
||||||
void extractCompressed(SampleId id, amuse::SystemStringView destDir, const unsigned char* samp) const;
|
void extractCompressed(SampleId id, amuse::SystemStringView destDir, const unsigned char* samp) const;
|
||||||
void extractAllCompressed(amuse::SystemStringView destDir, const unsigned char* samp) const;
|
void extractAllCompressed(amuse::SystemStringView destDir, const unsigned char* samp) const;
|
||||||
|
|
||||||
|
void reloadSampleData(SystemStringView groupPath);
|
||||||
|
|
||||||
AudioGroupSampleDirectory(const AudioGroupSampleDirectory&) = delete;
|
AudioGroupSampleDirectory(const AudioGroupSampleDirectory&) = delete;
|
||||||
AudioGroupSampleDirectory& operator=(const AudioGroupSampleDirectory&) = delete;
|
AudioGroupSampleDirectory& operator=(const AudioGroupSampleDirectory&) = delete;
|
||||||
AudioGroupSampleDirectory(AudioGroupSampleDirectory&&) = default;
|
AudioGroupSampleDirectory(AudioGroupSampleDirectory&&) = default;
|
||||||
AudioGroupSampleDirectory& operator=(AudioGroupSampleDirectory&&) = default;
|
AudioGroupSampleDirectory& operator=(AudioGroupSampleDirectory&&) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using SampleEntry = AudioGroupSampleDirectory::Entry;
|
||||||
|
using SampleEntryData = AudioGroupSampleDirectory::EntryData;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __AMUSE_AUDIOGROUPSAMPLEDIR_HPP__
|
#endif // __AMUSE_AUDIOGROUPSAMPLEDIR_HPP__
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <atomic>
|
||||||
#include "athena/DNA.hpp"
|
#include "athena/DNA.hpp"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
@ -134,6 +135,64 @@ struct LittleUInt24 : LittleDNA
|
||||||
LittleUInt24& operator=(uint32_t valIn) { val = valIn; return *this; }
|
LittleUInt24& operator=(uint32_t valIn) { val = valIn; return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IObj
|
||||||
|
{
|
||||||
|
std::atomic_int m_refCount = {0};
|
||||||
|
protected:
|
||||||
|
virtual ~IObj() = default;
|
||||||
|
public:
|
||||||
|
void increment() { m_refCount++; }
|
||||||
|
void decrement()
|
||||||
|
{
|
||||||
|
if (m_refCount.fetch_sub(1) == 1)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class SubCls>
|
||||||
|
class ObjToken;
|
||||||
|
|
||||||
|
template<class SubCls>
|
||||||
|
class ObjWrapper : IObj
|
||||||
|
{
|
||||||
|
friend class ObjToken<SubCls>;
|
||||||
|
SubCls m_obj;
|
||||||
|
SubCls* get() { return &m_obj; }
|
||||||
|
const SubCls* get() const { return &m_obj; }
|
||||||
|
public:
|
||||||
|
template <class... _Args>
|
||||||
|
ObjWrapper(_Args&&... args) : m_obj(std::forward<_Args>(args)...) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class SubCls>
|
||||||
|
class ObjToken
|
||||||
|
{
|
||||||
|
ObjWrapper<SubCls>* m_obj = nullptr;
|
||||||
|
public:
|
||||||
|
ObjToken() = default;
|
||||||
|
ObjToken(ObjWrapper<SubCls>* obj) : m_obj(obj) { if (m_obj) m_obj->increment(); }
|
||||||
|
ObjToken(const ObjToken& other) : m_obj(other.m_obj) { if (m_obj) m_obj->increment(); }
|
||||||
|
ObjToken(ObjToken&& other) : m_obj(other.m_obj) { other.m_obj = nullptr; }
|
||||||
|
ObjToken& operator=(ObjWrapper<SubCls>* obj)
|
||||||
|
{ if (m_obj) m_obj->decrement(); m_obj = obj; if (m_obj) m_obj->increment(); return *this; }
|
||||||
|
ObjToken& operator=(const ObjToken& other)
|
||||||
|
{ if (m_obj) m_obj->decrement(); m_obj = other.m_obj; if (m_obj) m_obj->increment(); return *this; }
|
||||||
|
ObjToken& operator=(ObjToken&& other)
|
||||||
|
{ if (m_obj) m_obj->decrement(); m_obj = other.m_obj; other.m_obj = nullptr; return *this; }
|
||||||
|
~ObjToken() { if (m_obj) m_obj->decrement(); }
|
||||||
|
SubCls* get() const { return m_obj->get(); }
|
||||||
|
SubCls* operator->() const { return m_obj->get(); }
|
||||||
|
SubCls& operator*() const { return *m_obj->get(); }
|
||||||
|
operator bool() const { return m_obj != nullptr; }
|
||||||
|
void reset() { if (m_obj) m_obj->decrement(); m_obj = nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Tp, class... _Args>
|
||||||
|
static inline ObjToken<Tp> MakeObj(_Args&&... args)
|
||||||
|
{
|
||||||
|
return new ObjWrapper<Tp>(std::forward<_Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef PRISize
|
#ifndef PRISize
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define PRISize "Iu"
|
#define PRISize "Iu"
|
||||||
|
@ -480,6 +539,12 @@ DECL_ID_HASH(LayersId)
|
||||||
DECL_ID_HASH(SongId)
|
DECL_ID_HASH(SongId)
|
||||||
DECL_ID_HASH(SFXId)
|
DECL_ID_HASH(SFXId)
|
||||||
DECL_ID_HASH(GroupId)
|
DECL_ID_HASH(GroupId)
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct hash<amuse::ObjToken<T>>
|
||||||
|
{
|
||||||
|
size_t operator()(const amuse::ObjToken<T>& val) const noexcept { return reinterpret_cast<size_t>(val.get()); }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
|
|
||||||
#include "Entity.hpp"
|
#include "Entity.hpp"
|
||||||
#include "Common.hpp"
|
#include "Common.hpp"
|
||||||
|
#include "Voice.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
class Voice;
|
|
||||||
class Listener;
|
class Listener;
|
||||||
|
|
||||||
using Vector3f = float[3];
|
using Vector3f = float[3];
|
||||||
|
@ -37,7 +37,7 @@ static inline float Normalize(Vector3f& out)
|
||||||
/** Voice wrapper with positional-3D level control */
|
/** Voice wrapper with positional-3D level control */
|
||||||
class Emitter : public Entity
|
class Emitter : public Entity
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> m_vox;
|
ObjToken<Voice> m_vox;
|
||||||
Vector3f m_pos = {};
|
Vector3f m_pos = {};
|
||||||
Vector3f m_dir = {};
|
Vector3f m_dir = {};
|
||||||
float m_maxDist;
|
float m_maxDist;
|
||||||
|
@ -54,13 +54,13 @@ class Emitter : public Entity
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Emitter();
|
~Emitter();
|
||||||
Emitter(Engine& engine, const AudioGroup& group, const std::shared_ptr<Voice>& vox,
|
Emitter(Engine& engine, const AudioGroup& group, ObjToken<Voice> vox,
|
||||||
float maxDist, float minVol, float falloff, bool doppler);
|
float maxDist, float minVol, float falloff, bool doppler);
|
||||||
|
|
||||||
void setVectors(const float* pos, const float* dir);
|
void setVectors(const float* pos, const float* dir);
|
||||||
void setMaxVol(float maxVol) { m_maxVol = clamp(0.f, maxVol, 1.f); m_dirty = true; }
|
void setMaxVol(float maxVol) { m_maxVol = clamp(0.f, maxVol, 1.f); m_dirty = true; }
|
||||||
|
|
||||||
const std::shared_ptr<Voice>& getVoice() const { return m_vox; }
|
ObjToken<Voice> getVoice() const { return m_vox; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,13 +42,12 @@ class Engine
|
||||||
AmplitudeMode m_ampMode;
|
AmplitudeMode m_ampMode;
|
||||||
std::unique_ptr<IMIDIReader> m_midiReader;
|
std::unique_ptr<IMIDIReader> m_midiReader;
|
||||||
std::unordered_map<const AudioGroupData*, std::unique_ptr<AudioGroup>> m_audioGroups;
|
std::unordered_map<const AudioGroupData*, std::unique_ptr<AudioGroup>> m_audioGroups;
|
||||||
std::list<std::shared_ptr<Voice>> m_activeVoices;
|
std::list<ObjToken<Voice>> m_activeVoices;
|
||||||
std::list<std::shared_ptr<Emitter>> m_activeEmitters;
|
std::list<ObjToken<Emitter>> m_activeEmitters;
|
||||||
std::list<std::shared_ptr<Listener>> m_activeListeners;
|
std::list<ObjToken<Listener>> m_activeListeners;
|
||||||
std::list<std::shared_ptr<Sequencer>> m_activeSequencers;
|
std::list<ObjToken<Sequencer>> m_activeSequencers;
|
||||||
std::list<std::weak_ptr<Studio>> m_activeStudios; /* lifetime dependent on contributing audio entities */
|
|
||||||
bool m_defaultStudioReady = false;
|
bool m_defaultStudioReady = false;
|
||||||
std::shared_ptr<Studio> m_defaultStudio;
|
ObjToken<Studio> m_defaultStudio;
|
||||||
std::unordered_map<SFXId, std::tuple<AudioGroup*, int, const SFXGroupIndex::SFXEntry*>> m_sfxLookup;
|
std::unordered_map<SFXId, std::tuple<AudioGroup*, int, const SFXGroupIndex::SFXEntry*>> m_sfxLookup;
|
||||||
std::linear_congruential_engine<uint32_t, 0x41c64e6d, 0x3039, UINT32_MAX> m_random;
|
std::linear_congruential_engine<uint32_t, 0x41c64e6d, 0x3039, UINT32_MAX> m_random;
|
||||||
int m_nextVid = 0;
|
int m_nextVid = 0;
|
||||||
|
@ -59,15 +58,14 @@ class Engine
|
||||||
std::pair<AudioGroup*, const SongGroupIndex*> _findSongGroup(int groupId) const;
|
std::pair<AudioGroup*, const SongGroupIndex*> _findSongGroup(int groupId) const;
|
||||||
std::pair<AudioGroup*, const SFXGroupIndex*> _findSFXGroup(int groupId) const;
|
std::pair<AudioGroup*, const SFXGroupIndex*> _findSFXGroup(int groupId) const;
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator _allocateVoice(const AudioGroup& group, int groupId, double sampleRate,
|
std::list<ObjToken<Voice>>::iterator _allocateVoice(const AudioGroup& group, int groupId, double sampleRate,
|
||||||
bool dynamicPitch, bool emitter,
|
bool dynamicPitch, bool emitter, ObjToken<Studio> studio);
|
||||||
std::weak_ptr<Studio> studio);
|
std::list<ObjToken<Sequencer>>::iterator _allocateSequencer(const AudioGroup& group, int groupId,
|
||||||
std::list<std::shared_ptr<Sequencer>>::iterator _allocateSequencer(const AudioGroup& group, int groupId,
|
int setupId, ObjToken<Studio> studio);
|
||||||
int setupId, std::weak_ptr<Studio> studio);
|
ObjToken<Studio> _allocateStudio(bool mainOut);
|
||||||
std::shared_ptr<Studio> _allocateStudio(bool mainOut);
|
std::list<ObjToken<Voice>>::iterator _destroyVoice(std::list<ObjToken<Voice>>::iterator it);
|
||||||
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it);
|
std::list<ObjToken<Sequencer>>::iterator
|
||||||
std::list<std::shared_ptr<Sequencer>>::iterator
|
_destroySequencer(std::list<ObjToken<Sequencer>>::iterator it);
|
||||||
_destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it);
|
|
||||||
void _bringOutYourDead();
|
void _bringOutYourDead();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -84,48 +82,46 @@ public:
|
||||||
void removeAudioGroup(const AudioGroupData& data);
|
void removeAudioGroup(const AudioGroupData& data);
|
||||||
|
|
||||||
/** Access engine's default studio */
|
/** Access engine's default studio */
|
||||||
std::shared_ptr<Studio> getDefaultStudio() { return m_defaultStudio; }
|
ObjToken<Studio> getDefaultStudio() { return m_defaultStudio; }
|
||||||
|
|
||||||
/** Create new Studio within engine */
|
/** Create new Studio within engine */
|
||||||
std::shared_ptr<Studio> addStudio(bool mainOut);
|
ObjToken<Studio> addStudio(bool mainOut);
|
||||||
|
|
||||||
/** Start soundFX playing from loaded audio groups */
|
/** Start soundFX playing from loaded audio groups */
|
||||||
std::shared_ptr<Voice> fxStart(int sfxId, float vol, float pan, std::weak_ptr<Studio> smx);
|
ObjToken<Voice> fxStart(int sfxId, float vol, float pan, ObjToken<Studio> smx);
|
||||||
std::shared_ptr<Voice> fxStart(int sfxId, float vol, float pan)
|
ObjToken<Voice> fxStart(int sfxId, float vol, float pan)
|
||||||
{
|
{
|
||||||
return fxStart(sfxId, vol, pan, m_defaultStudio);
|
return fxStart(sfxId, vol, pan, m_defaultStudio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start SoundMacro node playing directly (for editor use) */
|
/** Start SoundMacro node playing directly (for editor use) */
|
||||||
std::shared_ptr<Voice> macroStart(const AudioGroup* group, SoundMacroId id, uint8_t key,
|
ObjToken<Voice> macroStart(const AudioGroup* group, SoundMacroId id, uint8_t key,
|
||||||
uint8_t vel, uint8_t mod, std::weak_ptr<Studio> smx);
|
uint8_t vel, uint8_t mod, ObjToken<Studio> smx);
|
||||||
std::shared_ptr<Voice> macroStart(const AudioGroup* group, SoundMacroId id, uint8_t key,
|
ObjToken<Voice> macroStart(const AudioGroup* group, SoundMacroId id, uint8_t key,
|
||||||
uint8_t vel, uint8_t mod)
|
uint8_t vel, uint8_t mod)
|
||||||
{
|
{
|
||||||
return macroStart(group, id, key, vel, mod, m_defaultStudio);
|
return macroStart(group, id, key, vel, mod, m_defaultStudio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
||||||
std::shared_ptr<Emitter> addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
|
ObjToken<Emitter> addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
|
||||||
int sfxId, float minVol, float maxVol, bool doppler,
|
int sfxId, float minVol, float maxVol, bool doppler, ObjToken<Studio> smx);
|
||||||
std::weak_ptr<Studio> smx);
|
ObjToken<Emitter> addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
|
||||||
std::shared_ptr<Emitter> addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
|
|
||||||
int sfxId, float minVol, float maxVol, bool doppler)
|
int sfxId, float minVol, float maxVol, bool doppler)
|
||||||
{
|
{
|
||||||
return addEmitter(pos, dir, maxDist, falloff, sfxId, minVol, maxVol, doppler, m_defaultStudio);
|
return addEmitter(pos, dir, maxDist, falloff, sfxId, minVol, maxVol, doppler, m_defaultStudio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build listener and add to engine's listener list */
|
/** Build listener and add to engine's listener list */
|
||||||
std::shared_ptr<Listener> addListener(const float* pos, const float* dir, const float* heading, const float* up,
|
ObjToken<Listener> addListener(const float* pos, const float* dir, const float* heading, const float* up,
|
||||||
float frontDiff, float backDiff, float soundSpeed, float volume);
|
float frontDiff, float backDiff, float soundSpeed, float volume);
|
||||||
|
|
||||||
/** Remove listener from engine's listener list */
|
/** Remove listener from engine's listener list */
|
||||||
void removeListener(Listener* listener);
|
void removeListener(Listener* listener);
|
||||||
|
|
||||||
/** Start song playing from loaded audio groups */
|
/** Start song playing from loaded audio groups */
|
||||||
std::shared_ptr<Sequencer> seqPlay(int groupId, int songId, const unsigned char* arrData,
|
ObjToken<Sequencer> seqPlay(int groupId, int songId, const unsigned char* arrData, ObjToken<Studio> smx);
|
||||||
std::weak_ptr<Studio> smx);
|
ObjToken<Sequencer> seqPlay(int groupId, int songId, const unsigned char* arrData)
|
||||||
std::shared_ptr<Sequencer> seqPlay(int groupId, int songId, const unsigned char* arrData)
|
|
||||||
{
|
{
|
||||||
return seqPlay(groupId, songId, arrData, m_defaultStudio);
|
return seqPlay(groupId, songId, arrData, m_defaultStudio);
|
||||||
}
|
}
|
||||||
|
@ -134,7 +130,7 @@ public:
|
||||||
void setVolume(float vol);
|
void setVolume(float vol);
|
||||||
|
|
||||||
/** Find voice from VoiceId */
|
/** Find voice from VoiceId */
|
||||||
std::shared_ptr<Voice> findVoice(int vid);
|
ObjToken<Voice> findVoice(int vid);
|
||||||
|
|
||||||
/** Stop all voices in `kg`, stops immediately (no KeyOff) when `now` set */
|
/** Stop all voices in `kg`, stops immediately (no KeyOff) when `now` set */
|
||||||
void killKeygroup(uint8_t kg, bool now);
|
void killKeygroup(uint8_t kg, bool now);
|
||||||
|
@ -146,10 +142,10 @@ public:
|
||||||
uint32_t nextRandom() { return m_random(); }
|
uint32_t nextRandom() { return m_random(); }
|
||||||
|
|
||||||
/** Obtain list of active voices */
|
/** Obtain list of active voices */
|
||||||
std::list<std::shared_ptr<Voice>>& getActiveVoices() { return m_activeVoices; }
|
std::list<ObjToken<Voice>>& getActiveVoices() { return m_activeVoices; }
|
||||||
|
|
||||||
/** Obtain list of active sequencers */
|
/** Obtain list of active sequencers */
|
||||||
std::list<std::shared_ptr<Sequencer>>& getActiveSequencers() { return m_activeSequencers; }
|
std::list<ObjToken<Sequencer>>& getActiveSequencers() { return m_activeSequencers; }
|
||||||
|
|
||||||
/** All mixing occurs in virtual 5ms intervals;
|
/** All mixing occurs in virtual 5ms intervals;
|
||||||
* this is called at the start of each interval for all mixable entities */
|
* this is called at the start of each interval for all mixable entities */
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
const AudioGroup& getAudioGroup() const { return m_audioGroup; }
|
const AudioGroup& getAudioGroup() const { return m_audioGroup; }
|
||||||
int getGroupId() const { return m_groupId; }
|
int getGroupId() const { return m_groupId; }
|
||||||
ObjectId getObjectId() const { return m_objectId; }
|
ObjectId getObjectId() const { return m_objectId; }
|
||||||
|
bool isDestroyed() const { return m_destroyed; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "Entity.hpp"
|
#include "Entity.hpp"
|
||||||
#include "AudioGroupProject.hpp"
|
#include "AudioGroupProject.hpp"
|
||||||
#include "SongState.hpp"
|
#include "SongState.hpp"
|
||||||
|
#include "Studio.hpp"
|
||||||
|
#include "Voice.hpp"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -11,8 +13,6 @@
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
class Studio;
|
|
||||||
class Voice;
|
|
||||||
|
|
||||||
/** State of sequencer over lifetime */
|
/** State of sequencer over lifetime */
|
||||||
enum class SequencerState
|
enum class SequencerState
|
||||||
|
@ -30,7 +30,7 @@ class Sequencer : public Entity
|
||||||
const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup (may be null) */
|
const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup (may be null) */
|
||||||
const SFXGroupIndex* m_sfxGroup = nullptr; /**< SFX Groups are alternatively referenced here */
|
const SFXGroupIndex* m_sfxGroup = nullptr; /**< SFX Groups are alternatively referenced here */
|
||||||
std::vector<const SFXGroupIndex::SFXEntry*> m_sfxMappings; /**< SFX entries are mapped to MIDI keys this via this */
|
std::vector<const SFXGroupIndex::SFXEntry*> m_sfxMappings; /**< SFX entries are mapped to MIDI keys this via this */
|
||||||
std::shared_ptr<Studio> m_studio; /**< Studio this sequencer outputs to */
|
ObjToken<Studio> m_studio; /**< Studio this sequencer outputs to */
|
||||||
|
|
||||||
const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */
|
const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */
|
||||||
SongState m_songState; /**< State of current arrangement playback */
|
SongState m_songState; /**< State of current arrangement playback */
|
||||||
|
@ -58,9 +58,9 @@ class Sequencer : public Entity
|
||||||
operator bool() const { return m_parent != nullptr; }
|
operator bool() const { return m_parent != nullptr; }
|
||||||
|
|
||||||
/** Voices corresponding to currently-pressed keys in channel */
|
/** Voices corresponding to currently-pressed keys in channel */
|
||||||
std::unordered_map<uint8_t, std::shared_ptr<Voice>> m_chanVoxs;
|
std::unordered_map<uint8_t, ObjToken<Voice>> m_chanVoxs;
|
||||||
std::unordered_set<std::shared_ptr<Voice>> m_keyoffVoxs;
|
std::unordered_set<ObjToken<Voice>> m_keyoffVoxs;
|
||||||
std::weak_ptr<Voice> m_lastVoice;
|
ObjToken<Voice> m_lastVoice;
|
||||||
int8_t m_ctrlVals[128] = {}; /**< MIDI controller values */
|
int8_t m_ctrlVals[128] = {}; /**< MIDI controller values */
|
||||||
float m_curPitchWheel = 0.f; /**< MIDI pitch-wheel */
|
float m_curPitchWheel = 0.f; /**< MIDI pitch-wheel */
|
||||||
int8_t m_curProgram = 0; /**< MIDI program number */
|
int8_t m_curProgram = 0; /**< MIDI program number */
|
||||||
|
@ -69,7 +69,7 @@ class Sequencer : public Entity
|
||||||
|
|
||||||
void _bringOutYourDead();
|
void _bringOutYourDead();
|
||||||
size_t getVoiceCount() const;
|
size_t getVoiceCount() const;
|
||||||
std::shared_ptr<Voice> keyOn(uint8_t note, uint8_t velocity);
|
ObjToken<Voice> keyOn(uint8_t note, uint8_t velocity);
|
||||||
void keyOff(uint8_t note, uint8_t velocity);
|
void keyOff(uint8_t note, uint8_t velocity);
|
||||||
void setCtrlValue(uint8_t ctrl, int8_t val);
|
void setCtrlValue(uint8_t ctrl, int8_t val);
|
||||||
bool programChange(int8_t prog);
|
bool programChange(int8_t prog);
|
||||||
|
@ -80,7 +80,7 @@ class Sequencer : public Entity
|
||||||
void setPan(float pan);
|
void setPan(float pan);
|
||||||
void allOff();
|
void allOff();
|
||||||
void killKeygroup(uint8_t kg, bool now);
|
void killKeygroup(uint8_t kg, bool now);
|
||||||
std::shared_ptr<Voice> findVoice(int vid);
|
ObjToken<Voice> findVoice(int vid);
|
||||||
void sendMacroMessage(ObjectId macroId, int32_t val);
|
void sendMacroMessage(ObjectId macroId, int32_t val);
|
||||||
};
|
};
|
||||||
std::array<ChannelState, 16> m_chanStates; /**< Lazily-allocated channel states */
|
std::array<ChannelState, 16> m_chanStates; /**< Lazily-allocated channel states */
|
||||||
|
@ -91,15 +91,15 @@ class Sequencer : public Entity
|
||||||
public:
|
public:
|
||||||
~Sequencer();
|
~Sequencer();
|
||||||
Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SongGroupIndex* songGroup, int setupId,
|
Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SongGroupIndex* songGroup, int setupId,
|
||||||
std::weak_ptr<Studio> studio);
|
ObjToken<Studio> studio);
|
||||||
Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SFXGroupIndex* sfxGroup,
|
Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SFXGroupIndex* sfxGroup,
|
||||||
std::weak_ptr<Studio> studio);
|
ObjToken<Studio> studio);
|
||||||
|
|
||||||
/** Advance current song data (if any) */
|
/** Advance current song data (if any) */
|
||||||
void advance(double dt);
|
void advance(double dt);
|
||||||
|
|
||||||
/** Obtain pointer to Sequencer's Submix */
|
/** Obtain pointer to Sequencer's Submix */
|
||||||
std::shared_ptr<Studio> getStudio() { return m_studio; }
|
ObjToken<Studio> getStudio() { return m_studio; }
|
||||||
|
|
||||||
/** Get current state of sequencer */
|
/** Get current state of sequencer */
|
||||||
SequencerState state() const { return m_state; }
|
SequencerState state() const { return m_state; }
|
||||||
|
@ -108,7 +108,7 @@ public:
|
||||||
size_t getVoiceCount() const;
|
size_t getVoiceCount() const;
|
||||||
|
|
||||||
/** Register key press with voice set */
|
/** Register key press with voice set */
|
||||||
std::shared_ptr<Voice> keyOn(uint8_t chan, uint8_t note, uint8_t velocity);
|
ObjToken<Voice> keyOn(uint8_t chan, uint8_t note, uint8_t velocity);
|
||||||
|
|
||||||
/** Register key release with voice set */
|
/** Register key release with voice set */
|
||||||
void keyOff(uint8_t chan, uint8_t note, uint8_t velocity);
|
void keyOff(uint8_t chan, uint8_t note, uint8_t velocity);
|
||||||
|
@ -129,7 +129,7 @@ public:
|
||||||
void killKeygroup(uint8_t kg, bool now);
|
void killKeygroup(uint8_t kg, bool now);
|
||||||
|
|
||||||
/** Find voice instance contained within Sequencer */
|
/** Find voice instance contained within Sequencer */
|
||||||
std::shared_ptr<Voice> findVoice(int vid);
|
ObjToken<Voice> findVoice(int vid);
|
||||||
|
|
||||||
/** Send all voices using `macroId` the message `val` */
|
/** Send all voices using `macroId` the message `val` */
|
||||||
void sendMacroMessage(ObjectId macroId, int32_t val);
|
void sendMacroMessage(ObjectId macroId, int32_t val);
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include "Entity.hpp"
|
#include "Entity.hpp"
|
||||||
#include "Voice.hpp"
|
|
||||||
#include "Submix.hpp"
|
#include "Submix.hpp"
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
@ -20,11 +19,11 @@ class Studio
|
||||||
Submix m_auxB;
|
Submix m_auxB;
|
||||||
struct StudioSend
|
struct StudioSend
|
||||||
{
|
{
|
||||||
std::shared_ptr<Studio> m_targetStudio;
|
ObjToken<Studio> m_targetStudio;
|
||||||
float m_dryLevel;
|
float m_dryLevel;
|
||||||
float m_auxALevel;
|
float m_auxALevel;
|
||||||
float m_auxBLevel;
|
float m_auxBLevel;
|
||||||
StudioSend(std::weak_ptr<Studio> studio, float dry, float auxA, float auxB)
|
StudioSend(ObjToken<Studio> studio, float dry, float auxA, float auxB)
|
||||||
: m_targetStudio(studio), m_dryLevel(dry), m_auxALevel(auxA), m_auxBLevel(auxB)
|
: m_targetStudio(studio), m_dryLevel(dry), m_auxALevel(auxA), m_auxBLevel(auxB)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -38,7 +37,7 @@ public:
|
||||||
Studio(Engine& engine, bool mainOut);
|
Studio(Engine& engine, bool mainOut);
|
||||||
|
|
||||||
/** Register a target Studio to send this Studio's mixing busses */
|
/** Register a target Studio to send this Studio's mixing busses */
|
||||||
void addStudioSend(std::weak_ptr<Studio> studio, float dry, float auxA, float auxB);
|
void addStudioSend(ObjToken<Studio> studio, float dry, float auxA, float auxB);
|
||||||
|
|
||||||
/** Advise submixes of changing sample rate */
|
/** Advise submixes of changing sample rate */
|
||||||
void resetOutputSampleRate(double sampleRate);
|
void resetOutputSampleRate(double sampleRate);
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
#include "AudioGroupSampleDirectory.hpp"
|
#include "AudioGroupSampleDirectory.hpp"
|
||||||
#include "AudioGroup.hpp"
|
#include "AudioGroup.hpp"
|
||||||
#include "Envelope.hpp"
|
#include "Envelope.hpp"
|
||||||
|
#include "Studio.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
class IBackendVoice;
|
class IBackendVoice;
|
||||||
class Studio;
|
|
||||||
struct Keymap;
|
struct Keymap;
|
||||||
struct LayerMapping;
|
struct LayerMapping;
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class Voice : public Entity
|
||||||
|
|
||||||
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 */
|
ObjToken<Studio> m_studio; /**< Studio this voice outputs to */
|
||||||
|
|
||||||
std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */
|
std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */
|
||||||
SoundMacroState m_state; /**< State container for SoundMacro playback */
|
SoundMacroState m_state; /**< State container for SoundMacro playback */
|
||||||
|
@ -55,10 +55,10 @@ class Voice : public Entity
|
||||||
SoundMacroState::EventTrap m_sampleEndTrap; /**< Trap for sampleend (SoundMacro overrides voice removal) */
|
SoundMacroState::EventTrap m_sampleEndTrap; /**< Trap for sampleend (SoundMacro overrides voice removal) */
|
||||||
SoundMacroState::EventTrap m_messageTrap; /**< Trap for messages sent from other SoundMacros */
|
SoundMacroState::EventTrap m_messageTrap; /**< Trap for messages sent from other SoundMacros */
|
||||||
int32_t m_latestMessage = 0; /**< Latest message received on voice */
|
int32_t m_latestMessage = 0; /**< Latest message received on voice */
|
||||||
std::list<std::shared_ptr<Voice>> m_childVoices; /**< Child voices for PLAYMACRO usage */
|
std::list<ObjToken<Voice>> m_childVoices; /**< Child voices for PLAYMACRO usage */
|
||||||
uint8_t m_keygroup = 0; /**< Keygroup voice is a member of */
|
uint8_t m_keygroup = 0; /**< Keygroup voice is a member of */
|
||||||
|
|
||||||
const AudioGroupSampleDirectory::Entry* m_curSample = nullptr; /**< Current sample entry playing */
|
ObjToken<SampleEntryData> m_curSample; /**< Current sample entry playing */
|
||||||
const unsigned char* m_curSampleData = nullptr; /**< Current sample data playing */
|
const unsigned char* m_curSampleData = nullptr; /**< Current sample data playing */
|
||||||
SampleFormat m_curFormat; /**< Current sample format playing */
|
SampleFormat m_curFormat; /**< Current sample format playing */
|
||||||
uint32_t m_curSamplePos = 0; /**< Current sample position */
|
uint32_t m_curSamplePos = 0; /**< Current sample position */
|
||||||
|
@ -82,9 +82,7 @@ class Voice : public Entity
|
||||||
float m_curVol = 1.f; /**< Current volume of voice */
|
float m_curVol = 1.f; /**< Current volume of voice */
|
||||||
float m_curReverbVol = 0.f; /**< Current reverb volume of voice */
|
float m_curReverbVol = 0.f; /**< Current reverb volume of voice */
|
||||||
float m_curAuxBVol = 0.f; /**< Current AuxB volume of voice */
|
float m_curAuxBVol = 0.f; /**< Current AuxB volume of voice */
|
||||||
float m_userPan = 0.f; /**< User pan of voice */
|
|
||||||
float m_curPan = 0.f; /**< Current pan of voice */
|
float m_curPan = 0.f; /**< Current pan of voice */
|
||||||
float m_userSpan = -1.f; /**< User span of voice */
|
|
||||||
float m_curSpan = -1.f; /**< Current surround pan of voice */
|
float m_curSpan = -1.f; /**< Current surround pan of voice */
|
||||||
float m_curPitchWheel = 0.f; /**< Current normalized wheel value for control */
|
float m_curPitchWheel = 0.f; /**< Current normalized wheel value for control */
|
||||||
int32_t m_pitchWheelUp = 600; /**< Up range for pitchwheel control in cents */
|
int32_t m_pitchWheelUp = 600; /**< Up range for pitchwheel control in cents */
|
||||||
|
@ -156,11 +154,11 @@ class Voice : public Entity
|
||||||
bool _isRecursivelyDead();
|
bool _isRecursivelyDead();
|
||||||
void _bringOutYourDead();
|
void _bringOutYourDead();
|
||||||
static uint32_t _GetBlockSampleCount(SampleFormat fmt);
|
static uint32_t _GetBlockSampleCount(SampleFormat fmt);
|
||||||
std::shared_ptr<Voice> _findVoice(int vid, std::weak_ptr<Voice> thisPtr);
|
ObjToken<Voice> _findVoice(int vid, ObjToken<Voice> thisPtr);
|
||||||
std::unique_ptr<int8_t[]>& _ensureCtrlVals();
|
std::unique_ptr<int8_t[]>& _ensureCtrlVals();
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator _allocateVoice(double sampleRate, bool dynamicPitch);
|
std::list<ObjToken<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<ObjToken<Voice>>::iterator _destroyVoice(std::list<ObjToken<Voice>>::iterator it);
|
||||||
|
|
||||||
bool _loadSoundMacro(SoundMacroId id, const SoundMacro* macroData, int macroStep, double ticksPerSec,
|
bool _loadSoundMacro(SoundMacroId id, const SoundMacro* macroData, int macroStep, double ticksPerSec,
|
||||||
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
||||||
|
@ -168,7 +166,7 @@ class Voice : public Entity
|
||||||
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
||||||
bool _loadLayer(const std::vector<LayerMapping>& layer, double ticksPerSec,
|
bool _loadLayer(const std::vector<LayerMapping>& layer, double ticksPerSec,
|
||||||
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
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,
|
ObjToken<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);
|
||||||
|
|
||||||
void _panLaw(float coefsOut[8], float frontPan, float backPan, float totalSpan) const;
|
void _panLaw(float coefsOut[8], float frontPan, float backPan, float totalSpan) const;
|
||||||
|
@ -180,9 +178,9 @@ class Voice : public Entity
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Voice();
|
~Voice();
|
||||||
Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, std::weak_ptr<Studio> studio);
|
Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, ObjToken<Studio> studio);
|
||||||
Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter,
|
Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter,
|
||||||
std::weak_ptr<Studio> studio);
|
ObjToken<Studio> studio);
|
||||||
|
|
||||||
/** Called before each supplyAudio invocation to prepare voice
|
/** Called before each supplyAudio invocation to prepare voice
|
||||||
* backend for possible parameter updates */
|
* backend for possible parameter updates */
|
||||||
|
@ -199,7 +197,7 @@ public:
|
||||||
void routeAudio(size_t frames, double dt, int busId, float* in, float* out);
|
void routeAudio(size_t frames, double dt, int busId, float* in, float* out);
|
||||||
|
|
||||||
/** Obtain pointer to Voice's Studio */
|
/** Obtain pointer to Voice's Studio */
|
||||||
std::shared_ptr<Studio> getStudio() { return m_studio; }
|
ObjToken<Studio> getStudio() { return m_studio; }
|
||||||
|
|
||||||
/** Get current state of voice */
|
/** Get current state of voice */
|
||||||
VoiceState state() const { return m_voxState; }
|
VoiceState state() const { return m_voxState; }
|
||||||
|
@ -211,7 +209,7 @@ public:
|
||||||
int maxVid() const;
|
int maxVid() const;
|
||||||
|
|
||||||
/** Allocate parallel macro and tie to voice for possible emitter influence */
|
/** Allocate parallel macro and tie to voice for possible emitter influence */
|
||||||
std::shared_ptr<Voice> startChildMacro(int8_t addNote, ObjectId macroId, int macroStep);
|
ObjToken<Voice> startChildMacro(int8_t addNote, ObjectId macroId, int macroStep);
|
||||||
|
|
||||||
/** Load specified SoundMacro Object from within group into voice */
|
/** Load specified SoundMacro Object from within group into voice */
|
||||||
bool loadMacroObject(SoundMacroId macroId, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
|
bool loadMacroObject(SoundMacroId macroId, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
|
||||||
|
|
|
@ -21,17 +21,18 @@ void AudioGroup::assign(SystemStringView groupPath)
|
||||||
m_samp = nullptr;
|
m_samp = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AudioGroupSampleDirectory::Entry* AudioGroup::getSample(SampleId sfxId) const
|
const SampleEntry* AudioGroup::getSample(SampleId sfxId) const
|
||||||
{
|
{
|
||||||
auto search = m_sdir.m_entries.find(sfxId);
|
auto search = m_sdir.m_entries.find(sfxId);
|
||||||
if (search == m_sdir.m_entries.cend())
|
if (search == m_sdir.m_entries.cend())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return &search->second;
|
return search->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char* AudioGroup::getSampleData(SampleId sfxId, const AudioGroupSampleDirectory::Entry* sample) const
|
std::pair<ObjToken<SampleEntryData>, const unsigned char*>
|
||||||
|
AudioGroup::getSampleData(SampleId sfxId, const SampleEntry* sample) const
|
||||||
{
|
{
|
||||||
if (sample->m_looseData)
|
if (sample->m_data->m_looseData)
|
||||||
{
|
{
|
||||||
setIdDatabases();
|
setIdDatabases();
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
|
@ -41,9 +42,9 @@ const unsigned char* AudioGroup::getSampleData(SampleId sfxId, const AudioGroupS
|
||||||
SystemString basePath = m_groupPath + _S('/') +
|
SystemString basePath = m_groupPath + _S('/') +
|
||||||
SampleId::CurNameDB->resolveNameFromId(sfxId).data();
|
SampleId::CurNameDB->resolveNameFromId(sfxId).data();
|
||||||
#endif
|
#endif
|
||||||
const_cast<AudioGroupSampleDirectory::Entry*>(sample)->loadLooseData(basePath);
|
const_cast<SampleEntry*>(sample)->loadLooseData(basePath);
|
||||||
return sample->m_looseData.get();
|
return {sample->m_data, sample->m_data->m_looseData.get()};
|
||||||
}
|
}
|
||||||
return m_samp + sample->m_sampleOff;
|
return {{}, m_samp + sample->m_data->m_sampleOff};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
|
||||||
atInt64 startPos = r.position();
|
atInt64 startPos = r.position();
|
||||||
objHead.read(r);
|
objHead.read(r);
|
||||||
auto& macro = ret.m_soundMacros[objHead.objectId.id];
|
auto& macro = ret.m_soundMacros[objHead.objectId.id];
|
||||||
macro = std::make_shared<SoundMacro>();
|
macro = MakeObj<SoundMacro>();
|
||||||
macro->template readCmds<DNAE>(r, objHead.size - 8);
|
macro->template readCmds<DNAE>(r, objHead.size - 8);
|
||||||
r.seek(startPos + objHead.size, athena::Begin);
|
r.seek(startPos + objHead.size, athena::Begin);
|
||||||
}
|
}
|
||||||
|
@ -127,17 +127,17 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
|
||||||
switch (objHead.size)
|
switch (objHead.size)
|
||||||
{
|
{
|
||||||
case 0x10:
|
case 0x10:
|
||||||
ptr = std::make_shared<ADSR>();
|
ptr = MakeObj<std::unique_ptr<ITable>>(std::make_unique<ADSR>());
|
||||||
static_cast<ADSR&>(*ptr).read(r);
|
static_cast<ADSR&>(**ptr).read(r);
|
||||||
break;
|
break;
|
||||||
case 0x1c:
|
case 0x1c:
|
||||||
ptr = std::make_shared<ADSRDLS>();
|
ptr = MakeObj<std::unique_ptr<ITable>>(std::make_unique<ADSRDLS>());
|
||||||
static_cast<ADSRDLS&>(*ptr).read(r);
|
static_cast<ADSRDLS&>(**ptr).read(r);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ptr = std::make_shared<Curve>();
|
ptr = MakeObj<std::unique_ptr<ITable>>(std::make_unique<Curve>());
|
||||||
static_cast<Curve&>(*ptr).data.resize(objHead.size - 8);
|
static_cast<Curve&>(**ptr).data.resize(objHead.size - 8);
|
||||||
r.readUBytesToBuf(&static_cast<Curve&>(*ptr).data[0], objHead.size - 8);
|
r.readUBytesToBuf(&static_cast<Curve&>(**ptr).data[0], objHead.size - 8);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
r.seek(startPos + objHead.size, athena::Begin);
|
r.seek(startPos + objHead.size, athena::Begin);
|
||||||
|
@ -155,7 +155,7 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
|
||||||
KeymapDNA<DNAE> kmData;
|
KeymapDNA<DNAE> kmData;
|
||||||
kmData.read(r);
|
kmData.read(r);
|
||||||
auto& km = ret.m_keymaps[objHead.objectId.id];
|
auto& km = ret.m_keymaps[objHead.objectId.id];
|
||||||
km = std::make_shared<Keymap>(kmData);
|
km = MakeObj<Keymap>(kmData);
|
||||||
r.seek(startPos + objHead.size, athena::Begin);
|
r.seek(startPos + objHead.size, athena::Begin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
|
||||||
atInt64 startPos = r.position();
|
atInt64 startPos = r.position();
|
||||||
objHead.read(r);
|
objHead.read(r);
|
||||||
auto& lm = ret.m_layers[objHead.objectId.id];
|
auto& lm = ret.m_layers[objHead.objectId.id];
|
||||||
lm = std::make_shared<std::vector<LayerMapping>>();
|
lm = MakeObj<std::vector<LayerMapping>>();
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
athena::io::Read<athena::io::PropType::None>::Do<decltype(count), DNAE>({}, count, r);
|
athena::io::Read<athena::io::PropType::None>::Do<decltype(count), DNAE>({}, count, r);
|
||||||
lm->reserve(count);
|
lm->reserve(count);
|
||||||
|
@ -262,7 +262,7 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
for (const auto& sm : r.getCurNode()->m_mapChildren)
|
for (const auto& sm : r.getCurNode()->m_mapChildren)
|
||||||
{
|
{
|
||||||
auto& smOut = ret.m_soundMacros[SoundMacroId::CurNameDB->resolveIdFromName(sm.first)];
|
auto& smOut = ret.m_soundMacros[SoundMacroId::CurNameDB->resolveIdFromName(sm.first)];
|
||||||
smOut = std::make_shared<SoundMacro>();
|
smOut = MakeObj<SoundMacro>();
|
||||||
size_t cmdCount;
|
size_t cmdCount;
|
||||||
if (auto __v = r.enterSubVector(sm.first.c_str(), cmdCount))
|
if (auto __v = r.enterSubVector(sm.first.c_str(), cmdCount))
|
||||||
{
|
{
|
||||||
|
@ -288,20 +288,20 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
if (auto __vta = r.enterSubRecord("velToAttack"))
|
if (auto __vta = r.enterSubRecord("velToAttack"))
|
||||||
{
|
{
|
||||||
__vta.leave();
|
__vta.leave();
|
||||||
tableOut = std::make_shared<ADSRDLS>();
|
tableOut = MakeObj<std::unique_ptr<ITable>>(std::make_unique<ADSRDLS>());
|
||||||
static_cast<ADSRDLS&>(*tableOut).read(r);
|
static_cast<ADSRDLS&>(**tableOut).read(r);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tableOut = std::make_shared<ADSR>();
|
tableOut = MakeObj<std::unique_ptr<ITable>>(std::make_unique<ADSR>());
|
||||||
static_cast<ADSR&>(*tableOut).read(r);
|
static_cast<ADSR&>(**tableOut).read(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (auto __dat = r.enterSubRecord("data"))
|
else if (auto __dat = r.enterSubRecord("data"))
|
||||||
{
|
{
|
||||||
__dat.leave();
|
__dat.leave();
|
||||||
tableOut = std::make_shared<Curve>();
|
tableOut = MakeObj<std::unique_ptr<ITable>>(std::make_unique<Curve>());
|
||||||
static_cast<Curve&>(*tableOut).read(r);
|
static_cast<Curve&>(**tableOut).read(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,7 +314,7 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
if (auto __v = r.enterSubRecord(k.first.c_str()))
|
if (auto __v = r.enterSubRecord(k.first.c_str()))
|
||||||
{
|
{
|
||||||
auto& kmOut = ret.m_keymaps[KeymapId::CurNameDB->resolveIdFromName(k.first)];
|
auto& kmOut = ret.m_keymaps[KeymapId::CurNameDB->resolveIdFromName(k.first)];
|
||||||
kmOut = std::make_shared<Keymap>();
|
kmOut = MakeObj<Keymap>();
|
||||||
kmOut->read(r);
|
kmOut->read(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,7 +328,7 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
if (auto __v = r.enterSubVector(l.first.c_str(), mappingCount))
|
if (auto __v = r.enterSubVector(l.first.c_str(), mappingCount))
|
||||||
{
|
{
|
||||||
auto& layOut = ret.m_layers[LayersId::CurNameDB->resolveIdFromName(l.first)];
|
auto& layOut = ret.m_layers[LayersId::CurNameDB->resolveIdFromName(l.first)];
|
||||||
layOut = std::make_shared<std::vector<LayerMapping>>();
|
layOut = MakeObj<std::vector<LayerMapping>>();
|
||||||
layOut->reserve(mappingCount);
|
layOut->reserve(mappingCount);
|
||||||
for (int lm = 0; lm < mappingCount; ++lm)
|
for (int lm = 0; lm < mappingCount; ++lm)
|
||||||
{
|
{
|
||||||
|
@ -402,25 +402,25 @@ const std::vector<LayerMapping>* AudioGroupPool::layer(ObjectId id) const
|
||||||
const ADSR* AudioGroupPool::tableAsAdsr(ObjectId id) const
|
const ADSR* AudioGroupPool::tableAsAdsr(ObjectId id) const
|
||||||
{
|
{
|
||||||
auto search = m_tables.find(id);
|
auto search = m_tables.find(id);
|
||||||
if (search == m_tables.cend() || search->second->Isa() != ITable::Type::ADSR)
|
if (search == m_tables.cend() || (*search->second)->Isa() != ITable::Type::ADSR)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return static_cast<const ADSR*>(search->second.get());
|
return static_cast<const ADSR*>((*search->second).get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const ADSRDLS* AudioGroupPool::tableAsAdsrDLS(ObjectId id) const
|
const ADSRDLS* AudioGroupPool::tableAsAdsrDLS(ObjectId id) const
|
||||||
{
|
{
|
||||||
auto search = m_tables.find(id);
|
auto search = m_tables.find(id);
|
||||||
if (search == m_tables.cend() || search->second->Isa() != ITable::Type::ADSRDLS)
|
if (search == m_tables.cend() || (*search->second)->Isa() != ITable::Type::ADSRDLS)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return static_cast<const ADSRDLS*>(search->second.get());
|
return static_cast<const ADSRDLS*>((*search->second).get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const Curve* AudioGroupPool::tableAsCurves(ObjectId id) const
|
const Curve* AudioGroupPool::tableAsCurves(ObjectId id) const
|
||||||
{
|
{
|
||||||
auto search = m_tables.find(id);
|
auto search = m_tables.find(id);
|
||||||
if (search == m_tables.cend() || search->second->Isa() != ITable::Type::Curve)
|
if (search == m_tables.cend() || (*search->second)->Isa() != ITable::Type::Curve)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return static_cast<const Curve*>(search->second.get());
|
return static_cast<const Curve*>((*search->second).get());
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoundMacro::CmdOp _ReadCmdOp(athena::io::MemoryReader& r)
|
static SoundMacro::CmdOp _ReadCmdOp(athena::io::MemoryReader& r)
|
||||||
|
@ -979,7 +979,7 @@ bool AudioGroupPool::toYAML(SystemStringView groupPath) const
|
||||||
if (auto __v = w.enterSubRecord(TableId::CurNameDB->resolveNameFromId(p.first).data()))
|
if (auto __v = w.enterSubRecord(TableId::CurNameDB->resolveNameFromId(p.first).data()))
|
||||||
{
|
{
|
||||||
w.setStyle(athena::io::YAMLNodeStyle::Flow);
|
w.setStyle(athena::io::YAMLNodeStyle::Flow);
|
||||||
p.second.get()->write(w);
|
(*p.second.get())->write(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ AudioGroupProject::AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag)
|
||||||
if (header.type == GroupType::Song)
|
if (header.type == GroupType::Song)
|
||||||
{
|
{
|
||||||
auto& idx = m_songGroups[header.groupId];
|
auto& idx = m_songGroups[header.groupId];
|
||||||
idx = std::make_shared<SongGroupIndex>();
|
idx = MakeObj<SongGroupIndex>();
|
||||||
|
|
||||||
/* Normal pages */
|
/* Normal pages */
|
||||||
r.seek(header.pageTableOff, athena::Begin);
|
r.seek(header.pageTableOff, athena::Begin);
|
||||||
|
@ -116,7 +116,7 @@ AudioGroupProject::AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag)
|
||||||
else if (header.type == GroupType::SFX)
|
else if (header.type == GroupType::SFX)
|
||||||
{
|
{
|
||||||
auto& idx = m_sfxGroups[header.groupId];
|
auto& idx = m_sfxGroups[header.groupId];
|
||||||
idx = std::make_shared<SFXGroupIndex>();
|
idx = MakeObj<SFXGroupIndex>();
|
||||||
|
|
||||||
/* SFX entries */
|
/* SFX entries */
|
||||||
r.seek(header.pageTableOff, athena::Begin);
|
r.seek(header.pageTableOff, athena::Begin);
|
||||||
|
@ -179,7 +179,7 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
|
||||||
if (header.type == GroupType::Song)
|
if (header.type == GroupType::Song)
|
||||||
{
|
{
|
||||||
auto& idx = ret.m_songGroups[header.groupId];
|
auto& idx = ret.m_songGroups[header.groupId];
|
||||||
idx = std::make_shared<SongGroupIndex>();
|
idx = MakeObj<SongGroupIndex>();
|
||||||
|
|
||||||
if (absOffs)
|
if (absOffs)
|
||||||
{
|
{
|
||||||
|
@ -255,7 +255,7 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
|
||||||
else if (header.type == GroupType::SFX)
|
else if (header.type == GroupType::SFX)
|
||||||
{
|
{
|
||||||
auto& idx = ret.m_sfxGroups[header.groupId];
|
auto& idx = ret.m_sfxGroups[header.groupId];
|
||||||
idx = std::make_shared<SFXGroupIndex>();
|
idx = MakeObj<SFXGroupIndex>();
|
||||||
|
|
||||||
/* SFX entries */
|
/* SFX entries */
|
||||||
r.seek(subDataOff + header.pageTableOff, athena::Begin);
|
r.seek(subDataOff + header.pageTableOff, athena::Begin);
|
||||||
|
@ -333,7 +333,7 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr
|
||||||
GroupId::CurNameDB->registerPair(groupName, groupId);
|
GroupId::CurNameDB->registerPair(groupName, groupId);
|
||||||
|
|
||||||
auto& idx = ret.m_songGroups[groupId];
|
auto& idx = ret.m_songGroups[groupId];
|
||||||
idx = std::make_shared<SongGroupIndex>();
|
idx = MakeObj<SongGroupIndex>();
|
||||||
if (auto __v2 = r.enterSubRecord("normPages"))
|
if (auto __v2 = r.enterSubRecord("normPages"))
|
||||||
{
|
{
|
||||||
idx->m_normPages.reserve(r.getCurNode()->m_mapChildren.size());
|
idx->m_normPages.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
@ -387,7 +387,7 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr
|
||||||
GroupId::CurNameDB->registerPair(groupName, groupId);
|
GroupId::CurNameDB->registerPair(groupName, groupId);
|
||||||
|
|
||||||
auto& idx = ret.m_sfxGroups[groupId];
|
auto& idx = ret.m_sfxGroups[groupId];
|
||||||
idx = std::make_shared<SFXGroupIndex>();
|
idx = MakeObj<SFXGroupIndex>();
|
||||||
for (const auto& sfx : r.getCurNode()->m_mapChildren)
|
for (const auto& sfx : r.getCurNode()->m_mapChildren)
|
||||||
if (auto __r2 = r.enterSubRecord(sfx.first.c_str()))
|
if (auto __r2 = r.enterSubRecord(sfx.first.c_str()))
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,17 +44,17 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader&
|
||||||
{
|
{
|
||||||
EntryDNA<athena::Big> ent;
|
EntryDNA<athena::Big> ent;
|
||||||
ent.read(r);
|
ent.read(r);
|
||||||
m_entries[ent.m_sfxId] = ent;
|
m_entries[ent.m_sfxId] = MakeObj<Entry>(ent);
|
||||||
SampleId::CurNameDB->registerPair(NameDB::generateName(ent.m_sfxId, NameDB::Type::Sample), ent.m_sfxId);
|
SampleId::CurNameDB->registerPair(NameDB::generateName(ent.m_sfxId, NameDB::Type::Sample), ent.m_sfxId);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& p : m_entries)
|
for (auto& p : m_entries)
|
||||||
{
|
{
|
||||||
if (p.second.m_adpcmParmOffset)
|
if (p.second->m_data->m_adpcmParmOffset)
|
||||||
{
|
{
|
||||||
r.seek(p.second.m_adpcmParmOffset, athena::Begin);
|
r.seek(p.second->m_data->m_adpcmParmOffset, athena::Begin);
|
||||||
r.readUBytesToBuf(&p.second.m_ADPCMParms, sizeof(ADPCMParms::DSPParms));
|
r.readUBytesToBuf(&p.second->m_data->m_ADPCMParms, sizeof(ADPCMParms::DSPParms));
|
||||||
p.second.m_ADPCMParms.swapBigDSP();
|
p.second->m_data->m_ADPCMParms.swapBigDSP();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader&
|
||||||
{
|
{
|
||||||
MusyX1AbsSdirEntry<athena::Big> ent;
|
MusyX1AbsSdirEntry<athena::Big> ent;
|
||||||
ent.read(r);
|
ent.read(r);
|
||||||
m_entries[ent.m_sfxId] = ent;
|
m_entries[ent.m_sfxId] = MakeObj<Entry>(ent);
|
||||||
SampleId::CurNameDB->registerPair(NameDB::generateName(ent.m_sfxId, NameDB::Type::Sample), ent.m_sfxId);
|
SampleId::CurNameDB->registerPair(NameDB::generateName(ent.m_sfxId, NameDB::Type::Sample), ent.m_sfxId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,15 +78,15 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader&
|
||||||
{
|
{
|
||||||
MusyX1SdirEntry<athena::Big> ent;
|
MusyX1SdirEntry<athena::Big> ent;
|
||||||
ent.read(r);
|
ent.read(r);
|
||||||
m_entries[ent.m_sfxId] = ent;
|
m_entries[ent.m_sfxId] = MakeObj<Entry>(ent);
|
||||||
SampleId::CurNameDB->registerPair(NameDB::generateName(ent.m_sfxId, NameDB::Type::Sample), ent.m_sfxId);
|
SampleId::CurNameDB->registerPair(NameDB::generateName(ent.m_sfxId, NameDB::Type::Sample), ent.m_sfxId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& p : m_entries)
|
for (auto& p : m_entries)
|
||||||
{
|
{
|
||||||
memcpy(&p.second.m_ADPCMParms, sampData + p.second.m_sampleOff, sizeof(ADPCMParms::VADPCMParms));
|
memcpy(&p.second->m_data->m_ADPCMParms, sampData + p.second->m_data->m_sampleOff, sizeof(ADPCMParms::VADPCMParms));
|
||||||
p.second.m_ADPCMParms.swapBigVADPCM();
|
p.second->m_data->m_ADPCMParms.swapBigVADPCM();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,9 +98,9 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader&
|
||||||
{
|
{
|
||||||
MusyX1AbsSdirEntry<athena::Little> ent;
|
MusyX1AbsSdirEntry<athena::Little> ent;
|
||||||
ent.read(r);
|
ent.read(r);
|
||||||
Entry& store = m_entries[ent.m_sfxId];
|
auto& store = m_entries[ent.m_sfxId];
|
||||||
store = ent;
|
store = MakeObj<Entry>(ent);
|
||||||
store.m_numSamples |= atUint32(SampleFormat::PCM_PC) << 24;
|
store->m_data->m_numSamples |= atUint32(SampleFormat::PCM_PC) << 24;
|
||||||
SampleId::CurNameDB->registerPair(NameDB::generateName(ent.m_sfxId, NameDB::Type::Sample), ent.m_sfxId);
|
SampleId::CurNameDB->registerPair(NameDB::generateName(ent.m_sfxId, NameDB::Type::Sample), ent.m_sfxId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,9 +110,9 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader&
|
||||||
{
|
{
|
||||||
MusyX1SdirEntry<athena::Little> ent;
|
MusyX1SdirEntry<athena::Little> ent;
|
||||||
ent.read(r);
|
ent.read(r);
|
||||||
Entry& store = m_entries[ent.m_sfxId];
|
auto& store = m_entries[ent.m_sfxId];
|
||||||
store = ent;
|
store = MakeObj<Entry>(ent);
|
||||||
store.m_numSamples |= atUint32(SampleFormat::PCM_PC) << 24;
|
store->m_data->m_numSamples |= atUint32(SampleFormat::PCM_PC) << 24;
|
||||||
SampleId::CurNameDB->registerPair(NameDB::generateName(ent.m_sfxId, NameDB::Type::Sample), ent.m_sfxId);
|
SampleId::CurNameDB->registerPair(NameDB::generateName(ent.m_sfxId, NameDB::Type::Sample), ent.m_sfxId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,30 +149,16 @@ static uint32_t DSPNibbleToSample(uint32_t nibble)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath)
|
void AudioGroupSampleDirectory::EntryData::loadLooseDSP(SystemStringView dspPath)
|
||||||
{
|
{
|
||||||
SystemString wavPath = SystemString(basePath) + _S(".wav");
|
|
||||||
SystemString dspPath = SystemString(basePath) + _S(".dsp");
|
|
||||||
Sstat wavStat, dspStat;
|
|
||||||
bool wavValid = !Stat(wavPath.c_str(), &wavStat) && S_ISREG(wavStat.st_mode);
|
|
||||||
bool dspValid = !Stat(dspPath.c_str(), &dspStat) && S_ISREG(dspStat.st_mode);
|
|
||||||
|
|
||||||
if (wavValid && dspValid)
|
|
||||||
{
|
|
||||||
if (wavStat.st_mtime > dspStat.st_mtime)
|
|
||||||
dspValid = false;
|
|
||||||
else
|
|
||||||
wavValid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dspValid && (!m_looseData || dspStat.st_mtime > m_looseModTime))
|
|
||||||
{
|
|
||||||
athena::io::FileReader r(dspPath);
|
athena::io::FileReader r(dspPath);
|
||||||
if (!r.hasError())
|
if (!r.hasError())
|
||||||
{
|
{
|
||||||
DSPADPCMHeader header;
|
DSPADPCMHeader header;
|
||||||
header.read(r);
|
header.read(r);
|
||||||
m_pitch = header.m_pitch;
|
m_pitch = header.m_pitch;
|
||||||
|
if (m_pitch == 0)
|
||||||
|
m_pitch = 60;
|
||||||
m_sampleRate = atUint16(header.x8_sample_rate);
|
m_sampleRate = atUint16(header.x8_sample_rate);
|
||||||
m_numSamples = header.x0_num_samples;
|
m_numSamples = header.x0_num_samples;
|
||||||
if (header.xc_loop_flag)
|
if (header.xc_loop_flag)
|
||||||
|
@ -191,14 +177,11 @@ void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath)
|
||||||
uint32_t dataLen = (header.x4_num_nibbles + 1) / 2;
|
uint32_t dataLen = (header.x4_num_nibbles + 1) / 2;
|
||||||
m_looseData.reset(new uint8_t[dataLen]);
|
m_looseData.reset(new uint8_t[dataLen]);
|
||||||
r.readUBytesToBuf(m_looseData.get(), dataLen);
|
r.readUBytesToBuf(m_looseData.get(), dataLen);
|
||||||
|
|
||||||
m_looseModTime = dspStat.st_mtime;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (wavValid && (!m_looseData || wavStat.st_mtime > m_looseModTime))
|
void AudioGroupSampleDirectory::EntryData::loadLooseWAV(SystemStringView wavPath)
|
||||||
{
|
{
|
||||||
athena::io::FileReader r(wavPath);
|
athena::io::FileReader r(wavPath);
|
||||||
if (!r.hasError())
|
if (!r.hasError())
|
||||||
{
|
{
|
||||||
|
@ -226,6 +209,8 @@ void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath)
|
||||||
WAVSampleChunk smpl;
|
WAVSampleChunk smpl;
|
||||||
smpl.read(r);
|
smpl.read(r);
|
||||||
m_pitch = atUint8(smpl.midiNote);
|
m_pitch = atUint8(smpl.midiNote);
|
||||||
|
if (m_pitch == 0)
|
||||||
|
m_pitch = 60;
|
||||||
|
|
||||||
if (smpl.numSampleLoops)
|
if (smpl.numSampleLoops)
|
||||||
{
|
{
|
||||||
|
@ -243,10 +228,38 @@ void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath)
|
||||||
}
|
}
|
||||||
r.seek(startPos + chunkSize, athena::Begin);
|
r.seek(startPos + chunkSize, athena::Begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_looseModTime = wavStat.st_mtime;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath)
|
||||||
|
{
|
||||||
|
SystemString wavPath = SystemString(basePath) + _S(".wav");
|
||||||
|
SystemString dspPath = SystemString(basePath) + _S(".dsp");
|
||||||
|
Sstat wavStat, dspStat;
|
||||||
|
bool wavValid = !Stat(wavPath.c_str(), &wavStat) && S_ISREG(wavStat.st_mode);
|
||||||
|
bool dspValid = !Stat(dspPath.c_str(), &dspStat) && S_ISREG(dspStat.st_mode);
|
||||||
|
|
||||||
|
if (wavValid && dspValid)
|
||||||
|
{
|
||||||
|
if (wavStat.st_mtime > dspStat.st_mtime)
|
||||||
|
dspValid = false;
|
||||||
|
else
|
||||||
|
wavValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntryData& curData = *m_data;
|
||||||
|
|
||||||
|
if (dspValid && (!curData.m_looseData || dspStat.st_mtime > curData.m_looseModTime))
|
||||||
|
{
|
||||||
|
m_data = MakeObj<EntryData>();
|
||||||
|
m_data->loadLooseDSP(dspPath);
|
||||||
|
m_data->m_looseModTime = dspStat.st_mtime;
|
||||||
|
}
|
||||||
|
else if (wavValid && (!curData.m_looseData || wavStat.st_mtime > curData.m_looseModTime))
|
||||||
|
{
|
||||||
|
m_data = MakeObj<EntryData>();
|
||||||
|
m_data->loadLooseWAV(wavPath);
|
||||||
|
m_data->m_looseModTime = wavStat.st_mtime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,15 +286,16 @@ AudioGroupSampleDirectory AudioGroupSampleDirectory::CreateAudioGroupSampleDirec
|
||||||
SampleId::CurNameDB->registerPair(baseName, sampleId);
|
SampleId::CurNameDB->registerPair(baseName, sampleId);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Entry& entry = ret.m_entries[sampleId];
|
auto& entry = ret.m_entries[sampleId];
|
||||||
|
entry = MakeObj<Entry>();
|
||||||
SystemString basePath = SystemString(ent.m_path.begin(), ent.m_path.begin() + ent.m_path.size() - 4);
|
SystemString basePath = SystemString(ent.m_path.begin(), ent.m_path.begin() + ent.m_path.size() - 4);
|
||||||
entry.loadLooseData(basePath);
|
entry->loadLooseData(basePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioGroupSampleDirectory::_extractWAV(SampleId id, const Entry& ent,
|
void AudioGroupSampleDirectory::_extractWAV(SampleId id, const EntryData& ent,
|
||||||
amuse::SystemStringView destDir, const unsigned char* samp)
|
amuse::SystemStringView destDir, const unsigned char* samp)
|
||||||
{
|
{
|
||||||
amuse::SystemString path(destDir);
|
amuse::SystemString path(destDir);
|
||||||
|
@ -389,16 +403,16 @@ void AudioGroupSampleDirectory::extractWAV(SampleId id, amuse::SystemStringView
|
||||||
auto search = m_entries.find(id);
|
auto search = m_entries.find(id);
|
||||||
if (search == m_entries.cend())
|
if (search == m_entries.cend())
|
||||||
return;
|
return;
|
||||||
_extractWAV(id, search->second, destDir, samp);
|
_extractWAV(id, *search->second->m_data, destDir, samp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioGroupSampleDirectory::extractAllWAV(amuse::SystemStringView destDir, const unsigned char* samp) const
|
void AudioGroupSampleDirectory::extractAllWAV(amuse::SystemStringView destDir, const unsigned char* samp) const
|
||||||
{
|
{
|
||||||
for (const auto& ent : m_entries)
|
for (const auto& ent : m_entries)
|
||||||
_extractWAV(ent.first, ent.second, destDir, samp);
|
_extractWAV(ent.first, *ent.second->m_data, destDir, samp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioGroupSampleDirectory::_extractCompressed(SampleId id, const Entry& ent,
|
void AudioGroupSampleDirectory::_extractCompressed(SampleId id, const EntryData& ent,
|
||||||
amuse::SystemStringView destDir, const unsigned char* samp)
|
amuse::SystemStringView destDir, const unsigned char* samp)
|
||||||
{
|
{
|
||||||
SampleFormat fmt = SampleFormat(ent.m_numSamples >> 24);
|
SampleFormat fmt = SampleFormat(ent.m_numSamples >> 24);
|
||||||
|
@ -475,13 +489,46 @@ void AudioGroupSampleDirectory::extractCompressed(SampleId id, amuse::SystemStri
|
||||||
auto search = m_entries.find(id);
|
auto search = m_entries.find(id);
|
||||||
if (search == m_entries.cend())
|
if (search == m_entries.cend())
|
||||||
return;
|
return;
|
||||||
_extractCompressed(id, search->second, destDir, samp);
|
_extractCompressed(id, *search->second->m_data, destDir, samp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioGroupSampleDirectory::extractAllCompressed(amuse::SystemStringView destDir,
|
void AudioGroupSampleDirectory::extractAllCompressed(amuse::SystemStringView destDir,
|
||||||
const unsigned char* samp) const
|
const unsigned char* samp) const
|
||||||
{
|
{
|
||||||
for (const auto& ent : m_entries)
|
for (const auto& ent : m_entries)
|
||||||
_extractCompressed(ent.first, ent.second, destDir, samp);
|
_extractCompressed(ent.first, *ent.second->m_data, destDir, samp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupSampleDirectory::reloadSampleData(SystemStringView groupPath)
|
||||||
|
{
|
||||||
|
DirectoryEnumerator de(groupPath, DirectoryEnumerator::Mode::FilesSorted);
|
||||||
|
for (const DirectoryEnumerator::Entry& ent : de)
|
||||||
|
{
|
||||||
|
if (ent.m_name.size() < 4)
|
||||||
|
continue;
|
||||||
|
SystemString baseName;
|
||||||
|
if (!CompareCaseInsensitive(ent.m_name.data() + ent.m_name.size() - 4, _S(".dsp")) ||
|
||||||
|
!CompareCaseInsensitive(ent.m_name.data() + ent.m_name.size() - 4, _S(".wav")))
|
||||||
|
baseName = SystemString(ent.m_name.begin(), ent.m_name.begin() + ent.m_name.size() - 4);
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::string baseNameStd = athena::utility::wideToUtf8(baseName);
|
||||||
|
#else
|
||||||
|
std::string& baseNameStd = baseName;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (SampleId::CurNameDB->m_stringToId.find(baseNameStd) == SampleId::CurNameDB->m_stringToId.end())
|
||||||
|
{
|
||||||
|
ObjectId sampleId = SampleId::CurNameDB->generateId(NameDB::Type::Sample);
|
||||||
|
SampleId::CurNameDB->registerPair(baseNameStd, sampleId);
|
||||||
|
|
||||||
|
auto& entry = m_entries[sampleId];
|
||||||
|
entry = MakeObj<Entry>();
|
||||||
|
SystemString basePath = SystemString(ent.m_path.begin(), ent.m_path.begin() + ent.m_path.size() - 4);
|
||||||
|
entry->loadLooseData(basePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,7 +174,7 @@ void BooBackendMIDIReader::pumpReader(double dt)
|
||||||
|
|
||||||
void BooBackendMIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
void BooBackendMIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
for (ObjToken<Sequencer>& seq : m_engine.getActiveSequencers())
|
||||||
seq->keyOff(chan, key, velocity);
|
seq->keyOff(chan, key, velocity);
|
||||||
#if 0
|
#if 0
|
||||||
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
|
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
|
||||||
|
@ -185,7 +185,7 @@ void BooBackendMIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
|
|
||||||
void BooBackendMIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
void BooBackendMIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
for (ObjToken<Sequencer>& seq : m_engine.getActiveSequencers())
|
||||||
seq->keyOn(chan, key, velocity);
|
seq->keyOn(chan, key, velocity);
|
||||||
#if 0
|
#if 0
|
||||||
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
|
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
|
||||||
|
@ -198,13 +198,13 @@ void BooBackendMIDIReader::notePressure(uint8_t /*chan*/, uint8_t /*key*/, uint8
|
||||||
|
|
||||||
void BooBackendMIDIReader::controlChange(uint8_t chan, uint8_t control, uint8_t value)
|
void BooBackendMIDIReader::controlChange(uint8_t chan, uint8_t control, uint8_t value)
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
for (ObjToken<Sequencer>& seq : m_engine.getActiveSequencers())
|
||||||
seq->setCtrlValue(chan, control, value);
|
seq->setCtrlValue(chan, control, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendMIDIReader::programChange(uint8_t chan, uint8_t program)
|
void BooBackendMIDIReader::programChange(uint8_t chan, uint8_t program)
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
for (ObjToken<Sequencer>& seq : m_engine.getActiveSequencers())
|
||||||
seq->setChanProgram(chan, program);
|
seq->setChanProgram(chan, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,13 +212,13 @@ void BooBackendMIDIReader::channelPressure(uint8_t /*chan*/, uint8_t /*pressure*
|
||||||
|
|
||||||
void BooBackendMIDIReader::pitchBend(uint8_t chan, int16_t pitch)
|
void BooBackendMIDIReader::pitchBend(uint8_t chan, int16_t pitch)
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
for (ObjToken<Sequencer>& seq : m_engine.getActiveSequencers())
|
||||||
seq->setPitchWheel(chan, (pitch - 0x2000) / float(0x2000));
|
seq->setPitchWheel(chan, (pitch - 0x2000) / float(0x2000));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendMIDIReader::allSoundOff(uint8_t chan)
|
void BooBackendMIDIReader::allSoundOff(uint8_t chan)
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
for (ObjToken<Sequencer>& seq : m_engine.getActiveSequencers())
|
||||||
seq->allOff(chan, true);
|
seq->allOff(chan, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ void BooBackendMIDIReader::localControl(uint8_t /*chan*/, bool /*on*/) {}
|
||||||
|
|
||||||
void BooBackendMIDIReader::allNotesOff(uint8_t chan)
|
void BooBackendMIDIReader::allNotesOff(uint8_t chan)
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
for (ObjToken<Sequencer>& seq : m_engine.getActiveSequencers())
|
||||||
seq->allOff(chan, false);
|
seq->allOff(chan, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ static void Delta(Vector3f& out, const Vector3f& a, const Vector3f& b)
|
||||||
|
|
||||||
Emitter::~Emitter() {}
|
Emitter::~Emitter() {}
|
||||||
|
|
||||||
Emitter::Emitter(Engine& engine, const AudioGroup& group, const std::shared_ptr<Voice>& vox,
|
Emitter::Emitter(Engine& engine, const AudioGroup& group, ObjToken<Voice> vox,
|
||||||
float maxDist, float minVol, float falloff, bool doppler)
|
float maxDist, float minVol, float falloff, bool doppler)
|
||||||
: Entity(engine, group, vox->getGroupId(), vox->getObjectId()), m_vox(vox), m_maxDist(maxDist),
|
: Entity(engine, group, vox->getGroupId(), vox->getObjectId()), m_vox(vox), m_maxDist(maxDist),
|
||||||
m_minVol(clamp(0.f, minVol, 1.f)), m_falloff(clamp(-1.f, falloff, 1.f)), m_doppler(doppler)
|
m_minVol(clamp(0.f, minVol, 1.f)), m_falloff(clamp(-1.f, falloff, 1.f)), m_doppler(doppler)
|
||||||
|
|
101
lib/Engine.cpp
101
lib/Engine.cpp
|
@ -16,12 +16,12 @@ static const float FullLevels[8] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
|
||||||
Engine::~Engine()
|
Engine::~Engine()
|
||||||
{
|
{
|
||||||
m_backend.setCallbackInterface(nullptr);
|
m_backend.setCallbackInterface(nullptr);
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
for (ObjToken<Sequencer>& seq : m_activeSequencers)
|
||||||
if (!seq->m_destroyed)
|
if (!seq->m_destroyed)
|
||||||
seq->_destroy();
|
seq->_destroy();
|
||||||
for (std::shared_ptr<Emitter>& emitter : m_activeEmitters)
|
for (ObjToken<Emitter>& emitter : m_activeEmitters)
|
||||||
emitter->_destroy();
|
emitter->_destroy();
|
||||||
for (std::shared_ptr<Voice>& vox : m_activeVoices)
|
for (ObjToken<Voice>& vox : m_activeVoices)
|
||||||
vox->_destroy();
|
vox->_destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,51 +57,49 @@ std::pair<AudioGroup*, const SFXGroupIndex*> Engine::_findSFXGroup(int groupId)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator Engine::_allocateVoice(const AudioGroup& group, int groupId,
|
std::list<ObjToken<Voice>>::iterator Engine::_allocateVoice(const AudioGroup& group, int groupId,
|
||||||
double sampleRate, bool dynamicPitch, bool emitter,
|
double sampleRate, bool dynamicPitch, bool emitter,
|
||||||
std::weak_ptr<Studio> studio)
|
ObjToken<Studio> studio)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Studio> st = studio.lock();
|
|
||||||
auto it =
|
auto it =
|
||||||
m_activeVoices.emplace(m_activeVoices.end(), new Voice(*this, group, groupId, m_nextVid++, emitter, studio));
|
m_activeVoices.emplace(m_activeVoices.end(), MakeObj<Voice>(*this, group, groupId, m_nextVid++, emitter, studio));
|
||||||
m_activeVoices.back()->m_backendVoice = m_backend.allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch);
|
m_activeVoices.back()->m_backendVoice = m_backend.allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch);
|
||||||
m_activeVoices.back()->m_backendVoice->setChannelLevels(st->getMaster().m_backendSubmix.get(), FullLevels, false);
|
m_activeVoices.back()->m_backendVoice->setChannelLevels(studio->getMaster().m_backendSubmix.get(), FullLevels, false);
|
||||||
m_activeVoices.back()->m_backendVoice->setChannelLevels(st->getAuxA().m_backendSubmix.get(), FullLevels, false);
|
m_activeVoices.back()->m_backendVoice->setChannelLevels(studio->getAuxA().m_backendSubmix.get(), FullLevels, false);
|
||||||
m_activeVoices.back()->m_backendVoice->setChannelLevels(st->getAuxB().m_backendSubmix.get(), FullLevels, false);
|
m_activeVoices.back()->m_backendVoice->setChannelLevels(studio->getAuxB().m_backendSubmix.get(), FullLevels, false);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Sequencer>>::iterator Engine::_allocateSequencer(const AudioGroup& group, int groupId,
|
std::list<ObjToken<Sequencer>>::iterator Engine::_allocateSequencer(const AudioGroup& group, int groupId,
|
||||||
int setupId, std::weak_ptr<Studio> studio)
|
int setupId, ObjToken<Studio> studio)
|
||||||
{
|
{
|
||||||
const SongGroupIndex* songGroup = group.getProj().getSongGroupIndex(groupId);
|
const SongGroupIndex* songGroup = group.getProj().getSongGroupIndex(groupId);
|
||||||
if (songGroup)
|
if (songGroup)
|
||||||
{
|
{
|
||||||
auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
|
auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
|
||||||
new Sequencer(*this, group, groupId, songGroup, setupId, studio));
|
MakeObj<Sequencer>(*this, group, groupId, songGroup, setupId, studio));
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
const SFXGroupIndex* sfxGroup = group.getProj().getSFXGroupIndex(groupId);
|
const SFXGroupIndex* sfxGroup = group.getProj().getSFXGroupIndex(groupId);
|
||||||
if (sfxGroup)
|
if (sfxGroup)
|
||||||
{
|
{
|
||||||
auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
|
auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
|
||||||
new Sequencer(*this, group, groupId, sfxGroup, studio));
|
MakeObj<Sequencer>(*this, group, groupId, sfxGroup, studio));
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Studio> Engine::_allocateStudio(bool mainOut)
|
ObjToken<Studio> Engine::_allocateStudio(bool mainOut)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Studio> ret = std::make_shared<Studio>(*this, mainOut);
|
ObjToken<Studio> ret = MakeObj<Studio>(*this, mainOut);
|
||||||
m_activeStudios.emplace(m_activeStudios.end(), ret);
|
|
||||||
ret->m_master.m_backendSubmix = m_backend.allocateSubmix(ret->m_master, mainOut, 0);
|
ret->m_master.m_backendSubmix = m_backend.allocateSubmix(ret->m_master, mainOut, 0);
|
||||||
ret->m_auxA.m_backendSubmix = m_backend.allocateSubmix(ret->m_auxA, mainOut, 1);
|
ret->m_auxA.m_backendSubmix = m_backend.allocateSubmix(ret->m_auxA, mainOut, 1);
|
||||||
ret->m_auxB.m_backendSubmix = m_backend.allocateSubmix(ret->m_auxB, mainOut, 2);
|
ret->m_auxB.m_backendSubmix = m_backend.allocateSubmix(ret->m_auxB, mainOut, 2);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator Engine::_destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it)
|
std::list<ObjToken<Voice>>::iterator Engine::_destroyVoice(std::list<ObjToken<Voice>>::iterator it)
|
||||||
{
|
{
|
||||||
assert(this == &(*it)->getEngine());
|
assert(this == &(*it)->getEngine());
|
||||||
if ((*it)->m_destroyed)
|
if ((*it)->m_destroyed)
|
||||||
|
@ -110,8 +108,8 @@ std::list<std::shared_ptr<Voice>>::iterator Engine::_destroyVoice(std::list<std:
|
||||||
return m_activeVoices.erase(it);
|
return m_activeVoices.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Sequencer>>::iterator
|
std::list<ObjToken<Sequencer>>::iterator
|
||||||
Engine::_destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it)
|
Engine::_destroySequencer(std::list<ObjToken<Sequencer>>::iterator it)
|
||||||
{
|
{
|
||||||
assert(this == &(*it)->getEngine());
|
assert(this == &(*it)->getEngine());
|
||||||
if ((*it)->m_destroyed)
|
if ((*it)->m_destroyed)
|
||||||
|
@ -157,15 +155,6 @@ void Engine::_bringOutYourDead()
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it = m_activeStudios.begin(); it != m_activeStudios.end();)
|
|
||||||
{
|
|
||||||
std::shared_ptr<Studio> st = it->lock();
|
|
||||||
if (!st)
|
|
||||||
it = m_activeStudios.erase(it);
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::_on5MsInterval(IBackendVoiceAllocator& engine, double dt)
|
void Engine::_on5MsInterval(IBackendVoiceAllocator& engine, double dt)
|
||||||
|
@ -173,11 +162,11 @@ void Engine::_on5MsInterval(IBackendVoiceAllocator& engine, double dt)
|
||||||
m_channelSet = engine.getAvailableSet();
|
m_channelSet = engine.getAvailableSet();
|
||||||
if (m_midiReader)
|
if (m_midiReader)
|
||||||
m_midiReader->pumpReader(dt);
|
m_midiReader->pumpReader(dt);
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
for (ObjToken<Sequencer>& seq : m_activeSequencers)
|
||||||
seq->advance(dt);
|
seq->advance(dt);
|
||||||
for (std::shared_ptr<Emitter>& emitter : m_activeEmitters)
|
for (ObjToken<Emitter>& emitter : m_activeEmitters)
|
||||||
emitter->_update();
|
emitter->_update();
|
||||||
for (std::shared_ptr<Listener>& listener : m_activeListeners)
|
for (ObjToken<Listener>& listener : m_activeListeners)
|
||||||
listener->m_dirty = false;
|
listener->m_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +176,7 @@ void Engine::_onPumpCycleComplete(IBackendVoiceAllocator& engine)
|
||||||
|
|
||||||
/* Determine lowest available free vid */
|
/* Determine lowest available free vid */
|
||||||
int maxVid = -1;
|
int maxVid = -1;
|
||||||
for (std::shared_ptr<Voice>& vox : m_activeVoices)
|
for (ObjToken<Voice>& vox : m_activeVoices)
|
||||||
maxVid = std::max(maxVid, vox->maxVid());
|
maxVid = std::max(maxVid, vox->maxVid());
|
||||||
m_nextVid = maxVid + 1;
|
m_nextVid = maxVid + 1;
|
||||||
}
|
}
|
||||||
|
@ -273,10 +262,10 @@ void Engine::removeAudioGroup(const AudioGroupData& data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create new Studio within engine */
|
/** Create new Studio within engine */
|
||||||
std::shared_ptr<Studio> Engine::addStudio(bool mainOut) { return _allocateStudio(mainOut); }
|
ObjToken<Studio> Engine::addStudio(bool mainOut) { return _allocateStudio(mainOut); }
|
||||||
|
|
||||||
/** Start soundFX playing from loaded audio groups */
|
/** Start soundFX playing from loaded audio groups */
|
||||||
std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, std::weak_ptr<Studio> smx)
|
ObjToken<Voice> Engine::fxStart(int sfxId, float vol, float pan, ObjToken<Studio> smx)
|
||||||
{
|
{
|
||||||
auto search = m_sfxLookup.find(sfxId);
|
auto search = m_sfxLookup.find(sfxId);
|
||||||
if (search == m_sfxLookup.end())
|
if (search == m_sfxLookup.end())
|
||||||
|
@ -287,7 +276,7 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, std::wea
|
||||||
if (!grp)
|
if (!grp)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator ret =
|
std::list<ObjToken<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);
|
||||||
|
|
||||||
if (!(*ret)->loadMacroObject(entry->macro.id, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
if (!(*ret)->loadMacroObject(entry->macro.id, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
||||||
|
@ -302,13 +291,13 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, std::wea
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start SoundMacro node playing directly (for editor use) */
|
/** Start SoundMacro node playing directly (for editor use) */
|
||||||
std::shared_ptr<Voice> Engine::macroStart(const AudioGroup* group, SoundMacroId id, uint8_t key, uint8_t vel,
|
ObjToken<Voice> Engine::macroStart(const AudioGroup* group, SoundMacroId id, uint8_t key, uint8_t vel,
|
||||||
uint8_t mod, std::weak_ptr<Studio> smx)
|
uint8_t mod, ObjToken<Studio> smx)
|
||||||
{
|
{
|
||||||
if (!group)
|
if (!group)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator ret =
|
std::list<ObjToken<Voice>>::iterator ret =
|
||||||
_allocateVoice(*group, {}, NativeSampleRate, true, false, smx);
|
_allocateVoice(*group, {}, NativeSampleRate, true, false, smx);
|
||||||
|
|
||||||
if (!(*ret)->loadMacroObject(id, 0, 1000.f, key, vel, mod))
|
if (!(*ret)->loadMacroObject(id, 0, 1000.f, key, vel, mod))
|
||||||
|
@ -321,9 +310,8 @@ std::shared_ptr<Voice> Engine::macroStart(const AudioGroup* group, SoundMacroId
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
||||||
std::shared_ptr<Emitter> Engine::addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
|
ObjToken<Emitter> Engine::addEmitter(const float* pos, const float* dir, float maxDist, float falloff,
|
||||||
int sfxId, float minVol, float maxVol, bool doppler,
|
int sfxId, float minVol, float maxVol, bool doppler, ObjToken<Studio> smx)
|
||||||
std::weak_ptr<Studio> smx)
|
|
||||||
{
|
{
|
||||||
auto search = m_sfxLookup.find(sfxId);
|
auto search = m_sfxLookup.find(sfxId);
|
||||||
if (search == m_sfxLookup.end())
|
if (search == m_sfxLookup.end())
|
||||||
|
@ -334,7 +322,7 @@ std::shared_ptr<Emitter> Engine::addEmitter(const float* pos, const float* dir,
|
||||||
if (!grp)
|
if (!grp)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator vox =
|
std::list<ObjToken<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);
|
||||||
|
|
||||||
if (!(*vox)->loadMacroObject(entry->macro, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
if (!(*vox)->loadMacroObject(entry->macro, 0, 1000.f, entry->defKey, entry->defVel, 0))
|
||||||
|
@ -344,7 +332,7 @@ std::shared_ptr<Emitter> Engine::addEmitter(const float* pos, const float* dir,
|
||||||
}
|
}
|
||||||
|
|
||||||
auto emitIt = m_activeEmitters.emplace(m_activeEmitters.end(),
|
auto emitIt = m_activeEmitters.emplace(m_activeEmitters.end(),
|
||||||
new Emitter(*this, *grp, *vox, maxDist, minVol, falloff, doppler));
|
MakeObj<Emitter>(*this, *grp, *vox, maxDist, minVol, falloff, doppler));
|
||||||
Emitter& ret = *(*emitIt);
|
Emitter& ret = *(*emitIt);
|
||||||
|
|
||||||
ret.getVoice()->setPan(entry->panning);
|
ret.getVoice()->setPan(entry->panning);
|
||||||
|
@ -355,11 +343,11 @@ std::shared_ptr<Emitter> Engine::addEmitter(const float* pos, const float* dir,
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build listener and add to engine's listener list */
|
/** Build listener and add to engine's listener list */
|
||||||
std::shared_ptr<Listener> Engine::addListener(const float* pos, const float* dir, const float* heading, const float* up,
|
ObjToken<Listener> Engine::addListener(const float* pos, const float* dir, const float* heading, const float* up,
|
||||||
float frontDiff, float backDiff, float soundSpeed, float volume)
|
float frontDiff, float backDiff, float soundSpeed, float volume)
|
||||||
{
|
{
|
||||||
auto listenerIt = m_activeListeners.emplace(m_activeListeners.end(),
|
auto listenerIt = m_activeListeners.emplace(m_activeListeners.end(),
|
||||||
new Listener(volume, frontDiff, backDiff, soundSpeed));
|
MakeObj<Listener>(volume, frontDiff, backDiff, soundSpeed));
|
||||||
Listener& ret = *(*listenerIt);
|
Listener& ret = *(*listenerIt);
|
||||||
ret.setVectors(pos, dir, heading, up);
|
ret.setVectors(pos, dir, heading, up);
|
||||||
return *listenerIt;
|
return *listenerIt;
|
||||||
|
@ -379,13 +367,12 @@ void Engine::removeListener(Listener* listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start song playing from loaded audio groups */
|
/** Start song playing from loaded audio groups */
|
||||||
std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId, const unsigned char* arrData,
|
ObjToken<Sequencer> Engine::seqPlay(int groupId, int songId, const unsigned char* arrData, ObjToken<Studio> smx)
|
||||||
std::weak_ptr<Studio> smx)
|
|
||||||
{
|
{
|
||||||
std::pair<AudioGroup*, const SongGroupIndex*> songGrp = _findSongGroup(groupId);
|
std::pair<AudioGroup*, const SongGroupIndex*> songGrp = _findSongGroup(groupId);
|
||||||
if (songGrp.second)
|
if (songGrp.second)
|
||||||
{
|
{
|
||||||
std::list<std::shared_ptr<Sequencer>>::iterator ret = _allocateSequencer(*songGrp.first, groupId, songId, smx);
|
std::list<ObjToken<Sequencer>>::iterator ret = _allocateSequencer(*songGrp.first, groupId, songId, smx);
|
||||||
if (!*ret)
|
if (!*ret)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -397,7 +384,7 @@ std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId, const unsign
|
||||||
std::pair<AudioGroup*, const SFXGroupIndex*> sfxGrp = _findSFXGroup(groupId);
|
std::pair<AudioGroup*, const SFXGroupIndex*> sfxGrp = _findSFXGroup(groupId);
|
||||||
if (sfxGrp.second)
|
if (sfxGrp.second)
|
||||||
{
|
{
|
||||||
std::list<std::shared_ptr<Sequencer>>::iterator ret = _allocateSequencer(*sfxGrp.first, groupId, songId, smx);
|
std::list<ObjToken<Sequencer>>::iterator ret = _allocateSequencer(*sfxGrp.first, groupId, songId, smx);
|
||||||
if (!*ret)
|
if (!*ret)
|
||||||
return {};
|
return {};
|
||||||
return *ret;
|
return *ret;
|
||||||
|
@ -413,18 +400,18 @@ void Engine::setVolume(float vol)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Find voice from VoiceId */
|
/** Find voice from VoiceId */
|
||||||
std::shared_ptr<Voice> Engine::findVoice(int vid)
|
ObjToken<Voice> Engine::findVoice(int vid)
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<Voice>& vox : m_activeVoices)
|
for (ObjToken<Voice>& vox : m_activeVoices)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> ret = vox->_findVoice(vid, vox);
|
ObjToken<Voice> ret = vox->_findVoice(vid, vox);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
for (ObjToken<Sequencer>& seq : m_activeSequencers)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> ret = seq->findVoice(vid);
|
ObjToken<Voice> ret = seq->findVoice(vid);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -450,7 +437,7 @@ void Engine::killKeygroup(uint8_t kg, bool now)
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
for (ObjToken<Sequencer>& seq : m_activeSequencers)
|
||||||
seq->killKeygroup(kg, now);
|
seq->killKeygroup(kg, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,7 +451,7 @@ void Engine::sendMacroMessage(ObjectId macroId, int32_t val)
|
||||||
vox->message(val);
|
vox->message(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
for (ObjToken<Sequencer>& seq : m_activeSequencers)
|
||||||
seq->sendMacroMessage(macroId, val);
|
seq->sendMacroMessage(macroId, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ Sequencer::~Sequencer()
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SongGroupIndex* songGroup, int setupId,
|
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SongGroupIndex* songGroup, int setupId,
|
||||||
std::weak_ptr<Studio> studio)
|
ObjToken<Studio> studio)
|
||||||
: Entity(engine, group, groupId), m_songGroup(songGroup), m_studio(studio)
|
: Entity(engine, group, groupId), m_songGroup(songGroup), m_studio(studio)
|
||||||
{
|
{
|
||||||
auto it = m_songGroup->m_midiSetups.find(setupId);
|
auto it = m_songGroup->m_midiSetups.find(setupId);
|
||||||
|
@ -67,7 +67,7 @@ Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SFXGroupIndex* sfxGroup,
|
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SFXGroupIndex* sfxGroup,
|
||||||
std::weak_ptr<Studio> studio)
|
ObjToken<Studio> studio)
|
||||||
: Entity(engine, group, groupId), m_sfxGroup(sfxGroup), m_studio(studio)
|
: Entity(engine, group, groupId), m_sfxGroup(sfxGroup), m_studio(studio)
|
||||||
{
|
{
|
||||||
std::map<uint16_t, const SFXGroupIndex::SFXEntry*> sortSFX;
|
std::map<uint16_t, const SFXGroupIndex::SFXEntry*> sortSFX;
|
||||||
|
@ -210,13 +210,16 @@ size_t Sequencer::getVoiceCount() const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velocity)
|
ObjToken<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velocity)
|
||||||
{
|
{
|
||||||
if (m_parent->m_songGroup && !m_page)
|
if (m_parent->m_songGroup && !m_page)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
if (m_lastVoice->isDestroyed())
|
||||||
|
m_lastVoice.reset();
|
||||||
|
|
||||||
/* If portamento is enabled for voice, pre-empt spawning new voices */
|
/* If portamento is enabled for voice, pre-empt spawning new voices */
|
||||||
if (std::shared_ptr<Voice> lastVoice = m_lastVoice.lock())
|
if (ObjToken<Voice> lastVoice = m_lastVoice)
|
||||||
{
|
{
|
||||||
uint8_t lastNote = lastVoice->getLastNote();
|
uint8_t lastNote = lastVoice->getLastNote();
|
||||||
if (lastVoice->doPortamento(note))
|
if (lastVoice->doPortamento(note))
|
||||||
|
@ -231,7 +234,7 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
|
||||||
auto keySearch = m_chanVoxs.find(note);
|
auto keySearch = m_chanVoxs.find(note);
|
||||||
if (keySearch != m_chanVoxs.cend())
|
if (keySearch != m_chanVoxs.cend())
|
||||||
{
|
{
|
||||||
if (keySearch->second == m_lastVoice.lock())
|
if (keySearch->second == m_lastVoice)
|
||||||
m_lastVoice.reset();
|
m_lastVoice.reset();
|
||||||
keySearch->second->keyOff();
|
keySearch->second->keyOff();
|
||||||
keySearch->second->setPedal(false);
|
keySearch->second->setPedal(false);
|
||||||
|
@ -239,7 +242,7 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
|
||||||
m_chanVoxs.erase(keySearch);
|
m_chanVoxs.erase(keySearch);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator ret = m_parent->m_engine._allocateVoice(
|
std::list<ObjToken<Voice>>::iterator ret = m_parent->m_engine._allocateVoice(
|
||||||
m_parent->m_audioGroup, m_parent->m_groupId, NativeSampleRate, true, false, m_parent->m_studio);
|
m_parent->m_audioGroup, m_parent->m_groupId, NativeSampleRate, true, false, m_parent->m_studio);
|
||||||
if (*ret)
|
if (*ret)
|
||||||
{
|
{
|
||||||
|
@ -284,7 +287,7 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
|
||||||
return *ret;
|
return *ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Voice> Sequencer::keyOn(uint8_t chan, uint8_t note, uint8_t velocity)
|
ObjToken<Voice> Sequencer::keyOn(uint8_t chan, uint8_t note, uint8_t velocity)
|
||||||
{
|
{
|
||||||
if (chan > 15)
|
if (chan > 15)
|
||||||
return {};
|
return {};
|
||||||
|
@ -301,7 +304,7 @@ void Sequencer::ChannelState::keyOff(uint8_t note, uint8_t velocity)
|
||||||
if (keySearch == m_chanVoxs.cend())
|
if (keySearch == m_chanVoxs.cend())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (keySearch->second == m_lastVoice.lock())
|
if (m_lastVoice->isDestroyed() || keySearch->second == m_lastVoice)
|
||||||
m_lastVoice.reset();
|
m_lastVoice.reset();
|
||||||
keySearch->second->keyOff();
|
keySearch->second->keyOff();
|
||||||
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
||||||
|
@ -425,9 +428,11 @@ void Sequencer::setTempo(double ticksPerSec) { m_ticksPerSec = ticksPerSec; }
|
||||||
|
|
||||||
void Sequencer::ChannelState::allOff()
|
void Sequencer::ChannelState::allOff()
|
||||||
{
|
{
|
||||||
|
if (m_lastVoice->isDestroyed())
|
||||||
|
m_lastVoice.reset();
|
||||||
for (auto it = m_chanVoxs.begin(); it != m_chanVoxs.end();)
|
for (auto it = m_chanVoxs.begin(); it != m_chanVoxs.end();)
|
||||||
{
|
{
|
||||||
if (it->second == m_lastVoice.lock())
|
if (it->second == m_lastVoice)
|
||||||
m_lastVoice.reset();
|
m_lastVoice.reset();
|
||||||
it->second->keyOff();
|
it->second->keyOff();
|
||||||
m_keyoffVoxs.emplace(std::move(it->second));
|
m_keyoffVoxs.emplace(std::move(it->second));
|
||||||
|
@ -476,12 +481,15 @@ void Sequencer::allOff(uint8_t chan, bool now)
|
||||||
|
|
||||||
void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
||||||
{
|
{
|
||||||
|
if (m_lastVoice->isDestroyed())
|
||||||
|
m_lastVoice.reset();
|
||||||
|
|
||||||
for (auto it = m_chanVoxs.begin(); it != m_chanVoxs.end();)
|
for (auto it = m_chanVoxs.begin(); it != m_chanVoxs.end();)
|
||||||
{
|
{
|
||||||
Voice* vox = it->second.get();
|
Voice* vox = it->second.get();
|
||||||
if (vox->m_keygroup == kg)
|
if (vox->m_keygroup == kg)
|
||||||
{
|
{
|
||||||
if (it->second == m_lastVoice.lock())
|
if (it->second == m_lastVoice)
|
||||||
m_lastVoice.reset();
|
m_lastVoice.reset();
|
||||||
if (now)
|
if (now)
|
||||||
{
|
{
|
||||||
|
@ -518,7 +526,7 @@ void Sequencer::killKeygroup(uint8_t kg, bool now)
|
||||||
chan.killKeygroup(kg, now);
|
chan.killKeygroup(kg, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Voice> Sequencer::ChannelState::findVoice(int vid)
|
ObjToken<Voice> Sequencer::ChannelState::findVoice(int vid)
|
||||||
{
|
{
|
||||||
for (const auto& vox : m_chanVoxs)
|
for (const auto& vox : m_chanVoxs)
|
||||||
if (vox.second->vid() == vid)
|
if (vox.second->vid() == vid)
|
||||||
|
@ -529,13 +537,13 @@ std::shared_ptr<Voice> Sequencer::ChannelState::findVoice(int vid)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Voice> Sequencer::findVoice(int vid)
|
ObjToken<Voice> Sequencer::findVoice(int vid)
|
||||||
{
|
{
|
||||||
for (auto& chan : m_chanStates)
|
for (auto& chan : m_chanStates)
|
||||||
{
|
{
|
||||||
if (chan)
|
if (chan)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> ret = chan.findVoice(vid);
|
ObjToken<Voice> ret = chan.findVoice(vid);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -469,7 +469,7 @@ const SoundMacro::CmdIntrospection SoundMacro::CmdWaitMs::Introspective =
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
FIELD_HEAD(SoundMacro::CmdWaitMs, ms),
|
FIELD_HEAD(SoundMacro::CmdWaitMs, ms),
|
||||||
"Ticks/Millisec"sv,
|
"Millisec"sv,
|
||||||
0, 65535, 96
|
0, 65535, 96
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -541,7 +541,7 @@ const SoundMacro::CmdIntrospection SoundMacro::CmdPlayMacro::Introspective =
|
||||||
};
|
};
|
||||||
bool SoundMacro::CmdPlayMacro::Do(SoundMacroState& st, Voice& vox) const
|
bool SoundMacro::CmdPlayMacro::Do(SoundMacroState& st, Voice& vox) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> sibVox = vox.startChildMacro(addNote, macro.id, macroStep.step);
|
ObjToken<Voice> sibVox = vox.startChildMacro(addNote, macro.id, macroStep.step);
|
||||||
if (sibVox)
|
if (sibVox)
|
||||||
st.m_lastPlayMacroVid = sibVox->vid();
|
st.m_lastPlayMacroVid = sibVox->vid();
|
||||||
|
|
||||||
|
@ -572,14 +572,14 @@ bool SoundMacro::CmdSendKeyOff::Do(SoundMacroState& st, Voice& vox) const
|
||||||
{
|
{
|
||||||
if (st.m_lastPlayMacroVid != -1)
|
if (st.m_lastPlayMacroVid != -1)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> otherVox = vox.getEngine().findVoice(st.m_lastPlayMacroVid);
|
ObjToken<Voice> otherVox = vox.getEngine().findVoice(st.m_lastPlayMacroVid);
|
||||||
if (otherVox)
|
if (otherVox)
|
||||||
otherVox->keyOff();
|
otherVox->keyOff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> otherVox = vox.getEngine().findVoice(st.m_variables[variable & 0x1f]);
|
ObjToken<Voice> otherVox = vox.getEngine().findVoice(st.m_variables[variable & 0x1f]);
|
||||||
if (otherVox)
|
if (otherVox)
|
||||||
otherVox->keyOff();
|
otherVox->keyOff();
|
||||||
}
|
}
|
||||||
|
@ -1361,12 +1361,12 @@ const SoundMacro::CmdIntrospection SoundMacro::CmdPitchSweep1::Introspective =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
FIELD_HEAD(SoundMacro::CmdPitchSweep1, times),
|
FIELD_HEAD(SoundMacro::CmdPitchSweep1, times),
|
||||||
"Level Note"sv,
|
"Times"sv,
|
||||||
0, 127, 100,
|
0, 127, 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
FIELD_HEAD(SoundMacro::CmdPitchSweep1, add),
|
FIELD_HEAD(SoundMacro::CmdPitchSweep1, add),
|
||||||
"Level Fine"sv,
|
"Add"sv,
|
||||||
-32768, 32767, 100,
|
-32768, 32767, 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1406,12 +1406,12 @@ const SoundMacro::CmdIntrospection SoundMacro::CmdPitchSweep2::Introspective =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
FIELD_HEAD(SoundMacro::CmdPitchSweep2, times),
|
FIELD_HEAD(SoundMacro::CmdPitchSweep2, times),
|
||||||
"Level Note"sv,
|
"Times"sv,
|
||||||
0, 127, 100,
|
0, 127, 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
FIELD_HEAD(SoundMacro::CmdPitchSweep2, add),
|
FIELD_HEAD(SoundMacro::CmdPitchSweep2, add),
|
||||||
"Level Fine"sv,
|
"Add"sv,
|
||||||
-32768, 32767, 100,
|
-32768, 32767, 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1744,7 +1744,7 @@ bool SoundMacro::CmdSendMessage::Do(SoundMacroState& st, Voice& vox) const
|
||||||
{
|
{
|
||||||
if (isVar)
|
if (isVar)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> findVox = vox.getEngine().findVoice(st.m_variables[voiceVar & 0x1f]);
|
ObjToken<Voice> findVox = vox.getEngine().findVoice(st.m_variables[voiceVar & 0x1f]);
|
||||||
if (findVox)
|
if (findVox)
|
||||||
findVox->message(st.m_variables[valueVar & 0x1f]);
|
findVox->message(st.m_variables[valueVar & 0x1f]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ Studio::Studio(Engine& engine, bool mainOut) : m_engine(engine), m_master(engine
|
||||||
addStudioSend(engine.getDefaultStudio(), 1.f, 1.f, 1.f);
|
addStudioSend(engine.getDefaultStudio(), 1.f, 1.f, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Studio::addStudioSend(std::weak_ptr<Studio> studio, float dry, float auxA, float auxB)
|
void Studio::addStudioSend(ObjToken<Studio> studio, float dry, float auxA, float auxB)
|
||||||
{
|
{
|
||||||
m_studiosOut.emplace_back(studio, dry, auxA, auxB);
|
m_studiosOut.emplace_back(studio, dry, auxA, auxB);
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,12 @@ void Voice::_destroy()
|
||||||
{
|
{
|
||||||
Entity::_destroy();
|
Entity::_destroy();
|
||||||
|
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (auto& vox : m_childVoices)
|
||||||
vox->_destroy();
|
vox->_destroy();
|
||||||
|
|
||||||
|
m_studio.reset();
|
||||||
|
m_backendVoice.reset();
|
||||||
|
m_curSample.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
Voice::~Voice()
|
Voice::~Voice()
|
||||||
|
@ -26,14 +30,14 @@ Voice::~Voice()
|
||||||
// fprintf(stderr, "DEALLOC %d\n", m_vid);
|
// fprintf(stderr, "DEALLOC %d\n", m_vid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Voice::Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, std::weak_ptr<Studio> studio)
|
Voice::Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, ObjToken<Studio> studio)
|
||||||
: Entity(engine, group, groupId), m_vid(vid), m_emitter(emitter), m_studio(studio)
|
: Entity(engine, group, groupId), m_vid(vid), m_emitter(emitter), m_studio(studio)
|
||||||
{
|
{
|
||||||
// fprintf(stderr, "ALLOC %d\n", m_vid);
|
// fprintf(stderr, "ALLOC %d\n", m_vid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Voice::Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter,
|
Voice::Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter,
|
||||||
std::weak_ptr<Studio> studio)
|
ObjToken<Studio> studio)
|
||||||
: Entity(engine, group, groupId, oid), m_vid(vid), m_emitter(emitter), m_studio(studio)
|
: Entity(engine, group, groupId, oid), m_vid(vid), m_emitter(emitter), m_studio(studio)
|
||||||
{
|
{
|
||||||
// fprintf(stderr, "ALLOC %d\n", m_vid);
|
// fprintf(stderr, "ALLOC %d\n", m_vid);
|
||||||
|
@ -115,7 +119,7 @@ void Voice::_doKeyOff()
|
||||||
void Voice::_setTotalPitch(int32_t cents, bool slew)
|
void Voice::_setTotalPitch(int32_t cents, bool slew)
|
||||||
{
|
{
|
||||||
// fprintf(stderr, "PITCH %d %d \n", cents, slew);
|
// fprintf(stderr, "PITCH %d %d \n", cents, slew);
|
||||||
int32_t interval = cents - m_curSample->m_pitch * 100;
|
int32_t interval = clamp(0, cents, 12700) - m_curSample->m_pitch * 100;
|
||||||
double ratio = std::exp2(interval / 1200.0) * m_dopplerRatio;
|
double ratio = std::exp2(interval / 1200.0) * m_dopplerRatio;
|
||||||
m_sampleRate = m_curSample->m_sampleRate * ratio;
|
m_sampleRate = m_curSample->m_sampleRate * ratio;
|
||||||
m_backendVoice->setPitchRatio(ratio, slew);
|
m_backendVoice->setPitchRatio(ratio, slew);
|
||||||
|
@ -125,7 +129,7 @@ bool Voice::_isRecursivelyDead()
|
||||||
{
|
{
|
||||||
if (m_voxState != VoiceState::Dead)
|
if (m_voxState != VoiceState::Dead)
|
||||||
return false;
|
return false;
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (auto& vox : m_childVoices)
|
||||||
if (!vox->_isRecursivelyDead())
|
if (!vox->_isRecursivelyDead())
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -146,14 +150,14 @@ void Voice::_bringOutYourDead()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Voice> Voice::_findVoice(int vid, std::weak_ptr<Voice> thisPtr)
|
ObjToken<Voice> Voice::_findVoice(int vid, ObjToken<Voice> thisPtr)
|
||||||
{
|
{
|
||||||
if (m_vid == vid)
|
if (m_vid == vid)
|
||||||
return thisPtr.lock();
|
return thisPtr;
|
||||||
|
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> ret = vox->_findVoice(vid, vox);
|
ObjToken<Voice> ret = vox->_findVoice(vid, vox);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -170,16 +174,16 @@ std::unique_ptr<int8_t[]>& Voice::_ensureCtrlVals()
|
||||||
return m_ctrlValsSelf;
|
return m_ctrlValsSelf;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator Voice::_allocateVoice(double sampleRate, bool dynamicPitch)
|
std::list<ObjToken<Voice>>::iterator Voice::_allocateVoice(double sampleRate, bool dynamicPitch)
|
||||||
{
|
{
|
||||||
auto it = m_childVoices.emplace(
|
auto it = m_childVoices.emplace(
|
||||||
m_childVoices.end(), new Voice(m_engine, m_audioGroup, m_groupId, m_engine.m_nextVid++, m_emitter, m_studio));
|
m_childVoices.end(), MakeObj<Voice>(m_engine, m_audioGroup, m_groupId, m_engine.m_nextVid++, m_emitter, m_studio));
|
||||||
m_childVoices.back()->m_backendVoice =
|
m_childVoices.back()->m_backendVoice =
|
||||||
m_engine.getBackend().allocateVoice(*m_childVoices.back(), sampleRate, dynamicPitch);
|
m_engine.getBackend().allocateVoice(*m_childVoices.back(), sampleRate, dynamicPitch);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator Voice::_destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it)
|
std::list<ObjToken<Voice>>::iterator Voice::_destroyVoice(std::list<ObjToken<Voice>>::iterator it)
|
||||||
{
|
{
|
||||||
if ((*it)->m_destroyed)
|
if ((*it)->m_destroyed)
|
||||||
return m_childVoices.begin();
|
return m_childVoices.begin();
|
||||||
|
@ -657,7 +661,7 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
|
||||||
memset(data, 0, sizeof(int16_t) * samples);
|
memset(data, 0, sizeof(int16_t) * samples);
|
||||||
|
|
||||||
if (m_voxState == VoiceState::Dead)
|
if (m_voxState == VoiceState::Dead)
|
||||||
m_curSample = nullptr;
|
m_curSample.reset();
|
||||||
|
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
@ -749,27 +753,27 @@ void Voice::routeAudio(size_t frames, double dt, int busId, float* in, float* ou
|
||||||
int Voice::maxVid() const
|
int Voice::maxVid() const
|
||||||
{
|
{
|
||||||
int maxVid = m_vid;
|
int maxVid = m_vid;
|
||||||
for (const std::shared_ptr<Voice>& vox : m_childVoices)
|
for (const ObjToken<Voice>& vox : m_childVoices)
|
||||||
maxVid = std::max(maxVid, vox->maxVid());
|
maxVid = std::max(maxVid, vox->maxVid());
|
||||||
return maxVid;
|
return maxVid;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Voice> Voice::_startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
|
ObjToken<Voice> Voice::_startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
|
||||||
uint8_t midiVel, uint8_t midiMod, bool pushPc)
|
uint8_t midiVel, uint8_t midiMod, bool pushPc)
|
||||||
{
|
{
|
||||||
std::list<std::shared_ptr<Voice>>::iterator vox = _allocateVoice(NativeSampleRate, true);
|
std::list<ObjToken<Voice>>::iterator vox = _allocateVoice(NativeSampleRate, true);
|
||||||
if (!(*vox)->loadMacroObject(macroId, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc))
|
if (!(*vox)->loadMacroObject(macroId, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc))
|
||||||
{
|
{
|
||||||
_destroyVoice(vox);
|
_destroyVoice(vox);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
(*vox)->setVolume(m_targetUserVol);
|
(*vox)->setVolume(m_targetUserVol);
|
||||||
(*vox)->setPan(m_userPan);
|
(*vox)->setPan(m_curPan);
|
||||||
(*vox)->setSurroundPan(m_userSpan);
|
(*vox)->setSurroundPan(m_curSpan);
|
||||||
return *vox;
|
return *vox;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Voice> Voice::startChildMacro(int8_t addNote, ObjectId macroId, int macroStep)
|
ObjToken<Voice> Voice::startChildMacro(int8_t addNote, ObjectId macroId, int macroStep)
|
||||||
{
|
{
|
||||||
return _startChildMacro(macroId, macroStep, 1000.0, m_state.m_initKey + addNote, m_state.m_initVel,
|
return _startChildMacro(macroId, macroStep, 1000.0, m_state.m_initKey + addNote, m_state.m_initVel,
|
||||||
m_state.m_initMod);
|
m_state.m_initMod);
|
||||||
|
@ -824,7 +828,7 @@ bool Voice::_loadLayer(const std::vector<LayerMapping>& layer, double ticksPerSe
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::shared_ptr<Voice> vox =
|
ObjToken<Voice> vox =
|
||||||
_startChildMacro(mapping.macro.id, 0, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
|
_startChildMacro(mapping.macro.id, 0, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
|
||||||
if (vox)
|
if (vox)
|
||||||
{
|
{
|
||||||
|
@ -904,7 +908,7 @@ void Voice::keyOff()
|
||||||
else if (!m_curSample || m_curSample->m_loopLengthSamples)
|
else if (!m_curSample || m_curSample->m_loopLengthSamples)
|
||||||
_macroKeyOff();
|
_macroKeyOff();
|
||||||
|
|
||||||
for (const std::shared_ptr<Voice>& vox : m_childVoices)
|
for (const ObjToken<Voice>& vox : m_childVoices)
|
||||||
vox->keyOff();
|
vox->keyOff();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -930,10 +934,9 @@ void Voice::startSample(SampleId sampId, int32_t offset)
|
||||||
if (m_destroyed)
|
if (m_destroyed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_curSample = m_audioGroup.getSample(sampId);
|
if (const SampleEntry* sample = m_audioGroup.getSample(sampId))
|
||||||
if (m_curSample)
|
|
||||||
{
|
{
|
||||||
m_curSampleData = m_audioGroup.getSampleData(sampId, m_curSample);
|
std::tie(m_curSample, m_curSampleData) = m_audioGroup.getSampleData(sampId, sample);
|
||||||
|
|
||||||
m_sampleRate = m_curSample->m_sampleRate;
|
m_sampleRate = m_curSample->m_sampleRate;
|
||||||
m_curPitch = m_curSample->m_pitch;
|
m_curPitch = m_curSample->m_pitch;
|
||||||
|
@ -986,7 +989,7 @@ void Voice::startSample(SampleId sampId, int32_t offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::stopSample() { m_curSample = nullptr; }
|
void Voice::stopSample() { m_curSample.reset(); }
|
||||||
|
|
||||||
void Voice::setVolume(float vol)
|
void Voice::setVolume(float vol)
|
||||||
{
|
{
|
||||||
|
@ -994,7 +997,7 @@ void Voice::setVolume(float vol)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_targetUserVol = clamp(0.f, vol, 1.f);
|
m_targetUserVol = clamp(0.f, vol, 1.f);
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
vox->setVolume(vol);
|
vox->setVolume(vol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1116,8 +1119,8 @@ void Voice::_setPan(float pan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_curPan = clamp(-1.f, pan, 1.f);
|
m_curPan = clamp(-1.f, pan, 1.f);
|
||||||
float totalPan = clamp(-1.f, m_curPan + m_userPan, 1.f);
|
float totalPan = clamp(-1.f, m_curPan, 1.f);
|
||||||
float totalSpan = clamp(-1.f, m_curSpan + m_userSpan, 1.f);
|
float totalSpan = clamp(-1.f, m_curSpan, 1.f);
|
||||||
float coefs[8] = {};
|
float coefs[8] = {};
|
||||||
_panLaw(coefs, totalPan, totalPan, totalSpan);
|
_panLaw(coefs, totalPan, totalPan, totalSpan);
|
||||||
_setChannelCoefs(coefs);
|
_setChannelCoefs(coefs);
|
||||||
|
@ -1128,9 +1131,8 @@ void Voice::setPan(float pan)
|
||||||
if (m_destroyed)
|
if (m_destroyed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_userPan = pan;
|
_setPan(pan);
|
||||||
_setPan(m_curPan);
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
|
||||||
vox->setPan(pan);
|
vox->setPan(pan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1145,9 +1147,8 @@ void Voice::setSurroundPan(float span)
|
||||||
if (m_destroyed)
|
if (m_destroyed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_userSpan = span;
|
_setSurroundPan(span);
|
||||||
_setSurroundPan(m_curSpan);
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
|
||||||
vox->setSurroundPan(span);
|
vox->setSurroundPan(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1164,7 +1165,7 @@ void Voice::setChannelCoefs(const float coefs[8])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_setChannelCoefs(coefs);
|
_setChannelCoefs(coefs);
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
vox->setChannelCoefs(coefs);
|
vox->setChannelCoefs(coefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1220,7 +1221,7 @@ void Voice::setPedal(bool pedal)
|
||||||
}
|
}
|
||||||
m_sustained = pedal;
|
m_sustained = pedal;
|
||||||
|
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
vox->setPedal(pedal);
|
vox->setPedal(pedal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1264,7 +1265,7 @@ void Voice::setReverbVol(float rvol)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_curReverbVol = clamp(0.f, rvol, 1.f);
|
m_curReverbVol = clamp(0.f, rvol, 1.f);
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
vox->setReverbVol(rvol);
|
vox->setReverbVol(rvol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1274,7 +1275,7 @@ void Voice::setAuxBVol(float bvol)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_curAuxBVol = clamp(0.f, bvol, 1.f);
|
m_curAuxBVol = clamp(0.f, bvol, 1.f);
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
vox->setAuxBVol(bvol);
|
vox->setAuxBVol(bvol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1351,7 +1352,7 @@ void Voice::setPitchWheel(float pitchWheel)
|
||||||
m_curPitchWheel = amuse::clamp(-1.f, pitchWheel, 1.f);
|
m_curPitchWheel = amuse::clamp(-1.f, pitchWheel, 1.f);
|
||||||
_setPitchWheel(m_curPitchWheel);
|
_setPitchWheel(m_curPitchWheel);
|
||||||
|
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
vox->setPitchWheel(pitchWheel);
|
vox->setPitchWheel(pitchWheel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1371,7 +1372,7 @@ void Voice::setAftertouch(uint8_t aftertouch)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_curAftertouch = aftertouch;
|
m_curAftertouch = aftertouch;
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
vox->setAftertouch(aftertouch);
|
vox->setAftertouch(aftertouch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1424,14 +1425,14 @@ void Voice::_notifyCtrlChange(uint8_t ctrl, int8_t val)
|
||||||
m_state.m_curMod = uint8_t(val);
|
m_state.m_curMod = uint8_t(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::shared_ptr<Voice>& vox : m_childVoices)
|
for (ObjToken<Voice>& vox : m_childVoices)
|
||||||
vox->_notifyCtrlChange(ctrl, val);
|
vox->_notifyCtrlChange(ctrl, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Voice::getTotalVoices() const
|
size_t Voice::getTotalVoices() const
|
||||||
{
|
{
|
||||||
size_t ret = 1;
|
size_t ret = 1;
|
||||||
for (const std::shared_ptr<Voice>& vox : m_childVoices)
|
for (const ObjToken<Voice>& vox : m_childVoices)
|
||||||
ret += vox->getTotalVoices();
|
ret += vox->getTotalVoices();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1443,7 +1444,7 @@ void Voice::kill()
|
||||||
|
|
||||||
m_voxState = VoiceState::Dead;
|
m_voxState = VoiceState::Dead;
|
||||||
m_backendVoice->stop();
|
m_backendVoice->stop();
|
||||||
for (const std::shared_ptr<Voice>& vox : m_childVoices)
|
for (const ObjToken<Voice>& vox : m_childVoices)
|
||||||
vox->kill();
|
vox->kill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue