/* * ReadTrack.java * Copyright 2001 Michael Castleman, mlc67@columbia.edu * * 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 */ import java.io.*; /** * Reads a chunk from a {@link InputStream} and aids in parsing it if it's * a track. */ final class ReadTrack { /** Little data structure representing a MIDI event */ public static class Event { /** Time since previous event */ public int deltaTime; /** Status byte (indicates type of event) */ public byte status; /** actual data for the event. */ public byte[] data; /** creates a new Event */ public Event(int deltaTime, byte status, byte[] data) { this.deltaTime = deltaTime; this.status = status; this.data = data; } } protected String chunkType; protected byte [] data; private int inPos; private byte lastStatus; /** * Reads a chunk from the stream and makes it ready for parsing. * @throws IOException if there's a problem reading the data. */ public ReadTrack(InputStream in) throws IOException { byte[] b = new byte[4]; in.read(b); chunkType = new String(b); in.read(b); int chunkLen = (((b[0]&0xFF) << 24) | ((b[1]&0xFF) << 16) | ((b[2]&0xFF) << 8) | ((b[3]&0xFF))); System.err.println(chunkType + " " + chunkLen + " (" + b[0] + "," + b[1] + "," + b[2] + "," + b[3] + ")"); data = new byte[chunkLen]; in.read(data); inPos = 0; } /** * Constructs a reader for the specified chunk type and data */ public ReadTrack(String chunkType, byte [] data) { this.data = (byte[])(data.clone()); this.chunkType = chunkType; inPos = 0; } public String toString() { return "ReadTrack " + chunkType + ", " + data.length + " bytes"; } /** * Reads a byte from the buffer */ public byte readByte() { return data[inPos++]; } /** * Reads from the buffer * @param buf A buffer to store data into * @param start Where in the buffer to start storing data * @param len How many bytes to store */ public void read(byte [] buf, int start, int len) { System.arraycopy(data, inPos, buf, start, len); inPos += len; } /** * Reads from the buffer * @param buf The buffer to fill */ public void read(byte [] buf) { read(buf, 0, buf.length); } /** * Reads a variable length value * @see TrackChunk#addVarLen(int) */ public int readVarLen() { int value; byte c; if (((value = readByte()) & 0x80) != 0) { value &= 0x7F; do { value = (value << 7) + ((c = readByte()) & 0x7F); } while ((c & (byte)(0x80)) != 0); } return value; } /** * Pushes back the previously read byte */ public void unReadByte() { inPos--; } /** * Reads a MIDI event * @return an {@link Event} or null if the track is done */ public Event readEvent() { if (this.inPos>= this.data.length) return null; int deltaTime = readVarLen(); byte status = readByte(); if ((status & (byte)(0x80)) == 0) { System.out.println(status + " " + (status&(byte)(0x80)) + " " + lastStatus); System.out.println((status & (byte)(0x80)) == 0); unReadByte(); status = lastStatus; } else { lastStatus = status; } byte [] data = null; if (status == (byte)(0xFF)) { // midi file special stuff byte type = readByte(); int len = readVarLen(); data = new byte[1 + len]; data[0] = type; read(data, 1, len); } else { int len; switch (status & (byte)(0xF0)) { // get 'status nibble' case (byte)(0x80): // note off case (byte)(0x90): // note on case (byte)(0xA0): // after touch case (byte)(0xB0): // controller case (byte)(0xE0): // pitch wheel len = 2; break; case (byte)(0xC0): // program change case (byte)(0xD0): // channel pressure len = 1; break; case (byte)(0xF0): switch (status & (byte)(0x0F)) { // case 0xFF is special and handled above case (byte)(0x00): // System exclusive case (byte)(0x07): // system exclusive continuation len = readVarLen(); break; case (byte)(0x01): // MTC quarter frame case (byte)(0x03): // Song select len = 1; break; case (byte)(0x02): // Song position pointer len = 2; break; case (byte)(0x06): // Tune request case (byte)(0x08): // MIDI clock case (byte)(0x09): // Tick case (byte)(0x0A): // start case (byte)(0x0B): // continue case (byte)(0x0C): // stop case (byte)(0x0E): // active sense len = 0; break; default: throw new RuntimeException("Invalid MIDI byte or broken parser?"); } break; default: throw new RuntimeException("I'm confused"); } data = new byte[len]; read(data); } return new Event(deltaTime, status, data); } }

AltStyle によって変換されたページ (->オリジナル) /