mirror of https://github.com/AxioDL/amuse.git
AudioGroupProject loader and initial driver
This commit is contained in:
parent
a62fa64fb5
commit
04382030a1
|
@ -4,14 +4,92 @@
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
static logvisor::Module Log("amusetool");
|
||||||
|
|
||||||
|
static amuse::IntrusiveAudioGroupData LoadFromArgs(int argc, char* argv[],
|
||||||
|
std::string& descOut, bool& good)
|
||||||
|
{
|
||||||
|
return {nullptr, nullptr, nullptr, nullptr};
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
logvisor::RegisterConsoleLogger();
|
logvisor::RegisterConsoleLogger();
|
||||||
|
|
||||||
|
/* Load data */
|
||||||
|
std::string desc;
|
||||||
|
bool good = false;
|
||||||
|
amuse::IntrusiveAudioGroupData data = LoadFromArgs(argc, argv, desc, good);
|
||||||
|
if (!good)
|
||||||
|
Log.report(logvisor::Fatal, "incomplete data in args");
|
||||||
|
printf("Found '%s' Audio Group data\n", desc.c_str());
|
||||||
|
|
||||||
|
/* Load project to assemble group list */
|
||||||
|
amuse::AudioGroupProject proj(data.getProj());
|
||||||
|
|
||||||
|
/* Get group selection from user */
|
||||||
|
int groupId;
|
||||||
|
bool sfxGroup;
|
||||||
|
size_t totalGroups = proj.sfxGroups().size() + proj.songGroups().size();
|
||||||
|
if (totalGroups > 1)
|
||||||
|
{
|
||||||
|
/* Ask user to specify which group in project */
|
||||||
|
printf("Multiple Audio Groups discovered:\n");
|
||||||
|
for (const auto& pair : proj.songGroups())
|
||||||
|
{
|
||||||
|
printf(" %d (SongGroup) %" PRISize " normal-pages, %" PRISize " drum-pages\n",
|
||||||
|
pair.first, pair.second.m_normPages.size(), pair.second.m_drumPages.size());
|
||||||
|
}
|
||||||
|
for (const auto& pair : proj.sfxGroups())
|
||||||
|
{
|
||||||
|
printf(" %d (SFXGroup) %" PRISize " sfx-entries\n",
|
||||||
|
pair.first, pair.second.m_sfxEntries.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int userSel = 0;
|
||||||
|
printf("Enter Group Number: ");
|
||||||
|
if (scanf("%d", &userSel) <= 0)
|
||||||
|
Log.report(logvisor::Fatal, "unable to parse prompt");
|
||||||
|
|
||||||
|
if (proj.getSongGroupIndex(userSel))
|
||||||
|
{
|
||||||
|
groupId = userSel;
|
||||||
|
sfxGroup = false;
|
||||||
|
}
|
||||||
|
else if (proj.getSFXGroupIndex(userSel))
|
||||||
|
{
|
||||||
|
groupId = userSel;
|
||||||
|
sfxGroup = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log.report(logvisor::Fatal, "unable to find Group %d", userSel);
|
||||||
|
}
|
||||||
|
else if (totalGroups == 1)
|
||||||
|
{
|
||||||
|
/* Load one and only group */
|
||||||
|
if (proj.songGroups().size())
|
||||||
|
{
|
||||||
|
const auto& pair = *proj.songGroups().cbegin();
|
||||||
|
groupId = pair.first;
|
||||||
|
sfxGroup = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto& pair = *proj.sfxGroups().cbegin();
|
||||||
|
groupId = pair.first;
|
||||||
|
sfxGroup = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log.report(logvisor::Fatal, "empty project");
|
||||||
|
|
||||||
|
/* Build voice engine */
|
||||||
std::unique_ptr<boo::IAudioVoiceEngine> voxEngine = boo::NewAudioVoiceEngine();
|
std::unique_ptr<boo::IAudioVoiceEngine> voxEngine = boo::NewAudioVoiceEngine();
|
||||||
amuse::BooBackendVoiceAllocator booBackend(*voxEngine);
|
amuse::BooBackendVoiceAllocator booBackend(*voxEngine);
|
||||||
amuse::Engine engine(booBackend);
|
amuse::Engine engine(booBackend);
|
||||||
|
|
||||||
|
engine.addAudioGroup(groupId, data);
|
||||||
|
|
||||||
amuse::Voice* vox = engine.fxStart(1, 1.f, 0.f);
|
amuse::Voice* vox = engine.fxStart(1, 1.f, 0.f);
|
||||||
|
|
||||||
for (int f=0 ; f<300 ; ++f)
|
for (int f=0 ; f<300 ; ++f)
|
||||||
|
|
|
@ -1,13 +1,74 @@
|
||||||
#ifndef __AMUSE_AUDIOGROUPPROJECT_HPP__
|
#ifndef __AMUSE_AUDIOGROUPPROJECT_HPP__
|
||||||
#define __AMUSE_AUDIOGROUPPROJECT_HPP__
|
#define __AMUSE_AUDIOGROUPPROJECT_HPP__
|
||||||
|
|
||||||
|
#include "Entity.hpp"
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct AudioGroupIndex {};
|
||||||
|
|
||||||
|
/** Root index of SongGroup */
|
||||||
|
struct SongGroupIndex : AudioGroupIndex
|
||||||
|
{
|
||||||
|
/** Maps GM program numbers to sound entities */
|
||||||
|
struct PageEntry
|
||||||
|
{
|
||||||
|
ObjectId objId;
|
||||||
|
uint8_t priority;
|
||||||
|
uint8_t maxVoices;
|
||||||
|
uint8_t programNo;
|
||||||
|
uint8_t pad;
|
||||||
|
};
|
||||||
|
std::unordered_map<uint8_t, const PageEntry*> m_normPages;
|
||||||
|
std::unordered_map<uint8_t, const PageEntry*> m_drumPages;
|
||||||
|
|
||||||
|
/** Maps SongID to 16 MIDI channel numbers to GM program numbers and settings */
|
||||||
|
struct MIDISetup
|
||||||
|
{
|
||||||
|
uint8_t programNo;
|
||||||
|
uint8_t volume;
|
||||||
|
uint8_t panning;
|
||||||
|
uint8_t reverb;
|
||||||
|
uint8_t chorus;
|
||||||
|
};
|
||||||
|
std::unordered_map<int, std::array<const MIDISetup*, 16>> m_midiSetups;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Root index of SFXGroup */
|
||||||
|
struct SFXGroupIndex : AudioGroupIndex
|
||||||
|
{
|
||||||
|
/** Maps game-side SFX define IDs to sound entities */
|
||||||
|
struct SFXEntry
|
||||||
|
{
|
||||||
|
uint16_t defineId;
|
||||||
|
ObjectId objId;
|
||||||
|
uint8_t priority;
|
||||||
|
uint8_t maxVoices;
|
||||||
|
uint8_t defVel;
|
||||||
|
uint8_t panning;
|
||||||
|
uint8_t defKey;
|
||||||
|
uint8_t pad;
|
||||||
|
};
|
||||||
|
std::unordered_map<uint16_t, const SFXEntry*> m_sfxEntries;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Collection of SongGroup and SFXGroup indexes */
|
||||||
class AudioGroupProject
|
class AudioGroupProject
|
||||||
{
|
{
|
||||||
|
std::unordered_map<int, SongGroupIndex> m_songGroups;
|
||||||
|
std::unordered_map<int, SFXGroupIndex> m_sfxGroups;
|
||||||
public:
|
public:
|
||||||
AudioGroupProject(const unsigned char* data);
|
AudioGroupProject(const unsigned char* 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;}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,14 @@
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifndef PRISize
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define PRISize "Iu"
|
||||||
|
#else
|
||||||
|
#define PRISize "zu"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline T clamp(T a, T val, T b) {return std::max<T>(a, std::min<T>(b, val));}
|
static inline T clamp(T a, T val, T b) {return std::max<T>(a, std::min<T>(b, val));}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,108 @@
|
||||||
#include "amuse/AudioGroupProject.hpp"
|
#include "amuse/AudioGroupProject.hpp"
|
||||||
|
#include "amuse/Common.hpp"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
|
enum class GroupType : uint16_t
|
||||||
|
{
|
||||||
|
Song,
|
||||||
|
SFX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GroupHeader
|
||||||
|
{
|
||||||
|
uint32_t groupEndOff;
|
||||||
|
uint16_t groupId;
|
||||||
|
GroupType type;
|
||||||
|
uint32_t soundMacroIdsOff;
|
||||||
|
uint32_t samplIdsOff;
|
||||||
|
uint32_t tableIdsOff;
|
||||||
|
uint32_t keymapIdsOff;
|
||||||
|
uint32_t layerIdsOff;
|
||||||
|
uint32_t pageTableOff;
|
||||||
|
uint32_t drumTableOff;
|
||||||
|
uint32_t midiSetupsOff;
|
||||||
|
|
||||||
|
void swapBig()
|
||||||
|
{
|
||||||
|
groupEndOff = SBig(groupEndOff);
|
||||||
|
groupId = SBig(groupId);
|
||||||
|
type = GroupType(SBig(uint16_t(type)));
|
||||||
|
soundMacroIdsOff = SBig(soundMacroIdsOff);
|
||||||
|
samplIdsOff = SBig(samplIdsOff);
|
||||||
|
tableIdsOff = SBig(tableIdsOff);
|
||||||
|
keymapIdsOff = SBig(keymapIdsOff);
|
||||||
|
layerIdsOff = SBig(layerIdsOff);
|
||||||
|
pageTableOff = SBig(pageTableOff);
|
||||||
|
drumTableOff = SBig(drumTableOff);
|
||||||
|
midiSetupsOff = SBig(midiSetupsOff);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
AudioGroupProject::AudioGroupProject(const unsigned char* data)
|
AudioGroupProject::AudioGroupProject(const unsigned char* data)
|
||||||
{
|
{
|
||||||
|
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
|
||||||
|
while (group->groupEndOff != 0xffffffff)
|
||||||
|
{
|
||||||
|
GroupHeader header = *group;
|
||||||
|
header.swapBig();
|
||||||
|
|
||||||
|
if (header.type == GroupType::Song)
|
||||||
|
{
|
||||||
|
SongGroupIndex& idx = m_songGroups[header.groupId];
|
||||||
|
|
||||||
|
/* Normal pages */
|
||||||
|
const SongGroupIndex::PageEntry* normEntries =
|
||||||
|
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + header.pageTableOff);
|
||||||
|
while (normEntries->objId.type != ObjectType::Invalid)
|
||||||
|
{
|
||||||
|
idx.m_normPages[normEntries->programNo] = normEntries;
|
||||||
|
++normEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drum pages */
|
||||||
|
const SongGroupIndex::PageEntry* drumEntries =
|
||||||
|
reinterpret_cast<const SongGroupIndex::PageEntry*>(data + header.drumTableOff);
|
||||||
|
while (drumEntries->objId.type != ObjectType::Invalid)
|
||||||
|
{
|
||||||
|
idx.m_drumPages[drumEntries->programNo] = drumEntries;
|
||||||
|
++drumEntries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (header.type == GroupType::SFX)
|
||||||
|
{
|
||||||
|
SFXGroupIndex& idx = m_sfxGroups[header.groupId];
|
||||||
|
|
||||||
|
/* SFX entries */
|
||||||
|
const SFXGroupIndex::SFXEntry* entries =
|
||||||
|
reinterpret_cast<const SFXGroupIndex::SFXEntry*>(data + header.pageTableOff);
|
||||||
|
while (entries->objId.type != ObjectType::Invalid)
|
||||||
|
{
|
||||||
|
idx.m_sfxEntries[SBig(entries->defineId)] = entries;
|
||||||
|
++entries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
group = reinterpret_cast<const GroupHeader*>(data + header.groupEndOff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SongGroupIndex* AudioGroupProject::getSongGroupIndex(int groupId) const
|
||||||
|
{
|
||||||
|
auto search = m_songGroups.find(groupId);
|
||||||
|
if (search == m_songGroups.cend())
|
||||||
|
return nullptr;
|
||||||
|
return &search->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SFXGroupIndex* AudioGroupProject::getSFXGroupIndex(int groupId) const
|
||||||
|
{
|
||||||
|
auto search = m_sfxGroups.find(groupId);
|
||||||
|
if (search == m_sfxGroups.cend())
|
||||||
|
return nullptr;
|
||||||
|
return &search->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue