////////////////////////////////////////////////////////////////////////////// // 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; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import com.leff.midi.util.MidiUtil; public class MidiFile { public static final int HEADER_SIZE = 14; public static final byte[] IDENTIFIER = { 'M', 'T', 'h', 'd' }; public static final int DEFAULT_RESOLUTION = 480; private int mType; private int mTrackCount; private int mResolution; private ArrayList<MidiTrack> mTracks; public MidiFile() { this(DEFAULT_RESOLUTION); } public MidiFile(int resolution) { this(resolution, new ArrayList<MidiTrack>()); } public MidiFile(int resolution, ArrayList<MidiTrack> tracks) { mResolution = resolution >= 0 ? resolution : DEFAULT_RESOLUTION; mTracks = tracks != null ? tracks : new ArrayList<MidiTrack>(); mTrackCount = tracks.size(); mType = mTrackCount > 1 ? 1 : 0; } public MidiFile(File fileIn) throws FileNotFoundException, IOException { this(new FileInputStream(fileIn)); } public MidiFile(InputStream rawIn) throws IOException { BufferedInputStream in = new BufferedInputStream(rawIn); byte[] buffer = new byte[HEADER_SIZE]; in.read(buffer); initFromBuffer(buffer); mTracks = new ArrayList<MidiTrack>(); for(int i = 0; i < mTrackCount; i++) { mTracks.add(new MidiTrack(in)); } } public void setType(int type) { if(type < 0) { type = 0; } else if(type > 2) { type = 1; } else if(type == 0 && mTrackCount > 1) { type = 1; } mType = type; } public int getType() { return mType; } public int getTrackCount() { return mTrackCount; } public void setResolution(int res) { if(res >= 0) { mResolution = res; } } public int getResolution() { return mResolution; } public long getLengthInTicks() { long length = 0; for(MidiTrack T : mTracks) { long l = T.getLengthInTicks(); if(l > length) { length = l; } } return length; } public ArrayList<MidiTrack> getTracks() { return mTracks; } public void addTrack(MidiTrack T) { addTrack(T, mTracks.size()); } public void addTrack(MidiTrack T, int pos) { if(pos > mTracks.size()) { pos = mTracks.size(); } else if(pos < 0) { pos = 0; } mTracks.add(pos, T); mTrackCount = mTracks.size(); mType = mTrackCount > 1 ? 1 : 0; } public void removeTrack(int pos) { if(pos < 0 || pos >= mTracks.size()) { return; } mTracks.remove(pos); mTrackCount = mTracks.size(); mType = mTrackCount > 1 ? 1 : 0; } public void writeToFile(File outFile) throws FileNotFoundException, IOException { FileOutputStream fout = new FileOutputStream(outFile); fout.write(IDENTIFIER); fout.write(MidiUtil.intToBytes(6, 4)); fout.write(MidiUtil.intToBytes(mType, 2)); fout.write(MidiUtil.intToBytes(mTrackCount, 2)); fout.write(MidiUtil.intToBytes(mResolution, 2)); for(MidiTrack T : mTracks) { T.writeToFile(fout); } fout.flush(); fout.close(); } private void initFromBuffer(byte[] buffer) { if(!MidiUtil.bytesEqual(buffer, IDENTIFIER, 0, 4)) { System.out.println("File identifier not MThd. Exiting"); mType = 0; mTrackCount = 0; mResolution = DEFAULT_RESOLUTION; return; } mType = MidiUtil.bytesToInt(buffer, 8, 2); mTrackCount = MidiUtil.bytesToInt(buffer, 10, 2); mResolution = MidiUtil.bytesToInt(buffer, 12, 2); } }