mirror of
https://github.com/zeldaret/oot.git
synced 2024-12-02 07:46:01 +00:00
29acf96db2
* [Audio 1/?] Extract Samplebanks and Soundfonts to XML * Remove config.py and use the version yamls for addresses, other suggested changes * Adjust setup-audio * Remove some commented out dead code (MM review)
119 lines
3.3 KiB
Python
119 lines
3.3 KiB
Python
# SPDX-FileCopyrightText: © 2024 ZeldaRET
|
|
# SPDX-License-Identifier: CC0-1.0
|
|
#
|
|
# Implements envelopes and envelope point structures
|
|
#
|
|
|
|
import collections
|
|
|
|
from .util import XMLWriter
|
|
|
|
class EnvDelay(int):
|
|
def __str__(self):
|
|
return {
|
|
0 : "ADSR_DISABLE",
|
|
-1 : "ADSR_HANG",
|
|
-2 : "ADSR_GOTO",
|
|
-3 : "ADSR_RESTART",
|
|
}.get(self, super().__str__())
|
|
|
|
class Envelope:
|
|
"""
|
|
Array of envelope points
|
|
"""
|
|
|
|
class EnvelopePoint:
|
|
"""
|
|
typedef struct {
|
|
/* 0x0 */ s16 delay;
|
|
/* 0x2 */ s16 arg;
|
|
} EnvelopePoint; // size = 0x4
|
|
"""
|
|
|
|
def __init__(self, delay, arg):
|
|
self.delay = EnvDelay(delay)
|
|
self.arg = arg
|
|
|
|
def __repr__(self):
|
|
return str(self)
|
|
|
|
def __str__(self):
|
|
return f"{{ {self.delay}, {self.arg} }}"
|
|
|
|
def is_disable(self):
|
|
return self.delay == 0 and self.arg == 0
|
|
|
|
def is_hang(self):
|
|
return self.delay == -1 and self.arg == 0
|
|
|
|
def to_xml(self, xml : XMLWriter):
|
|
if self.delay == 0: # Disable
|
|
assert self.arg == 0
|
|
xml.write_element("Disable")
|
|
elif self.delay == -1: # Hang
|
|
assert self.arg == 0
|
|
xml.write_element("Hang")
|
|
elif self.delay == -2: # Goto
|
|
xml.write_element("Goto",
|
|
{ "Arg" : self.arg }
|
|
)
|
|
elif self.delay == -3: # Restart
|
|
assert self.arg == 0
|
|
xml.write_element("Restart")
|
|
else:
|
|
assert self.delay >= 0
|
|
xml.write_element("Point",
|
|
{
|
|
"Delay" : self.delay,
|
|
"Arg" : self.arg,
|
|
}
|
|
)
|
|
|
|
def __init__(self, points, is_zero=False):
|
|
self.name = None # Assigned when bank is finalized
|
|
|
|
self.is_zero = is_zero
|
|
self.release_rates = []
|
|
self._release_rate = None # cached
|
|
|
|
assert len(points) != 0
|
|
assert type(points[0]) == Envelope.EnvelopePoint
|
|
self.points = points
|
|
|
|
if not self.is_zero:
|
|
while self.points[-1].is_disable():
|
|
self.points.pop()
|
|
|
|
assert self.points[-1].is_hang()
|
|
|
|
def __str__(self):
|
|
out = "{\n"
|
|
out += " " + ", ".join([str(point) for point in self.points]) + "\n"
|
|
out += "}\n"
|
|
return out
|
|
|
|
def release_rate(self):
|
|
if self._release_rate is not None:
|
|
return self._release_rate
|
|
|
|
rates = collections.Counter(self.release_rates).most_common()
|
|
assert len(rates) in [0, 1], rates # TODO handle ties?
|
|
|
|
self._release_rate = 0 if len(rates) == 0 else rates[0][0]
|
|
return self._release_rate
|
|
|
|
def to_xml(self, xml : XMLWriter, name : str):
|
|
if self.is_zero:
|
|
return xml.write_element("Envelope")
|
|
|
|
xml.write_start_tag("Envelope",
|
|
{
|
|
"Name" : name,
|
|
"Release" : self.release_rate(),
|
|
}
|
|
)
|
|
|
|
for point in self.points[:-1]: # exclude final hang command, will be added by the soundfont compiler on build
|
|
point.to_xml(xml)
|
|
|
|
xml.write_end_tag()
|