More athena refactoring

This commit is contained in:
Jack Andersen 2018-07-14 20:10:50 -10:00
parent 4c884d019d
commit 26cfa07f77
18 changed files with 1290 additions and 710 deletions

View File

@ -18,6 +18,7 @@ endif()
atdna(atdna_AudioGroupPool.cpp include/amuse/AudioGroupPool.hpp)
atdna(atdna_AudioGroupProject.cpp include/amuse/AudioGroupProject.hpp)
atdna(atdna_AudioGroupSampleDirectory.cpp include/amuse/AudioGroupSampleDirectory.hpp)
set(SOURCES
lib/AudioGroup.cpp
@ -45,7 +46,8 @@ set(SOURCES
lib/DSPCodec.cpp
lib/N64MusyXCodec.cpp
atdna_AudioGroupPool.cpp
atdna_AudioGroupProject.cpp)
atdna_AudioGroupProject.cpp
atdna_AudioGroupSampleDirectory.cpp)
set(HEADERS
include/amuse/AudioGroup.hpp

View File

@ -211,7 +211,6 @@ void MainWindow::importAction()
QFileInfo fInfo(path);
QString newPath = QFileInfo(fInfo.dir(), newName).filePath();
printf("%s\n", newPath.toUtf8().data());
if (!MkPath(fInfo.dir(), newName, this))
return;
if (!setProjectPath(newPath))
@ -227,7 +226,7 @@ void MainWindow::importAction()
auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(dir.filePath(fPath)).c_str());
for (auto& p : data)
if (!m_projectModel->importGroupData(SysStringToQString(p.first), std::move(p.second),
ProjectModel::ImportMode(impMode), this))
ProjectModel::ImportMode(impMode)))
return;
}
m_projectModel->saveToFile(this);
@ -256,7 +255,7 @@ void MainWindow::importAction()
auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(path).c_str());
for (auto& p : data)
if (!m_projectModel->importGroupData(SysStringToQString(p.first), std::move(p.second),
ProjectModel::ImportMode(impMode), this))
ProjectModel::ImportMode(impMode)))
return;
m_projectModel->saveToFile(this);
@ -328,7 +327,7 @@ void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
if (QLineEdit* le = qobject_cast<QLineEdit*>(now))
{
m_undoConn = connect(m_ui.actionUndo, SIGNAL(triggered()), le, SLOT(undo()));
m_canUndoConn = connect(le, SIGNAL(textChanged()), this, SLOT(onTextEdited()));
m_canUndoConn = connect(le, SIGNAL(textChanged(const QString&)), this, SLOT(onTextEdited()));
m_ui.actionUndo->setEnabled(le->isUndoAvailable());
m_redoConn = connect(m_ui.actionRedo, SIGNAL(triggered()), le, SLOT(redo()));
m_ui.actionRedo->setEnabled(le->isRedoAvailable());

View File

@ -17,111 +17,40 @@ ProjectModel::ProjectGroup::ProjectGroup(amuse::IntrusiveAudioGroupData&& data)
m_sdir(amuse::AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(m_data))
{}
bool ProjectModel::importGroupData(const QString& groupName,
amuse::IntrusiveAudioGroupData&& data,
ImportMode mode, QWidget* parent)
bool ProjectModel::importGroupData(const QString& groupName, amuse::IntrusiveAudioGroupData&& data, ImportMode mode)
{
amuse::SongId::CurNameDB = &m_songDb;
amuse::SongId::CurNameDB = &m_sfxDb;
setIdDatabases();
ProjectGroup& grp = m_groups.insert(std::make_pair(groupName, std::move(data))).first->second;
for (const auto& p : grp.m_proj.songGroups())
{
for (const auto& song : p.second.m_midiSetups)
{
char name[16];
snprintf(name, 16, "song%d", song.first.id);
m_songDb.registerPair(name, song.first);
}
}
for (const auto& p : grp.m_proj.sfxGroups())
{
for (const auto& sfx : p.second.m_sfxEntries)
{
char name[16];
snprintf(name, 16, "sfx%d", sfx.first.id);
m_sfxDb.registerPair(name, sfx.first);
}
}
grp.setIdDatabases();
amuse::AudioGroupProject::BootstrapObjectIDs(grp.m_data);
return true;
}
bool ProjectModel::saveToFile(QWidget* parent)
{
amuse::SongId::CurNameDB = &m_songDb;
amuse::SongId::CurNameDB = &m_sfxDb;
setIdDatabases();
if (!MkPath(m_dir.path(), parent))
return false;
for (auto& g : m_groups)
{
athena::io::YAMLDocWriter w("amuse::Group");
QDir dir(QFileInfo(m_dir, g.first).filePath());
if (!MkPath(dir.path(), parent))
return false;
if (auto __v = w.enterSubVector("songGroups"))
g.second.setIdDatabases();
{
for (const auto& p : g.second.m_proj.songGroups())
athena::io::FileWriter fo(QStringToSysString(dir.filePath("!project.yaml")));
g.second.m_proj.toYAML(fo);
}
{
if (auto __r = w.enterSubRecord(nullptr))
{
if (auto __v2 = w.enterSubRecord("normPages"))
{
for (const auto& pg : p.second.m_normPages)
{
char name[16];
snprintf(name, 16, "%d", pg.first);
if (auto __r2 = w.enterSubRecord(name))
pg.second.toDNA<athena::Big>(pg.first).write(w);
athena::io::FileWriter fo(QStringToSysString(dir.filePath("!pool.yaml")));
g.second.m_pool.toYAML(fo);
}
}
if (auto __v2 = w.enterSubRecord("drumPages"))
{
for (const auto& pg : p.second.m_drumPages)
{
char name[16];
snprintf(name, 16, "%d", pg.first);
if (auto __r2 = w.enterSubRecord(name))
pg.second.toDNA<athena::Big>(pg.first).write(w);
}
}
if (auto __v2 = w.enterSubRecord("songs"))
{
for (const auto& song : p.second.m_midiSetups)
{
if (auto __v3 = w.enterSubVector(m_songDb.resolveNameFromId(song.first).data()))
for (int i = 0; i < 16; ++i)
if (auto __r2 = w.enterSubRecord(nullptr))
song.second[i].write(w);
}
}
}
}
}
if (auto __v = w.enterSubVector("sfxGroups"))
{
for (const auto& p : g.second.m_proj.sfxGroups())
{
if (auto __r = w.enterSubRecord(nullptr))
{
for (const auto& sfx : p.second.m_sfxEntries)
{
if (auto __r2 = w.enterSubRecord(m_sfxDb.resolveNameFromId(sfx.first).data()))
sfx.second.toDNA<athena::Big>(sfx.first).write(w);
}
}
}
}
athena::io::FileWriter fo(QStringToSysString(dir.filePath("project.yaml")));
w.finish(&fo);
//g.second.m_sdir.sampleEntries()
}
return true;

View File

@ -25,8 +25,21 @@ public:
amuse::AudioGroupProject m_proj;
amuse::AudioGroupPool m_pool;
amuse::AudioGroupSampleDirectory m_sdir;
amuse::NameDB m_soundMacroDb;
amuse::NameDB m_sampleDb;
amuse::NameDB m_tableDb;
amuse::NameDB m_keymapDb;
amuse::NameDB m_layersDb;
explicit ProjectGroup(amuse::IntrusiveAudioGroupData&& data);
void setIdDatabases()
{
amuse::SoundMacroId::CurNameDB = &m_soundMacroDb;
amuse::SampleId::CurNameDB = &m_sampleDb;
amuse::TableId::CurNameDB = &m_tableDb;
amuse::KeymapId::CurNameDB = &m_keymapDb;
amuse::LayersId::CurNameDB = &m_layersDb;
}
};
private:
@ -36,11 +49,16 @@ private:
amuse::NameDB m_sfxDb;
std::map<QString, ProjectGroup> m_groups;
void setIdDatabases()
{
amuse::SongId::CurNameDB = &m_songDb;
amuse::SFXId::CurNameDB = &m_sfxDb;
}
public:
explicit ProjectModel(const QString& path, QObject* parent = Q_NULLPTR);
bool importGroupData(const QString& groupName, amuse::IntrusiveAudioGroupData&& data,
ImportMode mode, QWidget* parent);
bool importGroupData(const QString& groupName, amuse::IntrusiveAudioGroupData&& data, ImportMode mode);
bool saveToFile(QWidget* parent);
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;

View File

@ -119,8 +119,12 @@ struct SoundMacro
AddIVars,
IfEqual = 0x70,
IfLess,
Invalid = 0xff
};
static std::string_view CmdOpToStr(CmdOp op);
static CmdOp CmdStrToOp(std::string_view op);
/** Base command interface. All versions of MusyX encode little-endian parameters */
struct ICmd : LittleDNAV
{
@ -148,7 +152,7 @@ struct SoundMacro
AT_DECL_DNA_YAML
AT_DECL_DNAV
Value<atInt8> key;
ObjectIdDNA<athena::Little> macro;
SoundMacroIdDNA<athena::Little> macro;
Value<atUint16> macroStep;
bool Do(SoundMacroState& st, Voice& vox) const;
CmdOp Isa() const { return CmdOp::SplitKey; }
@ -158,7 +162,7 @@ struct SoundMacro
AT_DECL_DNA_YAML
AT_DECL_DNAV
Value<atInt8> velocity;
ObjectIdDNA<athena::Little> macro;
SoundMacroIdDNA<athena::Little> macro;
Value<atUint16> macroStep;
bool Do(SoundMacroState& st, Voice& vox) const;
CmdOp Isa() const { return CmdOp::SplitVel; }
@ -193,7 +197,7 @@ struct SoundMacro
AT_DECL_DNA_YAML
AT_DECL_DNAV
Seek<1, athena::SeekOrigin::Current> dummy;
ObjectIdDNA<athena::Little> macro;
SoundMacroIdDNA<athena::Little> macro;
Value<atUint16> macroStep;
bool Do(SoundMacroState& st, Voice& vox) const;
CmdOp Isa() const { return CmdOp::Goto; }
@ -216,7 +220,7 @@ struct SoundMacro
AT_DECL_DNA_YAML
AT_DECL_DNAV
Value<atInt8> addNote;
ObjectIdDNA<athena::Little> macro;
SoundMacroIdDNA<athena::Little> macro;
Value<atUint16> macroStep;
Value<atUint8> priority;
Value<atUint8> maxVoices;
@ -237,7 +241,7 @@ struct SoundMacro
AT_DECL_DNA_YAML
AT_DECL_DNAV
Value<atInt8> modValue;
ObjectIdDNA<athena::Little> macro;
SoundMacroIdDNA<athena::Little> macro;
Value<atUint16> macroStep;
Value<atUint8> priority;
Value<atUint8> maxVoices;
@ -258,7 +262,7 @@ struct SoundMacro
{
AT_DECL_DNA_YAML
AT_DECL_DNAV
ObjectIdDNA<athena::Little> table;
TableIdDNA<athena::Little> table;
Value<bool> dlsMode;
bool Do(SoundMacroState& st, Voice& vox) const;
CmdOp Isa() const { return CmdOp::SetAdsr; }
@ -269,7 +273,7 @@ struct SoundMacro
AT_DECL_DNAV
Value<atInt8> scale;
Value<atInt8> add;
ObjectIdDNA<athena::Little> table;
TableIdDNA<athena::Little> table;
Value<bool> originalVol;
bool Do(SoundMacroState& st, Voice& vox) const;
CmdOp Isa() const { return CmdOp::ScaleVolume; }
@ -290,7 +294,7 @@ struct SoundMacro
AT_DECL_DNAV
Value<atInt8> scale;
Value<atInt8> add;
ObjectIdDNA<athena::Little> table;
TableIdDNA<athena::Little> table;
Value<bool> msSwitch;
Value<atUint16> fadeTime;
bool Do(SoundMacroState& st, Voice& vox) const;
@ -325,7 +329,7 @@ struct SoundMacro
AT_DECL_DNA_YAML
AT_DECL_DNAV
Value<atUint8> rnd;
ObjectIdDNA<athena::Little> macro;
SoundMacroIdDNA<athena::Little> macro;
Value<atUint16> macroStep;
bool Do(SoundMacroState& st, Voice& vox) const;
CmdOp Isa() const { return CmdOp::SplitRnd; }
@ -336,7 +340,7 @@ struct SoundMacro
AT_DECL_DNAV
Value<atInt8> scale;
Value<atInt8> add;
ObjectIdDNA<athena::Little> table;
TableIdDNA<athena::Little> table;
Value<bool> msSwitch;
Value<atUint16> ticksPerMs;
bool Do(SoundMacroState& st, Voice& vox) const;
@ -474,7 +478,7 @@ struct SoundMacro
{
AT_DECL_DNA_YAML
AT_DECL_DNAV
ObjectIdDNA<athena::Little> table;
TableIdDNA<athena::Little> table;
Seek<1, athena::SeekOrigin::Current> seek;
Value<atInt8> keys;
Value<atInt8> cents;
@ -521,7 +525,7 @@ struct SoundMacro
AT_DECL_DNA_YAML
AT_DECL_DNAV
Seek<1, athena::SeekOrigin::Current> seek;
ObjectIdDNA<athena::Little> macro;
SoundMacroIdDNA<athena::Little> macro;
Value<atUint16> macroStep;
bool Do(SoundMacroState& st, Voice& vox) const;
CmdOp Isa() const { return CmdOp::GoSub; }
@ -531,7 +535,7 @@ struct SoundMacro
AT_DECL_DNA_YAML
AT_DECL_DNAV
Value<atUint8> event;
ObjectIdDNA<athena::Little> macro;
SoundMacroIdDNA<athena::Little> macro;
Value<atUint16> macroStep;
bool Do(SoundMacroState& st, Voice& vox) const;
CmdOp Isa() const { return CmdOp::TrapEvent; }
@ -549,7 +553,7 @@ struct SoundMacro
AT_DECL_DNA_YAML
AT_DECL_DNAV
Value<bool> isVar;
ObjectIdDNA<athena::Little> macro;
SoundMacroIdDNA<athena::Little> macro;
Value<atUint8> vid;
Value<atUint8> variable;
bool Do(SoundMacroState& st, Voice& vox) const;
@ -1031,19 +1035,51 @@ struct Curve : ITable
/** Maps individual MIDI keys to sound-entity as indexed in table
* (macro-voice, keymap, layer) */
struct Keymap : LittleDNA
template <athena::Endian DNAEn>
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
KeymapDNA : BigDNA
{
AT_DECL_DNA_YAML
AT_DECL_DNA
SoundMacroIdDNA<DNAEn> macro;
Value<atInt8> transpose;
Value<atInt8> pan; /* -128 for surround-channel only */
Value<atInt8> prioOffset;
Seek<3, athena::Current> pad;
};
/** Maps ranges of MIDI keys to sound-entity (macro-voice, keymap, layer) */
struct LayerMapping : LittleDNA
struct Keymap : BigDNA
{
AT_DECL_DNA_YAML
SoundMacroIdDNA<athena::Big> macro;
Value<atInt8> transpose;
Value<atInt8> pan; /* -128 for surround-channel only */
Value<atInt8> prioOffset;
Keymap() = default;
template <athena::Endian DNAE>
Keymap(const KeymapDNA<DNAE>& in)
: macro(in.macro.id), transpose(in.transpose), pan(in.pan),
prioOffset(in.prioOffset) {}
template <athena::Endian DNAEn>
KeymapDNA<DNAEn> toDNA() const
{
KeymapDNA<DNAEn> ret;
ret.macro.id = macro;
ret.transpose = transpose;
ret.pan = pan;
ret.prioOffset = prioOffset;
return ret;
}
};
/** Maps ranges of MIDI keys to sound-entity (macro-voice, keymap, layer) */
template <athena::Endian DNAEn>
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
LayerMappingDNA : BigDNA
{
AT_DECL_DNA
SoundMacroIdDNA<DNAEn> macro;
Value<atInt8> keyLo;
Value<atInt8> keyHi;
Value<atInt8> transpose;
@ -1051,6 +1087,42 @@ struct LayerMapping : LittleDNA
Value<atInt8> prioOffset;
Value<atInt8> span;
Value<atInt8> pan;
Seek<3, athena::Current> pad;
};
struct LayerMapping : BigDNA
{
AT_DECL_DNA_YAML
SoundMacroIdDNA<athena::Big> macro;
Value<atInt8> keyLo;
Value<atInt8> keyHi;
Value<atInt8> transpose;
Value<atInt8> volume;
Value<atInt8> prioOffset;
Value<atInt8> span;
Value<atInt8> pan;
LayerMapping() = default;
template <athena::Endian DNAE>
LayerMapping(const LayerMappingDNA<DNAE>& in)
: macro(in.macro.id), keyLo(in.keyLo), keyHi(in.keyHi),
transpose(in.transpose), volume(in.volume), prioOffset(in.prioOffset),
span(in.span), pan(in.pan) {}
template <athena::Endian DNAEn>
LayerMappingDNA<DNAEn> toDNA() const
{
LayerMappingDNA<DNAEn> ret;
ret.macro.id = macro;
ret.keyLo = keyLo;
ret.keyHi = keyHi;
ret.transpose = transpose;
ret.volume = volume;
ret.prioOffset = prioOffset;
ret.span = span;
ret.pan = pan;
return ret;
}
};
/** Database of functional objects within Audio Group */
@ -1073,6 +1145,8 @@ public:
const ADSR* tableAsAdsr(ObjectId id) const;
const ADSRDLS* tableAsAdsrDLS(ObjectId id) const { return reinterpret_cast<const ADSRDLS*>(tableAsAdsr(id)); }
const Curve* tableAsCurves(ObjectId id) const { return reinterpret_cast<const Curve*>(tableAsAdsr(id)); }
bool toYAML(athena::io::IStreamWriter& w) const;
};
}

View File

@ -49,7 +49,7 @@ struct SongGroupIndex : AudioGroupIndex
PageEntryDNA : BigDNA
{
AT_DECL_DNA_YAML
ObjectIdDNA<DNAEn> objId;
PageObjectIdDNA<DNAEn> objId;
Value<atUint8> priority;
Value<atUint8> maxVoices;
Value<atUint8> programNo;
@ -59,19 +59,20 @@ struct SongGroupIndex : AudioGroupIndex
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
MusyX1PageEntryDNA : BigDNA
{
AT_DECL_DNA_YAML
ObjectIdDNA<DNAEn> objId;
AT_DECL_DNA
PageObjectIdDNA<DNAEn> objId;
Value<atUint8> priority;
Value<atUint8> maxVoices;
Value<atUint8> unk;
Value<atUint8> programNo;
Seek<2, athena::Current> pad;
};
struct PageEntry
struct PageEntry : BigDNA
{
ObjectId objId;
atUint8 priority;
atUint8 maxVoices;
AT_DECL_DNA_YAML
PageObjectIdDNA<athena::Big> objId;
Value<atUint8> priority;
Value<atUint8> maxVoices;
PageEntry() = default;
@ -87,7 +88,7 @@ struct SongGroupIndex : AudioGroupIndex
PageEntryDNA<DNAEn> toDNA(uint8_t programNo) const
{
PageEntryDNA<DNAEn> ret;
ret.objId.id = objId;
ret.objId = objId;
ret.priority = priority;
ret.maxVoices = maxVoices;
ret.programNo = programNo;
@ -132,9 +133,9 @@ struct SFXGroupIndex : AudioGroupIndex
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
SFXEntryDNA : BigDNA
{
AT_DECL_DNA_YAML
SFXIdDNA<DNAEn> defineId;
ObjectIdDNA<DNAEn> objId;
AT_DECL_DNA
SFXIdDNA<DNAEn> sfxId;
SoundMacroIdDNA<DNAEn> macro;
Value<atUint8> priority;
Value<atUint8> maxVoices;
Value<atUint8> defVel;
@ -142,28 +143,29 @@ struct SFXGroupIndex : AudioGroupIndex
Value<atUint8> defKey;
Seek<1, athena::Current> pad;
};
struct SFXEntry
struct SFXEntry : BigDNA
{
ObjectId objId;
atUint8 priority;
atUint8 maxVoices;
atUint8 defVel;
atUint8 panning;
atUint8 defKey;
AT_DECL_DNA_YAML
SoundMacroIdDNA<athena::Big> macro;
Value<atUint8> priority;
Value<atUint8> maxVoices;
Value<atUint8> defVel;
Value<atUint8> panning;
Value<atUint8> defKey;
SFXEntry() = default;
template <athena::Endian DNAE>
SFXEntry(const SFXEntryDNA<DNAE>& in)
: objId(in.objId.id), priority(in.priority), maxVoices(in.maxVoices),
: macro(in.macro.id), priority(in.priority), maxVoices(in.maxVoices),
defVel(in.defVel), panning(in.panning), defKey(in.defKey) {}
template <athena::Endian DNAEn>
SFXEntryDNA<DNAEn> toDNA(SFXId defineId) const
SFXEntryDNA<DNAEn> toDNA(SFXId id) const
{
SFXEntryDNA<DNAEn> ret;
ret.defineId.id = defineId;
ret.objId.id = objId;
ret.sfxId.id = id;
ret.macro = macro;
ret.priority = priority;
ret.maxVoices = maxVoices;
ret.defVel = defVel;
@ -185,14 +187,21 @@ class AudioGroupProject
AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag);
template <athena::Endian DNAE>
static AudioGroupProject _AudioGroupProject(athena::io::IStreamReader& r, bool absOffs);
static void BootstrapObjectIDs(athena::io::IStreamReader& r, GCNDataTag);
template <athena::Endian DNAE>
static void BootstrapObjectIDs(athena::io::IStreamReader& r, bool absOffs);
public:
static AudioGroupProject CreateAudioGroupProject(const AudioGroupData& data);
static void BootstrapObjectIDs(const AudioGroupData& data);
const SongGroupIndex* getSongGroupIndex(int groupId) const;
const SFXGroupIndex* getSFXGroupIndex(int groupId) const;
const std::unordered_map<int, SongGroupIndex>& songGroups() const { return m_songGroups; }
const std::unordered_map<int, SFXGroupIndex>& sfxGroups() const { return m_sfxGroups; }
bool toYAML(athena::io::IStreamWriter& w) const;
};
}

View File

@ -15,19 +15,106 @@ class AudioGroupSampleDirectory
friend class AudioGroup;
public:
enum class SampleFormat : atUint8
{
DSP,
DSP2,
PCM,
N64
};
template <athena::Endian DNAEn>
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
EntryDNA : BigDNA
{
AT_DECL_DNA
SFXIdDNA<DNAEn> m_sfxId;
Value<atUint32, DNAEn> m_sampleOff;
Value<atUint32, DNAEn> m_unk;
Value<atUint8, DNAEn> m_pitch;
Seek<1, athena::Current> pad;
Value<atUint16, DNAEn> m_sampleRate;
Value<atUint32, DNAEn> m_numSamples; // Top 8 bits is SampleFormat
Value<atUint32, DNAEn> m_loopStartSample;
Value<atUint32, DNAEn> m_loopLengthSamples;
Value<atUint32, DNAEn> m_adpcmParmOffset;
};
template <athena::Endian DNAEn>
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
MusyX1SdirEntry : BigDNA
{
AT_DECL_DNA
SFXIdDNA<DNAEn> m_sfxId;
Value<atUint32, DNAEn> m_sampleOff;
Value<atUint32, DNAEn> m_pitchSampleRate;
Value<atUint32, DNAEn> m_numSamples;
Value<atUint32, DNAEn> m_loopStartSample;
Value<atUint32, DNAEn> m_loopLengthSamples;
};
template <athena::Endian DNAEn>
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
MusyX1AbsSdirEntry : BigDNA
{
AT_DECL_DNA
SFXIdDNA<DNAEn> m_sfxId;
Value<uint32_t, DNAEn> m_sampleOff;
Value<uint32_t, DNAEn> m_unk;
Value<uint32_t, DNAEn> m_pitchSampleRate;
Value<uint32_t, DNAEn> m_numSamples;
Value<uint32_t, DNAEn> m_loopStartSample;
Value<uint32_t, DNAEn> m_loopLengthSamples;
};
struct Entry
{
uint16_t m_sfxId;
uint32_t m_sampleOff;
uint32_t m_unk;
uint8_t m_pitch;
uint16_t m_sampleRate;
uint32_t m_numSamples;
uint32_t m_loopStartSample;
uint32_t m_loopLengthSamples;
uint32_t m_adpcmParmOffset;
void swapBig();
atUint32 m_sampleOff;
atUint32 m_unk;
atUint8 m_pitch;
atUint16 m_sampleRate;
atUint32 m_numSamples; // Top 8 bits is SampleFormat
atUint32 m_loopStartSample;
atUint32 m_loopLengthSamples;
atUint32 m_adpcmParmOffset;
Entry() = default;
template <athena::Endian DNAE>
Entry(const EntryDNA<DNAE>& in)
: 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_loopStartSample(in.m_loopStartSample), m_loopLengthSamples(in.m_loopLengthSamples),
m_adpcmParmOffset(in.m_adpcmParmOffset) {}
template <athena::Endian DNAE>
Entry(const MusyX1SdirEntry<DNAE>& in)
: 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_loopStartSample(in.m_loopStartSample), m_loopLengthSamples(in.m_loopLengthSamples),
m_adpcmParmOffset(0) {}
template <athena::Endian DNAE>
Entry(const MusyX1AbsSdirEntry<DNAE>& in)
: 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_loopStartSample(in.m_loopStartSample), m_loopLengthSamples(in.m_loopLengthSamples),
m_adpcmParmOffset(0) {}
template <athena::Endian DNAEn>
EntryDNA<DNAEn> toDNA(SFXId id) const
{
EntryDNA<DNAEn> ret;
ret.m_sfxId.id = id;
ret.m_sampleOff = m_sampleOff;
ret.m_unk = m_unk;
ret.m_pitch = m_pitch;
ret.m_sampleRate = m_sampleRate;
ret.m_numSamples = m_numSamples;
ret.m_loopStartSample = m_loopStartSample;
ret.m_loopLengthSamples = m_loopLengthSamples;
ret.m_adpcmParmOffset = m_adpcmParmOffset;
return ret;
}
};
union ADPCMParms {
struct DSPParms
{
@ -47,15 +134,15 @@ public:
};
private:
std::unordered_map<uint16_t, std::pair<Entry, ADPCMParms>> m_entries;
std::unordered_map<SFXId, std::pair<Entry, ADPCMParms>> m_entries;
public:
AudioGroupSampleDirectory(const unsigned char* data, GCNDataTag);
AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData, bool absOffs, N64DataTag);
AudioGroupSampleDirectory(const unsigned char* data, bool absOffs, PCDataTag);
AudioGroupSampleDirectory(athena::io::IStreamReader& r, GCNDataTag);
AudioGroupSampleDirectory(athena::io::IStreamReader& r, const unsigned char* sampData, bool absOffs, N64DataTag);
AudioGroupSampleDirectory(athena::io::IStreamReader& r, bool absOffs, PCDataTag);
static AudioGroupSampleDirectory CreateAudioGroupSampleDirectory(const AudioGroupData& data);
const std::unordered_map<uint16_t, std::pair<Entry, ADPCMParms>>& sampleEntries() const { return m_entries; }
const std::unordered_map<SFXId, std::pair<Entry, ADPCMParms>>& sampleEntries() const { return m_entries; }
};
}

View File

@ -37,7 +37,7 @@ using BigDNAV = athena::io::DNAVYaml<athena::Big>;
using LittleDNAV = athena::io::DNAVYaml<athena::Little>;
/** Common ID structure statically tagging
* SoundMacros, Tables, Keymaps, Layers */
* SoundMacros, Tables, Keymaps, Layers, Samples, SFX, Songs */
struct ObjectId
{
uint16_t id = 0xffff;
@ -47,7 +47,6 @@ struct ObjectId
ObjectId& operator=(uint16_t idIn) { id = idIn; return *this; }
static thread_local NameDB* CurNameDB;
};
template <athena::Endian DNAEn>
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
ObjectIdDNA : BigDNA
@ -56,57 +55,52 @@ ObjectIdDNA : BigDNA
void _read(athena::io::YAMLDocReader& r);
void _write(athena::io::YAMLDocWriter& w);
ObjectId id;
ObjectIdDNA() = default;
ObjectIdDNA(ObjectId idIn) : id(idIn) {}
operator ObjectId() const { return id; }
};
struct SampleId : ObjectId
{
using ObjectId::ObjectId;
SampleId(const ObjectId& id) : ObjectId(id) {}
static thread_local NameDB* CurNameDB;
#define DECL_ID_TYPE(type) \
struct type : ObjectId \
{ \
using ObjectId::ObjectId; \
type(const ObjectId& id) : ObjectId(id) {} \
static thread_local NameDB* CurNameDB; \
}; \
template <athena::Endian DNAEn> \
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little) \
type##DNA : BigDNA \
{ \
AT_DECL_EXPLICIT_DNA_YAML \
void _read(athena::io::YAMLDocReader& r); \
void _write(athena::io::YAMLDocWriter& w); \
type id; \
type##DNA() = default; \
type##DNA(type idIn) : id(idIn) {} \
operator type() const { return id; } \
};
DECL_ID_TYPE(SoundMacroId)
DECL_ID_TYPE(SampleId)
DECL_ID_TYPE(TableId)
DECL_ID_TYPE(KeymapId)
DECL_ID_TYPE(LayersId)
DECL_ID_TYPE(SongId)
DECL_ID_TYPE(SFXId)
/* MusyX has object polymorphism between Keymaps and Layers when
* referenced by a song group's page object. When the upper bit is set,
* this indicates a layer type. */
template <athena::Endian DNAEn>
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
SampleIdDNA : BigDNA
PageObjectIdDNA : BigDNA
{
AT_DECL_EXPLICIT_DNA_YAML
void _read(athena::io::YAMLDocReader& r);
void _write(athena::io::YAMLDocWriter& w);
SampleId id;
};
struct SongId : ObjectId
{
using ObjectId::ObjectId;
SongId(const ObjectId& id) : ObjectId(id) {}
static thread_local NameDB* CurNameDB;
};
template <athena::Endian DNAEn>
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
SongIdDNA : BigDNA
{
AT_DECL_EXPLICIT_DNA_YAML
void _read(athena::io::YAMLDocReader& r);
void _write(athena::io::YAMLDocWriter& w);
SongId id;
};
struct SFXId : ObjectId
{
using ObjectId::ObjectId;
SFXId(const ObjectId& id) : ObjectId(id) {}
static thread_local NameDB* CurNameDB;
};
template <athena::Endian DNAEn>
struct AT_SPECIALIZE_PARMS(athena::Endian::Big, athena::Endian::Little)
SFXIdDNA : BigDNA
{
AT_DECL_EXPLICIT_DNA_YAML
void _read(athena::io::YAMLDocReader& r);
void _write(athena::io::YAMLDocWriter& w);
SFXId id;
ObjectId id;
PageObjectIdDNA() = default;
PageObjectIdDNA(ObjectId idIn) : id(idIn) {}
operator ObjectId() const { return id; }
};
struct LittleUInt24 : LittleDNA
@ -422,30 +416,34 @@ struct N64DataTag
struct PCDataTag
{
};
template <class T>
static std::vector<std::pair<typename T::key_type,
std::reference_wrapper<const typename T::mapped_type>>> SortUnorderedMap(const T& um)
{
std::vector<std::pair<typename T::key_type,
std::reference_wrapper<const typename T::mapped_type>>> ret(um.cbegin(), um.cend());
std::sort(ret.begin(), ret.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
return ret;
}
}
namespace std
{
template<>
struct hash<amuse::ObjectId>
{
size_t operator()(const amuse::ObjectId& val) const noexcept { return val.id; }
};
template<>
struct hash<amuse::SampleId>
{
size_t operator()(const amuse::SampleId& val) const noexcept { return val.id; }
};
template<>
struct hash<amuse::SongId>
{
size_t operator()(const amuse::SongId& val) const noexcept { return val.id; }
};
template<>
struct hash<amuse::SFXId>
{
size_t operator()(const amuse::SFXId& val) const noexcept { return val.id; }
#define DECL_ID_HASH(type) \
template<> \
struct hash<amuse::type> \
{ \
size_t operator()(const amuse::type& val) const noexcept { return val.id; } \
};
DECL_ID_HASH(ObjectId)
DECL_ID_HASH(SoundMacroId)
DECL_ID_HASH(SampleId)
DECL_ID_HASH(TableId)
DECL_ID_HASH(KeymapId)
DECL_ID_HASH(LayersId)
DECL_ID_HASH(SongId)
DECL_ID_HASH(SFXId)
}
namespace amuse
@ -454,17 +452,20 @@ struct NameDB
{
enum class Type
{
SoundMacro = 0,
Table = 1,
Keymap = 4,
Layer = 8
SoundMacro,
Table,
Keymap,
Layer,
Song,
SFX,
Sample
};
std::unordered_map<std::string, ObjectId> m_stringToId;
std::unordered_map<ObjectId, std::string> m_idToString;
ObjectId generateId(Type tp);
static std::string generateName(ObjectId id);
static std::string generateName(ObjectId id, Type tp);
std::string_view registerPair(std::string_view str, ObjectId id);
std::string_view resolveNameFromId(ObjectId id) const;
ObjectId resolveIdFromName(std::string_view str) const;

View File

@ -171,11 +171,11 @@ class Voice : public Entity
std::list<std::shared_ptr<Voice>>::iterator _allocateVoice(double sampleRate, bool dynamicPitch);
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it);
bool _loadSoundMacro(ObjectId 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);
bool _loadKeymap(ObjectId id, const Keymap* keymap, int macroStep, double ticksPerSec, uint8_t midiKey,
bool _loadKeymap(const Keymap* keymap, double ticksPerSec, uint8_t midiKey,
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
bool _loadLayer(ObjectId id, const std::vector<LayerMapping>& layer, int macroStep, double ticksPerSec,
bool _loadLayer(const std::vector<LayerMapping>& layer, double ticksPerSec,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
std::shared_ptr<Voice> _startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
@ -222,10 +222,13 @@ public:
/** Allocate parallel macro and tie to voice for possible emitter influence */
std::shared_ptr<Voice> startChildMacro(int8_t addNote, ObjectId macroId, int macroStep);
/** Load specified Sound Object from within group into voice */
bool loadSoundObject(ObjectId objectId, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
/** Load specified SoundMacro Object from within group into voice */
bool loadMacroObject(SoundMacroId macroId, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
uint8_t midiMod, bool pushPc = false);
/** Load specified song page object (Keymap/Layer) from within group into voice */
bool loadPageObject(ObjectId objectId, double ticksPerSec, uint8_t midiKey, uint8_t midiVel, uint8_t midiMod);
/** Signals voice to begin fade-out (or defer if sustained), eventually reaching silence */
void keyOff();

View File

@ -7,7 +7,7 @@ namespace amuse
AudioGroup::AudioGroup(const AudioGroupData& data, GCNDataTag)
: m_proj(AudioGroupProject::CreateAudioGroupProject(data))
, m_pool(AudioGroupPool::CreateAudioGroupPool(data))
, m_sdir(data.getSdir(), GCNDataTag{})
, m_sdir(AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(data))
, m_samp(data.getSamp())
, m_fmt(DataFormat::GCN)
{
@ -16,7 +16,7 @@ AudioGroup::AudioGroup(const AudioGroupData& data, GCNDataTag)
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag)
: m_proj(AudioGroupProject::CreateAudioGroupProject(data))
, m_pool(AudioGroupPool::CreateAudioGroupPool(data))
, m_sdir(data.getSdir(), data.getSamp(), absOffs, N64DataTag{})
, m_sdir(AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(data))
, m_samp(data.getSamp())
, m_fmt(DataFormat::N64)
{
@ -25,7 +25,7 @@ AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag)
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag)
: m_proj(AudioGroupProject::CreateAudioGroupProject(data))
, m_pool(AudioGroupPool::CreateAudioGroupPool(data))
, m_sdir(data.getSdir(), absOffs, PCDataTag{})
, m_sdir(AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(data))
, m_samp(data.getSamp())
, m_fmt(DataFormat::PC)
{

View File

@ -5,6 +5,8 @@
#include "athena/MemoryReader.hpp"
#include "logvisor/logvisor.hpp"
using namespace std::literals;
namespace amuse
{
static logvisor::Module Log("amuse::AudioGroupPool");
@ -75,8 +77,9 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
ObjectHeader<DNAE> objHead;
atInt64 startPos = r.position();
objHead.read(r);
Keymap& km = ret.m_keymaps[objHead.objectId.id];
km.read(r);
KeymapDNA<DNAE> kmData;
kmData.read(r);
ret.m_keymaps[objHead.objectId.id] = kmData;
r.seek(startPos + objHead.size, athena::Begin);
}
}
@ -95,8 +98,9 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
lm.reserve(count);
for (uint32_t i = 0; i < count; ++i)
{
lm.emplace_back();
lm.back().read(r);
LayerMappingDNA<DNAE> lmData;
lmData.read(r);
lm.push_back(lmData);
}
r.seek(startPos + objHead.size, athena::Begin);
}
@ -347,6 +351,408 @@ const ADSR* AudioGroupPool::tableAsAdsr(ObjectId id) const
return static_cast<const ADSR*>(search->second.get());
}
std::string_view SoundMacro::CmdOpToStr(CmdOp op)
{
switch (op)
{
case CmdOp::End:
return "End"sv;
case CmdOp::Stop:
return "Stop"sv;
case CmdOp::SplitKey:
return "SplitKey"sv;
case CmdOp::SplitVel:
return "SplitVel"sv;
case CmdOp::WaitTicks:
return "WaitTicks"sv;
case CmdOp::Loop:
return "Loop"sv;
case CmdOp::Goto:
return "Goto"sv;
case CmdOp::WaitMs:
return "WaitMs"sv;
case CmdOp::PlayMacro:
return "PlayMacro"sv;
case CmdOp::SendKeyOff:
return "SendKeyOff"sv;
case CmdOp::SplitMod:
return "SplitMod"sv;
case CmdOp::PianoPan:
return "PianoPan"sv;
case CmdOp::SetAdsr:
return "SetAdsr"sv;
case CmdOp::ScaleVolume:
return "ScaleVolume"sv;
case CmdOp::Panning:
return "Panning"sv;
case CmdOp::Envelope:
return "Envelope"sv;
case CmdOp::StartSample:
return "StartSample"sv;
case CmdOp::StopSample:
return "StopSample"sv;
case CmdOp::KeyOff:
return "KeyOff"sv;
case CmdOp::SplitRnd:
return "SplitRnd"sv;
case CmdOp::FadeIn:
return "FadeIn"sv;
case CmdOp::Spanning:
return "Spanning"sv;
case CmdOp::SetAdsrCtrl:
return "SetAdsrCtrl"sv;
case CmdOp::RndNote:
return "RndNote"sv;
case CmdOp::AddNote:
return "AddNote"sv;
case CmdOp::SetNote:
return "SetNote"sv;
case CmdOp::LastNote:
return "LastNote"sv;
case CmdOp::Portamento:
return "Portamento"sv;
case CmdOp::Vibrato:
return "Vibrato"sv;
case CmdOp::PitchSweep1:
return "PitchSweep1"sv;
case CmdOp::PitchSweep2:
return "PitchSweep2"sv;
case CmdOp::SetPitch:
return "SetPitch"sv;
case CmdOp::SetPitchAdsr:
return "SetPitchAdsr"sv;
case CmdOp::ScaleVolumeDLS:
return "ScaleVolumeDLS"sv;
case CmdOp::Mod2Vibrange:
return "Mod2Vibrange"sv;
case CmdOp::SetupTremolo:
return "SetupTremolo"sv;
case CmdOp::Return:
return "Return"sv;
case CmdOp::GoSub:
return "GoSub"sv;
case CmdOp::TrapEvent:
return "TrapEvent"sv;
case CmdOp::UntrapEvent:
return "UntrapEvent"sv;
case CmdOp::SendMessage:
return "SendMessage"sv;
case CmdOp::GetMessage:
return "GetMessage"sv;
case CmdOp::GetVid:
return "GetVid"sv;
case CmdOp::AddAgeCount:
return "AddAgeCount"sv;
case CmdOp::SetAgeCount:
return "SetAgeCount"sv;
case CmdOp::SendFlag:
return "SendFlag"sv;
case CmdOp::PitchWheelR:
return "PitchWheelR"sv;
case CmdOp::SetPriority:
return "SetPriority"sv;
case CmdOp::AddPriority:
return "AddPriority"sv;
case CmdOp::AgeCntSpeed:
return "AgeCntSpeed"sv;
case CmdOp::AgeCntVel:
return "AgeCntVel"sv;
case CmdOp::VolSelect:
return "VolSelect"sv;
case CmdOp::PanSelect:
return "PanSelect"sv;
case CmdOp::PitchWheelSelect:
return "PitchWheelSelect"sv;
case CmdOp::ModWheelSelect:
return "ModWheelSelect"sv;
case CmdOp::PedalSelect:
return "PedalSelect"sv;
case CmdOp::PortamentoSelect:
return "PortamentoSelect"sv;
case CmdOp::ReverbSelect:
return "ReverbSelect"sv;
case CmdOp::SpanSelect:
return "SpanSelect"sv;
case CmdOp::DopplerSelect:
return "DopplerSelect"sv;
case CmdOp::TremoloSelect:
return "TremoloSelect"sv;
case CmdOp::PreASelect:
return "PreASelect"sv;
case CmdOp::PreBSelect:
return "PreBSelect"sv;
case CmdOp::PostBSelect:
return "PostBSelect"sv;
case CmdOp::AuxAFXSelect:
return "AuxAFXSelect"sv;
case CmdOp::AuxBFXSelect:
return "AuxBFXSelect"sv;
case CmdOp::SetupLFO:
return "SetupLFO"sv;
case CmdOp::ModeSelect:
return "ModeSelect"sv;
case CmdOp::SetKeygroup:
return "SetKeygroup"sv;
case CmdOp::SRCmodeSelect:
return "SRCmodeSelect"sv;
case CmdOp::AddVars:
return "AddVars"sv;
case CmdOp::SubVars:
return "SubVars"sv;
case CmdOp::MulVars:
return "MulVars"sv;
case CmdOp::DivVars:
return "DivVars"sv;
case CmdOp::AddIVars:
return "AddIVars"sv;
case CmdOp::IfEqual:
return "IfEqual"sv;
case CmdOp::IfLess:
return "IfLess"sv;
default:
return ""sv;
}
}
SoundMacro::CmdOp SoundMacro::CmdStrToOp(std::string_view op)
{
if (!CompareCaseInsensitive(op.data(), "End"))
return CmdOp::End;
else if (!CompareCaseInsensitive(op.data(), "Stop"))
return CmdOp::Stop;
else if (!CompareCaseInsensitive(op.data(), "SplitKey"))
return CmdOp::SplitKey;
else if (!CompareCaseInsensitive(op.data(), "SplitVel"))
return CmdOp::SplitVel;
else if (!CompareCaseInsensitive(op.data(), "WaitTicks"))
return CmdOp::WaitTicks;
else if (!CompareCaseInsensitive(op.data(), "Loop"))
return CmdOp::Loop;
else if (!CompareCaseInsensitive(op.data(), "Goto"))
return CmdOp::Goto;
else if (!CompareCaseInsensitive(op.data(), "WaitMs"))
return CmdOp::WaitMs;
else if (!CompareCaseInsensitive(op.data(), "PlayMacro"))
return CmdOp::PlayMacro;
else if (!CompareCaseInsensitive(op.data(), "SendKeyOff"))
return CmdOp::SendKeyOff;
else if (!CompareCaseInsensitive(op.data(), "SplitMod"))
return CmdOp::SplitMod;
else if (!CompareCaseInsensitive(op.data(), "PianoPan"))
return CmdOp::PianoPan;
else if (!CompareCaseInsensitive(op.data(), "SetAdsr"))
return CmdOp::SetAdsr;
else if (!CompareCaseInsensitive(op.data(), "ScaleVolume"))
return CmdOp::ScaleVolume;
else if (!CompareCaseInsensitive(op.data(), "Panning"))
return CmdOp::Panning;
else if (!CompareCaseInsensitive(op.data(), "Envelope"))
return CmdOp::Envelope;
else if (!CompareCaseInsensitive(op.data(), "StartSample"))
return CmdOp::StartSample;
else if (!CompareCaseInsensitive(op.data(), "StopSample"))
return CmdOp::StopSample;
else if (!CompareCaseInsensitive(op.data(), "KeyOff"))
return CmdOp::KeyOff;
else if (!CompareCaseInsensitive(op.data(), "SplitRnd"))
return CmdOp::SplitRnd;
else if (!CompareCaseInsensitive(op.data(), "FadeIn"))
return CmdOp::FadeIn;
else if (!CompareCaseInsensitive(op.data(), "Spanning"))
return CmdOp::Spanning;
else if (!CompareCaseInsensitive(op.data(), "SetAdsrCtrl"))
return CmdOp::SetAdsrCtrl;
else if (!CompareCaseInsensitive(op.data(), "RndNote"))
return CmdOp::RndNote;
else if (!CompareCaseInsensitive(op.data(), "AddNote"))
return CmdOp::AddNote;
else if (!CompareCaseInsensitive(op.data(), "SetNote"))
return CmdOp::SetNote;
else if (!CompareCaseInsensitive(op.data(), "LastNote"))
return CmdOp::LastNote;
else if (!CompareCaseInsensitive(op.data(), "Portamento"))
return CmdOp::Portamento;
else if (!CompareCaseInsensitive(op.data(), "Vibrato"))
return CmdOp::Vibrato;
else if (!CompareCaseInsensitive(op.data(), "PitchSweep1"))
return CmdOp::PitchSweep1;
else if (!CompareCaseInsensitive(op.data(), "PitchSweep2"))
return CmdOp::PitchSweep2;
else if (!CompareCaseInsensitive(op.data(), "SetPitch"))
return CmdOp::SetPitch;
else if (!CompareCaseInsensitive(op.data(), "SetPitchAdsr"))
return CmdOp::SetPitchAdsr;
else if (!CompareCaseInsensitive(op.data(), "ScaleVolumeDLS"))
return CmdOp::ScaleVolumeDLS;
else if (!CompareCaseInsensitive(op.data(), "Mod2Vibrange"))
return CmdOp::Mod2Vibrange;
else if (!CompareCaseInsensitive(op.data(), "SetupTremolo"))
return CmdOp::SetupTremolo;
else if (!CompareCaseInsensitive(op.data(), "Return"))
return CmdOp::Return;
else if (!CompareCaseInsensitive(op.data(), "GoSub"))
return CmdOp::GoSub;
else if (!CompareCaseInsensitive(op.data(), "TrapEvent"))
return CmdOp::TrapEvent;
else if (!CompareCaseInsensitive(op.data(), "UntrapEvent"))
return CmdOp::UntrapEvent;
else if (!CompareCaseInsensitive(op.data(), "SendMessage"))
return CmdOp::SendMessage;
else if (!CompareCaseInsensitive(op.data(), "GetMessage"))
return CmdOp::GetMessage;
else if (!CompareCaseInsensitive(op.data(), "GetVid"))
return CmdOp::GetVid;
else if (!CompareCaseInsensitive(op.data(), "AddAgeCount"))
return CmdOp::AddAgeCount;
else if (!CompareCaseInsensitive(op.data(), "SetAgeCount"))
return CmdOp::SetAgeCount;
else if (!CompareCaseInsensitive(op.data(), "SendFlag"))
return CmdOp::SendFlag;
else if (!CompareCaseInsensitive(op.data(), "PitchWheelR"))
return CmdOp::PitchWheelR;
else if (!CompareCaseInsensitive(op.data(), "SetPriority"))
return CmdOp::SetPriority;
else if (!CompareCaseInsensitive(op.data(), "AddPriority"))
return CmdOp::AddPriority;
else if (!CompareCaseInsensitive(op.data(), "AgeCntSpeed"))
return CmdOp::AgeCntSpeed;
else if (!CompareCaseInsensitive(op.data(), "AgeCntVel"))
return CmdOp::AgeCntVel;
else if (!CompareCaseInsensitive(op.data(), "VolSelect"))
return CmdOp::VolSelect;
else if (!CompareCaseInsensitive(op.data(), "PanSelect"))
return CmdOp::PanSelect;
else if (!CompareCaseInsensitive(op.data(), "PitchWheelSelect"))
return CmdOp::PitchWheelSelect;
else if (!CompareCaseInsensitive(op.data(), "ModWheelSelect"))
return CmdOp::ModWheelSelect;
else if (!CompareCaseInsensitive(op.data(), "PedalSelect"))
return CmdOp::PedalSelect;
else if (!CompareCaseInsensitive(op.data(), "PortamentoSelect"))
return CmdOp::PortamentoSelect;
else if (!CompareCaseInsensitive(op.data(), "ReverbSelect"))
return CmdOp::ReverbSelect;
else if (!CompareCaseInsensitive(op.data(), "SpanSelect"))
return CmdOp::SpanSelect;
else if (!CompareCaseInsensitive(op.data(), "DopplerSelect"))
return CmdOp::DopplerSelect;
else if (!CompareCaseInsensitive(op.data(), "TremoloSelect"))
return CmdOp::TremoloSelect;
else if (!CompareCaseInsensitive(op.data(), "PreASelect"))
return CmdOp::PreASelect;
else if (!CompareCaseInsensitive(op.data(), "PreBSelect"))
return CmdOp::PreBSelect;
else if (!CompareCaseInsensitive(op.data(), "PostBSelect"))
return CmdOp::PostBSelect;
else if (!CompareCaseInsensitive(op.data(), "AuxAFXSelect"))
return CmdOp::AuxAFXSelect;
else if (!CompareCaseInsensitive(op.data(), "AuxBFXSelect"))
return CmdOp::AuxBFXSelect;
else if (!CompareCaseInsensitive(op.data(), "SetupLFO"))
return CmdOp::SetupLFO;
else if (!CompareCaseInsensitive(op.data(), "ModeSelect"))
return CmdOp::ModeSelect;
else if (!CompareCaseInsensitive(op.data(), "SetKeygroup"))
return CmdOp::SetKeygroup;
else if (!CompareCaseInsensitive(op.data(), "SRCmodeSelect"))
return CmdOp::SRCmodeSelect;
else if (!CompareCaseInsensitive(op.data(), "AddVars"))
return CmdOp::AddVars;
else if (!CompareCaseInsensitive(op.data(), "SubVars"))
return CmdOp::SubVars;
else if (!CompareCaseInsensitive(op.data(), "MulVars"))
return CmdOp::MulVars;
else if (!CompareCaseInsensitive(op.data(), "DivVars"))
return CmdOp::DivVars;
else if (!CompareCaseInsensitive(op.data(), "AddIVars"))
return CmdOp::AddIVars;
else if (!CompareCaseInsensitive(op.data(), "IfEqual"))
return CmdOp::IfEqual;
else if (!CompareCaseInsensitive(op.data(), "IfLess"))
return CmdOp::IfLess;
return CmdOp::Invalid;
}
bool AudioGroupPool::toYAML(athena::io::IStreamWriter& writer) const
{
athena::io::YAMLDocWriter w("amuse::Pool");
if (!m_soundMacros.empty())
{
if (auto __r = w.enterSubRecord("soundMacros"))
{
for (const auto& p : SortUnorderedMap(m_soundMacros))
{
if (auto __v = w.enterSubVector(SoundMacroId::CurNameDB->resolveNameFromId(p.first).data()))
{
for (const auto& c : p.second.get().m_cmds)
{
if (auto __r2 = w.enterSubRecord(nullptr))
{
w.setStyle(athena::io::YAMLNodeStyle::Flow);
w.writeString("cmdOp", SoundMacro::CmdOpToStr(c->Isa()));
c->write(w);
}
}
}
}
}
}
if (!m_tables.empty())
{
if (auto __r = w.enterSubRecord("tables"))
{
for (const auto& p : SortUnorderedMap(m_tables))
{
if (auto __v = w.enterSubRecord(TableId::CurNameDB->resolveNameFromId(p.first).data()))
{
w.setStyle(athena::io::YAMLNodeStyle::Flow);
p.second.get()->write(w);
}
}
}
}
if (!m_keymaps.empty())
{
if (auto __r = w.enterSubRecord("keymaps"))
{
for (const auto& p : SortUnorderedMap(m_keymaps))
{
if (auto __v = w.enterSubRecord(KeymapId::CurNameDB->resolveNameFromId(p.first).data()))
{
w.setStyle(athena::io::YAMLNodeStyle::Flow);
p.second.get().write(w);
}
}
}
}
if (!m_layers.empty())
{
if (auto __r = w.enterSubRecord("layers"))
{
for (const auto& p : SortUnorderedMap(m_layers))
{
if (auto __v = w.enterSubVector(LayersId::CurNameDB->resolveNameFromId(p.first).data()))
{
for (const auto& lm : p.second.get())
{
if (auto __r2 = w.enterSubRecord(nullptr))
{
w.setStyle(athena::io::YAMLNodeStyle::Flow);
lm.write(w);
}
}
}
}
}
}
return w.finish(&writer);
}
template <>
void amuse::Curve::Enumerate<LittleDNA::Read>(athena::io::IStreamReader& r)
{
@ -368,17 +774,18 @@ void amuse::Curve::Enumerate<LittleDNA::BinarySize>(size_t& sz)
template <>
void amuse::Curve::Enumerate<LittleDNA::ReadYaml>(athena::io::YAMLDocReader& r)
{
r.enumerate(nullptr, data);
r.enumerate("data", data);
}
template <>
void amuse::Curve::Enumerate<LittleDNA::WriteYaml>(athena::io::YAMLDocWriter& w)
{
w.enumerate(nullptr, data);
w.enumerate("data", data);
}
const char* amuse::Curve::DNAType()
{
return "amuse::ADSR";
}
}

View File

@ -72,7 +72,7 @@ AudioGroupProject::AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag)
{
SFXGroupIndex::SFXEntryDNA<athena::Big> entry;
entry.read(r);
idx.m_sfxEntries[entry.defineId.id] = entry;
idx.m_sfxEntries[entry.sfxId.id] = entry;
}
}
@ -120,7 +120,8 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
r.seek(header.midiSetupsOff, athena::Begin);
while (r.position() < header.groupEndOff)
{
uint16_t songId = r.readUint16Big();
uint16_t songId;
athena::io::Read<athena::io::PropType::None>::Do<decltype(songId), DNAE>({}, songId, r);
r.seek(2, athena::Current);
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
for (int i = 0; i < 16 ; ++i)
@ -151,7 +152,8 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
r.seek(subDataOff + header.midiSetupsOff, athena::Begin);
while (r.position() < groupBegin + header.groupEndOff)
{
uint16_t songId = r.readUint16Big();
uint16_t songId;
athena::io::Read<athena::io::PropType::None>::Do<decltype(songId), DNAE>({}, songId, r);
r.seek(2, athena::Current);
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
for (int i = 0; i < 16 ; ++i)
@ -169,7 +171,8 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
/* SFX entries */
r.seek(subDataOff + header.pageTableOff, athena::Begin);
uint16_t count = r.readUint16Big();
uint16_t count;
athena::io::Read<athena::io::PropType::None>::Do<decltype(count), DNAE>({}, count, r);
r.seek(2, athena::Current);
idx.m_sfxEntries.reserve(count);
for (int i = 0; i < count; ++i)
@ -177,7 +180,7 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
SFXGroupIndex::SFXEntryDNA<DNAE> entry;
entry.read(r);
r.seek(2, athena::Current);
idx.m_sfxEntries[entry.defineId.id] = entry;
idx.m_sfxEntries[entry.sfxId.id] = entry;
}
}
@ -205,6 +208,194 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(const AudioGroupDat
}
}
template <athena::Endian DNAE>
static void ReadRangedObjectIds(NameDB* db, athena::io::IStreamReader& r, NameDB::Type tp)
{
uint16_t id;
athena::io::Read<athena::io::PropType::None>::Do<decltype(id), DNAE>({}, id, r);
if ((id & 0x8000) == 0x8000)
{
uint16_t endId;
athena::io::Read<athena::io::PropType::None>::Do<decltype(endId), DNAE>({}, endId, r);
for (uint16_t i = uint16_t(id & 0x7fff); i <= uint16_t(endId & 0x7fff); ++i)
{
ObjectId useId = i;
if (tp == NameDB::Type::Layer)
useId.id |= 0x8000;
db->registerPair(NameDB::generateName(useId, tp), useId);
}
}
else
{
db->registerPair(NameDB::generateName(id, tp), id);
}
}
void AudioGroupProject::BootstrapObjectIDs(athena::io::IStreamReader& r, GCNDataTag)
{
while (!AtEnd32(r))
{
GroupHeader<athena::Big> header;
header.read(r);
/* Sound Macros */
r.seek(header.soundMacroIdsOff, athena::Begin);
while (!AtEnd16(r))
ReadRangedObjectIds<athena::Big>(SoundMacroId::CurNameDB, r, NameDB::Type::SoundMacro);
/* Samples */
r.seek(header.samplIdsOff, athena::Begin);
while (!AtEnd16(r))
ReadRangedObjectIds<athena::Big>(SampleId::CurNameDB, r, NameDB::Type::Sample);
/* Tables */
r.seek(header.tableIdsOff, athena::Begin);
while (!AtEnd16(r))
ReadRangedObjectIds<athena::Big>(TableId::CurNameDB, r, NameDB::Type::Table);
/* Keymaps */
r.seek(header.keymapIdsOff, athena::Begin);
while (!AtEnd16(r))
ReadRangedObjectIds<athena::Big>(KeymapId::CurNameDB, r, NameDB::Type::Keymap);
/* Layers */
r.seek(header.layerIdsOff, athena::Begin);
while (!AtEnd16(r))
ReadRangedObjectIds<athena::Big>(LayersId::CurNameDB, r, NameDB::Type::Layer);
if (header.type == GroupType::Song)
{
/* MIDI setups */
r.seek(header.midiSetupsOff, athena::Begin);
while (r.position() < header.groupEndOff)
{
uint16_t id = r.readUint16Big();
SongId::CurNameDB->registerPair(NameDB::generateName(id, NameDB::Type::Song), id);
r.seek(2 + 5 * 16, athena::Current);
}
}
else if (header.type == GroupType::SFX)
{
/* SFX entries */
r.seek(header.pageTableOff, athena::Begin);
uint16_t count = r.readUint16Big();
r.seek(2, athena::Current);
for (int i = 0; i < count; ++i)
{
SFXGroupIndex::SFXEntryDNA<athena::Big> entry;
entry.read(r);
SFXId::CurNameDB->registerPair(
NameDB::generateName(entry.sfxId.id, NameDB::Type::SFX), entry.sfxId.id);
}
}
r.seek(header.groupEndOff, athena::Begin);
}
}
template <athena::Endian DNAE>
void AudioGroupProject::BootstrapObjectIDs(athena::io::IStreamReader& r, bool absOffs)
{
while (!AtEnd32(r))
{
atInt64 groupBegin = r.position();
atInt64 subDataOff = absOffs ? 0 : groupBegin + 8;
GroupHeader<DNAE> header;
header.read(r);
/* Sound Macros */
r.seek(subDataOff + header.soundMacroIdsOff, athena::Begin);
while (!AtEnd16(r))
ReadRangedObjectIds<DNAE>(SoundMacroId::CurNameDB, r, NameDB::Type::SoundMacro);
/* Samples */
r.seek(subDataOff + header.samplIdsOff, athena::Begin);
while (!AtEnd16(r))
ReadRangedObjectIds<DNAE>(SampleId::CurNameDB, r, NameDB::Type::Sample);
/* Tables */
r.seek(subDataOff + header.tableIdsOff, athena::Begin);
while (!AtEnd16(r))
ReadRangedObjectIds<DNAE>(TableId::CurNameDB, r, NameDB::Type::Table);
/* Keymaps */
r.seek(subDataOff + header.keymapIdsOff, athena::Begin);
while (!AtEnd16(r))
ReadRangedObjectIds<DNAE>(KeymapId::CurNameDB, r, NameDB::Type::Keymap);
/* Layers */
r.seek(subDataOff + header.layerIdsOff, athena::Begin);
while (!AtEnd16(r))
ReadRangedObjectIds<DNAE>(LayersId::CurNameDB, r, NameDB::Type::Layer);
if (header.type == GroupType::Song)
{
/* MIDI setups */
if (absOffs)
{
r.seek(header.midiSetupsOff, athena::Begin);
while (r.position() < header.groupEndOff)
{
uint16_t id;
athena::io::Read<athena::io::PropType::None>::Do<decltype(id), DNAE>({}, id, r);
SongId::CurNameDB->registerPair(NameDB::generateName(id, NameDB::Type::Song), id);
r.seek(2 + 5 * 16, athena::Current);
}
}
else
{
r.seek(subDataOff + header.midiSetupsOff, athena::Begin);
while (r.position() < groupBegin + header.groupEndOff)
{
uint16_t id;
athena::io::Read<athena::io::PropType::None>::Do<decltype(id), DNAE>({}, id, r);
SongId::CurNameDB->registerPair(NameDB::generateName(id, NameDB::Type::Song), id);
r.seek(2 + 8 * 16, athena::Current);
}
}
}
else if (header.type == GroupType::SFX)
{
/* SFX entries */
r.seek(subDataOff + header.pageTableOff, athena::Begin);
uint16_t count;
athena::io::Read<athena::io::PropType::None>::Do<decltype(count), DNAE>({}, count, r);
r.seek(2, athena::Current);
for (int i = 0; i < count; ++i)
{
SFXGroupIndex::SFXEntryDNA<DNAE> entry;
entry.read(r);
r.seek(2, athena::Current);
SFXId::CurNameDB->registerPair(
NameDB::generateName(entry.sfxId.id, NameDB::Type::SFX), entry.sfxId.id);
}
}
if (absOffs)
r.seek(header.groupEndOff, athena::Begin);
else
r.seek(groupBegin + header.groupEndOff, athena::Begin);
}
}
void AudioGroupProject::BootstrapObjectIDs(const AudioGroupData& data)
{
athena::io::MemoryReader r(data.getProj(), data.getProjSize());
switch (data.getDataFormat())
{
case DataFormat::GCN:
default:
BootstrapObjectIDs(r, GCNDataTag{});
break;
case DataFormat::N64:
BootstrapObjectIDs<athena::Big>(r, data.getAbsoluteProjOffsets());
break;
case DataFormat::PC:
BootstrapObjectIDs<athena::Little>(r, data.getAbsoluteProjOffsets());
break;
}
}
const SongGroupIndex* AudioGroupProject::getSongGroupIndex(int groupId) const
{
auto search = m_songGroups.find(groupId);
@ -221,4 +412,93 @@ const SFXGroupIndex* AudioGroupProject::getSFXGroupIndex(int groupId) const
return nullptr;
}
bool AudioGroupProject::toYAML(athena::io::IStreamWriter& writer) const
{
athena::io::YAMLDocWriter w("amuse::Project");
if (!m_songGroups.empty())
{
if (auto __v = w.enterSubVector("songGroups"))
{
for (const auto& p : SortUnorderedMap(m_songGroups))
{
if (auto __r = w.enterSubRecord(nullptr))
{
if (!p.second.get().m_normPages.empty())
{
if (auto __v2 = w.enterSubRecord("normPages"))
{
for (const auto& pg : SortUnorderedMap(p.second.get().m_normPages))
{
char name[16];
snprintf(name, 16, "%d", pg.first);
if (auto __r2 = w.enterSubRecord(name))
{
w.setStyle(athena::io::YAMLNodeStyle::Flow);
pg.second.get().write(w);
}
}
}
}
if (!p.second.get().m_drumPages.empty())
{
if (auto __v2 = w.enterSubRecord("drumPages"))
{
for (const auto& pg : SortUnorderedMap(p.second.get().m_drumPages))
{
char name[16];
snprintf(name, 16, "%d", pg.first);
if (auto __r2 = w.enterSubRecord(name))
{
w.setStyle(athena::io::YAMLNodeStyle::Flow);
pg.second.get().write(w);
}
}
}
}
if (!p.second.get().m_midiSetups.empty())
{
if (auto __v2 = w.enterSubRecord("songs"))
{
for (const auto& song : SortUnorderedMap(p.second.get().m_midiSetups))
{
if (auto __v3 = w.enterSubVector(SongId::CurNameDB->resolveNameFromId(song.first).data()))
for (int i = 0; i < 16; ++i)
if (auto __r2 = w.enterSubRecord(nullptr))
{
w.setStyle(athena::io::YAMLNodeStyle::Flow);
song.second.get()[i].write(w);
}
}
}
}
}
}
}
}
if (!m_sfxGroups.empty())
{
if (auto __v = w.enterSubVector("sfxGroups"))
{
for (const auto& p : SortUnorderedMap(m_sfxGroups))
{
if (auto __r = w.enterSubRecord(nullptr))
{
for (const auto& sfx : SortUnorderedMap(p.second.get().m_sfxEntries))
{
if (auto __r2 = w.enterSubRecord(SFXId::CurNameDB->resolveNameFromId(sfx.first).data()))
{
w.setStyle(athena::io::YAMLNodeStyle::Flow);
sfx.second.get().write(w);
}
}
}
}
}
}
return w.finish(&writer);
}
}

View File

@ -2,20 +2,16 @@
#include "amuse/Common.hpp"
#include "amuse/AudioGroupData.hpp"
#include <cstring>
#include <athena/MemoryReader.hpp>
namespace amuse
{
void AudioGroupSampleDirectory::Entry::swapBig()
static bool AtEnd32(athena::io::IStreamReader& r)
{
m_sfxId = SBig(m_sfxId);
m_sampleOff = SBig(m_sampleOff);
m_unk = SBig(m_unk);
m_sampleRate = SBig(m_sampleRate);
m_numSamples = SBig(m_numSamples);
m_loopStartSample = SBig(m_loopStartSample);
m_loopLengthSamples = SBig(m_loopLengthSamples);
m_adpcmParmOffset = SBig(m_adpcmParmOffset);
uint32_t v = r.readUint32Big();
r.seek(-4, athena::Current);
return v == 0xffffffff;
}
void AudioGroupSampleDirectory::ADPCMParms::swapBigDSP()
@ -37,177 +33,94 @@ void AudioGroupSampleDirectory::ADPCMParms::swapBigVADPCM()
allCoefs[i] = SBig(allCoefs[i]);
}
AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data, GCNDataTag)
AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader& r, GCNDataTag)
{
const unsigned char* cur = data;
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
while (!AtEnd32(r))
{
const AudioGroupSampleDirectory::Entry* ent = reinterpret_cast<const AudioGroupSampleDirectory::Entry*>(cur);
std::pair<Entry, ADPCMParms>& store = m_entries[SBig(ent->m_sfxId)];
store.first = *ent;
store.first.swapBig();
if (store.first.m_adpcmParmOffset)
{
const AudioGroupSampleDirectory::ADPCMParms* adpcm =
reinterpret_cast<const AudioGroupSampleDirectory::ADPCMParms*>(data + store.first.m_adpcmParmOffset);
store.second.dsp = adpcm->dsp;
store.second.swapBigDSP();
EntryDNA<athena::Big> ent;
ent.read(r);
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
store.first = ent;
}
cur += 32;
for (auto& p : m_entries)
{
if (p.second.first.m_adpcmParmOffset)
{
r.seek(p.second.first.m_adpcmParmOffset, athena::Begin);
r.readUBytesToBuf(&p.second.second, sizeof(ADPCMParms::DSPParms));
p.second.second.swapBigDSP();
}
}
}
struct MusyX1SdirEntry
{
uint16_t m_sfxId;
uint32_t m_sampleOff;
uint32_t m_pitchSampleRate;
uint32_t m_numSamples;
uint32_t m_loopStartSample;
uint32_t m_loopLengthSamples;
void swapBig()
{
m_sfxId = SBig(m_sfxId);
m_sampleOff = SBig(m_sampleOff);
m_pitchSampleRate = SBig(m_pitchSampleRate);
m_numSamples = SBig(m_numSamples);
m_loopStartSample = SBig(m_loopStartSample);
m_loopLengthSamples = SBig(m_loopLengthSamples);
}
void setIntoMusyX2(AudioGroupSampleDirectory::Entry& ent) const
{
ent.m_sfxId = m_sfxId;
ent.m_sampleOff = m_sampleOff;
ent.m_unk = 0;
ent.m_pitch = m_pitchSampleRate >> 24;
ent.m_sampleRate = m_pitchSampleRate & 0xffff;
ent.m_numSamples = m_numSamples;
ent.m_loopStartSample = m_loopStartSample;
ent.m_loopLengthSamples = m_loopLengthSamples;
ent.m_adpcmParmOffset = 0;
}
};
struct MusyX1AbsSdirEntry
{
uint16_t m_sfxId;
uint32_t m_sampleOff;
uint32_t m_unk;
uint32_t m_pitchSampleRate;
uint32_t m_numSamples;
uint32_t m_loopStartSample;
uint32_t m_loopLengthSamples;
void swapBig()
{
m_sfxId = SBig(m_sfxId);
m_sampleOff = SBig(m_sampleOff);
m_unk = SBig(m_unk);
m_pitchSampleRate = SBig(m_pitchSampleRate);
m_numSamples = SBig(m_numSamples);
m_loopStartSample = SBig(m_loopStartSample);
m_loopLengthSamples = SBig(m_loopLengthSamples);
}
void setIntoMusyX2(AudioGroupSampleDirectory::Entry& ent) const
{
ent.m_sfxId = m_sfxId;
ent.m_sampleOff = m_sampleOff;
ent.m_unk = m_unk;
ent.m_pitch = m_pitchSampleRate >> 24;
ent.m_sampleRate = m_pitchSampleRate & 0xffff;
ent.m_numSamples = m_numSamples;
ent.m_loopStartSample = m_loopStartSample;
ent.m_loopLengthSamples = m_loopLengthSamples;
ent.m_adpcmParmOffset = 0;
}
};
AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData,
AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader& r, const unsigned char* sampData,
bool absOffs, N64DataTag)
{
const unsigned char* cur = data;
if (absOffs)
{
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
while (!AtEnd32(r))
{
MusyX1AbsSdirEntry ent = *reinterpret_cast<const MusyX1AbsSdirEntry*>(cur);
ent.swapBig();
MusyX1AbsSdirEntry<athena::Big> ent;
ent.read(r);
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
ent.setIntoMusyX2(store.first);
memmove(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
store.second.swapBigVADPCM();
cur += 28;
store.first = ent;
}
}
else
{
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
while (!AtEnd32(r))
{
MusyX1SdirEntry ent = *reinterpret_cast<const MusyX1SdirEntry*>(cur);
ent.swapBig();
MusyX1SdirEntry<athena::Big> ent;
ent.read(r);
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
ent.setIntoMusyX2(store.first);
memmove(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
store.second.swapBigVADPCM();
cur += 24;
}
store.first = ent;
}
}
AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data, bool absOffs, PCDataTag)
for (auto& p : m_entries)
{
const unsigned char* cur = data;
memcpy(&p.second.second, sampData + p.second.first.m_sampleOff, sizeof(ADPCMParms::VADPCMParms));
p.second.second.swapBigVADPCM();
}
}
AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader& r, bool absOffs, PCDataTag)
{
if (absOffs)
{
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
while (!AtEnd32(r))
{
const MusyX1AbsSdirEntry* ent = reinterpret_cast<const MusyX1AbsSdirEntry*>(cur);
std::pair<Entry, ADPCMParms>& store = m_entries[ent->m_sfxId];
ent->setIntoMusyX2(store.first);
cur += 28;
MusyX1AbsSdirEntry<athena::Little> ent;
ent.read(r);
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
store.first = ent;
}
}
else
{
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
while (!AtEnd32(r))
{
const MusyX1SdirEntry* ent = reinterpret_cast<const MusyX1SdirEntry*>(cur);
std::pair<Entry, ADPCMParms>& store = m_entries[ent->m_sfxId];
ent->setIntoMusyX2(store.first);
cur += 24;
MusyX1SdirEntry<athena::Little> ent;
ent.read(r);
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
store.first = ent;
}
}
}
AudioGroupSampleDirectory AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(const AudioGroupData& data)
{
athena::io::MemoryReader r(data.getSdir(), data.getSdirSize());
switch (data.getDataFormat())
{
case DataFormat::GCN:
default:
return AudioGroupSampleDirectory(data.getSdir(), GCNDataTag{});
return AudioGroupSampleDirectory(r, GCNDataTag{});
case DataFormat::N64:
return AudioGroupSampleDirectory(data.getSdir(), data.getSamp(), data.getAbsoluteProjOffsets(), N64DataTag{});
return AudioGroupSampleDirectory(r, data.getSamp(), data.getAbsoluteProjOffsets(), N64DataTag{});
case DataFormat::PC:
return AudioGroupSampleDirectory(data.getSdir(), data.getAbsoluteProjOffsets(), PCDataTag{});
return AudioGroupSampleDirectory(r, data.getAbsoluteProjOffsets(), PCDataTag{});
}
}
}

View File

@ -5,374 +5,228 @@ namespace amuse
{
static logvisor::Module Log("amuse");
thread_local NameDB* ObjectId::CurNameDB = nullptr;
thread_local NameDB* SampleId::CurNameDB = nullptr;
thread_local NameDB* SongId::CurNameDB = nullptr;
thread_local NameDB* SFXId::CurNameDB = nullptr;
#define DEFINE_ID_TYPE(type, typeName) \
thread_local NameDB* type::CurNameDB = nullptr; \
template<> template<> \
void type##DNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) \
{ \
id = reader.readUint16Little(); \
} \
template<> template<> \
void type##DNA<athena::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer) \
{ \
writer.writeUint16Little(id); \
} \
template<> template<> \
void type##DNA<athena::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz) \
{ \
sz += 2; \
} \
template<> template<> \
void type##DNA<athena::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader) \
{ \
_read(reader); \
} \
template<> template<> \
void type##DNA<athena::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer) \
{ \
_write(writer); \
} \
template<> template<> \
void type##DNA<athena::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) \
{ \
id = reader.readUint16Big(); \
} \
template<> template<> \
void type##DNA<athena::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer) \
{ \
writer.writeUint16Big(id); \
} \
template<> template<> \
void type##DNA<athena::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz) \
{ \
sz += 2; \
} \
template<> template<> \
void type##DNA<athena::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader) \
{ \
_read(reader); \
} \
template<> template<> \
void type##DNA<athena::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer) \
{ \
_write(writer); \
} \
template <athena::Endian DNAE> \
void type##DNA<DNAE>::_read(athena::io::YAMLDocReader& r) \
{ \
std::string name = r.readString(nullptr); \
if (!type::CurNameDB) \
Log.report(logvisor::Fatal, "Unable to resolve " typeName " name %s, no database present", name.c_str()); \
if (name.empty()) \
{ \
id.id = 0xffff; \
return; \
} \
id = type::CurNameDB->resolveIdFromName(name); \
} \
template <athena::Endian DNAE> \
void type##DNA<DNAE>::_write(athena::io::YAMLDocWriter& w) \
{ \
if (!type::CurNameDB) \
Log.report(logvisor::Fatal, "Unable to resolve " typeName " ID %d, no database present", id.id); \
if (id.id == 0xffff) \
return; \
std::string_view name = type::CurNameDB->resolveNameFromId(id); \
w.writeString(nullptr, name); \
} \
template <athena::Endian DNAE> \
const char* type##DNA<DNAE>::DNAType() \
{ \
return "amuse::" #type "DNA"; \
} \
template struct type##DNA<athena::Big>; \
template struct type##DNA<athena::Little>;
DEFINE_ID_TYPE(ObjectId, "object")
DEFINE_ID_TYPE(SoundMacroId, "SoundMacro")
DEFINE_ID_TYPE(SampleId, "sample")
DEFINE_ID_TYPE(TableId, "table")
DEFINE_ID_TYPE(KeymapId, "keymap")
DEFINE_ID_TYPE(LayersId, "layers")
DEFINE_ID_TYPE(SongId, "song")
DEFINE_ID_TYPE(SFXId, "sfx")
template<> template<>
void ObjectIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
void PageObjectIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
{
id = reader.readUint16Little();
}
template<> template<>
void ObjectIdDNA<athena::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
void PageObjectIdDNA<athena::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
{
writer.writeUint16Little(id);
}
template<> template<>
void ObjectIdDNA<athena::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz)
void PageObjectIdDNA<athena::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz)
{
sz += 2;
}
template<> template<>
void ObjectIdDNA<athena::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
void PageObjectIdDNA<athena::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
{
_read(reader);
}
template<> template<>
void ObjectIdDNA<athena::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
void PageObjectIdDNA<athena::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
{
_write(writer);
}
template<> template<>
void ObjectIdDNA<athena::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
void PageObjectIdDNA<athena::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
{
id = reader.readUint16Big();
}
template<> template<>
void ObjectIdDNA<athena::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
void PageObjectIdDNA<athena::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
{
writer.writeUint16Big(id);
}
template<> template<>
void ObjectIdDNA<athena::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz)
void PageObjectIdDNA<athena::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz)
{
sz += 2;
}
template<> template<>
void ObjectIdDNA<athena::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
void PageObjectIdDNA<athena::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
{
_read(reader);
}
template<> template<>
void ObjectIdDNA<athena::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
void PageObjectIdDNA<athena::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
{
_write(writer);
}
template <athena::Endian DNAE>
void ObjectIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r)
void PageObjectIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r)
{
std::string name = r.readString(nullptr);
if (!ObjectId::CurNameDB)
Log.report(logvisor::Fatal, "Unable to resolve object name %s, no database present", name.c_str());
id = ObjectId::CurNameDB->resolveIdFromName(name);
}
template <athena::Endian DNAE>
void ObjectIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
if (!KeymapId::CurNameDB || !LayersId::CurNameDB)
Log.report(logvisor::Fatal, "Unable to resolve keymap or layers name %s, no database present", name.c_str());
if (name.empty())
{
if (!ObjectId::CurNameDB)
Log.report(logvisor::Fatal, "Unable to resolve object ID %d, no database present", id.id);
std::string_view name = ObjectId::CurNameDB->resolveNameFromId(id);
id.id = 0xffff;
return;
}
auto search = KeymapId::CurNameDB->m_stringToId.find(name);
if (search == KeymapId::CurNameDB->m_stringToId.cend())
{
search = LayersId::CurNameDB->m_stringToId.find(name);
if (search == LayersId::CurNameDB->m_stringToId.cend())
Log.report(logvisor::Fatal, "Unable to resolve name %s", name.c_str());
}
id = search->second;
}
template <athena::Endian DNAE>
void PageObjectIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
{
if (!KeymapId::CurNameDB || !LayersId::CurNameDB)
Log.report(logvisor::Fatal, "Unable to resolve keymap or layers ID %d, no database present", id.id);
if (id.id == 0xffff)
return;
if (id.id & 0x8000)
{
std::string_view name = LayersId::CurNameDB->resolveNameFromId(id);
w.writeString(nullptr, name);
}
template <athena::Endian DNAE>
const char* ObjectIdDNA<DNAE>::DNAType()
else
{
return "amuse::ObjectId";
}
template<> template<>
void SampleIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
{
id = reader.readUint16Little();
}
template<> template<>
void SampleIdDNA<athena::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
{
writer.writeUint16Little(id);
}
template<> template<>
void SampleIdDNA<athena::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz)
{
sz += 2;
}
template<> template<>
void SampleIdDNA<athena::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
{
_read(reader);
}
template<> template<>
void SampleIdDNA<athena::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
{
_write(writer);
}
template<> template<>
void SampleIdDNA<athena::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
{
id = reader.readUint16Big();
}
template<> template<>
void SampleIdDNA<athena::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
{
writer.writeUint16Big(id);
}
template<> template<>
void SampleIdDNA<athena::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz)
{
sz += 2;
}
template<> template<>
void SampleIdDNA<athena::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
{
_read(reader);
}
template<> template<>
void SampleIdDNA<athena::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
{
_write(writer);
}
template <athena::Endian DNAE>
void SampleIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r)
{
std::string name = r.readString(nullptr);
if (!SampleId::CurNameDB)
Log.report(logvisor::Fatal, "Unable to resolve sample name %s, no database present", name.c_str());
id = SampleId::CurNameDB->resolveIdFromName(name);
}
template <athena::Endian DNAE>
void SampleIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
{
if (!SampleId::CurNameDB)
Log.report(logvisor::Fatal, "Unable to resolve sample ID %d, no database present", id.id);
std::string_view name = SampleId::CurNameDB->resolveNameFromId(id);
std::string_view name = KeymapId::CurNameDB->resolveNameFromId(id);
w.writeString(nullptr, name);
}
}
template <athena::Endian DNAE>
const char* SampleIdDNA<DNAE>::DNAType()
const char* PageObjectIdDNA<DNAE>::DNAType()
{
return "amuse::SampleId";
}
template<> template<>
void SongIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
{
id = reader.readUint16Little();
}
template<> template<>
void SongIdDNA<athena::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
{
writer.writeUint16Little(id);
}
template<> template<>
void SongIdDNA<athena::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz)
{
sz += 2;
}
template<> template<>
void SongIdDNA<athena::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
{
_read(reader);
}
template<> template<>
void SongIdDNA<athena::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
{
_write(writer);
}
template<> template<>
void SongIdDNA<athena::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
{
id = reader.readUint16Big();
}
template<> template<>
void SongIdDNA<athena::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
{
writer.writeUint16Big(id);
}
template<> template<>
void SongIdDNA<athena::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz)
{
sz += 2;
}
template<> template<>
void SongIdDNA<athena::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
{
_read(reader);
}
template<> template<>
void SongIdDNA<athena::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
{
_write(writer);
}
template <athena::Endian DNAE>
void SongIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r)
{
std::string name = r.readString(nullptr);
if (!SongId::CurNameDB)
Log.report(logvisor::Fatal, "Unable to resolve song name %s, no database present", name.c_str());
id = SongId::CurNameDB->resolveIdFromName(name);
}
template <athena::Endian DNAE>
void SongIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
{
if (!SongId::CurNameDB)
Log.report(logvisor::Fatal, "Unable to resolve song ID %d, no database present", id.id);
std::string_view name = SongId::CurNameDB->resolveNameFromId(id);
w.writeString(nullptr, name);
}
template <athena::Endian DNAE>
const char* SongIdDNA<DNAE>::DNAType()
{
return "amuse::SongId";
}
template<> template<>
void SFXIdDNA<athena::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
{
id = reader.readUint16Little();
}
template<> template<>
void SFXIdDNA<athena::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
{
writer.writeUint16Little(id);
}
template<> template<>
void SFXIdDNA<athena::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz)
{
sz += 2;
}
template<> template<>
void SFXIdDNA<athena::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
{
_read(reader);
}
template<> template<>
void SFXIdDNA<athena::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
{
_write(writer);
}
template<> template<>
void SFXIdDNA<athena::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader)
{
id = reader.readUint16Big();
}
template<> template<>
void SFXIdDNA<athena::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer)
{
writer.writeUint16Big(id);
}
template<> template<>
void SFXIdDNA<athena::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz)
{
sz += 2;
}
template<> template<>
void SFXIdDNA<athena::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader)
{
_read(reader);
}
template<> template<>
void SFXIdDNA<athena::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer)
{
_write(writer);
}
template <athena::Endian DNAE>
void SFXIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r)
{
std::string name = r.readString(nullptr);
if (!SFXId::CurNameDB)
Log.report(logvisor::Fatal, "Unable to resolve song name %s, no database present", name.c_str());
id = SFXId::CurNameDB->resolveIdFromName(name);
}
template <athena::Endian DNAE>
void SFXIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
{
if (!SFXId::CurNameDB)
Log.report(logvisor::Fatal, "Unable to resolve song ID %d, no database present", id.id);
std::string_view name = SFXId::CurNameDB->resolveNameFromId(id);
w.writeString(nullptr, name);
}
template <athena::Endian DNAE>
const char* SFXIdDNA<DNAE>::DNAType()
{
return "amuse::SFXId";
return "amuse::PageObjectIdDNA";
}
template struct PageObjectIdDNA<athena::Big>;
template struct PageObjectIdDNA<athena::Little>;
ObjectId NameDB::generateId(Type tp)
{
uint16_t upperMatch = uint16_t(tp) << 8;
uint16_t maxMatch = 0;
uint16_t maxMatch = uint16_t(tp == Type::Layer ? 0x8000 : 0);
for (const auto& p : m_idToString)
if ((p.first & 0xff00) == upperMatch && (p.first & 0xff) >= maxMatch)
maxMatch = (p.first & 0xff) + 1;
return upperMatch | maxMatch;
if (p.first >= maxMatch)
maxMatch = p.first + 1;
return maxMatch;
}
std::string NameDB::generateName(ObjectId id)
std::string NameDB::generateName(ObjectId id, Type tp)
{
Type tp = Type(id.id >> 8);
char name[32];
switch (tp)
{
case Type::SoundMacro:
snprintf(name, 32, "macro%d", id.id & 0xff);
snprintf(name, 32, "macro%04X", id.id);
break;
case Type::Table:
snprintf(name, 32, "table%d", id.id & 0xff);
snprintf(name, 32, "table%04X", id.id);
break;
case Type::Keymap:
snprintf(name, 32, "keymap%d", id.id & 0xff);
snprintf(name, 32, "keymap%04X", id.id);
break;
case Type::Layer:
snprintf(name, 32, "layers%d", id.id & 0xff);
snprintf(name, 32, "layers%04X", id.id);
break;
case Type::Song:
snprintf(name, 32, "song%04X", id.id);
break;
case Type::SFX:
snprintf(name, 32, "sfx%04X", id.id);
break;
case Type::Sample:
snprintf(name, 32, "sample%04X", id.id);
break;
default:
snprintf(name, 32, "obj%04X", id.id);
@ -391,7 +245,7 @@ std::string_view NameDB::resolveNameFromId(ObjectId id) const
{
auto search = m_idToString.find(id);
if (search == m_idToString.cend())
Log.report(logvisor::Fatal, "Unable to resolve ID %d", id.id);
Log.report(logvisor::Fatal, "Unable to resolve ID 0x%04X", id.id);
return search->second;
}
@ -403,12 +257,6 @@ ObjectId NameDB::resolveIdFromName(std::string_view str) const
return search->second;
}
template struct ObjectIdDNA<athena::Big>;
template struct ObjectIdDNA<athena::Little>;
template struct SampleIdDNA<athena::Big>;
template struct SampleIdDNA<athena::Little>;
template<>
void LittleUInt24::Enumerate<LittleDNA::Read>(athena::io::IStreamReader& reader)
{

View File

@ -307,7 +307,7 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, std::wea
std::list<std::shared_ptr<Voice>>::iterator ret =
_allocateVoice(*grp, std::get<1>(search->second), NativeSampleRate, true, false, smx);
if (!(*ret)->loadSoundObject(entry->objId, 0, 1000.f, entry->defKey, entry->defVel, 0))
if (!(*ret)->loadMacroObject(entry->macro.id, 0, 1000.f, entry->defKey, entry->defVel, 0))
{
_destroyVoice(ret);
return {};
@ -335,7 +335,7 @@ std::shared_ptr<Emitter> Engine::addEmitter(const float* pos, const float* dir,
std::list<std::shared_ptr<Voice>>::iterator vox =
_allocateVoice(*grp, std::get<1>(search->second), NativeSampleRate, true, true, smx);
if (!(*vox)->loadSoundObject(entry->objId, 0, 1000.f, entry->defKey, entry->defVel, 0))
if (!(*vox)->loadMacroObject(entry->macro, 0, 1000.f, entry->defKey, entry->defVel, 0))
{
_destroyVoice(vox);
return {};

View File

@ -247,19 +247,24 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
(*ret)->installCtrlValues(m_ctrlVals);
ObjectId oid;
bool res;
if (m_parent->m_songGroup)
{
oid = m_page->objId;
res = (*ret)->loadPageObject(oid, m_parent->m_ticksPerSec, note, velocity, m_ctrlVals[1]);
}
else if (m_parent->m_sfxMappings.size())
{
size_t lookupIdx = note % m_parent->m_sfxMappings.size();
const SFXGroupIndex::SFXEntry* sfxEntry = m_parent->m_sfxMappings[lookupIdx];
oid = sfxEntry->objId;
oid = sfxEntry->macro;
note = sfxEntry->defKey;
res = (*ret)->loadMacroObject(oid, 0, m_parent->m_ticksPerSec, note, velocity, m_ctrlVals[1]);
}
else
return {};
if (!(*ret)->loadSoundObject(oid, 0, m_parent->m_ticksPerSec, note, velocity, m_ctrlVals[1]))
if (!res)
{
m_parent->m_engine._destroyVoice(ret);
return {};

View File

@ -152,7 +152,7 @@ bool SoundMacro::CmdSplitKey::Do(SoundMacroState& st, Voice& vox) const
if (macro.id == std::get<0>(st.m_pc.back()))
st._setPC(macroStep);
else
vox.loadSoundObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod);
vox.loadMacroObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod);
}
return false;
@ -166,7 +166,7 @@ bool SoundMacro::CmdSplitVel::Do(SoundMacroState& st, Voice& vox) const
if (macro.id == std::get<0>(st.m_pc.back()))
st._setPC(macroStep);
else
vox.loadSoundObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod);
vox.loadMacroObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod);
}
return false;
@ -238,7 +238,7 @@ bool SoundMacro::CmdGoto::Do(SoundMacroState& st, Voice& vox) const
if (macro.id == std::get<0>(st.m_pc.back()))
st._setPC(macroStep);
else
vox.loadSoundObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod);
vox.loadMacroObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod);
return false;
}
@ -312,7 +312,7 @@ bool SoundMacro::CmdSplitMod::Do(SoundMacroState& st, Voice& vox) const
if (macro.id == std::get<0>(st.m_pc.back()))
st._setPC(macroStep);
else
vox.loadSoundObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod);
vox.loadMacroObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod);
}
return false;
@ -420,7 +420,7 @@ bool SoundMacro::CmdSplitRnd::Do(SoundMacroState& st, Voice& vox) const
if (macro.id == std::get<0>(st.m_pc.back()))
st._setPC(macroStep);
else
vox.loadSoundObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod);
vox.loadMacroObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod);
}
return false;
@ -641,8 +641,7 @@ bool SoundMacro::CmdGoSub::Do(SoundMacroState& st, Voice& vox) const
st.m_pc.emplace_back(std::get<0>(st.m_pc.back()), std::get<1>(st.m_pc.back()),
std::get<1>(st.m_pc.back())->assertPC(macroStep));
else
vox.loadSoundObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod, true);
vox.loadMacroObject(macro.id, macroStep, st.m_ticksPerSec, st.m_initKey, st.m_initVel, st.m_initMod, true);
vox._setObjectId(std::get<0>(st.m_pc.back()));

View File

@ -49,7 +49,7 @@ void Voice::_macroSampleEnd()
m_state.m_inWait = false;
}
else
loadSoundObject(m_sampleEndTrap.macroId, m_sampleEndTrap.macroStep, m_state.m_ticksPerSec,
loadMacroObject(m_sampleEndTrap.macroId, m_sampleEndTrap.macroStep, m_state.m_ticksPerSec,
m_state.m_initKey, m_state.m_initVel, m_state.m_initMod);
}
else
@ -734,7 +734,7 @@ std::shared_ptr<Voice> Voice::_startChildMacro(ObjectId macroId, int macroStep,
uint8_t midiVel, uint8_t midiMod, bool pushPc)
{
std::list<std::shared_ptr<Voice>>::iterator vox = _allocateVoice(NativeSampleRate, true);
if (!(*vox)->loadSoundObject(macroId, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc))
if (!(*vox)->loadMacroObject(macroId, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc))
{
_destroyVoice(vox);
return {};
@ -751,9 +751,11 @@ std::shared_ptr<Voice> Voice::startChildMacro(int8_t addNote, ObjectId macroId,
m_state.m_initMod);
}
bool Voice::_loadSoundMacro(ObjectId id, const SoundMacro* macroData, int macroStep, double ticksPerSec,
bool Voice::_loadSoundMacro(SoundMacroId id, const SoundMacro* macroData, int macroStep, double ticksPerSec,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc)
{
m_objectId = id;
if (m_state.m_pc.empty())
m_state.initialize(id, macroData, macroStep, ticksPerSec, midiKey, midiVel, midiMod);
else
@ -768,19 +770,19 @@ bool Voice::_loadSoundMacro(ObjectId id, const SoundMacro* macroData, int macroS
return true;
}
bool Voice::_loadKeymap(ObjectId id, const Keymap* keymap, int macroStep, double ticksPerSec,
bool Voice::_loadKeymap(const Keymap* keymap, double ticksPerSec,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc)
{
const Keymap& km = keymap[midiKey];
midiKey += km.transpose;
bool ret = loadSoundObject(id, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
bool ret = loadMacroObject(km.macro.id, 0, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
m_curVol = 1.f;
_setPan((km.pan - 64) / 64.f);
_setSurroundPan(-1.f);
return ret;
}
bool Voice::_loadLayer(ObjectId id, const std::vector<LayerMapping>& layer, int macroStep, double ticksPerSec,
bool Voice::_loadLayer(const std::vector<LayerMapping>& layer, double ticksPerSec,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc)
{
bool ret = false;
@ -791,7 +793,7 @@ bool Voice::_loadLayer(ObjectId id, const std::vector<LayerMapping>& layer, int
uint8_t mappingKey = midiKey + mapping.transpose;
if (m_voxState != VoiceState::Playing)
{
ret |= loadSoundObject(id, macroStep, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
ret |= loadMacroObject(mapping.macro.id, 0, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
m_curVol = mapping.volume / 127.f;
_setPan((mapping.pan - 64) / 64.f);
_setSurroundPan((mapping.span - 64) / 64.f);
@ -799,7 +801,7 @@ bool Voice::_loadLayer(ObjectId id, const std::vector<LayerMapping>& layer, int
else
{
std::shared_ptr<Voice> vox =
_startChildMacro(id, macroStep, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
_startChildMacro(mapping.macro.id, 0, ticksPerSec, mappingKey, midiVel, midiMod, pushPc);
if (vox)
{
vox->m_curVol = mapping.volume / 127.f;
@ -813,31 +815,35 @@ bool Voice::_loadLayer(ObjectId id, const std::vector<LayerMapping>& layer, int
return ret;
}
bool Voice::loadSoundObject(ObjectId objectId, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
bool Voice::loadMacroObject(SoundMacroId macroId, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
uint8_t midiMod, bool pushPc)
{
if (m_destroyed)
return false;
const SoundMacro* macroData = m_audioGroup.getPool().soundMacro(objectId);
const SoundMacro* macroData = m_audioGroup.getPool().soundMacro(macroId);
if (macroData)
{
m_objectId = objectId;
return _loadSoundMacro(objectId, macroData, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
return _loadSoundMacro(macroId, macroData, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
return false;
}
const Keymap* keymap = m_audioGroup.getPool().keymap(objectId);
if (keymap)
bool Voice::loadPageObject(ObjectId objectId, double ticksPerSec, uint8_t midiKey, uint8_t midiVel, uint8_t midiMod)
{
m_objectId = objectId;
return _loadKeymap(objectId, keymap, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
}
if (m_destroyed)
return false;
if (objectId.id & 0x8000)
{
const std::vector<LayerMapping>* layer = m_audioGroup.getPool().layer(objectId);
if (layer)
return _loadLayer(*layer, ticksPerSec, midiKey, midiVel, midiMod);
}
else
{
m_objectId = objectId;
return _loadLayer(objectId, *layer, macroStep, ticksPerSec, midiKey, midiVel, midiMod, pushPc);
const Keymap* keymap = m_audioGroup.getPool().keymap(objectId);
if (keymap)
return _loadKeymap(keymap, ticksPerSec, midiKey, midiVel, midiMod);
}
return false;
@ -868,7 +874,7 @@ void Voice::keyOff()
m_state.m_inWait = false;
}
else
loadSoundObject(m_keyoffTrap.macroId, m_keyoffTrap.macroStep, m_state.m_ticksPerSec, m_state.m_initKey,
loadMacroObject(m_keyoffTrap.macroId, m_keyoffTrap.macroStep, m_state.m_ticksPerSec, m_state.m_initKey,
m_state.m_initVel, m_state.m_initMod);
}
else if (!m_curSample || m_curSample->first.m_loopLengthSamples)
@ -890,7 +896,7 @@ void Voice::message(int32_t val)
if (m_messageTrap.macroId == std::get<0>(m_state.m_pc.back()))
std::get<2>(m_state.m_pc.back()) = std::get<1>(m_state.m_pc.back())->assertPC(m_messageTrap.macroStep);
else
loadSoundObject(m_messageTrap.macroId, m_messageTrap.macroStep, m_state.m_ticksPerSec, m_state.m_initKey,
loadMacroObject(m_messageTrap.macroId, m_messageTrap.macroStep, m_state.m_ticksPerSec, m_state.m_initKey,
m_state.m_initVel, m_state.m_initMod);
}
}