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:
Andrzej Kapolka
2008-03-21 02:00:20 +00:00
parent aaaebc4a2f
commit fcb5fa200c
3 changed files with 189 additions and 12 deletions
+4 -4
View File
@@ -17,9 +17,9 @@
classname="com.jmex.bui.BWindow" classpathref="classpath"/> classname="com.jmex.bui.BWindow" classpathref="classpath"/>
<echo level="info" message="Have JME-BUI: ${jme-bui.present}"/> <echo level="info" message="Have JME-BUI: ${jme-bui.present}"/>
<available property="jme-sound.present" <available property="jorbis.present"
classname="com.jmex.sound.openAL.SoundSystem" classpathref="classpath"/> classname="com.jcraft.jorbis.Info" classpathref="classpath"/>
<echo level="info" message="Have OpenAL: ${jme-sound.present}"/> <echo level="info" message="Have JOrbis: ${jorbis.present}"/>
<available property="jl.present" <available property="jl.present"
classname="javazoom.jl.decoder.Decoder" classpathref="classpath"/> classname="javazoom.jl.decoder.Decoder" classpathref="classpath"/>
@@ -39,7 +39,7 @@
<condition property="build.openal"> <condition property="build.openal">
<and> <and>
<isset property="lwjgl.present"/> <isset property="lwjgl.present"/>
<isset property="jme-sound.present"/> <isset property="jorbis.present"/>
<isset property="jl.present"/> <isset property="jl.present"/>
</and> </and>
</condition> </condition>
+2
View File
@@ -27,6 +27,8 @@
<include name="jme-terrain.jar"/> <include name="jme-terrain.jar"/>
<include name="jme.jar"/> <include name="jme.jar"/>
<include name="jme-bui.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"/> <include name="jl1.0.jar"/>
<!-- ActionScript dependencies --> <!-- ActionScript dependencies -->
<include name="naryalib.swc"/> <include name="naryalib.swc"/>
@@ -25,43 +25,218 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.openal.AL10; 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. * Decodes Ogg Vorbis streams.
*/ */
public class OggStreamDecoder extends StreamDecoder public class OggStreamDecoder extends StreamDecoder
{ {
// documentation inherited // documentation inherited
public void init (InputStream in) public void init (InputStream in)
throws IOException 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 // documentation inherited
public int getFormat () public int getFormat ()
{ {
return (_istream.getFormat() == OggInputStream.FORMAT_MONO16) ? return (_info.channels == 1) ? AL10.AL_FORMAT_MONO16 : AL10.AL_FORMAT_STEREO16;
AL10.AL_FORMAT_MONO16 : AL10.AL_FORMAT_STEREO16;
} }
// documentation inherited // documentation inherited
public int getFrequency () public int getFrequency ()
{ {
return _istream.getRate(); return _info.rate;
} }
// documentation inherited // documentation inherited
public int read (ByteBuffer buf) public int read (ByteBuffer buf)
throws IOException 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;
} }