1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2024-12-29 08:16:11 +00:00
oot/tools/audio/samplebank.c

125 lines
4.3 KiB
C

/**
* SPDX-FileCopyrightText: Copyright (C) 2024 ZeldaRET
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <assert.h>
#include <stdlib.h>
#include "xml.h"
#include "samplebank.h"
#include "util.h"
const char *
samplebank_path_forname(samplebank *sb, const char *name)
{
assert(name != NULL);
for (size_t i = 0; i < sb->num_samples; i++) {
if (strequ(sb->sample_names[i], name))
return sb->sample_paths[i];
}
return NULL;
}
typedef struct {
const char *name;
const char *path;
} samplebank_xml_entry;
void
read_samplebank_xml(samplebank *sb, xmlDocPtr doc)
{
// XML Example:
// <SampleBank Name="" Index="" Medium="" CachePolicy="" BufferBug="">
// <Pointer Index=""/>
// <Sample Name="" Path=""/>
// <Blob Name="" Path=""/>
static const xml_attr_spec header_spec = {
{"Name", false, xml_parse_c_identifier, offsetof(samplebank, name) },
{ "Index", false, xml_parse_int, offsetof(samplebank, index) },
{ "Medium", false, xml_parse_c_identifier, offsetof(samplebank, medium) },
{ "CachePolicy", false, xml_parse_c_identifier, offsetof(samplebank, cache_policy)},
{ "BufferBug", true, xml_parse_bool, offsetof(samplebank, buffer_bug) },
};
static const xml_attr_spec entry_spec = {
{"Name", false, xml_parse_c_identifier, offsetof(samplebank_xml_entry, name)},
{ "Path", false, xml_parse_string, offsetof(samplebank_xml_entry, path)},
};
xmlNodePtr root = xmlDocGetRootElement(doc);
if (!strequ(XMLSTR_TO_STR(root->name), "SampleBank"))
error("Root node must be <SampleBank>");
sb->buffer_bug = false;
xml_parse_node_by_spec(sb, root, header_spec, ARRAY_COUNT(header_spec));
if (root->children == NULL)
error("Missing samples list");
size_t entries_cap = 8;
size_t entries_len = 0;
sb->sample_names = malloc(entries_cap * sizeof(const char *));
sb->sample_paths = malloc(entries_cap * sizeof(const char *));
sb->is_sample = malloc(entries_cap * sizeof(bool));
size_t pointers_cap = 4;
size_t pointers_len = 0;
sb->pointer_indices = malloc(pointers_cap * sizeof(int));
LL_FOREACH(xmlNodePtr, node, root->children) {
if (node->type != XML_ELEMENT_NODE)
continue;
if (node->children != NULL) {
xmlNodePtr first_child = node->children;
const char *child_name = XMLSTR_TO_STR(first_child->name);
error("Unexpected child node(s) (first is %s) in samples list (line %d)", child_name, first_child->line);
}
const char *node_name = XMLSTR_TO_STR(node->name);
bool is_sample;
if (strequ(node_name, "Sample")) {
is_sample = true;
} else if (strequ(node_name, "Blob")) {
is_sample = false;
} else if (strequ(node_name, "Pointer")) {
// pointer entry
int ptr_index;
xml_get_single_property(&ptr_index, node, "Index", xml_parse_int);
if (pointers_len == pointers_cap) {
pointers_cap *= 2;
sb->pointer_indices = realloc(sb->pointer_indices, pointers_cap * sizeof(int));
}
sb->pointer_indices[pointers_len++] = ptr_index;
continue;
} else {
error("Unexpected element node %s in samples list (line %d)", node_name, node->line);
}
samplebank_xml_entry ent;
xml_parse_node_by_spec(&ent, node, entry_spec, ARRAY_COUNT(entry_spec));
if (entries_len == entries_cap) {
entries_cap *= 2;
sb->sample_names = realloc(sb->sample_names, entries_cap * sizeof(const char *));
sb->sample_paths = realloc(sb->sample_paths, entries_cap * sizeof(const char *));
sb->is_sample = realloc(sb->is_sample, entries_cap * sizeof(bool));
}
sb->sample_names[entries_len] = ent.name;
sb->sample_paths[entries_len] = ent.path;
sb->is_sample[entries_len] = is_sample;
entries_len++;
}
sb->num_samples = entries_len;
sb->num_pointers = pointers_len;
}