summaryrefslogtreecommitdiff
path: root/src/factories/oot/OoTAudioSequenceWriter.cpp
blob: 3863affc196a0ce9a84e24ee71bf2e6fa952dc51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include "OoTAudioSequenceWriter.h"
#include "spdlog/spdlog.h"
#include "Companion.h"
#include <iomanip>
#include <sstream>

namespace OoT {

void AudioSequenceWriter::WriteCompanion(const uint8_t* seqData, uint32_t seqSize,
                                         uint32_t originalIndex, uint8_t medium, uint8_t cachePolicy,
                                         const std::vector<uint8_t>& fonts, const std::string& seqName) {
    LUS::BinaryWriter w;
    BaseExporter::WriteHeader(w, Torch::ResourceType::OoTAudioSequence, 2);

    w.Write(seqSize);
    w.Write((char*)seqData, seqSize);

    w.Write(static_cast<uint8_t>(originalIndex));
    w.Write(medium);
    w.Write(cachePolicy);

    w.Write(static_cast<uint32_t>(fonts.size()));
    for (auto f : fonts) {
        w.Write(f);
    }

    std::stringstream ss;
    w.Finish(ss);
    std::string str = ss.str();
    Companion::Instance->RegisterCompanionFile(
        "sequences/" + seqName, std::vector<char>(str.begin(), str.end()));
}

bool AudioSequenceWriter::Extract(std::vector<uint8_t>& buffer, YAML::Node& node,
                                  const std::vector<AudioTableEntry>& seqTable,
                                  const std::vector<std::vector<uint8_t>>& seqFontMap) {
    // Get Audioseq ROM data (segment 2, uncompressed)
    auto audioseqSeg = Companion::Instance->GetFileOffsetFromSegmentedAddr(2);
    if (!audioseqSeg.has_value()) {
        SPDLOG_ERROR("OoTAudioFactory: Audioseq segment not found");
        return false;
    }
    uint32_t audioseqOff = audioseqSeg.value();

    // Get sequence names from YAML
    std::vector<std::string> seqNames;
    if (node["sequences"] && node["sequences"].IsSequence()) {
        auto seqNode = node["sequences"];
        for (size_t i = 0; i < seqNode.size(); i++) {
            seqNames.push_back(seqNode[i].as<std::string>());
        }
    }

    for (uint32_t i = 0; i < seqTable.size(); i++) {
        auto medium = seqTable[i].medium;
        auto cachePolicy = seqTable[i].cachePolicy;
        auto& fonts = seqFontMap[i];

        // Resolve alias: size==0 means ptr holds the index of the real sequence
        bool isAlias = (seqTable[i].size == 0);
        uint32_t dataIdx = isAlias ? seqTable[i].ptr : i;
        if (dataIdx >= seqTable.size()) {
            SPDLOG_WARN("OoTAudioFactory: sequence {} alias index {} out of range", i, dataIdx);
            continue;
        }
        auto& dataEntry = seqTable[dataIdx];

        // Sequence name
        std::string seqName;
        if (i < seqNames.size()) {
            seqName = seqNames[i];
        } else {
            std::ostringstream ss;
            ss << std::setfill('0') << std::setw(3) << i << "_Sequence";
            seqName = ss.str();
        }

        // Resolve sequence data location in ROM (using dataEntry for aliased sequences)
        uint32_t seqDataOff = audioseqOff + dataEntry.ptr;
        if (seqDataOff + dataEntry.size > buffer.size()) {
            SPDLOG_WARN("OoTAudioFactory: sequence {} out of bounds", seqName);
            continue;
        }

        WriteCompanion(buffer.data() + seqDataOff, dataEntry.size,
                        i, medium, cachePolicy, fonts, seqName);
    }

    SPDLOG_INFO("OoTAudioFactory: wrote {} sequence companion files", seqTable.size());
    return true;
}

} // namespace OoT