bf797f0adf269815dcd1cd3f0c39dc3e77470c38
[old-projects.git] / ekit / com / hexidec / util / DMCScodec.java
1 /* GNU General Public License DMCScodec Copyright (C) 2002 Howard A Kistler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package com.hexidec.util; import java.awt.AWTException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; /** DMCScodec * * Utility for reading (and eventually converting) Deluxe Music * Construction Set (DMCS) files * * @author Howard Kistler * @version 0.1 * * VERSION HISTORY * 0.1 (03/13/2002) - initial creation (03/13/2002) */ public class DMCScodec { // Constants ----------------------------------------------------------------------------> /* DMCS File Structure FILE HEADER ==================== (At the beginning of each file) FILE HEADER BLOCK 4 bytes - FORM 4 bytes - ? 4 bytes - DMCS 4 bytes - AMGA (for Amiga files) 4 bytes - ? (all zeroes?) SC HEADER BLOCK 4 bytes - USC1 8 bytes - ? 4 bytes - ? 8 bytes - ? 4 x 32 bytes - ? 1 byte - Title Byte count (number of letters in song title) X bytes - Song Title (length stated in previous byte) 16 bytes - 00 05 FE 77 01 01 01 02 00 00 3F 80 00 7F 00 00 SONG BODY ==================== UBR1 BLOCKS 4 bytes - UBR1 INSTRUMENT BLOCK ==================== (At the end of each file) INSTRUMENT HEAD BLOCK 4 bytes - UVLT 22 bytes - 00 00 00 12 00 00 00 0A 00 13 00 1F 00 2F 00 3F 00 51 00 69 00 7F INDIVIDUAL INSTRUMENT BLOCKS 4 bytes - UIID 4 bytes - ? (small int) X bytes - Instrument Name 2 bytes - 00 00 (last instrument may have just one byte of 00) */ // Header Array Sizes private final static byte StartFileHeaderSize = (byte)20; private final static byte InfoHeaderSize = (byte)40; // InfoHeader is always 40 bytes in size for BMP/ICO/CUR format // File Header Fields private final static byte[] FileHeaderFormWord = { 'F', 'O', 'R', 'M', }; private static byte[] FileHeaderSizeWord = new byte[4]; private final static byte[] FileHeaderTypeWord = { 'D', 'M', 'C', 'S' }; private final static byte[] FileHeaderOSAMWord = { 'A', 'M', 'G', 'A' }; // OS Word for Amiga DMCS files private final static byte[] FileHeaderTailWord = { (byte)0, (byte)0, (byte)0, (byte)0 }; // Song Body Fields private final static byte[] SongBlockUnitWord = { 'U', 'B', 'R', '1' }; // Instrument Body Fields private final static byte[] InstrumentBlockHeadWord = { 'U', 'V', 'L', 'T' }; private final static byte[] InstrumentBlockUnitWord = { 'U', 'I', 'I', 'D' }; // Public Vartypes ----------------------------------------------------------------------> public final static int FILETYPE_DMCS = 1; public final static int FILETYPE_TEXT = 2; public final static int FILETYPE_FINALE = 3; // Constructor --------------------------------------------------------------------------> public DMCScodec() { } // Decode Method ------------------------------------------------------------------------> public static void decode(String sourceFile, String destFile) throws FileNotFoundException, IOException, AWTException { convertToTextFile(sourceFile, destFile); } // Encode Method ------------------------------------------------------------------------> public static void encode(String sourceFile, String destFile, int fileType) throws FileNotFoundException, IOException, AWTException { // String newFormat = convertToFormat(sourceFile, fileType); // writeToDMCSFile(newFormat, destFile); } // DMCS-to-TEXT File Conversion --------------------------------------------------------> protected static void convertToTextFile(String inFile, String outFile) throws IOException { File srcFile = new File(inFile); FileInputStream fis = new FileInputStream(srcFile); int filesize = (int)(srcFile.length()); byte[] bData = new byte[filesize]; int iCounter = 0; while(iCounter < filesize) { bData[iCounter] = (byte)(fis.read()); iCounter++; } fis.close(); FileWriter fw = new FileWriter(new File(outFile)); String sOutput = "FILE SIZE : " + srcFile.length() + "\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "BYTES READ : " + iCounter + "\r"; fw.write(sOutput, 0, sOutput.length()); int iPlace = 0; sOutput = "====================\rFILE HEADER\r====================\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "--------------------\rFILE HEADER BLOCK\r--------------------\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "FORM BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r"; fw.write(sOutput, 0, sOutput.length()); int iSize = (int)( ((bData[iPlace++]) << 24) + ((bData[iPlace++]) << 16) + ((bData[iPlace++]) << 8) + ((bData[iPlace++]) ) ); sOutput = "SIZE BLOCK : " + iSize + "\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "TYPE BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "OS BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "TAIL BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "--------------------\rSC HEADER BLOCK\r--------------------\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "USC1 BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r"; fw.write(sOutput, 0, sOutput.length()); int iData = (int)( ((bData[iPlace++]) << 24) + ((bData[iPlace++]) << 16) + ((bData[iPlace++]) << 8) + ((bData[iPlace++]) ) ); sOutput = "DATA INT 1 : " + iData + "\r"; fw.write(sOutput, 0, sOutput.length()); iData = (int)( ((bData[iPlace++]) << 24) + ((bData[iPlace++]) << 16) + ((bData[iPlace++]) << 8) + ((bData[iPlace++]) ) ); sOutput = "DATA INT 2 : " + iData + "\r"; fw.write(sOutput, 0, sOutput.length()); iData = (int)( ((bData[iPlace++]) << 24) + ((bData[iPlace++]) << 16) + ((bData[iPlace++]) << 8) + ((bData[iPlace++]) ) ); sOutput = "DATA INT 3 : " + iData + "\r"; fw.write(sOutput, 0, sOutput.length()); iData = (int)( ((bData[iPlace++]) << 24) + ((bData[iPlace++]) << 16) + ((bData[iPlace++]) << 8) + ((bData[iPlace++]) ) ); sOutput = "DATA INT 4 : " + iData + "\r"; fw.write(sOutput, 0, sOutput.length()); iData = (int)( ((bData[iPlace++]) << 24) + ((bData[iPlace++]) << 16) + ((bData[iPlace++]) << 8) + ((bData[iPlace++]) ) ); sOutput = "DATA INT 5 : " + iData + "\r"; fw.write(sOutput, 0, sOutput.length()); for(int i = 0; i < 32; i++) { iData = (int)( ((bData[iPlace++]) << 24) + ((bData[iPlace++]) << 16) + ((bData[iPlace++]) << 8) + ((bData[iPlace++]) ) ); sOutput = "SUB INT " + (i+1) + " : " + iData + "\r"; fw.write(sOutput, 0, sOutput.length()); } sOutput = "PAD BYTES : " + bData[iPlace++] + bData[iPlace++] + bData[iPlace++] + bData[iPlace++] + "\r"; fw.write(sOutput, 0, sOutput.length()); int titleCharCount = (int)(bData[iPlace++]); sOutput = "TITLE BYTE : " + titleCharCount + "\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "SONG TITLE : "; for(int i = 0; i < titleCharCount; i++) { sOutput = sOutput + (char)(bData[iPlace++]); } sOutput = sOutput + "\r"; fw.write(sOutput, 0, sOutput.length()); for(int i = 0; i < 19; i++) { sOutput = "POST BYTE " + (i+1) + " : " + bData[iPlace++] + "\r"; fw.write(sOutput, 0, sOutput.length()); } sOutput = "====================\rSONG BODY\r====================\r"; fw.write(sOutput, 0, sOutput.length()); byte byteA = (byte)0; byte byteB = (byte)0; String blockWord = ""; while(iPlace < filesize - 5) { byteA = bData[iPlace++]; byteB = bData[iPlace++]; blockWord = "" + (char)byteA + (char)byteB; if(blockWord.equals("UB")) { byte byteC = bData[iPlace++]; byte byteD = bData[iPlace++]; String blockWord2 = "" + (char)byteC + (char)byteD; if(blockWord2.equals("R1")) { sOutput = "--------------------\rUBR1 DATA BLOCK\r--------------------\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "DATA HEAD : " + blockWord + blockWord2 + "\r"; fw.write(sOutput, 0, sOutput.length()); } else { int iWord = (int)( (byteA << 8) + (byteB ) ); sOutput = "WORD VALUE : " + iWord + "\r"; fw.write(sOutput, 0, sOutput.length()); iWord = (int)( (byteC << 8) + (byteD ) ); sOutput = "WORD VALUE : " + iWord + "\r"; fw.write(sOutput, 0, sOutput.length()); } } else if(blockWord.equals("UV")) { byte byteC = bData[iPlace++]; byte byteD = bData[iPlace++]; String blockWord2 = "" + (char)byteC + (char)byteD; if(blockWord2.equals("LT")) { sOutput = "====================\rINSTRUMENT BLOCK\r====================\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "--------------------\rINSTRUMENT HEAD BLOCK\r--------------------\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "GROUP HEAD : " + blockWord + blockWord2 + "\r"; fw.write(sOutput, 0, sOutput.length()); int iWord = 0; for(int i = 0; i < 11; i++) { iWord = (int)( ((bData[iPlace++]) << 8) + ((bData[iPlace++]) ) ); sOutput = "SUB WORD " + (i+1) + " : " + iWord + "\r"; fw.write(sOutput, 0, sOutput.length()); } } else { int iWord = (int)( (byteA << 8) + (byteB ) ); sOutput = "WORD VALUE : " + iWord + "\r"; fw.write(sOutput, 0, sOutput.length()); iWord = (int)( (byteC << 8) + (byteD ) ); sOutput = "WORD VALUE : " + iWord + "\r"; fw.write(sOutput, 0, sOutput.length()); } } else if(blockWord.equals("UI")) { byte byteC = bData[iPlace++]; byte byteD = bData[iPlace++]; String blockWord2 = "" + (char)byteC + (char)byteD; if(blockWord2.equals("ID")) { sOutput = "--------------------\rINDIVIDUAL INSTRUMENT BLOCK\r--------------------\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "INSTR HEAD : " + blockWord + blockWord2 + "\r"; fw.write(sOutput, 0, sOutput.length()); int iVal = (int)( ((bData[iPlace++]) << 24) + ((bData[iPlace++]) << 16) + ((bData[iPlace++]) << 8) + ((bData[iPlace++]) ) ); sOutput = "NAME BYTES : " + iVal + "\r"; fw.write(sOutput, 0, sOutput.length()); sOutput = "INSTR NAME : "; for(int i = 0; i < iVal - 1; i++) { sOutput = sOutput + (char)(bData[iPlace++]); } sOutput = sOutput + "\r"; fw.write(sOutput, 0, sOutput.length()); if(iPlace < filesize - 2) { sOutput = "PAD BYTES : " + bData[iPlace++] + bData[iPlace++] + "\r"; fw.write(sOutput, 0, sOutput.length()); } } else { int iWord = (int)( (byteA << 8) + (byteB ) ); sOutput = "WORD VALUE : " + iWord + "\r"; fw.write(sOutput, 0, sOutput.length()); iWord = (int)( (byteC << 8) + (byteD ) ); sOutput = "WORD VALUE : " + iWord + "\r"; fw.write(sOutput, 0, sOutput.length()); } } else { int iWord = (int)( (byteA << 8) + (byteB ) ); sOutput = "WORD VALUE : " + iWord + "\r"; fw.write(sOutput, 0, sOutput.length()); } } fw.flush(); fw.close(); } // File Write Method -------------------------------------------------------------------> protected static void writeToDMCSFile(String fileData, String outFile) throws IOException { FileOutputStream fos = new FileOutputStream(new File(outFile)); byte FileSizeByte1 = (byte)(fileData.length() & 0xFF); byte FileSizeByte2 = (byte)((fileData.length() >> 8) & 0xFF); byte FileSizeByte3 = (byte)((fileData.length() >> 16) & 0xFF); byte FileSizeByte4 = (byte)((fileData.length() >> 24) & 0xFF); byte[] DMCSFileHeader = new byte[] { FileHeaderFormWord[0], FileHeaderFormWord[1], FileHeaderFormWord[2], FileHeaderFormWord[3], FileSizeByte1, FileSizeByte2, FileSizeByte3, FileSizeByte4, FileHeaderTypeWord[0], FileHeaderTypeWord[1], FileHeaderTypeWord[2], FileHeaderTypeWord[3], FileHeaderOSAMWord[0], FileHeaderOSAMWord[1], FileHeaderOSAMWord[2], FileHeaderOSAMWord[3], FileHeaderTailWord[0], FileHeaderTailWord[1], FileHeaderTailWord[2], FileHeaderTailWord[3] }; fos.write(DMCSFileHeader); /* byte BitmapWidthByte1 = (byte)(IntBitmapWidth & 0xFF); byte BitmapWidthByte2 = (byte)((IntBitmapWidth >> 8) & 0xFF); byte BitmapWidthByte3 = (byte)((IntBitmapWidth >> 16) & 0xFF); byte BitmapWidthByte4 = (byte)((IntBitmapWidth >> 24) & 0xFF); byte BitmapHeightByte1 = (byte)(IntBitmapHeight & 0xFF); byte BitmapHeightByte2 = (byte)((IntBitmapHeight >> 8) & 0xFF); byte BitmapHeightByte3 = (byte)((IntBitmapHeight >> 16) & 0xFF); byte BitmapHeightByte4 = (byte)((IntBitmapHeight >> 24) & 0xFF); byte BitmapImageSizeByte1 = (byte)(IntBitmapSize & 0xFF); byte BitmapImageSizeByte2 = (byte)((IntBitmapSize >> 8) & 0xFF); byte BitmapImageSizeByte3 = (byte)((IntBitmapSize >> 16) & 0xFF); byte BitmapImageSizeByte4 = (byte)((IntBitmapSize >> 24) & 0xFF); byte[] BitmapBodyHeader = new byte[] { InfoHeaderSizeByte1, InfoHeaderSizeByte2, InfoHeaderSizeByte3, InfoHeaderSizeByte4, BitmapWidthByte1, BitmapWidthByte2, BitmapWidthByte3, BitmapWidthByte4, BitmapHeightByte1, BitmapHeightByte2, BitmapHeightByte3, BitmapHeightByte4, BitmapPlanesByte1, BitmapPlanesByte2, BitmapBitCountByte1, BitmapBitCountByte2, BitmapCompressionByte1, BitmapCompressionByte2, BitmapCompressionByte3, BitmapCompressionByte4, BitmapImageSizeByte1, BitmapImageSizeByte2, BitmapImageSizeByte3, BitmapImageSizeByte4, BitmapXPixelsPerMByte1, BitmapXPixelsPerMByte2, BitmapXPixelsPerMByte3, BitmapXPixelsPerMByte4, BitmapYPixelsPerMByte1, BitmapYPixelsPerMByte2, BitmapYPixelsPerMByte3, BitmapYPixelsPerMByte4, BitmapColorsUsedByte1, BitmapColorsUsedByte2, BitmapColorsUsedByte3, BitmapColorsUsedByte4, BitmapColorsImportantByte1, BitmapColorsImportantByte2, BitmapColorsImportantByte3, BitmapColorsImportantByte4 }; fos.write(BitmapBodyHeader); int bodySize = IntBitmapWidth * IntBitmapHeight; int bitPad = 4 - ((IntBitmapWidth * 3) % 4); if(bitPad == 4) { bitPad = 0; } int countRow = 1; int indexRow = bodySize - IntBitmapWidth; int indexLastRow = indexRow; byte[] rgbArray = new byte[3]; for(int i = 0; i < bodySize; i++) { int colorValue = PixelMap[indexRow]; rgbArray[0] = (byte)(colorValue & 0xFF); // red rgbArray[1] = (byte)((colorValue >> 8) & 0xFF); // green rgbArray[2] = (byte)((colorValue >> 16) & 0xFF); // blue fos.write(rgbArray); if(countRow == IntBitmapWidth) { // pad row to 4 bits requirement for(int p = 0; p < bitPad; p++) { fos.write(0x00); } countRow = 1; indexRow = indexLastRow - IntBitmapWidth; indexLastRow = indexRow; } else { countRow++; } indexRow++; } */ fos.flush(); fos.close(); } public static void main(String[] args) { if(args.length < 3) { System.out.println("USAGE : DMCScodec -action input output"); } else { if(args[0].equals("-t")) { try { decode(args[1], args[2]); } catch(Exception e) { System.out.println(e); } } else { System.out.println("action " + args[0] + "not yet supported"); } } } }