Removed dependency on JME for OggStreamDecoder (use JOrbis
directly). git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@454 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -17,9 +17,9 @@
|
||||
classname="com.jmex.bui.BWindow" classpathref="classpath"/>
|
||||
<echo level="info" message="Have JME-BUI: ${jme-bui.present}"/>
|
||||
|
||||
<available property="jme-sound.present"
|
||||
classname="com.jmex.sound.openAL.SoundSystem" classpathref="classpath"/>
|
||||
<echo level="info" message="Have OpenAL: ${jme-sound.present}"/>
|
||||
<available property="jorbis.present"
|
||||
classname="com.jcraft.jorbis.Info" classpathref="classpath"/>
|
||||
<echo level="info" message="Have JOrbis: ${jorbis.present}"/>
|
||||
|
||||
<available property="jl.present"
|
||||
classname="javazoom.jl.decoder.Decoder" classpathref="classpath"/>
|
||||
@@ -39,7 +39,7 @@
|
||||
<condition property="build.openal">
|
||||
<and>
|
||||
<isset property="lwjgl.present"/>
|
||||
<isset property="jme-sound.present"/>
|
||||
<isset property="jorbis.present"/>
|
||||
<isset property="jl.present"/>
|
||||
</and>
|
||||
</condition>
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
<include name="jme-terrain.jar"/>
|
||||
<include name="jme.jar"/>
|
||||
<include name="jme-bui.jar"/>
|
||||
<include name="jogg-0.0.7.jar"/>
|
||||
<include name="jorbis-0.0.15.jar"/>
|
||||
<include name="jl1.0.jar"/>
|
||||
<!-- ActionScript dependencies -->
|
||||
<include name="naryalib.swc"/>
|
||||
|
||||
@@ -25,43 +25,218 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.lwjgl.openal.AL10;
|
||||
|
||||
import com.jmex.sound.openAL.objects.util.OggInputStream;
|
||||
import com.jcraft.jogg.Packet;
|
||||
import com.jcraft.jogg.Page;
|
||||
import com.jcraft.jogg.StreamState;
|
||||
import com.jcraft.jogg.SyncState;
|
||||
import com.jcraft.jorbis.Block;
|
||||
import com.jcraft.jorbis.Comment;
|
||||
import com.jcraft.jorbis.DspState;
|
||||
import com.jcraft.jorbis.Info;
|
||||
|
||||
/**
|
||||
* Decodes Ogg Vorbis streams.
|
||||
*/
|
||||
public class OggStreamDecoder extends StreamDecoder
|
||||
{
|
||||
|
||||
// documentation inherited
|
||||
public void init (InputStream in)
|
||||
throws IOException
|
||||
{
|
||||
_istream = new OggInputStream(in);
|
||||
_in = in;
|
||||
_sync.init();
|
||||
_info.init();
|
||||
|
||||
// read the first packet "manually" to make sure everything's kosher
|
||||
readChunk();
|
||||
if (_sync.pageout(_page) != 1) {
|
||||
throw new IOException("Input is not an Ogg bitstream.");
|
||||
}
|
||||
_stream.init(_page.serialno());
|
||||
_stream.reset();
|
||||
|
||||
if (_stream.pagein(_page) < 0) {
|
||||
throw new IOException("Error reading first page of Ogg bitstream data.");
|
||||
}
|
||||
if (_stream.packetout(_packet) != 1) {
|
||||
throw new IOException("Error reading initial header packet.");
|
||||
}
|
||||
|
||||
Comment comment = new Comment();
|
||||
comment.init();
|
||||
if (_info.synthesis_headerin(comment, _packet) < 0) {
|
||||
throw new IOException("Ogg bitstream does not contain Vorbis audio data.");
|
||||
}
|
||||
|
||||
// two more packets in header
|
||||
for (int ii = 0; ii < 2; ii++) {
|
||||
if (!readPacket()) {
|
||||
throw new IOException("End of file before reading all Vorbis headers.");
|
||||
}
|
||||
_info.synthesis_headerin(comment, _packet);
|
||||
}
|
||||
_dsp.synthesis_init(_info);
|
||||
_block.init(_dsp);
|
||||
_offsets = new int[_info.channels];
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getFormat ()
|
||||
{
|
||||
return (_istream.getFormat() == OggInputStream.FORMAT_MONO16) ?
|
||||
AL10.AL_FORMAT_MONO16 : AL10.AL_FORMAT_STEREO16;
|
||||
return (_info.channels == 1) ? AL10.AL_FORMAT_MONO16 : AL10.AL_FORMAT_STEREO16;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getFrequency ()
|
||||
{
|
||||
return _istream.getRate();
|
||||
return _info.rate;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int read (ByteBuffer buf)
|
||||
throws IOException
|
||||
{
|
||||
return _istream.read(buf, buf.position(), buf.remaining());
|
||||
ShortBuffer sbuf = buf.asShortBuffer();
|
||||
int channels = _info.channels;
|
||||
int total = 0;
|
||||
while (sbuf.hasRemaining()) {
|
||||
int samples = Math.min(readSamples(), sbuf.remaining() / channels);
|
||||
if (samples == 0) {
|
||||
break;
|
||||
}
|
||||
int length = samples * channels;
|
||||
if (_data.length < length) {
|
||||
_data = new short[length];
|
||||
}
|
||||
short[] data = _data;
|
||||
for (int ii = 0; ii < channels; ii++) {
|
||||
float[] pcm = _pcm[0][ii];
|
||||
int sidx = _offsets[ii], didx = ii;
|
||||
for (int jj = 0; jj < samples; jj++) {
|
||||
float value = Math.min(Math.max(pcm[sidx], -1f), +1f);
|
||||
data[didx] = (short)(value * 32767f);
|
||||
sidx++;
|
||||
didx += channels;
|
||||
}
|
||||
}
|
||||
sbuf.put(_data, 0, length);
|
||||
_dsp.synthesis_read(samples);
|
||||
total += (length * 2);
|
||||
}
|
||||
buf.position(buf.position() + total);
|
||||
return total;
|
||||
}
|
||||
|
||||
/** The underlying Ogg input stream. */
|
||||
protected OggInputStream _istream;
|
||||
/**
|
||||
* Reads a buffer's worth of samples.
|
||||
*
|
||||
* @return the number of samples read, or zero if we've reached the end of the stream.
|
||||
*/
|
||||
protected int readSamples ()
|
||||
throws IOException
|
||||
{
|
||||
int samples;
|
||||
while ((samples = _dsp.synthesis_pcmout(_pcm, _offsets)) <= 0) {
|
||||
if (samples == 0 && !readPacket()) {
|
||||
return 0;
|
||||
}
|
||||
if (_block.synthesis(_packet) == 0) {
|
||||
_dsp.synthesis_blockin(_block);
|
||||
}
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a packet.
|
||||
*
|
||||
* @return true if a packet was read, false if we've reached the end of the stream.
|
||||
*/
|
||||
protected boolean readPacket ()
|
||||
throws IOException
|
||||
{
|
||||
int result;
|
||||
while ((result = _stream.packetout(_packet)) != 1) {
|
||||
if (result == 0 && !readPage()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in a page.
|
||||
*
|
||||
* @return true if a page was read, false if we've reached the end of the stream.
|
||||
*/
|
||||
protected boolean readPage ()
|
||||
throws IOException
|
||||
{
|
||||
int result;
|
||||
while ((result = _sync.pageout(_page)) != 1) {
|
||||
if (result == 0 && !readChunk()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_stream.pagein(_page);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in a chunk of data from the underlying input stream.
|
||||
*
|
||||
* @return true if a chunk was read, false if we've reached the end of the stream.
|
||||
*/
|
||||
protected boolean readChunk ()
|
||||
throws IOException
|
||||
{
|
||||
int offset = _sync.buffer(BUFFER_SIZE);
|
||||
int bytes = _in.read(_sync.data, offset, BUFFER_SIZE);
|
||||
if (bytes > 0) {
|
||||
_sync.wrote(bytes);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** The underlying input stream. */
|
||||
protected InputStream _in;
|
||||
|
||||
/** The sync state. */
|
||||
protected SyncState _sync = new SyncState();
|
||||
|
||||
/** The stream state. */
|
||||
protected StreamState _stream = new StreamState();
|
||||
|
||||
/** The output page. */
|
||||
protected Page _page = new Page();
|
||||
|
||||
/** The output packet. */
|
||||
protected Packet _packet = new Packet();
|
||||
|
||||
/** The stream info. */
|
||||
protected Info _info = new Info();
|
||||
|
||||
/** The DSP state. */
|
||||
protected DspState _dsp = new DspState();
|
||||
|
||||
/** The output block. */
|
||||
protected Block _block = new Block(_dsp);
|
||||
|
||||
/** Holds the decoded PCM data buffers. */
|
||||
protected float[][][] _pcm = new float[1][][];
|
||||
|
||||
/** The DSP offsets for each channel. */
|
||||
protected int[] _offsets;
|
||||
|
||||
/** Intermediate storage for converted data. */
|
||||
protected short[] _data = new short[0];
|
||||
|
||||
/** The decode buffer size. */
|
||||
protected static final int BUFFER_SIZE = 4096 * 2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user