////////////////////////////////////////////////////////////////////////////// // Copyright 2011 Alex Leffelman // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. ////////////////////////////////////////////////////////////////////////////// package com.leff.midi.event.meta; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import com.leff.midi.event.MidiEvent; import com.leff.midi.util.VariableLengthInt; public abstract class MetaEvent extends MidiEvent { protected int mType; protected VariableLengthInt mLength; protected MetaEvent(long tick, long delta, int type, VariableLengthInt length) { super(tick, delta); mType = type & 0xFF; mLength = length; } protected abstract int getEventSize(); @Override public void writeToFile(OutputStream out, boolean writeType) throws IOException { writeToFile(out); } protected void writeToFile(OutputStream out) throws IOException { super.writeToFile(out, true); out.write(0xFF); out.write(mType); } public static MetaEvent parseMetaEvent(long tick, long delta, InputStream in) throws IOException { MetaEventData eventData = new MetaEventData(in); boolean isText = false; switch(eventData.type) { case SEQUENCE_NUMBER: case MIDI_CHANNEL_PREFIX: case END_OF_TRACK: case TEMPO: case SMPTE_OFFSET: case TIME_SIGNATURE: case KEY_SIGNATURE: break; case TEXT_EVENT: case COPYRIGHT_NOTICE: case TRACK_NAME: case INSTRUMENT_NAME: case LYRICS: case MARKER: case CUE_POINT: case SEQUENCER_SPECIFIC: // Not technically text, but follows same // structure default: // Also not technically text, but it should follow isText = true; break; } if(isText) { String text = new String(eventData.data); switch(eventData.type) { case TEXT_EVENT: return new Text(tick, delta, text); case COPYRIGHT_NOTICE: return new CopyrightNotice(tick, delta, text); case TRACK_NAME: return new TrackName(tick, delta, text); case INSTRUMENT_NAME: return new InstrumentName(tick, delta, text); case LYRICS: return new Lyrics(tick, delta, text); case MARKER: return new Marker(tick, delta, text); case CUE_POINT: return new CuePoint(tick, delta, text); case SEQUENCER_SPECIFIC: return new SequencerSpecificEvent(tick, delta, eventData.data); default: return new GenericMetaEvent(tick, delta, eventData); } } switch(eventData.type) { case SEQUENCE_NUMBER: return SequenceNumber.parseSequenceNumber(tick, delta, eventData); case MIDI_CHANNEL_PREFIX: return MidiChannelPrefix.parseMidiChannelPrefix(tick, delta, eventData); case END_OF_TRACK: return new EndOfTrack(tick, delta); case TEMPO: return Tempo.parseTempo(tick, delta, eventData); case SMPTE_OFFSET: return SmpteOffset.parseSmpteOffset(tick, delta, eventData); case TIME_SIGNATURE: return TimeSignature.parseTimeSignature(tick, delta, eventData); case KEY_SIGNATURE: return KeySignature.parseKeySignature(tick, delta, eventData); } System.out.println("Completely broken in MetaEvent.parseMetaEvent()"); return null; } protected static class MetaEventData { public final int type; public final VariableLengthInt length; public final byte[] data; public MetaEventData(InputStream in) throws IOException { type = in.read(); length = new VariableLengthInt(in); data = new byte[length.getValue()]; if(length.getValue() > 0) { in.read(data); } } } public static final int SEQUENCE_NUMBER = 0; public static final int TEXT_EVENT = 1; public static final int COPYRIGHT_NOTICE = 2; public static final int TRACK_NAME = 3; public static final int INSTRUMENT_NAME = 4; public static final int LYRICS = 5; public static final int MARKER = 6; public static final int CUE_POINT = 7; public static final int MIDI_CHANNEL_PREFIX = 0x20; public static final int END_OF_TRACK = 0x2F; public static final int TEMPO = 0x51; public static final int SMPTE_OFFSET = 0x54; public static final int TIME_SIGNATURE = 0x58; public static final int KEY_SIGNATURE = 0x59; public static final int SEQUENCER_SPECIFIC = 0x7F; }