Added hacked-together support for playing .ogg files.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2255 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -0,0 +1,383 @@
|
||||
//
|
||||
// $Id: OggPlayer.java,v 1.1 2003/02/12 01:44:44 ray Exp $
|
||||
|
||||
package com.threerings.media.sound;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.DataLine;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
|
||||
import com.jcraft.jorbis.*;
|
||||
import com.jcraft.jogg.*;
|
||||
|
||||
/**
|
||||
* Plays Ogg Vorbis streams.
|
||||
*
|
||||
* Hacked together from NASTY code from JOrbis.
|
||||
*/
|
||||
// TODO- this would need to be greatly cleaned up if we were serious about
|
||||
// using it.
|
||||
public class OggPlayer extends MusicPlayer
|
||||
{
|
||||
// documentation inherited
|
||||
public void start (final InputStream stream)
|
||||
{
|
||||
_player = new Thread("narya ogg player") {
|
||||
public void run () {
|
||||
playStream(stream);
|
||||
}
|
||||
};
|
||||
_player.setDaemon(true);
|
||||
_player.start();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void stop ()
|
||||
{
|
||||
_player = null;
|
||||
}
|
||||
|
||||
static final int BUFSIZE=4096*2;
|
||||
static int convsize=BUFSIZE*2;
|
||||
static byte[] convbuffer=new byte[convsize];
|
||||
|
||||
SyncState oy;
|
||||
StreamState os;
|
||||
Page og;
|
||||
Packet op;
|
||||
Info vi;
|
||||
Comment vc;
|
||||
DspState vd;
|
||||
Block vb;
|
||||
|
||||
byte[] buffer=null;
|
||||
int bytes=0;
|
||||
|
||||
int format;
|
||||
int rate=0;
|
||||
int channels=0;
|
||||
SourceDataLine outputLine=null;
|
||||
|
||||
int frameSizeInBytes;
|
||||
int bufferLengthInBytes;
|
||||
|
||||
void init_jorbis(){
|
||||
oy=new SyncState();
|
||||
os=new StreamState();
|
||||
og=new Page();
|
||||
op=new Packet();
|
||||
|
||||
vi=new Info();
|
||||
vc=new Comment();
|
||||
vd=new DspState();
|
||||
vb=new Block(vd);
|
||||
|
||||
buffer=null;
|
||||
bytes=0;
|
||||
|
||||
oy.init();
|
||||
}
|
||||
|
||||
SourceDataLine getOutputLine(int channels, int rate){
|
||||
if(outputLine!=null || this.rate!=rate || this.channels!=channels){
|
||||
if(outputLine!=null){
|
||||
outputLine.drain();
|
||||
outputLine.stop();
|
||||
outputLine.close();
|
||||
}
|
||||
init_audio(channels, rate);
|
||||
outputLine.start();
|
||||
}
|
||||
return outputLine;
|
||||
}
|
||||
|
||||
void init_audio(int channels, int rate){
|
||||
try {
|
||||
//ClassLoader originalClassLoader=null;
|
||||
//try{
|
||||
// originalClassLoader=Thread.currentThread().getContextClassLoader();
|
||||
// Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
|
||||
//}
|
||||
//catch(Exception ee){
|
||||
// System.out.println(ee);
|
||||
//}
|
||||
AudioFormat audioFormat =
|
||||
new AudioFormat((float)rate,
|
||||
16,
|
||||
channels,
|
||||
true, // PCM_Signed
|
||||
false // littleEndian
|
||||
);
|
||||
DataLine.Info info =
|
||||
new DataLine.Info(SourceDataLine.class,
|
||||
audioFormat,
|
||||
AudioSystem.NOT_SPECIFIED);
|
||||
if (!AudioSystem.isLineSupported(info)) {
|
||||
//System.out.println("Line " + info + " not supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
outputLine = (SourceDataLine) AudioSystem.getLine(info);
|
||||
//outputLine.addLineListener(this);
|
||||
outputLine.open(audioFormat);
|
||||
}
|
||||
catch (LineUnavailableException ex) {
|
||||
System.out.println("Unable to open the sourceDataLine: " + ex);
|
||||
return;
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
System.out.println("Illegal Argument: " + ex);
|
||||
return;
|
||||
}
|
||||
|
||||
frameSizeInBytes = audioFormat.getFrameSize();
|
||||
int bufferLengthInFrames = outputLine.getBufferSize()/frameSizeInBytes/2;
|
||||
bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
|
||||
|
||||
//buffer = new byte[bufferLengthInBytes];
|
||||
//if(originalClassLoader!=null)
|
||||
// Thread.currentThread().setContextClassLoader(originalClassLoader);
|
||||
|
||||
this.rate=rate;
|
||||
this.channels=channels;
|
||||
}
|
||||
catch(Exception ee){
|
||||
System.out.println(ee);
|
||||
}
|
||||
}
|
||||
|
||||
protected void playStream (InputStream stream)
|
||||
{
|
||||
init_jorbis();
|
||||
|
||||
loop:
|
||||
while (true) {
|
||||
int eos = 0;
|
||||
|
||||
int index = oy.buffer(BUFSIZE);
|
||||
buffer = oy.data;
|
||||
try {
|
||||
bytes = stream.read(buffer, index, BUFSIZE);
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
return;
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
|
||||
if (oy.pageout(og) != 1) {
|
||||
if (bytes < BUFSIZE) {
|
||||
break;
|
||||
}
|
||||
System.err.println("Input does not appear to be an Ogg bitstream.");
|
||||
return;
|
||||
}
|
||||
|
||||
os.init(og.serialno());
|
||||
os.reset();
|
||||
|
||||
vi.init();
|
||||
vc.init();
|
||||
|
||||
if (os.pagein(og) < 0) {
|
||||
// error; stream version mismatch perhaps
|
||||
System.err.println("Error reading first page of Ogg bitstream data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (os.packetout(op) != 1) {
|
||||
// no page? must not be vorbis
|
||||
System.err.println("Error reading initial header packet.");
|
||||
break;
|
||||
// return;
|
||||
}
|
||||
|
||||
if (vi.synthesis_headerin(vc, op) < 0) {
|
||||
// error case; not a vorbis header
|
||||
System.err.println("This Ogg bitstream does not contain Vorbis audio data.");
|
||||
return;
|
||||
}
|
||||
|
||||
int i=0;
|
||||
|
||||
while (i < 2) {
|
||||
while (i < 2) {
|
||||
int result = oy.pageout(og);
|
||||
if (result==0) {
|
||||
break; // Need more data
|
||||
}
|
||||
if (result==1) {
|
||||
os.pagein(og);
|
||||
while (i < 2) {
|
||||
result = os.packetout(op);
|
||||
if (result == 0) {
|
||||
break;
|
||||
}
|
||||
if (result == -1) {
|
||||
System.err.println("Corrupt secondary header. Exiting.");
|
||||
//return;
|
||||
break loop;
|
||||
}
|
||||
vi.synthesis_headerin(vc, op);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index = oy.buffer(BUFSIZE);
|
||||
buffer = oy.data;
|
||||
try {
|
||||
bytes = stream.read(buffer, index, BUFSIZE);
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes == 0 && i < 2) {
|
||||
System.err.println("End of file before finding all Vorbis headers!");
|
||||
return;
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
}
|
||||
|
||||
convsize=BUFSIZE/vi.channels;
|
||||
|
||||
vd.synthesis_init(vi);
|
||||
vb.init(vd);
|
||||
|
||||
double[][][] _pcm=new double[1][][];
|
||||
float[][][] _pcmf=new float[1][][];
|
||||
int[] _index=new int[vi.channels];
|
||||
|
||||
getOutputLine(vi.channels, vi.rate);
|
||||
|
||||
while (eos == 0) {
|
||||
while (eos == 0) {
|
||||
|
||||
if (_player != Thread.currentThread()) {
|
||||
//System.err.println("bye.");
|
||||
try {
|
||||
//outputLine.drain();
|
||||
//outputLine.stop();
|
||||
//outputLine.close();
|
||||
stream.close();
|
||||
} catch(Exception ee) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int result = oy.pageout(og);
|
||||
if (result == 0) {
|
||||
break; // need more data
|
||||
}
|
||||
if (result == -1) { // missing or corrupt data at this page position
|
||||
// System.err.println("Corrupt or missing data in bitstream; continuing...");
|
||||
|
||||
} else {
|
||||
os.pagein(og);
|
||||
while (true) {
|
||||
result = os.packetout(op);
|
||||
if (result == 0) break; // need more data
|
||||
if (result == -1) { // missing or corrupt data at this page position
|
||||
// no reason to complain; already complained above
|
||||
} else {
|
||||
// we have a packet. Decode it
|
||||
int samples;
|
||||
if (vb.synthesis(op) == 0) { // test for success!
|
||||
vd.synthesis_blockin(vb);
|
||||
}
|
||||
while ((samples =
|
||||
vd.synthesis_pcmout(_pcmf, _index)) > 0) {
|
||||
|
||||
double[][] pcm = _pcm[0];
|
||||
float[][] pcmf = _pcmf[0];
|
||||
boolean clipflag = false;
|
||||
int bout = Math.min(samples, convsize);
|
||||
|
||||
// convert doubles to 16 bit signed ints (host order) and
|
||||
// interleave
|
||||
for (i = 0; i < vi.channels; i++) {
|
||||
int ptr = i*2;
|
||||
//int ptr=i;
|
||||
int mono = _index[i];
|
||||
for (int j = 0; j < bout; j++) {
|
||||
int val = (int)
|
||||
(pcmf[i][mono+j] * 32767.);
|
||||
if (val > 32767){
|
||||
val = 32767;
|
||||
clipflag = true;
|
||||
|
||||
} else if (val < -32768) {
|
||||
val = -32768;
|
||||
clipflag = true;
|
||||
}
|
||||
if (val < 0) {
|
||||
val = val | 0x8000;
|
||||
}
|
||||
convbuffer[ptr] = (byte)(val);
|
||||
convbuffer[ptr+1] = (byte)(val>>>8);
|
||||
ptr += 2 * (vi.channels);
|
||||
}
|
||||
}
|
||||
outputLine.write(convbuffer, 0,
|
||||
2 * vi.channels * bout);
|
||||
vd.synthesis_read(bout);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (og.eos() != 0) {
|
||||
eos=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (eos==0) {
|
||||
index = oy.buffer(BUFSIZE);
|
||||
buffer = oy.data;
|
||||
try {
|
||||
bytes = stream.read(buffer,index,BUFSIZE);
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
return;
|
||||
}
|
||||
if (bytes == -1) {
|
||||
break;
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
if (bytes==0) {
|
||||
eos=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
os.clear();
|
||||
vb.clear();
|
||||
vd.clear();
|
||||
vi.clear();
|
||||
}
|
||||
|
||||
oy.clear();
|
||||
|
||||
//System.err.println("Done.");
|
||||
|
||||
try {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void setVolume (float volume)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
protected Thread _player;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: SoundManager.java,v 1.45 2003/02/07 02:53:49 ray Exp $
|
||||
// $Id: SoundManager.java,v 1.46 2003/02/12 01:44:44 ray Exp $
|
||||
|
||||
package com.threerings.media.sound;
|
||||
|
||||
@@ -503,6 +503,9 @@ public class SoundManager
|
||||
} else if (path.endsWith(".mp3")) {
|
||||
return Mp3Player.class;
|
||||
|
||||
} else if (path.endsWith(".ogg")) {
|
||||
return OggPlayer.class;
|
||||
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user