mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 02:08:00 +00:00
- Added Stasis.
- Added JLayer libraries.
This commit is contained in:
52
.gitattributes
vendored
52
.gitattributes
vendored
@@ -256,6 +256,58 @@ src/forge/gui/ForgeAction.java svneol=native#text/plain
|
|||||||
src/forge/gui/ListChooser.java svneol=native#text/plain
|
src/forge/gui/ListChooser.java svneol=native#text/plain
|
||||||
src/forge/properties/ForgeProps.java svneol=native#text/plain
|
src/forge/properties/ForgeProps.java svneol=native#text/plain
|
||||||
src/forge/properties/NewConstants.java svneol=native#text/plain
|
src/forge/properties/NewConstants.java svneol=native#text/plain
|
||||||
|
src/javazoom/jl/converter/Converter.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/converter/RiffFile.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/converter/WaveFile.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/converter/WaveFileObuffer.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/converter/jlc.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/BitReserve.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/Bitstream.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/BitstreamErrors.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/BitstreamException.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/Control.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/Crc16.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/Decoder.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/DecoderErrors.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/DecoderException.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/Equalizer.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/FrameDecoder.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/Header.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/InputStreamSource.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/JavaLayerError.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/JavaLayerErrors.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/JavaLayerException.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/JavaLayerHook.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/JavaLayerUtils.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/LayerIDecoder.java svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/LayerIIDecoder.java svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/LayerIIIDecoder.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/Manager.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/Obuffer.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/OutputChannels.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/SampleBuffer.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/Source.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/SynthesisFilter.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/au2lin.ser -text svneol=unset#unset
|
||||||
|
src/javazoom/jl/decoder/huffcodetab.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/l3reorder.ser -text svneol=unset#unset
|
||||||
|
src/javazoom/jl/decoder/lin2au.ser -text svneol=unset#unset
|
||||||
|
src/javazoom/jl/decoder/readme.txt -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/decoder/sfd.ser -text svneol=unset#unset
|
||||||
|
src/javazoom/jl/player/AudioDevice.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/AudioDeviceBase.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/AudioDeviceFactory.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/FactoryRegistry.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/JavaSoundAudioDevice.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/JavaSoundAudioDeviceFactory.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/NullAudioDevice.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/Player.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/PlayerApplet.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/advanced/AdvancedPlayer.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/advanced/PlaybackEvent.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/advanced/PlaybackListener.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/advanced/jlap.java -text svneol=native#text/plain
|
||||||
|
src/javazoom/jl/player/jlp.java -text svneol=native#text/plain
|
||||||
src/org/jdesktop/swingx/MultiSplitLayout.java -text svneol=native#text/plain
|
src/org/jdesktop/swingx/MultiSplitLayout.java -text svneol=native#text/plain
|
||||||
src/org/jdesktop/swingx/MultiSplitPane.java -text svneol=native#text/plain
|
src/org/jdesktop/swingx/MultiSplitPane.java -text svneol=native#text/plain
|
||||||
src/treeProperties/PropertyElement.java svneol=native#text/plain
|
src/treeProperties/PropertyElement.java svneol=native#text/plain
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
Stasis
|
||||||
|
1 U
|
||||||
|
Enchantment
|
||||||
|
Players skip their untap steps.
|
||||||
|
At the beginning of your upkeep, sacrifice Stasis unless you pay:U
|
||||||
|
|
||||||
Cosmic Horror
|
Cosmic Horror
|
||||||
3 B B B
|
3 B B B
|
||||||
Creature
|
Creature
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class Input_Untap extends Input
|
|||||||
|
|
||||||
if(isMarbleTitanInPlay())
|
if(isMarbleTitanInPlay())
|
||||||
marbleUntap();
|
marbleUntap();
|
||||||
else
|
else if(!isStasisInPlay())
|
||||||
regularUntap();
|
regularUntap();
|
||||||
|
|
||||||
GameActionUtil.executeUpkeepEffects();
|
GameActionUtil.executeUpkeepEffects();
|
||||||
@@ -51,6 +51,25 @@ public class Input_Untap extends Input
|
|||||||
|
|
||||||
return all.size() > 0;
|
return all.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isStasisInPlay()
|
||||||
|
{
|
||||||
|
CardList all = new CardList();
|
||||||
|
all.addAll(AllZone.Human_Play.getCards());
|
||||||
|
all.addAll(AllZone.Computer_Play.getCards());
|
||||||
|
|
||||||
|
all = all.filter(new CardListFilter()
|
||||||
|
{
|
||||||
|
public boolean addCard(Card c) {
|
||||||
|
return c.getName().equals("Stasis");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return all.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void regularUntap()
|
private void regularUntap()
|
||||||
{
|
{
|
||||||
PlayerZone p = AllZone.getZone(Constant.Zone.Play, AllZone.Phase.getActivePlayer());
|
PlayerZone p = AllZone.getZone(Constant.Zone.Play, AllZone.Phase.getActivePlayer());
|
||||||
|
|||||||
411
src/javazoom/jl/converter/Converter.java
Normal file
411
src/javazoom/jl/converter/Converter.java
Normal file
@@ -0,0 +1,411 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Original verion. mdm@techie.com.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.converter;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.Bitstream;
|
||||||
|
import javazoom.jl.decoder.Decoder;
|
||||||
|
import javazoom.jl.decoder.Header;
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
import javazoom.jl.decoder.Obuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>Converter</code> class implements the conversion of
|
||||||
|
* an MPEG audio file to a .WAV file. To convert an MPEG audio stream,
|
||||||
|
* just create an instance of this class and call the convert()
|
||||||
|
* method, passing in the names of the input and output files. You can
|
||||||
|
* pass in optional <code>ProgressListener</code> and
|
||||||
|
* <code>Decoder.Params</code> objects also to customize the conversion.
|
||||||
|
*
|
||||||
|
* @author MDM 12/12/99
|
||||||
|
* @since 0.0.7
|
||||||
|
*/
|
||||||
|
public class Converter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates a new converter instance.
|
||||||
|
*/
|
||||||
|
public Converter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void convert(String sourceName, String destName)
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
convert(sourceName, destName, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void convert(String sourceName, String destName,
|
||||||
|
ProgressListener progressListener)
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
convert(sourceName, destName, progressListener, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void convert(String sourceName, String destName,
|
||||||
|
ProgressListener progressListener, Decoder.Params decoderParams)
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
if (destName.length()==0)
|
||||||
|
destName = null;
|
||||||
|
try {
|
||||||
|
InputStream in = openInput(sourceName);
|
||||||
|
convert(in, destName, progressListener, decoderParams);
|
||||||
|
in.close();
|
||||||
|
} catch(IOException ioe) {
|
||||||
|
throw new JavaLayerException(ioe.getLocalizedMessage(), ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void convert(InputStream sourceStream, String destName,
|
||||||
|
ProgressListener progressListener, Decoder.Params decoderParams)
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
if (progressListener==null)
|
||||||
|
progressListener = PrintWriterProgressListener.newStdOut(
|
||||||
|
PrintWriterProgressListener.NO_DETAIL);
|
||||||
|
try {
|
||||||
|
if (!(sourceStream instanceof BufferedInputStream))
|
||||||
|
sourceStream = new BufferedInputStream(sourceStream);
|
||||||
|
int frameCount = -1;
|
||||||
|
if (sourceStream.markSupported()) {
|
||||||
|
sourceStream.mark(-1);
|
||||||
|
frameCount = countFrames(sourceStream);
|
||||||
|
sourceStream.reset();
|
||||||
|
}
|
||||||
|
progressListener.converterUpdate(ProgressListener.UPDATE_FRAME_COUNT, frameCount, 0);
|
||||||
|
|
||||||
|
|
||||||
|
Obuffer output = null;
|
||||||
|
Decoder decoder = new Decoder(decoderParams);
|
||||||
|
Bitstream stream = new Bitstream(sourceStream);
|
||||||
|
|
||||||
|
if (frameCount==-1)
|
||||||
|
frameCount = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
int frame = 0;
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (; frame<frameCount; frame++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Header header = stream.readFrame();
|
||||||
|
if (header==null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
progressListener.readFrame(frame, header);
|
||||||
|
|
||||||
|
if (output==null)
|
||||||
|
{
|
||||||
|
// REVIEW: Incorrect functionality.
|
||||||
|
// the decoder should provide decoded
|
||||||
|
// frequency and channels output as it may differ from
|
||||||
|
// the source (e.g. when downmixing stereo to mono.)
|
||||||
|
int channels = (header.mode()==Header.SINGLE_CHANNEL) ? 1 : 2;
|
||||||
|
int freq = header.frequency();
|
||||||
|
output = new WaveFileObuffer(channels, freq, destName);
|
||||||
|
decoder.setOutputBuffer(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
Obuffer decoderOutput = decoder.decodeFrame(header, stream);
|
||||||
|
|
||||||
|
// REVIEW: the way the output buffer is set
|
||||||
|
// on the decoder is a bit dodgy. Even though
|
||||||
|
// this exception should never happen, we test to be sure.
|
||||||
|
if (decoderOutput!=output)
|
||||||
|
throw new InternalError("Output buffers are different.");
|
||||||
|
|
||||||
|
|
||||||
|
progressListener.decodedFrame(frame, header, output);
|
||||||
|
|
||||||
|
stream.closeFrame();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
boolean stop = !progressListener.converterException(ex);
|
||||||
|
|
||||||
|
if (stop)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException(ex.getLocalizedMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
|
||||||
|
if (output!=null)
|
||||||
|
output.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int time = (int)(System.currentTimeMillis()-startTime);
|
||||||
|
progressListener.converterUpdate(ProgressListener.UPDATE_CONVERT_COMPLETE,
|
||||||
|
time, frame);
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException(ex.getLocalizedMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected int countFrames(InputStream in)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected InputStream openInput(String fileName)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// ensure name is abstract path name
|
||||||
|
File file = new File(fileName);
|
||||||
|
InputStream fileIn = new FileInputStream(file);
|
||||||
|
BufferedInputStream bufIn = new BufferedInputStream(fileIn);
|
||||||
|
|
||||||
|
return bufIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is used by the Converter to provide
|
||||||
|
* notification of tasks being carried out by the converter,
|
||||||
|
* and to provide new information as it becomes available.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static public interface ProgressListener
|
||||||
|
{
|
||||||
|
public static final int UPDATE_FRAME_COUNT = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversion is complete. Param1 contains the time
|
||||||
|
* to convert in milliseconds. Param2 contains the number
|
||||||
|
* of MPEG audio frames converted.
|
||||||
|
*/
|
||||||
|
public static final int UPDATE_CONVERT_COMPLETE = 2;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the listener that new information is available.
|
||||||
|
*
|
||||||
|
* @param updateID Code indicating the information that has been
|
||||||
|
* updated.
|
||||||
|
*
|
||||||
|
* @param param1 Parameter whose value depends upon the update code.
|
||||||
|
* @param param2 Parameter whose value depends upon the update code.
|
||||||
|
*
|
||||||
|
* The <code>updateID</code> parameter can take these values:
|
||||||
|
*
|
||||||
|
* UPDATE_FRAME_COUNT: param1 is the frame count, or -1 if not known.
|
||||||
|
* UPDATE_CONVERT_COMPLETE: param1 is the conversion time, param2
|
||||||
|
* is the number of frames converted.
|
||||||
|
*/
|
||||||
|
public void converterUpdate(int updateID, int param1, int param2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the converter wishes to make a first pass over the
|
||||||
|
* audio frames, this is called as each frame is parsed.
|
||||||
|
*/
|
||||||
|
public void parsedFrame(int frameNo, Header header);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called after each frame has been read,
|
||||||
|
* but before it has been decoded.
|
||||||
|
*
|
||||||
|
* @param frameNo The 0-based sequence number of the frame.
|
||||||
|
* @param header The Header rerpesenting the frame just read.
|
||||||
|
*/
|
||||||
|
public void readFrame(int frameNo, Header header);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called after a frame has been decoded.
|
||||||
|
*
|
||||||
|
* @param frameNo The 0-based sequence number of the frame.
|
||||||
|
* @param header The Header rerpesenting the frame just read.
|
||||||
|
* @param o The Obuffer the deocded data was written to.
|
||||||
|
*/
|
||||||
|
public void decodedFrame(int frameNo, Header header, Obuffer o);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an exception is thrown during while converting
|
||||||
|
* a frame.
|
||||||
|
*
|
||||||
|
* @param t The <code>Throwable</code> instance that
|
||||||
|
* was thrown.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> to continue processing, or false
|
||||||
|
* to abort conversion.
|
||||||
|
*
|
||||||
|
* If this method returns <code>false</code>, the exception
|
||||||
|
* is propagated to the caller of the convert() method. If
|
||||||
|
* <code>true</code> is returned, the exception is silently
|
||||||
|
* ignored and the converter moves onto the next frame.
|
||||||
|
*/
|
||||||
|
public boolean converterException(Throwable t);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of <code>ProgressListener</code> that writes
|
||||||
|
* notification text to a <code>PrintWriter</code>.
|
||||||
|
*/
|
||||||
|
// REVIEW: i18n of text and order required.
|
||||||
|
static public class PrintWriterProgressListener implements ProgressListener
|
||||||
|
{
|
||||||
|
static public final int NO_DETAIL = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Level of detail typically expected of expert
|
||||||
|
* users.
|
||||||
|
*/
|
||||||
|
static public final int EXPERT_DETAIL = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verbose detail.
|
||||||
|
*/
|
||||||
|
static public final int VERBOSE_DETAIL = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug detail. All frame read notifications are shown.
|
||||||
|
*/
|
||||||
|
static public final int DEBUG_DETAIL = 7;
|
||||||
|
|
||||||
|
static public final int MAX_DETAIL = 10;
|
||||||
|
|
||||||
|
private PrintWriter pw;
|
||||||
|
|
||||||
|
private int detailLevel;
|
||||||
|
|
||||||
|
static public PrintWriterProgressListener newStdOut(int detail)
|
||||||
|
{
|
||||||
|
return new PrintWriterProgressListener(
|
||||||
|
new PrintWriter(System.out, true), detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrintWriterProgressListener(PrintWriter writer, int detailLevel)
|
||||||
|
{
|
||||||
|
this.pw = writer;
|
||||||
|
this.detailLevel = detailLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isDetail(int detail)
|
||||||
|
{
|
||||||
|
return (this.detailLevel >= detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void converterUpdate(int updateID, int param1, int param2)
|
||||||
|
{
|
||||||
|
if (isDetail(VERBOSE_DETAIL))
|
||||||
|
{
|
||||||
|
switch (updateID)
|
||||||
|
{
|
||||||
|
case UPDATE_CONVERT_COMPLETE:
|
||||||
|
// catch divide by zero errors.
|
||||||
|
if (param2==0)
|
||||||
|
param2 = 1;
|
||||||
|
|
||||||
|
pw.println();
|
||||||
|
pw.println("Converted "+param2+" frames in "+param1+" ms ("+
|
||||||
|
(param1/param2)+" ms per frame.)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parsedFrame(int frameNo, Header header)
|
||||||
|
{
|
||||||
|
if ((frameNo==0) && isDetail(VERBOSE_DETAIL))
|
||||||
|
{
|
||||||
|
String headerString = header.toString();
|
||||||
|
pw.println("File is a "+headerString);
|
||||||
|
}
|
||||||
|
else if (isDetail(MAX_DETAIL))
|
||||||
|
{
|
||||||
|
String headerString = header.toString();
|
||||||
|
pw.println("Prased frame "+frameNo+": "+headerString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readFrame(int frameNo, Header header)
|
||||||
|
{
|
||||||
|
if ((frameNo==0) && isDetail(VERBOSE_DETAIL))
|
||||||
|
{
|
||||||
|
String headerString = header.toString();
|
||||||
|
pw.println("File is a "+headerString);
|
||||||
|
}
|
||||||
|
else if (isDetail(MAX_DETAIL))
|
||||||
|
{
|
||||||
|
String headerString = header.toString();
|
||||||
|
pw.println("Read frame "+frameNo+": "+headerString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodedFrame(int frameNo, Header header, Obuffer o)
|
||||||
|
{
|
||||||
|
if (isDetail(MAX_DETAIL))
|
||||||
|
{
|
||||||
|
String headerString = header.toString();
|
||||||
|
pw.println("Decoded frame "+frameNo+": "+headerString);
|
||||||
|
pw.println("Output: "+o);
|
||||||
|
}
|
||||||
|
else if (isDetail(VERBOSE_DETAIL))
|
||||||
|
{
|
||||||
|
if (frameNo==0)
|
||||||
|
{
|
||||||
|
pw.print("Converting.");
|
||||||
|
pw.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((frameNo % 10)==0)
|
||||||
|
{
|
||||||
|
pw.print('.');
|
||||||
|
pw.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean converterException(Throwable t)
|
||||||
|
{
|
||||||
|
if (this.detailLevel>NO_DETAIL)
|
||||||
|
{
|
||||||
|
t.printStackTrace(pw);
|
||||||
|
pw.flush();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
495
src/javazoom/jl/converter/RiffFile.java
Normal file
495
src/javazoom/jl/converter/RiffFile.java
Normal file
@@ -0,0 +1,495 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 02/23/99 JavaConversion by E.B
|
||||||
|
* Don Cross, April 1993.
|
||||||
|
* RIFF file format classes.
|
||||||
|
* See Chapter 8 of "Multimedia Programmer's Reference" in
|
||||||
|
* the Microsoft Windows SDK.
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.converter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to manage RIFF files
|
||||||
|
*/
|
||||||
|
public class RiffFile
|
||||||
|
{
|
||||||
|
class RiffChunkHeader
|
||||||
|
{
|
||||||
|
public int ckID = 0; // Four-character chunk ID
|
||||||
|
public int ckSize = 0; // Length of data in chunk
|
||||||
|
public RiffChunkHeader()
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DDCRET
|
||||||
|
public static final int DDC_SUCCESS = 0; // The operation succeded
|
||||||
|
public static final int DDC_FAILURE = 1; // The operation failed for unspecified reasons
|
||||||
|
public static final int DDC_OUT_OF_MEMORY = 2; // Operation failed due to running out of memory
|
||||||
|
public static final int DDC_FILE_ERROR = 3; // Operation encountered file I/O error
|
||||||
|
public static final int DDC_INVALID_CALL = 4; // Operation was called with invalid parameters
|
||||||
|
public static final int DDC_USER_ABORT = 5; // Operation was aborted by the user
|
||||||
|
public static final int DDC_INVALID_FILE = 6; // File format does not match
|
||||||
|
|
||||||
|
// RiffFileMode
|
||||||
|
public static final int RFM_UNKNOWN = 0; // undefined type (can use to mean "N/A" or "not open")
|
||||||
|
public static final int RFM_WRITE = 1; // open for write
|
||||||
|
public static final int RFM_READ = 2; // open for read
|
||||||
|
|
||||||
|
private RiffChunkHeader riff_header; // header for whole file
|
||||||
|
protected int fmode; // current file I/O mode
|
||||||
|
protected RandomAccessFile file; // I/O stream to use
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dummy Constructor
|
||||||
|
*/
|
||||||
|
public RiffFile()
|
||||||
|
{
|
||||||
|
file = null;
|
||||||
|
fmode = RFM_UNKNOWN;
|
||||||
|
riff_header = new RiffChunkHeader();
|
||||||
|
|
||||||
|
riff_header.ckID = FourCC("RIFF");
|
||||||
|
riff_header.ckSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return File Mode.
|
||||||
|
*/
|
||||||
|
public int CurrentFileMode()
|
||||||
|
{return fmode;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a RIFF file.
|
||||||
|
*/
|
||||||
|
public int Open(String Filename, int NewMode)
|
||||||
|
{
|
||||||
|
int retcode = DDC_SUCCESS;
|
||||||
|
|
||||||
|
if ( fmode != RFM_UNKNOWN )
|
||||||
|
{
|
||||||
|
retcode = Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
switch ( NewMode )
|
||||||
|
{
|
||||||
|
case RFM_WRITE:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file = new RandomAccessFile(Filename,"rw");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Write the RIFF header...
|
||||||
|
// We will have to come back later and patch it!
|
||||||
|
byte[] br = new byte[8];
|
||||||
|
br[0] = (byte) ((riff_header.ckID >>> 24) & 0x000000FF);
|
||||||
|
br[1] = (byte) ((riff_header.ckID >>> 16) & 0x000000FF);
|
||||||
|
br[2] = (byte) ((riff_header.ckID >>> 8) & 0x000000FF);
|
||||||
|
br[3] = (byte) (riff_header.ckID & 0x000000FF);
|
||||||
|
|
||||||
|
byte br4 = (byte) ((riff_header.ckSize >>> 24)& 0x000000FF);
|
||||||
|
byte br5 = (byte) ((riff_header.ckSize >>> 16)& 0x000000FF);
|
||||||
|
byte br6 = (byte) ((riff_header.ckSize >>> 8)& 0x000000FF);
|
||||||
|
byte br7 = (byte) (riff_header.ckSize & 0x000000FF);
|
||||||
|
|
||||||
|
br[4] = br7;
|
||||||
|
br[5] = br6;
|
||||||
|
br[6] = br5;
|
||||||
|
br[7] = br4;
|
||||||
|
|
||||||
|
file.write(br,0,8);
|
||||||
|
fmode = RFM_WRITE;
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
file.close();
|
||||||
|
fmode = RFM_UNKNOWN;
|
||||||
|
}
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
fmode = RFM_UNKNOWN;
|
||||||
|
retcode = DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RFM_READ:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file = new RandomAccessFile(Filename,"r");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Try to read the RIFF header...
|
||||||
|
byte[] br = new byte[8];
|
||||||
|
file.read(br,0,8);
|
||||||
|
fmode = RFM_READ;
|
||||||
|
riff_header.ckID = ((br[0]<<24)& 0xFF000000) | ((br[1]<<16)&0x00FF0000) | ((br[2]<<8)&0x0000FF00) | (br[3]&0x000000FF);
|
||||||
|
riff_header.ckSize = ((br[4]<<24)& 0xFF000000) | ((br[5]<<16)&0x00FF0000) | ((br[6]<<8)&0x0000FF00) | (br[7]&0x000000FF);
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
file.close();
|
||||||
|
fmode = RFM_UNKNOWN;
|
||||||
|
}
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
fmode = RFM_UNKNOWN;
|
||||||
|
retcode = DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
retcode = DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write NumBytes data.
|
||||||
|
*/
|
||||||
|
public int Write(byte[] Data, int NumBytes )
|
||||||
|
{
|
||||||
|
if ( fmode != RFM_WRITE )
|
||||||
|
{
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.write(Data,0,NumBytes);
|
||||||
|
fmode = RFM_WRITE;
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
return DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
riff_header.ckSize += NumBytes;
|
||||||
|
return DDC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write NumBytes data.
|
||||||
|
*/
|
||||||
|
public int Write(short[] Data, int NumBytes )
|
||||||
|
{
|
||||||
|
byte[] theData = new byte[NumBytes];
|
||||||
|
int yc = 0;
|
||||||
|
for (int y = 0;y<NumBytes;y=y+2)
|
||||||
|
{
|
||||||
|
theData[y] = (byte) (Data[yc] & 0x00FF);
|
||||||
|
theData[y+1] =(byte) ((Data[yc++] >>> 8) & 0x00FF);
|
||||||
|
}
|
||||||
|
if ( fmode != RFM_WRITE )
|
||||||
|
{
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.write(theData,0,NumBytes);
|
||||||
|
fmode = RFM_WRITE;
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
return DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
riff_header.ckSize += NumBytes;
|
||||||
|
return DDC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write NumBytes data.
|
||||||
|
*/
|
||||||
|
public int Write(RiffChunkHeader Triff_header, int NumBytes )
|
||||||
|
{
|
||||||
|
byte[] br = new byte[8];
|
||||||
|
br[0] = (byte) ((Triff_header.ckID >>> 24) & 0x000000FF);
|
||||||
|
br[1] = (byte) ((Triff_header.ckID >>> 16) & 0x000000FF);
|
||||||
|
br[2] = (byte) ((Triff_header.ckID >>> 8) & 0x000000FF);
|
||||||
|
br[3] = (byte) (Triff_header.ckID & 0x000000FF);
|
||||||
|
|
||||||
|
byte br4 = (byte) ((Triff_header.ckSize >>> 24)& 0x000000FF);
|
||||||
|
byte br5 = (byte) ((Triff_header.ckSize >>> 16)& 0x000000FF);
|
||||||
|
byte br6 = (byte) ((Triff_header.ckSize >>> 8)& 0x000000FF);
|
||||||
|
byte br7 = (byte) (Triff_header.ckSize & 0x000000FF);
|
||||||
|
|
||||||
|
br[4] = br7;
|
||||||
|
br[5] = br6;
|
||||||
|
br[6] = br5;
|
||||||
|
br[7] = br4;
|
||||||
|
|
||||||
|
if ( fmode != RFM_WRITE )
|
||||||
|
{
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.write(br,0,NumBytes);
|
||||||
|
fmode = RFM_WRITE;
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
return DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
riff_header.ckSize += NumBytes;
|
||||||
|
return DDC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write NumBytes data.
|
||||||
|
*/
|
||||||
|
public int Write(short Data, int NumBytes )
|
||||||
|
{
|
||||||
|
short theData = (short) ( ((Data>>>8)&0x00FF) | ((Data<<8)&0xFF00) );
|
||||||
|
if ( fmode != RFM_WRITE )
|
||||||
|
{
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.writeShort(theData);
|
||||||
|
fmode = RFM_WRITE;
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
return DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
riff_header.ckSize += NumBytes;
|
||||||
|
return DDC_SUCCESS;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Write NumBytes data.
|
||||||
|
*/
|
||||||
|
public int Write(int Data, int NumBytes )
|
||||||
|
{
|
||||||
|
short theDataL = (short) ((Data>>>16)&0x0000FFFF);
|
||||||
|
short theDataR = (short) (Data&0x0000FFFF);
|
||||||
|
short theDataLI = (short) ( ((theDataL>>>8)&0x00FF) | ((theDataL<<8)&0xFF00) );
|
||||||
|
short theDataRI = (short) ( ((theDataR>>>8)&0x00FF) | ((theDataR<<8)&0xFF00) );
|
||||||
|
int theData = ((theDataRI<<16)&0xFFFF0000) | (theDataLI&0x0000FFFF);
|
||||||
|
if ( fmode != RFM_WRITE )
|
||||||
|
{
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.writeInt(theData);
|
||||||
|
fmode = RFM_WRITE;
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
return DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
riff_header.ckSize += NumBytes;
|
||||||
|
return DDC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read NumBytes data.
|
||||||
|
*/
|
||||||
|
public int Read (byte[] Data, int NumBytes)
|
||||||
|
{
|
||||||
|
int retcode = DDC_SUCCESS;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.read(Data,0,NumBytes);
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
retcode = DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
return retcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expect NumBytes data.
|
||||||
|
*/
|
||||||
|
public int Expect(String Data, int NumBytes )
|
||||||
|
{
|
||||||
|
byte target = 0;
|
||||||
|
int cnt = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while ((NumBytes--) != 0)
|
||||||
|
{
|
||||||
|
target = file.readByte();
|
||||||
|
if (target != Data.charAt(cnt++)) return DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
return DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
return DDC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close Riff File.
|
||||||
|
* Length is written too.
|
||||||
|
*/
|
||||||
|
public int Close()
|
||||||
|
{
|
||||||
|
int retcode = DDC_SUCCESS;
|
||||||
|
|
||||||
|
switch ( fmode )
|
||||||
|
{
|
||||||
|
case RFM_WRITE:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.seek(0);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] br = new byte[8];
|
||||||
|
br[0] = (byte) ((riff_header.ckID >>> 24) & 0x000000FF);
|
||||||
|
br[1] = (byte) ((riff_header.ckID >>> 16) & 0x000000FF);
|
||||||
|
br[2] = (byte) ((riff_header.ckID >>> 8) & 0x000000FF);
|
||||||
|
br[3] = (byte) (riff_header.ckID & 0x000000FF);
|
||||||
|
|
||||||
|
br[7] = (byte) ((riff_header.ckSize >>> 24)& 0x000000FF);
|
||||||
|
br[6] = (byte) ((riff_header.ckSize >>> 16)& 0x000000FF);
|
||||||
|
br[5] = (byte) ((riff_header.ckSize >>> 8)& 0x000000FF);
|
||||||
|
br[4] = (byte) (riff_header.ckSize & 0x000000FF);
|
||||||
|
file.write(br,0,8);
|
||||||
|
file.close();
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
retcode = DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
retcode = DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RFM_READ:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.close();
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
retcode = DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
file = null;
|
||||||
|
fmode = RFM_UNKNOWN;
|
||||||
|
return retcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return File Position.
|
||||||
|
*/
|
||||||
|
public long CurrentFilePosition()
|
||||||
|
{
|
||||||
|
long position;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
position = file.getFilePointer();
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
position = -1;
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write Data to specified offset.
|
||||||
|
*/
|
||||||
|
public int Backpatch (long FileOffset, RiffChunkHeader Data, int NumBytes )
|
||||||
|
{
|
||||||
|
if (file == null)
|
||||||
|
{
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.seek(FileOffset);
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
return DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
return Write ( Data, NumBytes );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Backpatch (long FileOffset, byte[] Data, int NumBytes )
|
||||||
|
{
|
||||||
|
if (file == null)
|
||||||
|
{
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.seek(FileOffset);
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
return DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
return Write ( Data, NumBytes );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seek in the File.
|
||||||
|
*/
|
||||||
|
protected int Seek(long offset)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.seek(offset);
|
||||||
|
rc = DDC_SUCCESS;
|
||||||
|
} catch (IOException ioe)
|
||||||
|
{
|
||||||
|
rc = DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error Messages.
|
||||||
|
*/
|
||||||
|
private String DDCRET_String(int retcode)
|
||||||
|
{
|
||||||
|
switch ( retcode )
|
||||||
|
{
|
||||||
|
case DDC_SUCCESS: return "DDC_SUCCESS";
|
||||||
|
case DDC_FAILURE: return "DDC_FAILURE";
|
||||||
|
case DDC_OUT_OF_MEMORY: return "DDC_OUT_OF_MEMORY";
|
||||||
|
case DDC_FILE_ERROR: return "DDC_FILE_ERROR";
|
||||||
|
case DDC_INVALID_CALL: return "DDC_INVALID_CALL";
|
||||||
|
case DDC_USER_ABORT: return "DDC_USER_ABORT";
|
||||||
|
case DDC_INVALID_FILE: return "DDC_INVALID_FILE";
|
||||||
|
}
|
||||||
|
return "Unknown Error";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the header.
|
||||||
|
*/
|
||||||
|
public static int FourCC(String ChunkName)
|
||||||
|
{
|
||||||
|
byte[] p = {0x20,0x20,0x20,0x20};
|
||||||
|
ChunkName.getBytes(0,4,p,0);
|
||||||
|
int ret = (((p[0] << 24)& 0xFF000000) | ((p[1] << 16)&0x00FF0000) | ((p[2] << 8)&0x0000FF00) | (p[3]&0x000000FF));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
522
src/javazoom/jl/converter/WaveFile.java
Normal file
522
src/javazoom/jl/converter/WaveFile.java
Normal file
@@ -0,0 +1,522 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 02/23/99 JavaConversion by E.B
|
||||||
|
* Don Cross, April 1993.
|
||||||
|
* RIFF file format classes.
|
||||||
|
* See Chapter 8 of "Multimedia Programmer's Reference" in
|
||||||
|
* the Microsoft Windows SDK.
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class allowing WaveFormat Access
|
||||||
|
*/
|
||||||
|
public class WaveFile extends RiffFile
|
||||||
|
{
|
||||||
|
public static final int MAX_WAVE_CHANNELS = 2;
|
||||||
|
|
||||||
|
class WaveFormat_ChunkData
|
||||||
|
{
|
||||||
|
public short wFormatTag = 0; // Format category (PCM=1)
|
||||||
|
public short nChannels = 0; // Number of channels (mono=1, stereo=2)
|
||||||
|
public int nSamplesPerSec = 0; // Sampling rate [Hz]
|
||||||
|
public int nAvgBytesPerSec = 0;
|
||||||
|
public short nBlockAlign = 0;
|
||||||
|
public short nBitsPerSample = 0;
|
||||||
|
|
||||||
|
public WaveFormat_ChunkData()
|
||||||
|
{
|
||||||
|
wFormatTag = 1; // PCM
|
||||||
|
Config(44100,(short)16,(short)1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Config (int NewSamplingRate, short NewBitsPerSample, short NewNumChannels)
|
||||||
|
{
|
||||||
|
nSamplesPerSec = NewSamplingRate;
|
||||||
|
nChannels = NewNumChannels;
|
||||||
|
nBitsPerSample = NewBitsPerSample;
|
||||||
|
nAvgBytesPerSec = (nChannels * nSamplesPerSec * nBitsPerSample) / 8;
|
||||||
|
nBlockAlign = (short) ((nChannels * nBitsPerSample) / 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class WaveFormat_Chunk
|
||||||
|
{
|
||||||
|
public RiffChunkHeader header;
|
||||||
|
public WaveFormat_ChunkData data;
|
||||||
|
|
||||||
|
public WaveFormat_Chunk()
|
||||||
|
{
|
||||||
|
header = new RiffChunkHeader();
|
||||||
|
data = new WaveFormat_ChunkData();
|
||||||
|
header.ckID = FourCC("fmt ");
|
||||||
|
header.ckSize = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int VerifyValidity()
|
||||||
|
{
|
||||||
|
boolean ret = header.ckID == FourCC("fmt ") &&
|
||||||
|
|
||||||
|
(data.nChannels == 1 || data.nChannels == 2) &&
|
||||||
|
|
||||||
|
data.nAvgBytesPerSec == ( data.nChannels *
|
||||||
|
data.nSamplesPerSec *
|
||||||
|
data.nBitsPerSample ) / 8 &&
|
||||||
|
|
||||||
|
data.nBlockAlign == ( data.nChannels *
|
||||||
|
data.nBitsPerSample ) / 8;
|
||||||
|
if (ret == true) return 1;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class WaveFileSample
|
||||||
|
{
|
||||||
|
public short[] chan;
|
||||||
|
|
||||||
|
public WaveFileSample()
|
||||||
|
{chan = new short[WaveFile.MAX_WAVE_CHANNELS];}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WaveFormat_Chunk wave_format;
|
||||||
|
private RiffChunkHeader pcm_data;
|
||||||
|
private long pcm_data_offset = 0; // offset of 'pcm_data' in output file
|
||||||
|
private int num_samples = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new WaveFile instance.
|
||||||
|
*/
|
||||||
|
public WaveFile()
|
||||||
|
{
|
||||||
|
pcm_data = new RiffChunkHeader();
|
||||||
|
wave_format = new WaveFormat_Chunk();
|
||||||
|
pcm_data.ckID = FourCC("data");
|
||||||
|
pcm_data.ckSize = 0;
|
||||||
|
num_samples = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
public int OpenForRead (String Filename)
|
||||||
|
{
|
||||||
|
// Verify filename parameter as best we can...
|
||||||
|
if (Filename == null)
|
||||||
|
{
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
int retcode = Open ( Filename, RFM_READ );
|
||||||
|
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
retcode = Expect ( "WAVE", 4 );
|
||||||
|
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
retcode = Read(wave_format,24);
|
||||||
|
|
||||||
|
if ( retcode == DDC_SUCCESS && !wave_format.VerifyValidity() )
|
||||||
|
{
|
||||||
|
// This isn't standard PCM, so we don't know what it is!
|
||||||
|
retcode = DDC_FILE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
pcm_data_offset = CurrentFilePosition();
|
||||||
|
|
||||||
|
// Figure out number of samples from
|
||||||
|
// file size, current file position, and
|
||||||
|
// WAVE header.
|
||||||
|
retcode = Read (pcm_data, 8 );
|
||||||
|
num_samples = filelength(fileno(file)) - CurrentFilePosition();
|
||||||
|
num_samples /= NumChannels();
|
||||||
|
num_samples /= (BitsPerSample() / 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retcode;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public int OpenForWrite (String Filename, int SamplingRate, short BitsPerSample, short NumChannels)
|
||||||
|
{
|
||||||
|
// Verify parameters...
|
||||||
|
if ( (Filename==null) ||
|
||||||
|
(BitsPerSample != 8 && BitsPerSample != 16) ||
|
||||||
|
NumChannels < 1 || NumChannels > 2 )
|
||||||
|
{
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wave_format.data.Config ( SamplingRate, BitsPerSample, NumChannels );
|
||||||
|
|
||||||
|
int retcode = Open ( Filename, RFM_WRITE );
|
||||||
|
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
byte [] theWave = {(byte)'W',(byte)'A',(byte)'V',(byte)'E'};
|
||||||
|
retcode = Write ( theWave, 4 );
|
||||||
|
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
// Ecriture de wave_format
|
||||||
|
retcode = Write (wave_format.header, 8);
|
||||||
|
retcode = Write (wave_format.data.wFormatTag, 2);
|
||||||
|
retcode = Write (wave_format.data.nChannels, 2);
|
||||||
|
retcode = Write (wave_format.data.nSamplesPerSec, 4);
|
||||||
|
retcode = Write (wave_format.data.nAvgBytesPerSec, 4);
|
||||||
|
retcode = Write (wave_format.data.nBlockAlign, 2);
|
||||||
|
retcode = Write (wave_format.data.nBitsPerSample, 2);
|
||||||
|
/* byte[] br = new byte[16];
|
||||||
|
br[0] = (byte) ((wave_format.data.wFormatTag >> 8) & 0x00FF);
|
||||||
|
br[1] = (byte) (wave_format.data.wFormatTag & 0x00FF);
|
||||||
|
|
||||||
|
br[2] = (byte) ((wave_format.data.nChannels >> 8) & 0x00FF);
|
||||||
|
br[3] = (byte) (wave_format.data.nChannels & 0x00FF);
|
||||||
|
|
||||||
|
br[4] = (byte) ((wave_format.data.nSamplesPerSec >> 24)& 0x000000FF);
|
||||||
|
br[5] = (byte) ((wave_format.data.nSamplesPerSec >> 16)& 0x000000FF);
|
||||||
|
br[6] = (byte) ((wave_format.data.nSamplesPerSec >> 8)& 0x000000FF);
|
||||||
|
br[7] = (byte) (wave_format.data.nSamplesPerSec & 0x000000FF);
|
||||||
|
|
||||||
|
br[8] = (byte) ((wave_format.data.nAvgBytesPerSec>> 24)& 0x000000FF);
|
||||||
|
br[9] = (byte) ((wave_format.data.nAvgBytesPerSec >> 16)& 0x000000FF);
|
||||||
|
br[10] = (byte) ((wave_format.data.nAvgBytesPerSec >> 8)& 0x000000FF);
|
||||||
|
br[11] = (byte) (wave_format.data.nAvgBytesPerSec & 0x000000FF);
|
||||||
|
|
||||||
|
br[12] = (byte) ((wave_format.data.nBlockAlign >> 8) & 0x00FF);
|
||||||
|
br[13] = (byte) (wave_format.data.nBlockAlign & 0x00FF);
|
||||||
|
|
||||||
|
br[14] = (byte) ((wave_format.data.nBitsPerSample >> 8) & 0x00FF);
|
||||||
|
br[15] = (byte) (wave_format.data.nBitsPerSample & 0x00FF);
|
||||||
|
retcode = Write (br, 16); */
|
||||||
|
|
||||||
|
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
pcm_data_offset = CurrentFilePosition();
|
||||||
|
retcode = Write ( pcm_data, 8 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
public int ReadSample ( short[] Sample )
|
||||||
|
{
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
public int WriteSample( short[] Sample )
|
||||||
|
{
|
||||||
|
int retcode = DDC_SUCCESS;
|
||||||
|
switch ( wave_format.data.nChannels )
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
switch ( wave_format.data.nBitsPerSample )
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
pcm_data.ckSize += 1;
|
||||||
|
retcode = Write ( Sample, 1 );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
pcm_data.ckSize += 2;
|
||||||
|
retcode = Write ( Sample, 2 );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
retcode = DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
switch ( wave_format.data.nBitsPerSample )
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
retcode = Write ( Sample, 1 );
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
// &Sample[1]
|
||||||
|
retcode = Write (Sample, 1 );
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
pcm_data.ckSize += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
retcode = Write ( Sample, 2 );
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
// &Sample[1]
|
||||||
|
retcode = Write (Sample, 2 );
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
pcm_data.ckSize += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
retcode = DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
retcode = DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retcode;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
public int SeekToSample ( long SampleIndex )
|
||||||
|
{
|
||||||
|
if ( SampleIndex >= NumSamples() )
|
||||||
|
{
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
int SampleSize = (BitsPerSample() + 7) / 8;
|
||||||
|
int rc = Seek ( pcm_data_offset + 8 +
|
||||||
|
SampleSize * NumChannels() * SampleIndex );
|
||||||
|
return rc;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write 16-bit audio
|
||||||
|
*/
|
||||||
|
public int WriteData ( short[] data, int numData )
|
||||||
|
{
|
||||||
|
int extraBytes = numData * 2;
|
||||||
|
pcm_data.ckSize += extraBytes;
|
||||||
|
return super.Write ( data, extraBytes );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read 16-bit audio.
|
||||||
|
*
|
||||||
|
public int ReadData (short[] data, int numData)
|
||||||
|
{return super.Read ( data, numData * 2);} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write 8-bit audio.
|
||||||
|
*
|
||||||
|
public int WriteData ( byte[] data, int numData )
|
||||||
|
{
|
||||||
|
pcm_data.ckSize += numData;
|
||||||
|
return super.Write ( data, numData );
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read 8-bit audio.
|
||||||
|
*
|
||||||
|
public int ReadData ( byte[] data, int numData )
|
||||||
|
{return super.Read ( data, numData );} */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
public int ReadSamples (int num, int [] WaveFileSample)
|
||||||
|
{
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
public int WriteMonoSample ( short[] SampleData )
|
||||||
|
{
|
||||||
|
switch ( wave_format.data.nBitsPerSample )
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
pcm_data.ckSize += 1;
|
||||||
|
return Write ( SampleData, 1 );
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
pcm_data.ckSize += 2;
|
||||||
|
return Write ( SampleData, 2 );
|
||||||
|
}
|
||||||
|
return DDC_INVALID_CALL;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
public int WriteStereoSample ( short[] LeftSample, short[] RightSample )
|
||||||
|
{
|
||||||
|
int retcode = DDC_SUCCESS;
|
||||||
|
switch ( wave_format.data.nBitsPerSample )
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
retcode = Write ( LeftSample, 1 );
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
retcode = Write ( RightSample, 1 );
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
pcm_data.ckSize += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
retcode = Write ( LeftSample, 2 );
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
retcode = Write ( RightSample, 2 );
|
||||||
|
if ( retcode == DDC_SUCCESS )
|
||||||
|
{
|
||||||
|
pcm_data.ckSize += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
retcode = DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
return retcode;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
public int ReadMonoSample ( short[] Sample )
|
||||||
|
{
|
||||||
|
int retcode = DDC_SUCCESS;
|
||||||
|
switch ( wave_format.data.nBitsPerSample )
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
byte[] x = {0};
|
||||||
|
retcode = Read ( x, 1 );
|
||||||
|
Sample[0] = (short)(x[0]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
retcode = Read ( Sample, 2 );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
retcode = DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
return retcode;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
public int ReadStereoSample ( short[] LeftSampleData, short[] RightSampleData )
|
||||||
|
{
|
||||||
|
int retcode = DDC_SUCCESS;
|
||||||
|
byte[] x = new byte[2];
|
||||||
|
short[] y = new short[2];
|
||||||
|
switch ( wave_format.data.nBitsPerSample )
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
retcode = Read ( x, 2 );
|
||||||
|
L[0] = (short) ( x[0] );
|
||||||
|
R[0] = (short) ( x[1] );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
retcode = Read ( y, 4 );
|
||||||
|
L[0] = (short) ( y[0] );
|
||||||
|
R[0] = (short) ( y[1] );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
retcode = DDC_INVALID_CALL;
|
||||||
|
}
|
||||||
|
return retcode;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public int Close()
|
||||||
|
{
|
||||||
|
int rc = DDC_SUCCESS;
|
||||||
|
|
||||||
|
if ( fmode == RFM_WRITE )
|
||||||
|
rc = Backpatch ( pcm_data_offset, pcm_data, 8 );
|
||||||
|
if ( rc == DDC_SUCCESS )
|
||||||
|
rc = super.Close();
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [Hz]
|
||||||
|
public int SamplingRate()
|
||||||
|
{return wave_format.data.nSamplesPerSec;}
|
||||||
|
|
||||||
|
public short BitsPerSample()
|
||||||
|
{return wave_format.data.nBitsPerSample;}
|
||||||
|
|
||||||
|
public short NumChannels()
|
||||||
|
{return wave_format.data.nChannels;}
|
||||||
|
|
||||||
|
public int NumSamples()
|
||||||
|
{return num_samples;}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open for write using another wave file's parameters...
|
||||||
|
*/
|
||||||
|
public int OpenForWrite (String Filename, WaveFile OtherWave )
|
||||||
|
{
|
||||||
|
return OpenForWrite ( Filename,
|
||||||
|
OtherWave.SamplingRate(),
|
||||||
|
OtherWave.BitsPerSample(),
|
||||||
|
OtherWave.NumChannels() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public long CurrentFilePosition()
|
||||||
|
{
|
||||||
|
return super.CurrentFilePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public int FourCC(String ChunkName)
|
||||||
|
{
|
||||||
|
byte[] p = {0x20,0x20,0x20,0x20};
|
||||||
|
ChunkName.getBytes(0,4,p,0);
|
||||||
|
int ret = (((p[0] << 24)& 0xFF000000) | ((p[1] << 16)&0x00FF0000) | ((p[2] << 8)&0x0000FF00) | (p[3]&0x000000FF));
|
||||||
|
return ret;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
141
src/javazoom/jl/converter/WaveFileObuffer.java
Normal file
141
src/javazoom/jl/converter/WaveFileObuffer.java
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*
|
||||||
|
* 12/12/99 0.0.7 Renamed class, additional constructor arguments
|
||||||
|
* and larger write buffers. mdm@techie.com.
|
||||||
|
*
|
||||||
|
* 15/02/99 Java Conversion by E.B ,javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.converter;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.Obuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements an Obuffer by writing the data to
|
||||||
|
* a file in RIFF WAVE format.
|
||||||
|
*
|
||||||
|
* @since 0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
public class WaveFileObuffer extends Obuffer
|
||||||
|
{
|
||||||
|
private short[] buffer;
|
||||||
|
private short[] bufferp;
|
||||||
|
private int channels;
|
||||||
|
private WaveFile outWave;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new WareFileObuffer instance.
|
||||||
|
*
|
||||||
|
* @param number_of_channels
|
||||||
|
* The number of channels of audio data
|
||||||
|
* this buffer will receive.
|
||||||
|
*
|
||||||
|
* @param freq The sample frequency of the samples in the buffer.
|
||||||
|
*
|
||||||
|
* @param fileName The filename to write the data to.
|
||||||
|
*/
|
||||||
|
public WaveFileObuffer(int number_of_channels, int freq, String FileName)
|
||||||
|
{
|
||||||
|
if (FileName==null)
|
||||||
|
throw new NullPointerException("FileName");
|
||||||
|
|
||||||
|
buffer = new short[OBUFFERSIZE];
|
||||||
|
bufferp = new short[MAXCHANNELS];
|
||||||
|
channels = number_of_channels;
|
||||||
|
|
||||||
|
for (int i = 0; i < number_of_channels; ++i)
|
||||||
|
bufferp[i] = (short)i;
|
||||||
|
|
||||||
|
outWave = new WaveFile();
|
||||||
|
|
||||||
|
int rc = outWave.OpenForWrite (FileName,freq,(short)16,(short)channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a 16 Bit PCM sample.
|
||||||
|
*/
|
||||||
|
public void append(int channel, short value)
|
||||||
|
{
|
||||||
|
buffer[bufferp[channel]] = value;
|
||||||
|
bufferp[channel] += channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the samples to the file (Random Acces).
|
||||||
|
*/
|
||||||
|
short[] myBuffer = new short[2];
|
||||||
|
public void write_buffer(int val)
|
||||||
|
{
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
rc = outWave.WriteData(buffer, bufferp[0]);
|
||||||
|
// REVIEW: handle RiffFile errors.
|
||||||
|
/*
|
||||||
|
for (int j=0;j<bufferp[0];j=j+2)
|
||||||
|
{
|
||||||
|
|
||||||
|
//myBuffer[0] = (short)(((buffer[j]>>8)&0x000000FF) | ((buffer[j]<<8)&0x0000FF00));
|
||||||
|
//myBuffer[1] = (short) (((buffer[j+1]>>8)&0x000000FF) | ((buffer[j+1]<<8)&0x0000FF00));
|
||||||
|
myBuffer[0] = buffer[j];
|
||||||
|
myBuffer[1] = buffer[j+1];
|
||||||
|
rc = outWave.WriteData (myBuffer,2);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < channels; ++i) bufferp[i] = (short)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
outWave.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void clear_buffer()
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void set_stop_flag()
|
||||||
|
{}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create STDOUT buffer
|
||||||
|
*
|
||||||
|
*
|
||||||
|
public static Obuffer create_stdout_obuffer(MPEG_Args maplay_args)
|
||||||
|
{
|
||||||
|
Obuffer thebuffer = null;
|
||||||
|
int mode = maplay_args.MPEGheader.mode();
|
||||||
|
int which_channels = maplay_args.which_c;
|
||||||
|
if (mode == Header.single_channel || which_channels != MPEG_Args.both)
|
||||||
|
thebuffer = new FileObuffer(1,maplay_args.output_filename);
|
||||||
|
else
|
||||||
|
thebuffer = new FileObuffer(2,maplay_args.output_filename);
|
||||||
|
return(thebuffer);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
216
src/javazoom/jl/converter/jlc.java
Normal file
216
src/javazoom/jl/converter/jlc.java
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*
|
||||||
|
* 12/12/99 JavaLayer 0.0.7 mdm@techie.com
|
||||||
|
*
|
||||||
|
* 14/02/99 MPEG_Args Based Class - E.B
|
||||||
|
* Adapted from javalayer and MPEG_Args.
|
||||||
|
* Doc'ed and integerated with JL converter. Removed
|
||||||
|
* Win32 specifics from original Maplay code.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.converter;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.Crc16;
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
import javazoom.jl.decoder.OutputChannels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>jlc</code> class presents the JavaLayer
|
||||||
|
* Conversion functionality as a command-line program.
|
||||||
|
*
|
||||||
|
* @since 0.0.7
|
||||||
|
*/
|
||||||
|
public class jlc
|
||||||
|
{
|
||||||
|
|
||||||
|
static public void main(String args[])
|
||||||
|
{
|
||||||
|
String[] argv;
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
int argc = args.length + 1;
|
||||||
|
argv = new String[argc];
|
||||||
|
argv[0] = "jlc";
|
||||||
|
for(int i=0;i<args.length;i++)
|
||||||
|
argv[i+1] = args[i];
|
||||||
|
|
||||||
|
jlcArgs ma = new jlcArgs();
|
||||||
|
if (!ma.processArgs(argv))
|
||||||
|
System.exit(1);
|
||||||
|
|
||||||
|
Converter conv = new Converter();
|
||||||
|
|
||||||
|
int detail = (ma.verbose_mode ?
|
||||||
|
ma.verbose_level :
|
||||||
|
Converter.PrintWriterProgressListener.NO_DETAIL);
|
||||||
|
|
||||||
|
Converter.ProgressListener listener =
|
||||||
|
new Converter.PrintWriterProgressListener(
|
||||||
|
new PrintWriter(System.out, true), detail);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
conv.convert(ma.filename, ma.output_filename, listener);
|
||||||
|
}
|
||||||
|
catch (JavaLayerException ex)
|
||||||
|
{
|
||||||
|
System.err.println("Convertion failure: "+ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to contain arguments for maplay.
|
||||||
|
*/
|
||||||
|
static class jlcArgs
|
||||||
|
{
|
||||||
|
// channel constants moved into OutputChannels class.
|
||||||
|
//public static final int both = 0;
|
||||||
|
//public static final int left = 1;
|
||||||
|
//public static final int right = 2;
|
||||||
|
//public static final int downmix = 3;
|
||||||
|
|
||||||
|
public int which_c;
|
||||||
|
public int output_mode;
|
||||||
|
public boolean use_own_scalefactor;
|
||||||
|
public float scalefactor;
|
||||||
|
public String output_filename;
|
||||||
|
public String filename;
|
||||||
|
//public boolean stdout_mode;
|
||||||
|
public boolean verbose_mode;
|
||||||
|
public int verbose_level = 3;
|
||||||
|
|
||||||
|
public jlcArgs()
|
||||||
|
{
|
||||||
|
which_c = OutputChannels.BOTH_CHANNELS;
|
||||||
|
use_own_scalefactor = false;
|
||||||
|
scalefactor = (float) 32768.0;
|
||||||
|
//stdout_mode = false;
|
||||||
|
verbose_mode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process user arguments.
|
||||||
|
*
|
||||||
|
* Returns true if successful.
|
||||||
|
*/
|
||||||
|
public boolean processArgs(String[] argv)
|
||||||
|
{
|
||||||
|
filename = null;
|
||||||
|
Crc16[] crc;
|
||||||
|
crc = new Crc16[1];
|
||||||
|
int i;
|
||||||
|
int argc = argv.length;
|
||||||
|
|
||||||
|
//stdout_mode = false;
|
||||||
|
verbose_mode = false;
|
||||||
|
output_mode = OutputChannels.BOTH_CHANNELS;
|
||||||
|
output_filename = "";
|
||||||
|
if (argc < 2 || argv[1].equals("-h"))
|
||||||
|
return Usage();
|
||||||
|
|
||||||
|
i = 1;
|
||||||
|
while (i < argc)
|
||||||
|
{
|
||||||
|
/* System.out.println("Option = "+argv[i]);*/
|
||||||
|
if (argv[i].charAt(0) == '-')
|
||||||
|
{
|
||||||
|
if (argv[i].startsWith("-v"))
|
||||||
|
{
|
||||||
|
verbose_mode = true;
|
||||||
|
if (argv[i].length()>2)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String level = argv[i].substring(2);
|
||||||
|
verbose_level = Integer.parseInt(level);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException ex)
|
||||||
|
{
|
||||||
|
System.err.println("Invalid verbose level. Using default.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Verbose Activated (level "+verbose_level+")");
|
||||||
|
}
|
||||||
|
/* else if (argv[i].equals("-s"))
|
||||||
|
ma.stdout_mode = true; */
|
||||||
|
else if (argv[i].equals("-p"))
|
||||||
|
{
|
||||||
|
if (++i == argc)
|
||||||
|
{
|
||||||
|
System.out.println("Please specify an output filename after the -p option!");
|
||||||
|
System.exit (1);
|
||||||
|
}
|
||||||
|
//output_mode = O_WAVEFILE;
|
||||||
|
output_filename = argv[i];
|
||||||
|
}
|
||||||
|
/*else if (argv[i].equals("-f"))
|
||||||
|
{
|
||||||
|
if (++i == argc)
|
||||||
|
{
|
||||||
|
System.out.println("Please specify a new scalefactor after the -f option!");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
ma.use_own_scalefactor = true;
|
||||||
|
// ma.scalefactor = argv[i];
|
||||||
|
}*/
|
||||||
|
else return Usage();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filename = argv[i];
|
||||||
|
System.out.println("FileName = "+argv[i]);
|
||||||
|
if (filename == null) return Usage();
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (filename == null)
|
||||||
|
return Usage();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usage of JavaLayer.
|
||||||
|
*/
|
||||||
|
public boolean Usage()
|
||||||
|
{
|
||||||
|
System.out.println("JavaLayer Converter :");
|
||||||
|
System.out.println(" -v[x] verbose mode. ");
|
||||||
|
System.out.println(" default = 2");
|
||||||
|
/* System.out.println(" -s write u-law samples at 8 kHz rate to stdout");
|
||||||
|
System.out.println(" -l decode only the left channel");
|
||||||
|
System.out.println(" -r decode only the right channel");
|
||||||
|
System.out.println(" -d downmix mode (layer III only)");
|
||||||
|
System.out.println(" -s write pcm samples to stdout");
|
||||||
|
System.out.println(" -d downmix mode (layer III only)");*/
|
||||||
|
System.out.println(" -p name output as a PCM wave file");
|
||||||
|
System.out.println("");
|
||||||
|
System.out.println(" More info on http://www.javazoom.net");
|
||||||
|
/* System.out.println(" -f ushort use this scalefactor instead of the default value 32768");*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
223
src/javazoom/jl/decoder/BitReserve.java
Normal file
223
src/javazoom/jl/decoder/BitReserve.java
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*
|
||||||
|
* 12/12/99 0.0.7 Implementation stores single bits
|
||||||
|
* as ints for better performance. mdm@techie.com.
|
||||||
|
*
|
||||||
|
* 02/28/99 0.0 Java Conversion by E.B, javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
* Adapted from the public c code by Jeff Tsay.
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of Bit Reservoir for Layer III.
|
||||||
|
* <p>
|
||||||
|
* The implementation stores single bits as a word in the buffer. If
|
||||||
|
* a bit is set, the corresponding word in the buffer will be non-zero.
|
||||||
|
* If a bit is clear, the corresponding word is zero. Although this
|
||||||
|
* may seem waseful, this can be a factor of two quicker than
|
||||||
|
* packing 8 bits to a byte and extracting.
|
||||||
|
* <p>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// REVIEW: there is no range checking, so buffer underflow or overflow
|
||||||
|
// can silently occur.
|
||||||
|
final class BitReserve
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Size of the internal buffer to store the reserved bits.
|
||||||
|
* Must be a power of 2. And x8, as each bit is stored as a single
|
||||||
|
* entry.
|
||||||
|
*/
|
||||||
|
private static final int BUFSIZE = 4096*8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mask that can be used to quickly implement the
|
||||||
|
* modulus operation on BUFSIZE.
|
||||||
|
*/
|
||||||
|
private static final int BUFSIZE_MASK = BUFSIZE-1;
|
||||||
|
|
||||||
|
private int offset, totbit, buf_byte_idx;
|
||||||
|
private final int[] buf = new int[BUFSIZE];
|
||||||
|
private int buf_bit_idx;
|
||||||
|
|
||||||
|
BitReserve()
|
||||||
|
{
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
totbit = 0;
|
||||||
|
buf_byte_idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return totbit Field.
|
||||||
|
*/
|
||||||
|
public int hsstell()
|
||||||
|
{
|
||||||
|
return(totbit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a number bits from the bit stream.
|
||||||
|
* @param N the number of
|
||||||
|
*/
|
||||||
|
public int hgetbits(int N)
|
||||||
|
{
|
||||||
|
totbit += N;
|
||||||
|
|
||||||
|
int val = 0;
|
||||||
|
|
||||||
|
int pos = buf_byte_idx;
|
||||||
|
if (pos+N < BUFSIZE)
|
||||||
|
{
|
||||||
|
while (N-- > 0)
|
||||||
|
{
|
||||||
|
val <<= 1;
|
||||||
|
val |= ((buf[pos++]!=0) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (N-- > 0)
|
||||||
|
{
|
||||||
|
val <<= 1;
|
||||||
|
val |= ((buf[pos]!=0) ? 1 : 0);
|
||||||
|
pos = (pos+1) & BUFSIZE_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf_byte_idx = pos;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read 1 bit from the bit stream.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
public int hget1bit_old()
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
totbit++;
|
||||||
|
if (buf_bit_idx == 0)
|
||||||
|
{
|
||||||
|
buf_bit_idx = 8;
|
||||||
|
buf_byte_idx++;
|
||||||
|
}
|
||||||
|
// BUFSIZE = 4096 = 2^12, so
|
||||||
|
// buf_byte_idx%BUFSIZE == buf_byte_idx & 0xfff
|
||||||
|
val = buf[buf_byte_idx & BUFSIZE_MASK] & putmask[buf_bit_idx];
|
||||||
|
buf_bit_idx--;
|
||||||
|
val = val >>> buf_bit_idx;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Returns next bit from reserve.
|
||||||
|
* @returns 0 if next bit is reset, or 1 if next bit is set.
|
||||||
|
*/
|
||||||
|
public int hget1bit()
|
||||||
|
{
|
||||||
|
totbit++;
|
||||||
|
int val = buf[buf_byte_idx];
|
||||||
|
buf_byte_idx = (buf_byte_idx+1) & BUFSIZE_MASK;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves bits from the reserve.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
public int readBits(int[] out, int len)
|
||||||
|
{
|
||||||
|
if (buf_bit_idx == 0)
|
||||||
|
{
|
||||||
|
buf_bit_idx = 8;
|
||||||
|
buf_byte_idx++;
|
||||||
|
current = buf[buf_byte_idx & BUFSIZE_MASK];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// save total number of bits returned
|
||||||
|
len = buf_bit_idx;
|
||||||
|
buf_bit_idx = 0;
|
||||||
|
|
||||||
|
int b = current;
|
||||||
|
int count = len-1;
|
||||||
|
|
||||||
|
while (count >= 0)
|
||||||
|
{
|
||||||
|
out[count--] = (b & 0x1);
|
||||||
|
b >>>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
totbit += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write 8 bits into the bit stream.
|
||||||
|
*/
|
||||||
|
public void hputbuf(int val)
|
||||||
|
{
|
||||||
|
int ofs = offset;
|
||||||
|
buf[ofs++] = val & 0x80;
|
||||||
|
buf[ofs++] = val & 0x40;
|
||||||
|
buf[ofs++] = val & 0x20;
|
||||||
|
buf[ofs++] = val & 0x10;
|
||||||
|
buf[ofs++] = val & 0x08;
|
||||||
|
buf[ofs++] = val & 0x04;
|
||||||
|
buf[ofs++] = val & 0x02;
|
||||||
|
buf[ofs++] = val & 0x01;
|
||||||
|
|
||||||
|
if (ofs==BUFSIZE)
|
||||||
|
offset = 0;
|
||||||
|
else
|
||||||
|
offset = ofs;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewind N bits in Stream.
|
||||||
|
*/
|
||||||
|
public void rewindNbits(int N)
|
||||||
|
{
|
||||||
|
totbit -= N;
|
||||||
|
buf_byte_idx -= N;
|
||||||
|
if (buf_byte_idx<0)
|
||||||
|
buf_byte_idx += BUFSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewind N bytes in Stream.
|
||||||
|
*/
|
||||||
|
public void rewindNbytes(int N)
|
||||||
|
{
|
||||||
|
int bits = (N << 3);
|
||||||
|
totbit -= bits;
|
||||||
|
buf_byte_idx -= bits;
|
||||||
|
if (buf_byte_idx<0)
|
||||||
|
buf_byte_idx += BUFSIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
655
src/javazoom/jl/decoder/Bitstream.java
Normal file
655
src/javazoom/jl/decoder/Bitstream.java
Normal file
@@ -0,0 +1,655 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*
|
||||||
|
* 11/17/04 Uncomplete frames discarded. E.B, javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
* 12/05/03 ID3v2 tag returned. E.B, javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
* 12/12/99 Based on Ibitstream. Exceptions thrown on errors,
|
||||||
|
* Temporary removed seek functionality. mdm@techie.com
|
||||||
|
*
|
||||||
|
* 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
* 04/14/97 : Added function prototypes for new syncing and seeking
|
||||||
|
* mechanisms. Also made this file portable. Changes made by Jeff Tsay
|
||||||
|
*
|
||||||
|
* @(#) ibitstream.h 1.5, last edit: 6/15/94 16:55:34
|
||||||
|
* @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
|
||||||
|
* @(#) Berlin University of Technology
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PushbackInputStream;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>Bistream</code> class is responsible for parsing
|
||||||
|
* an MPEG audio bitstream.
|
||||||
|
*
|
||||||
|
* <b>REVIEW:</b> much of the parsing currently occurs in the
|
||||||
|
* various decoders. This should be moved into this class and associated
|
||||||
|
* inner classes.
|
||||||
|
*/
|
||||||
|
public final class Bitstream implements BitstreamErrors
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Synchronization control constant for the initial
|
||||||
|
* synchronization to the start of a frame.
|
||||||
|
*/
|
||||||
|
static byte INITIAL_SYNC = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronization control constant for non-initial frame
|
||||||
|
* synchronizations.
|
||||||
|
*/
|
||||||
|
static byte STRICT_SYNC = 1;
|
||||||
|
|
||||||
|
// max. 1730 bytes per frame: 144 * 384kbit/s / 32000 Hz + 2 Bytes CRC
|
||||||
|
/**
|
||||||
|
* Maximum size of the frame buffer.
|
||||||
|
*/
|
||||||
|
private static final int BUFFER_INT_SIZE = 433;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The frame buffer that holds the data for the current frame.
|
||||||
|
*/
|
||||||
|
private final int[] framebuffer = new int[BUFFER_INT_SIZE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of valid bytes in the frame buffer.
|
||||||
|
*/
|
||||||
|
private int framesize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bytes read from the stream.
|
||||||
|
*/
|
||||||
|
private byte[] frame_bytes = new byte[BUFFER_INT_SIZE*4];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index into <code>framebuffer</code> where the next bits are
|
||||||
|
* retrieved.
|
||||||
|
*/
|
||||||
|
private int wordpointer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number (0-31, from MSB to LSB) of next bit for get_bits()
|
||||||
|
*/
|
||||||
|
private int bitindex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current specified syncword
|
||||||
|
*/
|
||||||
|
private int syncword;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Audio header position in stream.
|
||||||
|
*/
|
||||||
|
private int header_pos = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private boolean single_ch_mode;
|
||||||
|
//private int current_frame_number;
|
||||||
|
//private int last_frame_number;
|
||||||
|
|
||||||
|
private final int bitmask[] = {0, // dummy
|
||||||
|
0x00000001, 0x00000003, 0x00000007, 0x0000000F,
|
||||||
|
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
|
||||||
|
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
|
||||||
|
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
|
||||||
|
0x0001FFFF };
|
||||||
|
|
||||||
|
private final PushbackInputStream source;
|
||||||
|
|
||||||
|
private final Header header = new Header();
|
||||||
|
|
||||||
|
private final byte syncbuf[] = new byte[4];
|
||||||
|
|
||||||
|
private Crc16[] crc = new Crc16[1];
|
||||||
|
|
||||||
|
private byte[] rawid3v2 = null;
|
||||||
|
|
||||||
|
private boolean firstframe = true;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a IBitstream that reads data from a
|
||||||
|
* given InputStream.
|
||||||
|
*
|
||||||
|
* @param in The InputStream to read from.
|
||||||
|
*/
|
||||||
|
public Bitstream(InputStream in)
|
||||||
|
{
|
||||||
|
if (in==null) throw new NullPointerException("in");
|
||||||
|
in = new BufferedInputStream(in);
|
||||||
|
loadID3v2(in);
|
||||||
|
firstframe = true;
|
||||||
|
//source = new PushbackInputStream(in, 1024);
|
||||||
|
source = new PushbackInputStream(in, BUFFER_INT_SIZE*4);
|
||||||
|
|
||||||
|
closeFrame();
|
||||||
|
//current_frame_number = -1;
|
||||||
|
//last_frame_number = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return position of the first audio header.
|
||||||
|
* @return size of ID3v2 tag frames.
|
||||||
|
*/
|
||||||
|
public int header_pos()
|
||||||
|
{
|
||||||
|
return header_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load ID3v2 frames.
|
||||||
|
* @param in MP3 InputStream.
|
||||||
|
* @author JavaZOOM
|
||||||
|
*/
|
||||||
|
private void loadID3v2(InputStream in)
|
||||||
|
{
|
||||||
|
int size = -1;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Read ID3v2 header (10 bytes).
|
||||||
|
in.mark(10);
|
||||||
|
size = readID3v2Header(in);
|
||||||
|
header_pos = size;
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Unread ID3v2 header (10 bytes).
|
||||||
|
in.reset();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
// Load ID3v2 tags.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
rawid3v2 = new byte[size];
|
||||||
|
in.read(rawid3v2,0,rawid3v2.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse ID3v2 tag header to find out size of ID3v2 frames.
|
||||||
|
* @param in MP3 InputStream
|
||||||
|
* @return size of ID3v2 frames + header
|
||||||
|
* @throws IOException
|
||||||
|
* @author JavaZOOM
|
||||||
|
*/
|
||||||
|
private int readID3v2Header(InputStream in) throws IOException
|
||||||
|
{
|
||||||
|
byte[] id3header = new byte[4];
|
||||||
|
int size = -10;
|
||||||
|
in.read(id3header,0,3);
|
||||||
|
// Look for ID3v2
|
||||||
|
if ( (id3header[0]=='I') && (id3header[1]=='D') && (id3header[2]=='3'))
|
||||||
|
{
|
||||||
|
in.read(id3header,0,3);
|
||||||
|
int majorVersion = id3header[0];
|
||||||
|
int revision = id3header[1];
|
||||||
|
in.read(id3header,0,4);
|
||||||
|
size = (int) (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]);
|
||||||
|
}
|
||||||
|
return (size+10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return raw ID3v2 frames + header.
|
||||||
|
* @return ID3v2 InputStream or null if ID3v2 frames are not available.
|
||||||
|
*/
|
||||||
|
public InputStream getRawID3v2()
|
||||||
|
{
|
||||||
|
if (rawid3v2 == null) return null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ByteArrayInputStream bain = new ByteArrayInputStream(rawid3v2);
|
||||||
|
return bain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the Bitstream.
|
||||||
|
* @throws BitstreamException
|
||||||
|
*/
|
||||||
|
public void close() throws BitstreamException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
source.close();
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
throw newBitstreamException(STREAM_ERROR, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads and parses the next frame from the input source.
|
||||||
|
* @return the Header describing details of the frame read,
|
||||||
|
* or null if the end of the stream has been reached.
|
||||||
|
*/
|
||||||
|
public Header readFrame() throws BitstreamException
|
||||||
|
{
|
||||||
|
Header result = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = readNextFrame();
|
||||||
|
// E.B, Parse VBR (if any) first frame.
|
||||||
|
if (firstframe == true)
|
||||||
|
{
|
||||||
|
result.parseVBR(frame_bytes);
|
||||||
|
firstframe = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (BitstreamException ex)
|
||||||
|
{
|
||||||
|
if ((ex.getErrorCode()==INVALIDFRAME))
|
||||||
|
{
|
||||||
|
// Try to skip this frame.
|
||||||
|
//System.out.println("INVALIDFRAME");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
closeFrame();
|
||||||
|
result = readNextFrame();
|
||||||
|
}
|
||||||
|
catch (BitstreamException e)
|
||||||
|
{
|
||||||
|
if ((e.getErrorCode()!=STREAM_EOF))
|
||||||
|
{
|
||||||
|
// wrap original exception so stack trace is maintained.
|
||||||
|
throw newBitstreamException(e.getErrorCode(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((ex.getErrorCode()!=STREAM_EOF))
|
||||||
|
{
|
||||||
|
// wrap original exception so stack trace is maintained.
|
||||||
|
throw newBitstreamException(ex.getErrorCode(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read next MP3 frame.
|
||||||
|
* @return MP3 frame header.
|
||||||
|
* @throws BitstreamException
|
||||||
|
*/
|
||||||
|
private Header readNextFrame() throws BitstreamException
|
||||||
|
{
|
||||||
|
if (framesize == -1)
|
||||||
|
{
|
||||||
|
nextFrame();
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read next MP3 frame.
|
||||||
|
* @throws BitstreamException
|
||||||
|
*/
|
||||||
|
private void nextFrame() throws BitstreamException
|
||||||
|
{
|
||||||
|
// entire frame is read by the header class.
|
||||||
|
header.read_header(this, crc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unreads the bytes read from the frame.
|
||||||
|
* @throws BitstreamException
|
||||||
|
*/
|
||||||
|
// REVIEW: add new error codes for this.
|
||||||
|
public void unreadFrame() throws BitstreamException
|
||||||
|
{
|
||||||
|
if (wordpointer==-1 && bitindex==-1 && (framesize>0))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
source.unread(frame_bytes, 0, framesize);
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
throw newBitstreamException(STREAM_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close MP3 frame.
|
||||||
|
*/
|
||||||
|
public void closeFrame()
|
||||||
|
{
|
||||||
|
framesize = -1;
|
||||||
|
wordpointer = -1;
|
||||||
|
bitindex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the next 4 bytes of the stream represent a
|
||||||
|
* frame header.
|
||||||
|
*/
|
||||||
|
public boolean isSyncCurrentPosition(int syncmode) throws BitstreamException
|
||||||
|
{
|
||||||
|
int read = readBytes(syncbuf, 0, 4);
|
||||||
|
int headerstring = ((syncbuf[0] << 24) & 0xFF000000) | ((syncbuf[1] << 16) & 0x00FF0000) | ((syncbuf[2] << 8) & 0x0000FF00) | ((syncbuf[3] << 0) & 0x000000FF);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
source.unread(syncbuf, 0, read);
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean sync = false;
|
||||||
|
switch (read)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
sync = true;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
sync = isSyncMark(headerstring, syncmode, syncword);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// REVIEW: this class should provide inner classes to
|
||||||
|
// parse the frame contents. Eventually, readBits will
|
||||||
|
// be removed.
|
||||||
|
public int readBits(int n)
|
||||||
|
{
|
||||||
|
return get_bits(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readCheckedBits(int n)
|
||||||
|
{
|
||||||
|
// REVIEW: implement CRC check.
|
||||||
|
return get_bits(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BitstreamException newBitstreamException(int errorcode)
|
||||||
|
{
|
||||||
|
return new BitstreamException(errorcode, null);
|
||||||
|
}
|
||||||
|
protected BitstreamException newBitstreamException(int errorcode, Throwable throwable)
|
||||||
|
{
|
||||||
|
return new BitstreamException(errorcode, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get next 32 bits from bitstream.
|
||||||
|
* They are stored in the headerstring.
|
||||||
|
* syncmod allows Synchro flag ID
|
||||||
|
* The returned value is False at the end of stream.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int syncHeader(byte syncmode) throws BitstreamException
|
||||||
|
{
|
||||||
|
boolean sync;
|
||||||
|
int headerstring;
|
||||||
|
// read additional 2 bytes
|
||||||
|
int bytesRead = readBytes(syncbuf, 0, 3);
|
||||||
|
|
||||||
|
if (bytesRead!=3) throw newBitstreamException(STREAM_EOF, null);
|
||||||
|
|
||||||
|
headerstring = ((syncbuf[0] << 16) & 0x00FF0000) | ((syncbuf[1] << 8) & 0x0000FF00) | ((syncbuf[2] << 0) & 0x000000FF);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
headerstring <<= 8;
|
||||||
|
|
||||||
|
if (readBytes(syncbuf, 3, 1)!=1)
|
||||||
|
throw newBitstreamException(STREAM_EOF, null);
|
||||||
|
|
||||||
|
headerstring |= (syncbuf[3] & 0x000000FF);
|
||||||
|
|
||||||
|
sync = isSyncMark(headerstring, syncmode, syncword);
|
||||||
|
}
|
||||||
|
while (!sync);
|
||||||
|
|
||||||
|
//current_frame_number++;
|
||||||
|
//if (last_frame_number < current_frame_number) last_frame_number = current_frame_number;
|
||||||
|
|
||||||
|
return headerstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSyncMark(int headerstring, int syncmode, int word)
|
||||||
|
{
|
||||||
|
boolean sync = false;
|
||||||
|
|
||||||
|
if (syncmode == INITIAL_SYNC)
|
||||||
|
{
|
||||||
|
//sync = ((headerstring & 0xFFF00000) == 0xFFF00000);
|
||||||
|
sync = ((headerstring & 0xFFE00000) == 0xFFE00000); // SZD: MPEG 2.5
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sync = ((headerstring & 0xFFF80C00) == word) &&
|
||||||
|
(((headerstring & 0x000000C0) == 0x000000C0) == single_ch_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter out invalid sample rate
|
||||||
|
if (sync)
|
||||||
|
sync = (((headerstring >>> 10) & 3)!=3);
|
||||||
|
// filter out invalid layer
|
||||||
|
if (sync)
|
||||||
|
sync = (((headerstring >>> 17) & 3)!=0);
|
||||||
|
// filter out invalid version
|
||||||
|
if (sync)
|
||||||
|
sync = (((headerstring >>> 19) & 3)!=1);
|
||||||
|
|
||||||
|
return sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the data for the next frame. The frame is not parsed
|
||||||
|
* until parse frame is called.
|
||||||
|
*/
|
||||||
|
int read_frame_data(int bytesize) throws BitstreamException
|
||||||
|
{
|
||||||
|
int numread = 0;
|
||||||
|
numread = readFully(frame_bytes, 0, bytesize);
|
||||||
|
framesize = bytesize;
|
||||||
|
wordpointer = -1;
|
||||||
|
bitindex = -1;
|
||||||
|
return numread;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the data previously read with read_frame_data().
|
||||||
|
*/
|
||||||
|
void parse_frame() throws BitstreamException
|
||||||
|
{
|
||||||
|
// Convert Bytes read to int
|
||||||
|
int b=0;
|
||||||
|
byte[] byteread = frame_bytes;
|
||||||
|
int bytesize = framesize;
|
||||||
|
|
||||||
|
// Check ID3v1 TAG (True only if last frame).
|
||||||
|
//for (int t=0;t<(byteread.length)-2;t++)
|
||||||
|
//{
|
||||||
|
// if ((byteread[t]=='T') && (byteread[t+1]=='A') && (byteread[t+2]=='G'))
|
||||||
|
// {
|
||||||
|
// System.out.println("ID3v1 detected at offset "+t);
|
||||||
|
// throw newBitstreamException(INVALIDFRAME, null);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
for (int k=0;k<bytesize;k=k+4)
|
||||||
|
{
|
||||||
|
int convert = 0;
|
||||||
|
byte b0 = 0;
|
||||||
|
byte b1 = 0;
|
||||||
|
byte b2 = 0;
|
||||||
|
byte b3 = 0;
|
||||||
|
b0 = byteread[k];
|
||||||
|
if (k+1<bytesize) b1 = byteread[k+1];
|
||||||
|
if (k+2<bytesize) b2 = byteread[k+2];
|
||||||
|
if (k+3<bytesize) b3 = byteread[k+3];
|
||||||
|
framebuffer[b++] = ((b0 << 24) &0xFF000000) | ((b1 << 16) & 0x00FF0000) | ((b2 << 8) & 0x0000FF00) | (b3 & 0x000000FF);
|
||||||
|
}
|
||||||
|
wordpointer = 0;
|
||||||
|
bitindex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read bits from buffer into the lower bits of an unsigned int.
|
||||||
|
* The LSB contains the latest read bit of the stream.
|
||||||
|
* (1 <= number_of_bits <= 16)
|
||||||
|
*/
|
||||||
|
public int get_bits(int number_of_bits)
|
||||||
|
{
|
||||||
|
int returnvalue = 0;
|
||||||
|
int sum = bitindex + number_of_bits;
|
||||||
|
|
||||||
|
// E.B
|
||||||
|
// There is a problem here, wordpointer could be -1 ?!
|
||||||
|
if (wordpointer < 0) wordpointer = 0;
|
||||||
|
// E.B : End.
|
||||||
|
|
||||||
|
if (sum <= 32)
|
||||||
|
{
|
||||||
|
// all bits contained in *wordpointer
|
||||||
|
returnvalue = (framebuffer[wordpointer] >>> (32 - sum)) & bitmask[number_of_bits];
|
||||||
|
// returnvalue = (wordpointer[0] >> (32 - sum)) & bitmask[number_of_bits];
|
||||||
|
if ((bitindex += number_of_bits) == 32)
|
||||||
|
{
|
||||||
|
bitindex = 0;
|
||||||
|
wordpointer++; // added by me!
|
||||||
|
}
|
||||||
|
return returnvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// E.B : Check that ?
|
||||||
|
//((short[])&returnvalue)[0] = ((short[])wordpointer + 1)[0];
|
||||||
|
//wordpointer++; // Added by me!
|
||||||
|
//((short[])&returnvalue + 1)[0] = ((short[])wordpointer)[0];
|
||||||
|
int Right = (framebuffer[wordpointer] & 0x0000FFFF);
|
||||||
|
wordpointer++;
|
||||||
|
int Left = (framebuffer[wordpointer] & 0xFFFF0000);
|
||||||
|
returnvalue = ((Right << 16) & 0xFFFF0000) | ((Left >>> 16)& 0x0000FFFF);
|
||||||
|
|
||||||
|
returnvalue >>>= 48 - sum; // returnvalue >>= 16 - (number_of_bits - (32 - bitindex))
|
||||||
|
returnvalue &= bitmask[number_of_bits];
|
||||||
|
bitindex = sum - 32;
|
||||||
|
return returnvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the word we want to sync the header to.
|
||||||
|
* In Big-Endian byte order
|
||||||
|
*/
|
||||||
|
void set_syncword(int syncword0)
|
||||||
|
{
|
||||||
|
syncword = syncword0 & 0xFFFFFF3F;
|
||||||
|
single_ch_mode = ((syncword0 & 0x000000C0) == 0x000000C0);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Reads the exact number of bytes from the source
|
||||||
|
* input stream into a byte array.
|
||||||
|
*
|
||||||
|
* @param b The byte array to read the specified number
|
||||||
|
* of bytes into.
|
||||||
|
* @param offs The index in the array where the first byte
|
||||||
|
* read should be stored.
|
||||||
|
* @param len the number of bytes to read.
|
||||||
|
*
|
||||||
|
* @exception BitstreamException is thrown if the specified
|
||||||
|
* number of bytes could not be read from the stream.
|
||||||
|
*/
|
||||||
|
private int readFully(byte[] b, int offs, int len)
|
||||||
|
throws BitstreamException
|
||||||
|
{
|
||||||
|
int nRead = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
int bytesread = source.read(b, offs, len);
|
||||||
|
if (bytesread == -1)
|
||||||
|
{
|
||||||
|
while (len-->0)
|
||||||
|
{
|
||||||
|
b[offs++] = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//throw newBitstreamException(UNEXPECTED_EOF, new EOFException());
|
||||||
|
}
|
||||||
|
nRead = nRead + bytesread;
|
||||||
|
offs += bytesread;
|
||||||
|
len -= bytesread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
throw newBitstreamException(STREAM_ERROR, ex);
|
||||||
|
}
|
||||||
|
return nRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simlar to readFully, but doesn't throw exception when
|
||||||
|
* EOF is reached.
|
||||||
|
*/
|
||||||
|
private int readBytes(byte[] b, int offs, int len)
|
||||||
|
throws BitstreamException
|
||||||
|
{
|
||||||
|
int totalBytesRead = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
int bytesread = source.read(b, offs, len);
|
||||||
|
if (bytesread == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
totalBytesRead += bytesread;
|
||||||
|
offs += bytesread;
|
||||||
|
len -= bytesread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
throw newBitstreamException(STREAM_ERROR, ex);
|
||||||
|
}
|
||||||
|
return totalBytesRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/javazoom/jl/decoder/BitstreamErrors.java
Normal file
72
src/javazoom/jl/decoder/BitstreamErrors.java
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 11/17/04 INVALIDFRAME code added. javalayer@javazoom.net
|
||||||
|
* 12/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface describes all error codes that can be thrown
|
||||||
|
* in <code>BistreamException</code>s.
|
||||||
|
*
|
||||||
|
* @see BitstreamException
|
||||||
|
*
|
||||||
|
* @author MDM 12/12/99
|
||||||
|
* @since 0.0.6
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface BitstreamErrors extends JavaLayerErrors
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An undeterminable error occurred.
|
||||||
|
*/
|
||||||
|
static public final int UNKNOWN_ERROR = BITSTREAM_ERROR + 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The header describes an unknown sample rate.
|
||||||
|
*/
|
||||||
|
static public final int UNKNOWN_SAMPLE_RATE = BITSTREAM_ERROR + 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A problem occurred reading from the stream.
|
||||||
|
*/
|
||||||
|
static public final int STREAM_ERROR = BITSTREAM_ERROR + 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The end of the stream was reached prematurely.
|
||||||
|
*/
|
||||||
|
static public final int UNEXPECTED_EOF = BITSTREAM_ERROR + 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The end of the stream was reached.
|
||||||
|
*/
|
||||||
|
static public final int STREAM_EOF = BITSTREAM_ERROR + 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frame data are missing.
|
||||||
|
*/
|
||||||
|
static public final int INVALIDFRAME = BITSTREAM_ERROR + 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static public final int BITSTREAM_LAST = 0x1ff;
|
||||||
|
|
||||||
|
}
|
||||||
71
src/javazoom/jl/decoder/BitstreamException.java
Normal file
71
src/javazoom/jl/decoder/BitstreamException.java
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of <code>BitstreamException</code> are thrown
|
||||||
|
* when operations on a <code>Bitstream</code> fail.
|
||||||
|
* <p>
|
||||||
|
* The exception provides details of the exception condition
|
||||||
|
* in two ways:
|
||||||
|
* <ol><li>
|
||||||
|
* as an error-code describing the nature of the error
|
||||||
|
* </li><br></br><li>
|
||||||
|
* as the <code>Throwable</code> instance, if any, that was thrown
|
||||||
|
* indicating that an exceptional condition has occurred.
|
||||||
|
* </li></ol></p>
|
||||||
|
*
|
||||||
|
* @since 0.0.6
|
||||||
|
* @author MDM 12/12/99
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class BitstreamException extends JavaLayerException
|
||||||
|
implements BitstreamErrors
|
||||||
|
{
|
||||||
|
private int errorcode = UNKNOWN_ERROR;
|
||||||
|
|
||||||
|
public BitstreamException(String msg, Throwable t)
|
||||||
|
{
|
||||||
|
super(msg, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BitstreamException(int errorcode, Throwable t)
|
||||||
|
{
|
||||||
|
this(getErrorString(errorcode), t);
|
||||||
|
this.errorcode = errorcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getErrorCode()
|
||||||
|
{
|
||||||
|
return errorcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static public String getErrorString(int errorcode)
|
||||||
|
{
|
||||||
|
// REVIEW: use resource bundle to map error codes
|
||||||
|
// to locale-sensitive strings.
|
||||||
|
|
||||||
|
return "Bitstream errorcode "+Integer.toHexString(errorcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
57
src/javazoom/jl/decoder/Control.java
Normal file
57
src/javazoom/jl/decoder/Control.java
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Work in progress.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface Control
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts playback of the media presented by this control.
|
||||||
|
*/
|
||||||
|
public void start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops playback of the media presented by this control.
|
||||||
|
*/
|
||||||
|
public void stop();
|
||||||
|
|
||||||
|
public boolean isPlaying();
|
||||||
|
|
||||||
|
public void pause();
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isRandomAccess();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current position.
|
||||||
|
*/
|
||||||
|
public double getPosition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setPosition(double d);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
70
src/javazoom/jl/decoder/Crc16.java
Normal file
70
src/javazoom/jl/decoder/Crc16.java
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 : 1.0 moved to LGPL.
|
||||||
|
*
|
||||||
|
* 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
* @(#) crc.h 1.5, last edit: 6/15/94 16:55:32
|
||||||
|
* @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
|
||||||
|
* @(#) Berlin University of Technology
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16-Bit CRC checksum
|
||||||
|
*/
|
||||||
|
public final class Crc16
|
||||||
|
{
|
||||||
|
private static short polynomial=(short)0x8005;
|
||||||
|
private short crc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dummy Constructor
|
||||||
|
*/
|
||||||
|
public Crc16()
|
||||||
|
{
|
||||||
|
crc = (short) 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feed a bitstring to the crc calculation (0 < length <= 32).
|
||||||
|
*/
|
||||||
|
public void add_bits (int bitstring, int length)
|
||||||
|
{
|
||||||
|
int bitmask = 1 << (length - 1);
|
||||||
|
do
|
||||||
|
if (((crc & 0x8000) == 0) ^ ((bitstring & bitmask) == 0 ))
|
||||||
|
{
|
||||||
|
crc <<= 1;
|
||||||
|
crc ^= polynomial;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
crc <<= 1;
|
||||||
|
while ((bitmask >>>= 1) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the calculated checksum.
|
||||||
|
* Erase it for next calls to add_bits().
|
||||||
|
*/
|
||||||
|
public short checksum()
|
||||||
|
{
|
||||||
|
short sum = crc;
|
||||||
|
crc = (short) 0xFFFF;
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
357
src/javazoom/jl/decoder/Decoder.java
Normal file
357
src/javazoom/jl/decoder/Decoder.java
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 01/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>Decoder</code> class encapsulates the details of
|
||||||
|
* decoding an MPEG audio frame.
|
||||||
|
*
|
||||||
|
* @author MDM
|
||||||
|
* @version 0.0.7 12/12/99
|
||||||
|
* @since 0.0.5
|
||||||
|
*/
|
||||||
|
public class Decoder implements DecoderErrors
|
||||||
|
{
|
||||||
|
static private final Params DEFAULT_PARAMS = new Params();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Bistream from which the MPEG audio frames are read.
|
||||||
|
*/
|
||||||
|
//private Bitstream stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Obuffer instance that will receive the decoded
|
||||||
|
* PCM samples.
|
||||||
|
*/
|
||||||
|
private Obuffer output;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synthesis filter for the left channel.
|
||||||
|
*/
|
||||||
|
private SynthesisFilter filter1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sythesis filter for the right channel.
|
||||||
|
*/
|
||||||
|
private SynthesisFilter filter2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decoder used to decode layer III frames.
|
||||||
|
*/
|
||||||
|
private LayerIIIDecoder l3decoder;
|
||||||
|
private LayerIIDecoder l2decoder;
|
||||||
|
private LayerIDecoder l1decoder;
|
||||||
|
|
||||||
|
private int outputFrequency;
|
||||||
|
private int outputChannels;
|
||||||
|
|
||||||
|
private Equalizer equalizer = new Equalizer();
|
||||||
|
|
||||||
|
private Params params;
|
||||||
|
|
||||||
|
private boolean initialized;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new <code>Decoder</code> instance with default
|
||||||
|
* parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public Decoder()
|
||||||
|
{
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new <code>Decoder</code> instance with default
|
||||||
|
* parameters.
|
||||||
|
*
|
||||||
|
* @param params The <code>Params</code> instance that describes
|
||||||
|
* the customizable aspects of the decoder.
|
||||||
|
*/
|
||||||
|
public Decoder(Params params0)
|
||||||
|
{
|
||||||
|
if (params0==null)
|
||||||
|
params0 = DEFAULT_PARAMS;
|
||||||
|
|
||||||
|
params = params0;
|
||||||
|
|
||||||
|
Equalizer eq = params.getInitialEqualizerSettings();
|
||||||
|
if (eq!=null)
|
||||||
|
{
|
||||||
|
equalizer.setFrom(eq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public Params getDefaultParams()
|
||||||
|
{
|
||||||
|
return (Params)DEFAULT_PARAMS.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEqualizer(Equalizer eq)
|
||||||
|
{
|
||||||
|
if (eq==null)
|
||||||
|
eq = Equalizer.PASS_THRU_EQ;
|
||||||
|
|
||||||
|
equalizer.setFrom(eq);
|
||||||
|
|
||||||
|
float[] factors = equalizer.getBandFactors();
|
||||||
|
|
||||||
|
if (filter1!=null)
|
||||||
|
filter1.setEQ(factors);
|
||||||
|
|
||||||
|
if (filter2!=null)
|
||||||
|
filter2.setEQ(factors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes one frame from an MPEG audio bitstream.
|
||||||
|
*
|
||||||
|
* @param header The header describing the frame to decode.
|
||||||
|
* @param bitstream The bistream that provides the bits for te body of the frame.
|
||||||
|
*
|
||||||
|
* @return A SampleBuffer containing the decoded samples.
|
||||||
|
*/
|
||||||
|
public Obuffer decodeFrame(Header header, Bitstream stream)
|
||||||
|
throws DecoderException
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
{
|
||||||
|
initialize(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
int layer = header.layer();
|
||||||
|
|
||||||
|
output.clear_buffer();
|
||||||
|
|
||||||
|
FrameDecoder decoder = retrieveDecoder(header, stream, layer);
|
||||||
|
|
||||||
|
decoder.decodeFrame();
|
||||||
|
|
||||||
|
output.write_buffer(1);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the output buffer. This will take effect the next time
|
||||||
|
* decodeFrame() is called.
|
||||||
|
*/
|
||||||
|
public void setOutputBuffer(Obuffer out)
|
||||||
|
{
|
||||||
|
output = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the sample frequency of the PCM samples output
|
||||||
|
* by this decoder. This typically corresponds to the sample
|
||||||
|
* rate encoded in the MPEG audio stream.
|
||||||
|
*
|
||||||
|
* @param the sample rate (in Hz) of the samples written to the
|
||||||
|
* output buffer when decoding.
|
||||||
|
*/
|
||||||
|
public int getOutputFrequency()
|
||||||
|
{
|
||||||
|
return outputFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the number of channels of PCM samples output by
|
||||||
|
* this decoder. This usually corresponds to the number of
|
||||||
|
* channels in the MPEG audio stream, although it may differ.
|
||||||
|
*
|
||||||
|
* @return The number of output channels in the decoded samples: 1
|
||||||
|
* for mono, or 2 for stereo.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public int getOutputChannels()
|
||||||
|
{
|
||||||
|
return outputChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the maximum number of samples that will be written to
|
||||||
|
* the output buffer when one frame is decoded. This can be used to
|
||||||
|
* help calculate the size of other buffers whose size is based upon
|
||||||
|
* the number of samples written to the output buffer. NB: this is
|
||||||
|
* an upper bound and fewer samples may actually be written, depending
|
||||||
|
* upon the sample rate and number of channels.
|
||||||
|
*
|
||||||
|
* @return The maximum number of samples that are written to the
|
||||||
|
* output buffer when decoding a single frame of MPEG audio.
|
||||||
|
*/
|
||||||
|
public int getOutputBlockSize()
|
||||||
|
{
|
||||||
|
return Obuffer.OBUFFERSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected DecoderException newDecoderException(int errorcode)
|
||||||
|
{
|
||||||
|
return new DecoderException(errorcode, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DecoderException newDecoderException(int errorcode, Throwable throwable)
|
||||||
|
{
|
||||||
|
return new DecoderException(errorcode, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FrameDecoder retrieveDecoder(Header header, Bitstream stream, int layer)
|
||||||
|
throws DecoderException
|
||||||
|
{
|
||||||
|
FrameDecoder decoder = null;
|
||||||
|
|
||||||
|
// REVIEW: allow channel output selection type
|
||||||
|
// (LEFT, RIGHT, BOTH, DOWNMIX)
|
||||||
|
switch (layer)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
if (l3decoder==null)
|
||||||
|
{
|
||||||
|
l3decoder = new LayerIIIDecoder(stream,
|
||||||
|
header, filter1, filter2,
|
||||||
|
output, OutputChannels.BOTH_CHANNELS);
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder = l3decoder;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (l2decoder==null)
|
||||||
|
{
|
||||||
|
l2decoder = new LayerIIDecoder();
|
||||||
|
l2decoder.create(stream,
|
||||||
|
header, filter1, filter2,
|
||||||
|
output, OutputChannels.BOTH_CHANNELS);
|
||||||
|
}
|
||||||
|
decoder = l2decoder;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (l1decoder==null)
|
||||||
|
{
|
||||||
|
l1decoder = new LayerIDecoder();
|
||||||
|
l1decoder.create(stream,
|
||||||
|
header, filter1, filter2,
|
||||||
|
output, OutputChannels.BOTH_CHANNELS);
|
||||||
|
}
|
||||||
|
decoder = l1decoder;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decoder==null)
|
||||||
|
{
|
||||||
|
throw newDecoderException(UNSUPPORTED_LAYER, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize(Header header)
|
||||||
|
throws DecoderException
|
||||||
|
{
|
||||||
|
|
||||||
|
// REVIEW: allow customizable scale factor
|
||||||
|
float scalefactor = 32700.0f;
|
||||||
|
|
||||||
|
int mode = header.mode();
|
||||||
|
int layer = header.layer();
|
||||||
|
int channels = mode==Header.SINGLE_CHANNEL ? 1 : 2;
|
||||||
|
|
||||||
|
|
||||||
|
// set up output buffer if not set up by client.
|
||||||
|
if (output==null)
|
||||||
|
output = new SampleBuffer(header.frequency(), channels);
|
||||||
|
|
||||||
|
float[] factors = equalizer.getBandFactors();
|
||||||
|
filter1 = new SynthesisFilter(0, scalefactor, factors);
|
||||||
|
|
||||||
|
// REVIEW: allow mono output for stereo
|
||||||
|
if (channels==2)
|
||||||
|
filter2 = new SynthesisFilter(1, scalefactor, factors);
|
||||||
|
|
||||||
|
outputChannels = channels;
|
||||||
|
outputFrequency = header.frequency();
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>Params</code> class presents the customizable
|
||||||
|
* aspects of the decoder.
|
||||||
|
* <p>
|
||||||
|
* Instances of this class are not thread safe.
|
||||||
|
*/
|
||||||
|
public static class Params implements Cloneable
|
||||||
|
{
|
||||||
|
private OutputChannels outputChannels = OutputChannels.BOTH;
|
||||||
|
|
||||||
|
private Equalizer equalizer = new Equalizer();
|
||||||
|
|
||||||
|
public Params()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
catch (CloneNotSupportedException ex)
|
||||||
|
{
|
||||||
|
throw new InternalError(this+": "+ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOutputChannels(OutputChannels out)
|
||||||
|
{
|
||||||
|
if (out==null)
|
||||||
|
throw new NullPointerException("out");
|
||||||
|
|
||||||
|
outputChannels = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputChannels getOutputChannels()
|
||||||
|
{
|
||||||
|
return outputChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the equalizer settings that the decoder's equalizer
|
||||||
|
* will be initialized from.
|
||||||
|
* <p>
|
||||||
|
* The <code>Equalizer</code> instance returned
|
||||||
|
* cannot be changed in real time to affect the
|
||||||
|
* decoder output as it is used only to initialize the decoders
|
||||||
|
* EQ settings. To affect the decoder's output in realtime,
|
||||||
|
* use the Equalizer returned from the getEqualizer() method on
|
||||||
|
* the decoder.
|
||||||
|
*
|
||||||
|
* @return The <code>Equalizer</code> used to initialize the
|
||||||
|
* EQ settings of the decoder.
|
||||||
|
*/
|
||||||
|
public Equalizer getInitialEqualizerSettings()
|
||||||
|
{
|
||||||
|
return equalizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
45
src/javazoom/jl/decoder/DecoderErrors.java
Normal file
45
src/javazoom/jl/decoder/DecoderErrors.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 09/26/08 throw exception on subbband alloc error: Christopher G. Jennings (cjennings@acm.org)
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 01/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface provides constants describing the error
|
||||||
|
* codes used by the Decoder to indicate errors.
|
||||||
|
*
|
||||||
|
* @author MDM
|
||||||
|
*/
|
||||||
|
public interface DecoderErrors extends JavaLayerErrors
|
||||||
|
{
|
||||||
|
|
||||||
|
static public final int UNKNOWN_ERROR = DECODER_ERROR + 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layer not supported by the decoder.
|
||||||
|
*/
|
||||||
|
static public final int UNSUPPORTED_LAYER = DECODER_ERROR + 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Illegal allocation in subband layer. Indicates a corrupt stream.
|
||||||
|
*/
|
||||||
|
static public final int ILLEGAL_SUBBAND_ALLOCATION = DECODER_ERROR + 2;
|
||||||
|
|
||||||
|
}
|
||||||
61
src/javazoom/jl/decoder/DecoderException.java
Normal file
61
src/javazoom/jl/decoder/DecoderException.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 01/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>DecoderException</code> represents the class of
|
||||||
|
* errors that can occur when decoding MPEG audio.
|
||||||
|
*
|
||||||
|
* @author MDM
|
||||||
|
*/
|
||||||
|
public class DecoderException extends JavaLayerException
|
||||||
|
implements DecoderErrors
|
||||||
|
{
|
||||||
|
private int errorcode = UNKNOWN_ERROR;
|
||||||
|
|
||||||
|
public DecoderException(String msg, Throwable t)
|
||||||
|
{
|
||||||
|
super(msg, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecoderException(int errorcode, Throwable t)
|
||||||
|
{
|
||||||
|
this(getErrorString(errorcode), t);
|
||||||
|
this.errorcode = errorcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getErrorCode()
|
||||||
|
{
|
||||||
|
return errorcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static public String getErrorString(int errorcode)
|
||||||
|
{
|
||||||
|
// REVIEW: use resource file to map error codes
|
||||||
|
// to locale-sensitive strings.
|
||||||
|
|
||||||
|
return "Decoder errorcode "+Integer.toHexString(errorcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
227
src/javazoom/jl/decoder/Equalizer.java
Normal file
227
src/javazoom/jl/decoder/Equalizer.java
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>Equalizer</code> class can be used to specify
|
||||||
|
* equalization settings for the MPEG audio decoder.
|
||||||
|
* <p>
|
||||||
|
* The equalizer consists of 32 band-pass filters.
|
||||||
|
* Each band of the equalizer can take on a fractional value between
|
||||||
|
* -1.0 and +1.0.
|
||||||
|
* At -1.0, the input signal is attenuated by 6dB, at +1.0 the signal is
|
||||||
|
* amplified by 6dB.
|
||||||
|
*
|
||||||
|
* @see Decoder
|
||||||
|
*
|
||||||
|
* @author MDM
|
||||||
|
*/
|
||||||
|
public final class Equalizer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Equalizer setting to denote that a given band will not be
|
||||||
|
* present in the output signal.
|
||||||
|
*/
|
||||||
|
static public final float BAND_NOT_PRESENT = Float.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
|
static public final Equalizer PASS_THRU_EQ = new Equalizer();
|
||||||
|
|
||||||
|
private static final int BANDS = 32;
|
||||||
|
|
||||||
|
private final float[] settings = new float[BANDS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new <code>Equalizer</code> instance.
|
||||||
|
*/
|
||||||
|
public Equalizer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// private Equalizer(float b1, float b2, float b3, float b4, float b5,
|
||||||
|
// float b6, float b7, float b8, float b9, float b10, float b11,
|
||||||
|
// float b12, float b13, float b14, float b15, float b16,
|
||||||
|
// float b17, float b18, float b19, float b20);
|
||||||
|
|
||||||
|
public Equalizer(float[] settings)
|
||||||
|
{
|
||||||
|
setFrom(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Equalizer(EQFunction eq)
|
||||||
|
{
|
||||||
|
setFrom(eq);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrom(float[] eq)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
int max = (eq.length > BANDS) ? BANDS : eq.length;
|
||||||
|
|
||||||
|
for (int i=0; i<max; i++)
|
||||||
|
{
|
||||||
|
settings[i] = limit(eq[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrom(EQFunction eq)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
int max = BANDS;
|
||||||
|
|
||||||
|
for (int i=0; i<max; i++)
|
||||||
|
{
|
||||||
|
settings[i] = limit(eq.getBand(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the bands of this equalizer to the value the bands of
|
||||||
|
* another equalizer. Bands that are not present in both equalizers are ignored.
|
||||||
|
*/
|
||||||
|
public void setFrom(Equalizer eq)
|
||||||
|
{
|
||||||
|
if (eq!=this)
|
||||||
|
{
|
||||||
|
setFrom(eq.settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets all bands to 0.0
|
||||||
|
*/
|
||||||
|
public void reset()
|
||||||
|
{
|
||||||
|
for (int i=0; i<BANDS; i++)
|
||||||
|
{
|
||||||
|
settings[i] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the number of bands present in this equalizer.
|
||||||
|
*/
|
||||||
|
public int getBandCount()
|
||||||
|
{
|
||||||
|
return settings.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float setBand(int band, float neweq)
|
||||||
|
{
|
||||||
|
float eq = 0.0f;
|
||||||
|
|
||||||
|
if ((band>=0) && (band<BANDS))
|
||||||
|
{
|
||||||
|
eq = settings[band];
|
||||||
|
settings[band] = limit(neweq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return eq;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the eq setting for a given band.
|
||||||
|
*/
|
||||||
|
public float getBand(int band)
|
||||||
|
{
|
||||||
|
float eq = 0.0f;
|
||||||
|
|
||||||
|
if ((band>=0) && (band<BANDS))
|
||||||
|
{
|
||||||
|
eq = settings[band];
|
||||||
|
}
|
||||||
|
|
||||||
|
return eq;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float limit(float eq)
|
||||||
|
{
|
||||||
|
if (eq==BAND_NOT_PRESENT)
|
||||||
|
return eq;
|
||||||
|
if (eq > 1.0f)
|
||||||
|
return 1.0f;
|
||||||
|
if (eq < -1.0f)
|
||||||
|
return -1.0f;
|
||||||
|
|
||||||
|
return eq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an array of floats whose values represent a
|
||||||
|
* scaling factor that can be applied to linear samples
|
||||||
|
* in each band to provide the equalization represented by
|
||||||
|
* this instance.
|
||||||
|
*
|
||||||
|
* @return an array of factors that can be applied to the
|
||||||
|
* subbands.
|
||||||
|
*/
|
||||||
|
float[] getBandFactors()
|
||||||
|
{
|
||||||
|
float[] factors = new float[BANDS];
|
||||||
|
for (int i=0, maxCount=BANDS; i<maxCount; i++)
|
||||||
|
{
|
||||||
|
factors[i] = getBandFactor(settings[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return factors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an equalizer band setting to a sample factor.
|
||||||
|
* The factor is determined by the function f = 2^n where
|
||||||
|
* n is the equalizer band setting in the range [-1.0,1.0].
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
float getBandFactor(float eq)
|
||||||
|
{
|
||||||
|
if (eq==BAND_NOT_PRESENT)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
float f = (float)Math.pow(2.0, eq);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static abstract public class EQFunction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the setting of a band in the equalizer.
|
||||||
|
*
|
||||||
|
* @param band The index of the band to retrieve the setting
|
||||||
|
* for.
|
||||||
|
*
|
||||||
|
* @return the setting of the specified band. This is a value between
|
||||||
|
* -1 and +1.
|
||||||
|
*/
|
||||||
|
public float getBand(int band)
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
src/javazoom/jl/decoder/FrameDecoder.java
Normal file
39
src/javazoom/jl/decoder/FrameDecoder.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 09/26/08 throw exception on subbband alloc error: Christopher G. Jennings (cjennings@acm.org)
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementations of FrameDecoder are responsible for decoding
|
||||||
|
* an MPEG audio frame.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//REVIEW: the interface currently is too thin. There should be
|
||||||
|
// methods to specify the output buffer, the synthesis filters and
|
||||||
|
// possibly other objects used by the decoder.
|
||||||
|
public interface FrameDecoder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Decodes one frame of MPEG audio.
|
||||||
|
*/
|
||||||
|
public void decodeFrame() throws DecoderException;
|
||||||
|
|
||||||
|
}
|
||||||
762
src/javazoom/jl/decoder/Header.java
Normal file
762
src/javazoom/jl/decoder/Header.java
Normal file
@@ -0,0 +1,762 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 : 1.0 moved to LGPL.
|
||||||
|
* VBRI header support added, E.B javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
* 12/04/03 : VBR (XING) header support added, E.B javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
* 02/13/99 : Java Conversion by JavaZOOM , E.B javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
* Declarations for MPEG header class
|
||||||
|
* A few layer III, MPEG-2 LSF, and seeking modifications made by Jeff Tsay.
|
||||||
|
* Last modified : 04/19/97
|
||||||
|
*
|
||||||
|
* @(#) header.h 1.7, last edit: 6/15/94 16:55:33
|
||||||
|
* @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
|
||||||
|
* @(#) Berlin University of Technology
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for extracting information from a frame header.
|
||||||
|
*/
|
||||||
|
public final class Header
|
||||||
|
{
|
||||||
|
public static final int[][] frequencies =
|
||||||
|
{{22050, 24000, 16000, 1},
|
||||||
|
{44100, 48000, 32000, 1},
|
||||||
|
{11025, 12000, 8000, 1}}; // SZD: MPEG25
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant for MPEG-2 LSF version
|
||||||
|
*/
|
||||||
|
public static final int MPEG2_LSF = 0;
|
||||||
|
public static final int MPEG25_LSF = 2; // SZD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant for MPEG-1 version
|
||||||
|
*/
|
||||||
|
public static final int MPEG1 = 1;
|
||||||
|
|
||||||
|
public static final int STEREO = 0;
|
||||||
|
public static final int JOINT_STEREO = 1;
|
||||||
|
public static final int DUAL_CHANNEL = 2;
|
||||||
|
public static final int SINGLE_CHANNEL = 3;
|
||||||
|
public static final int FOURTYFOUR_POINT_ONE = 0;
|
||||||
|
public static final int FOURTYEIGHT=1;
|
||||||
|
public static final int THIRTYTWO=2;
|
||||||
|
|
||||||
|
private int h_layer, h_protection_bit, h_bitrate_index,
|
||||||
|
h_padding_bit, h_mode_extension;
|
||||||
|
private int h_version;
|
||||||
|
private int h_mode;
|
||||||
|
private int h_sample_frequency;
|
||||||
|
private int h_number_of_subbands, h_intensity_stereo_bound;
|
||||||
|
private boolean h_copyright, h_original;
|
||||||
|
// VBR support added by E.B
|
||||||
|
private double[] h_vbr_time_per_frame = {-1, 384, 1152, 1152};
|
||||||
|
private boolean h_vbr;
|
||||||
|
private int h_vbr_frames;
|
||||||
|
private int h_vbr_scale;
|
||||||
|
private int h_vbr_bytes;
|
||||||
|
private byte[] h_vbr_toc;
|
||||||
|
|
||||||
|
private byte syncmode = Bitstream.INITIAL_SYNC;
|
||||||
|
private Crc16 crc;
|
||||||
|
|
||||||
|
public short checksum;
|
||||||
|
public int framesize;
|
||||||
|
public int nSlots;
|
||||||
|
|
||||||
|
private int _headerstring = -1; // E.B
|
||||||
|
|
||||||
|
Header()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer buffer = new StringBuffer(200);
|
||||||
|
buffer.append("Layer ");
|
||||||
|
buffer.append(layer_string());
|
||||||
|
buffer.append(" frame ");
|
||||||
|
buffer.append(mode_string());
|
||||||
|
buffer.append(' ');
|
||||||
|
buffer.append(version_string());
|
||||||
|
if (!checksums())
|
||||||
|
buffer.append(" no");
|
||||||
|
buffer.append(" checksums");
|
||||||
|
buffer.append(' ');
|
||||||
|
buffer.append(sample_frequency_string());
|
||||||
|
buffer.append(',');
|
||||||
|
buffer.append(' ');
|
||||||
|
buffer.append(bitrate_string());
|
||||||
|
|
||||||
|
String s = buffer.toString();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a 32-bit header from the bitstream.
|
||||||
|
*/
|
||||||
|
void read_header(Bitstream stream, Crc16[] crcp) throws BitstreamException
|
||||||
|
{
|
||||||
|
int headerstring;
|
||||||
|
int channel_bitrate;
|
||||||
|
boolean sync = false;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
headerstring = stream.syncHeader(syncmode);
|
||||||
|
_headerstring = headerstring; // E.B
|
||||||
|
if (syncmode == Bitstream.INITIAL_SYNC)
|
||||||
|
{
|
||||||
|
h_version = ((headerstring >>> 19) & 1);
|
||||||
|
if (((headerstring >>> 20) & 1) == 0) // SZD: MPEG2.5 detection
|
||||||
|
if (h_version == MPEG2_LSF)
|
||||||
|
h_version = MPEG25_LSF;
|
||||||
|
else
|
||||||
|
throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);
|
||||||
|
if ((h_sample_frequency = ((headerstring >>> 10) & 3)) == 3)
|
||||||
|
{
|
||||||
|
throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h_layer = 4 - (headerstring >>> 17) & 3;
|
||||||
|
h_protection_bit = (headerstring >>> 16) & 1;
|
||||||
|
h_bitrate_index = (headerstring >>> 12) & 0xF;
|
||||||
|
h_padding_bit = (headerstring >>> 9) & 1;
|
||||||
|
h_mode = ((headerstring >>> 6) & 3);
|
||||||
|
h_mode_extension = (headerstring >>> 4) & 3;
|
||||||
|
if (h_mode == JOINT_STEREO)
|
||||||
|
h_intensity_stereo_bound = (h_mode_extension << 2) + 4;
|
||||||
|
else
|
||||||
|
h_intensity_stereo_bound = 0; // should never be used
|
||||||
|
if (((headerstring >>> 3) & 1) == 1)
|
||||||
|
h_copyright = true;
|
||||||
|
if (((headerstring >>> 2) & 1) == 1)
|
||||||
|
h_original = true;
|
||||||
|
// calculate number of subbands:
|
||||||
|
if (h_layer == 1)
|
||||||
|
h_number_of_subbands = 32;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
channel_bitrate = h_bitrate_index;
|
||||||
|
// calculate bitrate per channel:
|
||||||
|
if (h_mode != SINGLE_CHANNEL)
|
||||||
|
if (channel_bitrate == 4)
|
||||||
|
channel_bitrate = 1;
|
||||||
|
else
|
||||||
|
channel_bitrate -= 4;
|
||||||
|
if ((channel_bitrate == 1) || (channel_bitrate == 2))
|
||||||
|
if (h_sample_frequency == THIRTYTWO)
|
||||||
|
h_number_of_subbands = 12;
|
||||||
|
else
|
||||||
|
h_number_of_subbands = 8;
|
||||||
|
else if ((h_sample_frequency == FOURTYEIGHT) || ((channel_bitrate >= 3) && (channel_bitrate <= 5)))
|
||||||
|
h_number_of_subbands = 27;
|
||||||
|
else
|
||||||
|
h_number_of_subbands = 30;
|
||||||
|
}
|
||||||
|
if (h_intensity_stereo_bound > h_number_of_subbands)
|
||||||
|
h_intensity_stereo_bound = h_number_of_subbands;
|
||||||
|
// calculate framesize and nSlots
|
||||||
|
calculate_framesize();
|
||||||
|
// read framedata:
|
||||||
|
int framesizeloaded = stream.read_frame_data(framesize);
|
||||||
|
if ((framesize >=0) && (framesizeloaded != framesize))
|
||||||
|
{
|
||||||
|
// Data loaded does not match to expected framesize,
|
||||||
|
// it might be an ID3v1 TAG. (Fix 11/17/04).
|
||||||
|
throw stream.newBitstreamException(Bitstream.INVALIDFRAME);
|
||||||
|
}
|
||||||
|
if (stream.isSyncCurrentPosition(syncmode))
|
||||||
|
{
|
||||||
|
if (syncmode == Bitstream.INITIAL_SYNC)
|
||||||
|
{
|
||||||
|
syncmode = Bitstream.STRICT_SYNC;
|
||||||
|
stream.set_syncword(headerstring & 0xFFF80CC0);
|
||||||
|
}
|
||||||
|
sync = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream.unreadFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!sync);
|
||||||
|
stream.parse_frame();
|
||||||
|
if (h_protection_bit == 0)
|
||||||
|
{
|
||||||
|
// frame contains a crc checksum
|
||||||
|
checksum = (short) stream.get_bits(16);
|
||||||
|
if (crc == null)
|
||||||
|
crc = new Crc16();
|
||||||
|
crc.add_bits(headerstring, 16);
|
||||||
|
crcp[0] = crc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
crcp[0] = null;
|
||||||
|
if (h_sample_frequency == FOURTYFOUR_POINT_ONE)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if (offset == null)
|
||||||
|
{
|
||||||
|
int max = max_number_of_frames(stream);
|
||||||
|
offset = new int[max];
|
||||||
|
for(int i=0; i<max; i++) offset[i] = 0;
|
||||||
|
}
|
||||||
|
// E.B : Investigate more
|
||||||
|
int cf = stream.current_frame();
|
||||||
|
int lf = stream.last_frame();
|
||||||
|
if ((cf > 0) && (cf == lf))
|
||||||
|
{
|
||||||
|
offset[cf] = offset[cf-1] + h_padding_bit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset[0] = h_padding_bit;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse frame to extract optionnal VBR frame.
|
||||||
|
* @param firstframe
|
||||||
|
* @author E.B (javalayer@javazoom.net)
|
||||||
|
*/
|
||||||
|
void parseVBR(byte[] firstframe) throws BitstreamException
|
||||||
|
{
|
||||||
|
// Trying Xing header.
|
||||||
|
String xing = "Xing";
|
||||||
|
byte tmp[] = new byte[4];
|
||||||
|
int offset = 0;
|
||||||
|
// Compute "Xing" offset depending on MPEG version and channels.
|
||||||
|
if (h_version == MPEG1)
|
||||||
|
{
|
||||||
|
if (h_mode == SINGLE_CHANNEL) offset=21-4;
|
||||||
|
else offset=36-4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (h_mode == SINGLE_CHANNEL) offset=13-4;
|
||||||
|
else offset = 21-4;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
System.arraycopy(firstframe, offset, tmp, 0, 4);
|
||||||
|
// Is "Xing" ?
|
||||||
|
if (xing.equals(new String(tmp)))
|
||||||
|
{
|
||||||
|
//Yes.
|
||||||
|
h_vbr = true;
|
||||||
|
h_vbr_frames = -1;
|
||||||
|
h_vbr_bytes = -1;
|
||||||
|
h_vbr_scale = -1;
|
||||||
|
h_vbr_toc = new byte[100];
|
||||||
|
|
||||||
|
int length = 4;
|
||||||
|
// Read flags.
|
||||||
|
byte flags[] = new byte[4];
|
||||||
|
System.arraycopy(firstframe, offset + length, flags, 0, flags.length);
|
||||||
|
length += flags.length;
|
||||||
|
// Read number of frames (if available).
|
||||||
|
if ((flags[3] & (byte) (1 << 0)) != 0)
|
||||||
|
{
|
||||||
|
System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
|
||||||
|
h_vbr_frames = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;
|
||||||
|
length += 4;
|
||||||
|
}
|
||||||
|
// Read size (if available).
|
||||||
|
if ((flags[3] & (byte) (1 << 1)) != 0)
|
||||||
|
{
|
||||||
|
System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
|
||||||
|
h_vbr_bytes = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;
|
||||||
|
length += 4;
|
||||||
|
}
|
||||||
|
// Read TOC (if available).
|
||||||
|
if ((flags[3] & (byte) (1 << 2)) != 0)
|
||||||
|
{
|
||||||
|
System.arraycopy(firstframe, offset + length, h_vbr_toc, 0, h_vbr_toc.length);
|
||||||
|
length += h_vbr_toc.length;
|
||||||
|
}
|
||||||
|
// Read scale (if available).
|
||||||
|
if ((flags[3] & (byte) (1 << 3)) != 0)
|
||||||
|
{
|
||||||
|
System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
|
||||||
|
h_vbr_scale = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;
|
||||||
|
length += 4;
|
||||||
|
}
|
||||||
|
//System.out.println("VBR:"+xing+" Frames:"+ h_vbr_frames +" Size:"+h_vbr_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ArrayIndexOutOfBoundsException e)
|
||||||
|
{
|
||||||
|
throw new BitstreamException("XingVBRHeader Corrupted",e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trying VBRI header.
|
||||||
|
String vbri = "VBRI";
|
||||||
|
offset = 36-4;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
System.arraycopy(firstframe, offset, tmp, 0, 4);
|
||||||
|
// Is "VBRI" ?
|
||||||
|
if (vbri.equals(new String(tmp)))
|
||||||
|
{
|
||||||
|
//Yes.
|
||||||
|
h_vbr = true;
|
||||||
|
h_vbr_frames = -1;
|
||||||
|
h_vbr_bytes = -1;
|
||||||
|
h_vbr_scale = -1;
|
||||||
|
h_vbr_toc = new byte[100];
|
||||||
|
// Bytes.
|
||||||
|
int length = 4 + 6;
|
||||||
|
System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
|
||||||
|
h_vbr_bytes = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;
|
||||||
|
length += 4;
|
||||||
|
// Frames.
|
||||||
|
System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
|
||||||
|
h_vbr_frames = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;
|
||||||
|
length += 4;
|
||||||
|
//System.out.println("VBR:"+vbri+" Frames:"+ h_vbr_frames +" Size:"+h_vbr_bytes);
|
||||||
|
// TOC
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ArrayIndexOutOfBoundsException e)
|
||||||
|
{
|
||||||
|
throw new BitstreamException("VBRIVBRHeader Corrupted",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions to query header contents:
|
||||||
|
/**
|
||||||
|
* Returns version.
|
||||||
|
*/
|
||||||
|
public int version() { return h_version; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Layer ID.
|
||||||
|
*/
|
||||||
|
public int layer() { return h_layer; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns bitrate index.
|
||||||
|
*/
|
||||||
|
public int bitrate_index() { return h_bitrate_index; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Sample Frequency.
|
||||||
|
*/
|
||||||
|
public int sample_frequency() { return h_sample_frequency; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Frequency.
|
||||||
|
*/
|
||||||
|
public int frequency() {return frequencies[h_version][h_sample_frequency];}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Mode.
|
||||||
|
*/
|
||||||
|
public int mode() { return h_mode; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Protection bit.
|
||||||
|
*/
|
||||||
|
public boolean checksums()
|
||||||
|
{
|
||||||
|
if (h_protection_bit == 0) return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Copyright.
|
||||||
|
*/
|
||||||
|
public boolean copyright() { return h_copyright; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Original.
|
||||||
|
*/
|
||||||
|
public boolean original() { return h_original; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return VBR.
|
||||||
|
* @return true if VBR header is found
|
||||||
|
*/
|
||||||
|
public boolean vbr() { return h_vbr; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return VBR scale.
|
||||||
|
* @return scale of -1 if not available
|
||||||
|
*/
|
||||||
|
public int vbr_scale() { return h_vbr_scale; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return VBR TOC.
|
||||||
|
* @return vbr toc ot null if not available
|
||||||
|
*/
|
||||||
|
public byte[] vbr_toc() { return h_vbr_toc; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Checksum flag.
|
||||||
|
* Compares computed checksum with stream checksum.
|
||||||
|
*/
|
||||||
|
public boolean checksum_ok () { return (checksum == crc.checksum()); }
|
||||||
|
|
||||||
|
// Seeking and layer III stuff
|
||||||
|
/**
|
||||||
|
* Returns Layer III Padding bit.
|
||||||
|
*/
|
||||||
|
public boolean padding()
|
||||||
|
{
|
||||||
|
if (h_padding_bit == 0) return false;
|
||||||
|
else return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Slots.
|
||||||
|
*/
|
||||||
|
public int slots() { return nSlots; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Mode Extension.
|
||||||
|
*/
|
||||||
|
public int mode_extension() { return h_mode_extension; }
|
||||||
|
|
||||||
|
// E.B -> private to public
|
||||||
|
public static final int bitrates[][][] = {
|
||||||
|
{{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,
|
||||||
|
112000, 128000, 144000, 160000, 176000, 192000 ,224000, 256000, 0},
|
||||||
|
{0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
|
||||||
|
56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0},
|
||||||
|
{0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
|
||||||
|
56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}},
|
||||||
|
|
||||||
|
{{0 /*free format*/, 32000, 64000, 96000, 128000, 160000, 192000,
|
||||||
|
224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000, 0},
|
||||||
|
{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,
|
||||||
|
112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, 0},
|
||||||
|
{0 /*free format*/, 32000, 40000, 48000, 56000, 64000, 80000,
|
||||||
|
96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 0}},
|
||||||
|
// SZD: MPEG2.5
|
||||||
|
{{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,
|
||||||
|
112000, 128000, 144000, 160000, 176000, 192000 ,224000, 256000, 0},
|
||||||
|
{0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
|
||||||
|
56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0},
|
||||||
|
{0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
|
||||||
|
56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// E.B -> private to public
|
||||||
|
/**
|
||||||
|
* Calculate Frame size.
|
||||||
|
* Calculates framesize in bytes excluding header size.
|
||||||
|
*/
|
||||||
|
public int calculate_framesize()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (h_layer == 1)
|
||||||
|
{
|
||||||
|
framesize = (12 * bitrates[h_version][0][h_bitrate_index]) /
|
||||||
|
frequencies[h_version][h_sample_frequency];
|
||||||
|
if (h_padding_bit != 0 ) framesize++;
|
||||||
|
framesize <<= 2; // one slot is 4 bytes long
|
||||||
|
nSlots = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
framesize = (144 * bitrates[h_version][h_layer - 1][h_bitrate_index]) /
|
||||||
|
frequencies[h_version][h_sample_frequency];
|
||||||
|
if (h_version == MPEG2_LSF || h_version == MPEG25_LSF) framesize >>= 1; // SZD
|
||||||
|
if (h_padding_bit != 0) framesize++;
|
||||||
|
// Layer III slots
|
||||||
|
if (h_layer == 3)
|
||||||
|
{
|
||||||
|
if (h_version == MPEG1)
|
||||||
|
{
|
||||||
|
nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 17 : 32) // side info size
|
||||||
|
- ((h_protection_bit!=0) ? 0 : 2) // CRC size
|
||||||
|
- 4; // header size
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // MPEG-2 LSF, SZD: MPEG-2.5 LSF
|
||||||
|
nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 9 : 17) // side info size
|
||||||
|
- ((h_protection_bit!=0) ? 0 : 2) // CRC size
|
||||||
|
- 4; // header size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nSlots = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
framesize -= 4; // subtract header size
|
||||||
|
return framesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of frames in the stream.
|
||||||
|
* @param streamsize
|
||||||
|
* @return number of frames
|
||||||
|
*/
|
||||||
|
public int max_number_of_frames(int streamsize) // E.B
|
||||||
|
{
|
||||||
|
if (h_vbr == true) return h_vbr_frames;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((framesize + 4 - h_padding_bit) == 0) return 0;
|
||||||
|
else return(streamsize / (framesize + 4 - h_padding_bit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of frames in the stream.
|
||||||
|
* @param streamsize
|
||||||
|
* @return number of frames
|
||||||
|
*/
|
||||||
|
public int min_number_of_frames(int streamsize) // E.B
|
||||||
|
{
|
||||||
|
if (h_vbr == true) return h_vbr_frames;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((framesize + 5 - h_padding_bit) == 0) return 0;
|
||||||
|
else return(streamsize / (framesize + 5 - h_padding_bit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns ms/frame.
|
||||||
|
* @return milliseconds per frame
|
||||||
|
*/
|
||||||
|
public float ms_per_frame() // E.B
|
||||||
|
{
|
||||||
|
if (h_vbr == true)
|
||||||
|
{
|
||||||
|
double tpf = h_vbr_time_per_frame[layer()] / frequency();
|
||||||
|
if ((h_version == MPEG2_LSF) || (h_version == MPEG25_LSF)) tpf /= 2;
|
||||||
|
return ((float) (tpf * 1000));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float ms_per_frame_array[][] = {{8.707483f, 8.0f, 12.0f},
|
||||||
|
{26.12245f, 24.0f, 36.0f},
|
||||||
|
{26.12245f, 24.0f, 36.0f}};
|
||||||
|
return(ms_per_frame_array[h_layer-1][h_sample_frequency]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns total ms.
|
||||||
|
* @param streamsize
|
||||||
|
* @return total milliseconds
|
||||||
|
*/
|
||||||
|
public float total_ms(int streamsize) // E.B
|
||||||
|
{
|
||||||
|
return(max_number_of_frames(streamsize) * ms_per_frame());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns synchronized header.
|
||||||
|
*/
|
||||||
|
public int getSyncHeader() // E.B
|
||||||
|
{
|
||||||
|
return _headerstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
// functions which return header informations as strings:
|
||||||
|
/**
|
||||||
|
* Return Layer version.
|
||||||
|
*/
|
||||||
|
public String layer_string()
|
||||||
|
{
|
||||||
|
switch (h_layer)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return "I";
|
||||||
|
case 2:
|
||||||
|
return "II";
|
||||||
|
case 3:
|
||||||
|
return "III";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// E.B -> private to public
|
||||||
|
public static final String bitrate_str[][][] = {
|
||||||
|
{{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",
|
||||||
|
"80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s",
|
||||||
|
"160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s",
|
||||||
|
"forbidden"},
|
||||||
|
{"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
|
||||||
|
"40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
|
||||||
|
"96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
|
||||||
|
"forbidden"},
|
||||||
|
{"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
|
||||||
|
"40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
|
||||||
|
"96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
|
||||||
|
"forbidden"}},
|
||||||
|
|
||||||
|
{{"free format", "32 kbit/s", "64 kbit/s", "96 kbit/s", "128 kbit/s",
|
||||||
|
"160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "288 kbit/s",
|
||||||
|
"320 kbit/s", "352 kbit/s", "384 kbit/s", "416 kbit/s", "448 kbit/s",
|
||||||
|
"forbidden"},
|
||||||
|
{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",
|
||||||
|
"80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "160 kbit/s",
|
||||||
|
"192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s", "384 kbit/s",
|
||||||
|
"forbidden"},
|
||||||
|
{"free format", "32 kbit/s", "40 kbit/s", "48 kbit/s", "56 kbit/s",
|
||||||
|
"64 kbit/s", "80 kbit/s" , "96 kbit/s", "112 kbit/s", "128 kbit/s",
|
||||||
|
"160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s",
|
||||||
|
"forbidden"}},
|
||||||
|
// SZD: MPEG2.5
|
||||||
|
{{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",
|
||||||
|
"80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s",
|
||||||
|
"160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s",
|
||||||
|
"forbidden"},
|
||||||
|
{"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
|
||||||
|
"40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
|
||||||
|
"96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
|
||||||
|
"forbidden"},
|
||||||
|
{"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
|
||||||
|
"40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
|
||||||
|
"96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
|
||||||
|
"forbidden"}},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return Bitrate.
|
||||||
|
* @return bitrate in bps
|
||||||
|
*/
|
||||||
|
public String bitrate_string()
|
||||||
|
{
|
||||||
|
if (h_vbr == true)
|
||||||
|
{
|
||||||
|
return Integer.toString(bitrate()/1000)+" kb/s";
|
||||||
|
}
|
||||||
|
else return bitrate_str[h_version][h_layer - 1][h_bitrate_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return Bitrate.
|
||||||
|
* @return bitrate in bps and average bitrate for VBR header
|
||||||
|
*/
|
||||||
|
public int bitrate()
|
||||||
|
{
|
||||||
|
if (h_vbr == true)
|
||||||
|
{
|
||||||
|
return ((int) ((h_vbr_bytes * 8) / (ms_per_frame() * h_vbr_frames)))*1000;
|
||||||
|
}
|
||||||
|
else return bitrates[h_version][h_layer - 1][h_bitrate_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return Instant Bitrate.
|
||||||
|
* Bitrate for VBR is not constant.
|
||||||
|
* @return bitrate in bps
|
||||||
|
*/
|
||||||
|
public int bitrate_instant()
|
||||||
|
{
|
||||||
|
return bitrates[h_version][h_layer - 1][h_bitrate_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Frequency
|
||||||
|
* @return frequency string in kHz
|
||||||
|
*/
|
||||||
|
public String sample_frequency_string()
|
||||||
|
{
|
||||||
|
switch (h_sample_frequency)
|
||||||
|
{
|
||||||
|
case THIRTYTWO:
|
||||||
|
if (h_version == MPEG1)
|
||||||
|
return "32 kHz";
|
||||||
|
else if (h_version == MPEG2_LSF)
|
||||||
|
return "16 kHz";
|
||||||
|
else // SZD
|
||||||
|
return "8 kHz";
|
||||||
|
case FOURTYFOUR_POINT_ONE:
|
||||||
|
if (h_version == MPEG1)
|
||||||
|
return "44.1 kHz";
|
||||||
|
else if (h_version == MPEG2_LSF)
|
||||||
|
return "22.05 kHz";
|
||||||
|
else // SZD
|
||||||
|
return "11.025 kHz";
|
||||||
|
case FOURTYEIGHT:
|
||||||
|
if (h_version == MPEG1)
|
||||||
|
return "48 kHz";
|
||||||
|
else if (h_version == MPEG2_LSF)
|
||||||
|
return "24 kHz";
|
||||||
|
else // SZD
|
||||||
|
return "12 kHz";
|
||||||
|
}
|
||||||
|
return(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Mode.
|
||||||
|
*/
|
||||||
|
public String mode_string()
|
||||||
|
{
|
||||||
|
switch (h_mode)
|
||||||
|
{
|
||||||
|
case STEREO:
|
||||||
|
return "Stereo";
|
||||||
|
case JOINT_STEREO:
|
||||||
|
return "Joint stereo";
|
||||||
|
case DUAL_CHANNEL:
|
||||||
|
return "Dual channel";
|
||||||
|
case SINGLE_CHANNEL:
|
||||||
|
return "Single channel";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Version.
|
||||||
|
* @return MPEG-1 or MPEG-2 LSF or MPEG-2.5 LSF
|
||||||
|
*/
|
||||||
|
public String version_string()
|
||||||
|
{
|
||||||
|
switch (h_version)
|
||||||
|
{
|
||||||
|
case MPEG1:
|
||||||
|
return "MPEG-1";
|
||||||
|
case MPEG2_LSF:
|
||||||
|
return "MPEG-2 LSF";
|
||||||
|
case MPEG25_LSF: // SZD
|
||||||
|
return "MPEG-2.5 LSF";
|
||||||
|
}
|
||||||
|
return(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of subbands in the current frame.
|
||||||
|
* @return number of subbands
|
||||||
|
*/
|
||||||
|
public int number_of_subbands() {return h_number_of_subbands;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Intensity Stereo.
|
||||||
|
* (Layer II joint stereo only).
|
||||||
|
* Returns the number of subbands which are in stereo mode,
|
||||||
|
* subbands above that limit are in intensity stereo mode.
|
||||||
|
* @return intensity
|
||||||
|
*/
|
||||||
|
public int intensity_stereo_bound() {return h_intensity_stereo_bound;}
|
||||||
|
}
|
||||||
80
src/javazoom/jl/decoder/InputStreamSource.java
Normal file
80
src/javazoom/jl/decoder/InputStreamSource.java
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <i>Work In Progress.</i>
|
||||||
|
*
|
||||||
|
* An instance of <code>InputStreamSource</code> implements a
|
||||||
|
* <code>Source</code> that provides data from an <code>InputStream
|
||||||
|
* </code>. Seeking functionality is not supported.
|
||||||
|
*
|
||||||
|
* @author MDM
|
||||||
|
*/
|
||||||
|
public class InputStreamSource implements Source
|
||||||
|
{
|
||||||
|
private final InputStream in;
|
||||||
|
|
||||||
|
public InputStreamSource(InputStream in)
|
||||||
|
{
|
||||||
|
if (in==null)
|
||||||
|
throw new NullPointerException("in");
|
||||||
|
|
||||||
|
this.in = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(byte[] b, int offs, int len)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
int read = in.read(b, offs, len);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean willReadBlock()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
//boolean block = (in.available()==0);
|
||||||
|
//return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSeekable()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long tell()
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long seek(long to)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long length()
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/javazoom/jl/decoder/JavaLayerError.java
Normal file
31
src/javazoom/jl/decoder/JavaLayerError.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Work in progress.
|
||||||
|
*
|
||||||
|
* API usage errors may be handled by throwing an instance of this
|
||||||
|
* class, as per JMF 2.0.
|
||||||
|
*/
|
||||||
|
public class JavaLayerError extends Error
|
||||||
|
{
|
||||||
|
}
|
||||||
40
src/javazoom/jl/decoder/JavaLayerErrors.java
Normal file
40
src/javazoom/jl/decoder/JavaLayerErrors.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception erorr codes for components of the JavaLayer API.
|
||||||
|
*/
|
||||||
|
public interface JavaLayerErrors
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The first bitstream error code. See the {@link DecoderErrors DecoderErrors}
|
||||||
|
* interface for other bitstream error codes.
|
||||||
|
*/
|
||||||
|
static public final int BITSTREAM_ERROR = 0x100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first decoder error code. See the {@link DecoderErrors DecoderErrors}
|
||||||
|
* interface for other decoder error codes.
|
||||||
|
*/
|
||||||
|
static public final int DECODER_ERROR = 0x200;
|
||||||
|
|
||||||
|
}
|
||||||
80
src/javazoom/jl/decoder/JavaLayerException.java
Normal file
80
src/javazoom/jl/decoder/JavaLayerException.java
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JavaLayerException is the base class for all API-level
|
||||||
|
* exceptions thrown by JavaLayer. To facilitate conversion and
|
||||||
|
* common handling of exceptions from other domains, the class
|
||||||
|
* can delegate some functionality to a contained Throwable instance.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* @author MDM
|
||||||
|
*/
|
||||||
|
public class JavaLayerException extends Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
private Throwable exception;
|
||||||
|
|
||||||
|
|
||||||
|
public JavaLayerException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaLayerException(String msg)
|
||||||
|
{
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaLayerException(String msg, Throwable t)
|
||||||
|
{
|
||||||
|
super(msg);
|
||||||
|
exception = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Throwable getException()
|
||||||
|
{
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void printStackTrace()
|
||||||
|
{
|
||||||
|
printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printStackTrace(PrintStream ps)
|
||||||
|
{
|
||||||
|
if (this.exception==null)
|
||||||
|
{
|
||||||
|
super.printStackTrace(ps);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exception.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
36
src/javazoom/jl/decoder/JavaLayerHook.java
Normal file
36
src/javazoom/jl/decoder/JavaLayerHook.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>JavaLayerHooks</code> class allows developers to change
|
||||||
|
* the way the JavaLayer library uses Resources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface JavaLayerHook
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Retrieves the named resource. This allows resources to be
|
||||||
|
* obtained without specifying how they are retrieved.
|
||||||
|
*/
|
||||||
|
public InputStream getResourceAsStream(String name);
|
||||||
|
}
|
||||||
207
src/javazoom/jl/decoder/JavaLayerUtils.java
Normal file
207
src/javazoom/jl/decoder/JavaLayerUtils.java
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InvalidClassException;
|
||||||
|
import java.io.InvalidObjectException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JavaLayerUtils class is not strictly part of the JavaLayer API.
|
||||||
|
* It serves to provide useful methods and system-wide hooks.
|
||||||
|
*
|
||||||
|
* @author MDM
|
||||||
|
*/
|
||||||
|
public class JavaLayerUtils
|
||||||
|
{
|
||||||
|
static private JavaLayerHook hook = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes the object contained in the given input stream.
|
||||||
|
* @param in The input stream to deserialize an object from.
|
||||||
|
* @param cls The expected class of the deserialized object.
|
||||||
|
*/
|
||||||
|
static public Object deserialize(InputStream in, Class cls)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
if (cls==null)
|
||||||
|
throw new NullPointerException("cls");
|
||||||
|
|
||||||
|
Object obj = deserialize(in, cls);
|
||||||
|
if (!cls.isInstance(obj))
|
||||||
|
{
|
||||||
|
throw new InvalidObjectException("type of deserialized instance not of required class.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes an object from the given <code>InputStream</code>.
|
||||||
|
* The deserialization is delegated to an <code>
|
||||||
|
* ObjectInputStream</code> instance.
|
||||||
|
*
|
||||||
|
* @param in The <code>InputStream</code> to deserialize an object
|
||||||
|
* from.
|
||||||
|
*
|
||||||
|
* @return The object deserialized from the stream.
|
||||||
|
* @exception IOException is thrown if there was a problem reading
|
||||||
|
* the underlying stream, or an object could not be deserialized
|
||||||
|
* from the stream.
|
||||||
|
*
|
||||||
|
* @see java.io.ObjectInputStream
|
||||||
|
*/
|
||||||
|
static public Object deserialize(InputStream in)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
if (in==null)
|
||||||
|
throw new NullPointerException("in");
|
||||||
|
|
||||||
|
ObjectInputStream objIn = new ObjectInputStream(in);
|
||||||
|
|
||||||
|
Object obj;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
obj = objIn.readObject();
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ex)
|
||||||
|
{
|
||||||
|
throw new InvalidClassException(ex.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes an array from a given <code>InputStream</code>.
|
||||||
|
*
|
||||||
|
* @param in The <code>InputStream</code> to
|
||||||
|
* deserialize an object from.
|
||||||
|
*
|
||||||
|
* @param elemType The class denoting the type of the array
|
||||||
|
* elements.
|
||||||
|
* @param length The expected length of the array, or -1 if
|
||||||
|
* any length is expected.
|
||||||
|
*/
|
||||||
|
static public Object deserializeArray(InputStream in, Class elemType, int length)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
if (elemType==null)
|
||||||
|
throw new NullPointerException("elemType");
|
||||||
|
|
||||||
|
if (length<-1)
|
||||||
|
throw new IllegalArgumentException("length");
|
||||||
|
|
||||||
|
Object obj = deserialize(in);
|
||||||
|
|
||||||
|
Class cls = obj.getClass();
|
||||||
|
|
||||||
|
|
||||||
|
if (!cls.isArray())
|
||||||
|
throw new InvalidObjectException("object is not an array");
|
||||||
|
|
||||||
|
Class arrayElemType = cls.getComponentType();
|
||||||
|
if (arrayElemType!=elemType)
|
||||||
|
throw new InvalidObjectException("unexpected array component type");
|
||||||
|
|
||||||
|
if (length != -1)
|
||||||
|
{
|
||||||
|
int arrayLength = Array.getLength(obj);
|
||||||
|
if (arrayLength!=length)
|
||||||
|
throw new InvalidObjectException("array length mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public Object deserializeArrayResource(String name, Class elemType, int length)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
InputStream str = getResourceAsStream(name);
|
||||||
|
if (str==null)
|
||||||
|
throw new IOException("unable to load resource '"+name+"'");
|
||||||
|
|
||||||
|
Object obj = deserializeArray(str, elemType, length);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void serialize(OutputStream out, Object obj)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
if (out==null)
|
||||||
|
throw new NullPointerException("out");
|
||||||
|
|
||||||
|
if (obj==null)
|
||||||
|
throw new NullPointerException("obj");
|
||||||
|
|
||||||
|
ObjectOutputStream objOut = new ObjectOutputStream(out);
|
||||||
|
objOut.writeObject(obj);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the system-wide JavaLayer hook.
|
||||||
|
*/
|
||||||
|
static synchronized public void setHook(JavaLayerHook hook0)
|
||||||
|
{
|
||||||
|
hook = hook0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static synchronized public JavaLayerHook getHook()
|
||||||
|
{
|
||||||
|
return hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an InputStream for a named resource.
|
||||||
|
*
|
||||||
|
* @param name The name of the resource. This must be a simple
|
||||||
|
* name, and not a qualified package name.
|
||||||
|
*
|
||||||
|
* @return The InputStream for the named resource, or null if
|
||||||
|
* the resource has not been found. If a hook has been
|
||||||
|
* provided, its getResourceAsStream() method is called
|
||||||
|
* to retrieve the resource.
|
||||||
|
*/
|
||||||
|
static synchronized public InputStream getResourceAsStream(String name)
|
||||||
|
{
|
||||||
|
InputStream is = null;
|
||||||
|
|
||||||
|
if (hook!=null)
|
||||||
|
{
|
||||||
|
is = hook.getResourceAsStream(name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Class cls = JavaLayerUtils.class;
|
||||||
|
is = cls.getResourceAsStream(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
}
|
||||||
448
src/javazoom/jl/decoder/LayerIDecoder.java
Normal file
448
src/javazoom/jl/decoder/LayerIDecoder.java
Normal file
@@ -0,0 +1,448 @@
|
|||||||
|
/*
|
||||||
|
* 09/26/08 throw exception on subbband alloc error: Christopher G. Jennings (cjennings@acm.org)
|
||||||
|
*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*
|
||||||
|
* 12/12/99 Initial version. Adapted from javalayer.java
|
||||||
|
* and Subband*.java. mdm@techie.com
|
||||||
|
*
|
||||||
|
* 02/28/99 Initial version : javalayer.java by E.B
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements decoding of MPEG Audio Layer I frames.
|
||||||
|
*/
|
||||||
|
class LayerIDecoder implements FrameDecoder
|
||||||
|
{
|
||||||
|
protected Bitstream stream;
|
||||||
|
protected Header header;
|
||||||
|
protected SynthesisFilter filter1, filter2;
|
||||||
|
protected Obuffer buffer;
|
||||||
|
protected int which_channels;
|
||||||
|
protected int mode;
|
||||||
|
|
||||||
|
protected int num_subbands;
|
||||||
|
protected Subband[] subbands;
|
||||||
|
protected Crc16 crc = null; // new Crc16[1] to enable CRC checking.
|
||||||
|
|
||||||
|
public LayerIDecoder()
|
||||||
|
{
|
||||||
|
crc = new Crc16();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void create(Bitstream stream0, Header header0,
|
||||||
|
SynthesisFilter filtera, SynthesisFilter filterb,
|
||||||
|
Obuffer buffer0, int which_ch0)
|
||||||
|
{
|
||||||
|
stream = stream0;
|
||||||
|
header = header0;
|
||||||
|
filter1 = filtera;
|
||||||
|
filter2 = filterb;
|
||||||
|
buffer = buffer0;
|
||||||
|
which_channels = which_ch0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeFrame() throws DecoderException
|
||||||
|
{
|
||||||
|
|
||||||
|
num_subbands = header.number_of_subbands();
|
||||||
|
subbands = new Subband[32];
|
||||||
|
mode = header.mode();
|
||||||
|
|
||||||
|
createSubbands();
|
||||||
|
|
||||||
|
readAllocation();
|
||||||
|
readScaleFactorSelection();
|
||||||
|
|
||||||
|
if ((crc != null) || header.checksum_ok())
|
||||||
|
{
|
||||||
|
readScaleFactors();
|
||||||
|
|
||||||
|
readSampleData();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createSubbands()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (mode == Header.SINGLE_CHANNEL)
|
||||||
|
for (i = 0; i < num_subbands; ++i)
|
||||||
|
subbands[i] = new SubbandLayer1(i);
|
||||||
|
else if (mode == Header.JOINT_STEREO)
|
||||||
|
{
|
||||||
|
for (i = 0; i < header.intensity_stereo_bound(); ++i)
|
||||||
|
subbands[i] = new SubbandLayer1Stereo(i);
|
||||||
|
for (; i < num_subbands; ++i)
|
||||||
|
subbands[i] = new SubbandLayer1IntensityStereo(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < num_subbands; ++i)
|
||||||
|
subbands[i] = new SubbandLayer1Stereo(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void readAllocation() throws DecoderException
|
||||||
|
{
|
||||||
|
// start to read audio data:
|
||||||
|
for (int i = 0; i < num_subbands; ++i)
|
||||||
|
subbands[i].read_allocation(stream, header, crc);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void readScaleFactorSelection()
|
||||||
|
{
|
||||||
|
// scale factor selection not present for layer I.
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void readScaleFactors()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < num_subbands; ++i)
|
||||||
|
subbands[i].read_scalefactor(stream, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void readSampleData()
|
||||||
|
{
|
||||||
|
boolean read_ready = false;
|
||||||
|
boolean write_ready = false;
|
||||||
|
int mode = header.mode();
|
||||||
|
int i;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
for (i = 0; i < num_subbands; ++i)
|
||||||
|
read_ready = subbands[i].read_sampledata(stream);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
for (i = 0; i < num_subbands; ++i)
|
||||||
|
write_ready = subbands[i].put_next_sample(which_channels,filter1, filter2);
|
||||||
|
|
||||||
|
filter1.calculate_pcm_samples(buffer);
|
||||||
|
if ((which_channels == OutputChannels.BOTH_CHANNELS) && (mode != Header.SINGLE_CHANNEL))
|
||||||
|
filter2.calculate_pcm_samples(buffer);
|
||||||
|
} while (!write_ready);
|
||||||
|
} while (!read_ready);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for subband classes of layer I and II
|
||||||
|
*/
|
||||||
|
static abstract class Subband
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Changes from version 1.1 to 1.2:
|
||||||
|
* - array size increased by one, although a scalefactor with index 63
|
||||||
|
* is illegal (to prevent segmentation faults)
|
||||||
|
*/
|
||||||
|
// Scalefactors for layer I and II, Annex 3-B.1 in ISO/IEC DIS 11172:
|
||||||
|
public static final float scalefactors[] =
|
||||||
|
{
|
||||||
|
2.00000000000000f, 1.58740105196820f, 1.25992104989487f, 1.00000000000000f,
|
||||||
|
0.79370052598410f, 0.62996052494744f, 0.50000000000000f, 0.39685026299205f,
|
||||||
|
0.31498026247372f, 0.25000000000000f, 0.19842513149602f, 0.15749013123686f,
|
||||||
|
0.12500000000000f, 0.09921256574801f, 0.07874506561843f, 0.06250000000000f,
|
||||||
|
0.04960628287401f, 0.03937253280921f, 0.03125000000000f, 0.02480314143700f,
|
||||||
|
0.01968626640461f, 0.01562500000000f, 0.01240157071850f, 0.00984313320230f,
|
||||||
|
0.00781250000000f, 0.00620078535925f, 0.00492156660115f, 0.00390625000000f,
|
||||||
|
0.00310039267963f, 0.00246078330058f, 0.00195312500000f, 0.00155019633981f,
|
||||||
|
0.00123039165029f, 0.00097656250000f, 0.00077509816991f, 0.00061519582514f,
|
||||||
|
0.00048828125000f, 0.00038754908495f, 0.00030759791257f, 0.00024414062500f,
|
||||||
|
0.00019377454248f, 0.00015379895629f, 0.00012207031250f, 0.00009688727124f,
|
||||||
|
0.00007689947814f, 0.00006103515625f, 0.00004844363562f, 0.00003844973907f,
|
||||||
|
0.00003051757813f, 0.00002422181781f, 0.00001922486954f, 0.00001525878906f,
|
||||||
|
0.00001211090890f, 0.00000961243477f, 0.00000762939453f, 0.00000605545445f,
|
||||||
|
0.00000480621738f, 0.00000381469727f, 0.00000302772723f, 0.00000240310869f,
|
||||||
|
0.00000190734863f, 0.00000151386361f, 0.00000120155435f, 0.00000000000000f /* illegal scalefactor */
|
||||||
|
};
|
||||||
|
|
||||||
|
public abstract void read_allocation (Bitstream stream, Header header, Crc16 crc) throws DecoderException;
|
||||||
|
public abstract void read_scalefactor (Bitstream stream, Header header);
|
||||||
|
public abstract boolean read_sampledata (Bitstream stream);
|
||||||
|
public abstract boolean put_next_sample (int channels, SynthesisFilter filter1, SynthesisFilter filter2);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for layer I subbands in single channel mode.
|
||||||
|
* Used for single channel mode
|
||||||
|
* and in derived class for intensity stereo mode
|
||||||
|
*/
|
||||||
|
static class SubbandLayer1 extends Subband
|
||||||
|
{
|
||||||
|
|
||||||
|
// Factors and offsets for sample requantization
|
||||||
|
public static final float table_factor[] = {
|
||||||
|
0.0f, (1.0f/2.0f) * (4.0f/3.0f), (1.0f/4.0f) * (8.0f/7.0f), (1.0f/8.0f) * (16.0f/15.0f),
|
||||||
|
(1.0f/16.0f) * (32.0f/31.0f), (1.0f/32.0f) * (64.0f/63.0f), (1.0f/64.0f) * (128.0f/127.0f),
|
||||||
|
(1.0f/128.0f) * (256.0f/255.0f), (1.0f/256.0f) * (512.0f/511.0f),
|
||||||
|
(1.0f/512.0f) * (1024.0f/1023.0f), (1.0f/1024.0f) * (2048.0f/2047.0f),
|
||||||
|
(1.0f/2048.0f) * (4096.0f/4095.0f), (1.0f/4096.0f) * (8192.0f/8191.0f),
|
||||||
|
(1.0f/8192.0f) * (16384.0f/16383.0f), (1.0f/16384.0f) * (32768.0f/32767.0f)
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final float table_offset[] = {
|
||||||
|
0.0f, ((1.0f/2.0f)-1.0f) * (4.0f/3.0f), ((1.0f/4.0f)-1.0f) * (8.0f/7.0f), ((1.0f/8.0f)-1.0f) * (16.0f/15.0f),
|
||||||
|
((1.0f/16.0f)-1.0f) * (32.0f/31.0f), ((1.0f/32.0f)-1.0f) * (64.0f/63.0f), ((1.0f/64.0f)-1.0f) * (128.0f/127.0f),
|
||||||
|
((1.0f/128.0f)-1.0f) * (256.0f/255.0f), ((1.0f/256.0f)-1.0f) * (512.0f/511.0f),
|
||||||
|
((1.0f/512.0f)-1.0f) * (1024.0f/1023.0f), ((1.0f/1024.0f)-1.0f) * (2048.0f/2047.0f),
|
||||||
|
((1.0f/2048.0f)-1.0f) * (4096.0f/4095.0f), ((1.0f/4096.0f)-1.0f) * (8192.0f/8191.0f),
|
||||||
|
((1.0f/8192.0f)-1.0f) * (16384.0f/16383.0f), ((1.0f/16384.0f)-1.0f) * (32768.0f/32767.0f)
|
||||||
|
};
|
||||||
|
|
||||||
|
protected int subbandnumber;
|
||||||
|
protected int samplenumber;
|
||||||
|
protected int allocation;
|
||||||
|
protected float scalefactor;
|
||||||
|
protected int samplelength;
|
||||||
|
protected float sample;
|
||||||
|
protected float factor, offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construtor.
|
||||||
|
*/
|
||||||
|
public SubbandLayer1(int subbandnumber)
|
||||||
|
{
|
||||||
|
this.subbandnumber = subbandnumber;
|
||||||
|
samplenumber = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void read_allocation(Bitstream stream, Header header, Crc16 crc) throws DecoderException
|
||||||
|
{
|
||||||
|
if ((allocation = stream.get_bits (4)) == 15)
|
||||||
|
{
|
||||||
|
// CGJ: catch this condition and throw appropriate exception
|
||||||
|
throw new DecoderException(DecoderErrors.ILLEGAL_SUBBAND_ALLOCATION, null);
|
||||||
|
// cerr << "WARNING: stream contains an illegal allocation!\n";
|
||||||
|
// MPEG-stream is corrupted!
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crc != null) crc.add_bits (allocation, 4);
|
||||||
|
if (allocation != 0)
|
||||||
|
{
|
||||||
|
samplelength = allocation + 1;
|
||||||
|
factor = table_factor[allocation];
|
||||||
|
offset = table_offset[allocation];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void read_scalefactor(Bitstream stream, Header header)
|
||||||
|
{
|
||||||
|
if (allocation != 0) scalefactor = scalefactors[stream.get_bits(6)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean read_sampledata(Bitstream stream)
|
||||||
|
{
|
||||||
|
if (allocation != 0)
|
||||||
|
{
|
||||||
|
sample = (float) (stream.get_bits(samplelength));
|
||||||
|
}
|
||||||
|
if (++samplenumber == 12)
|
||||||
|
{
|
||||||
|
samplenumber = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2)
|
||||||
|
{
|
||||||
|
if ((allocation !=0) && (channels != OutputChannels.RIGHT_CHANNEL))
|
||||||
|
{
|
||||||
|
float scaled_sample = (sample * factor + offset) * scalefactor;
|
||||||
|
filter1.input_sample (scaled_sample, subbandnumber);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for layer I subbands in joint stereo mode.
|
||||||
|
*/
|
||||||
|
static class SubbandLayer1IntensityStereo extends SubbandLayer1
|
||||||
|
{
|
||||||
|
protected float channel2_scalefactor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public SubbandLayer1IntensityStereo(int subbandnumber)
|
||||||
|
{
|
||||||
|
super(subbandnumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void read_allocation(Bitstream stream, Header header, Crc16 crc) throws DecoderException
|
||||||
|
{
|
||||||
|
super.read_allocation (stream, header, crc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void read_scalefactor (Bitstream stream, Header header)
|
||||||
|
{
|
||||||
|
if (allocation != 0)
|
||||||
|
{
|
||||||
|
scalefactor = scalefactors[stream.get_bits(6)];
|
||||||
|
channel2_scalefactor = scalefactors[stream.get_bits(6)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean read_sampledata(Bitstream stream)
|
||||||
|
{
|
||||||
|
return super.read_sampledata (stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean put_next_sample (int channels, SynthesisFilter filter1, SynthesisFilter filter2)
|
||||||
|
{
|
||||||
|
if (allocation !=0 )
|
||||||
|
{
|
||||||
|
sample = sample * factor + offset; // requantization
|
||||||
|
if (channels == OutputChannels.BOTH_CHANNELS)
|
||||||
|
{
|
||||||
|
float sample1 = sample * scalefactor,
|
||||||
|
sample2 = sample * channel2_scalefactor;
|
||||||
|
filter1.input_sample(sample1, subbandnumber);
|
||||||
|
filter2.input_sample(sample2, subbandnumber);
|
||||||
|
}
|
||||||
|
else if (channels == OutputChannels.LEFT_CHANNEL)
|
||||||
|
{
|
||||||
|
float sample1 = sample * scalefactor;
|
||||||
|
filter1.input_sample(sample1, subbandnumber);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float sample2 = sample * channel2_scalefactor;
|
||||||
|
filter1.input_sample(sample2, subbandnumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for layer I subbands in stereo mode.
|
||||||
|
*/
|
||||||
|
static class SubbandLayer1Stereo extends SubbandLayer1
|
||||||
|
{
|
||||||
|
protected int channel2_allocation;
|
||||||
|
protected float channel2_scalefactor;
|
||||||
|
protected int channel2_samplelength;
|
||||||
|
protected float channel2_sample;
|
||||||
|
protected float channel2_factor, channel2_offset;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public SubbandLayer1Stereo(int subbandnumber)
|
||||||
|
{
|
||||||
|
super(subbandnumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void read_allocation (Bitstream stream, Header header, Crc16 crc) throws DecoderException
|
||||||
|
{
|
||||||
|
allocation = stream.get_bits(4);
|
||||||
|
channel2_allocation = stream.get_bits(4);
|
||||||
|
if (crc != null)
|
||||||
|
{
|
||||||
|
crc.add_bits (allocation, 4);
|
||||||
|
crc.add_bits (channel2_allocation, 4);
|
||||||
|
}
|
||||||
|
if (allocation != 0)
|
||||||
|
{
|
||||||
|
samplelength = allocation + 1;
|
||||||
|
factor = table_factor[allocation];
|
||||||
|
offset = table_offset[allocation];
|
||||||
|
}
|
||||||
|
if (channel2_allocation != 0)
|
||||||
|
{
|
||||||
|
channel2_samplelength = channel2_allocation + 1;
|
||||||
|
channel2_factor = table_factor[channel2_allocation];
|
||||||
|
channel2_offset = table_offset[channel2_allocation];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void read_scalefactor(Bitstream stream, Header header)
|
||||||
|
{
|
||||||
|
if (allocation != 0) scalefactor = scalefactors[stream.get_bits(6)];
|
||||||
|
if (channel2_allocation != 0) channel2_scalefactor = scalefactors[stream.get_bits(6)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean read_sampledata (Bitstream stream)
|
||||||
|
{
|
||||||
|
boolean returnvalue = super.read_sampledata(stream);
|
||||||
|
if (channel2_allocation != 0)
|
||||||
|
{
|
||||||
|
channel2_sample = (float) (stream.get_bits(channel2_samplelength));
|
||||||
|
}
|
||||||
|
return(returnvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2)
|
||||||
|
{
|
||||||
|
super.put_next_sample (channels, filter1, filter2);
|
||||||
|
if ((channel2_allocation != 0) && (channels != OutputChannels.LEFT_CHANNEL))
|
||||||
|
{
|
||||||
|
float sample2 = (channel2_sample * channel2_factor + channel2_offset) *
|
||||||
|
channel2_scalefactor;
|
||||||
|
if (channels == OutputChannels.BOTH_CHANNELS)
|
||||||
|
filter2.input_sample (sample2, subbandnumber);
|
||||||
|
else
|
||||||
|
filter1.input_sample (sample2, subbandnumber);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
1064
src/javazoom/jl/decoder/LayerIIDecoder.java
Normal file
1064
src/javazoom/jl/decoder/LayerIIDecoder.java
Normal file
File diff suppressed because it is too large
Load Diff
2439
src/javazoom/jl/decoder/LayerIIIDecoder.java
Normal file
2439
src/javazoom/jl/decoder/LayerIIIDecoder.java
Normal file
File diff suppressed because it is too large
Load Diff
46
src/javazoom/jl/decoder/Manager.java
Normal file
46
src/javazoom/jl/decoder/Manager.java
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Work in progress.
|
||||||
|
*
|
||||||
|
* Manages a number of controls.
|
||||||
|
*/
|
||||||
|
public class Manager //implements Control
|
||||||
|
{
|
||||||
|
public void addControl(Control c)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeControl(Control c)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAll()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// control interface delegates to a managed control
|
||||||
|
|
||||||
|
}
|
||||||
88
src/javazoom/jl/decoder/Obuffer.java
Normal file
88
src/javazoom/jl/decoder/Obuffer.java
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Added appendSamples() method for efficiency. MDM.
|
||||||
|
* 15/02/99 ,Java Conversion by E.B ,ebsp@iname.com, JavaLayer
|
||||||
|
*
|
||||||
|
* Declarations for output buffer, includes operating system
|
||||||
|
* implementation of the virtual Obuffer. Optional routines
|
||||||
|
* enabling seeks and stops added by Jeff Tsay.
|
||||||
|
*
|
||||||
|
* @(#) obuffer.h 1.8, last edit: 6/15/94 16:51:56
|
||||||
|
* @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
|
||||||
|
* @(#) Berlin University of Technology
|
||||||
|
*
|
||||||
|
* Idea and first implementation for u-law output with fast downsampling by
|
||||||
|
* Jim Boucher (jboucher@flash.bu.edu)
|
||||||
|
*
|
||||||
|
* LinuxObuffer class written by
|
||||||
|
* Louis P. Kruger (lpkruger@phoenix.princeton.edu)
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Class for audio output.
|
||||||
|
*/
|
||||||
|
public abstract class Obuffer
|
||||||
|
{
|
||||||
|
public static final int OBUFFERSIZE = 2 * 1152; // max. 2 * 1152 samples per frame
|
||||||
|
public static final int MAXCHANNELS = 2; // max. number of channels
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a 16 Bit PCM sample.
|
||||||
|
*/
|
||||||
|
public abstract void append(int channel, short value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts 32 new PCM samples.
|
||||||
|
*/
|
||||||
|
public void appendSamples(int channel, float[] f)
|
||||||
|
{
|
||||||
|
short s;
|
||||||
|
for (int i=0; i<32;)
|
||||||
|
{
|
||||||
|
s = clip(f[i++]);
|
||||||
|
append(channel, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clip Sample to 16 Bits
|
||||||
|
*/
|
||||||
|
private final short clip(float sample)
|
||||||
|
{
|
||||||
|
return ((sample > 32767.0f) ? 32767 :
|
||||||
|
((sample < -32768.0f) ? -32768 :
|
||||||
|
(short) sample));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the samples to the file or directly to the audio hardware.
|
||||||
|
*/
|
||||||
|
public abstract void write_buffer(int val);
|
||||||
|
public abstract void close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all data in the buffer (for seeking).
|
||||||
|
*/
|
||||||
|
public abstract void clear_buffer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the buffer that the user has stopped the stream.
|
||||||
|
*/
|
||||||
|
public abstract void set_stop_flag();
|
||||||
|
}
|
||||||
143
src/javazoom/jl/decoder/OutputChannels.java
Normal file
143
src/javazoom/jl/decoder/OutputChannels.java
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 12/12/99 Initial implementation. mdm@techie.com.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Type-safe representation of the the supported output channel
|
||||||
|
* constants.
|
||||||
|
*
|
||||||
|
* This class is immutable and, hence, is thread safe.
|
||||||
|
*
|
||||||
|
* @author Mat McGowan 12/12/99
|
||||||
|
* @since 0.0.7
|
||||||
|
*/
|
||||||
|
public class OutputChannels
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Flag to indicate output should include both channels.
|
||||||
|
*/
|
||||||
|
public static final int BOTH_CHANNELS = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag to indicate output should include the left channel only.
|
||||||
|
*/
|
||||||
|
public static final int LEFT_CHANNEL = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag to indicate output should include the right channel only.
|
||||||
|
*/
|
||||||
|
public static final int RIGHT_CHANNEL = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag to indicate output is mono.
|
||||||
|
*/
|
||||||
|
public static final int DOWNMIX_CHANNELS = 3;
|
||||||
|
|
||||||
|
|
||||||
|
public static final OutputChannels LEFT = new OutputChannels(LEFT_CHANNEL);
|
||||||
|
public static final OutputChannels RIGHT = new OutputChannels(RIGHT_CHANNEL);
|
||||||
|
public static final OutputChannels BOTH = new OutputChannels(BOTH_CHANNELS);
|
||||||
|
public static final OutputChannels DOWNMIX = new OutputChannels(DOWNMIX_CHANNELS);
|
||||||
|
|
||||||
|
|
||||||
|
private /*final*/ int outputChannels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an <code>OutputChannels</code> instance
|
||||||
|
* corresponding to the given channel code.
|
||||||
|
*
|
||||||
|
* @param code one of the OutputChannels channel code constants.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if code is not a valid
|
||||||
|
* channel code.
|
||||||
|
*/
|
||||||
|
static public OutputChannels fromInt(int code)
|
||||||
|
{
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case LEFT_CHANNEL:
|
||||||
|
return LEFT;
|
||||||
|
case RIGHT_CHANNEL:
|
||||||
|
return RIGHT;
|
||||||
|
case BOTH_CHANNELS:
|
||||||
|
return BOTH;
|
||||||
|
case DOWNMIX_CHANNELS:
|
||||||
|
return DOWNMIX;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid channel code: "+code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private OutputChannels(int channels)
|
||||||
|
{
|
||||||
|
outputChannels = channels;
|
||||||
|
|
||||||
|
if (channels<0 || channels>3)
|
||||||
|
throw new IllegalArgumentException("channels");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the code representing the desired output channels.
|
||||||
|
* Will be one of LEFT_CHANNEL, RIGHT_CHANNEL, BOTH_CHANNELS
|
||||||
|
* or DOWNMIX_CHANNELS.
|
||||||
|
*
|
||||||
|
* @return the channel code represented by this instance.
|
||||||
|
*/
|
||||||
|
public int getChannelsOutputCode()
|
||||||
|
{
|
||||||
|
return outputChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the number of output channels represented
|
||||||
|
* by this channel output type.
|
||||||
|
*
|
||||||
|
* @return The number of output channels for this channel output
|
||||||
|
* type. This will be 2 for BOTH_CHANNELS only, and 1
|
||||||
|
* for all other types.
|
||||||
|
*/
|
||||||
|
public int getChannelCount()
|
||||||
|
{
|
||||||
|
int count = (outputChannels==BOTH_CHANNELS) ? 2 : 1;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean equals(Object o)
|
||||||
|
{
|
||||||
|
boolean equals = false;
|
||||||
|
|
||||||
|
if (o instanceof OutputChannels)
|
||||||
|
{
|
||||||
|
OutputChannels oc = (OutputChannels)o;
|
||||||
|
equals = (oc.outputChannels == outputChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
return equals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return outputChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
132
src/javazoom/jl/decoder/SampleBuffer.java
Normal file
132
src/javazoom/jl/decoder/SampleBuffer.java
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*
|
||||||
|
* 12/12/99 Initial Version based on FileObuffer. mdm@techie.com.
|
||||||
|
*
|
||||||
|
* FileObuffer:
|
||||||
|
* 15/02/99 Java Conversion by E.B ,javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>SampleBuffer</code> class implements an output buffer
|
||||||
|
* that provides storage for a fixed size block of samples.
|
||||||
|
*/
|
||||||
|
public class SampleBuffer extends Obuffer
|
||||||
|
{
|
||||||
|
private short[] buffer;
|
||||||
|
private int[] bufferp;
|
||||||
|
private int channels;
|
||||||
|
private int frequency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public SampleBuffer(int sample_frequency, int number_of_channels)
|
||||||
|
{
|
||||||
|
buffer = new short[OBUFFERSIZE];
|
||||||
|
bufferp = new int[MAXCHANNELS];
|
||||||
|
channels = number_of_channels;
|
||||||
|
frequency = sample_frequency;
|
||||||
|
|
||||||
|
for (int i = 0; i < number_of_channels; ++i)
|
||||||
|
bufferp[i] = (short)i;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChannelCount()
|
||||||
|
{
|
||||||
|
return this.channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSampleFrequency()
|
||||||
|
{
|
||||||
|
return this.frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short[] getBuffer()
|
||||||
|
{
|
||||||
|
return this.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBufferLength()
|
||||||
|
{
|
||||||
|
return bufferp[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a 16 Bit PCM sample.
|
||||||
|
*/
|
||||||
|
public void append(int channel, short value)
|
||||||
|
{
|
||||||
|
buffer[bufferp[channel]] = value;
|
||||||
|
bufferp[channel] += channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendSamples(int channel, float[] f)
|
||||||
|
{
|
||||||
|
int pos = bufferp[channel];
|
||||||
|
|
||||||
|
short s;
|
||||||
|
float fs;
|
||||||
|
for (int i=0; i<32;)
|
||||||
|
{
|
||||||
|
fs = f[i++];
|
||||||
|
fs = (fs>32767.0f ? 32767.0f
|
||||||
|
: (fs < -32767.0f ? -32767.0f : fs));
|
||||||
|
|
||||||
|
s = (short)fs;
|
||||||
|
buffer[pos] = s;
|
||||||
|
pos += channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferp[channel] = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the samples to the file (Random Acces).
|
||||||
|
*/
|
||||||
|
public void write_buffer(int val)
|
||||||
|
{
|
||||||
|
|
||||||
|
//for (int i = 0; i < channels; ++i)
|
||||||
|
// bufferp[i] = (short)i;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void clear_buffer()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < channels; ++i)
|
||||||
|
bufferp[i] = (short)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void set_stop_flag()
|
||||||
|
{}
|
||||||
|
}
|
||||||
49
src/javazoom/jl/decoder/Source.java
Normal file
49
src/javazoom/jl/decoder/Source.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Work in progress.
|
||||||
|
*
|
||||||
|
* Class to describe a seekable data source.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface Source
|
||||||
|
{
|
||||||
|
|
||||||
|
public static final long LENGTH_UNKNOWN = -1;
|
||||||
|
|
||||||
|
public int read(byte[] b, int offs, int len)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
|
|
||||||
|
public boolean willReadBlock();
|
||||||
|
|
||||||
|
public boolean isSeekable();
|
||||||
|
|
||||||
|
public long length();
|
||||||
|
|
||||||
|
public long tell();
|
||||||
|
|
||||||
|
public long seek(long pos);
|
||||||
|
|
||||||
|
}
|
||||||
1817
src/javazoom/jl/decoder/SynthesisFilter.java
Normal file
1817
src/javazoom/jl/decoder/SynthesisFilter.java
Normal file
File diff suppressed because it is too large
Load Diff
BIN
src/javazoom/jl/decoder/au2lin.ser
Normal file
BIN
src/javazoom/jl/decoder/au2lin.ser
Normal file
Binary file not shown.
600
src/javazoom/jl/decoder/huffcodetab.java
Normal file
600
src/javazoom/jl/decoder/huffcodetab.java
Normal file
@@ -0,0 +1,600 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 16/11/99 Renamed class, added javadoc, and changed table
|
||||||
|
* name from String to 3 chars. mdm@techie.com
|
||||||
|
* 02/15/99 Java Conversion by E.B, javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
* 04/19/97 : Adapted from the ISO MPEG Audio Subgroup Software Simulation
|
||||||
|
* Group's public c source for its MPEG audio decoder. Miscellaneous
|
||||||
|
* changes by Jeff Tsay (ctsay@pasteur.eecs.berkeley.edu).
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* Copyright (c) 1991 MPEG/audio software simulation group, All Rights Reserved
|
||||||
|
* MPEG/audio coding/decoding software, work in progress
|
||||||
|
* NOT for public distribution until verified and approved by the
|
||||||
|
* MPEG/audio committee. For further information, please contact
|
||||||
|
* Davis Pan, 508-493-2241, e-mail: pan@3d.enet.dec.com
|
||||||
|
*
|
||||||
|
* VERSION 4.1
|
||||||
|
* changes made since last update:
|
||||||
|
* date programmers comment
|
||||||
|
* 27.2.92 F.O.Witte (ITT Intermetall)
|
||||||
|
* 8/24/93 M. Iwadare Changed for 1 pass decoding.
|
||||||
|
* 7/14/94 J. Koller useless 'typedef' before huffcodetab removed
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to implements Huffman decoder.
|
||||||
|
*/
|
||||||
|
final class huffcodetab
|
||||||
|
{
|
||||||
|
private static final int MXOFF=250;
|
||||||
|
private static final int HTN=34;
|
||||||
|
|
||||||
|
private char tablename0 = ' '; /* string, containing table_description */
|
||||||
|
private char tablename1 = ' '; /* string, containing table_description */
|
||||||
|
private char tablename2 = ' '; /* string, containing table_description */
|
||||||
|
|
||||||
|
private int xlen; /* max. x-index+ */
|
||||||
|
private int ylen; /* max. y-index+ */
|
||||||
|
private int linbits; /* number of linbits */
|
||||||
|
private int linmax; /* max number to be stored in linbits */
|
||||||
|
private int ref; /* a positive value indicates a reference */
|
||||||
|
private int[] table=null; /* pointer to array[xlen][ylen] */
|
||||||
|
private int[] hlen=null; /* pointer to array[xlen][ylen] */
|
||||||
|
private int[][] val=null; /* decoder tree */
|
||||||
|
private int treelen; /* length of decoder tree */
|
||||||
|
|
||||||
|
private static int ValTab0[][] = {
|
||||||
|
{0,0} // dummy
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab1[][] = {
|
||||||
|
{2,1},{0,0},{2,1},{0,16},{2,1},{0,1},{0,17},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab2[][] = {
|
||||||
|
{2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1},{2,1},
|
||||||
|
{0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab3[][] = {
|
||||||
|
{4,1},{2,1},{0,0},{0,1},{2,1},{0,17},{2,1},{0,16},{4,1},{2,1},
|
||||||
|
{0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab4[][] = {{0,0}}; // dummy
|
||||||
|
|
||||||
|
private static int ValTab5[][] = {
|
||||||
|
{2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{8,1},{4,1},
|
||||||
|
{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{8,1},{4,1},{2,1},{0,34},
|
||||||
|
{0,48},{2,1},{0,3},{0,19},{2,1},{0,49},{2,1},{0,50},{2,1},{0,35},
|
||||||
|
{0,51},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab6[][] = {
|
||||||
|
{6,1},{4,1},{2,1},{0,0},{0,16},{0,17},{6,1},{2,1},{0,1},{2,1},
|
||||||
|
{0,32},{0,33},{6,1},{2,1},{0,18},{2,1},{0,2},{0,34},{4,1},{2,1},
|
||||||
|
{0,49},{0,19},{4,1},{2,1},{0,48},{0,50},{2,1},{0,35},{2,1},{0,3},
|
||||||
|
{0,51},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab7[][] = {
|
||||||
|
{2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{8,1},{2,1},{0,17},{4,1},
|
||||||
|
{2,1},{0,32},{0,2},{0,33},{18,1},{6,1},{2,1},{0,18},{2,1},{0,34},
|
||||||
|
{0,48},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1},{0,3},{0,50},{2,1},
|
||||||
|
{0,35},{0,4},{10,1},{4,1},{2,1},{0,64},{0,65},{2,1},{0,20},{2,1},
|
||||||
|
{0,66},{0,36},{12,1},{6,1},{4,1},{2,1},{0,51},{0,67},{0,80},{4,1},
|
||||||
|
{2,1},{0,52},{0,5},{0,81},{6,1},{2,1},{0,21},{2,1},{0,82},{0,37},
|
||||||
|
{4,1},{2,1},{0,68},{0,53},{4,1},{2,1},{0,83},{0,84},{2,1},{0,69},
|
||||||
|
{0,85},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab8[][] = {
|
||||||
|
{6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1},{2,1},
|
||||||
|
{0,33},{0,18},{14,1},{4,1},{2,1},{0,32},{0,2},{2,1},{0,34},{4,1},
|
||||||
|
{2,1},{0,48},{0,3},{2,1},{0,49},{0,19},{14,1},{8,1},{4,1},{2,1},
|
||||||
|
{0,50},{0,35},{2,1},{0,64},{0,4},{2,1},{0,65},{2,1},{0,20},{0,66},
|
||||||
|
{12,1},{6,1},{2,1},{0,36},{2,1},{0,51},{0,80},{4,1},{2,1},{0,67},
|
||||||
|
{0,52},{0,81},{6,1},{2,1},{0,21},{2,1},{0,5},{0,82},{6,1},{2,1},
|
||||||
|
{0,37},{2,1},{0,68},{0,53},{2,1},{0,83},{2,1},{0,69},{2,1},{0,84},
|
||||||
|
{0,85},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab9[][] = {
|
||||||
|
{8,1},{4,1},{2,1},{0,0},{0,16},{2,1},{0,1},{0,17},{10,1},{4,1},
|
||||||
|
{2,1},{0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34},{12,1},{6,1},
|
||||||
|
{4,1},{2,1},{0,48},{0,3},{0,49},{2,1},{0,19},{2,1},{0,50},{0,35},
|
||||||
|
{12,1},{4,1},{2,1},{0,65},{0,20},{4,1},{2,1},{0,64},{0,51},{2,1},
|
||||||
|
{0,66},{0,36},{10,1},{6,1},{4,1},{2,1},{0,4},{0,80},{0,67},{2,1},
|
||||||
|
{0,52},{0,81},{8,1},{4,1},{2,1},{0,21},{0,82},{2,1},{0,37},{0,68},
|
||||||
|
{6,1},{4,1},{2,1},{0,5},{0,84},{0,83},{2,1},{0,53},{2,1},{0,69},
|
||||||
|
{0,85},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab10[][] = {
|
||||||
|
{2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{10,1},{2,1},{0,17},{4,1},
|
||||||
|
{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{28,1},{8,1},{4,1},{2,1},
|
||||||
|
{0,34},{0,48},{2,1},{0,49},{0,19},{8,1},{4,1},{2,1},{0,3},{0,50},
|
||||||
|
{2,1},{0,35},{0,64},{4,1},{2,1},{0,65},{0,20},{4,1},{2,1},{0,4},
|
||||||
|
{0,51},{2,1},{0,66},{0,36},{28,1},{10,1},{6,1},{4,1},{2,1},{0,80},
|
||||||
|
{0,5},{0,96},{2,1},{0,97},{0,22},{12,1},{6,1},{4,1},{2,1},{0,67},
|
||||||
|
{0,52},{0,81},{2,1},{0,21},{2,1},{0,82},{0,37},{4,1},{2,1},{0,38},
|
||||||
|
{0,54},{0,113},{20,1},{8,1},{2,1},{0,23},{4,1},{2,1},{0,68},{0,83},
|
||||||
|
{0,6},{6,1},{4,1},{2,1},{0,53},{0,69},{0,98},{2,1},{0,112},{2,1},
|
||||||
|
{0,7},{0,100},{14,1},{4,1},{2,1},{0,114},{0,39},{6,1},{2,1},{0,99},
|
||||||
|
{2,1},{0,84},{0,85},{2,1},{0,70},{0,115},{8,1},{4,1},{2,1},{0,55},
|
||||||
|
{0,101},{2,1},{0,86},{0,116},{6,1},{2,1},{0,71},{2,1},{0,102},{0,117},
|
||||||
|
{4,1},{2,1},{0,87},{0,118},{2,1},{0,103},{0,119},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab11[][] = {
|
||||||
|
{6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{8,1},{2,1},{0,17},{4,1},
|
||||||
|
{2,1},{0,32},{0,2},{0,18},{24,1},{8,1},{2,1},{0,33},{2,1},{0,34},
|
||||||
|
{2,1},{0,48},{0,3},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1},{0,50},
|
||||||
|
{0,35},{4,1},{2,1},{0,64},{0,4},{2,1},{0,65},{0,20},{30,1},{16,1},
|
||||||
|
{10,1},{4,1},{2,1},{0,66},{0,36},{4,1},{2,1},{0,51},{0,67},{0,80},
|
||||||
|
{4,1},{2,1},{0,52},{0,81},{0,97},{6,1},{2,1},{0,22},{2,1},{0,6},
|
||||||
|
{0,38},{2,1},{0,98},{2,1},{0,21},{2,1},{0,5},{0,82},{16,1},{10,1},
|
||||||
|
{6,1},{4,1},{2,1},{0,37},{0,68},{0,96},{2,1},{0,99},{0,54},{4,1},
|
||||||
|
{2,1},{0,112},{0,23},{0,113},{16,1},{6,1},{4,1},{2,1},{0,7},{0,100},
|
||||||
|
{0,114},{2,1},{0,39},{4,1},{2,1},{0,83},{0,53},{2,1},{0,84},{0,69},
|
||||||
|
{10,1},{4,1},{2,1},{0,70},{0,115},{2,1},{0,55},{2,1},{0,101},{0,86},
|
||||||
|
{10,1},{6,1},{4,1},{2,1},{0,85},{0,87},{0,116},{2,1},{0,71},{0,102},
|
||||||
|
{4,1},{2,1},{0,117},{0,118},{2,1},{0,103},{0,119},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab12[][] = {
|
||||||
|
{12,1},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{2,1},{0,0},{2,1},
|
||||||
|
{0,32},{0,2},{16,1},{4,1},{2,1},{0,33},{0,18},{4,1},{2,1},{0,34},
|
||||||
|
{0,49},{2,1},{0,19},{2,1},{0,48},{2,1},{0,3},{0,64},{26,1},{8,1},
|
||||||
|
{4,1},{2,1},{0,50},{0,35},{2,1},{0,65},{0,51},{10,1},{4,1},{2,1},
|
||||||
|
{0,20},{0,66},{2,1},{0,36},{2,1},{0,4},{0,80},{4,1},{2,1},{0,67},
|
||||||
|
{0,52},{2,1},{0,81},{0,21},{28,1},{14,1},{8,1},{4,1},{2,1},{0,82},
|
||||||
|
{0,37},{2,1},{0,83},{0,53},{4,1},{2,1},{0,96},{0,22},{0,97},{4,1},
|
||||||
|
{2,1},{0,98},{0,38},{6,1},{4,1},{2,1},{0,5},{0,6},{0,68},{2,1},
|
||||||
|
{0,84},{0,69},{18,1},{10,1},{4,1},{2,1},{0,99},{0,54},{4,1},{2,1},
|
||||||
|
{0,112},{0,7},{0,113},{4,1},{2,1},{0,23},{0,100},{2,1},{0,70},{0,114},
|
||||||
|
{10,1},{6,1},{2,1},{0,39},{2,1},{0,85},{0,115},{2,1},{0,55},{0,86},
|
||||||
|
{8,1},{4,1},{2,1},{0,101},{0,116},{2,1},{0,71},{0,102},{4,1},{2,1},
|
||||||
|
{0,117},{0,87},{2,1},{0,118},{2,1},{0,103},{0,119},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab13[][] = {
|
||||||
|
{2,1},{0,0},{6,1},{2,1},{0,16},{2,1},{0,1},{0,17},{28,1},{8,1},
|
||||||
|
{4,1},{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{8,1},{4,1},{2,1},
|
||||||
|
{0,34},{0,48},{2,1},{0,3},{0,49},{6,1},{2,1},{0,19},{2,1},{0,50},
|
||||||
|
{0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{70,1},{28,1},{14,1},{6,1},
|
||||||
|
{2,1},{0,20},{2,1},{0,51},{0,66},{4,1},{2,1},{0,36},{0,80},{2,1},
|
||||||
|
{0,67},{0,52},{4,1},{2,1},{0,81},{0,21},{4,1},{2,1},{0,5},{0,82},
|
||||||
|
{2,1},{0,37},{2,1},{0,68},{0,83},{14,1},{8,1},{4,1},{2,1},{0,96},
|
||||||
|
{0,6},{2,1},{0,97},{0,22},{4,1},{2,1},{0,128},{0,8},{0,129},{16,1},
|
||||||
|
{8,1},{4,1},{2,1},{0,53},{0,98},{2,1},{0,38},{0,84},{4,1},{2,1},
|
||||||
|
{0,69},{0,99},{2,1},{0,54},{0,112},{6,1},{4,1},{2,1},{0,7},{0,85},
|
||||||
|
{0,113},{2,1},{0,23},{2,1},{0,39},{0,55},{72,1},{24,1},{12,1},{4,1},
|
||||||
|
{2,1},{0,24},{0,130},{2,1},{0,40},{4,1},{2,1},{0,100},{0,70},{0,114},
|
||||||
|
{8,1},{4,1},{2,1},{0,132},{0,72},{2,1},{0,144},{0,9},{2,1},{0,145},
|
||||||
|
{0,25},{24,1},{14,1},{8,1},{4,1},{2,1},{0,115},{0,101},{2,1},{0,86},
|
||||||
|
{0,116},{4,1},{2,1},{0,71},{0,102},{0,131},{6,1},{2,1},{0,56},{2,1},
|
||||||
|
{0,117},{0,87},{2,1},{0,146},{0,41},{14,1},{8,1},{4,1},{2,1},{0,103},
|
||||||
|
{0,133},{2,1},{0,88},{0,57},{2,1},{0,147},{2,1},{0,73},{0,134},{6,1},
|
||||||
|
{2,1},{0,160},{2,1},{0,104},{0,10},{2,1},{0,161},{0,26},{68,1},{24,1},
|
||||||
|
{12,1},{4,1},{2,1},{0,162},{0,42},{4,1},{2,1},{0,149},{0,89},{2,1},
|
||||||
|
{0,163},{0,58},{8,1},{4,1},{2,1},{0,74},{0,150},{2,1},{0,176},{0,11},
|
||||||
|
{2,1},{0,177},{0,27},{20,1},{8,1},{2,1},{0,178},{4,1},{2,1},{0,118},
|
||||||
|
{0,119},{0,148},{6,1},{4,1},{2,1},{0,135},{0,120},{0,164},{4,1},{2,1},
|
||||||
|
{0,105},{0,165},{0,43},{12,1},{6,1},{4,1},{2,1},{0,90},{0,136},{0,179},
|
||||||
|
{2,1},{0,59},{2,1},{0,121},{0,166},{6,1},{4,1},{2,1},{0,106},{0,180},
|
||||||
|
{0,192},{4,1},{2,1},{0,12},{0,152},{0,193},{60,1},{22,1},{10,1},{6,1},
|
||||||
|
{2,1},{0,28},{2,1},{0,137},{0,181},{2,1},{0,91},{0,194},{4,1},{2,1},
|
||||||
|
{0,44},{0,60},{4,1},{2,1},{0,182},{0,107},{2,1},{0,196},{0,76},{16,1},
|
||||||
|
{8,1},{4,1},{2,1},{0,168},{0,138},{2,1},{0,208},{0,13},{2,1},{0,209},
|
||||||
|
{2,1},{0,75},{2,1},{0,151},{0,167},{12,1},{6,1},{2,1},{0,195},{2,1},
|
||||||
|
{0,122},{0,153},{4,1},{2,1},{0,197},{0,92},{0,183},{4,1},{2,1},{0,29},
|
||||||
|
{0,210},{2,1},{0,45},{2,1},{0,123},{0,211},{52,1},{28,1},{12,1},{4,1},
|
||||||
|
{2,1},{0,61},{0,198},{4,1},{2,1},{0,108},{0,169},{2,1},{0,154},{0,212},
|
||||||
|
{8,1},{4,1},{2,1},{0,184},{0,139},{2,1},{0,77},{0,199},{4,1},{2,1},
|
||||||
|
{0,124},{0,213},{2,1},{0,93},{0,224},{10,1},{4,1},{2,1},{0,225},{0,30},
|
||||||
|
{4,1},{2,1},{0,14},{0,46},{0,226},{8,1},{4,1},{2,1},{0,227},{0,109},
|
||||||
|
{2,1},{0,140},{0,228},{4,1},{2,1},{0,229},{0,186},{0,240},{38,1},{16,1},
|
||||||
|
{4,1},{2,1},{0,241},{0,31},{6,1},{4,1},{2,1},{0,170},{0,155},{0,185},
|
||||||
|
{2,1},{0,62},{2,1},{0,214},{0,200},{12,1},{6,1},{2,1},{0,78},{2,1},
|
||||||
|
{0,215},{0,125},{2,1},{0,171},{2,1},{0,94},{0,201},{6,1},{2,1},{0,15},
|
||||||
|
{2,1},{0,156},{0,110},{2,1},{0,242},{0,47},{32,1},{16,1},{6,1},{4,1},
|
||||||
|
{2,1},{0,216},{0,141},{0,63},{6,1},{2,1},{0,243},{2,1},{0,230},{0,202},
|
||||||
|
{2,1},{0,244},{0,79},{8,1},{4,1},{2,1},{0,187},{0,172},{2,1},{0,231},
|
||||||
|
{0,245},{4,1},{2,1},{0,217},{0,157},{2,1},{0,95},{0,232},{30,1},{12,1},
|
||||||
|
{6,1},{2,1},{0,111},{2,1},{0,246},{0,203},{4,1},{2,1},{0,188},{0,173},
|
||||||
|
{0,218},{8,1},{2,1},{0,247},{4,1},{2,1},{0,126},{0,127},{0,142},{6,1},
|
||||||
|
{4,1},{2,1},{0,158},{0,174},{0,204},{2,1},{0,248},{0,143},{18,1},{8,1},
|
||||||
|
{4,1},{2,1},{0,219},{0,189},{2,1},{0,234},{0,249},{4,1},{2,1},{0,159},
|
||||||
|
{0,235},{2,1},{0,190},{2,1},{0,205},{0,250},{14,1},{4,1},{2,1},{0,221},
|
||||||
|
{0,236},{6,1},{4,1},{2,1},{0,233},{0,175},{0,220},{2,1},{0,206},{0,251},
|
||||||
|
{8,1},{4,1},{2,1},{0,191},{0,222},{2,1},{0,207},{0,238},{4,1},{2,1},
|
||||||
|
{0,223},{0,239},{2,1},{0,255},{2,1},{0,237},{2,1},{0,253},{2,1},{0,252},
|
||||||
|
{0,254},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab14[][] = {
|
||||||
|
{0,0} // dummy
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab15[][] = {
|
||||||
|
{16,1},{6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1},
|
||||||
|
{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{50,1},{16,1},{6,1},{2,1},
|
||||||
|
{0,34},{2,1},{0,48},{0,49},{6,1},{2,1},{0,19},{2,1},{0,3},{0,64},
|
||||||
|
{2,1},{0,50},{0,35},{14,1},{6,1},{4,1},{2,1},{0,4},{0,20},{0,65},
|
||||||
|
{4,1},{2,1},{0,51},{0,66},{2,1},{0,36},{0,67},{10,1},{6,1},{2,1},
|
||||||
|
{0,52},{2,1},{0,80},{0,5},{2,1},{0,81},{0,21},{4,1},{2,1},{0,82},
|
||||||
|
{0,37},{4,1},{2,1},{0,68},{0,83},{0,97},{90,1},{36,1},{18,1},{10,1},
|
||||||
|
{6,1},{2,1},{0,53},{2,1},{0,96},{0,6},{2,1},{0,22},{0,98},{4,1},
|
||||||
|
{2,1},{0,38},{0,84},{2,1},{0,69},{0,99},{10,1},{6,1},{2,1},{0,54},
|
||||||
|
{2,1},{0,112},{0,7},{2,1},{0,113},{0,85},{4,1},{2,1},{0,23},{0,100},
|
||||||
|
{2,1},{0,114},{0,39},{24,1},{16,1},{8,1},{4,1},{2,1},{0,70},{0,115},
|
||||||
|
{2,1},{0,55},{0,101},{4,1},{2,1},{0,86},{0,128},{2,1},{0,8},{0,116},
|
||||||
|
{4,1},{2,1},{0,129},{0,24},{2,1},{0,130},{0,40},{16,1},{8,1},{4,1},
|
||||||
|
{2,1},{0,71},{0,102},{2,1},{0,131},{0,56},{4,1},{2,1},{0,117},{0,87},
|
||||||
|
{2,1},{0,132},{0,72},{6,1},{4,1},{2,1},{0,144},{0,25},{0,145},{4,1},
|
||||||
|
{2,1},{0,146},{0,118},{2,1},{0,103},{0,41},{92,1},{36,1},{18,1},{10,1},
|
||||||
|
{4,1},{2,1},{0,133},{0,88},{4,1},{2,1},{0,9},{0,119},{0,147},{4,1},
|
||||||
|
{2,1},{0,57},{0,148},{2,1},{0,73},{0,134},{10,1},{6,1},{2,1},{0,104},
|
||||||
|
{2,1},{0,160},{0,10},{2,1},{0,161},{0,26},{4,1},{2,1},{0,162},{0,42},
|
||||||
|
{2,1},{0,149},{0,89},{26,1},{14,1},{6,1},{2,1},{0,163},{2,1},{0,58},
|
||||||
|
{0,135},{4,1},{2,1},{0,120},{0,164},{2,1},{0,74},{0,150},{6,1},{4,1},
|
||||||
|
{2,1},{0,105},{0,176},{0,177},{4,1},{2,1},{0,27},{0,165},{0,178},{14,1},
|
||||||
|
{8,1},{4,1},{2,1},{0,90},{0,43},{2,1},{0,136},{0,151},{2,1},{0,179},
|
||||||
|
{2,1},{0,121},{0,59},{8,1},{4,1},{2,1},{0,106},{0,180},{2,1},{0,75},
|
||||||
|
{0,193},{4,1},{2,1},{0,152},{0,137},{2,1},{0,28},{0,181},{80,1},{34,1},
|
||||||
|
{16,1},{6,1},{4,1},{2,1},{0,91},{0,44},{0,194},{6,1},{4,1},{2,1},
|
||||||
|
{0,11},{0,192},{0,166},{2,1},{0,167},{0,122},{10,1},{4,1},{2,1},{0,195},
|
||||||
|
{0,60},{4,1},{2,1},{0,12},{0,153},{0,182},{4,1},{2,1},{0,107},{0,196},
|
||||||
|
{2,1},{0,76},{0,168},{20,1},{10,1},{4,1},{2,1},{0,138},{0,197},{4,1},
|
||||||
|
{2,1},{0,208},{0,92},{0,209},{4,1},{2,1},{0,183},{0,123},{2,1},{0,29},
|
||||||
|
{2,1},{0,13},{0,45},{12,1},{4,1},{2,1},{0,210},{0,211},{4,1},{2,1},
|
||||||
|
{0,61},{0,198},{2,1},{0,108},{0,169},{6,1},{4,1},{2,1},{0,154},{0,184},
|
||||||
|
{0,212},{4,1},{2,1},{0,139},{0,77},{2,1},{0,199},{0,124},{68,1},{34,1},
|
||||||
|
{18,1},{10,1},{4,1},{2,1},{0,213},{0,93},{4,1},{2,1},{0,224},{0,14},
|
||||||
|
{0,225},{4,1},{2,1},{0,30},{0,226},{2,1},{0,170},{0,46},{8,1},{4,1},
|
||||||
|
{2,1},{0,185},{0,155},{2,1},{0,227},{0,214},{4,1},{2,1},{0,109},{0,62},
|
||||||
|
{2,1},{0,200},{0,140},{16,1},{8,1},{4,1},{2,1},{0,228},{0,78},{2,1},
|
||||||
|
{0,215},{0,125},{4,1},{2,1},{0,229},{0,186},{2,1},{0,171},{0,94},{8,1},
|
||||||
|
{4,1},{2,1},{0,201},{0,156},{2,1},{0,241},{0,31},{6,1},{4,1},{2,1},
|
||||||
|
{0,240},{0,110},{0,242},{2,1},{0,47},{0,230},{38,1},{18,1},{8,1},{4,1},
|
||||||
|
{2,1},{0,216},{0,243},{2,1},{0,63},{0,244},{6,1},{2,1},{0,79},{2,1},
|
||||||
|
{0,141},{0,217},{2,1},{0,187},{0,202},{8,1},{4,1},{2,1},{0,172},{0,231},
|
||||||
|
{2,1},{0,126},{0,245},{8,1},{4,1},{2,1},{0,157},{0,95},{2,1},{0,232},
|
||||||
|
{0,142},{2,1},{0,246},{0,203},{34,1},{18,1},{10,1},{6,1},{4,1},{2,1},
|
||||||
|
{0,15},{0,174},{0,111},{2,1},{0,188},{0,218},{4,1},{2,1},{0,173},{0,247},
|
||||||
|
{2,1},{0,127},{0,233},{8,1},{4,1},{2,1},{0,158},{0,204},{2,1},{0,248},
|
||||||
|
{0,143},{4,1},{2,1},{0,219},{0,189},{2,1},{0,234},{0,249},{16,1},{8,1},
|
||||||
|
{4,1},{2,1},{0,159},{0,220},{2,1},{0,205},{0,235},{4,1},{2,1},{0,190},
|
||||||
|
{0,250},{2,1},{0,175},{0,221},{14,1},{6,1},{4,1},{2,1},{0,236},{0,206},
|
||||||
|
{0,251},{4,1},{2,1},{0,191},{0,237},{2,1},{0,222},{0,252},{6,1},{4,1},
|
||||||
|
{2,1},{0,207},{0,253},{0,238},{4,1},{2,1},{0,223},{0,254},{2,1},{0,239},
|
||||||
|
{0,255},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab16[][] = {
|
||||||
|
{2,1},{0,0},{6,1},{2,1},{0,16},{2,1},{0,1},{0,17},{42,1},{8,1},
|
||||||
|
{4,1},{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{10,1},{6,1},{2,1},
|
||||||
|
{0,34},{2,1},{0,48},{0,3},{2,1},{0,49},{0,19},{10,1},{4,1},{2,1},
|
||||||
|
{0,50},{0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{6,1},{2,1},{0,20},
|
||||||
|
{2,1},{0,51},{0,66},{4,1},{2,1},{0,36},{0,80},{2,1},{0,67},{0,52},
|
||||||
|
{138,1},{40,1},{16,1},{6,1},{4,1},{2,1},{0,5},{0,21},{0,81},{4,1},
|
||||||
|
{2,1},{0,82},{0,37},{4,1},{2,1},{0,68},{0,53},{0,83},{10,1},{6,1},
|
||||||
|
{4,1},{2,1},{0,96},{0,6},{0,97},{2,1},{0,22},{0,98},{8,1},{4,1},
|
||||||
|
{2,1},{0,38},{0,84},{2,1},{0,69},{0,99},{4,1},{2,1},{0,54},{0,112},
|
||||||
|
{0,113},{40,1},{18,1},{8,1},{2,1},{0,23},{2,1},{0,7},{2,1},{0,85},
|
||||||
|
{0,100},{4,1},{2,1},{0,114},{0,39},{4,1},{2,1},{0,70},{0,101},{0,115},
|
||||||
|
{10,1},{6,1},{2,1},{0,55},{2,1},{0,86},{0,8},{2,1},{0,128},{0,129},
|
||||||
|
{6,1},{2,1},{0,24},{2,1},{0,116},{0,71},{2,1},{0,130},{2,1},{0,40},
|
||||||
|
{0,102},{24,1},{14,1},{8,1},{4,1},{2,1},{0,131},{0,56},{2,1},{0,117},
|
||||||
|
{0,132},{4,1},{2,1},{0,72},{0,144},{0,145},{6,1},{2,1},{0,25},{2,1},
|
||||||
|
{0,9},{0,118},{2,1},{0,146},{0,41},{14,1},{8,1},{4,1},{2,1},{0,133},
|
||||||
|
{0,88},{2,1},{0,147},{0,57},{4,1},{2,1},{0,160},{0,10},{0,26},{8,1},
|
||||||
|
{2,1},{0,162},{2,1},{0,103},{2,1},{0,87},{0,73},{6,1},{2,1},{0,148},
|
||||||
|
{2,1},{0,119},{0,134},{2,1},{0,161},{2,1},{0,104},{0,149},{220,1},{126,1},
|
||||||
|
{50,1},{26,1},{12,1},{6,1},{2,1},{0,42},{2,1},{0,89},{0,58},{2,1},
|
||||||
|
{0,163},{2,1},{0,135},{0,120},{8,1},{4,1},{2,1},{0,164},{0,74},{2,1},
|
||||||
|
{0,150},{0,105},{4,1},{2,1},{0,176},{0,11},{0,177},{10,1},{4,1},{2,1},
|
||||||
|
{0,27},{0,178},{2,1},{0,43},{2,1},{0,165},{0,90},{6,1},{2,1},{0,179},
|
||||||
|
{2,1},{0,166},{0,106},{4,1},{2,1},{0,180},{0,75},{2,1},{0,12},{0,193},
|
||||||
|
{30,1},{14,1},{6,1},{4,1},{2,1},{0,181},{0,194},{0,44},{4,1},{2,1},
|
||||||
|
{0,167},{0,195},{2,1},{0,107},{0,196},{8,1},{2,1},{0,29},{4,1},{2,1},
|
||||||
|
{0,136},{0,151},{0,59},{4,1},{2,1},{0,209},{0,210},{2,1},{0,45},{0,211},
|
||||||
|
{18,1},{6,1},{4,1},{2,1},{0,30},{0,46},{0,226},{6,1},{4,1},{2,1},
|
||||||
|
{0,121},{0,152},{0,192},{2,1},{0,28},{2,1},{0,137},{0,91},{14,1},{6,1},
|
||||||
|
{2,1},{0,60},{2,1},{0,122},{0,182},{4,1},{2,1},{0,76},{0,153},{2,1},
|
||||||
|
{0,168},{0,138},{6,1},{2,1},{0,13},{2,1},{0,197},{0,92},{4,1},{2,1},
|
||||||
|
{0,61},{0,198},{2,1},{0,108},{0,154},{88,1},{86,1},{36,1},{16,1},{8,1},
|
||||||
|
{4,1},{2,1},{0,139},{0,77},{2,1},{0,199},{0,124},{4,1},{2,1},{0,213},
|
||||||
|
{0,93},{2,1},{0,224},{0,14},{8,1},{2,1},{0,227},{4,1},{2,1},{0,208},
|
||||||
|
{0,183},{0,123},{6,1},{4,1},{2,1},{0,169},{0,184},{0,212},{2,1},{0,225},
|
||||||
|
{2,1},{0,170},{0,185},{24,1},{10,1},{6,1},{4,1},{2,1},{0,155},{0,214},
|
||||||
|
{0,109},{2,1},{0,62},{0,200},{6,1},{4,1},{2,1},{0,140},{0,228},{0,78},
|
||||||
|
{4,1},{2,1},{0,215},{0,229},{2,1},{0,186},{0,171},{12,1},{4,1},{2,1},
|
||||||
|
{0,156},{0,230},{4,1},{2,1},{0,110},{0,216},{2,1},{0,141},{0,187},{8,1},
|
||||||
|
{4,1},{2,1},{0,231},{0,157},{2,1},{0,232},{0,142},{4,1},{2,1},{0,203},
|
||||||
|
{0,188},{0,158},{0,241},{2,1},{0,31},{2,1},{0,15},{0,47},{66,1},{56,1},
|
||||||
|
{2,1},{0,242},{52,1},{50,1},{20,1},{8,1},{2,1},{0,189},{2,1},{0,94},
|
||||||
|
{2,1},{0,125},{0,201},{6,1},{2,1},{0,202},{2,1},{0,172},{0,126},{4,1},
|
||||||
|
{2,1},{0,218},{0,173},{0,204},{10,1},{6,1},{2,1},{0,174},{2,1},{0,219},
|
||||||
|
{0,220},{2,1},{0,205},{0,190},{6,1},{4,1},{2,1},{0,235},{0,237},{0,238},
|
||||||
|
{6,1},{4,1},{2,1},{0,217},{0,234},{0,233},{2,1},{0,222},{4,1},{2,1},
|
||||||
|
{0,221},{0,236},{0,206},{0,63},{0,240},{4,1},{2,1},{0,243},{0,244},{2,1},
|
||||||
|
{0,79},{2,1},{0,245},{0,95},{10,1},{2,1},{0,255},{4,1},{2,1},{0,246},
|
||||||
|
{0,111},{2,1},{0,247},{0,127},{12,1},{6,1},{2,1},{0,143},{2,1},{0,248},
|
||||||
|
{0,249},{4,1},{2,1},{0,159},{0,250},{0,175},{8,1},{4,1},{2,1},{0,251},
|
||||||
|
{0,191},{2,1},{0,252},{0,207},{4,1},{2,1},{0,253},{0,223},{2,1},{0,254},
|
||||||
|
{0,239},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab24[][] = {
|
||||||
|
{60,1},{8,1},{4,1},{2,1},{0,0},{0,16},{2,1},{0,1},{0,17},{14,1},
|
||||||
|
{6,1},{4,1},{2,1},{0,32},{0,2},{0,33},{2,1},{0,18},{2,1},{0,34},
|
||||||
|
{2,1},{0,48},{0,3},{14,1},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1},
|
||||||
|
{0,50},{0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{8,1},{4,1},{2,1},
|
||||||
|
{0,20},{0,51},{2,1},{0,66},{0,36},{6,1},{4,1},{2,1},{0,67},{0,52},
|
||||||
|
{0,81},{6,1},{4,1},{2,1},{0,80},{0,5},{0,21},{2,1},{0,82},{0,37},
|
||||||
|
{250,1},{98,1},{34,1},{18,1},{10,1},{4,1},{2,1},{0,68},{0,83},{2,1},
|
||||||
|
{0,53},{2,1},{0,96},{0,6},{4,1},{2,1},{0,97},{0,22},{2,1},{0,98},
|
||||||
|
{0,38},{8,1},{4,1},{2,1},{0,84},{0,69},{2,1},{0,99},{0,54},{4,1},
|
||||||
|
{2,1},{0,113},{0,85},{2,1},{0,100},{0,70},{32,1},{14,1},{6,1},{2,1},
|
||||||
|
{0,114},{2,1},{0,39},{0,55},{2,1},{0,115},{4,1},{2,1},{0,112},{0,7},
|
||||||
|
{0,23},{10,1},{4,1},{2,1},{0,101},{0,86},{4,1},{2,1},{0,128},{0,8},
|
||||||
|
{0,129},{4,1},{2,1},{0,116},{0,71},{2,1},{0,24},{0,130},{16,1},{8,1},
|
||||||
|
{4,1},{2,1},{0,40},{0,102},{2,1},{0,131},{0,56},{4,1},{2,1},{0,117},
|
||||||
|
{0,87},{2,1},{0,132},{0,72},{8,1},{4,1},{2,1},{0,145},{0,25},{2,1},
|
||||||
|
{0,146},{0,118},{4,1},{2,1},{0,103},{0,41},{2,1},{0,133},{0,88},{92,1},
|
||||||
|
{34,1},{16,1},{8,1},{4,1},{2,1},{0,147},{0,57},{2,1},{0,148},{0,73},
|
||||||
|
{4,1},{2,1},{0,119},{0,134},{2,1},{0,104},{0,161},{8,1},{4,1},{2,1},
|
||||||
|
{0,162},{0,42},{2,1},{0,149},{0,89},{4,1},{2,1},{0,163},{0,58},{2,1},
|
||||||
|
{0,135},{2,1},{0,120},{0,74},{22,1},{12,1},{4,1},{2,1},{0,164},{0,150},
|
||||||
|
{4,1},{2,1},{0,105},{0,177},{2,1},{0,27},{0,165},{6,1},{2,1},{0,178},
|
||||||
|
{2,1},{0,90},{0,43},{2,1},{0,136},{0,179},{16,1},{10,1},{6,1},{2,1},
|
||||||
|
{0,144},{2,1},{0,9},{0,160},{2,1},{0,151},{0,121},{4,1},{2,1},{0,166},
|
||||||
|
{0,106},{0,180},{12,1},{6,1},{2,1},{0,26},{2,1},{0,10},{0,176},{2,1},
|
||||||
|
{0,59},{2,1},{0,11},{0,192},{4,1},{2,1},{0,75},{0,193},{2,1},{0,152},
|
||||||
|
{0,137},{67,1},{34,1},{16,1},{8,1},{4,1},{2,1},{0,28},{0,181},{2,1},
|
||||||
|
{0,91},{0,194},{4,1},{2,1},{0,44},{0,167},{2,1},{0,122},{0,195},{10,1},
|
||||||
|
{6,1},{2,1},{0,60},{2,1},{0,12},{0,208},{2,1},{0,182},{0,107},{4,1},
|
||||||
|
{2,1},{0,196},{0,76},{2,1},{0,153},{0,168},{16,1},{8,1},{4,1},{2,1},
|
||||||
|
{0,138},{0,197},{2,1},{0,92},{0,209},{4,1},{2,1},{0,183},{0,123},{2,1},
|
||||||
|
{0,29},{0,210},{9,1},{4,1},{2,1},{0,45},{0,211},{2,1},{0,61},{0,198},
|
||||||
|
{85,250},{4,1},{2,1},{0,108},{0,169},{2,1},{0,154},{0,212},{32,1},{16,1},
|
||||||
|
{8,1},{4,1},{2,1},{0,184},{0,139},{2,1},{0,77},{0,199},{4,1},{2,1},
|
||||||
|
{0,124},{0,213},{2,1},{0,93},{0,225},{8,1},{4,1},{2,1},{0,30},{0,226},
|
||||||
|
{2,1},{0,170},{0,185},{4,1},{2,1},{0,155},{0,227},{2,1},{0,214},{0,109},
|
||||||
|
{20,1},{10,1},{6,1},{2,1},{0,62},{2,1},{0,46},{0,78},{2,1},{0,200},
|
||||||
|
{0,140},{4,1},{2,1},{0,228},{0,215},{4,1},{2,1},{0,125},{0,171},{0,229},
|
||||||
|
{10,1},{4,1},{2,1},{0,186},{0,94},{2,1},{0,201},{2,1},{0,156},{0,110},
|
||||||
|
{8,1},{2,1},{0,230},{2,1},{0,13},{2,1},{0,224},{0,14},{4,1},{2,1},
|
||||||
|
{0,216},{0,141},{2,1},{0,187},{0,202},{74,1},{2,1},{0,255},{64,1},{58,1},
|
||||||
|
{32,1},{16,1},{8,1},{4,1},{2,1},{0,172},{0,231},{2,1},{0,126},{0,217},
|
||||||
|
{4,1},{2,1},{0,157},{0,232},{2,1},{0,142},{0,203},{8,1},{4,1},{2,1},
|
||||||
|
{0,188},{0,218},{2,1},{0,173},{0,233},{4,1},{2,1},{0,158},{0,204},{2,1},
|
||||||
|
{0,219},{0,189},{16,1},{8,1},{4,1},{2,1},{0,234},{0,174},{2,1},{0,220},
|
||||||
|
{0,205},{4,1},{2,1},{0,235},{0,190},{2,1},{0,221},{0,236},{8,1},{4,1},
|
||||||
|
{2,1},{0,206},{0,237},{2,1},{0,222},{0,238},{0,15},{4,1},{2,1},{0,240},
|
||||||
|
{0,31},{0,241},{4,1},{2,1},{0,242},{0,47},{2,1},{0,243},{0,63},{18,1},
|
||||||
|
{8,1},{4,1},{2,1},{0,244},{0,79},{2,1},{0,245},{0,95},{4,1},{2,1},
|
||||||
|
{0,246},{0,111},{2,1},{0,247},{2,1},{0,127},{0,143},{10,1},{4,1},{2,1},
|
||||||
|
{0,248},{0,249},{4,1},{2,1},{0,159},{0,175},{0,250},{8,1},{4,1},{2,1},
|
||||||
|
{0,251},{0,191},{2,1},{0,252},{0,207},{4,1},{2,1},{0,253},{0,223},{2,1},
|
||||||
|
{0,254},{0,239},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab32[][] = {
|
||||||
|
{2,1},{0,0},{8,1},{4,1},{2,1},{0,8},{0,4},{2,1},{0,1},{0,2},
|
||||||
|
{8,1},{4,1},{2,1},{0,12},{0,10},{2,1},{0,3},{0,6},{6,1},{2,1},
|
||||||
|
{0,9},{2,1},{0,5},{0,7},{4,1},{2,1},{0,14},{0,13},{2,1},{0,15},
|
||||||
|
{0,11},
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ValTab33[][] = {
|
||||||
|
{16,1},{8,1},{4,1},{2,1},{0,0},{0,1},{2,1},{0,2},{0,3},{4,1},
|
||||||
|
{2,1},{0,4},{0,5},{2,1},{0,6},{0,7},{8,1},{4,1},{2,1},{0,8},
|
||||||
|
{0,9},{2,1},{0,10},{0,11},{4,1},{2,1},{0,12},{0,13},{2,1},{0,14},
|
||||||
|
{0,15},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public static huffcodetab[] ht = null; /* Simulate extern struct */
|
||||||
|
|
||||||
|
private static int[] bitbuf = new int[32];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Big Constructor : Computes all Huffman Tables.
|
||||||
|
*/
|
||||||
|
private huffcodetab(String S,int XLEN, int YLEN, int LINBITS, int LINMAX, int REF,
|
||||||
|
int[] TABLE, int[] HLEN, int[][] VAL, int TREELEN)
|
||||||
|
{
|
||||||
|
tablename0 = S.charAt(0);
|
||||||
|
tablename1 = S.charAt(1);
|
||||||
|
tablename2 = S.charAt(2);
|
||||||
|
xlen = XLEN;
|
||||||
|
ylen = YLEN;
|
||||||
|
linbits = LINBITS;
|
||||||
|
linmax = LINMAX;
|
||||||
|
ref = REF;
|
||||||
|
table = TABLE;
|
||||||
|
hlen = HLEN;
|
||||||
|
val = VAL;
|
||||||
|
treelen = TREELEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do the huffman-decoding.
|
||||||
|
* note! for counta,countb -the 4 bit value is returned in y,
|
||||||
|
* discard x.
|
||||||
|
*/
|
||||||
|
public static int huffman_decoder(huffcodetab h, int[] x, int[] y, int[] v, int[] w, BitReserve br)
|
||||||
|
{
|
||||||
|
// array of all huffcodtable headers
|
||||||
|
// 0..31 Huffman code table 0..31
|
||||||
|
// 32,33 count1-tables
|
||||||
|
|
||||||
|
int dmask = 1 << ((4 * 8) - 1);
|
||||||
|
int hs = 4 * 8;
|
||||||
|
int level;
|
||||||
|
int point = 0;
|
||||||
|
int error = 1;
|
||||||
|
level = dmask;
|
||||||
|
|
||||||
|
if (h.val == null) return 2;
|
||||||
|
|
||||||
|
/* table 0 needs no bits */
|
||||||
|
if ( h.treelen == 0)
|
||||||
|
{
|
||||||
|
x[0] = y[0] = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lookup in Huffman table. */
|
||||||
|
|
||||||
|
/*int bitsAvailable = 0;
|
||||||
|
int bitIndex = 0;
|
||||||
|
|
||||||
|
int bits[] = bitbuf;*/
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (h.val[point][0]==0)
|
||||||
|
{ /*end of tree*/
|
||||||
|
x[0] = h.val[point][1] >>> 4;
|
||||||
|
y[0] = h.val[point][1] & 0xf;
|
||||||
|
error = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// hget1bit() is called thousands of times, and so needs to be
|
||||||
|
// ultra fast.
|
||||||
|
/*
|
||||||
|
if (bitIndex==bitsAvailable)
|
||||||
|
{
|
||||||
|
bitsAvailable = br.readBits(bits, 32);
|
||||||
|
bitIndex = 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
//if (bits[bitIndex++]!=0)
|
||||||
|
if (br.hget1bit()!=0)
|
||||||
|
{
|
||||||
|
while (h.val[point][1] >= MXOFF) point += h.val[point][1];
|
||||||
|
point += h.val[point][1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (h.val[point][0] >= MXOFF) point += h.val[point][0];
|
||||||
|
point += h.val[point][0];
|
||||||
|
}
|
||||||
|
level >>>= 1;
|
||||||
|
// MDM: ht[0] is always 0;
|
||||||
|
} while ((level !=0 ) || (point < 0 /*ht[0].treelen*/) );
|
||||||
|
|
||||||
|
// put back any bits not consumed
|
||||||
|
/*
|
||||||
|
int unread = (bitsAvailable-bitIndex);
|
||||||
|
if (unread>0)
|
||||||
|
br.rewindNbits(unread);
|
||||||
|
*/
|
||||||
|
/* Process sign encodings for quadruples tables. */
|
||||||
|
// System.out.println(h.tablename);
|
||||||
|
if (h.tablename0 == '3' && (h.tablename1 == '2' || h.tablename1 == '3'))
|
||||||
|
{
|
||||||
|
v[0] = (y[0]>>3) & 1;
|
||||||
|
w[0] = (y[0]>>2) & 1;
|
||||||
|
x[0] = (y[0]>>1) & 1;
|
||||||
|
y[0] = y[0] & 1;
|
||||||
|
|
||||||
|
/* v, w, x and y are reversed in the bitstream.
|
||||||
|
switch them around to make test bistream work. */
|
||||||
|
|
||||||
|
if (v[0]!=0)
|
||||||
|
if (br.hget1bit() != 0) v[0] = -v[0];
|
||||||
|
if (w[0]!=0)
|
||||||
|
if (br.hget1bit() != 0) w[0] = -w[0];
|
||||||
|
if (x[0]!=0)
|
||||||
|
if (br.hget1bit() != 0) x[0] = -x[0];
|
||||||
|
if (y[0]!=0)
|
||||||
|
if (br.hget1bit() != 0) y[0] = -y[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Process sign and escape encodings for dual tables.
|
||||||
|
// x and y are reversed in the test bitstream.
|
||||||
|
// Reverse x and y here to make test bitstream work.
|
||||||
|
|
||||||
|
if (h.linbits != 0)
|
||||||
|
if ((h.xlen-1) == x[0])
|
||||||
|
x[0] += br.hgetbits(h.linbits);
|
||||||
|
if (x[0] != 0)
|
||||||
|
if (br.hget1bit() != 0) x[0] = -x[0];
|
||||||
|
if (h.linbits != 0)
|
||||||
|
if ((h.ylen-1) == y[0])
|
||||||
|
y[0] += br.hgetbits(h.linbits);
|
||||||
|
if (y[0] != 0)
|
||||||
|
if (br.hget1bit() != 0) y[0] = -y[0];
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void inithuff()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (ht!=null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ht = new huffcodetab[HTN];
|
||||||
|
ht[0] = new huffcodetab("0 ",0,0,0,0,-1,null,null,ValTab0,0);
|
||||||
|
ht[1] = new huffcodetab("1 ",2,2,0,0,-1,null,null,ValTab1,7);
|
||||||
|
ht[2] = new huffcodetab("2 ",3,3,0,0,-1,null,null,ValTab2,17);
|
||||||
|
ht[3] = new huffcodetab("3 ",3,3,0,0,-1,null,null,ValTab3,17);
|
||||||
|
ht[4] = new huffcodetab("4 ",0,0,0,0,-1,null,null,ValTab4,0);
|
||||||
|
ht[5] = new huffcodetab("5 ",4,4,0,0,-1,null,null,ValTab5,31);
|
||||||
|
ht[6] = new huffcodetab("6 ",4,4,0,0,-1,null,null,ValTab6,31);
|
||||||
|
ht[7] = new huffcodetab("7 ",6,6,0,0,-1,null,null,ValTab7,71);
|
||||||
|
ht[8] = new huffcodetab("8 ",6,6,0,0,-1,null,null,ValTab8,71);
|
||||||
|
ht[9] = new huffcodetab("9 ",6,6,0,0,-1,null,null,ValTab9,71);
|
||||||
|
ht[10] = new huffcodetab("10 ",8,8,0,0,-1,null,null,ValTab10,127);
|
||||||
|
ht[11] = new huffcodetab("11 ",8,8,0,0,-1,null,null,ValTab11,127);
|
||||||
|
ht[12] = new huffcodetab("12 ",8,8,0,0,-1,null,null,ValTab12,127);
|
||||||
|
ht[13] = new huffcodetab("13 ",16,16,0,0,-1,null,null,ValTab13,511);
|
||||||
|
ht[14] = new huffcodetab("14 ",0,0,0,0,-1,null,null,ValTab14,0);
|
||||||
|
ht[15] = new huffcodetab("15 ",16,16,0,0,-1,null,null,ValTab15,511);
|
||||||
|
ht[16] = new huffcodetab("16 ",16,16,1,1,-1,null,null,ValTab16,511);
|
||||||
|
ht[17] = new huffcodetab("17 ",16,16,2,3,16,null,null,ValTab16,511);
|
||||||
|
ht[18] = new huffcodetab("18 ",16,16,3,7,16,null,null,ValTab16,511);
|
||||||
|
ht[19] = new huffcodetab("19 ",16,16,4,15,16,null,null,ValTab16,511);
|
||||||
|
ht[20] = new huffcodetab("20 ",16,16,6,63,16,null,null,ValTab16,511);
|
||||||
|
ht[21] = new huffcodetab("21 ",16,16,8,255,16,null,null,ValTab16,511);
|
||||||
|
ht[22] = new huffcodetab("22 ",16,16,10,1023,16,null,null,ValTab16,511);
|
||||||
|
ht[23] = new huffcodetab("23 ",16,16,13,8191,16,null,null,ValTab16,511);
|
||||||
|
ht[24] = new huffcodetab("24 ",16,16,4,15,-1,null,null,ValTab24,512);
|
||||||
|
ht[25] = new huffcodetab("25 ",16,16,5,31,24,null,null,ValTab24,512);
|
||||||
|
ht[26] = new huffcodetab("26 ",16,16,6,63,24,null,null,ValTab24,512);
|
||||||
|
ht[27] = new huffcodetab("27 ",16,16,7,127,24,null,null,ValTab24,512);
|
||||||
|
ht[28] = new huffcodetab("28 ",16,16,8,255,24,null,null,ValTab24,512);
|
||||||
|
ht[29] = new huffcodetab("29 ",16,16,9,511,24,null,null,ValTab24,512);
|
||||||
|
ht[30] = new huffcodetab("30 ",16,16,11,2047,24,null,null,ValTab24,512);
|
||||||
|
ht[31] = new huffcodetab("31 ",16,16,13,8191,24,null,null,ValTab24,512);
|
||||||
|
ht[32] = new huffcodetab("32 ",1,16,0,0,-1,null,null,ValTab32,31);
|
||||||
|
ht[33] = new huffcodetab("33 ",1,16,0,0,-1,null,null,ValTab33,31);
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/javazoom/jl/decoder/l3reorder.ser
Normal file
BIN
src/javazoom/jl/decoder/l3reorder.ser
Normal file
Binary file not shown.
BIN
src/javazoom/jl/decoder/lin2au.ser
Normal file
BIN
src/javazoom/jl/decoder/lin2au.ser
Normal file
Binary file not shown.
15
src/javazoom/jl/decoder/readme.txt
Normal file
15
src/javazoom/jl/decoder/readme.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
|
||||||
|
Implement high-level Player and Converter classes.
|
||||||
|
|
||||||
|
Add MP1 and MP2 support and test.
|
||||||
|
|
||||||
|
Add option to run each "stage" on own thread.
|
||||||
|
E.g. read & parse input, decode subbands, subband synthesis, audio output.
|
||||||
|
|
||||||
|
Retrofit seek support (temporarily removed when reworking classes.)
|
||||||
|
|
||||||
|
|
||||||
|
Document and give example code.
|
||||||
BIN
src/javazoom/jl/decoder/sfd.ser
Normal file
BIN
src/javazoom/jl/decoder/sfd.ser
Normal file
Binary file not shown.
103
src/javazoom/jl/player/AudioDevice.java
Normal file
103
src/javazoom/jl/player/AudioDevice.java
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.Decoder;
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>AudioDevice</code> interface provides an abstraction for
|
||||||
|
* a device capable of sounding audio samples. Samples are written to
|
||||||
|
* the device wia the write() method. The device assumes
|
||||||
|
* that these samples are signed 16-bit samples taken at the output frequency
|
||||||
|
* of the decoder. If the decoder outputs more than one channel, the samples for
|
||||||
|
* each channel are assumed to appear consecutively, with the lower numbered
|
||||||
|
* channels preceeding higher-numbered channels. E.g. if there are two
|
||||||
|
* channels, the samples will appear in this order:
|
||||||
|
* <pre><code>
|
||||||
|
*
|
||||||
|
* l0, r0, l1, r1, l2, r2...
|
||||||
|
*
|
||||||
|
* where
|
||||||
|
* l<i>x</i> indicates the <i>x</i>th sample on channel 0
|
||||||
|
* r<i>x</i> indicates the <i>x</i>th sample on channel 1
|
||||||
|
* </code></pre>
|
||||||
|
*
|
||||||
|
* @since 0.0.8
|
||||||
|
* @author Mat McGowan
|
||||||
|
*/
|
||||||
|
public interface AudioDevice
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Prepares the AudioDevice for playback of audio samples.
|
||||||
|
* @param decoder The decoder that will be providing the audio
|
||||||
|
* samples.
|
||||||
|
*
|
||||||
|
* If the audio device is already open, this method returns silently.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void open(Decoder decoder) throws JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the open state of this audio device.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if this audio device is open and playing
|
||||||
|
* audio samples, or <code>false</code> otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isOpen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a number of samples to this <code>AudioDevice</code>.
|
||||||
|
*
|
||||||
|
* @param samples The array of signed 16-bit samples to write
|
||||||
|
* to the audio device.
|
||||||
|
* @param offs The offset of the first sample.
|
||||||
|
* @param len The number of samples to write.
|
||||||
|
*
|
||||||
|
* This method may return prior to the samples actually being played
|
||||||
|
* by the audio device.
|
||||||
|
*/
|
||||||
|
public void write(short[] samples, int offs, int len) throws JavaLayerException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes this audio device. Any currently playing audio is stopped
|
||||||
|
* as soon as possible. Any previously written audio data that has not been heard
|
||||||
|
* is discarded.
|
||||||
|
*
|
||||||
|
* The implementation should ensure that any threads currently blocking
|
||||||
|
* on the device (e.g. during a <code>write</code> or <code>flush</code>
|
||||||
|
* operation should be unblocked by this method.
|
||||||
|
*/
|
||||||
|
public void close();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks until all audio samples previously written to this audio device have
|
||||||
|
* been heard.
|
||||||
|
*/
|
||||||
|
public void flush();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current playback position in milliseconds.
|
||||||
|
*/
|
||||||
|
public int getPosition();
|
||||||
|
}
|
||||||
177
src/javazoom/jl/player/AudioDeviceBase.java
Normal file
177
src/javazoom/jl/player/AudioDeviceBase.java
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.Decoder;
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>AudioDeviceBase</code> class provides a simple thread-safe
|
||||||
|
* implementation of the <code>AudioDevice</code> interface.
|
||||||
|
* Template methods are provided for subclasses to override and
|
||||||
|
* in doing so provide the implementation for the main operations
|
||||||
|
* of the <code>AudioDevice</code> interface.
|
||||||
|
*
|
||||||
|
* @since 0.0.8
|
||||||
|
* @author Mat McGowan
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* REVIEW: It is desirable to be able to use the decoder whe
|
||||||
|
* in the implementation of open(), but the decoder
|
||||||
|
* has not yet read a frame, and so much of the
|
||||||
|
* desired information (sample rate, channels etc.)
|
||||||
|
* are not available.
|
||||||
|
*/
|
||||||
|
public abstract class AudioDeviceBase implements AudioDevice
|
||||||
|
{
|
||||||
|
private boolean open = false;
|
||||||
|
|
||||||
|
private Decoder decoder = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens this audio device.
|
||||||
|
*
|
||||||
|
* @param decoder The decoder that will provide audio data
|
||||||
|
* to this audio device.
|
||||||
|
*/
|
||||||
|
public synchronized void open(Decoder decoder) throws JavaLayerException
|
||||||
|
{
|
||||||
|
if (!isOpen())
|
||||||
|
{
|
||||||
|
this.decoder = decoder;
|
||||||
|
openImpl();
|
||||||
|
setOpen(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template method to provide the
|
||||||
|
* implementation for the opening of the audio device.
|
||||||
|
*/
|
||||||
|
protected void openImpl() throws JavaLayerException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the open state for this audio device.
|
||||||
|
*/
|
||||||
|
protected void setOpen(boolean open)
|
||||||
|
{
|
||||||
|
this.open = open;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if this audio device is open or not.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the audio device is open,
|
||||||
|
* <code>false</code> if it is not.
|
||||||
|
*/
|
||||||
|
public synchronized boolean isOpen()
|
||||||
|
{
|
||||||
|
return open;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes this audio device. If the device is currently playing
|
||||||
|
* audio, playback is stopped immediately without flushing
|
||||||
|
* any buffered audio data.
|
||||||
|
*/
|
||||||
|
public synchronized void close()
|
||||||
|
{
|
||||||
|
if (isOpen())
|
||||||
|
{
|
||||||
|
closeImpl();
|
||||||
|
setOpen(false);
|
||||||
|
decoder = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template method to provide the implementation for
|
||||||
|
* closing the audio device.
|
||||||
|
*/
|
||||||
|
protected void closeImpl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes audio data to this audio device. Audio data is
|
||||||
|
* assumed to be in the output format of the decoder. This
|
||||||
|
* method may return before the data has actually been sounded
|
||||||
|
* by the device if the device buffers audio samples.
|
||||||
|
*
|
||||||
|
* @param samples The samples to write to the audio device.
|
||||||
|
* @param offs The offset into the array of the first sample to write.
|
||||||
|
* @param len The number of samples from the array to write.
|
||||||
|
* @throws JavaLayerException if the audio data could not be
|
||||||
|
* written to the audio device.
|
||||||
|
* If the audio device is not open, this method does nthing.
|
||||||
|
*/
|
||||||
|
public void write(short[] samples, int offs, int len)
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
if (isOpen())
|
||||||
|
{
|
||||||
|
writeImpl(samples, offs, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template method to provide the implementation for
|
||||||
|
* writing audio samples to the audio device.
|
||||||
|
*/
|
||||||
|
protected void writeImpl(short[] samples, int offs, int len)
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for any buffered audio samples to be played by the
|
||||||
|
* audio device. This method should only be called prior
|
||||||
|
* to closing the device.
|
||||||
|
*/
|
||||||
|
public void flush()
|
||||||
|
{
|
||||||
|
if (isOpen())
|
||||||
|
{
|
||||||
|
flushImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template method to provide the implementation for
|
||||||
|
* flushing any buffered audio data.
|
||||||
|
*/
|
||||||
|
protected void flushImpl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the decoder that provides audio data to this
|
||||||
|
* audio device.
|
||||||
|
*
|
||||||
|
* @return The associated decoder.
|
||||||
|
*/
|
||||||
|
protected Decoder getDecoder()
|
||||||
|
{
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
}
|
||||||
87
src/javazoom/jl/player/AudioDeviceFactory.java
Normal file
87
src/javazoom/jl/player/AudioDeviceFactory.java
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An <code>AudioDeviceFactory</code> class is responsible for creating
|
||||||
|
* a specific <code>AudioDevice</code> implementation. A factory implementation
|
||||||
|
* can be as simple or complex as desired and may support just one implementation
|
||||||
|
* or may return several implementations depending upon the execution
|
||||||
|
* environment.
|
||||||
|
* <p>
|
||||||
|
* When implementing a factory that provides an AudioDevice that uses
|
||||||
|
* class that may not be present, the factory should dynamically link to any
|
||||||
|
* specific implementation classes required to instantiate or test the audio
|
||||||
|
* implementation. This is so that the application as a whole
|
||||||
|
* can run without these classes being present. The audio
|
||||||
|
* device implementation, however, will usually statically link to the classes
|
||||||
|
* required. (See the JavaSound deivce and factory for an example
|
||||||
|
* of this.)
|
||||||
|
*
|
||||||
|
* @see FactoryRegistry
|
||||||
|
*
|
||||||
|
* @since 0.0.8
|
||||||
|
* @author Mat McGowan
|
||||||
|
*/
|
||||||
|
public abstract class AudioDeviceFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates a new <code>AudioDevice</code>.
|
||||||
|
*
|
||||||
|
* @return a new instance of a specific class of <code>AudioDevice</code>.
|
||||||
|
* @throws JavaLayerException if an instance of AudioDevice could not
|
||||||
|
* be created.
|
||||||
|
*/
|
||||||
|
public abstract AudioDevice createAudioDevice() throws JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of an AudioDevice implementation.
|
||||||
|
* @param loader The <code>ClassLoader</code> to use to
|
||||||
|
* load the named class, or null to use the
|
||||||
|
* system class loader.
|
||||||
|
* @param name The name of the class to load.
|
||||||
|
* @return A newly-created instance of the audio device class.
|
||||||
|
*/
|
||||||
|
protected AudioDevice instantiate(ClassLoader loader, String name)
|
||||||
|
throws ClassNotFoundException,
|
||||||
|
IllegalAccessException,
|
||||||
|
InstantiationException
|
||||||
|
{
|
||||||
|
AudioDevice dev = null;
|
||||||
|
|
||||||
|
Class cls = null;
|
||||||
|
if (loader==null)
|
||||||
|
{
|
||||||
|
cls = Class.forName(name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cls = loader.loadClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object o = cls.newInstance();
|
||||||
|
dev = (AudioDevice)o;
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
129
src/javazoom/jl/player/FactoryRegistry.java
Normal file
129
src/javazoom/jl/player/FactoryRegistry.java
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player;
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>FactoryRegistry</code> class stores the factories
|
||||||
|
* for all the audio device implementations available in the system.
|
||||||
|
* <p>
|
||||||
|
* Instances of this class are thread-safe.
|
||||||
|
*
|
||||||
|
* @since 0.0.8
|
||||||
|
* @author Mat McGowan
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class FactoryRegistry extends AudioDeviceFactory
|
||||||
|
{
|
||||||
|
static private FactoryRegistry instance = null;
|
||||||
|
|
||||||
|
static synchronized public FactoryRegistry systemRegistry()
|
||||||
|
{
|
||||||
|
if (instance==null)
|
||||||
|
{
|
||||||
|
instance = new FactoryRegistry();
|
||||||
|
instance.registerDefaultFactories();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected Hashtable factories = new Hashtable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an <code>AudioDeviceFactory</code> instance
|
||||||
|
* with this registry.
|
||||||
|
*/
|
||||||
|
public void addFactory(AudioDeviceFactory factory)
|
||||||
|
{
|
||||||
|
factories.put(factory.getClass(), factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFactoryType(Class cls)
|
||||||
|
{
|
||||||
|
factories.remove(cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFactory(AudioDeviceFactory factory)
|
||||||
|
{
|
||||||
|
factories.remove(factory.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
public AudioDevice createAudioDevice() throws JavaLayerException
|
||||||
|
{
|
||||||
|
AudioDevice device = null;
|
||||||
|
AudioDeviceFactory[] factories = getFactoriesPriority();
|
||||||
|
|
||||||
|
if (factories==null)
|
||||||
|
throw new JavaLayerException(this+": no factories registered");
|
||||||
|
|
||||||
|
JavaLayerException lastEx = null;
|
||||||
|
for (int i=0; (device==null) && (i<factories.length); i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
device = factories[i].createAudioDevice();
|
||||||
|
}
|
||||||
|
catch (JavaLayerException ex)
|
||||||
|
{
|
||||||
|
lastEx = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device==null && lastEx!=null)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException("Cannot create AudioDevice", lastEx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected AudioDeviceFactory[] getFactoriesPriority()
|
||||||
|
{
|
||||||
|
AudioDeviceFactory[] fa = null;
|
||||||
|
synchronized (factories)
|
||||||
|
{
|
||||||
|
int size = factories.size();
|
||||||
|
if (size!=0)
|
||||||
|
{
|
||||||
|
fa = new AudioDeviceFactory[size];
|
||||||
|
int idx = 0;
|
||||||
|
Enumeration e = factories.elements();
|
||||||
|
while (e.hasMoreElements())
|
||||||
|
{
|
||||||
|
AudioDeviceFactory factory = (AudioDeviceFactory)e.nextElement();
|
||||||
|
fa[idx++] = factory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void registerDefaultFactories()
|
||||||
|
{
|
||||||
|
addFactory(new JavaSoundAudioDeviceFactory());
|
||||||
|
}
|
||||||
|
}
|
||||||
215
src/javazoom/jl/player/JavaSoundAudioDevice.java
Normal file
215
src/javazoom/jl/player/JavaSoundAudioDevice.java
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* 11/26/04 Buffer size modified to support JRE 1.5 optimizations.
|
||||||
|
* (CPU usage < 1% under P4/2Ghz, RAM < 12MB).
|
||||||
|
* jlayer@javazoom.net
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 06/04/01 Too fast playback fixed. mdm@techie.com
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player;
|
||||||
|
|
||||||
|
import javax.sound.sampled.AudioFormat;
|
||||||
|
import javax.sound.sampled.AudioSystem;
|
||||||
|
import javax.sound.sampled.DataLine;
|
||||||
|
import javax.sound.sampled.Line;
|
||||||
|
import javax.sound.sampled.LineUnavailableException;
|
||||||
|
import javax.sound.sampled.SourceDataLine;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.Decoder;
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>JavaSoundAudioDevice</code> implements an audio
|
||||||
|
* device by using the JavaSound API.
|
||||||
|
*
|
||||||
|
* @since 0.0.8
|
||||||
|
* @author Mat McGowan
|
||||||
|
*/
|
||||||
|
public class JavaSoundAudioDevice extends AudioDeviceBase
|
||||||
|
{
|
||||||
|
private SourceDataLine source = null;
|
||||||
|
|
||||||
|
private AudioFormat fmt = null;
|
||||||
|
|
||||||
|
private byte[] byteBuf = new byte[4096];
|
||||||
|
|
||||||
|
protected void setAudioFormat(AudioFormat fmt0)
|
||||||
|
{
|
||||||
|
fmt = fmt0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AudioFormat getAudioFormat()
|
||||||
|
{
|
||||||
|
if (fmt==null)
|
||||||
|
{
|
||||||
|
Decoder decoder = getDecoder();
|
||||||
|
fmt = new AudioFormat(decoder.getOutputFrequency(),
|
||||||
|
16,
|
||||||
|
decoder.getOutputChannels(),
|
||||||
|
true,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
return fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DataLine.Info getSourceLineInfo()
|
||||||
|
{
|
||||||
|
AudioFormat fmt = getAudioFormat();
|
||||||
|
//DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt, 4000);
|
||||||
|
DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open(AudioFormat fmt) throws JavaLayerException
|
||||||
|
{
|
||||||
|
if (!isOpen())
|
||||||
|
{
|
||||||
|
setAudioFormat(fmt);
|
||||||
|
openImpl();
|
||||||
|
setOpen(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void openImpl()
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// createSource fix.
|
||||||
|
protected void createSource() throws JavaLayerException
|
||||||
|
{
|
||||||
|
Throwable t = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Line line = AudioSystem.getLine(getSourceLineInfo());
|
||||||
|
if (line instanceof SourceDataLine)
|
||||||
|
{
|
||||||
|
source = (SourceDataLine)line;
|
||||||
|
//source.open(fmt, millisecondsToBytes(fmt, 2000));
|
||||||
|
source.open(fmt);
|
||||||
|
/*
|
||||||
|
if (source.isControlSupported(FloatControl.Type.MASTER_GAIN))
|
||||||
|
{
|
||||||
|
FloatControl c = (FloatControl)source.getControl(FloatControl.Type.MASTER_GAIN);
|
||||||
|
c.setValue(c.getMaximum());
|
||||||
|
}*/
|
||||||
|
source.start();
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (RuntimeException ex)
|
||||||
|
{
|
||||||
|
t = ex;
|
||||||
|
}
|
||||||
|
catch (LinkageError ex)
|
||||||
|
{
|
||||||
|
t = ex;
|
||||||
|
}
|
||||||
|
catch (LineUnavailableException ex)
|
||||||
|
{
|
||||||
|
t = ex;
|
||||||
|
}
|
||||||
|
if (source==null) throw new JavaLayerException("cannot obtain source audio line", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int millisecondsToBytes(AudioFormat fmt, int time)
|
||||||
|
{
|
||||||
|
return (int)(time*(fmt.getSampleRate()*fmt.getChannels()*fmt.getSampleSizeInBits())/8000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void closeImpl()
|
||||||
|
{
|
||||||
|
if (source!=null)
|
||||||
|
{
|
||||||
|
source.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeImpl(short[] samples, int offs, int len)
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
if (source==null)
|
||||||
|
createSource();
|
||||||
|
|
||||||
|
byte[] b = toByteArray(samples, offs, len);
|
||||||
|
source.write(b, 0, len*2);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] getByteArray(int length)
|
||||||
|
{
|
||||||
|
if (byteBuf.length < length)
|
||||||
|
{
|
||||||
|
byteBuf = new byte[length+1024];
|
||||||
|
}
|
||||||
|
return byteBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] toByteArray(short[] samples, int offs, int len)
|
||||||
|
{
|
||||||
|
byte[] b = getByteArray(len*2);
|
||||||
|
int idx = 0;
|
||||||
|
short s;
|
||||||
|
while (len-- > 0)
|
||||||
|
{
|
||||||
|
s = samples[offs++];
|
||||||
|
b[idx++] = (byte)s;
|
||||||
|
b[idx++] = (byte)(s>>>8);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void flushImpl()
|
||||||
|
{
|
||||||
|
if (source!=null)
|
||||||
|
{
|
||||||
|
source.drain();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPosition()
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
if (source!=null)
|
||||||
|
{
|
||||||
|
pos = (int)(source.getMicrosecondPosition()/1000);
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a short test by playing a short silent sound.
|
||||||
|
*/
|
||||||
|
public void test()
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
open(new AudioFormat(22050, 16, 1, true, false));
|
||||||
|
short[] data = new short[22050/10];
|
||||||
|
write(data, 0, data.length);
|
||||||
|
flush();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
catch (RuntimeException ex)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException("Device test failed: "+ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
85
src/javazoom/jl/player/JavaSoundAudioDeviceFactory.java
Normal file
85
src/javazoom/jl/player/JavaSoundAudioDeviceFactory.java
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is responsible for creating instances of the
|
||||||
|
* JavaSoundAudioDevice. The audio device implementation is loaded
|
||||||
|
* and tested dynamically as not all systems will have support
|
||||||
|
* for JavaSound, or they may have the incorrect version.
|
||||||
|
*/
|
||||||
|
public class JavaSoundAudioDeviceFactory extends AudioDeviceFactory
|
||||||
|
{
|
||||||
|
private boolean tested = false;
|
||||||
|
|
||||||
|
static private final String DEVICE_CLASS_NAME = "javazoom.jl.player.JavaSoundAudioDevice";
|
||||||
|
|
||||||
|
public synchronized AudioDevice createAudioDevice()
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
if (!tested)
|
||||||
|
{
|
||||||
|
testAudioDevice();
|
||||||
|
tested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return createAudioDeviceImpl();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException("unable to create JavaSound device: "+ex);
|
||||||
|
}
|
||||||
|
catch (LinkageError ex)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException("unable to create JavaSound device: "+ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JavaSoundAudioDevice createAudioDeviceImpl()
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
ClassLoader loader = getClass().getClassLoader();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JavaSoundAudioDevice dev = (JavaSoundAudioDevice)instantiate(loader, DEVICE_CLASS_NAME);
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException("Cannot create JavaSound device", ex);
|
||||||
|
}
|
||||||
|
catch (LinkageError ex)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException("Cannot create JavaSound device", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAudioDevice() throws JavaLayerException
|
||||||
|
{
|
||||||
|
JavaSoundAudioDevice dev = createAudioDeviceImpl();
|
||||||
|
dev.test();
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/javazoom/jl/player/NullAudioDevice.java
Normal file
37
src/javazoom/jl/player/NullAudioDevice.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved o LGPL.
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>NullAudioDevice</code> implements a silent, no-op
|
||||||
|
* audio device. This is useful for testing purposes.
|
||||||
|
*
|
||||||
|
* @since 0.0.8
|
||||||
|
* @author Mat McGowan
|
||||||
|
*/
|
||||||
|
public class NullAudioDevice extends AudioDeviceBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public int getPosition()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
251
src/javazoom/jl/player/Player.java
Normal file
251
src/javazoom/jl/player/Player.java
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.Bitstream;
|
||||||
|
import javazoom.jl.decoder.BitstreamException;
|
||||||
|
import javazoom.jl.decoder.Decoder;
|
||||||
|
import javazoom.jl.decoder.Header;
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
import javazoom.jl.decoder.SampleBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>Player</code> class implements a simple player for playback
|
||||||
|
* of an MPEG audio stream.
|
||||||
|
*
|
||||||
|
* @author Mat McGowan
|
||||||
|
* @since 0.0.8
|
||||||
|
*/
|
||||||
|
|
||||||
|
// REVIEW: the audio device should not be opened until the
|
||||||
|
// first MPEG audio frame has been decoded.
|
||||||
|
public class Player
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The current frame number.
|
||||||
|
*/
|
||||||
|
private int frame = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MPEG audio bitstream.
|
||||||
|
*/
|
||||||
|
// javac blank final bug.
|
||||||
|
/*final*/ private Bitstream bitstream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MPEG audio decoder.
|
||||||
|
*/
|
||||||
|
/*final*/ private Decoder decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AudioDevice the audio samples are written to.
|
||||||
|
*/
|
||||||
|
private AudioDevice audio;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the player been closed?
|
||||||
|
*/
|
||||||
|
private boolean closed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the player played back all frames from the stream?
|
||||||
|
*/
|
||||||
|
private boolean complete = false;
|
||||||
|
|
||||||
|
private int lastPosition = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new <code>Player</code> instance.
|
||||||
|
*/
|
||||||
|
public Player(InputStream stream) throws JavaLayerException
|
||||||
|
{
|
||||||
|
this(stream, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player(InputStream stream, AudioDevice device) throws JavaLayerException
|
||||||
|
{
|
||||||
|
bitstream = new Bitstream(stream);
|
||||||
|
decoder = new Decoder();
|
||||||
|
|
||||||
|
if (device!=null)
|
||||||
|
{
|
||||||
|
audio = device;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FactoryRegistry r = FactoryRegistry.systemRegistry();
|
||||||
|
audio = r.createAudioDevice();
|
||||||
|
}
|
||||||
|
audio.open(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void play() throws JavaLayerException
|
||||||
|
{
|
||||||
|
play(Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays a number of MPEG audio frames.
|
||||||
|
*
|
||||||
|
* @param frames The number of frames to play.
|
||||||
|
* @return true if the last frame was played, or false if there are
|
||||||
|
* more frames.
|
||||||
|
*/
|
||||||
|
public boolean play(int frames) throws JavaLayerException
|
||||||
|
{
|
||||||
|
boolean ret = true;
|
||||||
|
|
||||||
|
while (frames-- > 0 && ret)
|
||||||
|
{
|
||||||
|
ret = decodeFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
// last frame, ensure all data flushed to the audio device.
|
||||||
|
AudioDevice out = audio;
|
||||||
|
if (out!=null)
|
||||||
|
{
|
||||||
|
out.flush();
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
complete = (!closed);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cloases this player. Any audio currently playing is stopped
|
||||||
|
* immediately.
|
||||||
|
*/
|
||||||
|
public synchronized void close()
|
||||||
|
{
|
||||||
|
AudioDevice out = audio;
|
||||||
|
if (out!=null)
|
||||||
|
{
|
||||||
|
closed = true;
|
||||||
|
audio = null;
|
||||||
|
// this may fail, so ensure object state is set up before
|
||||||
|
// calling this method.
|
||||||
|
out.close();
|
||||||
|
lastPosition = out.getPosition();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bitstream.close();
|
||||||
|
}
|
||||||
|
catch (BitstreamException ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the completed status of this player.
|
||||||
|
*
|
||||||
|
* @return true if all available MPEG audio frames have been
|
||||||
|
* decoded, or false otherwise.
|
||||||
|
*/
|
||||||
|
public synchronized boolean isComplete()
|
||||||
|
{
|
||||||
|
return complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the position in milliseconds of the current audio
|
||||||
|
* sample being played. This method delegates to the <code>
|
||||||
|
* AudioDevice</code> that is used by this player to sound
|
||||||
|
* the decoded audio samples.
|
||||||
|
*/
|
||||||
|
public int getPosition()
|
||||||
|
{
|
||||||
|
int position = lastPosition;
|
||||||
|
|
||||||
|
AudioDevice out = audio;
|
||||||
|
if (out!=null)
|
||||||
|
{
|
||||||
|
position = out.getPosition();
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a single frame.
|
||||||
|
*
|
||||||
|
* @return true if there are no more frames to decode, false otherwise.
|
||||||
|
*/
|
||||||
|
protected boolean decodeFrame() throws JavaLayerException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AudioDevice out = audio;
|
||||||
|
if (out==null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Header h = bitstream.readFrame();
|
||||||
|
|
||||||
|
if (h==null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// sample buffer set when decoder constructed
|
||||||
|
SampleBuffer output = (SampleBuffer)decoder.decodeFrame(h, bitstream);
|
||||||
|
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
out = audio;
|
||||||
|
if (out!=null)
|
||||||
|
{
|
||||||
|
out.write(output.getBuffer(), 0, output.getBufferLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitstream.closeFrame();
|
||||||
|
}
|
||||||
|
catch (RuntimeException ex)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException("Exception decoding audio frame", ex);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
System.out.println("exception decoding audio frame: "+ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (BitstreamException bitex)
|
||||||
|
{
|
||||||
|
System.out.println("exception decoding audio frame: "+bitex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (DecoderException decex)
|
||||||
|
{
|
||||||
|
System.out.println("exception decoding audio frame: "+decex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
246
src/javazoom/jl/player/PlayerApplet.java
Normal file
246
src/javazoom/jl/player/PlayerApplet.java
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player;
|
||||||
|
|
||||||
|
import java.applet.Applet;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple applet that plays an MPEG audio file.
|
||||||
|
* The URL (relative to the document base)
|
||||||
|
* is passed as the "audioURL" parameter.
|
||||||
|
*
|
||||||
|
* @author Mat McGowan
|
||||||
|
* @since 0.0.8
|
||||||
|
*/
|
||||||
|
public class PlayerApplet extends Applet implements Runnable
|
||||||
|
{
|
||||||
|
static public final String AUDIO_PARAMETER = "audioURL";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Player used to play the MPEG audio file.
|
||||||
|
*/
|
||||||
|
private Player player = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The thread that runs the player.
|
||||||
|
*/
|
||||||
|
private Thread playerThread = null;
|
||||||
|
|
||||||
|
private String fileName = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the <code>AudioDevice</code> instance that will
|
||||||
|
* be used to sound the audio data.
|
||||||
|
*
|
||||||
|
* @return an audio device instance that will be used to
|
||||||
|
* sound the audio stream.
|
||||||
|
*/
|
||||||
|
protected AudioDevice getAudioDevice() throws JavaLayerException
|
||||||
|
{
|
||||||
|
return FactoryRegistry.systemRegistry().createAudioDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the InputStream that provides the MPEG audio
|
||||||
|
* stream data.
|
||||||
|
*
|
||||||
|
* @return an InputStream from which the MPEG audio data
|
||||||
|
* is read, or null if an error occurs.
|
||||||
|
*/
|
||||||
|
protected InputStream getAudioStream()
|
||||||
|
{
|
||||||
|
InputStream in = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URL url = getAudioURL();
|
||||||
|
if (url!=null)
|
||||||
|
in = url.openStream();
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
System.err.println(ex);
|
||||||
|
}
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getAudioFileName()
|
||||||
|
{
|
||||||
|
String urlString = fileName;
|
||||||
|
if (urlString==null)
|
||||||
|
{
|
||||||
|
urlString = getParameter(AUDIO_PARAMETER);
|
||||||
|
}
|
||||||
|
return urlString;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected URL getAudioURL()
|
||||||
|
{
|
||||||
|
String urlString = getAudioFileName();
|
||||||
|
URL url = null;
|
||||||
|
if (urlString!=null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
url = new URL(getDocumentBase(), urlString);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.err.println(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL of the audio stream to play.
|
||||||
|
*/
|
||||||
|
public void setFileName(String name)
|
||||||
|
{
|
||||||
|
fileName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName()
|
||||||
|
{
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the audio player. If the player is already stopped
|
||||||
|
* this method is a no-op.
|
||||||
|
*/
|
||||||
|
protected void stopPlayer() throws JavaLayerException
|
||||||
|
{
|
||||||
|
if (player!=null)
|
||||||
|
{
|
||||||
|
player.close();
|
||||||
|
player = null;
|
||||||
|
playerThread = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompresses audio data from an InputStream and plays it
|
||||||
|
* back through an AudioDevice. The playback is run on a newly
|
||||||
|
* created thread.
|
||||||
|
*
|
||||||
|
* @param in The InputStream that provides the MPEG audio data.
|
||||||
|
* @param dev The AudioDevice to use to sound the decompressed data.
|
||||||
|
*
|
||||||
|
* @throws JavaLayerException if there was a problem decoding
|
||||||
|
* or playing the audio data.
|
||||||
|
*/
|
||||||
|
protected void play(InputStream in, AudioDevice dev) throws JavaLayerException
|
||||||
|
{
|
||||||
|
stopPlayer();
|
||||||
|
|
||||||
|
if (in!=null && dev!=null)
|
||||||
|
{
|
||||||
|
player = new Player(in, dev);
|
||||||
|
playerThread = createPlayerThread();
|
||||||
|
playerThread.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new thread used to run the audio player.
|
||||||
|
* @return A new Thread that, once started, runs the audio player.
|
||||||
|
*/
|
||||||
|
protected Thread createPlayerThread()
|
||||||
|
{
|
||||||
|
return new Thread(this, "Audio player thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes this applet.
|
||||||
|
*/
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts this applet. An input stream and audio device
|
||||||
|
* are created and passed to the play() method.
|
||||||
|
*/
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
String name = getAudioFileName();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
InputStream in = getAudioStream();
|
||||||
|
AudioDevice dev = getAudioDevice();
|
||||||
|
play(in, dev);
|
||||||
|
}
|
||||||
|
catch (JavaLayerException ex)
|
||||||
|
{
|
||||||
|
synchronized (System.err)
|
||||||
|
{
|
||||||
|
System.err.println("Unable to play "+name);
|
||||||
|
ex.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops this applet. If audio is currently playing, it is
|
||||||
|
* stopped.
|
||||||
|
*/
|
||||||
|
public void stop()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stopPlayer();
|
||||||
|
}
|
||||||
|
catch (JavaLayerException ex)
|
||||||
|
{
|
||||||
|
System.err.println(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The run method for the audio player thread. Simply calls
|
||||||
|
* play() on the player to play the entire stream.
|
||||||
|
*/
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
if (player!=null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
player.play();
|
||||||
|
}
|
||||||
|
catch (JavaLayerException ex)
|
||||||
|
{
|
||||||
|
System.err.println("Problem playing audio: "+ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
242
src/javazoom/jl/player/advanced/AdvancedPlayer.java
Normal file
242
src/javazoom/jl/player/advanced/AdvancedPlayer.java
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player.advanced;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.Bitstream;
|
||||||
|
import javazoom.jl.decoder.BitstreamException;
|
||||||
|
import javazoom.jl.decoder.Decoder;
|
||||||
|
import javazoom.jl.decoder.Header;
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
import javazoom.jl.decoder.SampleBuffer;
|
||||||
|
import javazoom.jl.player.AudioDevice;
|
||||||
|
import javazoom.jl.player.FactoryRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a hybrid of javazoom.jl.player.Player tweeked to include <code>play(startFrame, endFrame)</code>
|
||||||
|
* hopefully this will be included in the api
|
||||||
|
*/
|
||||||
|
public class AdvancedPlayer
|
||||||
|
{
|
||||||
|
/** The MPEG audio bitstream.*/
|
||||||
|
private Bitstream bitstream;
|
||||||
|
/** The MPEG audio decoder. */
|
||||||
|
private Decoder decoder;
|
||||||
|
/** The AudioDevice the audio samples are written to. */
|
||||||
|
private AudioDevice audio;
|
||||||
|
/** Has the player been closed? */
|
||||||
|
private boolean closed = false;
|
||||||
|
/** Has the player played back all frames from the stream? */
|
||||||
|
private boolean complete = false;
|
||||||
|
private int lastPosition = 0;
|
||||||
|
/** Listener for the playback process */
|
||||||
|
private PlaybackListener listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new <code>Player</code> instance.
|
||||||
|
*/
|
||||||
|
public AdvancedPlayer(InputStream stream) throws JavaLayerException
|
||||||
|
{
|
||||||
|
this(stream, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdvancedPlayer(InputStream stream, AudioDevice device) throws JavaLayerException
|
||||||
|
{
|
||||||
|
bitstream = new Bitstream(stream);
|
||||||
|
|
||||||
|
if (device!=null) audio = device;
|
||||||
|
else audio = FactoryRegistry.systemRegistry().createAudioDevice();
|
||||||
|
audio.open(decoder = new Decoder());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void play() throws JavaLayerException
|
||||||
|
{
|
||||||
|
play(Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays a number of MPEG audio frames.
|
||||||
|
*
|
||||||
|
* @param frames The number of frames to play.
|
||||||
|
* @return true if the last frame was played, or false if there are
|
||||||
|
* more frames.
|
||||||
|
*/
|
||||||
|
public boolean play(int frames) throws JavaLayerException
|
||||||
|
{
|
||||||
|
boolean ret = true;
|
||||||
|
|
||||||
|
// report to listener
|
||||||
|
if(listener != null) listener.playbackStarted(createEvent(PlaybackEvent.STARTED));
|
||||||
|
|
||||||
|
while (frames-- > 0 && ret)
|
||||||
|
{
|
||||||
|
ret = decodeFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!ret)
|
||||||
|
{
|
||||||
|
// last frame, ensure all data flushed to the audio device.
|
||||||
|
AudioDevice out = audio;
|
||||||
|
if (out != null)
|
||||||
|
{
|
||||||
|
// System.out.println(audio.getPosition());
|
||||||
|
out.flush();
|
||||||
|
// System.out.println(audio.getPosition());
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
complete = (!closed);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// report to listener
|
||||||
|
if(listener != null) listener.playbackFinished(createEvent(out, PlaybackEvent.STOPPED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cloases this player. Any audio currently playing is stopped
|
||||||
|
* immediately.
|
||||||
|
*/
|
||||||
|
public synchronized void close()
|
||||||
|
{
|
||||||
|
AudioDevice out = audio;
|
||||||
|
if (out != null)
|
||||||
|
{
|
||||||
|
closed = true;
|
||||||
|
audio = null;
|
||||||
|
// this may fail, so ensure object state is set up before
|
||||||
|
// calling this method.
|
||||||
|
out.close();
|
||||||
|
lastPosition = out.getPosition();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bitstream.close();
|
||||||
|
}
|
||||||
|
catch (BitstreamException ex)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a single frame.
|
||||||
|
*
|
||||||
|
* @return true if there are no more frames to decode, false otherwise.
|
||||||
|
*/
|
||||||
|
protected boolean decodeFrame() throws JavaLayerException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AudioDevice out = audio;
|
||||||
|
if (out == null) return false;
|
||||||
|
|
||||||
|
Header h = bitstream.readFrame();
|
||||||
|
if (h == null) return false;
|
||||||
|
|
||||||
|
// sample buffer set when decoder constructed
|
||||||
|
SampleBuffer output = (SampleBuffer) decoder.decodeFrame(h, bitstream);
|
||||||
|
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
out = audio;
|
||||||
|
if(out != null)
|
||||||
|
{
|
||||||
|
out.write(output.getBuffer(), 0, output.getBufferLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitstream.closeFrame();
|
||||||
|
}
|
||||||
|
catch (RuntimeException ex)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException("Exception decoding audio frame", ex);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* skips over a single frame
|
||||||
|
* @return false if there are no more frames to decode, true otherwise.
|
||||||
|
*/
|
||||||
|
protected boolean skipFrame() throws JavaLayerException
|
||||||
|
{
|
||||||
|
Header h = bitstream.readFrame();
|
||||||
|
if (h == null) return false;
|
||||||
|
bitstream.closeFrame();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays a range of MPEG audio frames
|
||||||
|
* @param start The first frame to play
|
||||||
|
* @param end The last frame to play
|
||||||
|
* @return true if the last frame was played, or false if there are more frames.
|
||||||
|
*/
|
||||||
|
public boolean play(final int start, final int end) throws JavaLayerException
|
||||||
|
{
|
||||||
|
boolean ret = true;
|
||||||
|
int offset = start;
|
||||||
|
while (offset-- > 0 && ret) ret = skipFrame();
|
||||||
|
return play(end - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a <code>PlaybackEvent</code>
|
||||||
|
*/
|
||||||
|
private PlaybackEvent createEvent(int id)
|
||||||
|
{
|
||||||
|
return createEvent(audio, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a <code>PlaybackEvent</code>
|
||||||
|
*/
|
||||||
|
private PlaybackEvent createEvent(AudioDevice dev, int id)
|
||||||
|
{
|
||||||
|
return new PlaybackEvent(this, id, dev.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the <code>PlaybackListener</code>
|
||||||
|
*/
|
||||||
|
public void setPlayBackListener(PlaybackListener listener)
|
||||||
|
{
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the <code>PlaybackListener</code>
|
||||||
|
*/
|
||||||
|
public PlaybackListener getPlayBackListener()
|
||||||
|
{
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* closes the player and notifies <code>PlaybackListener</code>
|
||||||
|
*/
|
||||||
|
public void stop()
|
||||||
|
{
|
||||||
|
listener.playbackFinished(createEvent(PlaybackEvent.STOPPED));
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
51
src/javazoom/jl/player/advanced/PlaybackEvent.java
Normal file
51
src/javazoom/jl/player/advanced/PlaybackEvent.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player.advanced;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event which indicates a <code>Player</code> has performed an 'playback action'
|
||||||
|
* @author Paul Stanton (http://wanto.f2o.org/)
|
||||||
|
*/
|
||||||
|
public class PlaybackEvent
|
||||||
|
{
|
||||||
|
public static int STOPPED = 1;
|
||||||
|
public static int STARTED = 2;
|
||||||
|
|
||||||
|
private AdvancedPlayer source;
|
||||||
|
private int frame;
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
public PlaybackEvent(AdvancedPlayer source, int id, int frame)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
this.source = source;
|
||||||
|
this.frame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId(){return id;}
|
||||||
|
public void setId(int id){this.id = id;}
|
||||||
|
|
||||||
|
public int getFrame(){return frame;}
|
||||||
|
public void setFrame(int frame){this.frame = frame;}
|
||||||
|
|
||||||
|
public AdvancedPlayer getSource(){return source;}
|
||||||
|
public void setSource(AdvancedPlayer source){this.source = source;}
|
||||||
|
|
||||||
|
}
|
||||||
30
src/javazoom/jl/player/advanced/PlaybackListener.java
Normal file
30
src/javazoom/jl/player/advanced/PlaybackListener.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player.advanced;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for javalayer Player playback
|
||||||
|
* @author Paul Stanton (http://wanto.f2o.org/)
|
||||||
|
*/
|
||||||
|
public abstract class PlaybackListener
|
||||||
|
{
|
||||||
|
public void playbackStarted(PlaybackEvent evt){}
|
||||||
|
public void playbackFinished(PlaybackEvent evt){}
|
||||||
|
}
|
||||||
116
src/javazoom/jl/player/advanced/jlap.java
Normal file
116
src/javazoom/jl/player/advanced/jlap.java
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player.advanced;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements a sample player using Playback listener.
|
||||||
|
*/
|
||||||
|
public class jlap
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
jlap test = new jlap();
|
||||||
|
if (args.length != 1)
|
||||||
|
{
|
||||||
|
test.showUsage();
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
test.play(args[0]);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.err.println(ex.getMessage());
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void play(String filename) throws JavaLayerException, IOException
|
||||||
|
{
|
||||||
|
InfoListener lst = new InfoListener();
|
||||||
|
playMp3(new File(filename), lst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showUsage()
|
||||||
|
{
|
||||||
|
System.out.println("Usage: jla <filename>");
|
||||||
|
System.out.println("");
|
||||||
|
System.out.println(" e.g. : java javazoom.jl.player.advanced.jlap localfile.mp3");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AdvancedPlayer playMp3(File mp3, PlaybackListener listener) throws IOException, JavaLayerException
|
||||||
|
{
|
||||||
|
return playMp3(mp3, 0, Integer.MAX_VALUE, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AdvancedPlayer playMp3(File mp3, int start, int end, PlaybackListener listener) throws IOException, JavaLayerException
|
||||||
|
{
|
||||||
|
return playMp3(new BufferedInputStream(new FileInputStream(mp3)), start, end, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AdvancedPlayer playMp3(final InputStream is, final int start, final int end, PlaybackListener listener) throws JavaLayerException
|
||||||
|
{
|
||||||
|
final AdvancedPlayer player = new AdvancedPlayer(is);
|
||||||
|
player.setPlayBackListener(listener);
|
||||||
|
// run in new thread
|
||||||
|
new Thread()
|
||||||
|
{
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
player.play(start, end);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InfoListener extends PlaybackListener
|
||||||
|
{
|
||||||
|
public void playbackStarted(PlaybackEvent evt)
|
||||||
|
{
|
||||||
|
System.out.println("Play started from frame " + evt.getFrame());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playbackFinished(PlaybackEvent evt)
|
||||||
|
{
|
||||||
|
System.out.println("Play completed at frame " + evt.getFrame());
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
176
src/javazoom/jl/player/jlp.java
Normal file
176
src/javazoom/jl/player/jlp.java
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* 11/19/04 1.0 moved to LGPL.
|
||||||
|
*
|
||||||
|
* 06/04/01 Streaming support added. javalayer@javazoom.net
|
||||||
|
*
|
||||||
|
* 29/01/00 Initial version. mdm@techie.com
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* 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 javazoom.jl.player;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import javazoom.jl.decoder.JavaLayerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>jlp</code> class implements a simple command-line
|
||||||
|
* player for MPEG audio files.
|
||||||
|
*
|
||||||
|
* @author Mat McGowan (mdm@techie.com)
|
||||||
|
*/
|
||||||
|
public class jlp
|
||||||
|
{
|
||||||
|
private String fFilename = null;
|
||||||
|
private boolean remote = false;
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
jlp player = createInstance(args);
|
||||||
|
if (player!=null)
|
||||||
|
player.play();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.err.println(ex);
|
||||||
|
ex.printStackTrace(System.err);
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
System.exit(retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public jlp createInstance(String[] args)
|
||||||
|
{
|
||||||
|
jlp player = new jlp();
|
||||||
|
if (!player.parseArgs(args))
|
||||||
|
player = null;
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
private jlp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public jlp(String filename)
|
||||||
|
{
|
||||||
|
init(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void init(String filename)
|
||||||
|
{
|
||||||
|
fFilename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean parseArgs(String[] args)
|
||||||
|
{
|
||||||
|
boolean parsed = false;
|
||||||
|
if (args.length == 1)
|
||||||
|
{
|
||||||
|
init(args[0]);
|
||||||
|
parsed = true;
|
||||||
|
remote = false;
|
||||||
|
}
|
||||||
|
else if (args.length == 2)
|
||||||
|
{
|
||||||
|
if (!(args[0].equals("-url")))
|
||||||
|
{
|
||||||
|
showUsage();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
init(args[1]);
|
||||||
|
parsed = true;
|
||||||
|
remote = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
showUsage();
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showUsage()
|
||||||
|
{
|
||||||
|
System.out.println("Usage: jlp [-url] <filename>");
|
||||||
|
System.out.println("");
|
||||||
|
System.out.println(" e.g. : java javazoom.jl.player.jlp localfile.mp3");
|
||||||
|
System.out.println(" java javazoom.jl.player.jlp -url http://www.server.com/remotefile.mp3");
|
||||||
|
System.out.println(" java javazoom.jl.player.jlp -url http://www.shoutcastserver.com:8000");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void play()
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
System.out.println("playing "+fFilename+"...");
|
||||||
|
InputStream in = null;
|
||||||
|
if (remote == true) in = getURLInputStream();
|
||||||
|
else in = getInputStream();
|
||||||
|
AudioDevice dev = getAudioDevice();
|
||||||
|
Player player = new Player(in, dev);
|
||||||
|
player.play();
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException("Problem playing file "+fFilename, ex);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new JavaLayerException("Problem playing file "+fFilename, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Playing file from URL (Streaming).
|
||||||
|
*/
|
||||||
|
protected InputStream getURLInputStream()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
URL url = new URL(fFilename);
|
||||||
|
InputStream fin = url.openStream();
|
||||||
|
BufferedInputStream bin = new BufferedInputStream(fin);
|
||||||
|
return bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Playing file from FileInputStream.
|
||||||
|
*/
|
||||||
|
protected InputStream getInputStream()
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
FileInputStream fin = new FileInputStream(fFilename);
|
||||||
|
BufferedInputStream bin = new BufferedInputStream(fin);
|
||||||
|
return bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AudioDevice getAudioDevice()
|
||||||
|
throws JavaLayerException
|
||||||
|
{
|
||||||
|
return FactoryRegistry.systemRegistry().createAudioDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user