////////////////////////////////////////////////////////////////////////////// // 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; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; public class ChannelEvent extends MidiEvent { protected int mType; protected int mChannel; protected int mValue1; protected int mValue2; private static HashMap<Integer, Integer> mOrderMap; protected ChannelEvent(long tick, int type, int channel, int param1, int param2) { this(tick, 0, type, channel, param1, param2); } protected ChannelEvent(long tick, long delta, int type, int channel, int param1, int param2) { super(tick, delta); mType = type & 0x0F; mChannel = channel & 0x0F; mValue1 = param1 & 0xFF; mValue2 = param2 & 0xFF; } public int getType() { return mType; } public void setChannel(int c) { if(c < 0) { c = 0; } else if(c > 15) { c = 15; } mChannel = c; } public int getChannel() { return mChannel; } protected int getEventSize() { switch(mType) { case PROGRAM_CHANGE: case CHANNEL_AFTERTOUCH: return 2; default: return 3; } } @Override public int compareTo(MidiEvent other) { if(mTick != other.getTick()) { return mTick < other.getTick() ? -1 : 1; } if(mDelta.getValue() != other.mDelta.getValue()) { return mDelta.getValue() < other.mDelta.getValue() ? 1 : -1; } if(!(other instanceof ChannelEvent)) { return 1; } ChannelEvent o = (ChannelEvent) other; if(mType != o.getType()) { if(mOrderMap == null) { buildOrderMap(); } int order1 = mOrderMap.get(mType); int order2 = mOrderMap.get(o.getType()); return order1 < order2 ? -1 : 1; } if(mValue1 != o.mValue1) { return mValue1 < o.mValue1 ? -1 : 1; } if(mValue2 != o.mValue2) { return mValue2 < o.mValue2 ? -1 : 1; } if(mChannel != o.getChannel()) { return mChannel < o.getChannel() ? -1 : 1; } return 0; } @Override public boolean requiresStatusByte(MidiEvent prevEvent) { if(prevEvent == null) { return true; } if(!(prevEvent instanceof ChannelEvent)) { return true; } ChannelEvent ce = (ChannelEvent) prevEvent; return !(mType == ce.getType() && mChannel == ce.getChannel()); } @Override public void writeToFile(OutputStream out, boolean writeType) throws IOException { super.writeToFile(out, writeType); if(writeType) { int typeChannel = (mType << 4) + mChannel; out.write(typeChannel); } out.write(mValue1); if(mType != PROGRAM_CHANGE && mType != CHANNEL_AFTERTOUCH) { out.write(mValue2); } } public static ChannelEvent parseChannelEvent(long tick, long delta, int type, int channel, InputStream in) throws IOException { int val1 = in.read(); int val2 = 0; if(type != PROGRAM_CHANGE && type != CHANNEL_AFTERTOUCH) { val2 = in.read(); } switch(type) { case NOTE_OFF: return new NoteOff(tick, delta, channel, val1, val2); case NOTE_ON: return new NoteOn(tick, delta, channel, val1, val2); case NOTE_AFTERTOUCH: return new NoteAftertouch(tick, delta, channel, val1, val2); case CONTROLLER: return new Controller(tick, delta, channel, val1, val2); case PROGRAM_CHANGE: return new ProgramChange(tick, delta, channel, val1); case CHANNEL_AFTERTOUCH: return new ChannelAftertouch(tick, delta, channel, val1); case PITCH_BEND: return new PitchBend(tick, delta, channel, val1, val2); default: return new ChannelEvent(tick, delta, type, channel, val1, val2); } } private static void buildOrderMap() { mOrderMap = new HashMap<Integer, Integer>(); mOrderMap.put(PROGRAM_CHANGE, 0); mOrderMap.put(CONTROLLER, 1); mOrderMap.put(NOTE_ON, 2); mOrderMap.put(NOTE_OFF, 3); mOrderMap.put(NOTE_AFTERTOUCH, 4); mOrderMap.put(CHANNEL_AFTERTOUCH, 5); mOrderMap.put(PITCH_BEND, 6); } public static final int NOTE_OFF = 0x8; public static final int NOTE_ON = 0x9; public static final int NOTE_AFTERTOUCH = 0xA; public static final int CONTROLLER = 0xB; public static final int PROGRAM_CHANGE = 0xC; public static final int CHANNEL_AFTERTOUCH = 0xD; public static final int PITCH_BEND = 0xE; }