219 lines
8.0 KiB
Java
219 lines
8.0 KiB
Java
/*
|
|
* Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code 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
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package com.sun.media.sound;
|
|
|
|
import java.io.File;
|
|
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.MidiMessage;
|
|
import javax.sound.midi.MidiSystem;
|
|
import javax.sound.midi.MidiUnavailableException;
|
|
import javax.sound.midi.Receiver;
|
|
import javax.sound.midi.Sequence;
|
|
import javax.sound.midi.Track;
|
|
import javax.sound.sampled.AudioFileFormat;
|
|
import javax.sound.sampled.AudioFileFormat.Type;
|
|
import javax.sound.sampled.AudioFormat;
|
|
import javax.sound.sampled.AudioInputStream;
|
|
import javax.sound.sampled.UnsupportedAudioFileException;
|
|
import javax.sound.sampled.spi.AudioFileReader;
|
|
|
|
/**
|
|
* MIDI File Audio Renderer/Reader.
|
|
*
|
|
* @author Karl Helgason
|
|
*/
|
|
public final class SoftMidiAudioFileReader extends AudioFileReader {
|
|
|
|
public static final Type MIDI = new Type("MIDI", "mid");
|
|
private static AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
|
|
|
|
public AudioFileFormat getAudioFileFormat(Sequence seq)
|
|
throws UnsupportedAudioFileException, IOException {
|
|
|
|
long totallen = seq.getMicrosecondLength() / 1000000;
|
|
long len = (long) (format.getFrameRate() * (totallen + 4));
|
|
return new AudioFileFormat(MIDI, format, (int) len);
|
|
}
|
|
|
|
public AudioInputStream getAudioInputStream(Sequence seq)
|
|
throws UnsupportedAudioFileException, IOException {
|
|
AudioSynthesizer synth = (AudioSynthesizer) new SoftSynthesizer();
|
|
AudioInputStream stream;
|
|
Receiver recv;
|
|
try {
|
|
stream = synth.openStream(format, null);
|
|
recv = synth.getReceiver();
|
|
} catch (MidiUnavailableException e) {
|
|
throw new IOException(e.toString());
|
|
}
|
|
float divtype = seq.getDivisionType();
|
|
Track[] tracks = seq.getTracks();
|
|
int[] trackspos = new int[tracks.length];
|
|
int mpq = 500000;
|
|
int seqres = seq.getResolution();
|
|
long lasttick = 0;
|
|
long curtime = 0;
|
|
while (true) {
|
|
MidiEvent selevent = null;
|
|
int seltrack = -1;
|
|
for (int i = 0; i < tracks.length; i++) {
|
|
int trackpos = trackspos[i];
|
|
Track track = tracks[i];
|
|
if (trackpos < track.size()) {
|
|
MidiEvent event = track.get(trackpos);
|
|
if (selevent == null || event.getTick() < selevent.getTick()) {
|
|
selevent = event;
|
|
seltrack = i;
|
|
}
|
|
}
|
|
}
|
|
if (seltrack == -1)
|
|
break;
|
|
trackspos[seltrack]++;
|
|
long tick = selevent.getTick();
|
|
if (divtype == Sequence.PPQ)
|
|
curtime += ((tick - lasttick) * mpq) / seqres;
|
|
else
|
|
curtime = (long) ((tick * 1000000.0 * divtype) / seqres);
|
|
lasttick = tick;
|
|
MidiMessage msg = selevent.getMessage();
|
|
if (msg instanceof MetaMessage) {
|
|
if (divtype == Sequence.PPQ) {
|
|
if (((MetaMessage) msg).getType() == 0x51) {
|
|
byte[] data = ((MetaMessage) msg).getData();
|
|
if (data.length < 3) {
|
|
throw new UnsupportedAudioFileException();
|
|
}
|
|
mpq = ((data[0] & 0xff) << 16)
|
|
| ((data[1] & 0xff) << 8) | (data[2] & 0xff);
|
|
}
|
|
}
|
|
} else {
|
|
recv.send(msg, curtime);
|
|
}
|
|
}
|
|
|
|
long totallen = curtime / 1000000;
|
|
long len = (long) (stream.getFormat().getFrameRate() * (totallen + 4));
|
|
stream = new AudioInputStream(stream, stream.getFormat(), len);
|
|
return stream;
|
|
}
|
|
|
|
public AudioInputStream getAudioInputStream(InputStream inputstream)
|
|
throws UnsupportedAudioFileException, IOException {
|
|
|
|
inputstream.mark(200);
|
|
Sequence seq;
|
|
try {
|
|
seq = MidiSystem.getSequence(inputstream);
|
|
} catch (InvalidMidiDataException e) {
|
|
inputstream.reset();
|
|
throw new UnsupportedAudioFileException();
|
|
} catch (IOException e) {
|
|
inputstream.reset();
|
|
throw new UnsupportedAudioFileException();
|
|
}
|
|
return getAudioInputStream(seq);
|
|
}
|
|
|
|
public AudioFileFormat getAudioFileFormat(URL url)
|
|
throws UnsupportedAudioFileException, IOException {
|
|
Sequence seq;
|
|
try {
|
|
seq = MidiSystem.getSequence(url);
|
|
} catch (InvalidMidiDataException e) {
|
|
throw new UnsupportedAudioFileException();
|
|
} catch (IOException e) {
|
|
throw new UnsupportedAudioFileException();
|
|
}
|
|
return getAudioFileFormat(seq);
|
|
}
|
|
|
|
public AudioFileFormat getAudioFileFormat(File file)
|
|
throws UnsupportedAudioFileException, IOException {
|
|
Sequence seq;
|
|
try {
|
|
seq = MidiSystem.getSequence(file);
|
|
} catch (InvalidMidiDataException e) {
|
|
throw new UnsupportedAudioFileException();
|
|
} catch (IOException e) {
|
|
throw new UnsupportedAudioFileException();
|
|
}
|
|
return getAudioFileFormat(seq);
|
|
}
|
|
|
|
public AudioInputStream getAudioInputStream(URL url)
|
|
throws UnsupportedAudioFileException, IOException {
|
|
Sequence seq;
|
|
try {
|
|
seq = MidiSystem.getSequence(url);
|
|
} catch (InvalidMidiDataException e) {
|
|
throw new UnsupportedAudioFileException();
|
|
} catch (IOException e) {
|
|
throw new UnsupportedAudioFileException();
|
|
}
|
|
return getAudioInputStream(seq);
|
|
}
|
|
|
|
public AudioInputStream getAudioInputStream(File file)
|
|
throws UnsupportedAudioFileException, IOException {
|
|
if (!file.getName().toLowerCase().endsWith(".mid"))
|
|
throw new UnsupportedAudioFileException();
|
|
Sequence seq;
|
|
try {
|
|
seq = MidiSystem.getSequence(file);
|
|
} catch (InvalidMidiDataException e) {
|
|
throw new UnsupportedAudioFileException();
|
|
} catch (IOException e) {
|
|
throw new UnsupportedAudioFileException();
|
|
}
|
|
return getAudioInputStream(seq);
|
|
}
|
|
|
|
public AudioFileFormat getAudioFileFormat(InputStream inputstream)
|
|
throws UnsupportedAudioFileException, IOException {
|
|
|
|
inputstream.mark(200);
|
|
Sequence seq;
|
|
try {
|
|
seq = MidiSystem.getSequence(inputstream);
|
|
} catch (InvalidMidiDataException e) {
|
|
inputstream.reset();
|
|
throw new UnsupportedAudioFileException();
|
|
} catch (IOException e) {
|
|
inputstream.reset();
|
|
throw new UnsupportedAudioFileException();
|
|
}
|
|
return getAudioFileFormat(seq);
|
|
}
|
|
}
|