mirror of https://github.com/AxioDL/amuse.git
Work on project file reading
This commit is contained in:
parent
26cfa07f77
commit
7a38fd0676
|
@ -225,10 +225,10 @@ void MainWindow::importAction()
|
||||||
{
|
{
|
||||||
auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(dir.filePath(fPath)).c_str());
|
auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(dir.filePath(fPath)).c_str());
|
||||||
for (auto& p : data)
|
for (auto& p : data)
|
||||||
if (!m_projectModel->importGroupData(SysStringToQString(p.first), std::move(p.second),
|
if (!m_projectModel->importGroupData(SysStringToQString(p.first), std::move(p.second)))
|
||||||
ProjectModel::ImportMode(impMode)))
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
m_projectModel->extractSamples(ProjectModel::ImportMode(impMode), this);
|
||||||
m_projectModel->saveToFile(this);
|
m_projectModel->saveToFile(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -254,10 +254,10 @@ void MainWindow::importAction()
|
||||||
/* Handle single container */
|
/* Handle single container */
|
||||||
auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(path).c_str());
|
auto data = amuse::ContainerRegistry::LoadContainer(QStringToSysString(path).c_str());
|
||||||
for (auto& p : data)
|
for (auto& p : data)
|
||||||
if (!m_projectModel->importGroupData(SysStringToQString(p.first), std::move(p.second),
|
if (!m_projectModel->importGroupData(SysStringToQString(p.first), std::move(p.second)))
|
||||||
ProjectModel::ImportMode(impMode)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_projectModel->extractSamples(ProjectModel::ImportMode(impMode), this);
|
||||||
m_projectModel->saveToFile(this);
|
m_projectModel->saveToFile(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ ProjectModel::ProjectGroup::ProjectGroup(amuse::IntrusiveAudioGroupData&& data)
|
||||||
m_sdir(amuse::AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(m_data))
|
m_sdir(amuse::AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(m_data))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool ProjectModel::importGroupData(const QString& groupName, amuse::IntrusiveAudioGroupData&& data, ImportMode mode)
|
bool ProjectModel::importGroupData(const QString& groupName, amuse::IntrusiveAudioGroupData&& data)
|
||||||
{
|
{
|
||||||
setIdDatabases();
|
setIdDatabases();
|
||||||
|
|
||||||
|
@ -28,6 +28,42 @@ bool ProjectModel::importGroupData(const QString& groupName, amuse::IntrusiveAud
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProjectModel::extractSamples(ImportMode mode, QWidget* parent)
|
||||||
|
{
|
||||||
|
setIdDatabases();
|
||||||
|
|
||||||
|
if (!MkPath(m_dir.path(), parent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto& g : m_groups)
|
||||||
|
{
|
||||||
|
g.second.setIdDatabases();
|
||||||
|
|
||||||
|
QDir dir(QFileInfo(m_dir, g.first).filePath());
|
||||||
|
if (!MkPath(dir.path(), parent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
amuse::SystemString sysDir = QStringToSysString(dir.path());
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case ImportMode::Original:
|
||||||
|
g.second.m_sdir.extractAllCompressed(sysDir, g.second.m_data.getSamp());
|
||||||
|
break;
|
||||||
|
case ImportMode::WAVs:
|
||||||
|
g.second.m_sdir.extractAllWAV(sysDir, g.second.m_data.getSamp());
|
||||||
|
break;
|
||||||
|
case ImportMode::Both:
|
||||||
|
g.second.m_sdir.extractAllCompressed(sysDir, g.second.m_data.getSamp());
|
||||||
|
g.second.m_sdir.extractAllWAV(sysDir, g.second.m_data.getSamp());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ProjectModel::saveToFile(QWidget* parent)
|
bool ProjectModel::saveToFile(QWidget* parent)
|
||||||
{
|
{
|
||||||
setIdDatabases();
|
setIdDatabases();
|
||||||
|
@ -42,15 +78,9 @@ bool ProjectModel::saveToFile(QWidget* parent)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
g.second.setIdDatabases();
|
g.second.setIdDatabases();
|
||||||
{
|
amuse::SystemString groupPath = QStringToSysString(dir.path());
|
||||||
athena::io::FileWriter fo(QStringToSysString(dir.filePath("!project.yaml")));
|
g.second.m_proj.toYAML(groupPath);
|
||||||
g.second.m_proj.toYAML(fo);
|
g.second.m_pool.toYAML(groupPath);
|
||||||
}
|
|
||||||
{
|
|
||||||
athena::io::FileWriter fo(QStringToSysString(dir.filePath("!pool.yaml")));
|
|
||||||
g.second.m_pool.toYAML(fo);
|
|
||||||
}
|
|
||||||
//g.second.m_sdir.sampleEntries()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -58,7 +58,8 @@ private:
|
||||||
public:
|
public:
|
||||||
explicit ProjectModel(const QString& path, QObject* parent = Q_NULLPTR);
|
explicit ProjectModel(const QString& path, QObject* parent = Q_NULLPTR);
|
||||||
|
|
||||||
bool importGroupData(const QString& groupName, amuse::IntrusiveAudioGroupData&& data, ImportMode mode);
|
bool importGroupData(const QString& groupName, amuse::IntrusiveAudioGroupData&& data);
|
||||||
|
bool extractSamples(ImportMode mode, QWidget* parent);
|
||||||
bool saveToFile(QWidget* parent);
|
bool saveToFile(QWidget* parent);
|
||||||
|
|
||||||
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
|
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
|
|
@ -9,30 +9,26 @@ namespace amuse
|
||||||
{
|
{
|
||||||
class AudioGroupData;
|
class AudioGroupData;
|
||||||
|
|
||||||
using Sample = std::pair<AudioGroupSampleDirectory::Entry, AudioGroupSampleDirectory::ADPCMParms>;
|
|
||||||
|
|
||||||
/** Runtime audio group index container */
|
/** Runtime audio group index container */
|
||||||
class AudioGroup
|
class AudioGroup
|
||||||
{
|
{
|
||||||
AudioGroupProject m_proj;
|
AudioGroupProject m_proj;
|
||||||
AudioGroupPool m_pool;
|
AudioGroupPool m_pool;
|
||||||
AudioGroupSampleDirectory m_sdir;
|
AudioGroupSampleDirectory m_sdir;
|
||||||
const unsigned char* m_samp;
|
const unsigned char* m_samp = nullptr;
|
||||||
DataFormat m_fmt;
|
SystemString m_groupPath;
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
operator bool() const { return m_valid; }
|
operator bool() const { return m_valid; }
|
||||||
AudioGroup(const AudioGroupData& data, GCNDataTag);
|
explicit AudioGroup(const AudioGroupData& data);
|
||||||
AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag);
|
explicit AudioGroup(SystemStringView groupPath);
|
||||||
AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag);
|
|
||||||
|
|
||||||
const Sample* getSample(int sfxId) const;
|
const AudioGroupSampleDirectory::Entry* getSample(SampleId sfxId) const;
|
||||||
const unsigned char* getSampleData(uint32_t offset) const;
|
const unsigned char* getSampleData(SampleId sfxId, const AudioGroupSampleDirectory::Entry* 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; }
|
||||||
DataFormat getDataFormat() const { return m_fmt; }
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "Entity.hpp"
|
#include "Entity.hpp"
|
||||||
#include "Common.hpp"
|
#include "Common.hpp"
|
||||||
|
#include "athena/MemoryReader.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
@ -122,9 +123,6 @@ struct SoundMacro
|
||||||
Invalid = 0xff
|
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 */
|
/** Base command interface. All versions of MusyX encode little-endian parameters */
|
||||||
struct ICmd : LittleDNAV
|
struct ICmd : LittleDNAV
|
||||||
{
|
{
|
||||||
|
@ -955,6 +953,11 @@ struct SoundMacro
|
||||||
CmdOp Isa() const { return CmdOp::IfLess; }
|
CmdOp Isa() const { return CmdOp::IfLess; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
static std::unique_ptr<ICmd> MakeCmd(R& r);
|
||||||
|
static std::string_view CmdOpToStr(CmdOp op);
|
||||||
|
static CmdOp CmdStrToOp(std::string_view op);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<ICmd>> m_cmds;
|
std::vector<std::unique_ptr<ICmd>> m_cmds;
|
||||||
int assertPC(int pc) const;
|
int assertPC(int pc) const;
|
||||||
|
|
||||||
|
@ -977,6 +980,13 @@ struct ITable : LittleDNAV
|
||||||
{
|
{
|
||||||
AT_DECL_DNA_YAML
|
AT_DECL_DNA_YAML
|
||||||
AT_DECL_DNAV
|
AT_DECL_DNAV
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
ADSR,
|
||||||
|
ADSRDLS,
|
||||||
|
Curve
|
||||||
|
};
|
||||||
|
virtual Type Isa() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Defines phase-based volume curve for macro volume control */
|
/** Defines phase-based volume curve for macro volume control */
|
||||||
|
@ -993,6 +1003,8 @@ struct ADSR : ITable
|
||||||
double getDecay() const { return (decay == 0x8000) ? 0.0 : (decay / 1000.0); }
|
double getDecay() const { return (decay == 0x8000) ? 0.0 : (decay / 1000.0); }
|
||||||
double getSustain() const { return sustain / double(0x1000); }
|
double getSustain() const { return sustain / double(0x1000); }
|
||||||
double getRelease() const { return release / 1000.0; }
|
double getRelease() const { return release / 1000.0; }
|
||||||
|
|
||||||
|
Type Isa() const { return ITable::Type::ADSR; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Defines phase-based volume curve for macro volume control (modified DLS standard) */
|
/** Defines phase-based volume curve for macro volume control (modified DLS standard) */
|
||||||
|
@ -1023,6 +1035,8 @@ struct ADSRDLS : ITable
|
||||||
return getDecay();
|
return getDecay();
|
||||||
return getDecay() + note * (keyToDecay / 65536.0 / 1000.0) / 128.0;
|
return getDecay() + note * (keyToDecay / 65536.0 / 1000.0) / 128.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type Isa() const { return ITable::Type::ADSRDLS; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Defines arbitrary data for use as volume curve */
|
/** Defines arbitrary data for use as volume curve */
|
||||||
|
@ -1031,6 +1045,8 @@ struct Curve : ITable
|
||||||
AT_DECL_EXPLICIT_DNA_YAML
|
AT_DECL_EXPLICIT_DNA_YAML
|
||||||
AT_DECL_DNAV
|
AT_DECL_DNAV
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
Type Isa() const { return ITable::Type::Curve; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Maps individual MIDI keys to sound-entity as indexed in table
|
/** Maps individual MIDI keys to sound-entity as indexed in table
|
||||||
|
@ -1128,25 +1144,26 @@ struct LayerMapping : BigDNA
|
||||||
/** Database of functional objects within Audio Group */
|
/** Database of functional objects within Audio Group */
|
||||||
class AudioGroupPool
|
class AudioGroupPool
|
||||||
{
|
{
|
||||||
std::unordered_map<ObjectId, SoundMacro> m_soundMacros;
|
std::unordered_map<SoundMacroId, SoundMacro> m_soundMacros;
|
||||||
std::unordered_map<ObjectId, std::unique_ptr<ITable>> m_tables;
|
std::unordered_map<TableId, std::unique_ptr<ITable>> m_tables;
|
||||||
std::unordered_map<ObjectId, Keymap> m_keymaps;
|
std::unordered_map<KeymapId, Keymap> m_keymaps;
|
||||||
std::unordered_map<ObjectId, std::vector<LayerMapping>> m_layers;
|
std::unordered_map<LayersId, std::vector<LayerMapping>> m_layers;
|
||||||
|
|
||||||
AudioGroupPool() = default;
|
AudioGroupPool() = default;
|
||||||
template <athena::Endian DNAE>
|
template <athena::Endian DNAE>
|
||||||
static AudioGroupPool _AudioGroupPool(athena::io::IStreamReader& r);
|
static AudioGroupPool _AudioGroupPool(athena::io::IStreamReader& r);
|
||||||
public:
|
public:
|
||||||
static AudioGroupPool CreateAudioGroupPool(const AudioGroupData& data);
|
static AudioGroupPool CreateAudioGroupPool(const AudioGroupData& data);
|
||||||
|
static AudioGroupPool CreateAudioGroupPool(SystemStringView groupPath);
|
||||||
|
|
||||||
const SoundMacro* soundMacro(ObjectId id) const;
|
const SoundMacro* soundMacro(ObjectId id) const;
|
||||||
const Keymap* keymap(ObjectId id) const;
|
const Keymap* keymap(ObjectId id) const;
|
||||||
const std::vector<LayerMapping>* layer(ObjectId id) const;
|
const std::vector<LayerMapping>* layer(ObjectId id) const;
|
||||||
const ADSR* tableAsAdsr(ObjectId id) const;
|
const ADSR* tableAsAdsr(ObjectId id) const;
|
||||||
const ADSRDLS* tableAsAdsrDLS(ObjectId id) const { return reinterpret_cast<const ADSRDLS*>(tableAsAdsr(id)); }
|
const ADSRDLS* tableAsAdsrDLS(ObjectId id) const;
|
||||||
const Curve* tableAsCurves(ObjectId id) const { return reinterpret_cast<const Curve*>(tableAsAdsr(id)); }
|
const Curve* tableAsCurves(ObjectId id) const;
|
||||||
|
|
||||||
bool toYAML(athena::io::IStreamWriter& w) const;
|
bool toYAML(SystemStringView groupPath) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,7 @@ class AudioGroupProject
|
||||||
static void BootstrapObjectIDs(athena::io::IStreamReader& r, bool absOffs);
|
static void BootstrapObjectIDs(athena::io::IStreamReader& r, bool absOffs);
|
||||||
public:
|
public:
|
||||||
static AudioGroupProject CreateAudioGroupProject(const AudioGroupData& data);
|
static AudioGroupProject CreateAudioGroupProject(const AudioGroupData& data);
|
||||||
|
static AudioGroupProject CreateAudioGroupProject(SystemStringView groupPath);
|
||||||
static void BootstrapObjectIDs(const AudioGroupData& data);
|
static void BootstrapObjectIDs(const AudioGroupData& data);
|
||||||
|
|
||||||
const SongGroupIndex* getSongGroupIndex(int groupId) const;
|
const SongGroupIndex* getSongGroupIndex(int groupId) const;
|
||||||
|
@ -201,7 +202,7 @@ public:
|
||||||
const std::unordered_map<int, SongGroupIndex>& songGroups() const { return m_songGroups; }
|
const std::unordered_map<int, SongGroupIndex>& songGroups() const { return m_songGroups; }
|
||||||
const std::unordered_map<int, SFXGroupIndex>& sfxGroups() const { return m_sfxGroups; }
|
const std::unordered_map<int, SFXGroupIndex>& sfxGroups() const { return m_sfxGroups; }
|
||||||
|
|
||||||
bool toYAML(athena::io::IStreamWriter& w) const;
|
bool toYAML(SystemStringView groupPath) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,18 +9,135 @@ namespace amuse
|
||||||
{
|
{
|
||||||
class AudioGroupData;
|
class AudioGroupData;
|
||||||
|
|
||||||
|
struct DSPADPCMHeader : BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA
|
||||||
|
Value<atUint32> x0_num_samples;
|
||||||
|
Value<atUint32> x4_num_nibbles;
|
||||||
|
Value<atUint32> x8_sample_rate;
|
||||||
|
Value<atUint16> xc_loop_flag;
|
||||||
|
Value<atUint16> xe_format = 0; /* 0 for ADPCM */
|
||||||
|
Value<atUint32> x10_loop_start_nibble = 0;
|
||||||
|
Value<atUint32> x14_loop_end_nibble = 0;
|
||||||
|
Value<atUint32> x18_ca = 0;
|
||||||
|
Value<atInt16> x1c_coef[8][2];
|
||||||
|
Value<atInt16> x3c_gain = 0;
|
||||||
|
Value<atInt16> x3e_ps;
|
||||||
|
Value<atInt16> x40_hist1;
|
||||||
|
Value<atInt16> x42_hist2;
|
||||||
|
Value<atInt16> x44_loop_ps;
|
||||||
|
Value<atInt16> x46_loop_hist1 = 0;
|
||||||
|
Value<atInt16> x48_loop_hist2 = 0;
|
||||||
|
Value<atUint8> m_pitch = 0; // Stash this in the padding
|
||||||
|
Seek<21, athena::Current> pad;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WAVFormatChunk : LittleDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA
|
||||||
|
Value<atUint16> sampleFmt = 1;
|
||||||
|
Value<atUint16> numChannels = 1;
|
||||||
|
Value<atUint32> sampleRate;
|
||||||
|
Value<atUint32> byteRate; // sampleRate * numChannels * bitsPerSample/8
|
||||||
|
Value<atUint16> blockAlign = 2; // numChannels * bitsPerSample/8
|
||||||
|
Value<atUint16> bitsPerSample = 16;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WAVSampleChunk : LittleDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA
|
||||||
|
Value<atUint32> smplManufacturer = 0;
|
||||||
|
Value<atUint32> smplProduct = 0;
|
||||||
|
Value<atUint32> smplPeriod; // 1 / sampleRate in nanoseconds
|
||||||
|
Value<atUint32> midiNote; // native MIDI note of sample
|
||||||
|
Value<atUint32> midiPitchFrac = 0;
|
||||||
|
Value<atUint32> smpteFormat = 0;
|
||||||
|
Value<atUint32> smpteOffset = 0;
|
||||||
|
Value<atUint32> numSampleLoops = 0;
|
||||||
|
Value<atUint32> additionalDataSize = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WAVSampleLoop : LittleDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA
|
||||||
|
Value<atUint32> cuePointId = 0;
|
||||||
|
Value<atUint32> loopType = 0; // 0: forward loop
|
||||||
|
Value<atUint32> start; // in bytes
|
||||||
|
Value<atUint32> end; // in bytes
|
||||||
|
Value<atUint32> fraction = 0;
|
||||||
|
Value<atUint32> playCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WAVHeader : LittleDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA
|
||||||
|
Value<atUint32> riffMagic = SBIG('RIFF');
|
||||||
|
Value<atUint32> wavChuckSize; // everything - 8
|
||||||
|
Value<atUint32> wavMagic = SBIG('WAVE');
|
||||||
|
|
||||||
|
Value<atUint32> fmtMagic = SBIG('fmt ');
|
||||||
|
Value<atUint32> fmtChunkSize = 16;
|
||||||
|
WAVFormatChunk fmtChunk;
|
||||||
|
|
||||||
|
Value<atUint32> smplMagic = SBIG('smpl');
|
||||||
|
Value<atUint32> smplChunkSize = 36; // 36 + numSampleLoops*24
|
||||||
|
WAVSampleChunk smplChunk;
|
||||||
|
|
||||||
|
Value<atUint32> dataMagic = SBIG('data');
|
||||||
|
Value<atUint32> dataChunkSize; // numSamples * numChannels * bitsPerSample/8
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WAVHeaderLoop : LittleDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA
|
||||||
|
Value<atUint32> riffMagic = SBIG('RIFF');
|
||||||
|
Value<atUint32> wavChuckSize; // everything - 8
|
||||||
|
Value<atUint32> wavMagic = SBIG('WAVE');
|
||||||
|
|
||||||
|
Value<atUint32> fmtMagic = SBIG('fmt ');
|
||||||
|
Value<atUint32> fmtChunkSize = 16;
|
||||||
|
WAVFormatChunk fmtChunk;
|
||||||
|
|
||||||
|
Value<atUint32> smplMagic = SBIG('smpl');
|
||||||
|
Value<atUint32> smplChunkSize = 60; // 36 + numSampleLoops*24
|
||||||
|
WAVSampleChunk smplChunk;
|
||||||
|
WAVSampleLoop sampleLoop;
|
||||||
|
|
||||||
|
Value<atUint32> dataMagic = SBIG('data');
|
||||||
|
Value<atUint32> dataChunkSize; // numSamples * numChannels * bitsPerSample/8
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SampleFormat : uint8_t
|
||||||
|
{
|
||||||
|
DSP, /**< GCN DSP-ucode ADPCM (very common for GameCube games) */
|
||||||
|
DSP_DRUM, /**< GCN DSP-ucode ADPCM (seems to be set into drum samples for expanding their amplitude appropriately) */
|
||||||
|
PCM, /**< Big-endian PCM found in MusyX2 demo GM instruments */
|
||||||
|
N64, /**< 2-stage VADPCM coding with SAMP-embedded codebooks */
|
||||||
|
PCM_PC /**< Little-endian PCM found in PC Rogue Squadron (actually enum 0 which conflicts with DSP-ADPCM) */
|
||||||
|
};
|
||||||
|
|
||||||
/** Indexes individual samples in SAMP chunk */
|
/** Indexes individual samples in SAMP chunk */
|
||||||
class AudioGroupSampleDirectory
|
class AudioGroupSampleDirectory
|
||||||
{
|
{
|
||||||
friend class AudioGroup;
|
friend class AudioGroup;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class SampleFormat : atUint8
|
union ADPCMParms {
|
||||||
|
struct DSPParms
|
||||||
{
|
{
|
||||||
DSP,
|
uint16_t m_bytesPerFrame;
|
||||||
DSP2,
|
uint8_t m_ps;
|
||||||
PCM,
|
uint8_t m_lps;
|
||||||
N64
|
int16_t m_hist2;
|
||||||
|
int16_t m_hist1;
|
||||||
|
int16_t m_coefs[8][2];
|
||||||
|
} dsp;
|
||||||
|
struct VADPCMParms
|
||||||
|
{
|
||||||
|
int16_t m_coefs[8][2][8];
|
||||||
|
} vadpcm;
|
||||||
|
void swapBigDSP();
|
||||||
|
void swapBigVADPCM();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <athena::Endian DNAEn>
|
template <athena::Endian DNAEn>
|
||||||
|
@ -28,11 +145,12 @@ public:
|
||||||
EntryDNA : BigDNA
|
EntryDNA : BigDNA
|
||||||
{
|
{
|
||||||
AT_DECL_DNA
|
AT_DECL_DNA
|
||||||
SFXIdDNA<DNAEn> m_sfxId;
|
SampleIdDNA<DNAEn> m_sfxId;
|
||||||
|
Seek<2, athena::Current> pad;
|
||||||
Value<atUint32, DNAEn> m_sampleOff;
|
Value<atUint32, DNAEn> m_sampleOff;
|
||||||
Value<atUint32, DNAEn> m_unk;
|
Value<atUint32, DNAEn> m_unk;
|
||||||
Value<atUint8, DNAEn> m_pitch;
|
Value<atUint8, DNAEn> m_pitch;
|
||||||
Seek<1, athena::Current> pad;
|
Seek<1, athena::Current> pad2;
|
||||||
Value<atUint16, DNAEn> m_sampleRate;
|
Value<atUint16, DNAEn> m_sampleRate;
|
||||||
Value<atUint32, DNAEn> m_numSamples; // Top 8 bits is SampleFormat
|
Value<atUint32, DNAEn> m_numSamples; // Top 8 bits is SampleFormat
|
||||||
Value<atUint32, DNAEn> m_loopStartSample;
|
Value<atUint32, DNAEn> m_loopStartSample;
|
||||||
|
@ -44,7 +162,8 @@ public:
|
||||||
MusyX1SdirEntry : BigDNA
|
MusyX1SdirEntry : BigDNA
|
||||||
{
|
{
|
||||||
AT_DECL_DNA
|
AT_DECL_DNA
|
||||||
SFXIdDNA<DNAEn> m_sfxId;
|
SampleIdDNA<DNAEn> m_sfxId;
|
||||||
|
Seek<2, athena::Current> pad;
|
||||||
Value<atUint32, DNAEn> m_sampleOff;
|
Value<atUint32, DNAEn> m_sampleOff;
|
||||||
Value<atUint32, DNAEn> m_pitchSampleRate;
|
Value<atUint32, DNAEn> m_pitchSampleRate;
|
||||||
Value<atUint32, DNAEn> m_numSamples;
|
Value<atUint32, DNAEn> m_numSamples;
|
||||||
|
@ -56,7 +175,8 @@ public:
|
||||||
MusyX1AbsSdirEntry : BigDNA
|
MusyX1AbsSdirEntry : BigDNA
|
||||||
{
|
{
|
||||||
AT_DECL_DNA
|
AT_DECL_DNA
|
||||||
SFXIdDNA<DNAEn> m_sfxId;
|
SampleIdDNA<DNAEn> m_sfxId;
|
||||||
|
Seek<2, athena::Current> pad;
|
||||||
Value<uint32_t, DNAEn> m_sampleOff;
|
Value<uint32_t, DNAEn> m_sampleOff;
|
||||||
Value<uint32_t, DNAEn> m_unk;
|
Value<uint32_t, DNAEn> m_unk;
|
||||||
Value<uint32_t, DNAEn> m_pitchSampleRate;
|
Value<uint32_t, DNAEn> m_pitchSampleRate;
|
||||||
|
@ -66,14 +186,23 @@ public:
|
||||||
};
|
};
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
atUint32 m_sampleOff;
|
atUint32 m_sampleOff = 0;
|
||||||
atUint32 m_unk;
|
atUint32 m_unk = 0;
|
||||||
atUint8 m_pitch;
|
atUint8 m_pitch = 0;
|
||||||
atUint16 m_sampleRate;
|
atUint16 m_sampleRate = 0;
|
||||||
atUint32 m_numSamples; // Top 8 bits is SampleFormat
|
atUint32 m_numSamples = 0; // Top 8 bits is SampleFormat
|
||||||
atUint32 m_loopStartSample;
|
atUint32 m_loopStartSample = 0;
|
||||||
atUint32 m_loopLengthSamples;
|
atUint32 m_loopLengthSamples = 0;
|
||||||
atUint32 m_adpcmParmOffset;
|
atUint32 m_adpcmParmOffset = 0;
|
||||||
|
|
||||||
|
/* Stored out-of-band in a platform-dependent way */
|
||||||
|
ADPCMParms m_ADPCMParms;
|
||||||
|
|
||||||
|
/* In-memory storage of an individual sample. Editors use this structure
|
||||||
|
* to override the loaded sample with a file-backed version without repacking
|
||||||
|
* the sample data into a SAMP block. */
|
||||||
|
time_t m_looseModTime = 0;
|
||||||
|
std::unique_ptr<uint8_t[]> m_looseData;
|
||||||
|
|
||||||
Entry() = default;
|
Entry() = default;
|
||||||
|
|
||||||
|
@ -113,36 +242,32 @@ public:
|
||||||
ret.m_adpcmParmOffset = m_adpcmParmOffset;
|
ret.m_adpcmParmOffset = m_adpcmParmOffset;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
union ADPCMParms {
|
void loadLooseData(SystemStringView basePath);
|
||||||
struct DSPParms
|
|
||||||
{
|
|
||||||
uint16_t m_bytesPerFrame;
|
|
||||||
uint8_t m_ps;
|
|
||||||
uint8_t m_lps;
|
|
||||||
int16_t m_hist2;
|
|
||||||
int16_t m_hist1;
|
|
||||||
int16_t m_coefs[8][2];
|
|
||||||
} dsp;
|
|
||||||
struct VADPCMParms
|
|
||||||
{
|
|
||||||
int16_t m_coefs[8][2][8];
|
|
||||||
} vadpcm;
|
|
||||||
void swapBigDSP();
|
|
||||||
void swapBigVADPCM();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<SFXId, std::pair<Entry, ADPCMParms>> m_entries;
|
std::unordered_map<SampleId, Entry> m_entries;
|
||||||
|
static void _extractWAV(SampleId id, const Entry& ent, amuse::SystemStringView destDir,
|
||||||
|
const unsigned char* samp);
|
||||||
|
static void _extractCompressed(SampleId id, const Entry& ent, amuse::SystemStringView destDir,
|
||||||
|
const unsigned char* samp);
|
||||||
|
|
||||||
|
AudioGroupSampleDirectory() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioGroupSampleDirectory(athena::io::IStreamReader& r, GCNDataTag);
|
AudioGroupSampleDirectory(athena::io::IStreamReader& r, GCNDataTag);
|
||||||
AudioGroupSampleDirectory(athena::io::IStreamReader& r, const unsigned char* sampData, bool absOffs, N64DataTag);
|
AudioGroupSampleDirectory(athena::io::IStreamReader& r, const unsigned char* sampData, bool absOffs, N64DataTag);
|
||||||
AudioGroupSampleDirectory(athena::io::IStreamReader& r, bool absOffs, PCDataTag);
|
AudioGroupSampleDirectory(athena::io::IStreamReader& r, bool absOffs, PCDataTag);
|
||||||
static AudioGroupSampleDirectory CreateAudioGroupSampleDirectory(const AudioGroupData& data);
|
static AudioGroupSampleDirectory CreateAudioGroupSampleDirectory(const AudioGroupData& data);
|
||||||
|
static AudioGroupSampleDirectory CreateAudioGroupSampleDirectory(SystemStringView groupPath);
|
||||||
|
|
||||||
const std::unordered_map<SFXId, std::pair<Entry, ADPCMParms>>& sampleEntries() const { return m_entries; }
|
const std::unordered_map<SampleId, Entry>& sampleEntries() const { return m_entries; }
|
||||||
|
|
||||||
|
void extractWAV(SampleId id, 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 extractAllCompressed(amuse::SystemStringView destDir, const unsigned char* samp) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -464,7 +464,7 @@ struct NameDB
|
||||||
std::unordered_map<std::string, ObjectId> m_stringToId;
|
std::unordered_map<std::string, ObjectId> m_stringToId;
|
||||||
std::unordered_map<ObjectId, std::string> m_idToString;
|
std::unordered_map<ObjectId, std::string> m_idToString;
|
||||||
|
|
||||||
ObjectId generateId(Type tp);
|
ObjectId generateId(Type tp) const;
|
||||||
static std::string generateName(ObjectId id, Type tp);
|
static std::string generateName(ObjectId id, Type tp);
|
||||||
std::string_view registerPair(std::string_view str, ObjectId id);
|
std::string_view registerPair(std::string_view str, ObjectId id);
|
||||||
std::string_view resolveNameFromId(ObjectId id) const;
|
std::string_view resolveNameFromId(ObjectId id) const;
|
||||||
|
|
|
@ -58,16 +58,7 @@ class Voice : public Entity
|
||||||
std::list<std::shared_ptr<Voice>> m_childVoices; /**< Child voices for PLAYMACRO usage */
|
std::list<std::shared_ptr<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 */
|
||||||
|
|
||||||
enum class SampleFormat : uint8_t
|
const AudioGroupSampleDirectory::Entry* m_curSample = nullptr; /**< Current sample entry playing */
|
||||||
{
|
|
||||||
DSP, /**< GCN DSP-ucode ADPCM (very common for GameCube games) */
|
|
||||||
DSP_DRUM, /**< GCN DSP-ucode ADPCM (seems to be set into drum samples for expanding their amplitude
|
|
||||||
appropriately) */
|
|
||||||
PCM, /**< Big-endian PCM found in MusyX2 demo GM instruments */
|
|
||||||
N64, /**< 2-stage VADPCM coding with SAMP-embedded codebooks */
|
|
||||||
PCM_PC /**< Little-endian PCM found in PC Rogue Squadron (actually enum 0 which conflicts with DSP-ADPCM) */
|
|
||||||
};
|
|
||||||
const Sample* m_curSample = nullptr; /**< 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 */
|
||||||
|
@ -236,7 +227,7 @@ public:
|
||||||
void message(int32_t val);
|
void message(int32_t val);
|
||||||
|
|
||||||
/** Start playing specified sample from within group, optionally by sample offset */
|
/** Start playing specified sample from within group, optionally by sample offset */
|
||||||
void startSample(int16_t sampId, int32_t offset);
|
void startSample(SampleId sampId, int32_t offset);
|
||||||
|
|
||||||
/** Stop playing current sample */
|
/** Stop playing current sample */
|
||||||
void stopSample();
|
void stopSample();
|
||||||
|
|
|
@ -4,34 +4,21 @@
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
AudioGroup::AudioGroup(const AudioGroupData& data, GCNDataTag)
|
AudioGroup::AudioGroup(const AudioGroupData& data)
|
||||||
: m_proj(AudioGroupProject::CreateAudioGroupProject(data))
|
: m_proj(AudioGroupProject::CreateAudioGroupProject(data))
|
||||||
, m_pool(AudioGroupPool::CreateAudioGroupPool(data))
|
, m_pool(AudioGroupPool::CreateAudioGroupPool(data))
|
||||||
, m_sdir(AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(data))
|
, m_sdir(AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(data))
|
||||||
, m_samp(data.getSamp())
|
, m_samp(data.getSamp())
|
||||||
, m_fmt(DataFormat::GCN)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag)
|
AudioGroup::AudioGroup(SystemStringView groupPath)
|
||||||
: m_proj(AudioGroupProject::CreateAudioGroupProject(data))
|
: m_proj(AudioGroupProject::CreateAudioGroupProject(groupPath))
|
||||||
, m_pool(AudioGroupPool::CreateAudioGroupPool(data))
|
, m_pool(AudioGroupPool::CreateAudioGroupPool(groupPath))
|
||||||
, m_sdir(AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(data))
|
, m_sdir(AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(groupPath))
|
||||||
, m_samp(data.getSamp())
|
, m_groupPath(groupPath)
|
||||||
, m_fmt(DataFormat::N64)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag)
|
const AudioGroupSampleDirectory::Entry* AudioGroup::getSample(SampleId sfxId) const
|
||||||
: m_proj(AudioGroupProject::CreateAudioGroupProject(data))
|
|
||||||
, m_pool(AudioGroupPool::CreateAudioGroupPool(data))
|
|
||||||
, m_sdir(AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(data))
|
|
||||||
, m_samp(data.getSamp())
|
|
||||||
, m_fmt(DataFormat::PC)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const Sample* AudioGroup::getSample(int 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())
|
||||||
|
@ -39,5 +26,20 @@ const Sample* AudioGroup::getSample(int sfxId) const
|
||||||
return &search->second;
|
return &search->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char* AudioGroup::getSampleData(uint32_t offset) const { return m_samp + offset; }
|
const unsigned char* AudioGroup::getSampleData(SampleId sfxId, const AudioGroupSampleDirectory::Entry* sample) const
|
||||||
|
{
|
||||||
|
if (sample->m_looseData)
|
||||||
|
{
|
||||||
|
#if _WIN32
|
||||||
|
SystemString basePath = m_groupPath + _S('/') +
|
||||||
|
athena::utility::utf8ToWide(SampleId::CurNameDB->resolveNameFromId(sfxId));
|
||||||
|
#else
|
||||||
|
SystemString basePath = m_groupPath + _S('/') +
|
||||||
|
SampleId::CurNameDB->resolveNameFromId(sfxId).data();
|
||||||
|
#endif
|
||||||
|
const_cast<AudioGroupSampleDirectory::Entry*>(sample)->loadLooseData(basePath);
|
||||||
|
return sample->m_looseData.get();
|
||||||
|
}
|
||||||
|
return m_samp + sample->m_sampleOff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
#include "amuse/Common.hpp"
|
#include "amuse/Common.hpp"
|
||||||
#include "amuse/Entity.hpp"
|
#include "amuse/Entity.hpp"
|
||||||
#include "amuse/AudioGroupData.hpp"
|
#include "amuse/AudioGroupData.hpp"
|
||||||
#include "athena/MemoryReader.hpp"
|
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
|
#include "athena/FileWriter.hpp"
|
||||||
|
#include "athena/FileReader.hpp"
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
|
@ -51,11 +52,11 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
|
||||||
auto& ptr = ret.m_tables[objHead.objectId.id];
|
auto& ptr = ret.m_tables[objHead.objectId.id];
|
||||||
switch (objHead.size)
|
switch (objHead.size)
|
||||||
{
|
{
|
||||||
case 8:
|
case 0x10:
|
||||||
ptr = std::make_unique<ADSR>();
|
ptr = std::make_unique<ADSR>();
|
||||||
static_cast<ADSR&>(*ptr).read(r);
|
static_cast<ADSR&>(*ptr).read(r);
|
||||||
break;
|
break;
|
||||||
case 0x14:
|
case 0x1c:
|
||||||
ptr = std::make_unique<ADSRDLS>();
|
ptr = std::make_unique<ADSRDLS>();
|
||||||
static_cast<ADSRDLS&>(*ptr).read(r);
|
static_cast<ADSRDLS&>(*ptr).read(r);
|
||||||
break;
|
break;
|
||||||
|
@ -123,11 +124,147 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(const AudioGroupData& data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Tp>
|
AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
static std::unique_ptr<SoundMacro::ICmd> MakeCmd(athena::io::MemoryReader& r)
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<SoundMacro::ICmd> ret = std::make_unique<Tp>();
|
AudioGroupPool ret;
|
||||||
static_cast<Tp&>(*ret).read(r);
|
SystemString poolPath(groupPath);
|
||||||
|
poolPath += _S("/!pool.yaml");
|
||||||
|
athena::io::FileReader fi(poolPath);
|
||||||
|
|
||||||
|
if (!fi.hasError())
|
||||||
|
{
|
||||||
|
athena::io::YAMLDocReader r;
|
||||||
|
if (r.parse(&fi) && r.ValidateClassType("amuse::Pool"))
|
||||||
|
{
|
||||||
|
if (auto __r = r.enterSubRecord("soundMacros"))
|
||||||
|
{
|
||||||
|
ret.m_soundMacros.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
for (const auto& sm : r.getCurNode()->m_mapChildren)
|
||||||
|
{
|
||||||
|
ObjectId macroId = SoundMacroId::CurNameDB->generateId(NameDB::Type::SoundMacro);
|
||||||
|
SoundMacroId::CurNameDB->registerPair(sm.first, macroId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto __r = r.enterSubRecord("tables"))
|
||||||
|
{
|
||||||
|
ret.m_tables.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
for (const auto& t : r.getCurNode()->m_mapChildren)
|
||||||
|
{
|
||||||
|
if (auto __v = r.enterSubRecord(t.first.c_str()))
|
||||||
|
{
|
||||||
|
ObjectId tableId = TableId::CurNameDB->generateId(NameDB::Type::Table);
|
||||||
|
TableId::CurNameDB->registerPair(t.first, tableId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto __r = r.enterSubRecord("keymaps"))
|
||||||
|
{
|
||||||
|
ret.m_keymaps.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
for (const auto& k : r.getCurNode()->m_mapChildren)
|
||||||
|
if (auto __v = r.enterSubRecord(k.first.c_str()))
|
||||||
|
{
|
||||||
|
ObjectId keymapId = KeymapId::CurNameDB->generateId(NameDB::Type::Keymap);
|
||||||
|
KeymapId::CurNameDB->registerPair(k.first, keymapId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto __r = r.enterSubRecord("layers"))
|
||||||
|
{
|
||||||
|
for (const auto& l : r.getCurNode()->m_mapChildren)
|
||||||
|
{
|
||||||
|
size_t mappingCount;
|
||||||
|
if (auto __v = r.enterSubVector(l.first.c_str(), mappingCount))
|
||||||
|
{
|
||||||
|
ObjectId layersId = LayersId::CurNameDB->generateId(NameDB::Type::Layer);
|
||||||
|
LayersId::CurNameDB->registerPair(l.first, layersId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto __r = r.enterSubRecord("soundMacros"))
|
||||||
|
{
|
||||||
|
ret.m_soundMacros.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
for (const auto& sm : r.getCurNode()->m_mapChildren)
|
||||||
|
{
|
||||||
|
SoundMacro& smOut = ret.m_soundMacros[SoundMacroId::CurNameDB->resolveIdFromName(sm.first)];
|
||||||
|
size_t cmdCount;
|
||||||
|
if (auto __v = r.enterSubVector(sm.first.c_str(), cmdCount))
|
||||||
|
{
|
||||||
|
smOut.m_cmds.reserve(cmdCount);
|
||||||
|
for (int c = 0; c < cmdCount; ++c)
|
||||||
|
if (auto __r2 = r.enterSubRecord(nullptr))
|
||||||
|
smOut.m_cmds.push_back(SoundMacro::MakeCmd(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto __r = r.enterSubRecord("tables"))
|
||||||
|
{
|
||||||
|
ret.m_tables.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
for (const auto& t : r.getCurNode()->m_mapChildren)
|
||||||
|
{
|
||||||
|
if (auto __v = r.enterSubRecord(t.first.c_str()))
|
||||||
|
{
|
||||||
|
std::unique_ptr<ITable>& tableOut = ret.m_tables[TableId::CurNameDB->resolveIdFromName(t.first)];
|
||||||
|
if (auto __att = r.enterSubRecord("attack"))
|
||||||
|
{
|
||||||
|
__att.leave();
|
||||||
|
if (auto __vta = r.enterSubRecord("velToAttack"))
|
||||||
|
{
|
||||||
|
__vta.leave();
|
||||||
|
tableOut = std::make_unique<ADSRDLS>();
|
||||||
|
static_cast<ADSRDLS&>(*tableOut).read(r);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tableOut = std::make_unique<ADSR>();
|
||||||
|
static_cast<ADSR&>(*tableOut).read(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (auto __dat = r.enterSubRecord("data"))
|
||||||
|
{
|
||||||
|
__dat.leave();
|
||||||
|
tableOut = std::make_unique<Curve>();
|
||||||
|
static_cast<Curve&>(*tableOut).read(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto __r = r.enterSubRecord("keymaps"))
|
||||||
|
{
|
||||||
|
ret.m_keymaps.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
for (const auto& k : r.getCurNode()->m_mapChildren)
|
||||||
|
if (auto __v = r.enterSubRecord(k.first.c_str()))
|
||||||
|
ret.m_keymaps[KeymapId::CurNameDB->resolveIdFromName(k.first)].read(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto __r = r.enterSubRecord("layers"))
|
||||||
|
{
|
||||||
|
ret.m_layers.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
for (const auto& l : r.getCurNode()->m_mapChildren)
|
||||||
|
{
|
||||||
|
size_t mappingCount;
|
||||||
|
if (auto __v = r.enterSubVector(l.first.c_str(), mappingCount))
|
||||||
|
{
|
||||||
|
std::vector<LayerMapping>& layOut = ret.m_layers[LayersId::CurNameDB->resolveIdFromName(l.first)];
|
||||||
|
layOut.reserve(mappingCount);
|
||||||
|
for (int lm = 0; lm < mappingCount; ++lm)
|
||||||
|
{
|
||||||
|
if (auto __r2 = r.enterSubRecord(nullptr))
|
||||||
|
{
|
||||||
|
layOut.emplace_back();
|
||||||
|
layOut.back().read(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,167 +290,7 @@ void SoundMacro::readCmds(athena::io::IStreamReader& r, uint32_t size)
|
||||||
uint32_t data[2];
|
uint32_t data[2];
|
||||||
athena::io::Read<athena::io::PropType::None>::Do<decltype(data), DNAE>({}, data, r);
|
athena::io::Read<athena::io::PropType::None>::Do<decltype(data), DNAE>({}, data, r);
|
||||||
athena::io::MemoryReader r(data, 8);
|
athena::io::MemoryReader r(data, 8);
|
||||||
std::unique_ptr<ICmd> cmd;
|
m_cmds.push_back(MakeCmd(r));
|
||||||
switch (CmdOp(r.readUByte()))
|
|
||||||
{
|
|
||||||
case CmdOp::End:
|
|
||||||
cmd = MakeCmd<CmdEnd>(r); break;
|
|
||||||
case CmdOp::Stop:
|
|
||||||
cmd = MakeCmd<CmdStop>(r); break;
|
|
||||||
case CmdOp::SplitKey:
|
|
||||||
cmd = MakeCmd<CmdSplitKey>(r); break;
|
|
||||||
case CmdOp::SplitVel:
|
|
||||||
cmd = MakeCmd<CmdSplitVel>(r); break;
|
|
||||||
case CmdOp::WaitTicks:
|
|
||||||
cmd = MakeCmd<CmdWaitTicks>(r); break;
|
|
||||||
case CmdOp::Loop:
|
|
||||||
cmd = MakeCmd<CmdLoop>(r); break;
|
|
||||||
case CmdOp::Goto:
|
|
||||||
cmd = MakeCmd<CmdGoto>(r); break;
|
|
||||||
case CmdOp::WaitMs:
|
|
||||||
cmd = MakeCmd<CmdWaitMs>(r); break;
|
|
||||||
case CmdOp::PlayMacro:
|
|
||||||
cmd = MakeCmd<CmdPlayMacro>(r); break;
|
|
||||||
case CmdOp::SendKeyOff:
|
|
||||||
cmd = MakeCmd<CmdSendKeyOff>(r); break;
|
|
||||||
case CmdOp::SplitMod:
|
|
||||||
cmd = MakeCmd<CmdSplitMod>(r); break;
|
|
||||||
case CmdOp::PianoPan:
|
|
||||||
cmd = MakeCmd<CmdPianoPan>(r); break;
|
|
||||||
case CmdOp::SetAdsr:
|
|
||||||
cmd = MakeCmd<CmdSetAdsr>(r); break;
|
|
||||||
case CmdOp::ScaleVolume:
|
|
||||||
cmd = MakeCmd<CmdScaleVolume>(r); break;
|
|
||||||
case CmdOp::Panning:
|
|
||||||
cmd = MakeCmd<CmdPanning>(r); break;
|
|
||||||
case CmdOp::Envelope:
|
|
||||||
cmd = MakeCmd<CmdEnvelope>(r); break;
|
|
||||||
case CmdOp::StartSample:
|
|
||||||
cmd = MakeCmd<CmdStartSample>(r); break;
|
|
||||||
case CmdOp::StopSample:
|
|
||||||
cmd = MakeCmd<CmdStopSample>(r); break;
|
|
||||||
case CmdOp::KeyOff:
|
|
||||||
cmd = MakeCmd<CmdKeyOff>(r); break;
|
|
||||||
case CmdOp::SplitRnd:
|
|
||||||
cmd = MakeCmd<CmdSplitRnd>(r); break;
|
|
||||||
case CmdOp::FadeIn:
|
|
||||||
cmd = MakeCmd<CmdFadeIn>(r); break;
|
|
||||||
case CmdOp::Spanning:
|
|
||||||
cmd = MakeCmd<CmdSpanning>(r); break;
|
|
||||||
case CmdOp::SetAdsrCtrl:
|
|
||||||
cmd = MakeCmd<CmdSetAdsrCtrl>(r); break;
|
|
||||||
case CmdOp::RndNote:
|
|
||||||
cmd = MakeCmd<CmdRndNote>(r); break;
|
|
||||||
case CmdOp::AddNote:
|
|
||||||
cmd = MakeCmd<CmdAddNote>(r); break;
|
|
||||||
case CmdOp::SetNote:
|
|
||||||
cmd = MakeCmd<CmdSetNote>(r); break;
|
|
||||||
case CmdOp::LastNote:
|
|
||||||
cmd = MakeCmd<CmdLastNote>(r); break;
|
|
||||||
case CmdOp::Portamento:
|
|
||||||
cmd = MakeCmd<CmdPortamento>(r); break;
|
|
||||||
case CmdOp::Vibrato:
|
|
||||||
cmd = MakeCmd<CmdVibrato>(r); break;
|
|
||||||
case CmdOp::PitchSweep1:
|
|
||||||
cmd = MakeCmd<CmdPitchSweep1>(r); break;
|
|
||||||
case CmdOp::PitchSweep2:
|
|
||||||
cmd = MakeCmd<CmdPitchSweep2>(r); break;
|
|
||||||
case CmdOp::SetPitch:
|
|
||||||
cmd = MakeCmd<CmdSetPitch>(r); break;
|
|
||||||
case CmdOp::SetPitchAdsr:
|
|
||||||
cmd = MakeCmd<CmdSetPitchAdsr>(r); break;
|
|
||||||
case CmdOp::ScaleVolumeDLS:
|
|
||||||
cmd = MakeCmd<CmdScaleVolumeDLS>(r); break;
|
|
||||||
case CmdOp::Mod2Vibrange:
|
|
||||||
cmd = MakeCmd<CmdMod2Vibrange>(r); break;
|
|
||||||
case CmdOp::SetupTremolo:
|
|
||||||
cmd = MakeCmd<CmdSetupTremolo>(r); break;
|
|
||||||
case CmdOp::Return:
|
|
||||||
cmd = MakeCmd<CmdReturn>(r); break;
|
|
||||||
case CmdOp::GoSub:
|
|
||||||
cmd = MakeCmd<CmdGoSub>(r); break;
|
|
||||||
case CmdOp::TrapEvent:
|
|
||||||
cmd = MakeCmd<CmdTrapEvent>(r); break;
|
|
||||||
case CmdOp::UntrapEvent:
|
|
||||||
cmd = MakeCmd<CmdUntrapEvent>(r); break;
|
|
||||||
case CmdOp::SendMessage:
|
|
||||||
cmd = MakeCmd<CmdSendMessage>(r); break;
|
|
||||||
case CmdOp::GetMessage:
|
|
||||||
cmd = MakeCmd<CmdGetMessage>(r); break;
|
|
||||||
case CmdOp::GetVid:
|
|
||||||
cmd = MakeCmd<CmdGetVid>(r); break;
|
|
||||||
case CmdOp::AddAgeCount:
|
|
||||||
cmd = MakeCmd<CmdAddAgeCount>(r); break;
|
|
||||||
case CmdOp::SetAgeCount:
|
|
||||||
cmd = MakeCmd<CmdSetAgeCount>(r); break;
|
|
||||||
case CmdOp::SendFlag:
|
|
||||||
cmd = MakeCmd<CmdSendFlag>(r); break;
|
|
||||||
case CmdOp::PitchWheelR:
|
|
||||||
cmd = MakeCmd<CmdPitchWheelR>(r); break;
|
|
||||||
case CmdOp::SetPriority:
|
|
||||||
cmd = MakeCmd<CmdSetPriority>(r); break;
|
|
||||||
case CmdOp::AddPriority:
|
|
||||||
cmd = MakeCmd<CmdAddPriority>(r); break;
|
|
||||||
case CmdOp::AgeCntSpeed:
|
|
||||||
cmd = MakeCmd<CmdAgeCntSpeed>(r); break;
|
|
||||||
case CmdOp::AgeCntVel:
|
|
||||||
cmd = MakeCmd<CmdAgeCntVel>(r); break;
|
|
||||||
case CmdOp::VolSelect:
|
|
||||||
cmd = MakeCmd<CmdVolSelect>(r); break;
|
|
||||||
case CmdOp::PanSelect:
|
|
||||||
cmd = MakeCmd<CmdPanSelect>(r); break;
|
|
||||||
case CmdOp::PitchWheelSelect:
|
|
||||||
cmd = MakeCmd<CmdPitchWheelSelect>(r); break;
|
|
||||||
case CmdOp::ModWheelSelect:
|
|
||||||
cmd = MakeCmd<CmdModWheelSelect>(r); break;
|
|
||||||
case CmdOp::PedalSelect:
|
|
||||||
cmd = MakeCmd<CmdPedalSelect>(r); break;
|
|
||||||
case CmdOp::PortamentoSelect:
|
|
||||||
cmd = MakeCmd<CmdPortamentoSelect>(r); break;
|
|
||||||
case CmdOp::ReverbSelect:
|
|
||||||
cmd = MakeCmd<CmdReverbSelect>(r); break;
|
|
||||||
case CmdOp::SpanSelect:
|
|
||||||
cmd = MakeCmd<CmdSpanSelect>(r); break;
|
|
||||||
case CmdOp::DopplerSelect:
|
|
||||||
cmd = MakeCmd<CmdDopplerSelect>(r); break;
|
|
||||||
case CmdOp::TremoloSelect:
|
|
||||||
cmd = MakeCmd<CmdTremoloSelect>(r); break;
|
|
||||||
case CmdOp::PreASelect:
|
|
||||||
cmd = MakeCmd<CmdPreASelect>(r); break;
|
|
||||||
case CmdOp::PreBSelect:
|
|
||||||
cmd = MakeCmd<CmdPreBSelect>(r); break;
|
|
||||||
case CmdOp::PostBSelect:
|
|
||||||
cmd = MakeCmd<CmdPostBSelect>(r); break;
|
|
||||||
case CmdOp::AuxAFXSelect:
|
|
||||||
cmd = MakeCmd<CmdAuxAFXSelect>(r); break;
|
|
||||||
case CmdOp::AuxBFXSelect:
|
|
||||||
cmd = MakeCmd<CmdAuxBFXSelect>(r); break;
|
|
||||||
case CmdOp::SetupLFO:
|
|
||||||
cmd = MakeCmd<CmdSetupLFO>(r); break;
|
|
||||||
case CmdOp::ModeSelect:
|
|
||||||
cmd = MakeCmd<CmdModeSelect>(r); break;
|
|
||||||
case CmdOp::SetKeygroup:
|
|
||||||
cmd = MakeCmd<CmdSetKeygroup>(r); break;
|
|
||||||
case CmdOp::SRCmodeSelect:
|
|
||||||
cmd = MakeCmd<CmdSRCmodeSelect>(r); break;
|
|
||||||
case CmdOp::AddVars:
|
|
||||||
cmd = MakeCmd<CmdAddVars>(r); break;
|
|
||||||
case CmdOp::SubVars:
|
|
||||||
cmd = MakeCmd<CmdSubVars>(r); break;
|
|
||||||
case CmdOp::MulVars:
|
|
||||||
cmd = MakeCmd<CmdMulVars>(r); break;
|
|
||||||
case CmdOp::DivVars:
|
|
||||||
cmd = MakeCmd<CmdDivVars>(r); break;
|
|
||||||
case CmdOp::AddIVars:
|
|
||||||
cmd = MakeCmd<CmdAddIVars>(r); break;
|
|
||||||
case CmdOp::IfEqual:
|
|
||||||
cmd = MakeCmd<CmdIfEqual>(r); break;
|
|
||||||
case CmdOp::IfLess:
|
|
||||||
cmd = MakeCmd<CmdIfLess>(r); break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
m_cmds.push_back(std::move(cmd));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template void SoundMacro::readCmds<athena::Big>(athena::io::IStreamReader& r, uint32_t size);
|
template void SoundMacro::readCmds<athena::Big>(athena::io::IStreamReader& r, uint32_t size);
|
||||||
|
@ -346,11 +323,213 @@ 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())
|
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
|
||||||
|
{
|
||||||
|
auto search = m_tables.find(id);
|
||||||
|
if (search == m_tables.cend() || search->second->Isa() != ITable::Type::ADSRDLS)
|
||||||
|
return nullptr;
|
||||||
|
return static_cast<const ADSRDLS*>(search->second.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
const Curve* AudioGroupPool::tableAsCurves(ObjectId id) const
|
||||||
|
{
|
||||||
|
auto search = m_tables.find(id);
|
||||||
|
if (search == m_tables.cend() || search->second->Isa() != ITable::Type::Curve)
|
||||||
|
return nullptr;
|
||||||
|
return static_cast<const Curve*>(search->second.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Tp, class R>
|
||||||
|
static std::unique_ptr<SoundMacro::ICmd> _MakeCmd(R& r)
|
||||||
|
{
|
||||||
|
std::unique_ptr<SoundMacro::ICmd> ret = std::make_unique<Tp>();
|
||||||
|
static_cast<Tp&>(*ret).read(r);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SoundMacro::CmdOp _ReadCmdOp(athena::io::MemoryReader& r)
|
||||||
|
{
|
||||||
|
return SoundMacro::CmdOp(r.readUByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
static SoundMacro::CmdOp _ReadCmdOp(athena::io::YAMLDocReader& r)
|
||||||
|
{
|
||||||
|
return SoundMacro::CmdStrToOp(r.readString("cmdOp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
std::unique_ptr<SoundMacro::ICmd> SoundMacro::MakeCmd(R& r)
|
||||||
|
{
|
||||||
|
std::unique_ptr<ICmd> cmd;
|
||||||
|
switch (_ReadCmdOp(r))
|
||||||
|
{
|
||||||
|
case CmdOp::End:
|
||||||
|
cmd = _MakeCmd<CmdEnd>(r); break;
|
||||||
|
case CmdOp::Stop:
|
||||||
|
cmd = _MakeCmd<CmdStop>(r); break;
|
||||||
|
case CmdOp::SplitKey:
|
||||||
|
cmd = _MakeCmd<CmdSplitKey>(r); break;
|
||||||
|
case CmdOp::SplitVel:
|
||||||
|
cmd = _MakeCmd<CmdSplitVel>(r); break;
|
||||||
|
case CmdOp::WaitTicks:
|
||||||
|
cmd = _MakeCmd<CmdWaitTicks>(r); break;
|
||||||
|
case CmdOp::Loop:
|
||||||
|
cmd = _MakeCmd<CmdLoop>(r); break;
|
||||||
|
case CmdOp::Goto:
|
||||||
|
cmd = _MakeCmd<CmdGoto>(r); break;
|
||||||
|
case CmdOp::WaitMs:
|
||||||
|
cmd = _MakeCmd<CmdWaitMs>(r); break;
|
||||||
|
case CmdOp::PlayMacro:
|
||||||
|
cmd = _MakeCmd<CmdPlayMacro>(r); break;
|
||||||
|
case CmdOp::SendKeyOff:
|
||||||
|
cmd = _MakeCmd<CmdSendKeyOff>(r); break;
|
||||||
|
case CmdOp::SplitMod:
|
||||||
|
cmd = _MakeCmd<CmdSplitMod>(r); break;
|
||||||
|
case CmdOp::PianoPan:
|
||||||
|
cmd = _MakeCmd<CmdPianoPan>(r); break;
|
||||||
|
case CmdOp::SetAdsr:
|
||||||
|
cmd = _MakeCmd<CmdSetAdsr>(r); break;
|
||||||
|
case CmdOp::ScaleVolume:
|
||||||
|
cmd = _MakeCmd<CmdScaleVolume>(r); break;
|
||||||
|
case CmdOp::Panning:
|
||||||
|
cmd = _MakeCmd<CmdPanning>(r); break;
|
||||||
|
case CmdOp::Envelope:
|
||||||
|
cmd = _MakeCmd<CmdEnvelope>(r); break;
|
||||||
|
case CmdOp::StartSample:
|
||||||
|
cmd = _MakeCmd<CmdStartSample>(r); break;
|
||||||
|
case CmdOp::StopSample:
|
||||||
|
cmd = _MakeCmd<CmdStopSample>(r); break;
|
||||||
|
case CmdOp::KeyOff:
|
||||||
|
cmd = _MakeCmd<CmdKeyOff>(r); break;
|
||||||
|
case CmdOp::SplitRnd:
|
||||||
|
cmd = _MakeCmd<CmdSplitRnd>(r); break;
|
||||||
|
case CmdOp::FadeIn:
|
||||||
|
cmd = _MakeCmd<CmdFadeIn>(r); break;
|
||||||
|
case CmdOp::Spanning:
|
||||||
|
cmd = _MakeCmd<CmdSpanning>(r); break;
|
||||||
|
case CmdOp::SetAdsrCtrl:
|
||||||
|
cmd = _MakeCmd<CmdSetAdsrCtrl>(r); break;
|
||||||
|
case CmdOp::RndNote:
|
||||||
|
cmd = _MakeCmd<CmdRndNote>(r); break;
|
||||||
|
case CmdOp::AddNote:
|
||||||
|
cmd = _MakeCmd<CmdAddNote>(r); break;
|
||||||
|
case CmdOp::SetNote:
|
||||||
|
cmd = _MakeCmd<CmdSetNote>(r); break;
|
||||||
|
case CmdOp::LastNote:
|
||||||
|
cmd = _MakeCmd<CmdLastNote>(r); break;
|
||||||
|
case CmdOp::Portamento:
|
||||||
|
cmd = _MakeCmd<CmdPortamento>(r); break;
|
||||||
|
case CmdOp::Vibrato:
|
||||||
|
cmd = _MakeCmd<CmdVibrato>(r); break;
|
||||||
|
case CmdOp::PitchSweep1:
|
||||||
|
cmd = _MakeCmd<CmdPitchSweep1>(r); break;
|
||||||
|
case CmdOp::PitchSweep2:
|
||||||
|
cmd = _MakeCmd<CmdPitchSweep2>(r); break;
|
||||||
|
case CmdOp::SetPitch:
|
||||||
|
cmd = _MakeCmd<CmdSetPitch>(r); break;
|
||||||
|
case CmdOp::SetPitchAdsr:
|
||||||
|
cmd = _MakeCmd<CmdSetPitchAdsr>(r); break;
|
||||||
|
case CmdOp::ScaleVolumeDLS:
|
||||||
|
cmd = _MakeCmd<CmdScaleVolumeDLS>(r); break;
|
||||||
|
case CmdOp::Mod2Vibrange:
|
||||||
|
cmd = _MakeCmd<CmdMod2Vibrange>(r); break;
|
||||||
|
case CmdOp::SetupTremolo:
|
||||||
|
cmd = _MakeCmd<CmdSetupTremolo>(r); break;
|
||||||
|
case CmdOp::Return:
|
||||||
|
cmd = _MakeCmd<CmdReturn>(r); break;
|
||||||
|
case CmdOp::GoSub:
|
||||||
|
cmd = _MakeCmd<CmdGoSub>(r); break;
|
||||||
|
case CmdOp::TrapEvent:
|
||||||
|
cmd = _MakeCmd<CmdTrapEvent>(r); break;
|
||||||
|
case CmdOp::UntrapEvent:
|
||||||
|
cmd = _MakeCmd<CmdUntrapEvent>(r); break;
|
||||||
|
case CmdOp::SendMessage:
|
||||||
|
cmd = _MakeCmd<CmdSendMessage>(r); break;
|
||||||
|
case CmdOp::GetMessage:
|
||||||
|
cmd = _MakeCmd<CmdGetMessage>(r); break;
|
||||||
|
case CmdOp::GetVid:
|
||||||
|
cmd = _MakeCmd<CmdGetVid>(r); break;
|
||||||
|
case CmdOp::AddAgeCount:
|
||||||
|
cmd = _MakeCmd<CmdAddAgeCount>(r); break;
|
||||||
|
case CmdOp::SetAgeCount:
|
||||||
|
cmd = _MakeCmd<CmdSetAgeCount>(r); break;
|
||||||
|
case CmdOp::SendFlag:
|
||||||
|
cmd = _MakeCmd<CmdSendFlag>(r); break;
|
||||||
|
case CmdOp::PitchWheelR:
|
||||||
|
cmd = _MakeCmd<CmdPitchWheelR>(r); break;
|
||||||
|
case CmdOp::SetPriority:
|
||||||
|
cmd = _MakeCmd<CmdSetPriority>(r); break;
|
||||||
|
case CmdOp::AddPriority:
|
||||||
|
cmd = _MakeCmd<CmdAddPriority>(r); break;
|
||||||
|
case CmdOp::AgeCntSpeed:
|
||||||
|
cmd = _MakeCmd<CmdAgeCntSpeed>(r); break;
|
||||||
|
case CmdOp::AgeCntVel:
|
||||||
|
cmd = _MakeCmd<CmdAgeCntVel>(r); break;
|
||||||
|
case CmdOp::VolSelect:
|
||||||
|
cmd = _MakeCmd<CmdVolSelect>(r); break;
|
||||||
|
case CmdOp::PanSelect:
|
||||||
|
cmd = _MakeCmd<CmdPanSelect>(r); break;
|
||||||
|
case CmdOp::PitchWheelSelect:
|
||||||
|
cmd = _MakeCmd<CmdPitchWheelSelect>(r); break;
|
||||||
|
case CmdOp::ModWheelSelect:
|
||||||
|
cmd = _MakeCmd<CmdModWheelSelect>(r); break;
|
||||||
|
case CmdOp::PedalSelect:
|
||||||
|
cmd = _MakeCmd<CmdPedalSelect>(r); break;
|
||||||
|
case CmdOp::PortamentoSelect:
|
||||||
|
cmd = _MakeCmd<CmdPortamentoSelect>(r); break;
|
||||||
|
case CmdOp::ReverbSelect:
|
||||||
|
cmd = _MakeCmd<CmdReverbSelect>(r); break;
|
||||||
|
case CmdOp::SpanSelect:
|
||||||
|
cmd = _MakeCmd<CmdSpanSelect>(r); break;
|
||||||
|
case CmdOp::DopplerSelect:
|
||||||
|
cmd = _MakeCmd<CmdDopplerSelect>(r); break;
|
||||||
|
case CmdOp::TremoloSelect:
|
||||||
|
cmd = _MakeCmd<CmdTremoloSelect>(r); break;
|
||||||
|
case CmdOp::PreASelect:
|
||||||
|
cmd = _MakeCmd<CmdPreASelect>(r); break;
|
||||||
|
case CmdOp::PreBSelect:
|
||||||
|
cmd = _MakeCmd<CmdPreBSelect>(r); break;
|
||||||
|
case CmdOp::PostBSelect:
|
||||||
|
cmd = _MakeCmd<CmdPostBSelect>(r); break;
|
||||||
|
case CmdOp::AuxAFXSelect:
|
||||||
|
cmd = _MakeCmd<CmdAuxAFXSelect>(r); break;
|
||||||
|
case CmdOp::AuxBFXSelect:
|
||||||
|
cmd = _MakeCmd<CmdAuxBFXSelect>(r); break;
|
||||||
|
case CmdOp::SetupLFO:
|
||||||
|
cmd = _MakeCmd<CmdSetupLFO>(r); break;
|
||||||
|
case CmdOp::ModeSelect:
|
||||||
|
cmd = _MakeCmd<CmdModeSelect>(r); break;
|
||||||
|
case CmdOp::SetKeygroup:
|
||||||
|
cmd = _MakeCmd<CmdSetKeygroup>(r); break;
|
||||||
|
case CmdOp::SRCmodeSelect:
|
||||||
|
cmd = _MakeCmd<CmdSRCmodeSelect>(r); break;
|
||||||
|
case CmdOp::AddVars:
|
||||||
|
cmd = _MakeCmd<CmdAddVars>(r); break;
|
||||||
|
case CmdOp::SubVars:
|
||||||
|
cmd = _MakeCmd<CmdSubVars>(r); break;
|
||||||
|
case CmdOp::MulVars:
|
||||||
|
cmd = _MakeCmd<CmdMulVars>(r); break;
|
||||||
|
case CmdOp::DivVars:
|
||||||
|
cmd = _MakeCmd<CmdDivVars>(r); break;
|
||||||
|
case CmdOp::AddIVars:
|
||||||
|
cmd = _MakeCmd<CmdAddIVars>(r); break;
|
||||||
|
case CmdOp::IfEqual:
|
||||||
|
cmd = _MakeCmd<CmdIfEqual>(r); break;
|
||||||
|
case CmdOp::IfLess:
|
||||||
|
cmd = _MakeCmd<CmdIfLess>(r); break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
template std::unique_ptr<SoundMacro::ICmd> SoundMacro::MakeCmd(athena::io::MemoryReader& r);
|
||||||
|
template std::unique_ptr<SoundMacro::ICmd> SoundMacro::MakeCmd(athena::io::YAMLDocReader& r);
|
||||||
|
|
||||||
std::string_view SoundMacro::CmdOpToStr(CmdOp op)
|
std::string_view SoundMacro::CmdOpToStr(CmdOp op)
|
||||||
{
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
|
@ -673,7 +852,7 @@ SoundMacro::CmdOp SoundMacro::CmdStrToOp(std::string_view op)
|
||||||
return CmdOp::Invalid;
|
return CmdOp::Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioGroupPool::toYAML(athena::io::IStreamWriter& writer) const
|
bool AudioGroupPool::toYAML(SystemStringView groupPath) const
|
||||||
{
|
{
|
||||||
athena::io::YAMLDocWriter w("amuse::Pool");
|
athena::io::YAMLDocWriter w("amuse::Pool");
|
||||||
|
|
||||||
|
@ -750,7 +929,10 @@ bool AudioGroupPool::toYAML(athena::io::IStreamWriter& writer) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.finish(&writer);
|
SystemString poolPath(groupPath);
|
||||||
|
poolPath += _S("/!pool.yaml");
|
||||||
|
athena::io::FileWriter fo(poolPath);
|
||||||
|
return w.finish(&fo);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -785,7 +967,7 @@ void amuse::Curve::Enumerate<LittleDNA::WriteYaml>(athena::io::YAMLDocWriter& w)
|
||||||
|
|
||||||
const char* amuse::Curve::DNAType()
|
const char* amuse::Curve::DNAType()
|
||||||
{
|
{
|
||||||
return "amuse::ADSR";
|
return "amuse::Curve";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "amuse/AudioGroupProject.hpp"
|
#include "amuse/AudioGroupProject.hpp"
|
||||||
#include "amuse/AudioGroupData.hpp"
|
#include "amuse/AudioGroupData.hpp"
|
||||||
#include "athena/MemoryReader.hpp"
|
#include "athena/MemoryReader.hpp"
|
||||||
|
#include "athena/FileWriter.hpp"
|
||||||
|
#include "athena/FileReader.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
@ -208,6 +210,87 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(const AudioGroupDat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView groupPath)
|
||||||
|
{
|
||||||
|
AudioGroupProject ret;
|
||||||
|
SystemString projPath(groupPath);
|
||||||
|
projPath += _S("/!project.yaml");
|
||||||
|
athena::io::FileReader fi(projPath);
|
||||||
|
|
||||||
|
if (!fi.hasError())
|
||||||
|
{
|
||||||
|
athena::io::YAMLDocReader r;
|
||||||
|
if (r.parse(&fi) && r.ValidateClassType("amuse::Project"))
|
||||||
|
{
|
||||||
|
size_t songGroupCount;
|
||||||
|
if (auto __v = r.enterSubVector("songGroups", songGroupCount))
|
||||||
|
{
|
||||||
|
ret.m_songGroups.reserve(songGroupCount);
|
||||||
|
for (int g = 0; g < songGroupCount; ++g)
|
||||||
|
{
|
||||||
|
if (auto __r = r.enterSubRecord(nullptr))
|
||||||
|
{
|
||||||
|
SongGroupIndex& idx = ret.m_songGroups[g];
|
||||||
|
if (auto __v2 = r.enterSubRecord("normPages"))
|
||||||
|
{
|
||||||
|
idx.m_normPages.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
for (const auto& pg : r.getCurNode()->m_mapChildren)
|
||||||
|
if (auto __r2 = r.enterSubRecord(pg.first.c_str()))
|
||||||
|
idx.m_normPages[strtoul(pg.first.c_str(), nullptr, 0)].read(r);
|
||||||
|
}
|
||||||
|
if (auto __v2 = r.enterSubRecord("drumPages"))
|
||||||
|
{
|
||||||
|
idx.m_drumPages.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
for (const auto& pg : r.getCurNode()->m_mapChildren)
|
||||||
|
if (auto __r2 = r.enterSubRecord(pg.first.c_str()))
|
||||||
|
idx.m_drumPages[strtoul(pg.first.c_str(), nullptr, 0)].read(r);
|
||||||
|
}
|
||||||
|
if (auto __v2 = r.enterSubRecord("songs"))
|
||||||
|
{
|
||||||
|
idx.m_midiSetups.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
|
for (const auto& song : r.getCurNode()->m_mapChildren)
|
||||||
|
{
|
||||||
|
size_t chanCount;
|
||||||
|
if (auto __v3 = r.enterSubVector(song.first.c_str(), chanCount))
|
||||||
|
{
|
||||||
|
ObjectId songId = SongId::CurNameDB->generateId(NameDB::Type::Song);
|
||||||
|
SongId::CurNameDB->registerPair(song.first, songId);
|
||||||
|
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
|
||||||
|
for (int i = 0; i < 16 && i < chanCount; ++i)
|
||||||
|
if (auto __r2 = r.enterSubRecord(nullptr))
|
||||||
|
setup[i].read(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sfxGroupCount;
|
||||||
|
if (auto __v = r.enterSubVector("sfxGroups", sfxGroupCount))
|
||||||
|
{
|
||||||
|
ret.m_sfxGroups.reserve(sfxGroupCount);
|
||||||
|
for (int g = 0; g < sfxGroupCount; ++g)
|
||||||
|
{
|
||||||
|
if (auto __r = r.enterSubRecord(nullptr))
|
||||||
|
{
|
||||||
|
SFXGroupIndex& idx = ret.m_sfxGroups[g];
|
||||||
|
for (const auto& sfx : r.getCurNode()->m_mapChildren)
|
||||||
|
if (auto __r2 = r.enterSubRecord(sfx.first.c_str()))
|
||||||
|
{
|
||||||
|
ObjectId sfxId = SFXId::CurNameDB->generateId(NameDB::Type::SFX);
|
||||||
|
SFXId::CurNameDB->registerPair(sfx.first, sfxId);
|
||||||
|
idx.m_sfxEntries[sfxId].read(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
template <athena::Endian DNAE>
|
template <athena::Endian DNAE>
|
||||||
static void ReadRangedObjectIds(NameDB* db, athena::io::IStreamReader& r, NameDB::Type tp)
|
static void ReadRangedObjectIds(NameDB* db, athena::io::IStreamReader& r, NameDB::Type tp)
|
||||||
{
|
{
|
||||||
|
@ -412,7 +495,7 @@ const SFXGroupIndex* AudioGroupProject::getSFXGroupIndex(int groupId) const
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioGroupProject::toYAML(athena::io::IStreamWriter& writer) const
|
bool AudioGroupProject::toYAML(SystemStringView groupPath) const
|
||||||
{
|
{
|
||||||
athena::io::YAMLDocWriter w("amuse::Project");
|
athena::io::YAMLDocWriter w("amuse::Project");
|
||||||
|
|
||||||
|
@ -498,7 +581,10 @@ bool AudioGroupProject::toYAML(athena::io::IStreamWriter& writer) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.finish(&writer);
|
SystemString projPath(groupPath);
|
||||||
|
projPath += _S("/!project.yaml");
|
||||||
|
athena::io::FileWriter fo(projPath);
|
||||||
|
return w.finish(&fo);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
#include "amuse/AudioGroupSampleDirectory.hpp"
|
#include "amuse/AudioGroupSampleDirectory.hpp"
|
||||||
#include "amuse/Common.hpp"
|
#include "amuse/Common.hpp"
|
||||||
#include "amuse/AudioGroupData.hpp"
|
#include "amuse/AudioGroupData.hpp"
|
||||||
|
#include "amuse/DSPCodec.hpp"
|
||||||
|
#include "amuse/N64MusyXCodec.hpp"
|
||||||
|
#include "amuse/DirectoryEnumerator.hpp"
|
||||||
|
#include "athena/MemoryReader.hpp"
|
||||||
|
#include "athena/FileWriter.hpp"
|
||||||
|
#include "athena/FileReader.hpp"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <athena/MemoryReader.hpp>
|
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
@ -39,17 +44,16 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader&
|
||||||
{
|
{
|
||||||
EntryDNA<athena::Big> ent;
|
EntryDNA<athena::Big> ent;
|
||||||
ent.read(r);
|
ent.read(r);
|
||||||
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
|
m_entries[ent.m_sfxId] = ent;
|
||||||
store.first = ent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& p : m_entries)
|
for (auto& p : m_entries)
|
||||||
{
|
{
|
||||||
if (p.second.first.m_adpcmParmOffset)
|
if (p.second.m_adpcmParmOffset)
|
||||||
{
|
{
|
||||||
r.seek(p.second.first.m_adpcmParmOffset, athena::Begin);
|
r.seek(p.second.m_adpcmParmOffset, athena::Begin);
|
||||||
r.readUBytesToBuf(&p.second.second, sizeof(ADPCMParms::DSPParms));
|
r.readUBytesToBuf(&p.second.m_ADPCMParms, sizeof(ADPCMParms::DSPParms));
|
||||||
p.second.second.swapBigDSP();
|
p.second.m_ADPCMParms.swapBigDSP();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,8 +67,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader&
|
||||||
{
|
{
|
||||||
MusyX1AbsSdirEntry<athena::Big> ent;
|
MusyX1AbsSdirEntry<athena::Big> ent;
|
||||||
ent.read(r);
|
ent.read(r);
|
||||||
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
|
m_entries[ent.m_sfxId] = ent;
|
||||||
store.first = ent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -73,15 +76,14 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader&
|
||||||
{
|
{
|
||||||
MusyX1SdirEntry<athena::Big> ent;
|
MusyX1SdirEntry<athena::Big> ent;
|
||||||
ent.read(r);
|
ent.read(r);
|
||||||
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
|
m_entries[ent.m_sfxId] = ent;
|
||||||
store.first = ent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& p : m_entries)
|
for (auto& p : m_entries)
|
||||||
{
|
{
|
||||||
memcpy(&p.second.second, sampData + p.second.first.m_sampleOff, sizeof(ADPCMParms::VADPCMParms));
|
memcpy(&p.second.m_ADPCMParms, sampData + p.second.m_sampleOff, sizeof(ADPCMParms::VADPCMParms));
|
||||||
p.second.second.swapBigVADPCM();
|
p.second.m_ADPCMParms.swapBigVADPCM();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,8 +95,9 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader&
|
||||||
{
|
{
|
||||||
MusyX1AbsSdirEntry<athena::Little> ent;
|
MusyX1AbsSdirEntry<athena::Little> ent;
|
||||||
ent.read(r);
|
ent.read(r);
|
||||||
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
|
Entry& store = m_entries[ent.m_sfxId];
|
||||||
store.first = ent;
|
store = ent;
|
||||||
|
store.m_numSamples |= atUint32(SampleFormat::PCM_PC) << 24;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -103,8 +106,9 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(athena::io::IStreamReader&
|
||||||
{
|
{
|
||||||
MusyX1SdirEntry<athena::Little> ent;
|
MusyX1SdirEntry<athena::Little> ent;
|
||||||
ent.read(r);
|
ent.read(r);
|
||||||
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
|
Entry& store = m_entries[ent.m_sfxId];
|
||||||
store.first = ent;
|
store = ent;
|
||||||
|
store.m_numSamples |= atUint32(SampleFormat::PCM_PC) << 24;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,4 +127,344 @@ AudioGroupSampleDirectory AudioGroupSampleDirectory::CreateAudioGroupSampleDirec
|
||||||
return AudioGroupSampleDirectory(r, data.getAbsoluteProjOffsets(), PCDataTag{});
|
return AudioGroupSampleDirectory(r, data.getAbsoluteProjOffsets(), PCDataTag{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t DSPSampleToNibble(uint32_t sample)
|
||||||
|
{
|
||||||
|
uint32_t ret = sample / 14 * 16;
|
||||||
|
if (sample % 14)
|
||||||
|
ret += (sample % 14) + 2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t DSPNibbleToSample(uint32_t nibble)
|
||||||
|
{
|
||||||
|
uint32_t ret = nibble / 16 * 14;
|
||||||
|
if (nibble % 16)
|
||||||
|
ret += (nibble % 16) - 2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupSampleDirectory::Entry::loadLooseData(SystemStringView basePath)
|
||||||
|
{
|
||||||
|
Sstat theStat;
|
||||||
|
SystemString filePath = SystemString(basePath) + _S(".dsp");
|
||||||
|
if (!Stat(filePath.c_str(), &theStat) && (!m_looseData || theStat.st_mtime > m_looseModTime))
|
||||||
|
{
|
||||||
|
athena::io::FileReader r(filePath);
|
||||||
|
if (!r.hasError())
|
||||||
|
{
|
||||||
|
DSPADPCMHeader header;
|
||||||
|
header.read(r);
|
||||||
|
m_pitch = header.m_pitch;
|
||||||
|
m_sampleRate = atUint16(header.x8_sample_rate);
|
||||||
|
m_numSamples = header.x0_num_samples;
|
||||||
|
if (header.xc_loop_flag)
|
||||||
|
{
|
||||||
|
m_loopStartSample = DSPNibbleToSample(header.x10_loop_start_nibble);
|
||||||
|
m_loopLengthSamples = DSPNibbleToSample(header.x14_loop_end_nibble) - m_loopStartSample;
|
||||||
|
}
|
||||||
|
m_ADPCMParms.dsp.m_ps = uint8_t(header.x3e_ps);
|
||||||
|
m_ADPCMParms.dsp.m_lps = uint8_t(header.x44_loop_ps);
|
||||||
|
m_ADPCMParms.dsp.m_hist1 = header.x40_hist1;
|
||||||
|
m_ADPCMParms.dsp.m_hist2 = header.x42_hist2;
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
for (int j = 0; j < 2; ++j)
|
||||||
|
m_ADPCMParms.dsp.m_coefs[i][j] = header.x1c_coef[i][j];
|
||||||
|
|
||||||
|
uint32_t dataLen = (header.x4_num_nibbles + 1) / 2;
|
||||||
|
m_looseData.reset(new uint8_t[dataLen]);
|
||||||
|
r.readUBytesToBuf(m_looseData.get(), dataLen);
|
||||||
|
|
||||||
|
m_looseModTime = theStat.st_mtime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!Stat(filePath.c_str(), &theStat) && (!m_looseData || theStat.st_mtime > m_looseModTime))
|
||||||
|
{
|
||||||
|
athena::io::FileReader r(filePath);
|
||||||
|
if (!r.hasError())
|
||||||
|
{
|
||||||
|
atUint32 riffMagic = r.readUint32Little();
|
||||||
|
if (riffMagic != SBIG('RIFF'))
|
||||||
|
return;
|
||||||
|
atUint32 wavChuckSize = r.readUint32Little();
|
||||||
|
atUint32 wavMagic = r.readUint32Little();
|
||||||
|
if (wavMagic != SBIG('WAVE'))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (r.position() < wavChuckSize + 8)
|
||||||
|
{
|
||||||
|
atUint32 chunkMagic = r.readUint32Little();
|
||||||
|
atUint32 chunkSize = r.readUint32Little();
|
||||||
|
atUint64 startPos = r.position();
|
||||||
|
if (chunkMagic == SBIG('fmt '))
|
||||||
|
{
|
||||||
|
WAVFormatChunk fmt;
|
||||||
|
fmt.read(r);
|
||||||
|
m_sampleRate = atUint16(fmt.sampleRate);
|
||||||
|
}
|
||||||
|
else if (chunkMagic == SBIG('smpl'))
|
||||||
|
{
|
||||||
|
WAVSampleChunk smpl;
|
||||||
|
smpl.read(r);
|
||||||
|
m_pitch = atUint8(smpl.midiNote);
|
||||||
|
|
||||||
|
if (smpl.numSampleLoops)
|
||||||
|
{
|
||||||
|
WAVSampleLoop loop;
|
||||||
|
loop.read(r);
|
||||||
|
m_loopStartSample = loop.start;
|
||||||
|
m_loopLengthSamples = loop.end - loop.start + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (chunkMagic == SBIG('data'))
|
||||||
|
{
|
||||||
|
m_numSamples = ((chunkSize / 2) & 0xffffff) | (atUint32(SampleFormat::PCM_PC) << 24);
|
||||||
|
m_looseData.reset(new uint8_t[chunkSize]);
|
||||||
|
r.readUBytesToBuf(m_looseData.get(), chunkSize);
|
||||||
|
}
|
||||||
|
r.seek(startPos + chunkSize, athena::Begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_looseModTime = theStat.st_mtime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioGroupSampleDirectory AudioGroupSampleDirectory::CreateAudioGroupSampleDirectory(SystemStringView groupPath)
|
||||||
|
{
|
||||||
|
AudioGroupSampleDirectory ret;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
ObjectId sampleId = SampleId::CurNameDB->generateId(NameDB::Type::Sample);
|
||||||
|
#ifdef _WIN32
|
||||||
|
SampleId::CurNameDB->registerPair(athena::utility::wideToUtf8(baseName), sampleId);
|
||||||
|
#else
|
||||||
|
SampleId::CurNameDB->registerPair(baseName, sampleId);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Entry& entry = ret.m_entries[sampleId];
|
||||||
|
SystemString basePath = SystemString(ent.m_path.begin(), ent.m_path.begin() + ent.m_path.size() - 4);
|
||||||
|
entry.loadLooseData(basePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupSampleDirectory::_extractWAV(SampleId id, const Entry& ent,
|
||||||
|
amuse::SystemStringView destDir, const unsigned char* samp)
|
||||||
|
{
|
||||||
|
amuse::SystemString path(destDir);
|
||||||
|
path += _S("/");
|
||||||
|
#ifdef _WIN32
|
||||||
|
path += athena::utility::utf8ToWide(SampleId::CurNameDB->resolveNameFromId(id));
|
||||||
|
#else
|
||||||
|
path += SampleId::CurNameDB->resolveNameFromId(id);
|
||||||
|
#endif
|
||||||
|
path += _S(".wav");
|
||||||
|
athena::io::FileWriter w(path);
|
||||||
|
|
||||||
|
SampleFormat fmt = SampleFormat(ent.m_numSamples >> 24);
|
||||||
|
uint32_t numSamples = ent.m_numSamples & 0xffffff;
|
||||||
|
if (ent.m_loopLengthSamples)
|
||||||
|
{
|
||||||
|
WAVHeaderLoop header;
|
||||||
|
header.fmtChunk.sampleRate = ent.m_sampleRate;
|
||||||
|
header.fmtChunk.byteRate = ent.m_sampleRate * 2u;
|
||||||
|
header.smplChunk.smplPeriod = 1000000000u / ent.m_sampleRate;
|
||||||
|
header.smplChunk.midiNote = ent.m_pitch;
|
||||||
|
header.smplChunk.numSampleLoops = 1;
|
||||||
|
header.sampleLoop.start = ent.m_loopStartSample;
|
||||||
|
header.sampleLoop.end = ent.m_loopStartSample + ent.m_loopLengthSamples - 1;
|
||||||
|
header.dataChunkSize = numSamples * 2u;
|
||||||
|
header.wavChuckSize = 36 + 68 + header.dataChunkSize;
|
||||||
|
header.write(w);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WAVHeader header;
|
||||||
|
header.fmtChunk.sampleRate = ent.m_sampleRate;
|
||||||
|
header.fmtChunk.byteRate = ent.m_sampleRate * 2u;
|
||||||
|
header.smplChunk.smplPeriod = 1000000000u / ent.m_sampleRate;
|
||||||
|
header.smplChunk.midiNote = ent.m_pitch;
|
||||||
|
header.dataChunkSize = numSamples * 2u;
|
||||||
|
header.wavChuckSize = 36 + 44 + header.dataChunkSize;
|
||||||
|
header.write(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
atUint64 dataLen;
|
||||||
|
if (fmt == SampleFormat::DSP || fmt == SampleFormat::DSP_DRUM)
|
||||||
|
{
|
||||||
|
uint32_t remSamples = numSamples;
|
||||||
|
uint32_t numFrames = (remSamples + 13) / 14;
|
||||||
|
const unsigned char* cur = samp + ent.m_sampleOff;
|
||||||
|
int16_t prev1 = ent.m_ADPCMParms.dsp.m_hist1;
|
||||||
|
int16_t prev2 = ent.m_ADPCMParms.dsp.m_hist2;
|
||||||
|
for (uint32_t i = 0; i < numFrames; ++i)
|
||||||
|
{
|
||||||
|
int16_t decomp[14] = {};
|
||||||
|
unsigned thisSamples = std::min(remSamples, 14u);
|
||||||
|
DSPDecompressFrame(decomp, cur, ent.m_ADPCMParms.dsp.m_coefs, &prev1, &prev2, thisSamples);
|
||||||
|
remSamples -= thisSamples;
|
||||||
|
cur += 8;
|
||||||
|
w.writeBytes(decomp, thisSamples * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataLen = (DSPSampleToNibble(numSamples) + 1) / 2;
|
||||||
|
}
|
||||||
|
else if (fmt == SampleFormat::N64)
|
||||||
|
{
|
||||||
|
uint32_t remSamples = numSamples;
|
||||||
|
uint32_t numFrames = (remSamples + 31) / 32;
|
||||||
|
const unsigned char* cur = samp + ent.m_sampleOff + sizeof(ADPCMParms::VADPCMParms);
|
||||||
|
for (uint32_t i = 0; i < numFrames; ++i)
|
||||||
|
{
|
||||||
|
int16_t decomp[32] = {};
|
||||||
|
unsigned thisSamples = std::min(remSamples, 32u);
|
||||||
|
N64MusyXDecompressFrame(decomp, cur, ent.m_ADPCMParms.vadpcm.m_coefs, thisSamples);
|
||||||
|
remSamples -= thisSamples;
|
||||||
|
cur += 16;
|
||||||
|
w.writeBytes(decomp, thisSamples * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataLen = sizeof(ADPCMParms::VADPCMParms) + (numSamples + 31) / 32 * 16;
|
||||||
|
}
|
||||||
|
else if (fmt == SampleFormat::PCM)
|
||||||
|
{
|
||||||
|
dataLen = numSamples * 2;
|
||||||
|
const int16_t* cur = reinterpret_cast<const int16_t*>(samp + ent.m_sampleOff);
|
||||||
|
for (int i = 0; i < numSamples; ++i)
|
||||||
|
w.writeInt16Big(cur[i]);
|
||||||
|
}
|
||||||
|
else // PCM_PC
|
||||||
|
{
|
||||||
|
dataLen = numSamples * 2;
|
||||||
|
w.writeBytes(samp + ent.m_sampleOff, dataLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<uint8_t[]>& ld = const_cast<std::unique_ptr<uint8_t[]>&>(ent.m_looseData);
|
||||||
|
if (!ld)
|
||||||
|
{
|
||||||
|
Sstat theStat;
|
||||||
|
Stat(path.c_str(), &theStat);
|
||||||
|
|
||||||
|
const_cast<time_t&>(ent.m_looseModTime) = theStat.st_mtime;
|
||||||
|
ld.reset(new uint8_t[dataLen]);
|
||||||
|
memcpy(ld.get(), samp + ent.m_sampleOff, dataLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupSampleDirectory::extractWAV(SampleId id, amuse::SystemStringView destDir, const unsigned char* samp) const
|
||||||
|
{
|
||||||
|
auto search = m_entries.find(id);
|
||||||
|
if (search == m_entries.cend())
|
||||||
|
return;
|
||||||
|
_extractWAV(id, search->second, destDir, samp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupSampleDirectory::extractAllWAV(amuse::SystemStringView destDir, const unsigned char* samp) const
|
||||||
|
{
|
||||||
|
for (const auto& ent : m_entries)
|
||||||
|
_extractWAV(ent.first, ent.second, destDir, samp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupSampleDirectory::_extractCompressed(SampleId id, const Entry& ent,
|
||||||
|
amuse::SystemStringView destDir, const unsigned char* samp)
|
||||||
|
{
|
||||||
|
SampleFormat fmt = SampleFormat(ent.m_numSamples >> 24);
|
||||||
|
if (fmt == SampleFormat::PCM || fmt == SampleFormat::PCM_PC)
|
||||||
|
{
|
||||||
|
_extractWAV(id, ent, destDir, samp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
amuse::SystemString path(destDir);
|
||||||
|
path += _S("/");
|
||||||
|
#ifdef _WIN32
|
||||||
|
path += athena::utility::utf8ToWide(SampleId::CurNameDB->resolveNameFromId(id));
|
||||||
|
#else
|
||||||
|
path += SampleId::CurNameDB->resolveNameFromId(id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t numSamples = ent.m_numSamples & 0xffffff;
|
||||||
|
atUint64 dataLen;
|
||||||
|
if (fmt == SampleFormat::DSP || fmt == SampleFormat::DSP_DRUM)
|
||||||
|
{
|
||||||
|
DSPADPCMHeader header;
|
||||||
|
header.x0_num_samples = numSamples;
|
||||||
|
header.x4_num_nibbles = DSPSampleToNibble(numSamples);
|
||||||
|
header.x8_sample_rate = ent.m_sampleRate;
|
||||||
|
header.xc_loop_flag = atUint16(ent.m_loopLengthSamples != 0);
|
||||||
|
if (header.xc_loop_flag)
|
||||||
|
{
|
||||||
|
header.x10_loop_start_nibble = DSPSampleToNibble(ent.m_loopStartSample);
|
||||||
|
header.x14_loop_end_nibble = DSPSampleToNibble(ent.m_loopStartSample + ent.m_loopLengthSamples);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
for (int j = 0; j < 2; ++j)
|
||||||
|
header.x1c_coef[i][j] = ent.m_ADPCMParms.dsp.m_coefs[i][j];
|
||||||
|
header.x3e_ps = ent.m_ADPCMParms.dsp.m_ps;
|
||||||
|
header.x40_hist1 = ent.m_ADPCMParms.dsp.m_hist1;
|
||||||
|
header.x42_hist2 = ent.m_ADPCMParms.dsp.m_hist2;
|
||||||
|
header.x44_loop_ps = ent.m_ADPCMParms.dsp.m_lps;
|
||||||
|
header.m_pitch = ent.m_pitch;
|
||||||
|
|
||||||
|
path += _S(".dsp");
|
||||||
|
athena::io::FileWriter w(path);
|
||||||
|
header.write(w);
|
||||||
|
dataLen = (header.x4_num_nibbles + 1) / 2;
|
||||||
|
w.writeUBytes(samp + ent.m_sampleOff, dataLen);
|
||||||
|
}
|
||||||
|
else if (fmt == SampleFormat::N64)
|
||||||
|
{
|
||||||
|
path += _S(".vadpcm");
|
||||||
|
athena::io::FileWriter w(path);
|
||||||
|
dataLen = sizeof(ADPCMParms::VADPCMParms) + (numSamples + 31) / 32 * 16;
|
||||||
|
w.writeUBytes(samp + ent.m_sampleOff, dataLen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<uint8_t[]>& ld = const_cast<std::unique_ptr<uint8_t[]>&>(ent.m_looseData);
|
||||||
|
if (!ld)
|
||||||
|
{
|
||||||
|
Sstat theStat;
|
||||||
|
Stat(path.c_str(), &theStat);
|
||||||
|
|
||||||
|
const_cast<time_t&>(ent.m_looseModTime) = theStat.st_mtime;
|
||||||
|
ld.reset(new uint8_t[dataLen]);
|
||||||
|
memcpy(ld.get(), samp + ent.m_sampleOff, dataLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupSampleDirectory::extractCompressed(SampleId id, amuse::SystemStringView destDir,
|
||||||
|
const unsigned char* samp) const
|
||||||
|
{
|
||||||
|
auto search = m_entries.find(id);
|
||||||
|
if (search == m_entries.cend())
|
||||||
|
return;
|
||||||
|
_extractCompressed(id, search->second, destDir, samp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupSampleDirectory::extractAllCompressed(amuse::SystemStringView destDir,
|
||||||
|
const unsigned char* samp) const
|
||||||
|
{
|
||||||
|
for (const auto& ent : m_entries)
|
||||||
|
_extractCompressed(ent.first, ent.second, destDir, samp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,7 @@ const char* PageObjectIdDNA<DNAE>::DNAType()
|
||||||
template struct PageObjectIdDNA<athena::Big>;
|
template struct PageObjectIdDNA<athena::Big>;
|
||||||
template struct PageObjectIdDNA<athena::Little>;
|
template struct PageObjectIdDNA<athena::Little>;
|
||||||
|
|
||||||
ObjectId NameDB::generateId(Type tp)
|
ObjectId NameDB::generateId(Type tp) const
|
||||||
{
|
{
|
||||||
uint16_t maxMatch = uint16_t(tp == Type::Layer ? 0x8000 : 0);
|
uint16_t maxMatch = uint16_t(tp == Type::Layer ? 0x8000 : 0);
|
||||||
for (const auto& p : m_idToString)
|
for (const auto& p : m_idToString)
|
||||||
|
|
|
@ -213,24 +213,7 @@ AudioGroup* Engine::_addAudioGroup(const AudioGroupData& data, std::unique_ptr<A
|
||||||
const AudioGroup* Engine::addAudioGroup(const AudioGroupData& data)
|
const AudioGroup* Engine::addAudioGroup(const AudioGroupData& data)
|
||||||
{
|
{
|
||||||
removeAudioGroup(data);
|
removeAudioGroup(data);
|
||||||
|
return _addAudioGroup(data, std::make_unique<AudioGroup>(data));
|
||||||
std::unique_ptr<AudioGroup> grp;
|
|
||||||
switch (data.m_fmt)
|
|
||||||
{
|
|
||||||
case DataFormat::GCN:
|
|
||||||
grp = std::make_unique<AudioGroup>(data, GCNDataTag{});
|
|
||||||
break;
|
|
||||||
case DataFormat::N64:
|
|
||||||
grp = std::make_unique<AudioGroup>(data, data.m_absOffs, N64DataTag{});
|
|
||||||
break;
|
|
||||||
case DataFormat::PC:
|
|
||||||
grp = std::make_unique<AudioGroup>(data, data.m_absOffs, PCDataTag{});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!grp)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return _addAudioGroup(data, std::move(grp));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Remove audio group from engine */
|
/** Remove audio group from engine */
|
||||||
|
|
|
@ -64,14 +64,14 @@ bool Voice::_checkSamplePos(bool& looped)
|
||||||
|
|
||||||
if (m_curSamplePos >= m_lastSamplePos)
|
if (m_curSamplePos >= m_lastSamplePos)
|
||||||
{
|
{
|
||||||
if (m_curSample->first.m_loopLengthSamples)
|
if (m_curSample->m_loopLengthSamples)
|
||||||
{
|
{
|
||||||
/* Turn over looped sample */
|
/* Turn over looped sample */
|
||||||
m_curSamplePos = m_curSample->first.m_loopStartSample;
|
m_curSamplePos = m_curSample->m_loopStartSample;
|
||||||
if (m_curFormat == SampleFormat::DSP)
|
if (m_curFormat == SampleFormat::DSP)
|
||||||
{
|
{
|
||||||
m_prev1 = m_curSample->second.dsp.m_hist1;
|
m_prev1 = m_curSample->m_ADPCMParms.dsp.m_hist1;
|
||||||
m_prev2 = m_curSample->second.dsp.m_hist2;
|
m_prev2 = m_curSample->m_ADPCMParms.dsp.m_hist2;
|
||||||
}
|
}
|
||||||
looped = true;
|
looped = true;
|
||||||
}
|
}
|
||||||
|
@ -115,9 +115,9 @@ 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->first.m_pitch * 100;
|
int32_t interval = cents - 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->first.m_sampleRate * ratio;
|
m_sampleRate = m_curSample->m_sampleRate * ratio;
|
||||||
m_backendVoice->setPitchRatio(ratio, slew);
|
m_backendVoice->setPitchRatio(ratio, slew);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,9 +346,10 @@ uint32_t Voice::_GetBlockSampleCount(SampleFormat fmt)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
case Voice::SampleFormat::DSP:
|
case SampleFormat::DSP:
|
||||||
|
case SampleFormat::DSP_DRUM:
|
||||||
return 14;
|
return 14;
|
||||||
case Voice::SampleFormat::N64:
|
case SampleFormat::N64:
|
||||||
return 64;
|
return 64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,14 +515,15 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
|
||||||
case SampleFormat::DSP:
|
case SampleFormat::DSP:
|
||||||
{
|
{
|
||||||
decSamples =
|
decSamples =
|
||||||
DSPDecompressFrameRanged(data, m_curSampleData + 8 * block, m_curSample->second.dsp.m_coefs,
|
DSPDecompressFrameRanged(data, m_curSampleData + 8 * block,
|
||||||
|
m_curSample->m_ADPCMParms.dsp.m_coefs,
|
||||||
&m_prev1, &m_prev2, rem, remCount);
|
&m_prev1, &m_prev2, rem, remCount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SampleFormat::N64:
|
case SampleFormat::N64:
|
||||||
{
|
{
|
||||||
decSamples = N64MusyXDecompressFrameRanged(data, m_curSampleData + 256 + 40 * block,
|
decSamples = N64MusyXDecompressFrameRanged(data, m_curSampleData + 256 + 40 * block,
|
||||||
m_curSample->second.vadpcm.m_coefs, rem, remCount);
|
m_curSample->m_ADPCMParms.vadpcm.m_coefs, rem, remCount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SampleFormat::PCM:
|
case SampleFormat::PCM:
|
||||||
|
@ -576,14 +578,14 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
|
||||||
{
|
{
|
||||||
case SampleFormat::DSP:
|
case SampleFormat::DSP:
|
||||||
{
|
{
|
||||||
decSamples = DSPDecompressFrame(data, m_curSampleData + 8 * block, m_curSample->second.dsp.m_coefs,
|
decSamples = DSPDecompressFrame(data, m_curSampleData + 8 * block,
|
||||||
&m_prev1, &m_prev2, remCount);
|
m_curSample->m_ADPCMParms.dsp.m_coefs, &m_prev1, &m_prev2, remCount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SampleFormat::N64:
|
case SampleFormat::N64:
|
||||||
{
|
{
|
||||||
decSamples = N64MusyXDecompressFrame(data, m_curSampleData + 256 + 40 * block,
|
decSamples = N64MusyXDecompressFrame(data, m_curSampleData + 256 + 40 * block,
|
||||||
m_curSample->second.vadpcm.m_coefs, remCount);
|
m_curSample->m_ADPCMParms.vadpcm.m_coefs, remCount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SampleFormat::PCM:
|
case SampleFormat::PCM:
|
||||||
|
@ -877,7 +879,7 @@ void Voice::keyOff()
|
||||||
loadMacroObject(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);
|
m_state.m_initVel, m_state.m_initMod);
|
||||||
}
|
}
|
||||||
else if (!m_curSample || m_curSample->first.m_loopLengthSamples)
|
else if (!m_curSample || m_curSample->m_loopLengthSamples)
|
||||||
_macroKeyOff();
|
_macroKeyOff();
|
||||||
|
|
||||||
for (const std::shared_ptr<Voice>& vox : m_childVoices)
|
for (const std::shared_ptr<Voice>& vox : m_childVoices)
|
||||||
|
@ -901,7 +903,7 @@ void Voice::message(int32_t val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::startSample(int16_t sampId, int32_t offset)
|
void Voice::startSample(SampleId sampId, int32_t offset)
|
||||||
{
|
{
|
||||||
if (m_destroyed)
|
if (m_destroyed)
|
||||||
return;
|
return;
|
||||||
|
@ -909,41 +911,38 @@ void Voice::startSample(int16_t sampId, int32_t offset)
|
||||||
m_curSample = m_audioGroup.getSample(sampId);
|
m_curSample = m_audioGroup.getSample(sampId);
|
||||||
if (m_curSample)
|
if (m_curSample)
|
||||||
{
|
{
|
||||||
m_sampleRate = m_curSample->first.m_sampleRate;
|
m_curSampleData = m_audioGroup.getSampleData(sampId, m_curSample);
|
||||||
m_curPitch = m_curSample->first.m_pitch;
|
|
||||||
|
m_sampleRate = m_curSample->m_sampleRate;
|
||||||
|
m_curPitch = m_curSample->m_pitch;
|
||||||
m_pitchDirty = true;
|
m_pitchDirty = true;
|
||||||
_setPitchWheel(m_curPitchWheel);
|
_setPitchWheel(m_curPitchWheel);
|
||||||
m_backendVoice->resetSampleRate(m_curSample->first.m_sampleRate);
|
m_backendVoice->resetSampleRate(m_curSample->m_sampleRate);
|
||||||
m_needsSlew = false;
|
m_needsSlew = false;
|
||||||
|
|
||||||
int32_t numSamples = m_curSample->first.m_numSamples & 0xffffff;
|
int32_t numSamples = m_curSample->m_numSamples & 0xffffff;
|
||||||
if (offset)
|
if (offset)
|
||||||
{
|
{
|
||||||
if (m_curSample->first.m_loopLengthSamples)
|
if (m_curSample->m_loopLengthSamples)
|
||||||
{
|
{
|
||||||
if (offset > int32_t(m_curSample->first.m_loopStartSample))
|
if (offset > int32_t(m_curSample->m_loopStartSample))
|
||||||
offset =
|
offset =
|
||||||
((offset - m_curSample->first.m_loopStartSample) % m_curSample->first.m_loopLengthSamples) +
|
((offset - m_curSample->m_loopStartSample) % m_curSample->m_loopLengthSamples) +
|
||||||
m_curSample->first.m_loopStartSample;
|
m_curSample->m_loopStartSample;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
offset = clamp(0, offset, numSamples);
|
offset = clamp(0, offset, numSamples);
|
||||||
}
|
}
|
||||||
m_curSamplePos = offset;
|
m_curSamplePos = offset;
|
||||||
m_curSampleData = m_audioGroup.getSampleData(m_curSample->first.m_sampleOff);
|
|
||||||
m_prev1 = 0;
|
m_prev1 = 0;
|
||||||
m_prev2 = 0;
|
m_prev2 = 0;
|
||||||
|
|
||||||
if (m_audioGroup.getDataFormat() == DataFormat::PC)
|
m_curFormat = SampleFormat(m_curSample->m_numSamples >> 24);
|
||||||
m_curFormat = SampleFormat::PCM_PC;
|
|
||||||
else
|
|
||||||
m_curFormat = SampleFormat(m_curSample->first.m_numSamples >> 24);
|
|
||||||
|
|
||||||
if (m_curFormat == SampleFormat::DSP_DRUM)
|
if (m_curFormat == SampleFormat::DSP_DRUM)
|
||||||
m_curFormat = SampleFormat::DSP;
|
m_curFormat = SampleFormat::DSP;
|
||||||
|
|
||||||
m_lastSamplePos = m_curSample->first.m_loopLengthSamples
|
m_lastSamplePos = m_curSample->m_loopLengthSamples
|
||||||
? (m_curSample->first.m_loopStartSample + m_curSample->first.m_loopLengthSamples)
|
? (m_curSample->m_loopStartSample + m_curSample->m_loopLengthSamples)
|
||||||
: numSamples;
|
: numSamples;
|
||||||
|
|
||||||
bool looped;
|
bool looped;
|
||||||
|
@ -955,11 +954,11 @@ void Voice::startSample(int16_t sampId, int32_t offset)
|
||||||
uint32_t block = m_curSamplePos / 14;
|
uint32_t block = m_curSamplePos / 14;
|
||||||
uint32_t rem = m_curSamplePos % 14;
|
uint32_t rem = m_curSamplePos % 14;
|
||||||
for (uint32_t b = 0; b < block; ++b)
|
for (uint32_t b = 0; b < block; ++b)
|
||||||
DSPDecompressFrameStateOnly(m_curSampleData + 8 * b, m_curSample->second.dsp.m_coefs, &m_prev1,
|
DSPDecompressFrameStateOnly(m_curSampleData + 8 * b, m_curSample->m_ADPCMParms.dsp.m_coefs, &m_prev1,
|
||||||
&m_prev2, 14);
|
&m_prev2, 14);
|
||||||
|
|
||||||
if (rem)
|
if (rem)
|
||||||
DSPDecompressFrameStateOnly(m_curSampleData + 8 * block, m_curSample->second.dsp.m_coefs, &m_prev1,
|
DSPDecompressFrameStateOnly(m_curSampleData + 8 * block, m_curSample->m_ADPCMParms.dsp.m_coefs, &m_prev1,
|
||||||
&m_prev2, rem);
|
&m_prev2, rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue