/* * Copyright (C) 2014 michidk && xxmicloxx * http://dev.bukkit.org/bukkit-plugins/noteblockapi/ * * 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 3 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, see <http://www.gnu.org/licenses/>. */ package me.eccentric_nz.TARDIS.noteblock; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; public class NBSDecoder { public static Song parse(File decodeFile) { try { return parse(new FileInputStream(decodeFile), decodeFile); } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } public static Song parse(InputStream inputStream) { return parse(inputStream, null); // Source is unknown -> no file } private static Song parse(InputStream inputStream, File decodeFile) { HashMap<Integer, Layer> layerHashMap = new HashMap<Integer, Layer>(); try { DataInputStream dis = new DataInputStream(inputStream); short length = readShort(dis); short songHeight = readShort(dis); String title = readString(dis); String author = readString(dis); readString(dis); String description = readString(dis); float speed = readShort(dis) / 100f; dis.readBoolean(); // auto-save dis.readByte(); // auto-save duration dis.readByte(); // x/4ths, time signature readInt(dis); // minutes spent on project readInt(dis); // left clicks (why?) readInt(dis); // right clicks (why?) readInt(dis); // blocks added readInt(dis); // blocks removed readString(dis); // .mid/.schematic file name short tick = -1; while (true) { short jumpTicks = readShort(dis); // jumps till next tick if (jumpTicks == 0) { break; } tick += jumpTicks; short layer = -1; while (true) { short jumpLayers = readShort(dis); // jumps till next layer if (jumpLayers == 0) { break; } layer += jumpLayers; setNote(layer, tick, dis.readByte() /* instrument */, dis.readByte() /* note */, layerHashMap); } } for (int i = 0; i < songHeight; i++) { Layer l = layerHashMap.get(i); if (l != null) { l.setName(readString(dis)); l.setVolume(dis.readByte()); } } return new Song(speed, layerHashMap, songHeight, length, title, author, description, decodeFile); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } private static void setNote(int layer, int ticks, byte instrument, byte key, HashMap<Integer, Layer> layerHashMap) { Layer l = layerHashMap.get(layer); if (l == null) { l = new Layer(); layerHashMap.put(layer, l); } l.setNote(ticks, new Note(instrument, key)); } private static short readShort(DataInputStream dis) throws IOException { int byte1 = dis.readUnsignedByte(); int byte2 = dis.readUnsignedByte(); return (short) (byte1 + (byte2 << 8)); } private static int readInt(DataInputStream dis) throws IOException { int byte1 = dis.readUnsignedByte(); int byte2 = dis.readUnsignedByte(); int byte3 = dis.readUnsignedByte(); int byte4 = dis.readUnsignedByte(); return (byte1 + (byte2 << 8) + (byte3 << 16) + (byte4 << 24)); } private static String readString(DataInputStream dis) throws IOException { int length = readInt(dis); StringBuilder sb = new StringBuilder(length); for (; length > 0; --length) { char c = (char) dis.readByte(); if (c == (char) 0x0D) { c = ' '; } sb.append(c); } return sb.toString(); } }