1
0
mirror of synced 2024-11-27 22:40:49 +01:00

Add new LUTs to cover the remaining soul gauge bytes (12/13, 16/17) (#31)

Fixes #14.
This commit is contained in:
Viv 2023-07-11 08:07:30 -04:00 committed by GitHub
parent c108475026
commit bd27e9dade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 70048 additions and 20 deletions

View File

@ -286,11 +286,17 @@ def convertTJAToFumen(tja):
headerMetadata = sampleHeaderMetadata.copy()
headerMetadata[8] = DIFFICULTY_BYTES[tja['metadata']['course']][0]
headerMetadata[9] = DIFFICULTY_BYTES[tja['metadata']['course']][1]
headerMetadata[20], headerMetadata[21] = computeSoulGaugeBytes(
soulGaugeBytes = computeSoulGaugeBytes(
n_notes=total_notes,
difficulty=tja['metadata']['course'],
stars=tja['metadata']['level']
)
headerMetadata[12] = soulGaugeBytes[0]
headerMetadata[13] = soulGaugeBytes[1]
headerMetadata[16] = soulGaugeBytes[2]
headerMetadata[17] = soulGaugeBytes[3]
headerMetadata[20] = soulGaugeBytes[4]
headerMetadata[21] = soulGaugeBytes[5]
tjaConverted['headerMetadata'] = b"".join(i.to_bytes(1, 'little') for i in headerMetadata)
tjaConverted['headerPadding'] = simpleHeaders[0] # Use a basic, known set of header bytes
tjaConverted['order'] = '<'

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -36,15 +36,37 @@ def computeSoulGaugeBytes(n_notes, difficulty, stars):
key = "Easy-2-3"
elif stars <= 1:
key = "Easy-1"
# Set default values for soul gauge bytes.
# NB: These will only be used if n_notes > 2500 (i.e. the most extreme, impossible case, beyond all official charts)
soulGaugeByte12 = 255
soulGaugeByte13 = 3
soulGaugeByte16 = 255
soulGaugeByte17 = 2
soulGaugeByte20 = 255
soulGaugeByte21 = 253
pkg_dir = os.path.dirname(os.path.realpath(__file__))
with open(os.path.join(pkg_dir, "soulgauge_LUTs", f"{key}.csv"), newline='') as csvfile:
with open(os.path.join(pkg_dir, "soulgauge_LUTs", f"byte1213_{key}.csv"), newline='') as csvfile:
lut_reader = csv.reader(csvfile, delimiter=',')
for row in lut_reader:
if int(row[0]) == n_notes:
soulGaugeByte12 = int(row[1]) % 255
soulGaugeByte13 = int(row[1]) // 255
break
with open(os.path.join(pkg_dir, "soulgauge_LUTs", f"byte1617_{key}.csv"), newline='') as csvfile:
lut_reader = csv.reader(csvfile, delimiter=',')
for row in lut_reader:
if int(row[0]) == n_notes:
soulGaugeByte16 = int(row[1]) % 255
soulGaugeByte17 = int(row[1]) // 255
break
with open(os.path.join(pkg_dir, "soulgauge_LUTs", f"byte2021_{key}.csv"), newline='') as csvfile:
lut_reader = csv.reader(csvfile, delimiter=',')
for row in lut_reader:
if int(row[0]) == n_notes:
soulGaugeByte20 = int(row[1]) % 255
soulGaugeByte21 = 253 + (int(row[1]) // 255)
return soulGaugeByte20, soulGaugeByte21
raise ValueError(f"n_notes value '{n_notes}' not in lookup table (1-2500)")
break
return soulGaugeByte12, soulGaugeByte13, soulGaugeByte16, soulGaugeByte17, soulGaugeByte20, soulGaugeByte21
def readStruct(file, order, format_string, seek=None):

View File

@ -204,27 +204,27 @@ def checkValidHeader(headerBytes, strict=False):
elif idx == 9:
assert val in [27, 31, 23], f"Expected 27/31/23 at position '{idx}', got '{val}' instead."
# 3. Unknown (possibly related to n_notes)
elif idx in [12, 13]:
pass
elif idx in [16, 17]:
pass
# 6. Soul gauge bytes
# Notes:
# * These bytes determine how quickly the soul gauge should increase
# * The higher the number of notes, the higher these values will be (i.e. the slower the soul gauge will rise)
# * In practice, most of the time [21, 22, 23] will be 255.
# * So, this means that byte 20 largely determines the soul gauge increase.
# * The precise mapping between n_notes and byte values is complex, and depends on difficulty/stars.
# - See also: https://github.com/vivaria/tja2fumen/issues/14
# * Re: Byte 21, a very small number of songs (~10) have values 253 or 254 instead of 255.
# * Generally speaking, though, the higher the number of notes, then:
# - The lower that bytes 12/16 will go.
# - The higher that byte 21 will go.
# * Also, most of the time [13, 17] will be 0 and [21, 22, 23] will be 255.
# * However, a very small number of songs (~30) have values different from 0/255.
# - This applies to Easy/Normal songs with VERY few notes (<30).
# - For these songs, byte 20 will drop BELOW 1 and wrap around back to <=255, decrementing byte 21 by one.
# - So, you can think of it like this:
# * b21==253: (0*255) + 1-255 = 1-225 (VERY rapid soul gauge increase)
# * b21==254: (1*255) + 1-255 = 256-510 (Rapid soul gauge increase)
# * b21==255: (2*255) + 1-255 = 511-765 (Moderate to slow soul gauge increase, i.e. most songs)
# * Bytes 12/16 will go above 255 and wrap around back to >=0, incrementing bytes 13/17 by one.
# * Byte 20 will go below and wrap around back to <=255, decrementing byte 21 by one.
elif idx == 12:
assert 1 <= val <= 255
elif idx == 13:
assert val in [0, 1, 2, 3]
elif idx == 16:
assert 1 <= val <= 255
elif idx == 17:
assert val in [0, 1, 2, 3]
elif idx == 20:
assert 1 <= val <= 255
elif idx == 21:

View File

@ -3,7 +3,7 @@ import pytest
from tja2fumen.utils import computeSoulGaugeBytes
# 255/256, 510/511,
@pytest.mark.skip("Incomplete test")
@pytest.mark.parametrize('difficulty,stars,n_notes,b20,b21', [
['Easy', 1, 24, 165, 254], ['Easy', 1, 54, 102, 255], ['Easy', 1, 112, 182, 255],
# TODO: Fetch official fumen values for each difficulty-star pairing