Split chunk reading into helper functions.
parent
e5bf3ca9c0
commit
35ffcbad33
|
@ -17,8 +17,8 @@
|
|||
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
|
||||
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
|
||||
20,Normal,,
|
||||
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,"Are you nervous? Hah, I'm so excited! Come on! Hurry up and start this race.",Pre-race
|
||||
21,Normal,,
|
||||
22,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)
|
||||
* @return value
|
||||
* @param reader
|
||||
* @param input
|
||||
* @return operation
|
||||
*/
|
||||
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;
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Examines a given file and reads some of its properties.
|
||||
*
|
||||
* @param unknownFile
|
||||
*/
|
||||
public static void identify(File unknownFile) {
|
||||
|
||||
// TODO check for characteristics of BIN or WAV files
|
||||
|
@ -307,55 +365,32 @@ public class AudioExtractor {
|
|||
case "wav":
|
||||
case "xma":
|
||||
default: {
|
||||
byte[] buffer = new byte[4];
|
||||
for(long i = 0; i < size - 4; i += 4) {
|
||||
file.seek(i);
|
||||
int value = file.readInt();
|
||||
switch(value) {
|
||||
case ASCII_RIFF: {
|
||||
System.out.println(formatAddress(i) + ":\tRIFF (Resource Interchange File Format) chunk");
|
||||
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();
|
||||
readRIFFChunk(file, (int) i);
|
||||
break;
|
||||
}
|
||||
case ASCII_fmt: {
|
||||
System.out.println(formatAddress(i) + ":\tfmt (Format) chunk");
|
||||
int fmtSize = 8;
|
||||
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) {
|
||||
file.seek(i + 8);
|
||||
byte[] LEBytes = new byte[2];
|
||||
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();
|
||||
readFormatChunk(file, (int) i);
|
||||
break;
|
||||
}
|
||||
case ASCII_smpl: {
|
||||
readSampleChunk(file, (int) i);
|
||||
break;
|
||||
}
|
||||
case ASCII_data: {
|
||||
readDataChunk(file, (int) i);
|
||||
break;
|
||||
}
|
||||
case ASCII_ALIG: {
|
||||
readAlignmentChunk(file, (int) i);
|
||||
break;
|
||||
}
|
||||
case ASCII_x2st: {
|
||||
readx2stChunk(file, (int) i);
|
||||
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.
|
||||
*
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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