Split chunk reading into helper functions.
parent
e5bf3ca9c0
commit
35ffcbad33
|
@ -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,,
|
||||||
|
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue