diff --git a/res/pack_dj_menu.csv b/res/pack_dj_menu.csv index 5158e0e..33882e9 100644 --- a/res/pack_dj_menu.csv +++ b/res/pack_dj_menu.csv @@ -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,, diff --git a/src/goblincave/gitea/nes/AudioExtractor.java b/src/goblincave/gitea/nes/AudioExtractor.java index 8f801a8..f8a6d2d 100644 --- a/src/goblincave/gitea/nes/AudioExtractor.java +++ b/src/goblincave/gitea/nes/AudioExtractor.java @@ -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; } } @@ -370,6 +405,81 @@ public class AudioExtractor { // check if RIFF header } + + 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; + } + }