Split chunk reading into helper functions.

main
Nes370 2024-07-24 10:19:49 -07:00
parent e5bf3ca9c0
commit 35ffcbad33
2 changed files with 193 additions and 119 deletions

View File

@ -17,8 +17,8 @@
16,Normal,Here's the next tune.,AV Player 16,Normal,Here's the next tune.,AV Player
17,Normal,I can feel this race is gonna be really hot. Now start your engine and get ready.,Pre-race 17,Normal,I can feel this race is gonna be really hot. Now start your engine and get ready.,Pre-race
18,Normal,I can feel this race is gonna be really hot. Now start your engine and get ready.,Pre-race 18,Normal,I can feel this race is gonna be really hot. Now start your engine and get ready.,Pre-race
19,Normal,Heh aww yeah… I can feel this race is gonna be really hot. Now start your engine and get ready.,Pre-race 19,Normal,Hehe aww yeah… I can feel this race is gonna be really hot. Now start your engine and get ready.,Pre-race
20,Normal,, 20,Normal,"Are you nervous? Hah, I'm so excited! Come on! Hurry up and start this race.",Pre-race
21,Normal,, 21,Normal,,
22,Normal,, 22,Normal,,
23,Normal,, 23,Normal,,

1 Track Speaker Transcript Context
17 16 Normal Here's the next tune. AV Player
18 17 Normal I can feel this race is gonna be really hot. Now start your engine and get ready. Pre-race
19 18 Normal I can feel this race is gonna be really hot. Now start your engine and get ready. Pre-race
20 19 Normal Heh aww yeah… I can feel this race is gonna be really hot. Now start your engine and get ready. Hehe aww yeah… I can feel this race is gonna be really hot. Now start your engine and get ready. Pre-race
21 20 Normal Are you nervous? Hah, I'm so excited! Come on! Hurry up and start this race. Pre-race
22 21 Normal
23 22 Normal
24 23 Normal

View File

@ -263,21 +263,79 @@ public class AudioExtractor {
} }
/** /**
* Helper method that converts a little-endian byte array into a long value. * Helper function to prompt user to select a program task.
* *
* @param bytes (up to 8 bytes) * @param reader
* @return value * @param input
* @return operation
*/ */
public static long littleEndianToLong(byte[] bytes) { private static String retrieveOperation(BufferedReader reader, String input) {
if(bytes.length > 8)
throw new IllegalArgumentException("Byte array must be 8 bytes or shorter."); String operation = null;
long value = 0; String[] values = {"identify", "extract", "pack", "patch", "print", "exit"};
for(int i = 0; i < bytes.length; i++)
value |= (long) (bytes[i] & 0xFF) << (8 * i); if(input != null)
return value; for(int i = 0; i < values.length; i++)
if(values[i].equalsIgnoreCase(input))
operation = values[i];
if(operation == null) {
String prompt = "\n" + Ansi.colorize("Operations", Attribute.BRIGHT_YELLOW_TEXT(), Attribute.BOLD()) + ":\n"
+ "- " + Ansi.colorize("Identify", Attribute.BRIGHT_RED_TEXT()) + " a package or audio file\n"
+ "- " + Ansi.colorize("Extract", Attribute.TEXT_COLOR(0xFF, 0x68, 0x1F)) + " audio tracks from a package (BIN -> WAV/XMA)\n"
+ "- " + Ansi.colorize("Convert", Attribute.TEXT_COLOR(0xFF, 0xEA, 0x00)) + " audio tracks to another format (XMA <-> WAV <-> FLAC)\n"
+ "- " + Ansi.colorize("Patch", Attribute.BRIGHT_GREEN_TEXT()) + " an audio track to repeat (WAV)\n"
+ "- " + Ansi.colorize("Pack", Attribute.BRIGHT_BLUE_TEXT()) + " audio tracks into a package (WAV/XMA -> BIN)\n"
+ "- " + Ansi.colorize("Print", Attribute.TEXT_COLOR(0x6B, 0x4C, 0xE3)) + " a Ridge Racer 6 style ASCII logo\n"
+ "- " + Ansi.colorize("Exit", Attribute.BRIGHT_MAGENTA_TEXT()) + " program\n"
+ "\nPlease select an operation: " + ANSI_BEIGE;
operation = retrieveInput(reader, prompt, values);
if(CMD_MODE) {
Attribute color = null;
switch(operation.toLowerCase()) {
case "identify":
color = Attribute.BRIGHT_RED_TEXT();
break;
case "extract":
color = Attribute.TEXT_COLOR(0xFF, 0x68, 0x1F);
break;
case "convert":
color = Attribute.TEXT_COLOR(0xFF, 0xEA, 0x00);
case "patch":
color = Attribute.BRIGHT_GREEN_TEXT();
break;
case "pack":
color = Attribute.BRIGHT_BLUE_TEXT();
break;
case "print":
color = Attribute.TEXT_COLOR(0x6B, 0x4C, 0xE3);
break;
case "exit":
color = Attribute.BRIGHT_MAGENTA_TEXT();
break;
}
System.out.println(ANSI_BACKLINE + Ansi.colorize("Please select an operation: ") + Ansi.colorize(operation, color));
} else System.out.print(Ansi.colorize(""));
} }
return operation.toLowerCase();
}
/**
* Examines a given file and reads some of its properties.
*
* @param unknownFile
*/
public static void identify(File unknownFile) { public static void identify(File unknownFile) {
// TODO check for characteristics of BIN or WAV files // TODO check for characteristics of BIN or WAV files
@ -307,55 +365,32 @@ public class AudioExtractor {
case "wav": case "wav":
case "xma": case "xma":
default: { default: {
byte[] buffer = new byte[4];
for(long i = 0; i < size - 4; i += 4) { for(long i = 0; i < size - 4; i += 4) {
file.seek(i); file.seek(i);
int value = file.readInt(); int value = file.readInt();
switch(value) { switch(value) {
case ASCII_RIFF: { case ASCII_RIFF: {
System.out.println(formatAddress(i) + ":\tRIFF (Resource Interchange File Format) chunk"); readRIFFChunk(file, (int) i);
if(i + 8 < size) {
int riffSize = readChunkSize(file, (int) i);
System.out.println(formatAddress(i + 4) + ":\t" + riffSize + " Bytes" + (riffSize > 1024 ? " (" + convertBytes(riffSize) + ")" : ""));
}
if(i + 12 < size) {
file.seek(i + 8);
value = file.readInt();
if(value == ASCII_WAVE)
System.out.println(formatAddress(i + 8) + ":\tWAVE (Waveform Audio File Format) type");
i += 8;
}
System.out.println();
break; break;
} }
case ASCII_fmt: { case ASCII_fmt: {
System.out.println(formatAddress(i) + ":\tfmt (Format) chunk"); readFormatChunk(file, (int) i);
int fmtSize = 8; break;
if(i + 8 < size) {
fmtSize = readChunkSize(file, (int) i);
System.out.println(formatAddress(i + 4) + ":\t" + fmtSize + " Bytes" + (fmtSize > 1024 ? " (" + convertBytes(fmtSize) + ")" : ""));
} }
if(i + fmtSize < size) { case ASCII_smpl: {
file.seek(i + 8); readSampleChunk(file, (int) i);
byte[] LEBytes = new byte[2]; break;
file.read(LEBytes);
long encoding = littleEndianToLong(LEBytes);
System.out.print(formatAddress(i + 8) + "\t");
if(encoding == 0x0001)
System.out.print("PCM (Pulse-Code Modulation)");
else if(encoding == 0x0002)
System.out.print("ADPCM (Adaptive Differential Pulse-Code Modulation)");
else if(encoding == 0x0165)
System.out.print("XMA (Xbox Media Audio)");
else if(encoding == 0x0166)
System.out.print("XMA2 (Xbox Media Audio 2)");
else System.out.print("Unknown");
// TODO lookup values from CSV
System.out.println(" encoding");
i += fmtSize;
} }
System.out.println(); case ASCII_data: {
readDataChunk(file, (int) i);
break;
}
case ASCII_ALIG: {
readAlignmentChunk(file, (int) i);
break;
}
case ASCII_x2st: {
readx2stChunk(file, (int) i);
break; break;
} }
} }
@ -371,6 +406,81 @@ public class AudioExtractor {
} }
public static void readRIFFChunk(RandomAccessFile file, int offset) throws IOException {
System.out.println(formatAddress(offset) + ":\tRIFF (Resource Interchange File Format) chunk");
if(offset + 8 < file.length()) {
int riffSize = readChunkSize(file, offset);
System.out.println(formatAddress(offset + 4) + ":\t" + riffSize + " Bytes" + (riffSize > 1024 ? " (" + convertBytes(riffSize) + ")" : ""));
}
if(offset + 12 < file.length()) {
file.seek(offset + 8);
if(file.readInt() == ASCII_WAVE)
System.out.println(formatAddress(offset + 8) + ":\tWAVE (Waveform Audio File Format) type");
offset += 8;
}
System.out.println();
}
public static void readFormatChunk(RandomAccessFile file, int offset) throws IOException {
System.out.println(formatAddress(offset) + ":\tfmt (Format) chunk");
int fmtSize = 8;
if(offset + 8 < file.length()) {
fmtSize = readChunkSize(file, (int) offset);
System.out.println(formatAddress(offset + 4) + ":\t" + fmtSize + " Bytes" + (fmtSize > 1024 ? " (" + convertBytes(fmtSize) + ")" : ""));
}
if(offset + fmtSize < file.length()) {
file.seek(offset + 8);
byte[] LEBytes = new byte[2];
file.read(LEBytes);
int encoding = littleEndianToInt(LEBytes);
System.out.print(formatAddress(offset + 8) + "\t");
if(encoding == 0x0001)
System.out.print("PCM (Pulse-Code Modulation)");
else if(encoding == 0x0002)
System.out.print("ADPCM (Adaptive Differential Pulse-Code Modulation)");
else if(encoding == 0x0165)
System.out.print("XMA (Xbox Media Audio)");
else if(encoding == 0x0166)
System.out.print("XMA2 (Xbox Media Audio 2)");
else System.out.print("Unknown");
// TODO lookup values from CSV
System.out.println(" encoding");
offset += fmtSize;
}
System.out.println();
}
private static void readx2stChunk(RandomAccessFile file, int i) {
// TODO Auto-generated method stub
}
private static void readAlignmentChunk(RandomAccessFile file, int i) {
// TODO Auto-generated method stub
}
private static void readDataChunk(RandomAccessFile file, int i) {
// TODO Auto-generated method stub
}
private static void readSampleChunk(RandomAccessFile file, int i) {
// TODO Auto-generated method stub
}
/** /**
* Formats a file address with leading zeroes. * Formats a file address with leading zeroes.
* *
@ -658,72 +768,6 @@ public class AudioExtractor {
} }
/**
* Helper function to prompt user to select a program task.
*
* @param reader
* @param input
* @return operation
*/
private static String retrieveOperation(BufferedReader reader, String input) {
String operation = null;
String[] values = {"identify", "extract", "pack", "patch", "print", "exit"};
if(input != null)
for(int i = 0; i < values.length; i++)
if(values[i].equalsIgnoreCase(input))
operation = values[i];
if(operation == null) {
String prompt = "\n" + Ansi.colorize("Operations", Attribute.BRIGHT_YELLOW_TEXT(), Attribute.BOLD()) + ":\n"
+ "- " + Ansi.colorize("Identify", Attribute.BRIGHT_RED_TEXT()) + " a package or audio file\n"
+ "- " + Ansi.colorize("Extract", Attribute.TEXT_COLOR(0xFF, 0x68, 0x1F)) + " audio tracks from a package (BIN -> WAV/XMA)\n"
+ "- " + Ansi.colorize("Convert", Attribute.TEXT_COLOR(0xFF, 0xEA, 0x00)) + " audio tracks to another format (XMA <-> WAV <-> FLAC)\n"
+ "- " + Ansi.colorize("Patch", Attribute.BRIGHT_GREEN_TEXT()) + " an audio track to repeat (WAV)\n"
+ "- " + Ansi.colorize("Pack", Attribute.BRIGHT_BLUE_TEXT()) + " audio tracks into a package (WAV/XMA -> BIN)\n"
+ "- " + Ansi.colorize("Print", Attribute.TEXT_COLOR(0x6B, 0x4C, 0xE3)) + " a Ridge Racer 6 style ASCII logo\n"
+ "- " + Ansi.colorize("Exit", Attribute.BRIGHT_MAGENTA_TEXT()) + " program\n"
+ "\nPlease select an operation: " + ANSI_BEIGE;
operation = retrieveInput(reader, prompt, values);
if(CMD_MODE) {
Attribute color = null;
switch(operation.toLowerCase()) {
case "identify":
color = Attribute.BRIGHT_RED_TEXT();
break;
case "extract":
color = Attribute.TEXT_COLOR(0xFF, 0x68, 0x1F);
break;
case "convert":
color = Attribute.TEXT_COLOR(0xFF, 0xEA, 0x00);
case "patch":
color = Attribute.BRIGHT_GREEN_TEXT();
break;
case "pack":
color = Attribute.BRIGHT_BLUE_TEXT();
break;
case "print":
color = Attribute.TEXT_COLOR(0x6B, 0x4C, 0xE3);
break;
case "exit":
color = Attribute.BRIGHT_MAGENTA_TEXT();
break;
}
System.out.println(ANSI_BACKLINE + Ansi.colorize("Please select an operation: ") + Ansi.colorize(operation, color));
} else System.out.print(Ansi.colorize(""));
}
return operation.toLowerCase();
}
/** /**
* Helper function to prompt user to select a WAV file. * Helper function to prompt user to select a WAV file.
* *
@ -1923,4 +1967,34 @@ public class AudioExtractor {
} }
/**
* Helper method that converts a little-endian byte array into a long value.
*
* @param bytes (up to 8 bytes)
* @return value
*/
public static long littleEndianToLong(byte[] bytes) {
if(bytes.length > 8)
throw new IllegalArgumentException("Byte array must be 8 bytes or shorter.");
long value = 0;
for(int i = 0; i < bytes.length; i++)
value |= (long) (bytes[i] & 0xFF) << (8 * i);
return value;
}
/**
* Helper method that converts a little-endian byte array into a long value.
*
* @param bytes (up to 8 bytes)
* @return value
*/
public static int littleEndianToInt(byte[] bytes) {
if(bytes.length > 8)
throw new IllegalArgumentException("Byte array must be 4 bytes or shorter.");
int value = 0;
for(int i = 0; i < bytes.length; i++)
value |= (int) (bytes[i] & 0xFF) << (8 * i);
return value;
}
} }