Skip to content

Commit

Permalink
Fixed aifc extraction on naudio v0
Browse files Browse the repository at this point in the history
  • Loading branch information
KiritoDv committed Nov 28, 2024
1 parent a0b671d commit 1d485d7
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 174 deletions.
31 changes: 30 additions & 1 deletion src/factories/naudio/v0/AudioHeaderFactory.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,36 @@
#include "AudioHeaderFactory.h"

#include <vector>
#include "AudioManager.h"
#include "Companion.h"
#include "AIFCDecode.h"
#include "spdlog/spdlog.h"
#include <factories/naudio/v1/AudioConverter.h>

ExportResult AudioAIFCExporter::Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) {

auto samples = AudioManager::Instance->get_samples();

int temp = 0;
for(auto& sample : samples){
std::string dpath = Companion::Instance->GetOutputPath() + "/" + (*replacement);
if(!exists(fs::path(dpath).parent_path())){
create_directories(fs::path(dpath).parent_path());
}
std::ofstream file(dpath + "_bank_" + std::to_string(++temp) + ".aiff", std::ios::binary);

LUS::BinaryWriter aifc = LUS::BinaryWriter();
AudioConverter::SampleV0ToAIFC(sample, aifc);

LUS::BinaryWriter aiff = LUS::BinaryWriter();
write_aiff(aifc.ToVector(), aiff);
aifc.Close();
aiff.Finish(file);
file.close();
SPDLOG_INFO("Exported {}", dpath + "_bank_" + std::to_string(temp) + ".aiff");
}

return std::nullopt;
}

std::optional<std::shared_ptr<IParsedData>> AudioHeaderFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& data) {
AudioManager::Instance->initialize(buffer, data);
Expand Down
7 changes: 6 additions & 1 deletion src/factories/naudio/v0/AudioHeaderFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

#include <factories/BaseFactory.h>

class AudioAIFCExporter : public BaseExporter {
public:
ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement);
};

class AudioDummyExporter : public BaseExporter {
public:
ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override {
Expand All @@ -17,7 +22,7 @@ class AudioHeaderFactory : public BaseFactory {
}
std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
return {
REGISTER(Modding, AudioDummyExporter)
REGISTER(Modding, AudioAIFCExporter)
REGISTER(Header, AudioDummyExporter)
REGISTER(Binary, AudioDummyExporter)
REGISTER(Code, AudioDummyExporter)
Expand Down
180 changes: 28 additions & 152 deletions src/factories/naudio/v0/AudioManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ Bank AudioManager::parse_ctl(CTLHeader header, std::vector<uint8_t> data, Sample
for (size_t i = 0; i < numDrums; ++i) {
uint32_t drumOffset;
memcpy(&drumOffset, rawData + drumBaseAddr + i * 4, 4);
drumOffset = BSWAP32(drumOffset);
assert(drumOffset != 0);
drumOffsets.push_back(drumOffset);
if(drumOffset == 0){
continue;
}

drumOffsets.push_back(BSWAP32(drumOffset));
}
} else {
assert(drumBaseAddr == 0);
Expand Down Expand Up @@ -382,7 +384,14 @@ AudioBankSample* AudioManager::parse_sample(std::vector<uint8_t>& data, std::vec
uint32_t loop = reader.ReadUInt32();
uint32_t book = reader.ReadUInt32();
uint32_t sampleSize = reader.ReadUInt32();
assert(zero == 0);

SPDLOG_INFO("Zero: 0x{:X}", zero);
SPDLOG_INFO("Addr: 0x{:X}", addr);
SPDLOG_INFO("Loop: 0x{:X}", loop);
SPDLOG_INFO("Book: 0x{:X}", book);
SPDLOG_INFO("Sample Size: {}", sampleSize);

// assert(zero == 0);
assert(loop != 0);
assert(book != 0);

Expand Down Expand Up @@ -479,154 +488,6 @@ void AudioManager::initialize(std::vector<uint8_t>& buffer, YAML::Node& data) {
}
}

void serialize_f80(double num, LUS::BinaryWriter &writer) {
// Convert the input double to an uint64_t
std::uint64_t f64;
std::memcpy(&f64, &num, sizeof(double));

std::uint64_t f64_sign_bit = f64 & (std::uint64_t) pow(2, 63);
if (num == 0.0) {
if (f64_sign_bit) {
writer.Write(0x80000000);
} else {
writer.Write(0x00000000);
}
}

std::uint64_t exponent = ((f64 ^ f64_sign_bit) >> 52);

assert(exponent != 0);
assert(exponent != 0x7FF);

exponent -= 1023;
uint64_t f64_mantissa_bits = f64 & (uint64_t) pow(2, 52) - 1;
uint64_t f80_sign_bit = f64_sign_bit << (80 - 64);
uint64_t f80_exponent = (exponent + 0x3FFF) << 64;
uint64_t f80_mantissa_bits = (uint64_t) pow(2, 63) | (f64_mantissa_bits << (63 - 52));
uint64_t f80 = f80_sign_bit | f80_exponent | f80_mantissa_bits;

// Split the f80 representation into two parts (high and low)
uint16_t high = BSWAP16((uint16_t) f80 >> 64);
writer.Write((char*) &high, 2);
uint64_t low = BSWAP64(f80 & ((uint64_t) pow(2, 64) - 1));
writer.Write((char*) &low, 8);
}

#define START_SECTION(section) \
{ \
out.Write((uint32_t) BSWAP32(section)); \
LUS::BinaryWriter tmp = LUS::BinaryWriter(); \
tmp.SetEndianness(Torch::Endianness::Big); \

#define START_CUSTOM_SECTION(section) \
{ \
LUS::BinaryWriter tmp = LUS::BinaryWriter(); \
tmp.SetEndianness(Torch::Endianness::Big); \
out.Write((uint32_t) BSWAP32(AIFC::MagicValues::AAPL)); \
tmp.Write(AIFC::MagicValues::stoc); \
tmp.Write(section, false); \

#define END_SECTION() \
auto odata = tmp.ToVector(); \
size_t size = odata.size(); \
len += ALIGN(size, 2) + 8; \
out.Write((uint32_t) BSWAP32((uint32_t) size)); \
out.Write(odata.data(), odata.size()); \
if(size % 2){ \
out.WriteByte(0); \
} \
} \

void AudioManager::write_aifc(AudioBankSample* entry, LUS::BinaryWriter &out) {
int16_t num_channels = 1;
auto data = entry->data;
size_t len = 0;
assert(data.size() % 9 == 0);
if(data.size() % 2 == 1){
data.push_back('\0');
}
uint32_t num_frames = data.size() * 16 / 9;
int16_t sample_size = 16;

uint32_t sample_rate = -1;
if(entry->tunings.size() == 1){
sample_rate = 32000 * entry->tunings[0];
} else {
float tmin = PyUtils::min(entry->tunings);
float tmax = PyUtils::max(entry->tunings);

if(tmin <= 0.5f <= tmax){
sample_rate = 16000;
} else if(tmin <= 1.0f <= tmax){
sample_rate = 32000;
} else if(tmin <= 1.5f <= tmax){
sample_rate = 48000;
} else if(tmin <= 2.5f <= tmax){
sample_rate = 80000;
} else {
sample_rate = 16000 * (tmin + tmax);
}
}

out.Write((uint32_t) BSWAP32(AIFC::MagicValues::FORM));
// This should be where the size is, but we need to write it later
out.Write((uint32_t) 0);
out.Write((uint32_t) BSWAP32(AIFC::MagicValues::AIFC));

START_SECTION(AIFC::MagicValues::COMM);

tmp.Write((uint16_t) num_channels);
tmp.Write((uint32_t) num_frames);

tmp.Write((uint16_t) sample_size);
serialize_f80(sample_rate, tmp);
tmp.Write(AIFC::MagicValues::VAPC);
tmp.Write("\x0bVADPCM ~4-1", false);

END_SECTION();

START_SECTION(AIFC::MagicValues::INST)
tmp.Write(std::string(20, '\0'), false);
END_SECTION();

START_CUSTOM_SECTION("\x0bVADPCMCODES")
tmp.Write((uint16_t) 1);
tmp.Write((uint16_t) entry->book.order);
tmp.Write((uint16_t) entry->book.npredictors);

for(auto x : entry->book.table){
tmp.Write((int16_t) x);
}
END_SECTION();

START_SECTION(AIFC::MagicValues::SSND)
uint32_t zero = 0;
tmp.Write((char*) &zero, 4);
tmp.Write((char*) &zero, 4);
tmp.Write((char*) data.data(), data.size());
END_SECTION();

if(entry->loop.count != 0){
START_CUSTOM_SECTION("\x0bVADPCMLOOPS")
uint16_t one = BSWAP16(1);
tmp.Write(reinterpret_cast<char*>(&one), 2);
tmp.Write(reinterpret_cast<char*>(&one), 2);
tmp.Write(entry->loop.start);
tmp.Write(entry->loop.end);
tmp.Write(entry->loop.count);
for(size_t i = 0; i < 16; i++){
int16_t loop = BSWAP16(entry->loop.state.value()[i]);
tmp.Write(reinterpret_cast<char*>(&loop), 2);
}
END_SECTION();
}

len += 4;
out.Seek(4, LUS::SeekOffsetType::Start);
out.Write((uint32_t) BSWAP32(len));

}

void AudioManager::bind_sample(YAML::Node& node, const std::string& path){
auto id = GetSafeNode<uint32_t>(node, "id");
sample_table[id] = path;
Expand All @@ -639,6 +500,7 @@ std::string& AudioManager::get_sample(uint32_t id) {
return sample_table[id];
}

/*
void AudioManager::create_aifc(int32_t index, LUS::BinaryWriter &out) {
int32_t idx = -1;
for(auto &sample_bank : this->loaded_tbl.banks){
Expand All @@ -653,6 +515,7 @@ void AudioManager::create_aifc(int32_t index, LUS::BinaryWriter &out) {
}
}
}
*/

AudioBankSample AudioManager::get_aifc(int32_t index) {
int32_t idx = 0;
Expand Down Expand Up @@ -680,4 +543,17 @@ uint32_t AudioManager::get_index(AudioBankSample* entry) {

std::map<uint32_t, Bank> AudioManager::get_banks() {
return this->banks;
}

std::vector<AudioBankSample*> AudioManager::get_samples() {
std::vector<AudioBankSample*> samples;
for(auto &bank : this->loaded_tbl.banks){
for(auto &entry : bank->entries){
// Avoid duplicates
if(std::find(samples.begin(), samples.end(), entry.second) == samples.end()){
samples.push_back(entry.second);
}
}
}
return samples;
}
18 changes: 1 addition & 17 deletions src/factories/naudio/v0/AudioManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,6 @@
#define NONE 0xFFFF
#define ALIGN(val, al) (size_t) ((val + (al - 1)) & -al)

namespace AIFC {
enum MagicValues {
FORM = 0x464f524d,
AIFC = 0x41494643,
COMM = 0x434f4d4d,
INST = 0x494e5354,
VAPC = 0x56415043,
SSND = 0x53534e44,
AAPL = 0x4150504c,
stoc = 0x73746f63,
};
}

struct Entry {
uint32_t offset;
uint32_t length;
Expand Down Expand Up @@ -139,12 +126,11 @@ class AudioManager {
static AudioManager* Instance;
void initialize(std::vector<uint8_t>& buffer, YAML::Node& data);
void bind_sample(YAML::Node& node, const std::string& path);
void create_aifc(int32_t index, LUS::BinaryWriter& writer);
std::string& get_sample(uint32_t id);
AudioBankSample get_aifc(int32_t index);
std::map<uint32_t, Bank> get_banks();
std::vector<AudioBankSample*> get_samples();
uint32_t get_index(AudioBankSample* bank);

private:
std::map<uint32_t, Bank> banks;
std::map<AudioBankSample*, uint32_t> sampleMap;
Expand All @@ -161,6 +147,4 @@ class AudioManager {
static std::vector<AdsrEnvelope> parse_envelope(uint32_t addr, std::vector<uint8_t>& dataBank);
static Bank parse_ctl(CTLHeader header, std::vector<uint8_t> data, SampleBank* bank, uint32_t index);
static TBLFile parse_tbl(std::vector<uint8_t>& data, std::vector<Entry>& entries);

static void write_aifc(AudioBankSample* entry, LUS::BinaryWriter& writer);
};
Loading

0 comments on commit 1d485d7

Please sign in to comment.