Skip to content

Instantly share code, notes, and snippets.

@BenjaminUrquhart
Last active June 12, 2020 04:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BenjaminUrquhart/9ea8371746ca7f282f819100d68db523 to your computer and use it in GitHub Desktop.
Save BenjaminUrquhart/9ea8371746ca7f282f819100d68db523 to your computer and use it in GitHub Desktop.
Why
/* |----------------------CHUNK FORMAT----------------------|
* | Offset | Size | Type | Description |
* |--------------------------------------------------------|
* | 0 | 4 | uint32 | Number of entries |
* | 4 | 4*N | uint32[N]| Offsets to entries|
* |----------------------ENTRY FORMAT----------------------|
* | 0 | 4 | uint32 | Name (ptr to STRG)|
* | 4 | 4 | uint32 | Flags (See Notes) |
* | 8 | 4 | uint32 |FileEx(ptr to STRG)|
* | 12 | 4 | uint32 | Path (ptr to STRG)|
* | 16 | 4 | uint32 | ??? |
* | 20 | 4 | uint32 | Offset to ??? |
* | 24 | 4 | uint32 | ??? |
* | 28 | 4 | uint32 | ??? |
* | 30 | 4 | uint32 | ??? |
* | 32 | 4 | uint32 | AUDO index |
* |--------------------------------------------------------|
* | Notes: This was by FAR the most infuriating chunk to |
* | parse. My reference document made no mention of it. |
* | |
* | I went in with nothing but a hex editor and optimism. |
* | |
* | I left with crippling depression and an unhealthy |
* | desire to assassinate whoever thought THIS was a good |
* | way to store audio metadata. Really? You couldn't just,|
* | you know, store all of this WITH THE AUDIO??? |
* | |
* | I did this so you wouldn't have to. It's too late for |
* | me, save yourself. |
* | |
* | FLAGS: |
* | 0x01 -> EMBEDDED (contained within the data file) |
* | 0x02 -> COMPRESSED (READ: embedded OGG instead of WAV) |
* | 0x64 -> REGULAR (all the entries are "regular") |
* | |
* | Fun fact: any COMPRESSED files will have their FileEx |
* | as ".mp3" despite them being OGG Vorbis. Go figure. |
* |--------------------------------------------------------|
*/
private static void initSoundMetadata() {
StringResource name, path;
boolean embedded;
int num = audioMetaChunk.readInt(0), offset, relativeOffset, index, flags, indexOffset = 0;
Set<AudioResource> processed = new HashSet<>();
AudioResource audio;
Set<AudioResource.Flag> flagSet;
for(int i = 0; i < num; i++) {
offset = audioMetaChunk.readInt(4*(i+1));
relativeOffset = (int)(offset-absoluteAudioMetaOffset);
name = getStringFromAbsoluteOffset(audioMetaChunk.readInt(relativeOffset));
flags = audioMetaChunk.readInt(relativeOffset+4);
flagSet = AudioResource.Flag.parse(flags);
embedded = flagSet.contains(AudioResource.Flag.EMBEDDED) || flagSet.contains(AudioResource.Flag.COMPRESSED);
path = getStringFromAbsoluteOffset(audioMetaChunk.readInt(relativeOffset+12));
index = audioMetaChunk.readInt(relativeOffset+32);
// Look, why even give us information for a track that isn't supposed to exist?
if(index < 0) {
System.out.printf("Invalid track %s (%s - %s) with index %d\n", name.getString(), path.getString(), flagSet, index);
continue;
}
//System.out.printf("Processing audio track %s (%s) at 0x%08x (Index: %d, Embedded: %s)\n", name.getString(), path.getString(), offset, index, embedded);
// The fact that we even NEED an index offset is absurd
if(embedded) {
audio = ResourceManager.audio.get(index+indexOffset);
//System.out.printf("0x%08x -> %s -> %s\n", offset, audio, audio.getSource());
}
else {
audio = new AudioResource(null, 0, 0);
ResourceManager.audio.add(index+indexOffset, audio);
//System.out.printf("0x%08x -> <new instance> -> <no chunk>\n", offset);
indexOffset++;
}
/* Yes, this actually happened. This is why the stupid index offset is necessary.
* It turns out if an external audio resource is referenced, the index isn't
* updated until the next embedded resource.
*
* The result: we might accidentally set the metadata of an audio resource twice, making
* it inaccurate.
*
* Brilliant design, I applaud whoever made this.
*
* End me.
*/
if(!processed.add(audio)) {
throw new IllegalStateException(String.format("encountered the same audio resource twice??? (Index: %d, Resource: %s)", index, audio));
}
audio.setFilename(path.getString());
audio.setName(name.getString());
audio.setFlags(flagSet);
// AAAAAAAAAAAAAAAAAAAAAAAAAAAAA more sanity checks
audio.verify();
audioTable.put(path.getString(), audio);
audioTable.put(name.getString(), audio);
}
}
/* |----------------------CHUNK FORMAT----------------------|
* | Offset | Size | Type | Description |
* |--------------------------------------------------------|
* | 0 | 4 | uint32 | Number of entries |
* | 4 | 4*N | uint32[N]| Offsets to entries|
* | 8 | ? | File[N] | Audio Files |
* |----------------------ENTRY FORMAT----------------------|
* | 0 | 4 | uint32 | File size |
* | 4 | N | uint8[N] | File data |
* |--------------------------------------------------------|
* | Notes: Why even HAVE the SOND chunk when you can just |
* | put the metadata here??? Just WHY??? |
* |--------------------------------------------------------|
*/
private static void initAudio() {
audioTable = new HashMap<>();
audio = new ArrayList<>();
int num = audioChunk.readInt(0), offset, relativeOffset, length;
AudioResource resource;
for(int i = 0; i < num; i++) {
offset = audioChunk.readInt(4*(i+1));
relativeOffset = (int)(offset-absoluteAudioOffset);
length = audioChunk.readInt(relativeOffset);
resource = new AudioResource(audioChunk, relativeOffset+4, length);
audio.add(resource);
if(resource.getSource() == null) {
throw new IllegalStateException("null source for newly-created audio object (" + resource + ")");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment