From faec8b68c68e7cfe8d69a4783dd1e74567dbef44 Mon Sep 17 00:00:00 2001 From: yeom Date: Fri, 5 Aug 2011 01:52:32 +0000 Subject: [PATCH] start revising the linear type checking --- .../src/Analysis/SSJava/LinearTypeCheck.java | 402 +++++ .../SSJava/MethodAnnotationCheck.java | 2 - .../src/Analysis/SSJava/SSJavaAnalysis.java | 13 +- .../Analysis/SSJava/SingleReferenceCheck.java | 147 -- .../src/Tests/ssJava/mp3decoder/Decoder.java | 723 ++++---- .../src/Tests/ssJava/mp3decoder/Header.java | 1506 +++++++++-------- .../ssJava/mp3decoder/LayerIDecoder.java | 20 +- .../src/Tests/ssJava/mp3decoder/Player.java | 17 +- 8 files changed, 1534 insertions(+), 1296 deletions(-) create mode 100644 Robust/src/Analysis/SSJava/LinearTypeCheck.java delete mode 100644 Robust/src/Analysis/SSJava/SingleReferenceCheck.java diff --git a/Robust/src/Analysis/SSJava/LinearTypeCheck.java b/Robust/src/Analysis/SSJava/LinearTypeCheck.java new file mode 100644 index 00000000..90aee1e7 --- /dev/null +++ b/Robust/src/Analysis/SSJava/LinearTypeCheck.java @@ -0,0 +1,402 @@ +package Analysis.SSJava; + +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Set; +import java.util.Vector; + +import IR.AnnotationDescriptor; +import IR.ClassDescriptor; +import IR.Descriptor; +import IR.MethodDescriptor; +import IR.State; +import IR.SymbolTable; +import IR.TaskDescriptor; +import IR.TypeDescriptor; +import IR.VarDescriptor; +import IR.Tree.ArrayAccessNode; +import IR.Tree.ArrayInitializerNode; +import IR.Tree.AssignmentNode; +import IR.Tree.AtomicNode; +import IR.Tree.BlockExpressionNode; +import IR.Tree.BlockNode; +import IR.Tree.BlockStatementNode; +import IR.Tree.CastNode; +import IR.Tree.ClassTypeNode; +import IR.Tree.ContinueBreakNode; +import IR.Tree.CreateObjectNode; +import IR.Tree.DeclarationNode; +import IR.Tree.ExpressionNode; +import IR.Tree.FieldAccessNode; +import IR.Tree.IfStatementNode; +import IR.Tree.InstanceOfNode; +import IR.Tree.Kind; +import IR.Tree.LiteralNode; +import IR.Tree.LoopNode; +import IR.Tree.MethodInvokeNode; +import IR.Tree.NameNode; +import IR.Tree.OffsetNode; +import IR.Tree.OpNode; +import IR.Tree.ReturnNode; +import IR.Tree.SubBlockNode; +import IR.Tree.SwitchBlockNode; +import IR.Tree.SwitchLabelNode; +import IR.Tree.SwitchStatementNode; +import IR.Tree.SynchronizedNode; +import IR.Tree.TagDeclarationNode; +import IR.Tree.TaskExitNode; +import IR.Tree.TertiaryNode; + +public class LinearTypeCheck { + + State state; + SSJavaAnalysis ssjava; + String needToNullify = null; + + Hashtable> md2DelegateParamSet; + + public LinearTypeCheck(SSJavaAnalysis ssjava, State state) { + this.ssjava = ssjava; + this.state = state; + md2DelegateParamSet = new Hashtable>(); + } + + public void linearTypeCheck() { + + // first, parsing DELEGATE annotation from method declarations + Iterator it = state.getClassSymbolTable().getDescriptorsIterator(); + while (it.hasNext()) { + ClassDescriptor cd = (ClassDescriptor) it.next(); + for (Iterator method_it = cd.getMethods(); method_it.hasNext();) { + MethodDescriptor md = (MethodDescriptor) method_it.next(); + parseAnnotations(md); + } + } + System.out.println("###"); + System.out.println("md2DelegateParamSet=" + md2DelegateParamSet); + + // second, check the linear type + it = state.getClassSymbolTable().getDescriptorsIterator(); + while (it.hasNext()) { + ClassDescriptor cd = (ClassDescriptor) it.next(); + for (Iterator method_it = cd.getMethods(); method_it.hasNext();) { + MethodDescriptor md = (MethodDescriptor) method_it.next(); + if (ssjava.needTobeAnnotated(md)) { + checkMethodBody(cd, md); + } + } + } + + } + + private void parseAnnotations(MethodDescriptor md) { + + for (int i = 0; i < md.numParameters(); i++) { + // process annotations on method parameters + VarDescriptor vd = (VarDescriptor) md.getParameter(i); + + Vector annotationVec = vd.getType().getAnnotationMarkers(); + + for (int anIdx = 0; anIdx < annotationVec.size(); anIdx++) { + AnnotationDescriptor ad = annotationVec.elementAt(anIdx); + if (ad.getMarker().equals(SSJavaAnalysis.DELEGATE)) { + + Set delegateSet = md2DelegateParamSet.get(md); + if (delegateSet == null) { + delegateSet = new HashSet(); + md2DelegateParamSet.put(md, delegateSet); + } + delegateSet.add(vd); + } + } + + } + + } + + private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) { + BlockNode bn = state.getMethodBody(md); + checkBlockNode(md, md.getParameterTable(), bn); + } + + private void checkBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) { + for (int i = 0; i < bn.size(); i++) { + BlockStatementNode bsn = bn.get(i); + checkBlockStatementNode(md, bn.getVarTable(), bsn); + } + } + + private void checkBlockStatementNode(MethodDescriptor md, SymbolTable nametable, + BlockStatementNode bsn) { + + if (needToNullify != null) { + if (!checkNullifying(bsn)) { + throw new Error( + "Reference field, which is read by a method, should be assigned to null before executing any following statement of the reference copy statement at " + + md.getClassDesc().getSourceFileName() + "::" + bsn.getNumLine()); + } + } + + switch (bsn.kind()) { + + case Kind.BlockExpressionNode: + checkBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn); + return; + + case Kind.DeclarationNode: + checkDeclarationNode(md, nametable, (DeclarationNode) bsn); + return; + + case Kind.IfStatementNode: + checkIfStatementNode(md, nametable, (IfStatementNode) bsn); + return; + + case Kind.SwitchStatementNode: + checkSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn); + return; + + case Kind.LoopNode: + checkLoopNode(md, nametable, (LoopNode) bsn); + return; + + case Kind.ReturnNode: + checkReturnNode(md, nametable, (ReturnNode) bsn); + return; + + case Kind.SubBlockNode: + checkSubBlockNode(md, nametable, (SubBlockNode) bsn); + return; + + case Kind.SynchronizedNode: + checkSynchronizedNode(md, nametable, (SynchronizedNode) bsn); + return; + } + + throw new Error(); + } + + private void checkSynchronizedNode(MethodDescriptor md, SymbolTable nametable, + SynchronizedNode sbn) { + checkBlockNode(md, nametable, sbn.getBlockNode()); + // todo this could be Object + checkExpressionNode(md, nametable, sbn.getExpr()); + } + + private void checkReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn) { + if (rn.getReturnExpression() != null) { + checkExpressionNode(md, nametable, rn.getReturnExpression()); + } + } + + private void checkSubBlockNode(MethodDescriptor md, SymbolTable nametable, SubBlockNode sbn) { + checkBlockNode(md, nametable, sbn.getBlockNode()); + } + + private void checkIfStatementNode(MethodDescriptor md, SymbolTable nametable, IfStatementNode isn) { + checkExpressionNode(md, nametable, isn.getCondition()); + checkBlockNode(md, nametable, isn.getTrueBlock()); + if (isn.getFalseBlock() != null) + checkBlockNode(md, nametable, isn.getFalseBlock()); + } + + private void checkSwitchStatementNode(MethodDescriptor md, SymbolTable nametable, + SwitchStatementNode ssn) { + + checkExpressionNode(md, nametable, ssn.getCondition()); + + BlockNode sbn = ssn.getSwitchBody(); + for (int i = 0; i < sbn.size(); i++) { + checkSwitchBlockNode(md, nametable, (SwitchBlockNode) sbn.get(i)); + } + } + + private void checkSwitchBlockNode(MethodDescriptor md, SymbolTable nametable, SwitchBlockNode sbn) { + checkBlockNode(md, nametable, sbn.getSwitchBlockStatement()); + } + + private void checkBlockExpressionNode(MethodDescriptor md, SymbolTable nametable, + BlockExpressionNode ben) { + checkExpressionNode(md, nametable, ben.getExpression()); + } + + private void checkExpressionNode(MethodDescriptor md, SymbolTable nametable, ExpressionNode en) { + switch (en.kind()) { + case Kind.AssignmentNode: + checkAssignmentNode(md, nametable, (AssignmentNode) en); + return; + + case Kind.CastNode: + checkCastNode(md, nametable, (CastNode) en); + return; + + case Kind.CreateObjectNode: + checkCreateObjectNode(md, nametable, (CreateObjectNode) en); + return; + + case Kind.FieldAccessNode: + checkFieldAccessNode(md, nametable, (FieldAccessNode) en); + return; + + case Kind.ArrayAccessNode: + checkArrayAccessNode(md, nametable, (ArrayAccessNode) en); + return; + + // case Kind.LiteralNode: + // checkLiteralNode(md, nametable, (LiteralNode) en); + // return; + + case Kind.MethodInvokeNode: + checkMethodInvokeNode(md, nametable, (MethodInvokeNode) en); + return; + + case Kind.NameNode: + checkNameNode(md, nametable, (NameNode) en); + return; + + case Kind.OpNode: + checkOpNode(md, nametable, (OpNode) en); + return; + + case Kind.OffsetNode: + checkOffsetNode(md, nametable, (OffsetNode) en); + return; + + case Kind.TertiaryNode: + checkTertiaryNode(md, nametable, (TertiaryNode) en); + return; + + // case Kind.InstanceOfNode: + // checkInstanceOfNode(md, nametable, (InstanceOfNode) en); + // return; + + // case Kind.ArrayInitializerNode: + // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en); + // return; + + // case Kind.ClassTypeNode: + // checkClassTypeNode(md, nametable, (ClassTypeNode) ens); + // return; + } + throw new Error(); + } + + private void checkTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode en) { + // TODO Auto-generated method stub + + } + + private void checkOffsetNode(MethodDescriptor md, SymbolTable nametable, OffsetNode en) { + // TODO Auto-generated method stub + + } + + private void checkOpNode(MethodDescriptor md, SymbolTable nametable, OpNode en) { + // TODO Auto-generated method stub + + } + + private void checkNameNode(MethodDescriptor md, SymbolTable nametable, NameNode en) { + // TODO Auto-generated method stub + + } + + private void checkMethodInvokeNode(MethodDescriptor md, SymbolTable nametable, MethodInvokeNode en) { + // TODO Auto-generated method stub + + } + + private void checkArrayAccessNode(MethodDescriptor md, SymbolTable nametable, ArrayAccessNode en) { + // TODO Auto-generated method stub + + } + + private void checkFieldAccessNode(MethodDescriptor md, SymbolTable nametable, FieldAccessNode fan) { + + } + + private void checkCreateObjectNode(MethodDescriptor md, SymbolTable nametable, + CreateObjectNode con) { + TypeDescriptor[] tdarray = new TypeDescriptor[con.numArgs()]; + for (int i = 0; i < con.numArgs(); i++) { + ExpressionNode en = con.getArg(i); + checkExpressionNode(md, nametable, en); + tdarray[i] = en.getType(); + } + + if ((con.getArrayInitializer() != null)) { + checkArrayInitializerNode(md, nametable, con.getArrayInitializer()); + } + + } + + private void checkArrayInitializerNode(MethodDescriptor md, SymbolTable nametable, + ArrayInitializerNode arrayInitializer) { + // TODO Auto-generated method stub + + } + + private void checkCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn) { + ExpressionNode en = cn.getExpression(); + checkExpressionNode(md, nametable, en); + } + + private boolean checkNullifying(BlockStatementNode bsn) { + + if (bsn.kind() == Kind.BlockExpressionNode) { + ExpressionNode en = ((BlockExpressionNode) bsn).getExpression(); + if (en.kind() == Kind.AssignmentNode) { + AssignmentNode an = (AssignmentNode) en; + + if (an.getSrc().getType().isNull() && an.getDest().printNode(0).equals(needToNullify)) { + needToNullify = null; + return true; + } + } + } + + return false; + } + + private void checkLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln) { + if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) { + checkExpressionNode(md, nametable, ln.getCondition()); + checkBlockNode(md, nametable, ln.getBody()); + } else { + // For loop case + /* Link in the initializer naming environment */ + BlockNode bn = ln.getInitializer(); + for (int i = 0; i < bn.size(); i++) { + BlockStatementNode bsn = bn.get(i); + checkBlockStatementNode(md, bn.getVarTable(), bsn); + } + // check the condition + checkExpressionNode(md, bn.getVarTable(), ln.getCondition()); + checkBlockNode(md, bn.getVarTable(), ln.getBody()); + checkBlockNode(md, bn.getVarTable(), ln.getUpdate()); + } + } + + private void checkAssignmentNode(Descriptor md, SymbolTable nametable, AssignmentNode an) { + needToNullify(an.getSrc()); + } + + private void checkDeclarationNode(Descriptor md, SymbolTable nametable, DeclarationNode dn) { + needToNullify(dn.getExpression()); + } + + private void needToNullify(ExpressionNode en) { + + if (en != null && en.getType().isPtr() && !en.getType().isString()) { + if (en.kind() != Kind.CreateObjectNode && en.kind() != Kind.LiteralNode) { + if (en.kind() == Kind.CastNode) { + needToNullify = ((CastNode) en).getExpression().printNode(0); + } else { + needToNullify = en.printNode(0); + } + } + } + + } + +} diff --git a/Robust/src/Analysis/SSJava/MethodAnnotationCheck.java b/Robust/src/Analysis/SSJava/MethodAnnotationCheck.java index 6c3dac6c..eba5f777 100644 --- a/Robust/src/Analysis/SSJava/MethodAnnotationCheck.java +++ b/Robust/src/Analysis/SSJava/MethodAnnotationCheck.java @@ -97,8 +97,6 @@ public class MethodAnnotationCheck { Set possibleCalleeSet = (Set) ssjava.getCallGraph().getMethods(calleeMD); - System.out.println("caller=" + callerMD + " callee=" + possibleCalleeSet); - for (Iterator iterator2 = possibleCalleeSet.iterator(); iterator2.hasNext();) { MethodDescriptor possibleCallee = (MethodDescriptor) iterator2.next(); diff --git a/Robust/src/Analysis/SSJava/SSJavaAnalysis.java b/Robust/src/Analysis/SSJava/SSJavaAnalysis.java index 4e62c259..41396e96 100644 --- a/Robust/src/Analysis/SSJava/SSJavaAnalysis.java +++ b/Robust/src/Analysis/SSJava/SSJavaAnalysis.java @@ -35,6 +35,7 @@ public class SSJavaAnalysis { public static final String LOC = "LOC"; public static final String DELTA = "DELTA"; public static final String TERMINATE = "TERMINATE"; + public static final String DELEGATE = "DELEGATE"; State state; TypeUtil tu; @@ -78,6 +79,7 @@ public class SSJavaAnalysis { } public void doCheck() { + doLinearTypeCheck(); doMethodAnnotationCheck(); if (state.SSJAVADEBUG) { debugPrint(); @@ -85,7 +87,11 @@ public class SSJavaAnalysis { parseLocationAnnotation(); doFlowDownCheck(); doDefinitelyWrittenCheck(); - doSingleReferenceCheck(); + } + + private void doLinearTypeCheck() { + LinearTypeCheck checker = new LinearTypeCheck(this, state); + checker.linearTypeCheck(); } public void debugPrint() { @@ -113,11 +119,6 @@ public class SSJavaAnalysis { checker.definitelyWrittenCheck(); } - public void doSingleReferenceCheck() { - SingleReferenceCheck checker = new SingleReferenceCheck(this, state); - checker.singleReferenceCheck(); - } - private void parseLocationAnnotation() { Iterator it = state.getClassSymbolTable().getDescriptorsIterator(); while (it.hasNext()) { diff --git a/Robust/src/Analysis/SSJava/SingleReferenceCheck.java b/Robust/src/Analysis/SSJava/SingleReferenceCheck.java deleted file mode 100644 index 8bc6a8c8..00000000 --- a/Robust/src/Analysis/SSJava/SingleReferenceCheck.java +++ /dev/null @@ -1,147 +0,0 @@ -package Analysis.SSJava; - -import java.util.Iterator; - -import IR.ClassDescriptor; -import IR.MethodDescriptor; -import IR.State; -import IR.Tree.AssignmentNode; -import IR.Tree.BlockExpressionNode; -import IR.Tree.BlockNode; -import IR.Tree.BlockStatementNode; -import IR.Tree.CastNode; -import IR.Tree.DeclarationNode; -import IR.Tree.ExpressionNode; -import IR.Tree.Kind; -import IR.Tree.LoopNode; -import IR.Tree.SubBlockNode; - -public class SingleReferenceCheck { - - State state; - SSJavaAnalysis ssjava; - String needToNullify = null; - - public SingleReferenceCheck(SSJavaAnalysis ssjava, State state) { - this.ssjava = ssjava; - this.state = state; - } - - public void singleReferenceCheck() { - Iterator it = state.getClassSymbolTable().getDescriptorsIterator(); - while (it.hasNext()) { - ClassDescriptor cd = (ClassDescriptor) it.next(); - for (Iterator method_it = cd.getMethods(); method_it.hasNext();) { - MethodDescriptor md = (MethodDescriptor) method_it.next(); - if (ssjava.needTobeAnnotated(md)) { - checkMethodBody(cd, md); - } - } - } - } - - private void checkMethodBody(ClassDescriptor cd, MethodDescriptor fm) { - BlockNode bn = state.getMethodBody(fm); - for (int i = 0; i < bn.size(); i++) { - checkBlockStatementNode(cd, bn.get(i)); - } - - } - - private boolean checkNullifying(BlockStatementNode bsn) { - - if (bsn.kind() == Kind.BlockExpressionNode) { - ExpressionNode en = ((BlockExpressionNode) bsn).getExpression(); - if (en.kind() == Kind.AssignmentNode) { - AssignmentNode an = (AssignmentNode) en; - - if (an.getSrc().getType().isNull() && an.getDest().printNode(0).equals(needToNullify)) { - needToNullify = null; - return true; - } - } - } - - return false; - } - - private void checkBlockStatementNode(ClassDescriptor cd, BlockStatementNode bsn) { - - if (needToNullify != null) { - if (!checkNullifying(bsn)) { - throw new Error( - "Reference field, which is read by a method, should be assigned to null before executing any following statement of the reference copy statement at " - + cd.getSourceFileName() + "::" + bsn.getNumLine()); - } - } - - switch (bsn.kind()) { - case Kind.BlockExpressionNode: - checkExpressionNode(((BlockExpressionNode) bsn).getExpression()); - break; - - case Kind.DeclarationNode: - checkDeclarationNode((DeclarationNode) bsn); - break; - - case Kind.SubBlockNode: - checkSubBlockNode(cd, (SubBlockNode) bsn); - return; - - case Kind.LoopNode: - checkLoopNode(cd, (LoopNode) bsn); - break; - } - - } - - private void checkLoopNode(ClassDescriptor cd, LoopNode ln) { - if (ln.getType() == LoopNode.FORLOOP) { - checkBlockNode(cd, ln.getInitializer()); - } - checkBlockNode(cd, ln.getBody()); - } - - private void checkSubBlockNode(ClassDescriptor cd, SubBlockNode sbn) { - checkBlockNode(cd, sbn.getBlockNode()); - } - - private void checkBlockNode(ClassDescriptor cd, BlockNode bn) { - for (int i = 0; i < bn.size(); i++) { - checkBlockStatementNode(cd, bn.get(i)); - } - } - - private void checkExpressionNode(ExpressionNode en) { - - switch (en.kind()) { - case Kind.AssignmentNode: - checkAssignmentNode((AssignmentNode) en); - break; - } - - } - - private void checkAssignmentNode(AssignmentNode an) { - needToNullify(an.getSrc()); - } - - private void checkDeclarationNode(DeclarationNode dn) { - needToNullify(dn.getExpression()); - } - - private void needToNullify(ExpressionNode en) { - - if (en != null && en.getType().isPtr() && !en.getType().isString()) { - if (en.kind() != Kind.CreateObjectNode && en.kind() != Kind.LiteralNode) { - if (en.kind() == Kind.CastNode) { - needToNullify = ((CastNode) en).getExpression().printNode(0); - } else { - needToNullify = en.printNode(0); - } - } - } - - } - -} diff --git a/Robust/src/Tests/ssJava/mp3decoder/Decoder.java b/Robust/src/Tests/ssJava/mp3decoder/Decoder.java index ec4bf7d4..e871eec9 100644 --- a/Robust/src/Tests/ssJava/mp3decoder/Decoder.java +++ b/Robust/src/Tests/ssJava/mp3decoder/Decoder.java @@ -17,391 +17,352 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *---------------------------------------------------------------------- */ - /** - * The Decoder class encapsulates the details of - * decoding an MPEG audio frame. + * The Decoder class encapsulates the details of decoding an MPEG + * audio frame. * - * @author MDM + * @author MDM * @version 0.0.7 12/12/99 - * @since 0.0.5 + * @since 0.0.5 */ @LATTICE("ST,DEDecoder instance with default - * parameters. - */ - - public Decoder() - { - this(null); - } - - /** - * Creates a new Decoder instance with default - * parameters. - * - * @param params The Params 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. - */ - @LATTICE("OParams class presents the customizable - * aspects of the decoder. - *

- * 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() - { - //TODO: need to have better clone method - Params clone=new Params(); - clone.outputChannels=outputChannels; - clone.equalizer=equalizer; - return 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. - *

- * The Equalizer 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 Equalizer used to initialize the - * EQ settings of the decoder. - */ - public Equalizer getInitialEqualizerSettings() - { - return equalizer; - } - - }; -} +public class Decoder implements DecoderErrors { + static private final Params DEFAULT_PARAMS = new Params(); + + /** + * The Bistream from which the MPEG audio frames are read. + */ + @LOC("ST") + private Bitstream stream; + + /** + * The Obuffer instance that will receive the decoded PCM samples. + */ + @LOC("OUT") + private Obuffer output; + + /** + * Synthesis filter for the left channel. + */ + @LOC("FIL") + private SynthesisFilter filter1; + + /** + * Sythesis filter for the right channel. + */ + @LOC("FIL") + private SynthesisFilter filter2; + + /** + * The decoder used to decode layer III frames. + */ + @LOC("DE") + private LayerIIIDecoder l3decoder; + @LOC("DE") + private LayerIIDecoder l2decoder; + @LOC("DE") + private LayerIDecoder l1decoder; + + @LOC("O") + private int outputFrequency; + @LOC("O") + private int outputChannels; + + @LOC("EQ") + private Equalizer equalizer = new Equalizer(); + + @LOC("PA") + private Params params; + + @LOC("INIT") + private boolean initialized; + + /** + * Creates a new Decoder instance with default parameters. + */ + + public Decoder() { + this(null); + } + + /** + * Creates a new Decoder instance with default parameters. + * + * @param params + * The Params 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. + */ + @LATTICE("OParams class presents the customizable aspects of the + * decoder. + *

+ * 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() { + // TODO: need to have better clone method + Params clone = new Params(); + clone.outputChannels = outputChannels; + clone.equalizer = equalizer; + return 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. + *

+ * The Equalizer 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 Equalizer used to initialize the EQ settings of + * the decoder. + */ + public Equalizer getInitialEqualizerSettings() { + return equalizer; + } + + }; +} diff --git a/Robust/src/Tests/ssJava/mp3decoder/Header.java b/Robust/src/Tests/ssJava/mp3decoder/Header.java index cd7fb01f..f4cef5c7 100644 --- a/Robust/src/Tests/ssJava/mp3decoder/Header.java +++ b/Robust/src/Tests/ssJava/mp3decoder/Header.java @@ -35,743 +35,771 @@ */ @LATTICE("HI>> 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 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. - */ - @RETURNLOC("OUT") - public int version() { return h_version; } - - /** - * Returns Layer ID. - */ - @RETURNLOC("OUT") - public int layer() { return h_layer; } - - /** - * Returns bitrate index. - */ - @RETURNLOC("OUT") - 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. - */ - @RETURNLOC("OUT") - 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. - */ - @RETURNLOC("OUT") - 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. - */ - @RETURNLOC("OUT") - public int slots() { return nSlots; } - - /** - * Returns Mode Extension. - */ - @RETURNLOC("OUT") - public int mode_extension() { return h_mode_extension; } - - // E.B -> private to public - @LOC("T") 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 - @LOC("T") 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 - */ - @RETURNLOC("OUT") - 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 - */ - @RETURNLOC("OUT") - public int intensity_stereo_bound() {return h_intensity_stereo_bound;} +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; + + @LOC("H") + private int h_layer; + @LOC("H") + private int h_protection_bit; + @LOC("H") + private int h_bitrate_index; + @LOC("H") + private int h_padding_bit; + @LOC("H") + private int h_mode_extension; + @LOC("HV") + private int h_version; + @LOC("H") + private int h_mode; + @LOC("H") + private int h_sample_frequency; + @LOC("HNS") + private int h_number_of_subbands; + @LOC("HI") + private int h_intensity_stereo_bound; + @LOC("H") + private boolean h_copyright; + @LOC("H") + private boolean h_original; + // VBR support added by E.B + @LOC("T") + private double[] h_vbr_time_per_frame = { -1.0, 384.0, 1152.0, 1152.0 }; + @LOC("T") + private boolean h_vbr; + @LOC("T") + private int h_vbr_frames; + @LOC("T") + private int h_vbr_scale; + @LOC("T") + private int h_vbr_bytes; + @LOC("T") + private byte[] h_vbr_toc; + + @LOC("SYNC") + private byte syncmode = Bitstream.INITIAL_SYNC; + @LOC("C") + private Crc16 crc; + + @LOC("C") + public short checksum; + @LOC("FS") + public int framesize; + @LOC("NS") + public int nSlots; + + @LOC("T") + 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 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. + */ + @RETURNLOC("OUT") + public int version() { + return h_version; + } + + /** + * Returns Layer ID. + */ + @RETURNLOC("OUT") + public int layer() { + return h_layer; + } + + /** + * Returns bitrate index. + */ + @RETURNLOC("OUT") + 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. + */ + @RETURNLOC("OUT") + 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. + */ + @RETURNLOC("OUT") + 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. + */ + @RETURNLOC("OUT") + public int slots() { + return nSlots; + } + + /** + * Returns Mode Extension. + */ + @RETURNLOC("OUT") + public int mode_extension() { + return h_mode_extension; + } + + // E.B -> private to public + @LOC("T") + 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 + @LOC("T") + 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 + */ + @RETURNLOC("OUT") + 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 + */ + @RETURNLOC("OUT") + public int intensity_stereo_bound() { + return h_intensity_stereo_bound; + } } diff --git a/Robust/src/Tests/ssJava/mp3decoder/LayerIDecoder.java b/Robust/src/Tests/ssJava/mp3decoder/LayerIDecoder.java index b895dafe..ef79a880 100644 --- a/Robust/src/Tests/ssJava/mp3decoder/LayerIDecoder.java +++ b/Robust/src/Tests/ssJava/mp3decoder/LayerIDecoder.java @@ -161,12 +161,11 @@ class LayerIDecoder implements FrameDecoder { * Class for layer I subbands in single channel mode. Used for single channel * mode and in derived class for intensity stereo mode */ - @LATTICE("SPlayer instance. */ @@ -84,11 +82,6 @@ public class Player bitstream = new Bitstream(stream); decoder = new Decoder(); - // decoder initialization - // taking out from ssjava loop - header = bitstream.readFrame(); - decoder.initialize(header, bitstream); - // if (device!=null) // { // audio = device; @@ -219,13 +212,13 @@ public class Player //if (out==null) // return false; -// Header h = bitstream.readFrame(); -// -// if (h==null) -// return false; + Header h = bitstream.readFrame(); + + if (h==null) + return false; // sample buffer set when decoder constructed - @LOC("O") SampleBuffer output = (SampleBuffer)decoder.decodeFrame(header, bitstream); + @LOC("O") SampleBuffer output = (SampleBuffer)decoder.decodeFrame(h, bitstream); //synchronized (this) //{ -- 2.34.1