⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 standardmidifilereader.java

📁 linux下建立JAVA虚拟机的源码KAFFE
💻 JAVA
字号:
/* *	StandardMidiFileReader.java *//* *  Copyright (c) 1999, 2000 by Matthias Pfisterer <Matthias.Pfisterer@gmx.de> * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU Library 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 Library General Public License for more details. * *   You should have received a copy of the GNU Library General Public *   License along with this program; if not, write to the Free Software *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */package	org.tritonus.midi.file;import java.io.DataInputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.net.URL;import javax.sound.midi.InvalidMidiDataException;import javax.sound.midi.MetaMessage;import javax.sound.midi.MidiEvent;import javax.sound.midi.MidiFileFormat;import javax.sound.midi.MidiMessage;import javax.sound.midi.Sequence;import javax.sound.midi.ShortMessage;import javax.sound.midi.SysexMessage;import javax.sound.midi.Track;import javax.sound.midi.spi.MidiFileReader;import org.tritonus.share.TDebug;import org.tritonus.share.midi.TMidiFileFormat;/**	TODO: */public class StandardMidiFileReaderextends MidiFileReader{	/**	TODO:	 */	public static boolean		CANCEL_RUNNING_STATUS_ON_META_AND_SYSEX = true;	private static final int	STATUS_NONE = 0;	private static final int	STATUS_ONE_BYTE = 1;	private static final int	STATUS_TWO_BYTES = 2;	private static final int	STATUS_SYSEX = 3;	private static final int	STATUS_META = 4;	/**	TODO:	 */	public MidiFileFormat getMidiFileFormat(InputStream inputStream)		throws InvalidMidiDataException, IOException	{		DataInputStream		dataInputStream = new DataInputStream(inputStream);		int	nHeaderMagic = dataInputStream.readInt();		if (nHeaderMagic != MidiConstants.HEADER_MAGIC)		{			throw new InvalidMidiDataException("not a MIDI file: wrong header magic");		}		int	nHeaderLength = dataInputStream.readInt();		if (nHeaderLength < 6)		{			throw new InvalidMidiDataException("corrupt MIDI file: wrong header length");		}		int	nType = dataInputStream.readShort();		if (nType < 0 || nType > 2)		{			throw new InvalidMidiDataException("corrupt MIDI file: illegal type");		}		if (nType == 2)		{			throw new InvalidMidiDataException("this implementation doesn't support type 2 MIDI files");		}		int	nNumTracks = dataInputStream.readShort();		if (nNumTracks <= 0)		{			throw new InvalidMidiDataException("corrupt MIDI file: number of tracks must be positive");		}		if (nType == 0 && nNumTracks != 1)		{			throw new InvalidMidiDataException("corrupt MIDI file:  type 0 files must contain exactely one track");		}		int	nDivision = dataInputStream.readUnsignedShort();		float	fDivisionType = -1.0F;		int	nResolution = -1;		if ((nDivision & 0x8000) != 0)	//frame division		{			// TODO:			int	nFrameType = -((nDivision >>> 8) & 0xFF);			switch (nFrameType)			{			case 24:				fDivisionType = Sequence.SMPTE_24;				break;			case 25:				fDivisionType = Sequence.SMPTE_25;				break;			case 29:				fDivisionType = Sequence.SMPTE_30DROP;				break;			case 30:				fDivisionType = Sequence.SMPTE_30;				break;			default:				throw new InvalidMidiDataException("corrupt MIDI file: illegal frame division type");			}			nResolution = nDivision & 0xff;		}		else				// BPM division		{			fDivisionType = Sequence.PPQ;			nResolution = nDivision & 0x7fff;		}		// skip additional bytes in the header		dataInputStream.skip(nHeaderLength - 6);		MidiFileFormat	midiFileFormat = new TMidiFileFormat(			nType,			fDivisionType,			nResolution,			MidiFileFormat.UNKNOWN_LENGTH,			MidiFileFormat.UNKNOWN_LENGTH,			nNumTracks);		return midiFileFormat;	}	/**	TODO:	 */	public MidiFileFormat getMidiFileFormat(URL url)		throws	InvalidMidiDataException, IOException	{		InputStream	inputStream = url.openStream();		try		{			return getMidiFileFormat(inputStream);		}		finally		{			inputStream.close();		}	}	/**	TODO:	 */	public MidiFileFormat getMidiFileFormat(File file)		throws	InvalidMidiDataException, IOException	{		InputStream	inputStream = new FileInputStream(file);		//inputStream = new BufferedInputStream(inputStream, 1024);		try		{			return getMidiFileFormat(inputStream);		}		finally		{			inputStream.close();		}	}	/**	TODO:	 */	public Sequence getSequence(URL url)		throws	InvalidMidiDataException, IOException	{		InputStream	inputStream = url.openStream();		try		{			return getSequence(inputStream);		}		catch (InvalidMidiDataException e)		{			if (TDebug.TraceAllExceptions)			{				TDebug.out(e);			}			inputStream.close();			throw e;		}		catch (IOException e)		{			if (TDebug.TraceAllExceptions)			{				TDebug.out(e);			}			inputStream.close();			throw e;		}	}	/**	TODO:	 */	public Sequence getSequence(File file)		throws	InvalidMidiDataException, IOException	{		InputStream	inputStream = new FileInputStream(file);		// inputStream = new BufferedInputStream(inputStream, 1024);		try		{			return getSequence(inputStream);		}		catch (InvalidMidiDataException e)		{			if (TDebug.TraceAllExceptions)			{				TDebug.out(e);			}			inputStream.close();			throw e;		}		catch (IOException e)		{			if (TDebug.TraceAllExceptions)			{				TDebug.out(e);			}			inputStream.close();			throw e;		}	}	/**	TODO:	 */	public Sequence getSequence(InputStream inputStream)		throws	InvalidMidiDataException, IOException	{		MidiFileFormat	midiFileFormat = getMidiFileFormat(inputStream);		Sequence	sequence = new Sequence(			midiFileFormat.getDivisionType(),			midiFileFormat.getResolution());		DataInputStream		dataInputStream = new DataInputStream(inputStream);		int	nNumTracks = ((TMidiFileFormat) midiFileFormat).getTrackCount();		for (int nTrack = 0; nTrack < nNumTracks; nTrack++)		{			Track	track = sequence.createTrack();			readTrack(dataInputStream, track);		}		return sequence;	}	/**	TODO:	 */	private void readTrack(DataInputStream dataInputStream, Track track)		throws	InvalidMidiDataException, IOException	{		// search for a "MTrk" chunk		while (true)		{			int	nMagic = dataInputStream.readInt();			if (nMagic == MidiConstants.TRACK_MAGIC)			{				break;			}			int	nChunkLength = dataInputStream.readInt();			if (nChunkLength % 2 != 0)			{				nChunkLength++;			}			dataInputStream.skip(nChunkLength);		}		int	nTrackChunkLength = dataInputStream.readInt();		long	lTicks = 0;		long[]	alRemainingBytes = new long[1];		alRemainingBytes[0] = nTrackChunkLength;		int[]	anRunningStatusByte = new int[1];		// indicates no running status in effect		anRunningStatusByte[0] = -1;		while (alRemainingBytes[0] > 0)		{			long	lDeltaTicks = readVariableLengthQuantity(dataInputStream, alRemainingBytes);			// TDebug.out("delta ticks: " + lDeltaTicks);			lTicks += lDeltaTicks;			MidiEvent	event = readEvent(dataInputStream, alRemainingBytes, anRunningStatusByte, lTicks);			track.add(event);		}	}	/**	TODO:	 */	private static MidiEvent readEvent(DataInputStream dataInputStream, long[] alRemainingBytes, int[] anRunningStatusByte, long lTicks)		throws	InvalidMidiDataException, IOException	{		int	nStatusByte = readUnsignedByte(dataInputStream, alRemainingBytes);		// TDebug.out("status byte: " + nStatusByte);		MidiMessage	message = null;		boolean		bRunningStatusApplies = false;		int		nSavedByte = 0;		if (nStatusByte < 0x80)		{			if (anRunningStatusByte[0] != -1)			{				bRunningStatusApplies = true;				nSavedByte = nStatusByte;				nStatusByte = anRunningStatusByte[0];			}			else			{				throw new InvalidMidiDataException("corrupt MIDI file: status byte missing");			}		}		switch (getType(nStatusByte))		{		case STATUS_ONE_BYTE:			int	nByte = 0;			if (bRunningStatusApplies)			{				nByte = nSavedByte;			}			else			{				nByte = readUnsignedByte(dataInputStream, alRemainingBytes);				anRunningStatusByte[0] = nStatusByte;			}			ShortMessage	shortMessage1 = new ShortMessage();			shortMessage1.setMessage(nStatusByte, nByte, 0);			message = shortMessage1;			break;		case STATUS_TWO_BYTES:			int	nByte1 = 0;			if (bRunningStatusApplies)			{				nByte1 = nSavedByte;			}			else			{				nByte1 = readUnsignedByte(dataInputStream, alRemainingBytes);				anRunningStatusByte[0] = nStatusByte;			}			int	nByte2 = readUnsignedByte(dataInputStream, alRemainingBytes);			ShortMessage	shortMessage2 = new ShortMessage();			shortMessage2.setMessage(nStatusByte, nByte1, nByte2);			message = shortMessage2;			break;		case STATUS_SYSEX:			if (CANCEL_RUNNING_STATUS_ON_META_AND_SYSEX)			{				anRunningStatusByte[0] = -1;			}			int	nSysexDataLength = (int) readVariableLengthQuantity(dataInputStream, alRemainingBytes);			byte[]	abSysexData = new byte[nSysexDataLength];			for (int i = 0; i < nSysexDataLength; i++)			{				int	nDataByte = readUnsignedByte(dataInputStream, alRemainingBytes);				abSysexData[i] = (byte) nDataByte;			}			SysexMessage	sysexMessage = new SysexMessage();			sysexMessage.setMessage(nStatusByte, abSysexData, nSysexDataLength);			message = sysexMessage;			break;		case STATUS_META:			if (CANCEL_RUNNING_STATUS_ON_META_AND_SYSEX)			{				anRunningStatusByte[0] = -1;			}			int	nTypeByte = readUnsignedByte(dataInputStream, alRemainingBytes);			int	nMetaDataLength = (int) readVariableLengthQuantity(dataInputStream, alRemainingBytes);			byte[]	abMetaData = new byte[nMetaDataLength];			for (int i = 0; i < nMetaDataLength; i++)			{				int	nDataByte = readUnsignedByte(dataInputStream, alRemainingBytes);				abMetaData[i] = (byte) nDataByte;			}			MetaMessage	metaMessage = new MetaMessage();			metaMessage.setMessage(nTypeByte, abMetaData, nMetaDataLength);			message = metaMessage;			break;		default:		}		MidiEvent	event = new MidiEvent(message, lTicks);		return event;	}	// TODO: use table	/**	TODO:	 */	private static int getType(int nStatusByte)	{		if (nStatusByte < 0xf0)	// channel voice or mode command		{			int	nCommand = nStatusByte & 0xf0;			switch (nCommand)			{			case 0x80:	// note off			case 0x90:	// note on			case 0xa0:	// polyphonic key pressure			case 0xb0:	// control change			case 0xe0:	// pitch wheel change				return STATUS_TWO_BYTES;			case 0xc0:	// program change			case 0xd0:	// channel pressure				return STATUS_ONE_BYTE;			default:				return STATUS_NONE;			}		}		else if (nStatusByte == 0xf0 || nStatusByte == 0xf7)		{			return STATUS_SYSEX;		}		else if (nStatusByte == 0xff)		{			return STATUS_META;		}		else		{			return STATUS_NONE;		}	}	/**	TODO:	 */	public static long readVariableLengthQuantity(DataInputStream dataInputStream, long[] alRemainingBytes)		throws	InvalidMidiDataException, IOException	{		long	lValue = 0;		int	nByteCount = 0;		while (nByteCount < 4)		{			int	nByte = readUnsignedByte(dataInputStream, alRemainingBytes);			nByteCount++;			lValue <<= 7;			lValue |= (nByte & 0x7f);			if (nByte < 128)	// MSB is 0: last byte			{				return lValue;			}		}		throw new InvalidMidiDataException("not a MIDI file: unterminated variable-length quantity");	}	/**	TODO:	 */	public static int readUnsignedByte(DataInputStream dataInputStream, long[] alRemainingBytes)		throws	IOException	{		int	nByte = dataInputStream.readUnsignedByte();// already done in DataInputStream.readUnsignedByte();// 		if (nByte < 0)// 		{// 			throw new EOFException();// 		}		alRemainingBytes[0]--;		return nByte;	}}/*** StandardMidiFileReader.java ***/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -