diff --git a/.classpath b/.classpath index dde97586384..9038d13e40d 100644 --- a/.classpath +++ b/.classpath @@ -9,5 +9,6 @@ + diff --git a/.gitattributes b/.gitattributes index a887b4b7ed4..657040606d9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -27,7 +27,6 @@ res/lang/howTo/en.properties svneol=native#text/plain res/lang/lang.properties svneol=native#text/plain res/lib/google-collections-1.0.jar -text svneol=unset#unset res/lib/java-image-scaling-0.8.4.jar -text svneol=unset#unset -res/lib/jdom-1.0.jar -text svneol=unset#unset res/lib/jl1.0.1.jar -text svneol=unset#unset res/lib/miglayout-3.7.3.1-swing.jar -text svneol=unset#unset res/lib/napkinlaf-1.2.jar -text svneol=unset#unset @@ -489,60 +488,12 @@ src/forge/gui/game/CardPanel.java svneol=native#text/plain src/forge/gui/game/CardPicturePanel.java svneol=native#text/plain src/forge/properties/ForgeProps.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/beans/AbstractBean.java svneol=native#text/plain +src/org/jdesktop/swingx/JXMultiSplitPane.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/graphics/GraphicsUtilities.java svneol=native#text/plain +src/org/jdesktop/swingx/painter/AbstractPainter.java svneol=native#text/plain +src/org/jdesktop/swingx/painter/Painter.java svneol=native#text/plain src/treeProperties/PropertyElement.java svneol=native#text/plain src/treeProperties/PropertyType.java -text svneol=native#text/plain src/treeProperties/TreeProperties.java -text svneol=native#text/plain diff --git a/res/lib/jdom-1.0.jar b/res/lib/jdom-1.0.jar deleted file mode 100644 index 288e64cb5c4..00000000000 Binary files a/res/lib/jdom-1.0.jar and /dev/null differ diff --git a/src/forge/GUI_DeckAnalysis.java b/src/forge/GUI_DeckAnalysis.java index 41c6fb69b23..8291b21049a 100644 --- a/src/forge/GUI_DeckAnalysis.java +++ b/src/forge/GUI_DeckAnalysis.java @@ -171,7 +171,6 @@ public class GUI_DeckAnalysis extends javax.swing.JDialog { private JSeparator getJSeparator1() { if(jSeparator1 == null) { jSeparator1 = new JSeparator(); - //AnchorLayout jSeparator1Layout = new AnchorLayout(); jSeparator1.setPreferredSize(new java.awt.Dimension(117, 6)); jSeparator1.setLayout(null); jSeparator1.setBounds(1, 20, 136, 5); @@ -224,7 +223,6 @@ public class GUI_DeckAnalysis extends javax.swing.JDialog { private JLabel getJLabel5() { if(jLabelRed == null) { jLabelRed = new JLabel(); - // AnchorLayout jLabel5Layout = new AnchorLayout(); jLabelRed.setText("Red:"); jLabelRed.setLayout(null); jLabelRed.setBounds(10, 94, 127, 14); @@ -235,7 +233,6 @@ public class GUI_DeckAnalysis extends javax.swing.JDialog { private JLabel getJLabel6() { if(jLabelWhite == null) { jLabelWhite = new JLabel(); - // AnchorLayout jLabel6Layout = new AnchorLayout(); jLabelWhite.setText("White:"); jLabelWhite.setLayout(null); jLabelWhite.setBounds(10, 116, 127, 13); @@ -246,7 +243,6 @@ public class GUI_DeckAnalysis extends javax.swing.JDialog { private JLabel getJLabel7() { if(jLabelMultiColor == null) { jLabelMultiColor = new JLabel(); - // AnchorLayout jLabel7Layout = new AnchorLayout(); jLabelMultiColor.setText("Multicolor:"); jLabelMultiColor.setLayout(null); jLabelMultiColor.setBounds(10, 138, 127, 12); @@ -257,7 +253,6 @@ public class GUI_DeckAnalysis extends javax.swing.JDialog { private JLabel getJLabel8() { if(jLabelColorless == null) { jLabelColorless = new JLabel(); - // AnchorLayout jLabel8Layout = new AnchorLayout(); jLabelColorless.setText("Colorless:"); jLabelColorless.setLayout(null); jLabelColorless.setBounds(10, 160, 128, 11); @@ -278,7 +273,6 @@ public class GUI_DeckAnalysis extends javax.swing.JDialog { private JLabel getJLabel1xx() { if(jLabelTotal == null) { jLabelTotal = new JLabel(); - // AnchorLayout jLabel1Layout = new AnchorLayout(); jLabelTotal.setText("Information about deck:"); jLabelTotal.setLayout(null); jLabelTotal.setBounds(5, 0, 454, 35); diff --git a/src/forge/GUI_Filter.java b/src/forge/GUI_Filter.java index aeb0b3cd679..2fe8f83ea4d 100644 --- a/src/forge/GUI_Filter.java +++ b/src/forge/GUI_Filter.java @@ -312,7 +312,6 @@ public class GUI_Filter extends javax.swing.JDialog { private JButton getJButtonOk() { if(jButtonOk == null) { jButtonOk = new JButton(); - //AnchorLayout jButtonOkLayout = new AnchorLayout(); jButtonOk.setLayout(null); jButtonOk.setText("OK"); jButtonOk.setPreferredSize(new java.awt.Dimension(100, 25)); @@ -324,7 +323,6 @@ public class GUI_Filter extends javax.swing.JDialog { private JCheckBox getJCheckBoxBlack() { if(jCheckBoxBlack == null) { jCheckBoxBlack = new JCheckBox(); - //AnchorLayout jCheckBoxBlackLayout = new AnchorLayout(); jCheckBoxBlack.setLayout(null); jCheckBoxBlack.setText("Black"); jCheckBoxBlack.setPreferredSize(new java.awt.Dimension(97, 20)); @@ -402,7 +400,6 @@ public class GUI_Filter extends javax.swing.JDialog { private JSeparator getJSeparator2() { if(jSeparator2 == null) { jSeparator2 = new JSeparator(); - //AnchorLayout jSeparator2Layout = new AnchorLayout(); jSeparator2.setPreferredSize(new java.awt.Dimension(116, 10)); jSeparator2.setLayout(null); } diff --git a/src/forge/GUI_Quest_Filter.java b/src/forge/GUI_Quest_Filter.java index 285be233cd1..e3741e6bfcf 100644 --- a/src/forge/GUI_Quest_Filter.java +++ b/src/forge/GUI_Quest_Filter.java @@ -74,8 +74,7 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private void initGUI() { try { - AnchorLayout thisLayout = new AnchorLayout(); - getContentPane().setLayout(thisLayout); + getContentPane().setLayout(new AnchorLayout()); { NameText = new JTextField(); getContentPane().add( @@ -111,7 +110,6 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { } { jLabel1 = new JLabel(); - //AnchorLayout jLabel1Layout = new AnchorLayout(); getContentPane().add( jLabel1, new AnchorConstraint(4, 313, 153, 41, AnchorConstraint.ANCHOR_REL, @@ -165,9 +163,8 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JPanel getJPanel1() { if(jPanel1 == null) { jPanel1 = new JPanel(); - AnchorLayout jPanel1Layout = new AnchorLayout(); jPanel1.setPreferredSize(new java.awt.Dimension(121, 183)); - jPanel1.setLayout(jPanel1Layout); + jPanel1.setLayout(new AnchorLayout()); jPanel1.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); jPanel1.setBackground(new java.awt.Color(192, 192, 192)); jPanel1.add(getJCheckBoxBlack(), new AnchorConstraint(134, 985, 240, 79, AnchorConstraint.ANCHOR_REL, @@ -206,7 +203,6 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JSeparator getJSeparator1() { if(jSeparator1 == null) { jSeparator1 = new JSeparator(); - //AnchorLayout jSeparator1Layout = new AnchorLayout(); jSeparator1.setPreferredSize(new java.awt.Dimension(117, 6)); jSeparator1.setLayout(null); } @@ -216,7 +212,6 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JCheckBox getJCheckBoxBlue() { if(jCheckBoxBlue == null) { jCheckBoxBlue = new JCheckBox(); - //AnchorLayout jCheckBoxBlueLayout = new AnchorLayout(); jCheckBoxBlue.setLayout(null); jCheckBoxBlue.setText("Blue"); jCheckBoxBlue.setPreferredSize(new java.awt.Dimension(109, 14)); @@ -238,7 +233,6 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JCheckBox getJCheckBoxGreen() { if(jCheckBoxGreen == null) { jCheckBoxGreen = new JCheckBox(); - //AnchorLayout jCheckBoxGreenLayout = new AnchorLayout(); jCheckBoxGreen.setLayout(null); jCheckBoxGreen.setText("Green"); jCheckBoxGreen.setPreferredSize(new java.awt.Dimension(109, 12)); @@ -260,7 +254,6 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JCheckBox getJCheckBoxRed() { if(jCheckBoxRed == null) { jCheckBoxRed = new JCheckBox(); - //AnchorLayout jCheckBoxRedLayout = new AnchorLayout(); jCheckBoxRed.setLayout(null); jCheckBoxRed.setText("Red"); jCheckBoxRed.setPreferredSize(new java.awt.Dimension(109, 14)); @@ -282,7 +275,6 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JCheckBox getJCheckBoxWhite() { if(jCheckBoxWhite == null) { jCheckBoxWhite = new JCheckBox(); - //AnchorLayout jCheckBoxWhiteLayout = new AnchorLayout(); jCheckBoxWhite.setLayout(null); jCheckBoxWhite.setText("White"); jCheckBoxWhite.setPreferredSize(new java.awt.Dimension(109, 13)); @@ -304,7 +296,6 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JCheckBox getJCheckBoxColorless() { if(jCheckBoxColorless == null) { jCheckBoxColorless = new JCheckBox(); - //AnchorLayout jCheckBoxColorlessLayout = new AnchorLayout(); jCheckBoxColorless.setLayout(null); jCheckBoxColorless.setText("Colorless"); jCheckBoxColorless.setPreferredSize(new java.awt.Dimension(80, 15)); @@ -326,7 +317,6 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JButton getJButtonOk() { if(jButtonOk == null) { jButtonOk = new JButton(); - //AnchorLayout jButtonOkLayout = new AnchorLayout(); jButtonOk.setLayout(null); jButtonOk.setText("OK"); jButtonOk.setPreferredSize(new java.awt.Dimension(100, 25)); @@ -338,7 +328,6 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JCheckBox getJCheckBoxBlack() { if(jCheckBoxBlack == null) { jCheckBoxBlack = new JCheckBox(); - //AnchorLayout jCheckBoxBlackLayout = new AnchorLayout(); jCheckBoxBlack.setLayout(null); jCheckBoxBlack.setText("Black"); jCheckBoxBlack.setPreferredSize(new java.awt.Dimension(97, 20)); @@ -360,9 +349,8 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JPanel getJPanel2() { if(jPanel2 == null) { jPanel2 = new JPanel(); - AnchorLayout jPanel2Layout = new AnchorLayout(); jPanel2.setPreferredSize(new java.awt.Dimension(121, 183)); - jPanel2.setLayout(jPanel2Layout); + jPanel2.setLayout(new AnchorLayout()); jPanel2.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); jPanel2.setBackground(new java.awt.Color(192, 192, 192)); jPanel2.add(getJSeparator2(), new AnchorConstraint(112, 987, 166, 20, AnchorConstraint.ANCHOR_REL, @@ -416,7 +404,6 @@ public class GUI_Quest_Filter extends javax.swing.JDialog { private JSeparator getJSeparator2() { if(jSeparator2 == null) { jSeparator2 = new JSeparator(); - //AnchorLayout jSeparator2Layout = new AnchorLayout(); jSeparator2.setPreferredSize(new java.awt.Dimension(116, 10)); jSeparator2.setLayout(null); } diff --git a/src/forge/GuiDisplay3.java b/src/forge/GuiDisplay3.java index 73f0844267e..dbd9c2719c9 100644 --- a/src/forge/GuiDisplay3.java +++ b/src/forge/GuiDisplay3.java @@ -58,7 +58,7 @@ import javax.swing.border.TitledBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import org.jdesktop.swingx.MultiSplitPane; +import org.jdesktop.swingx.JXMultiSplitPane; import org.jdesktop.swingx.MultiSplitLayout.Node; import forge.error.ErrorViewer; @@ -1006,7 +1006,7 @@ public class GuiDisplay3 extends JFrame implements CardContainer, Display, NewCo public static JCheckBoxMenuItem eotCheckboxForMenu = new JCheckBoxMenuItem("Stop at End of Turn", true); public static JCheckBoxMenuItem playsoundCheckboxForMenu = new JCheckBoxMenuItem("Play Sound", false); - MultiSplitPane pane = new MultiSplitPane(); + JXMultiSplitPane pane = new JXMultiSplitPane(); JButton cancelButton = new JButton(); JButton okButton = new JButton(); JTextArea messageArea = new JTextArea(1, 10); diff --git a/src/forge/Gui_DeckEditorNew.java b/src/forge/Gui_DeckEditorNew.java index cbe668b044c..00f888195e3 100755 --- a/src/forge/Gui_DeckEditorNew.java +++ b/src/forge/Gui_DeckEditorNew.java @@ -34,7 +34,7 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; -import org.jdesktop.swingx.MultiSplitPane; +import org.jdesktop.swingx.JXMultiSplitPane; import org.jdesktop.swingx.MultiSplitLayout.Node; import forge.error.ErrorViewer; @@ -110,7 +110,7 @@ public class Gui_DeckEditorNew extends JFrame implements CardContainer, NewConst private JCheckBox artifactCheckBox = new JCheckBox("Artifact", true); private JCheckBox enchantmentCheckBox = new JCheckBox("Enchant", true); - private MultiSplitPane pane; + private JXMultiSplitPane pane; private CardPoolModel topModel; private CardPoolModel bottomModel; @@ -160,7 +160,7 @@ public class Gui_DeckEditorNew extends JFrame implements CardContainer, NewConst //making the multi split pane Node model; File f = ForgeProps.getFile(LAYOUT); - pane = new MultiSplitPane(); + pane = new JXMultiSplitPane(); try { XMLDecoder decoder = new XMLDecoder(new BufferedInputStream(new FileInputStream(f))); model = (Node) decoder.readObject(); diff --git a/src/javazoom/jl/converter/Converter.java b/src/javazoom/jl/converter/Converter.java deleted file mode 100644 index 9ac6da20340..00000000000 --- a/src/javazoom/jl/converter/Converter.java +++ /dev/null @@ -1,411 +0,0 @@ -/* - * 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 Converter 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 ProgressListener and - * Decoder.Params 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 (; frameupdateID 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 Throwable instance that - * was thrown. - * - * @return true to continue processing, or false - * to abort conversion. - * - * If this method returns false, the exception - * is propagated to the caller of the convert() method. If - * true is returned, the exception is silently - * ignored and the converter moves onto the next frame. - */ - public boolean converterException(Throwable t); - - } - - - /** - * Implementation of ProgressListener that writes - * notification text to a PrintWriter. - */ - // 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; - } - - } - - -} \ No newline at end of file diff --git a/src/javazoom/jl/converter/RiffFile.java b/src/javazoom/jl/converter/RiffFile.java deleted file mode 100644 index 9e6341972a0..00000000000 --- a/src/javazoom/jl/converter/RiffFile.java +++ /dev/null @@ -1,497 +0,0 @@ -/* - * 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 -{ - static 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>> 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. - */ - @SuppressWarnings("unused") - 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. - */ - @SuppressWarnings("deprecation") - 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; - } - -} diff --git a/src/javazoom/jl/converter/WaveFile.java b/src/javazoom/jl/converter/WaveFile.java deleted file mode 100644 index d03039d76ad..00000000000 --- a/src/javazoom/jl/converter/WaveFile.java +++ /dev/null @@ -1,522 +0,0 @@ -/* - * 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; - - static 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); - } - } - - - static 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 static 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; - }*/ - -} \ No newline at end of file diff --git a/src/javazoom/jl/converter/WaveFileObuffer.java b/src/javazoom/jl/converter/WaveFileObuffer.java deleted file mode 100644 index c8b6ff7b3d8..00000000000 --- a/src/javazoom/jl/converter/WaveFileObuffer.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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(); - - @SuppressWarnings("unused") - 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) - { - - @SuppressWarnings("unused") - int k = 0; - @SuppressWarnings("unused") - int rc = 0; - - rc = outWave.WriteData(buffer, bufferp[0]); - // REVIEW: handle RiffFile errors. - /* - for (int j=0;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); - } - */ -} diff --git a/src/javazoom/jl/converter/jlc.java b/src/javazoom/jl/converter/jlc.java deleted file mode 100644 index 19f6a0455f2..00000000000 --- a/src/javazoom/jl/converter/jlc.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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 jlc 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; - @SuppressWarnings("unused") - long start = System.currentTimeMillis(); - int argc = args.length + 1; - argv = new String[argc]; - argv[0] = "jlc"; - for(int i=0;i2) - { - 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; - } - }; -}; \ No newline at end of file diff --git a/src/javazoom/jl/decoder/BitReserve.java b/src/javazoom/jl/decoder/BitReserve.java deleted file mode 100644 index 1ec54ba5a30..00000000000 --- a/src/javazoom/jl/decoder/BitReserve.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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. - *

- * 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. - *

- */ - -// 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; - } -} diff --git a/src/javazoom/jl/decoder/Bitstream.java b/src/javazoom/jl/decoder/Bitstream.java deleted file mode 100644 index 50828d3eb56..00000000000 --- a/src/javazoom/jl/decoder/Bitstream.java +++ /dev/null @@ -1,658 +0,0 @@ -/* - * 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 Bistream class is responsible for parsing - * an MPEG audio bitstream. - * - * REVIEW: 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 framebuffer 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); - @SuppressWarnings("unused") - int majorVersion = id3header[0]; - @SuppressWarnings("unused") - 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>> (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; - } -} diff --git a/src/javazoom/jl/decoder/BitstreamErrors.java b/src/javazoom/jl/decoder/BitstreamErrors.java deleted file mode 100644 index 26daeb9dffa..00000000000 --- a/src/javazoom/jl/decoder/BitstreamErrors.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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 BistreamExceptions. - * - * @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; - -} diff --git a/src/javazoom/jl/decoder/BitstreamException.java b/src/javazoom/jl/decoder/BitstreamException.java deleted file mode 100644 index dc24f7fb596..00000000000 --- a/src/javazoom/jl/decoder/BitstreamException.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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 BitstreamException are thrown - * when operations on a Bitstream fail. - *

- * The exception provides details of the exception condition - * in two ways: - *

  1. - * as an error-code describing the nature of the error - *


  2. - * as the Throwable instance, if any, that was thrown - * indicating that an exceptional condition has occurred. - *

- * - * @since 0.0.6 - * @author MDM 12/12/99 - */ - - @SuppressWarnings("serial") - 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); - } - - -} diff --git a/src/javazoom/jl/decoder/Control.java b/src/javazoom/jl/decoder/Control.java deleted file mode 100644 index 9d5660495a4..00000000000 --- a/src/javazoom/jl/decoder/Control.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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); - - -} diff --git a/src/javazoom/jl/decoder/Crc16.java b/src/javazoom/jl/decoder/Crc16.java deleted file mode 100644 index caad01cae68..00000000000 --- a/src/javazoom/jl/decoder/Crc16.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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; - } -} diff --git a/src/javazoom/jl/decoder/Decoder.java b/src/javazoom/jl/decoder/Decoder.java deleted file mode 100644 index 556a462241c..00000000000 --- a/src/javazoom/jl/decoder/Decoder.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * 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 Decoder 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 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. - */ - 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(); - @SuppressWarnings("unused") - 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 Params 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() - { - 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/src/javazoom/jl/decoder/DecoderErrors.java b/src/javazoom/jl/decoder/DecoderErrors.java deleted file mode 100644 index 686f2602213..00000000000 --- a/src/javazoom/jl/decoder/DecoderErrors.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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; - -} diff --git a/src/javazoom/jl/decoder/DecoderException.java b/src/javazoom/jl/decoder/DecoderException.java deleted file mode 100644 index c63bca89627..00000000000 --- a/src/javazoom/jl/decoder/DecoderException.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 DecoderException represents the class of - * errors that can occur when decoding MPEG audio. - * - * @author MDM - */ -public class DecoderException extends JavaLayerException - implements DecoderErrors -{ - private static final long serialVersionUID = 739129173366217466L; - 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); - } - - -} - diff --git a/src/javazoom/jl/decoder/Equalizer.java b/src/javazoom/jl/decoder/Equalizer.java deleted file mode 100644 index 439279e6100..00000000000 --- a/src/javazoom/jl/decoder/Equalizer.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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 Equalizer class can be used to specify - * equalization settings for the MPEG audio decoder. - *

- * 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 Equalizer 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=0) && (band=0) && (band 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>> 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. - */ - 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;} -} diff --git a/src/javazoom/jl/decoder/InputStreamSource.java b/src/javazoom/jl/decoder/InputStreamSource.java deleted file mode 100644 index fb6c0299304..00000000000 --- a/src/javazoom/jl/decoder/InputStreamSource.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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; - -/** - * Work In Progress. - * - * An instance of InputStreamSource implements a - * Source that provides data from an InputStream - * . 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; - } -} diff --git a/src/javazoom/jl/decoder/JavaLayerError.java b/src/javazoom/jl/decoder/JavaLayerError.java deleted file mode 100644 index 656e2843796..00000000000 --- a/src/javazoom/jl/decoder/JavaLayerError.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 -{ - private static final long serialVersionUID = -8924506540200863304L; -} diff --git a/src/javazoom/jl/decoder/JavaLayerErrors.java b/src/javazoom/jl/decoder/JavaLayerErrors.java deleted file mode 100644 index b141ce843d8..00000000000 --- a/src/javazoom/jl/decoder/JavaLayerErrors.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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; - -} diff --git a/src/javazoom/jl/decoder/JavaLayerException.java b/src/javazoom/jl/decoder/JavaLayerException.java deleted file mode 100644 index 902790cf449..00000000000 --- a/src/javazoom/jl/decoder/JavaLayerException.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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. - *

- * - * @author MDM - */ -public class JavaLayerException extends Exception -{ - private static final long serialVersionUID = 7212135786131434159L; - 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(); - } - } - - -} diff --git a/src/javazoom/jl/decoder/JavaLayerHook.java b/src/javazoom/jl/decoder/JavaLayerHook.java deleted file mode 100644 index edd890dd693..00000000000 --- a/src/javazoom/jl/decoder/JavaLayerHook.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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 JavaLayerHooks 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); -} diff --git a/src/javazoom/jl/decoder/JavaLayerUtils.java b/src/javazoom/jl/decoder/JavaLayerUtils.java deleted file mode 100644 index fc893dd0e16..00000000000 --- a/src/javazoom/jl/decoder/JavaLayerUtils.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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. - */ - @SuppressWarnings("unchecked") - 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 InputStream. - * The deserialization is delegated to an - * ObjectInputStream instance. - * - * @param in The InputStream 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 InputStream. - * - * @param in The InputStream 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. - */ - @SuppressWarnings("unchecked") - 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; - } - - @SuppressWarnings("unchecked") - 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. - */ - @SuppressWarnings("unchecked") - 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; - } -} diff --git a/src/javazoom/jl/decoder/LayerIDecoder.java b/src/javazoom/jl/decoder/LayerIDecoder.java deleted file mode 100644 index fb936d2b913..00000000000 --- a/src/javazoom/jl/decoder/LayerIDecoder.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * 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; - } - }; - -} diff --git a/src/javazoom/jl/decoder/LayerIIDecoder.java b/src/javazoom/jl/decoder/LayerIIDecoder.java deleted file mode 100644 index 7265b1f8faf..00000000000 --- a/src/javazoom/jl/decoder/LayerIIDecoder.java +++ /dev/null @@ -1,1064 +0,0 @@ -/* - * 11/19/04 1.0 moved to LGPL. - * - * 29/05/01 Michael Scheerer, Fixed some C++ to Java porting bugs. - * - * 16/07/01 Michael Scheerer, Catched a bug in method - * read_sampledata, which causes an outOfIndexException. - * - * 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 II frames. - */ -class LayerIIDecoder extends LayerIDecoder implements FrameDecoder -{ - - public LayerIIDecoder() - { - } - - - protected void createSubbands() - { - int i; - if (mode == Header.SINGLE_CHANNEL) - for (i = 0; i < num_subbands; ++i) - subbands[i] = new SubbandLayer2(i); - else if (mode == Header.JOINT_STEREO) - { - for (i = 0; i < header.intensity_stereo_bound(); ++i) - subbands[i] = new SubbandLayer2Stereo(i); - for (; i < num_subbands; ++i) - subbands[i] = new SubbandLayer2IntensityStereo(i); - } - else - { - for (i = 0; i < num_subbands; ++i) - subbands[i] = new SubbandLayer2Stereo(i); - } - - } - - protected void readScaleFactorSelection() - { - for (int i = 0; i < num_subbands; ++i) - ((SubbandLayer2)subbands[i]).read_scalefactor_selection(stream, crc); - } - - - - /** - * Class for layer II subbands in single channel mode. - */ - static class SubbandLayer2 extends Subband - { - // this table contains 3 requantized samples for each legal codeword - // when grouped in 5 bits, i.e. 3 quantizationsteps per sample - public static final float grouping_5bits[] = new float[] - { - -2.0f/3.0f, -2.0f/3.0f, -2.0f/3.0f, - 0.0f, -2.0f/3.0f, -2.0f/3.0f, - 2.0f/3.0f, -2.0f/3.0f, -2.0f/3.0f, - -2.0f/3.0f, 0.0f, -2.0f/3.0f, - 0.0f, 0.0f, -2.0f/3.0f, - 2.0f/3.0f, 0.0f, -2.0f/3.0f, - -2.0f/3.0f, 2.0f/3.0f, -2.0f/3.0f, - 0.0f, 2.0f/3.0f, -2.0f/3.0f, - 2.0f/3.0f, 2.0f/3.0f, -2.0f/3.0f, - -2.0f/3.0f, -2.0f/3.0f, 0.0f, - 0.0f, -2.0f/3.0f, 0.0f, - 2.0f/3.0f, -2.0f/3.0f, 0.0f, - -2.0f/3.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, - 2.0f/3.0f, 0.0f, 0.0f, - -2.0f/3.0f, 2.0f/3.0f, 0.0f, - 0.0f, 2.0f/3.0f, 0.0f, - 2.0f/3.0f, 2.0f/3.0f, 0.0f, - -2.0f/3.0f, -2.0f/3.0f, 2.0f/3.0f, - 0.0f, -2.0f/3.0f, 2.0f/3.0f, - 2.0f/3.0f, -2.0f/3.0f, 2.0f/3.0f, - -2.0f/3.0f, 0.0f, 2.0f/3.0f, - 0.0f, 0.0f, 2.0f/3.0f, - 2.0f/3.0f, 0.0f, 2.0f/3.0f, - -2.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f, - 0.0f, 2.0f/3.0f, 2.0f/3.0f, - 2.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f - }; - - // this table contains 3 requantized samples for each legal codeword - // when grouped in 7 bits, i.e. 5 quantizationsteps per sample - public static final float grouping_7bits[] = new float[] - { - -0.8f, -0.8f, -0.8f, -0.4f, -0.8f, -0.8f, 0.0f, -0.8f, -0.8f, 0.4f, -0.8f, -0.8f, 0.8f, -0.8f, -0.8f, - -0.8f, -0.4f, -0.8f, -0.4f, -0.4f, -0.8f, 0.0f, -0.4f, -0.8f, 0.4f, -0.4f, -0.8f, 0.8f, -0.4f, -0.8f, - -0.8f, 0.0f, -0.8f, -0.4f, 0.0f, -0.8f, 0.0f, 0.0f, -0.8f, 0.4f, 0.0f, -0.8f, 0.8f, 0.0f, -0.8f, - -0.8f, 0.4f, -0.8f, -0.4f, 0.4f, -0.8f, 0.0f, 0.4f, -0.8f, 0.4f, 0.4f, -0.8f, 0.8f, 0.4f, -0.8f, - -0.8f, 0.8f, -0.8f, -0.4f, 0.8f, -0.8f, 0.0f, 0.8f, -0.8f, 0.4f, 0.8f, -0.8f, 0.8f, 0.8f, -0.8f, - -0.8f, -0.8f, -0.4f, -0.4f, -0.8f, -0.4f, 0.0f, -0.8f, -0.4f, 0.4f, -0.8f, -0.4f, 0.8f, -0.8f, -0.4f, - -0.8f, -0.4f, -0.4f, -0.4f, -0.4f, -0.4f, 0.0f, -0.4f, -0.4f, 0.4f, -0.4f, -0.4f, 0.8f, -0.4f, -0.4f, - -0.8f, 0.0f, -0.4f, -0.4f, 0.0f, -0.4f, 0.0f, 0.0f, -0.4f, 0.4f, 0.0f, -0.4f, 0.8f, 0.0f, -0.4f, - -0.8f, 0.4f, -0.4f, -0.4f, 0.4f, -0.4f, 0.0f, 0.4f, -0.4f, 0.4f, 0.4f, -0.4f, 0.8f, 0.4f, -0.4f, - -0.8f, 0.8f, -0.4f, -0.4f, 0.8f, -0.4f, 0.0f, 0.8f, -0.4f, 0.4f, 0.8f, -0.4f, 0.8f, 0.8f, -0.4f, - -0.8f, -0.8f, 0.0f, -0.4f, -0.8f, 0.0f, 0.0f, -0.8f, 0.0f, 0.4f, -0.8f, 0.0f, 0.8f, -0.8f, 0.0f, - -0.8f, -0.4f, 0.0f, -0.4f, -0.4f, 0.0f, 0.0f, -0.4f, 0.0f, 0.4f, -0.4f, 0.0f, 0.8f, -0.4f, 0.0f, - -0.8f, 0.0f, 0.0f, -0.4f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.0f, 0.0f, 0.8f, 0.0f, 0.0f, - -0.8f, 0.4f, 0.0f, -0.4f, 0.4f, 0.0f, 0.0f, 0.4f, 0.0f, 0.4f, 0.4f, 0.0f, 0.8f, 0.4f, 0.0f, - -0.8f, 0.8f, 0.0f, -0.4f, 0.8f, 0.0f, 0.0f, 0.8f, 0.0f, 0.4f, 0.8f, 0.0f, 0.8f, 0.8f, 0.0f, - -0.8f, -0.8f, 0.4f, -0.4f, -0.8f, 0.4f, 0.0f, -0.8f, 0.4f, 0.4f, -0.8f, 0.4f, 0.8f, -0.8f, 0.4f, - -0.8f, -0.4f, 0.4f, -0.4f, -0.4f, 0.4f, 0.0f, -0.4f, 0.4f, 0.4f, -0.4f, 0.4f, 0.8f, -0.4f, 0.4f, - -0.8f, 0.0f, 0.4f, -0.4f, 0.0f, 0.4f, 0.0f, 0.0f, 0.4f, 0.4f, 0.0f, 0.4f, 0.8f, 0.0f, 0.4f, - -0.8f, 0.4f, 0.4f, -0.4f, 0.4f, 0.4f, 0.0f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f, 0.8f, 0.4f, 0.4f, - -0.8f, 0.8f, 0.4f, -0.4f, 0.8f, 0.4f, 0.0f, 0.8f, 0.4f, 0.4f, 0.8f, 0.4f, 0.8f, 0.8f, 0.4f, - -0.8f, -0.8f, 0.8f, -0.4f, -0.8f, 0.8f, 0.0f, -0.8f, 0.8f, 0.4f, -0.8f, 0.8f, 0.8f, -0.8f, 0.8f, - -0.8f, -0.4f, 0.8f, -0.4f, -0.4f, 0.8f, 0.0f, -0.4f, 0.8f, 0.4f, -0.4f, 0.8f, 0.8f, -0.4f, 0.8f, - -0.8f, 0.0f, 0.8f, -0.4f, 0.0f, 0.8f, 0.0f, 0.0f, 0.8f, 0.4f, 0.0f, 0.8f, 0.8f, 0.0f, 0.8f, - -0.8f, 0.4f, 0.8f, -0.4f, 0.4f, 0.8f, 0.0f, 0.4f, 0.8f, 0.4f, 0.4f, 0.8f, 0.8f, 0.4f, 0.8f, - -0.8f, 0.8f, 0.8f, -0.4f, 0.8f, 0.8f, 0.0f, 0.8f, 0.8f, 0.4f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f - }; - - // this table contains 3 requantized samples for each legal codeword - // when grouped in 10 bits, i.e. 9 quantizationsteps per sample - public static final float grouping_10bits[] = - { - -8.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, - -2.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, 0.0f, -8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, - 4.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, - -8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, - -2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 0.0f, -6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, - 4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, - -8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, - -2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 0.0f, -4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, - 4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, - -8.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, - -2.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, 0.0f, -2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, - 4.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, - -8.0f/9.0f, 0.0f, -8.0f/9.0f, -6.0f/9.0f, 0.0f, -8.0f/9.0f, -4.0f/9.0f, 0.0f, -8.0f/9.0f, - -2.0f/9.0f, 0.0f, -8.0f/9.0f, 0.0f, 0.0f, -8.0f/9.0f, 2.0f/9.0f, 0.0f, -8.0f/9.0f, - 4.0f/9.0f, 0.0f, -8.0f/9.0f, 6.0f/9.0f, 0.0f, -8.0f/9.0f, 8.0f/9.0f, 0.0f, -8.0f/9.0f, - -8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, - -2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 0.0f, 2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, - 4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, - -8.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, - -2.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, 0.0f, 4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, - 4.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, - -8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, - -2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 0.0f, 6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, - 4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, - -8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, - -2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 0.0f, 8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, - 4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, - -8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, - -2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 0.0f, -8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, - 4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, - -8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, - -2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 0.0f, -6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, - 4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, - -8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, - -2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 0.0f, -4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, - 4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, - -8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, - -2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 0.0f, -2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, - 4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, - -8.0f/9.0f, 0.0f, -6.0f/9.0f, -6.0f/9.0f, 0.0f, -6.0f/9.0f, -4.0f/9.0f, 0.0f, -6.0f/9.0f, - -2.0f/9.0f, 0.0f, -6.0f/9.0f, 0.0f, 0.0f, -6.0f/9.0f, 2.0f/9.0f, 0.0f, -6.0f/9.0f, - 4.0f/9.0f, 0.0f, -6.0f/9.0f, 6.0f/9.0f, 0.0f, -6.0f/9.0f, 8.0f/9.0f, 0.0f, -6.0f/9.0f, - -8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, - -2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 0.0f, 2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, - 4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, - -8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, - -2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 0.0f, 4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, - 4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, - -8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, - -2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 0.0f, 6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, - 4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, - -8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, - -2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 0.0f, 8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, - 4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, - -8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, - -2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 0.0f, -8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, - 4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, - -8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, - -2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 0.0f, -6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, - 4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, - -8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, - -2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 0.0f, -4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, - 4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, - -8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, - -2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 0.0f, -2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, - 4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, - -8.0f/9.0f, 0.0f, -4.0f/9.0f, -6.0f/9.0f, 0.0f, -4.0f/9.0f, -4.0f/9.0f, 0.0f, -4.0f/9.0f, - -2.0f/9.0f, 0.0f, -4.0f/9.0f, 0.0f, 0.0f, -4.0f/9.0f, 2.0f/9.0f, 0.0f, -4.0f/9.0f, - 4.0f/9.0f, 0.0f, -4.0f/9.0f, 6.0f/9.0f, 0.0f, -4.0f/9.0f, 8.0f/9.0f, 0.0f, -4.0f/9.0f, - -8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, - -2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 0.0f, 2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, - 4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, - -8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, - -2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 0.0f, 4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, - 4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, - -8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, - -2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 0.0f, 6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, - 4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, - -8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, - -2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 0.0f, 8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, - 4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, - -8.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, - -2.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, 0.0f, -8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, - 4.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, - -8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, - -2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 0.0f, -6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, - 4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, - -8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, - -2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 0.0f, -4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, - 4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, - -8.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, - -2.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, 0.0f, -2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, - 4.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, - -8.0f/9.0f, 0.0f, -2.0f/9.0f, -6.0f/9.0f, 0.0f, -2.0f/9.0f, -4.0f/9.0f, 0.0f, -2.0f/9.0f, - -2.0f/9.0f, 0.0f, -2.0f/9.0f, 0.0f, 0.0f, -2.0f/9.0f, 2.0f/9.0f, 0.0f, -2.0f/9.0f, - 4.0f/9.0f, 0.0f, -2.0f/9.0f, 6.0f/9.0f, 0.0f, -2.0f/9.0f, 8.0f/9.0f, 0.0f, -2.0f/9.0f, - -8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, - -2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 0.0f, 2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, - 4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, - -8.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, - -2.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, 0.0f, 4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, - 4.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, - -8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, - -2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 0.0f, 6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, - 4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, - -8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, - -2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 0.0f, 8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, - 4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, - -8.0f/9.0f, -8.0f/9.0f, 0.0f, -6.0f/9.0f, -8.0f/9.0f, 0.0f, -4.0f/9.0f, -8.0f/9.0f, 0.0f, - -2.0f/9.0f, -8.0f/9.0f, 0.0f, 0.0f, -8.0f/9.0f, 0.0f, 2.0f/9.0f, -8.0f/9.0f, 0.0f, - 4.0f/9.0f, -8.0f/9.0f, 0.0f, 6.0f/9.0f, -8.0f/9.0f, 0.0f, 8.0f/9.0f, -8.0f/9.0f, 0.0f, - -8.0f/9.0f, -6.0f/9.0f, 0.0f, -6.0f/9.0f, -6.0f/9.0f, 0.0f, -4.0f/9.0f, -6.0f/9.0f, 0.0f, - -2.0f/9.0f, -6.0f/9.0f, 0.0f, 0.0f, -6.0f/9.0f, 0.0f, 2.0f/9.0f, -6.0f/9.0f, 0.0f, - 4.0f/9.0f, -6.0f/9.0f, 0.0f, 6.0f/9.0f, -6.0f/9.0f, 0.0f, 8.0f/9.0f, -6.0f/9.0f, 0.0f, - -8.0f/9.0f, -4.0f/9.0f, 0.0f, -6.0f/9.0f, -4.0f/9.0f, 0.0f, -4.0f/9.0f, -4.0f/9.0f, 0.0f, - -2.0f/9.0f, -4.0f/9.0f, 0.0f, 0.0f, -4.0f/9.0f, 0.0f, 2.0f/9.0f, -4.0f/9.0f, 0.0f, - 4.0f/9.0f, -4.0f/9.0f, 0.0f, 6.0f/9.0f, -4.0f/9.0f, 0.0f, 8.0f/9.0f, -4.0f/9.0f, 0.0f, - -8.0f/9.0f, -2.0f/9.0f, 0.0f, -6.0f/9.0f, -2.0f/9.0f, 0.0f, -4.0f/9.0f, -2.0f/9.0f, 0.0f, - -2.0f/9.0f, -2.0f/9.0f, 0.0f, 0.0f, -2.0f/9.0f, 0.0f, 2.0f/9.0f, -2.0f/9.0f, 0.0f, - 4.0f/9.0f, -2.0f/9.0f, 0.0f, 6.0f/9.0f, -2.0f/9.0f, 0.0f, 8.0f/9.0f, -2.0f/9.0f, 0.0f, - -8.0f/9.0f, 0.0f, 0.0f, -6.0f/9.0f, 0.0f, 0.0f, -4.0f/9.0f, 0.0f, 0.0f, - -2.0f/9.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f/9.0f, 0.0f, 0.0f, - 4.0f/9.0f, 0.0f, 0.0f, 6.0f/9.0f, 0.0f, 0.0f, 8.0f/9.0f, 0.0f, 0.0f, - -8.0f/9.0f, 2.0f/9.0f, 0.0f, -6.0f/9.0f, 2.0f/9.0f, 0.0f, -4.0f/9.0f, 2.0f/9.0f, 0.0f, - -2.0f/9.0f, 2.0f/9.0f, 0.0f, 0.0f, 2.0f/9.0f, 0.0f, 2.0f/9.0f, 2.0f/9.0f, 0.0f, - 4.0f/9.0f, 2.0f/9.0f, 0.0f, 6.0f/9.0f, 2.0f/9.0f, 0.0f, 8.0f/9.0f, 2.0f/9.0f, 0.0f, - -8.0f/9.0f, 4.0f/9.0f, 0.0f, -6.0f/9.0f, 4.0f/9.0f, 0.0f, -4.0f/9.0f, 4.0f/9.0f, 0.0f, - -2.0f/9.0f, 4.0f/9.0f, 0.0f, 0.0f, 4.0f/9.0f, 0.0f, 2.0f/9.0f, 4.0f/9.0f, 0.0f, - 4.0f/9.0f, 4.0f/9.0f, 0.0f, 6.0f/9.0f, 4.0f/9.0f, 0.0f, 8.0f/9.0f, 4.0f/9.0f, 0.0f, - -8.0f/9.0f, 6.0f/9.0f, 0.0f, -6.0f/9.0f, 6.0f/9.0f, 0.0f, -4.0f/9.0f, 6.0f/9.0f, 0.0f, - -2.0f/9.0f, 6.0f/9.0f, 0.0f, 0.0f, 6.0f/9.0f, 0.0f, 2.0f/9.0f, 6.0f/9.0f, 0.0f, - 4.0f/9.0f, 6.0f/9.0f, 0.0f, 6.0f/9.0f, 6.0f/9.0f, 0.0f, 8.0f/9.0f, 6.0f/9.0f, 0.0f, - -8.0f/9.0f, 8.0f/9.0f, 0.0f, -6.0f/9.0f, 8.0f/9.0f, 0.0f, -4.0f/9.0f, 8.0f/9.0f, 0.0f, - -2.0f/9.0f, 8.0f/9.0f, 0.0f, 0.0f, 8.0f/9.0f, 0.0f, 2.0f/9.0f, 8.0f/9.0f, 0.0f, - 4.0f/9.0f, 8.0f/9.0f, 0.0f, 6.0f/9.0f, 8.0f/9.0f, 0.0f, 8.0f/9.0f, 8.0f/9.0f, 0.0f, - -8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, - -2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 0.0f, -8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, - 4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, - -8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, - -2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 0.0f, -6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, - 4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, - -8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, - -2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 0.0f, -4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, - 4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, - -8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, - -2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 0.0f, -2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, - 4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, - -8.0f/9.0f, 0.0f, 2.0f/9.0f, -6.0f/9.0f, 0.0f, 2.0f/9.0f, -4.0f/9.0f, 0.0f, 2.0f/9.0f, - -2.0f/9.0f, 0.0f, 2.0f/9.0f, 0.0f, 0.0f, 2.0f/9.0f, 2.0f/9.0f, 0.0f, 2.0f/9.0f, - 4.0f/9.0f, 0.0f, 2.0f/9.0f, 6.0f/9.0f, 0.0f, 2.0f/9.0f, 8.0f/9.0f, 0.0f, 2.0f/9.0f, - -8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, - -2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 0.0f, 2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, - 4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, - -8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, - -2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 0.0f, 4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, - 4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, - -8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, - -2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 0.0f, 6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, - 4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, - -8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, - -2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 0.0f, 8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, - 4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, - -8.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, - -2.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, 0.0f, -8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, - 4.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, - -8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, - -2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 0.0f, -6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, - 4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, - -8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, - -2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 0.0f, -4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, - 4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, - -8.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, - -2.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, 0.0f, -2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, - 4.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, - -8.0f/9.0f, 0.0f, 4.0f/9.0f, -6.0f/9.0f, 0.0f, 4.0f/9.0f, -4.0f/9.0f, 0.0f, 4.0f/9.0f, - -2.0f/9.0f, 0.0f, 4.0f/9.0f, 0.0f, 0.0f, 4.0f/9.0f, 2.0f/9.0f, 0.0f, 4.0f/9.0f, - 4.0f/9.0f, 0.0f, 4.0f/9.0f, 6.0f/9.0f, 0.0f, 4.0f/9.0f, 8.0f/9.0f, 0.0f, 4.0f/9.0f, - -8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, - -2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 0.0f, 2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, - 4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, - -8.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, - -2.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, 0.0f, 4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, - 4.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, - -8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, - -2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 0.0f, 6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, - 4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, - -8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, - -2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 0.0f, 8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, - 4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, - -8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, - -2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 0.0f, -8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, - 4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, - -8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, - -2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 0.0f, -6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, - 4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, - -8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, - -2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 0.0f, -4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, - 4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, - -8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, - -2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 0.0f, -2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, - 4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, - -8.0f/9.0f, 0.0f, 6.0f/9.0f, -6.0f/9.0f, 0.0f, 6.0f/9.0f, -4.0f/9.0f, 0.0f, 6.0f/9.0f, - -2.0f/9.0f, 0.0f, 6.0f/9.0f, 0.0f, 0.0f, 6.0f/9.0f, 2.0f/9.0f, 0.0f, 6.0f/9.0f, - 4.0f/9.0f, 0.0f, 6.0f/9.0f, 6.0f/9.0f, 0.0f, 6.0f/9.0f, 8.0f/9.0f, 0.0f, 6.0f/9.0f, - -8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, - -2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 0.0f, 2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, - 4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, - -8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, - -2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 0.0f, 4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, - 4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, - -8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, - -2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 0.0f, 6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, - 4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, - -8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, - -2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 0.0f, 8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, - 4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, - -8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, - -2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 0.0f, -8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, - 4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, - -8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, - -2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 0.0f, -6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, - 4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, - -8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, - -2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 0.0f, -4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, - 4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, - -8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, - -2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 0.0f, -2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, - 4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, - -8.0f/9.0f, 0.0f, 8.0f/9.0f, -6.0f/9.0f, 0.0f, 8.0f/9.0f, -4.0f/9.0f, 0.0f, 8.0f/9.0f, - -2.0f/9.0f, 0.0f, 8.0f/9.0f, 0.0f, 0.0f, 8.0f/9.0f, 2.0f/9.0f, 0.0f, 8.0f/9.0f, - 4.0f/9.0f, 0.0f, 8.0f/9.0f, 6.0f/9.0f, 0.0f, 8.0f/9.0f, 8.0f/9.0f, 0.0f, 8.0f/9.0f, - -8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, - -2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 0.0f, 2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, - 4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, - -8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, - -2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 0.0f, 4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, - 4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, - -8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, - -2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 0.0f, 6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, - 4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, - -8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, - -2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 0.0f, 8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, - 4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f - }; - - // data taken from ISO/IEC DIS 11172, Annexes 3-B.2[abcd] and 3-B.4: - - // subbands 0-2 in tables 3-B.2a and 2b: (index is allocation) - public static final int table_ab1_codelength[] = - // bits per codeword - { 0, 5, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; - - public static final float table_ab1_groupingtables[][] = - // pointer to sample grouping table, or NULL-pointer if ungrouped - { null, grouping_5bits, null, null, null, null, null, null, null, null, null, null, null, null, null, null }; - - public static final float table_ab1_factor[] = - // factor for requantization: (real)sample * factor - 1.0 gives requantized sample - { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/16.0f, 1.0f/32.0f, 1.0f/64.0f, - 1.0f/128.0f, 1.0f/256.0f, 1.0f/512.0f, 1.0f/1024.0f, 1.0f/2048.0f, - 1.0f/4096.0f, 1.0f/8192.0f, 1.0f/16384.0f, 1.0f/32768.0f }; - - public static final float table_ab1_c[] = - // factor c for requantization from table 3-B.4 - { 0.0f, 1.33333333333f, 1.14285714286f, 1.06666666666f, 1.03225806452f, - 1.01587301587f, 1.00787401575f, 1.00392156863f, 1.00195694716f, 1.00097751711f, - 1.00048851979f, 1.00024420024f, 1.00012208522f, 1.00006103888f, 1.00003051851f, - 1.00001525902f }; - - public static final float table_ab1_d[] = - // addend d for requantization from table 3-B.4 - { 0.0f, 0.50000000000f, 0.25000000000f, 0.12500000000f, 0.06250000000f, - 0.03125000000f, 0.01562500000f, 0.00781250000f, 0.00390625000f, 0.00195312500f, - 0.00097656250f, 0.00048828125f, 0.00024414063f, 0.00012207031f, 0.00006103516f, - 0.00003051758f }; - - // subbands 3-... tables 3-B.2a and 2b: - public static final float[] table_ab234_groupingtables[] = - { null, grouping_5bits, grouping_7bits, null, grouping_10bits, null, null, null, null, null, null, null, null, null, null, null }; - - // subbands 3-10 in tables 3-B.2a and 2b: - public static final int table_ab2_codelength[] = - { 0, 5, 7, 3, 10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 }; - public static final float table_ab2_factor[] = - { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/8.0f, 1.0f/16.0f, - 1.0f/32.0f, 1.0f/64.0f, 1.0f/128.0f, 1.0f/256.0f, 1.0f/512.0f, - 1.0f/1024.0f, 1.0f/2048.0f, 1.0f/4096.0f, 1.0f/32768.0f }; - public static final float table_ab2_c[] = - { 0.0f, 1.33333333333f, 1.60000000000f, 1.14285714286f, 1.77777777777f, - 1.06666666666f, 1.03225806452f, 1.01587301587f, 1.00787401575f, 1.00392156863f, - 1.00195694716f, 1.00097751711f, 1.00048851979f, 1.00024420024f, 1.00012208522f, - 1.00001525902f }; - public static final float table_ab2_d[] = - { 0.0f, 0.50000000000f, 0.50000000000f, 0.25000000000f, 0.50000000000f, - 0.12500000000f, 0.06250000000f, 0.03125000000f, 0.01562500000f, 0.00781250000f, - 0.00390625000f, 0.00195312500f, 0.00097656250f, 0.00048828125f, 0.00024414063f, - 0.00003051758f }; - - // subbands 11-22 in tables 3-B.2a and 2b: - public static final int table_ab3_codelength[] = { 0, 5, 7, 3, 10, 4, 5, 16 }; - public static final float table_ab3_factor[] = - { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/8.0f, 1.0f/16.0f, 1.0f/32768.0f }; - public static final float table_ab3_c[] = - { 0.0f, 1.33333333333f, 1.60000000000f, 1.14285714286f, 1.77777777777f, - 1.06666666666f, 1.03225806452f, 1.00001525902f }; - public static final float table_ab3_d[] = - { 0.0f, 0.50000000000f, 0.50000000000f, 0.25000000000f, 0.50000000000f, - 0.12500000000f, 0.06250000000f, 0.00003051758f }; - - // subbands 23-... in tables 3-B.2a and 2b: - public static final int table_ab4_codelength[] = { 0, 5, 7, 16 }; - public static final float table_ab4_factor[] = { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/32768.0f }; - public static final float table_ab4_c[] = { 0.0f, 1.33333333333f, 1.60000000000f, 1.00001525902f }; - public static final float table_ab4_d[] = { 0.0f, 0.50000000000f, 0.50000000000f, 0.00003051758f }; - - // subbands in tables 3-B.2c and 2d: - public static final int table_cd_codelength[] = - { 0, 5, 7, 10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - public static final float table_cd_groupingtables[][] = - { null, grouping_5bits, grouping_7bits, grouping_10bits, null, null, null, null, null, null, null, null, null, null, null, null }; - public static final float table_cd_factor[] = - { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/8.0f, 1.0f/16.0f, 1.0f/32.0f, 1.0f/64.0f, - 1.0f/128.0f, 1.0f/256.0f, 1.0f/512.0f, 1.0f/1024.0f, 1.0f/2048.0f, 1.0f/4096.0f, - 1.0f/8192.0f, 1.0f/16384.0f }; - public static final float table_cd_c[] = - { 0.0f, 1.33333333333f, 1.60000000000f, 1.77777777777f, 1.06666666666f, - 1.03225806452f, 1.01587301587f, 1.00787401575f, 1.00392156863f, 1.00195694716f, - 1.00097751711f, 1.00048851979f, 1.00024420024f, 1.00012208522f, 1.00006103888f, - 1.00003051851f }; - public static final float table_cd_d[] = - { 0.0f, 0.50000000000f, 0.50000000000f, 0.50000000000f, 0.12500000000f, - 0.06250000000f, 0.03125000000f, 0.01562500000f, 0.00781250000f, 0.00390625000f, - 0.00195312500f, 0.00097656250f, 0.00048828125f, 0.00024414063f, 0.00012207031f, - 0.00006103516f }; - - - - protected int subbandnumber; - protected int allocation; - protected int scfsi; - protected float scalefactor1, scalefactor2, scalefactor3; - protected int[] codelength = {0}; - protected float groupingtable[][] = new float[2][]; - //protected float[][] groupingtable = {{0},{0}} ; - protected float[] factor = {0.0f}; - protected int groupnumber; - protected int samplenumber; - protected float[] samples = new float[3]; - protected float[] c = {0}; - protected float[] d = {0}; - /** - * Constructor - */ - public SubbandLayer2(int subbandnumber) - { - this.subbandnumber = subbandnumber; - groupnumber = samplenumber = 0; - } - - - /** - * - */ - protected int get_allocationlength (Header header) - { - if (header.version() == Header.MPEG1) - { - int channel_bitrate = header.bitrate_index(); - - // calculate bitrate per channel: - if (header.mode() != Header.SINGLE_CHANNEL) - if (channel_bitrate == 4) - channel_bitrate = 1; - else - channel_bitrate -= 4; - - if (channel_bitrate == 1 || channel_bitrate == 2) - // table 3-B.2c or 3-B.2d - if (subbandnumber <= 1) - return 4; - else - return 3; - else - // tables 3-B.2a or 3-B.2b - if (subbandnumber <= 10) - return 4; - else if (subbandnumber <= 22) - return 3; - else - return 2; - } - else - { // MPEG-2 LSF -- Jeff - - // table B.1 of ISO/IEC 13818-3 - if (subbandnumber <= 3) - return 4; - else if (subbandnumber <= 10) - return 3; - else - return 2; - } - } - - /** - * - */ - protected void prepare_sample_reading(Header header, int allocation, - //float[][] groupingtable, - int channel, - float[] factor, int[] codelength, - float[] c, float[] d) - { - int channel_bitrate = header.bitrate_index(); - // calculate bitrate per channel: - if (header.mode() != Header.SINGLE_CHANNEL) - if (channel_bitrate == 4) - channel_bitrate = 1; - else - channel_bitrate -= 4; - - if (channel_bitrate == 1 || channel_bitrate == 2) - { - // table 3-B.2c or 3-B.2d - groupingtable[channel] = table_cd_groupingtables[allocation]; - factor[0] = table_cd_factor[allocation]; - codelength[0] = table_cd_codelength[allocation]; - c[0] = table_cd_c[allocation]; - d[0] = table_cd_d[allocation]; - } - else - { - // tables 3-B.2a or 3-B.2b - if (subbandnumber <= 2) - { - groupingtable[channel] = table_ab1_groupingtables[allocation]; - factor[0] = table_ab1_factor[allocation]; - codelength[0] = table_ab1_codelength[allocation]; - c[0] = table_ab1_c[allocation]; - d[0] = table_ab1_d[allocation]; - } - else - { - groupingtable[channel] = table_ab234_groupingtables[allocation]; - if (subbandnumber <= 10) - { - factor[0] = table_ab2_factor[allocation]; - codelength[0] = table_ab2_codelength[allocation]; - c[0] = table_ab2_c[allocation]; - d[0] = table_ab2_d[allocation]; - } - else if (subbandnumber <= 22) - { - factor[0] = table_ab3_factor[allocation]; - codelength[0] = table_ab3_codelength[allocation]; - c[0] = table_ab3_c[allocation]; - d[0] = table_ab3_d[allocation]; - } - else - { - factor[0] = table_ab4_factor[allocation]; - codelength[0] = table_ab4_codelength[allocation]; - c[0] = table_ab4_c[allocation]; - d[0] = table_ab4_d[allocation]; - } - } - } - } - - - /** - * - */ - public void read_allocation(Bitstream stream, Header header, Crc16 crc) - { - int length = get_allocationlength(header); - allocation = stream.get_bits(length); - if (crc != null) - crc.add_bits(allocation, length); - } - - /** - * - */ - public void read_scalefactor_selection (Bitstream stream, Crc16 crc) - { - if (allocation != 0) - { - scfsi = stream.get_bits(2); - if (crc != null) crc.add_bits(scfsi, 2); - } - } - - /** - * - */ - public void read_scalefactor (Bitstream stream, Header header) - { - if (allocation != 0) - { - switch (scfsi) - { - case 0: - scalefactor1 = scalefactors[stream.get_bits(6)]; - scalefactor2 = scalefactors[stream.get_bits(6)]; - scalefactor3 = scalefactors[stream.get_bits(6)]; - break; - case 1: - scalefactor1 = scalefactor2 = scalefactors[stream.get_bits(6)]; - scalefactor3 = scalefactors[stream.get_bits(6)]; - break; - case 2: - scalefactor1 = scalefactor2 = scalefactor3 = scalefactors[stream.get_bits(6)]; - break; - case 3: - scalefactor1 = scalefactors[stream.get_bits(6)]; - scalefactor2 = scalefactor3 = scalefactors[stream.get_bits(6)]; - break; - } - prepare_sample_reading(header, allocation, 0, - factor, codelength, c, d); - } - } - - /** - * - */ - public boolean read_sampledata (Bitstream stream) - { - if (allocation != 0) - if (groupingtable[0] != null) - { - int samplecode = stream.get_bits(codelength[0]); - // create requantized samples: - samplecode += samplecode << 1; - float[] target = samples; - float[] source = groupingtable[0]; - /* - int tmp = 0; - int temp = 0; - target[tmp++] = source[samplecode + temp]; - temp++; - target[tmp++] = source[samplecode + temp]; - temp++; - target[tmp] = source[samplecode + temp]; - */ - //Bugfix: - int tmp = 0; - int temp = samplecode; - - if(temp > source.length - 3) temp = source.length - 3; - - target[tmp] = source[temp]; - temp++;tmp++; - target[tmp] = source[temp]; - temp++;tmp++; - target[tmp] = source[temp]; - - // memcpy (samples, groupingtable + samplecode, 3 * sizeof (real)); - } - else - { - samples[0] = (float) ((stream.get_bits(codelength[0])) * factor[0] - 1.0); - samples[1] = (float) ((stream.get_bits(codelength[0])) * factor[0] - 1.0); - samples[2] = (float) ((stream.get_bits(codelength[0])) * factor[0] - 1.0); - } - - samplenumber = 0; - if (++groupnumber == 12) - return true; - else - return false; - } - - /** - * - */ - public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) - { - if ((allocation != 0) && (channels != OutputChannels.RIGHT_CHANNEL)) - { - float sample = samples[samplenumber]; - - if (groupingtable[0] == null) - sample = (sample + d[0]) * c[0]; - if (groupnumber <= 4) - sample *= scalefactor1; - else if (groupnumber <= 8) - sample *= scalefactor2; - else - sample *= scalefactor3; - filter1.input_sample(sample, subbandnumber); - } - - if (++samplenumber == 3) - return true; - else - return false; - } - }; - - /** - * Class for layer II subbands in joint stereo mode. - */ - static class SubbandLayer2IntensityStereo extends SubbandLayer2 - { - protected int channel2_scfsi; - protected float channel2_scalefactor1, channel2_scalefactor2, channel2_scalefactor3; - - /** - * Constructor - */ - public SubbandLayer2IntensityStereo (int subbandnumber) - { - super(subbandnumber); - } - - /** - * - */ - public void read_allocation(Bitstream stream, Header header, Crc16 crc) - { - super.read_allocation (stream, header, crc); - } - - /** - * - */ - public void read_scalefactor_selection(Bitstream stream, Crc16 crc) - { - if (allocation != 0) - { - scfsi = stream.get_bits(2); - channel2_scfsi = stream.get_bits(2); - if (crc != null) - { - crc.add_bits(scfsi, 2); - crc.add_bits(channel2_scfsi, 2); - } - } - } - - /** - * - */ - public void read_scalefactor(Bitstream stream, Header header) - { - if (allocation != 0) - { - super.read_scalefactor(stream, header); - switch (channel2_scfsi) - { - case 0: - channel2_scalefactor1 = scalefactors[stream.get_bits(6)]; - channel2_scalefactor2 = scalefactors[stream.get_bits(6)]; - channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; - break; - - case 1: - channel2_scalefactor1 = channel2_scalefactor2 = scalefactors[stream.get_bits (6)]; - channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; - break; - - case 2: - channel2_scalefactor1 = channel2_scalefactor2 = - channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; - break; - - case 3: - channel2_scalefactor1 = scalefactors[stream.get_bits(6)]; - channel2_scalefactor2 = channel2_scalefactor3 = scalefactors[stream.get_bits (6)]; - break; - } - } - - } - - /** - * - */ - 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) - { - float sample = samples[samplenumber]; - - if (groupingtable[0] == null) - sample = (sample + d[0]) * c[0]; - if (channels == OutputChannels.BOTH_CHANNELS) - { - float sample2 = sample; - if (groupnumber <= 4) - { - sample *= scalefactor1; - sample2 *= channel2_scalefactor1; - } - else if (groupnumber <= 8) - { - sample *= scalefactor2; - sample2 *= channel2_scalefactor2; - } - else - { - sample *= scalefactor3; - sample2 *= channel2_scalefactor3; - } - filter1.input_sample(sample, subbandnumber); - filter2.input_sample(sample2, subbandnumber); - } - else if (channels == OutputChannels.LEFT_CHANNEL) - { - if (groupnumber <= 4) - sample *= scalefactor1; - else if (groupnumber <= 8) - sample *= scalefactor2; - else - sample *= scalefactor3; - filter1.input_sample(sample, subbandnumber); - } - else - { - if (groupnumber <= 4) - sample *= channel2_scalefactor1; - else if (groupnumber <= 8) - sample *= channel2_scalefactor2; - else - sample *= channel2_scalefactor3; - filter1.input_sample(sample, subbandnumber); - } - } - - if (++samplenumber == 3) - return true; - else - return false; - } - }; - - /** - * Class for layer II subbands in stereo mode. - */ - static class SubbandLayer2Stereo extends SubbandLayer2 - { - protected int channel2_allocation; - protected int channel2_scfsi; - protected float channel2_scalefactor1, channel2_scalefactor2, channel2_scalefactor3; - //protected boolean channel2_grouping; ???? Never used! - protected int[] channel2_codelength = {0}; - //protected float[][] channel2_groupingtable = {{0},{0}}; - protected float[] channel2_factor = {0}; - protected float[] channel2_samples; - protected float[] channel2_c = {0}; - protected float[] channel2_d = {0}; - - /** - * Constructor - */ - public SubbandLayer2Stereo(int subbandnumber) - { - super(subbandnumber); - channel2_samples = new float[3]; - } - - /** - * - */ - public void read_allocation (Bitstream stream, Header header, Crc16 crc) - { - int length = get_allocationlength(header); - allocation = stream.get_bits(length); - channel2_allocation = stream.get_bits(length); - if (crc != null) - { - crc.add_bits(allocation, length); - crc.add_bits(channel2_allocation, length); - } - } - - /** - * - */ - public void read_scalefactor_selection(Bitstream stream, Crc16 crc) - { - if (allocation != 0) - { - scfsi = stream.get_bits(2); - if (crc != null) - crc.add_bits(scfsi, 2); - } - if (channel2_allocation != 0) - { - channel2_scfsi = stream.get_bits(2); - if (crc != null) - crc.add_bits(channel2_scfsi, 2); - } - } - - /** - * - */ - public void read_scalefactor(Bitstream stream, Header header) - { - super.read_scalefactor(stream, header); - if (channel2_allocation != 0) - { - switch (channel2_scfsi) - { - case 0: - channel2_scalefactor1 = scalefactors[stream.get_bits(6)]; - channel2_scalefactor2 = scalefactors[stream.get_bits(6)]; - channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; - break; - - case 1: - channel2_scalefactor1 = channel2_scalefactor2 = - scalefactors[stream.get_bits(6)]; - channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; - break; - - case 2: - channel2_scalefactor1 = channel2_scalefactor2 = - channel2_scalefactor3 = scalefactors[stream.get_bits(6)]; - break; - - case 3: - channel2_scalefactor1 = scalefactors[stream.get_bits(6)]; - channel2_scalefactor2 = channel2_scalefactor3 = - scalefactors[stream.get_bits(6)]; - break; - } - prepare_sample_reading(header, channel2_allocation, 1, - channel2_factor, channel2_codelength, channel2_c, - channel2_d); - } - } - - /** - * - */ - public boolean read_sampledata (Bitstream stream) - { - boolean returnvalue = super.read_sampledata(stream); - - if (channel2_allocation != 0) - if (groupingtable[1] != null) - { - int samplecode = stream.get_bits(channel2_codelength[0]); - // create requantized samples: - samplecode += samplecode << 1; - /* - float[] target = channel2_samples; - float[] source = channel2_groupingtable[0]; - int tmp = 0; - int temp = 0; - target[tmp++] = source[samplecode + temp]; - temp++; - target[tmp++] = source[samplecode + temp]; - temp++; - target[tmp] = source[samplecode + temp]; - // memcpy (channel2_samples, channel2_groupingtable + samplecode, 3 * sizeof (real)); - */ - float[] target = channel2_samples; - float[] source = groupingtable[1]; - int tmp = 0; - int temp = samplecode; - target[tmp] = source[temp]; - temp++;tmp++; - target[tmp] = source[temp]; - temp++;tmp++; - target[tmp] = source[temp]; - - } - else - { - channel2_samples[0] = (float) ((stream.get_bits(channel2_codelength[0])) * - channel2_factor[0] - 1.0); - channel2_samples[1] = (float) ((stream.get_bits(channel2_codelength[0])) * - channel2_factor[0] - 1.0); - channel2_samples[2] = (float) ((stream.get_bits(channel2_codelength[0])) * - channel2_factor[0] - 1.0); - } - return returnvalue; - } - - /** - * - */ - public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2) - { - boolean returnvalue = super.put_next_sample(channels, filter1, filter2); - if ((channel2_allocation != 0) && (channels != OutputChannels.LEFT_CHANNEL)) - { - float sample = channel2_samples[samplenumber - 1]; - - if (groupingtable[1] == null) - sample = (sample + channel2_d[0]) * channel2_c[0]; - - if (groupnumber <= 4) - sample *= channel2_scalefactor1; - else if (groupnumber <= 8) - sample *= channel2_scalefactor2; - else - sample *= channel2_scalefactor3; - if (channels == OutputChannels.BOTH_CHANNELS) - filter2.input_sample(sample, subbandnumber); - else - filter1.input_sample(sample, subbandnumber); - } - return returnvalue; - } - } -} diff --git a/src/javazoom/jl/decoder/LayerIIIDecoder.java b/src/javazoom/jl/decoder/LayerIIIDecoder.java deleted file mode 100644 index 3a48071f17a..00000000000 --- a/src/javazoom/jl/decoder/LayerIIIDecoder.java +++ /dev/null @@ -1,2439 +0,0 @@ -/* - * 11/19/04 1.0 moved to LGPL. - * - * 18/06/01 Michael Scheerer, Fixed bugs which causes - * negative indexes in method huffmann_decode and in method - * dequanisize_sample. - * - * 16/07/01 Michael Scheerer, Catched a bug in method - * huffmann_decode, which causes an outOfIndexException. - * Cause : Indexnumber of 24 at SfBandIndex, - * which has only a length of 22. I have simply and dirty - * fixed the index to <= 22, because I'm not really be able - * to fix the bug. The Indexnumber is taken from the MP3 - * file and the origin Ma-Player with the same code works - * well. - * - * 02/19/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; - -/** - * Class Implementing Layer 3 Decoder. - * - * @since 0.0 - */ -final class LayerIIIDecoder implements FrameDecoder -{ - final static double d43 = (4.0/3.0); - - public int[] scalefac_buffer; - - // MDM: removed, as this wasn't being used. - //private float CheckSumOut1d = 0.0f; - private int CheckSumHuff = 0; - private int[] is_1d; - private float[][][] ro; - private float[][][] lr; - private float[] out_1d; - private float[][] prevblck; - private float[][] k; - private int[] nonzero; - private Bitstream stream; - private Header header; - private SynthesisFilter filter1, filter2; - private Obuffer buffer; - private int which_channels; - private BitReserve br; - private III_side_info_t si; - - private temporaire2[] III_scalefac_t; - private temporaire2[] scalefac; - // private III_scalefac_t scalefac; - - private int max_gr; - private int frame_start; - private int part2_start; - private int channels; - private int first_channel; - private int last_channel; - private int sfreq; - - - /** - * Constructor. - */ - // REVIEW: these constructor arguments should be moved to the - // decodeFrame() method, where possible, so that one - public LayerIIIDecoder(Bitstream stream0, Header header0, - SynthesisFilter filtera, SynthesisFilter filterb, - Obuffer buffer0, int which_ch0) - { - huffcodetab.inithuff(); - is_1d = new int[SBLIMIT*SSLIMIT+4]; - ro = new float[2][SBLIMIT][SSLIMIT]; - lr = new float[2][SBLIMIT][SSLIMIT]; - out_1d = new float[SBLIMIT*SSLIMIT]; - prevblck = new float[2][SBLIMIT*SSLIMIT]; - k = new float[2][SBLIMIT*SSLIMIT]; - nonzero = new int[2]; - - //III_scalefact_t - III_scalefac_t = new temporaire2[2]; - III_scalefac_t[0] = new temporaire2(); - III_scalefac_t[1] = new temporaire2(); - scalefac = III_scalefac_t; - // L3TABLE INIT - - sfBandIndex = new SBI[9]; // SZD: MPEG2.5 +3 indices - int[] l0 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}; - int[] s0 = {0,4,8,12,18,24,32,42,56,74,100,132,174,192}; - int[] l1 = {0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,330,394,464,540,576}; - int[] s1 = {0,4,8,12,18,26,36,48,62,80,104,136,180,192}; - int[] l2 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}; - int[] s2 = {0,4,8,12,18,26,36,48,62,80,104,134,174,192}; - - int[] l3 = {0,4,8,12,16,20,24,30,36,44,52,62,74,90,110,134,162,196,238,288,342,418,576}; - int[] s3 = {0,4,8,12,16,22,30,40,52,66,84,106,136,192}; - int[] l4 = {0,4,8,12,16,20,24,30,36,42,50,60,72,88,106,128,156,190,230,276,330,384,576}; - int[] s4 = {0,4,8,12,16,22,28,38,50,64,80,100,126,192}; - int[] l5 = {0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576}; - int[] s5 = {0,4,8,12,16,22,30,42,58,78,104,138,180,192}; - // SZD: MPEG2.5 - int[] l6 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}; - int[] s6 = {0,4,8,12,18,26,36,48,62,80,104,134,174,192}; - int[] l7 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}; - int[] s7 = {0,4,8,12,18,26,36,48,62,80,104,134,174,192}; - int[] l8 = {0,12,24,36,48,60,72,88,108,132,160,192,232,280,336,400,476,566,568,570,572,574,576}; - int[] s8 = {0,8,16,24,36,52,72,96,124,160,162,164,166,192}; - - sfBandIndex[0]= new SBI(l0,s0); - sfBandIndex[1]= new SBI(l1,s1); - sfBandIndex[2]= new SBI(l2,s2); - - sfBandIndex[3]= new SBI(l3,s3); - sfBandIndex[4]= new SBI(l4,s4); - sfBandIndex[5]= new SBI(l5,s5); - //SZD: MPEG2.5 - sfBandIndex[6]= new SBI(l6,s6); - sfBandIndex[7]= new SBI(l7,s7); - sfBandIndex[8]= new SBI(l8,s8); - // END OF L3TABLE INIT - - if(reorder_table == null) { // SZD: generate LUT - reorder_table = new int[9][]; - for(int i = 0; i < 9; i++) - reorder_table[i] = reorder(sfBandIndex[i].s); - } - - // Sftable - int[] ll0 = {0, 6, 11, 16, 21}; - int[] ss0 = {0, 6, 12}; - sftable = new Sftable(ll0,ss0); - // END OF Sftable - - // scalefac_buffer - scalefac_buffer = new int[54]; - // END OF scalefac_buffer - - stream = stream0; - header = header0; - filter1 = filtera; - filter2 = filterb; - buffer = buffer0; - which_channels = which_ch0; - - frame_start = 0; - channels = (header.mode() == Header.SINGLE_CHANNEL) ? 1 : 2; - max_gr = (header.version() == Header.MPEG1) ? 2 : 1; - - sfreq = header.sample_frequency() + - ((header.version() == Header.MPEG1) ? 3 : - (header.version() == Header.MPEG25_LSF) ? 6 : 0); // SZD - - if (channels == 2) - { - switch (which_channels) - { - case OutputChannels.LEFT_CHANNEL: - case OutputChannels.DOWNMIX_CHANNELS: - first_channel = last_channel = 0; - break; - - case OutputChannels.RIGHT_CHANNEL: - first_channel = last_channel = 1; - break; - - case OutputChannels.BOTH_CHANNELS: - default: - first_channel = 0; - last_channel = 1; - break; - } - } - else - { - first_channel = last_channel = 0; - } - - for(int ch=0;ch<2;ch++) - for (int j=0; j<576; j++) - prevblck[ch][j] = 0.0f; - - nonzero[0] = nonzero[1] = 576; - - br = new BitReserve(); - si = new III_side_info_t(); - } - - /** - * Notify decoder that a seek is being made. - */ - public void seek_notify() - { - frame_start = 0; - for(int ch=0;ch<2;ch++) - for (int j=0; j<576; j++) - prevblck[ch][j] = 0.0f; - br = new BitReserve(); - } - - public void decodeFrame() - { - decode(); - } - - /** - * Decode one frame, filling the buffer with the output samples. - */ - - // subband samples are buffered and passed to the - // SynthesisFilter in one go. - private float[] samples1 = new float[32]; - private float[] samples2 = new float[32]; - - public void decode() - { - int nSlots = header.slots(); - int flush_main; - int gr, ch, ss, sb, sb18; - int main_data_end; - int bytes_to_discard; - int i; - - get_side_info(); - - for (i=0; i>> 3; // of previous frame - - if ((flush_main = (br.hsstell() & 7)) != 0) { - br.hgetbits(8 - flush_main); - main_data_end++; - } - - bytes_to_discard = frame_start - main_data_end - - si.main_data_begin; - - frame_start += nSlots; - - if (bytes_to_discard < 0) - return; - - if (main_data_end > 4096) { - frame_start -= 4096; - br.rewindNbytes(4096); - } - - for (; bytes_to_discard > 0; bytes_to_discard--) - br.hgetbits(8); - - for (gr=0;gr>> 4) / 5 ; - new_slen[1] = (scalefac_comp >>> 4) % 5 ; - new_slen[2] = (scalefac_comp & 0xF) >>> 2 ; - new_slen[3] = (scalefac_comp & 3); - si.ch[ch].gr[gr].preflag = 0; - blocknumber = 0; - - } else if (scalefac_comp < 500) { - - new_slen[0] = ((scalefac_comp - 400) >>> 2) / 5 ; - new_slen[1] = ((scalefac_comp - 400) >>> 2) % 5 ; - new_slen[2] = (scalefac_comp - 400 ) & 3 ; - new_slen[3] = 0; - si.ch[ch].gr[gr].preflag = 0; - blocknumber = 1; - - } else if (scalefac_comp < 512) { - - new_slen[0] = (scalefac_comp - 500 ) / 3 ; - new_slen[1] = (scalefac_comp - 500) % 3 ; - new_slen[2] = 0; - new_slen[3] = 0; - si.ch[ch].gr[gr].preflag = 1; - blocknumber = 2; - } - } - - if((((mode_ext == 1) || (mode_ext == 3)) && (ch == 1))) - { - int_scalefac_comp = scalefac_comp >>> 1; - - if (int_scalefac_comp < 180) - { - new_slen[0] = int_scalefac_comp / 36 ; - new_slen[1] = (int_scalefac_comp % 36 ) / 6 ; - new_slen[2] = (int_scalefac_comp % 36) % 6; - new_slen[3] = 0; - si.ch[ch].gr[gr].preflag = 0; - blocknumber = 3; - } else if (int_scalefac_comp < 244) { - new_slen[0] = ((int_scalefac_comp - 180 ) & 0x3F) >>> 4 ; - new_slen[1] = ((int_scalefac_comp - 180) & 0xF) >>> 2 ; - new_slen[2] = (int_scalefac_comp - 180 ) & 3 ; - new_slen[3] = 0; - si.ch[ch].gr[gr].preflag = 0; - blocknumber = 4; - } else if (int_scalefac_comp < 255) { - new_slen[0] = (int_scalefac_comp - 244 ) / 3 ; - new_slen[1] = (int_scalefac_comp - 244 ) % 3 ; - new_slen[2] = 0 ; - new_slen[3] = 0; - si.ch[ch].gr[gr].preflag = 0; - blocknumber = 5; - } - } - - for (int x=0; x<45; x++) // why 45, not 54? - scalefac_buffer[x] = 0; - - m = 0; - for (int i=0; i<4;i++) { - for (int j = 0; j < nr_of_sfb_block[blocknumber][blocktypenumber][i]; - j++) - { - scalefac_buffer[m] = (new_slen[i] == 0) ? 0 : - br.hgetbits(new_slen[i]); - m++; - - } // for (unint32 j ... - } // for (uint32 i ... - } - - /** - * - */ - private void get_LSF_scale_factors(int ch, int gr) - { - int m = 0; - int sfb, window; - gr_info_s gr_info = (si.ch[ch].gr[gr]); - - get_LSF_scale_data(ch, gr); - - if ((gr_info.window_switching_flag != 0) && (gr_info.block_type == 2)) { - if (gr_info.mixed_block_flag != 0) { // MIXED - for (sfb = 0; sfb < 8; sfb++) - { - scalefac[ch].l[sfb] = scalefac_buffer[m]; - m++; - } - for (sfb = 3; sfb < 12; sfb++) { - for (window=0; window<3; window++) - { - scalefac[ch].s[window][sfb] = scalefac_buffer[m]; - m++; - } - } - for (window=0; window<3; window++) - scalefac[ch].s[window][12] = 0; - - } else { // SHORT - - for (sfb = 0; sfb < 12; sfb++) { - for (window=0; window<3; window++) - { - scalefac[ch].s[window][sfb] = scalefac_buffer[m]; - m++; - } - } - - for (window=0; window<3; window++) - scalefac[ch].s[window][12] = 0; - } - } else { // LONG types 0,1,3 - - for (sfb = 0; sfb < 21; sfb++) { - scalefac[ch].l[sfb] = scalefac_buffer[m]; - m++; - } - scalefac[ch].l[21] = 0; // Jeff - scalefac[ch].l[22] = 0; - } - } - - /** - * - */ - int[] x = {0}; - int[] y = {0}; - int[] v = {0}; - int[] w = {0}; - private void huffman_decode(int ch, int gr) - { - x[0] = 0; - y[0] = 0; - v[0] = 0; - w[0] = 0; - - int part2_3_end = part2_start + si.ch[ch].gr[gr].part2_3_length; - int num_bits; - int region1Start; - int region2Start; - int index; - - int buf, buf1; - - huffcodetab h; - - // Find region boundary for short block case - - if ( ((si.ch[ch].gr[gr].window_switching_flag) != 0) && - (si.ch[ch].gr[gr].block_type == 2) ) { - - // Region2. - //MS: Extrahandling for 8KHZ - region1Start = (sfreq == 8) ? 72 : 36; // sfb[9/3]*3=36 or in case 8KHZ = 72 - region2Start = 576; // No Region2 for short block case - - } else { // Find region boundary for long block case - - buf = si.ch[ch].gr[gr].region0_count + 1; - buf1 = buf + si.ch[ch].gr[gr].region1_count + 1; - - if(buf1 > sfBandIndex[sfreq].l.length - 1) buf1 = sfBandIndex[sfreq].l.length - 1; - - region1Start = sfBandIndex[sfreq].l[buf]; - region2Start = sfBandIndex[sfreq].l[buf1]; /* MI */ - } - - index = 0; - // Read bigvalues area - for (int i=0; i<(si.ch[ch].gr[gr].big_values<<1); i+=2) { - if (i= is_1d.length) System.out.println("i0="+i+"/"+(si.ch[ch].gr[gr].big_values<<1)+" Index="+index+" is_1d="+is_1d.length); - - is_1d[index++] = x[0]; - is_1d[index++] = y[0]; - - CheckSumHuff = CheckSumHuff + x[0] + y[0]; - // System.out.println("x = "+x[0]+" y = "+y[0]); - } - - // Read count1 area - h = huffcodetab.ht[si.ch[ch].gr[gr].count1table_select+32]; - num_bits = br.hsstell(); - - while ((num_bits < part2_3_end) && (index < 576)) { - - huffcodetab.huffman_decoder(h, x, y, v, w, br); - - is_1d[index++] = v[0]; - is_1d[index++] = w[0]; - is_1d[index++] = x[0]; - is_1d[index++] = y[0]; - CheckSumHuff = CheckSumHuff + v[0] + w[0] + x[0] + y[0]; - // System.out.println("v = "+v[0]+" w = "+w[0]); - // System.out.println("x = "+x[0]+" y = "+y[0]); - num_bits = br.hsstell(); - } - - if (num_bits > part2_3_end) { - br.rewindNbits(num_bits - part2_3_end); - index-=4; - } - - num_bits = br.hsstell(); - - // Dismiss stuffing bits - if (num_bits < part2_3_end) - br.hgetbits(part2_3_end - num_bits); - - // Zero out rest - - if (index < 576) - nonzero[ch] = index; - else - nonzero[ch] = 576; - - if (index < 0) index = 0; - - // may not be necessary - for (; index<576; index++) - is_1d[index] = 0; - } - - /** - * - */ - private void i_stereo_k_values(int is_pos, int io_type, int i) - { - if (is_pos == 0) { - k[0][i] = 1.0f; - k[1][i] = 1.0f; - } else if ((is_pos & 1) != 0) { - k[0][i] = io[io_type][(is_pos + 1) >>> 1]; - k[1][i] = 1.0f; - } else { - k[0][i] = 1.0f; - k[1][i] = io[io_type][is_pos >>> 1]; - } - } - - /** - * - */ - private void dequantize_sample(float xr[][], int ch, int gr) - { - gr_info_s gr_info = (si.ch[ch].gr[gr]); - int cb=0; - int next_cb_boundary; - int cb_begin = 0; - int cb_width = 0; - int index=0, t_index, j; - float g_gain; - float[][] xr_1d = xr; - - // choose correct scalefactor band per block type, initalize boundary - - if ((gr_info.window_switching_flag !=0 ) && (gr_info.block_type == 2) ) { - if (gr_info.mixed_block_flag != 0) - next_cb_boundary=sfBandIndex[sfreq].l[1]; // LONG blocks: 0,1,3 - else { - cb_width = sfBandIndex[sfreq].s[1]; - next_cb_boundary = (cb_width << 2) - cb_width; - cb_begin = 0; - } - } else { - next_cb_boundary=sfBandIndex[sfreq].l[1]; // LONG blocks: 0,1,3 - } - - // Compute overall (global) scaling. - - g_gain = (float) Math.pow(2.0 , (0.25 * (gr_info.global_gain - 210.0))); - - for (j=0; j 0) xr_1d[quotien][reste] = g_gain * t_43[abv]; - else - { - if (-abv < t_43.length) xr_1d[quotien][reste] = -g_gain * t_43[-abv]; - else xr_1d[quotien][reste] = -g_gain * (float)Math.pow(-abv, d43); - } - } - else - { - if (is_1d[j] > 0) xr_1d[quotien][reste] = g_gain * (float)Math.pow(abv, d43); - else xr_1d[quotien][reste] = -g_gain * (float)Math.pow(-abv, d43); - } - } - } - - // apply formula per block type - for (j=0; j= 36)) )) - { - - t_index = (index - cb_begin) / cb_width; - /* xr[sb][ss] *= pow(2.0, ((-2.0 * gr_info.subblock_gain[t_index]) - -(0.5 * (1.0 + gr_info.scalefac_scale) - * scalefac[ch].s[t_index][cb]))); */ - int idx = scalefac[ch].s[t_index][cb] - << gr_info.scalefac_scale; - idx += (gr_info.subblock_gain[t_index] << 2); - - xr_1d[quotien][reste] *= two_to_negative_half_pow[idx]; - - } else { // LONG block types 0,1,3 & 1st 2 subbands of switched blocks - /* xr[sb][ss] *= pow(2.0, -0.5 * (1.0+gr_info.scalefac_scale) - * (scalefac[ch].l[cb] - + gr_info.preflag * pretab[cb])); */ - int idx = scalefac[ch].l[cb]; - - if (gr_info.preflag != 0) - idx += pretab[cb]; - - idx = idx << gr_info.scalefac_scale; - xr_1d[quotien][reste] *= two_to_negative_half_pow[idx]; - } - index++; - } - - for (j=nonzero[ch]; j<576; j++) - { - // Modif E.B 02/22/99 - int reste = j % SSLIMIT; - int quotien = (int) ((j-reste)/SSLIMIT); - if(reste < 0) reste = 0; - if(quotien < 0) quotien = 0; - xr_1d[quotien][reste] = 0.0f; - } - - return; - } - - /** - * - */ - private void reorder(float xr[][], int ch, int gr) - { - gr_info_s gr_info = (si.ch[ch].gr[gr]); - int freq, freq3; - int index; - int sfb, sfb_start, sfb_lines; - int src_line, des_line; - float[][] xr_1d = xr; - - if ((gr_info.window_switching_flag !=0) && (gr_info.block_type == 2)) { - - for(index=0; index<576; index++) - out_1d[index] = 0.0f; - - if (gr_info.mixed_block_flag !=0 ) { - // NO REORDER FOR LOW 2 SUBBANDS - for (index = 0; index < 36; index++) - { - // Modif E.B 02/22/99 - int reste = index % SSLIMIT; - int quotien = (int) ((index-reste)/SSLIMIT); - out_1d[index] = xr_1d[quotien][reste]; - } - // REORDERING FOR REST SWITCHED SHORT - /*for( sfb=3,sfb_start=sfBandIndex[sfreq].s[3], - sfb_lines=sfBandIndex[sfreq].s[4] - sfb_start; - sfb < 13; sfb++,sfb_start = sfBandIndex[sfreq].s[sfb], - sfb_lines = sfBandIndex[sfreq].s[sfb+1] - sfb_start ) - {*/ - for( sfb=3; sfb < 13; sfb++) - { - //System.out.println("sfreq="+sfreq+" sfb="+sfb+" sfBandIndex="+sfBandIndex.length+" sfBandIndex[sfreq].s="+sfBandIndex[sfreq].s.length); - sfb_start = sfBandIndex[sfreq].s[sfb]; - sfb_lines = sfBandIndex[sfreq].s[sfb+1] - sfb_start; - - int sfb_start3 = (sfb_start << 2) - sfb_start; - - for(freq=0, freq3=0; freq=3; sfb-- ) { - i = sfBandIndex[sfreq].s[sfb]; - lines = sfBandIndex[sfreq].s[sfb+1] - i; - i = (i << 2) - i + (j+1) * lines - 1; - - while (lines > 0) { - if (ro[1][i/18][i%18] != 0.0f) { - // MDM: in java, array access is very slow. - // Is quicker to compute div and mod values. - //if (ro[1][ss_div[i]][ss_mod[i]] != 0.0f) { - sfbcnt = sfb; - sfb = -10; - lines = -10; - } - - lines--; - i--; - - } // while (lines > 0) - - } // for (sfb=12 ... - sfb = sfbcnt + 1; - - if (sfb > max_sfb) - max_sfb = sfb; - - while(sfb < 12) { - temp = sfBandIndex[sfreq].s[sfb]; - sb = sfBandIndex[sfreq].s[sfb+1] - temp; - i = (temp << 2) - temp + j * sb; - - for ( ; sb > 0; sb--) { - is_pos[i] = scalefac[1].s[j][sfb]; - if (is_pos[i] != 7) - if (lsf) - i_stereo_k_values(is_pos[i], io_type, i); - else - is_ratio[i] = TAN12[is_pos[i]]; - - i++; - } // for (; sb>0... - sfb++; - } // while (sfb < 12) - sfb = sfBandIndex[sfreq].s[10]; - sb = sfBandIndex[sfreq].s[11] - sfb; - sfb = (sfb << 2) - sfb + j * sb; - temp = sfBandIndex[sfreq].s[11]; - sb = sfBandIndex[sfreq].s[12] - temp; - i = (temp << 2) - temp + j * sb; - - for (; sb > 0; sb--) { - is_pos[i] = is_pos[sfb]; - - if (lsf) { - k[0][i] = k[0][sfb]; - k[1][i] = k[1][sfb]; - } else { - is_ratio[i] = is_ratio[sfb]; - } - i++; - } // for (; sb > 0 ... - } - if (max_sfb <= 3) { - i = 2; - ss = 17; - sb = -1; - while (i >= 0) { - if (ro[1][i][ss] != 0.0f) { - sb = (i<<4) + (i<<1) + ss; - i = -1; - } else { - ss--; - if (ss < 0) { - i--; - ss = 17; - } - } // if (ro ... - } // while (i>=0) - i = 0; - while (sfBandIndex[sfreq].l[i] <= sb) - i++; - sfb = i; - i = sfBandIndex[sfreq].l[i]; - for (; sfb<8; sfb++) { - sb = sfBandIndex[sfreq].l[sfb+1]-sfBandIndex[sfreq].l[sfb]; - for (; sb>0; sb--) { - is_pos[i] = scalefac[1].l[sfb]; - if (is_pos[i] != 7) - if (lsf) - i_stereo_k_values(is_pos[i], io_type, i); - else - is_ratio[i] = TAN12[is_pos[i]]; - i++; - } // for (; sb>0 ... - } // for (; sfb<8 ... - } // for (j=0 ... - } else { // if (gr_info.mixed_block_flag) - for (int j=0; j<3; j++) { - int sfbcnt; - sfbcnt = -1; - for( sfb=12; sfb >=0; sfb-- ) - { - temp = sfBandIndex[sfreq].s[sfb]; - lines = sfBandIndex[sfreq].s[sfb+1] - temp; - i = (temp << 2) - temp + (j+1) * lines - 1; - - while (lines > 0) { - if (ro[1][i/18][i%18] != 0.0f) { - // MDM: in java, array access is very slow. - // Is quicker to compute div and mod values. - //if (ro[1][ss_div[i]][ss_mod[i]] != 0.0f) { - sfbcnt = sfb; - sfb = -10; - lines = -10; - } - lines--; - i--; - } // while (lines > 0) */ - - } // for (sfb=12 ... - sfb = sfbcnt + 1; - while(sfb<12) { - temp = sfBandIndex[sfreq].s[sfb]; - sb = sfBandIndex[sfreq].s[sfb+1] - temp; - i = (temp << 2) - temp + j * sb; - for ( ; sb > 0; sb--) { - is_pos[i] = scalefac[1].s[j][sfb]; - if (is_pos[i] != 7) - if (lsf) - i_stereo_k_values(is_pos[i], io_type, i); - else - is_ratio[i] = TAN12[is_pos[i]]; - i++; - } // for (; sb>0 ... - sfb++; - } // while (sfb<12) - - temp = sfBandIndex[sfreq].s[10]; - temp2= sfBandIndex[sfreq].s[11]; - sb = temp2 - temp; - sfb = (temp << 2) - temp + j * sb; - sb = sfBandIndex[sfreq].s[12] - temp2; - i = (temp2 << 2) - temp2 + j * sb; - - for (; sb>0; sb--) { - is_pos[i] = is_pos[sfb]; - - if (lsf) { - k[0][i] = k[0][sfb]; - k[1][i] = k[1][sfb]; - } else { - is_ratio[i] = is_ratio[sfb]; - } - i++; - } // for (; sb>0 ... - } // for (sfb=12 - } // for (j=0 ... - } else { // if (gr_info.window_switching_flag ... - i = 31; - ss = 17; - sb = 0; - while (i >= 0) { - if (ro[1][i][ss] != 0.0f) { - sb = (i<<4) + (i<<1) + ss; - i = -1; - } else { - ss--; - if (ss < 0) { - i--; - ss = 17; - } - } - } - i = 0; - while (sfBandIndex[sfreq].l[i] <= sb) - i++; - - sfb = i; - i = sfBandIndex[sfreq].l[i]; - for (; sfb<21; sfb++) { - sb = sfBandIndex[sfreq].l[sfb+1] - sfBandIndex[sfreq].l[sfb]; - for (; sb > 0; sb--) { - is_pos[i] = scalefac[1].l[sfb]; - if (is_pos[i] != 7) - if (lsf) - i_stereo_k_values(is_pos[i], io_type, i); - else - is_ratio[i] = TAN12[is_pos[i]]; - i++; - } - } - sfb = sfBandIndex[sfreq].l[20]; - for (sb = 576 - sfBandIndex[sfreq].l[21]; (sb > 0) && (i<576); sb--) - { - is_pos[i] = is_pos[sfb]; // error here : i >=576 - - if (lsf) { - k[0][i] = k[0][sfb]; - k[1][i] = k[1][sfb]; - } else { - is_ratio[i] = is_ratio[sfb]; - } - i++; - } // if (gr_info.mixed_block_flag) - } // if (gr_info.window_switching_flag ... - } // if (i_stereo) - - i = 0; - for(sb=0;sb 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(); -} diff --git a/src/javazoom/jl/decoder/OutputChannels.java b/src/javazoom/jl/decoder/OutputChannels.java deleted file mode 100644 index be2c66d22f6..00000000000 --- a/src/javazoom/jl/decoder/OutputChannels.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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 OutputChannels 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; - } - -} diff --git a/src/javazoom/jl/decoder/SampleBuffer.java b/src/javazoom/jl/decoder/SampleBuffer.java deleted file mode 100644 index 3bc0fe853ac..00000000000 --- a/src/javazoom/jl/decoder/SampleBuffer.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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 SampleBuffer 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() - {} -} diff --git a/src/javazoom/jl/decoder/Source.java b/src/javazoom/jl/decoder/Source.java deleted file mode 100644 index f4d7316a2f5..00000000000 --- a/src/javazoom/jl/decoder/Source.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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); - -} diff --git a/src/javazoom/jl/decoder/SynthesisFilter.java b/src/javazoom/jl/decoder/SynthesisFilter.java deleted file mode 100644 index 0321253cbb6..00000000000 --- a/src/javazoom/jl/decoder/SynthesisFilter.java +++ /dev/null @@ -1,1820 +0,0 @@ -/* - * 11/19/04 1.0 moved to LGPL. - * - * 04/01/00 Fixes for running under build 23xx Microsoft JVM. mdm. - * - * 19/12/99 Performance improvements to compute_pcm_samples(). - * Mat McGowan. mdm@techie.com. - * - * 16/02/99 Java Conversion by E.B , javalayer@javazoom.net - * - * @(#) synthesis_filter.h 1.8, last edit: 6/15/94 16:52:00 - * @(#) 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.IOException; - -/** - * A class for the synthesis filter bank. - * This class does a fast downsampling from 32, 44.1 or 48 kHz to 8 kHz, if ULAW is defined. - * Frequencies above 4 kHz are removed by ignoring higher subbands. - */ -final class SynthesisFilter -{ - private float[] v1; - private float[] v2; - private float[] actual_v; // v1 or v2 - private int actual_write_pos; // 0-15 - private float[] samples; // 32 new subband samples - private int channel; - private float scalefactor; - private float[] eq; - - /** - * Quality value for controlling CPU usage/quality tradeoff. - */ - /* - private int quality; - - private int v_inc; - - - - public static final int HIGH_QUALITY = 1; - public static final int MEDIUM_QUALITY = 2; - public static final int LOW_QUALITY = 4; - */ - - /** - * Contructor. - * The scalefactor scales the calculated float pcm samples to short values - * (raw pcm samples are in [-1.0, 1.0], if no violations occur). - */ - public SynthesisFilter(int channelnumber, float factor, float[] eq0) - { - if (d==null) - { - d = load_d(); - d16 = splitArray(d, 16); - } - - v1 = new float[512]; - v2 = new float[512]; - samples = new float[32]; - channel = channelnumber; - scalefactor = factor; - setEQ(eq0); - //setQuality(HIGH_QUALITY); - - reset(); - } - - public void setEQ(float[] eq0) - { - this.eq = eq0; - if (eq==null) - { - eq = new float[32]; - for (int i=0; i<32; i++) - eq[i] = 1.0f; - } - if (eq.length<32) - { - throw new IllegalArgumentException("eq0"); - } - - } - - /* - private void setQuality(int quality0) - { - switch (quality0) - { - case HIGH_QUALITY: - case MEDIUM_QUALITY: - case LOW_QUALITY: - v_inc = 16 * quality0; - quality = quality0; - break; - default : - throw new IllegalArgumentException("Unknown quality value"); - } - } - - public int getQuality() - { - return quality; - } - */ - - /** - * Reset the synthesis filter. - */ - public void reset() - { - //float[] floatp; - // float[] floatp2; - - // initialize v1[] and v2[]: - //for (floatp = v1 + 512, floatp2 = v2 + 512; floatp > v1; ) - // *--floatp = *--floatp2 = 0.0; - for (int p=0;p<512;p++) - v1[p] = v2[p] = 0.0f; - - // initialize samples[]: - //for (floatp = samples + 32; floatp > samples; ) - // *--floatp = 0.0; - for (int p2=0;p2<32;p2++) - samples[p2] = 0.0f; - - actual_v = v1; - actual_write_pos = 15; - } - - - /** - * Inject Sample. - */ - public void input_sample(float sample, int subbandnumber) - { - samples[subbandnumber] = eq[subbandnumber]*sample; - } - - public void input_samples(float[] s) - { - for (int i=31; i>=0; i--) - { - samples[i] = s[i]*eq[i]; - } - } - - /** - * Compute new values via a fast cosine transform. - */ - private void compute_new_v() - { - // p is fully initialized from x1 - //float[] p = _p; - // pp is fully initialized from p - //float[] pp = _pp; - - //float[] new_v = _new_v; - - //float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3 - //float[] p = new float[16]; - //float[] pp = new float[16]; - - /* - for (int i=31; i>=0; i--) - { - new_v[i] = 0.0f; - } - */ - - float new_v0, new_v1, new_v2, new_v3, new_v4, new_v5, new_v6, new_v7, new_v8, new_v9; - float new_v10, new_v11, new_v12, new_v13, new_v14, new_v15, new_v16, new_v17, new_v18, new_v19; - float new_v20, new_v21, new_v22, new_v23, new_v24, new_v25, new_v26, new_v27, new_v28, new_v29; - float new_v30, new_v31; - - new_v0 = new_v1 = new_v2 = new_v3 = new_v4 = new_v5 = new_v6 = new_v7 = new_v8 = new_v9 = - new_v10 = new_v11 = new_v12 = new_v13 = new_v14 = new_v15 = new_v16 = new_v17 = new_v18 = new_v19 = - new_v20 = new_v21 = new_v22 = new_v23 = new_v24 = new_v25 = new_v26 = new_v27 = new_v28 = new_v29 = - new_v30 = new_v31 = 0.0f; - - -// float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3 -// float[] p = new float[16]; -// float[] pp = new float[16]; - - float[] s = samples; - - float s0 = s[0]; - float s1 = s[1]; - float s2 = s[2]; - float s3 = s[3]; - float s4 = s[4]; - float s5 = s[5]; - float s6 = s[6]; - float s7 = s[7]; - float s8 = s[8]; - float s9 = s[9]; - float s10 = s[10]; - float s11 = s[11]; - float s12 = s[12]; - float s13 = s[13]; - float s14 = s[14]; - float s15 = s[15]; - float s16 = s[16]; - float s17 = s[17]; - float s18 = s[18]; - float s19 = s[19]; - float s20 = s[20]; - float s21 = s[21]; - float s22 = s[22]; - float s23 = s[23]; - float s24 = s[24]; - float s25 = s[25]; - float s26 = s[26]; - float s27 = s[27]; - float s28 = s[28]; - float s29 = s[29]; - float s30 = s[30]; - float s31 = s[31]; - - float p0 = s0 + s31; - float p1 = s1 + s30; - float p2 = s2 + s29; - float p3 = s3 + s28; - float p4 = s4 + s27; - float p5 = s5 + s26; - float p6 = s6 + s25; - float p7 = s7 + s24; - float p8 = s8 + s23; - float p9 = s9 + s22; - float p10 = s10 + s21; - float p11 = s11 + s20; - float p12 = s12 + s19; - float p13 = s13 + s18; - float p14 = s14 + s17; - float p15 = s15 + s16; - - float pp0 = p0 + p15; - float pp1 = p1 + p14; - float pp2 = p2 + p13; - float pp3 = p3 + p12; - float pp4 = p4 + p11; - float pp5 = p5 + p10; - float pp6 = p6 + p9; - float pp7 = p7 + p8; - float pp8 = (p0 - p15) * cos1_32; - float pp9 = (p1 - p14) * cos3_32; - float pp10 = (p2 - p13) * cos5_32; - float pp11 = (p3 - p12) * cos7_32; - float pp12 = (p4 - p11) * cos9_32; - float pp13 = (p5 - p10) * cos11_32; - float pp14 = (p6 - p9) * cos13_32; - float pp15 = (p7 - p8) * cos15_32; - - p0 = pp0 + pp7; - p1 = pp1 + pp6; - p2 = pp2 + pp5; - p3 = pp3 + pp4; - p4 = (pp0 - pp7) * cos1_16; - p5 = (pp1 - pp6) * cos3_16; - p6 = (pp2 - pp5) * cos5_16; - p7 = (pp3 - pp4) * cos7_16; - p8 = pp8 + pp15; - p9 = pp9 + pp14; - p10 = pp10 + pp13; - p11 = pp11 + pp12; - p12 = (pp8 - pp15) * cos1_16; - p13 = (pp9 - pp14) * cos3_16; - p14 = (pp10 - pp13) * cos5_16; - p15 = (pp11 - pp12) * cos7_16; - - - pp0 = p0 + p3; - pp1 = p1 + p2; - pp2 = (p0 - p3) * cos1_8; - pp3 = (p1 - p2) * cos3_8; - pp4 = p4 + p7; - pp5 = p5 + p6; - pp6 = (p4 - p7) * cos1_8; - pp7 = (p5 - p6) * cos3_8; - pp8 = p8 + p11; - pp9 = p9 + p10; - pp10 = (p8 - p11) * cos1_8; - pp11 = (p9 - p10) * cos3_8; - pp12 = p12 + p15; - pp13 = p13 + p14; - pp14 = (p12 - p15) * cos1_8; - pp15 = (p13 - p14) * cos3_8; - - p0 = pp0 + pp1; - p1 = (pp0 - pp1) * cos1_4; - p2 = pp2 + pp3; - p3 = (pp2 - pp3) * cos1_4; - p4 = pp4 + pp5; - p5 = (pp4 - pp5) * cos1_4; - p6 = pp6 + pp7; - p7 = (pp6 - pp7) * cos1_4; - p8 = pp8 + pp9; - p9 = (pp8 - pp9) * cos1_4; - p10 = pp10 + pp11; - p11 = (pp10 - pp11) * cos1_4; - p12 = pp12 + pp13; - p13 = (pp12 - pp13) * cos1_4; - p14 = pp14 + pp15; - p15 = (pp14 - pp15) * cos1_4; - - // this is pretty insane coding - float tmp1; - new_v19/*36-17*/ = -(new_v4 = (new_v12 = p7) + p5) - p6; - new_v27/*44-17*/ = -p6 - p7 - p4; - new_v6 = (new_v10 = (new_v14 = p15) + p11) + p13; - new_v17/*34-17*/ = -(new_v2 = p15 + p13 + p9) - p14; - new_v21/*38-17*/ = (tmp1 = -p14 - p15 - p10 - p11) - p13; - new_v29/*46-17*/ = -p14 - p15 - p12 - p8; - new_v25/*42-17*/ = tmp1 - p12; - new_v31/*48-17*/ = -p0; - new_v0 = p1; - new_v23/*40-17*/ = -(new_v8 = p3) - p2; - - p0 = (s0 - s31) * cos1_64; - p1 = (s1 - s30) * cos3_64; - p2 = (s2 - s29) * cos5_64; - p3 = (s3 - s28) * cos7_64; - p4 = (s4 - s27) * cos9_64; - p5 = (s5 - s26) * cos11_64; - p6 = (s6 - s25) * cos13_64; - p7 = (s7 - s24) * cos15_64; - p8 = (s8 - s23) * cos17_64; - p9 = (s9 - s22) * cos19_64; - p10 = (s10 - s21) * cos21_64; - p11 = (s11 - s20) * cos23_64; - p12 = (s12 - s19) * cos25_64; - p13 = (s13 - s18) * cos27_64; - p14 = (s14 - s17) * cos29_64; - p15 = (s15 - s16) * cos31_64; - - - pp0 = p0 + p15; - pp1 = p1 + p14; - pp2 = p2 + p13; - pp3 = p3 + p12; - pp4 = p4 + p11; - pp5 = p5 + p10; - pp6 = p6 + p9; - pp7 = p7 + p8; - pp8 = (p0 - p15) * cos1_32; - pp9 = (p1 - p14) * cos3_32; - pp10 = (p2 - p13) * cos5_32; - pp11 = (p3 - p12) * cos7_32; - pp12 = (p4 - p11) * cos9_32; - pp13 = (p5 - p10) * cos11_32; - pp14 = (p6 - p9) * cos13_32; - pp15 = (p7 - p8) * cos15_32; - - - p0 = pp0 + pp7; - p1 = pp1 + pp6; - p2 = pp2 + pp5; - p3 = pp3 + pp4; - p4 = (pp0 - pp7) * cos1_16; - p5 = (pp1 - pp6) * cos3_16; - p6 = (pp2 - pp5) * cos5_16; - p7 = (pp3 - pp4) * cos7_16; - p8 = pp8 + pp15; - p9 = pp9 + pp14; - p10 = pp10 + pp13; - p11 = pp11 + pp12; - p12 = (pp8 - pp15) * cos1_16; - p13 = (pp9 - pp14) * cos3_16; - p14 = (pp10 - pp13) * cos5_16; - p15 = (pp11 - pp12) * cos7_16; - - - pp0 = p0 + p3; - pp1 = p1 + p2; - pp2 = (p0 - p3) * cos1_8; - pp3 = (p1 - p2) * cos3_8; - pp4 = p4 + p7; - pp5 = p5 + p6; - pp6 = (p4 - p7) * cos1_8; - pp7 = (p5 - p6) * cos3_8; - pp8 = p8 + p11; - pp9 = p9 + p10; - pp10 = (p8 - p11) * cos1_8; - pp11 = (p9 - p10) * cos3_8; - pp12 = p12 + p15; - pp13 = p13 + p14; - pp14 = (p12 - p15) * cos1_8; - pp15 = (p13 - p14) * cos3_8; - - - p0 = pp0 + pp1; - p1 = (pp0 - pp1) * cos1_4; - p2 = pp2 + pp3; - p3 = (pp2 - pp3) * cos1_4; - p4 = pp4 + pp5; - p5 = (pp4 - pp5) * cos1_4; - p6 = pp6 + pp7; - p7 = (pp6 - pp7) * cos1_4; - p8 = pp8 + pp9; - p9 = (pp8 - pp9) * cos1_4; - p10 = pp10 + pp11; - p11 = (pp10 - pp11) * cos1_4; - p12 = pp12 + pp13; - p13 = (pp12 - pp13) * cos1_4; - p14 = pp14 + pp15; - p15 = (pp14 - pp15) * cos1_4; - - - // manually doing something that a compiler should handle sucks - // coding like this is hard to read - float tmp2; - new_v5 = (new_v11 = (new_v13 = (new_v15 = p15) + p7) + p11) - + p5 + p13; - new_v7 = (new_v9 = p15 + p11 + p3) + p13; - new_v16/*33-17*/ = -(new_v1 = (tmp1 = p13 + p15 + p9) + p1) - p14; - new_v18/*35-17*/ = -(new_v3 = tmp1 + p5 + p7) - p6 - p14; - - new_v22/*39-17*/ = (tmp1 = -p10 - p11 - p14 - p15) - - p13 - p2 - p3; - new_v20/*37-17*/ = tmp1 - p13 - p5 - p6 - p7; - new_v24/*41-17*/ = tmp1 - p12 - p2 - p3; - new_v26/*43-17*/ = tmp1 - p12 - (tmp2 = p4 + p6 + p7); - new_v30/*47-17*/ = (tmp1 = -p8 - p12 - p14 - p15) - p0; - new_v28/*45-17*/ = tmp1 - tmp2; - - // insert V[0-15] (== new_v[0-15]) into actual v: - // float[] x2 = actual_v + actual_write_pos; - float dest[] = actual_v; - - int pos = actual_write_pos; - - dest[0 + pos] = new_v0; - dest[16 + pos] = new_v1; - dest[32 + pos] = new_v2; - dest[48 + pos] = new_v3; - dest[64 + pos] = new_v4; - dest[80 + pos] = new_v5; - dest[96 + pos] = new_v6; - dest[112 + pos] = new_v7; - dest[128 + pos] = new_v8; - dest[144 + pos] = new_v9; - dest[160 + pos] = new_v10; - dest[176 + pos] = new_v11; - dest[192 + pos] = new_v12; - dest[208 + pos] = new_v13; - dest[224 + pos] = new_v14; - dest[240 + pos] = new_v15; - - // V[16] is always 0.0: - dest[256 + pos] = 0.0f; - - // insert V[17-31] (== -new_v[15-1]) into actual v: - dest[272 + pos] = -new_v15; - dest[288 + pos] = -new_v14; - dest[304 + pos] = -new_v13; - dest[320 + pos] = -new_v12; - dest[336 + pos] = -new_v11; - dest[352 + pos] = -new_v10; - dest[368 + pos] = -new_v9; - dest[384 + pos] = -new_v8; - dest[400 + pos] = -new_v7; - dest[416 + pos] = -new_v6; - dest[432 + pos] = -new_v5; - dest[448 + pos] = -new_v4; - dest[464 + pos] = -new_v3; - dest[480 + pos] = -new_v2; - dest[496 + pos] = -new_v1; - - // insert V[32] (== -new_v[0]) into other v: - dest = (actual_v==v1) ? v2 : v1; - - dest[0 + pos] = -new_v0; - // insert V[33-48] (== new_v[16-31]) into other v: - dest[16 + pos] = new_v16; - dest[32 + pos] = new_v17; - dest[48 + pos] = new_v18; - dest[64 + pos] = new_v19; - dest[80 + pos] = new_v20; - dest[96 + pos] = new_v21; - dest[112 + pos] = new_v22; - dest[128 + pos] = new_v23; - dest[144 + pos] = new_v24; - dest[160 + pos] = new_v25; - dest[176 + pos] = new_v26; - dest[192 + pos] = new_v27; - dest[208 + pos] = new_v28; - dest[224 + pos] = new_v29; - dest[240 + pos] = new_v30; - dest[256 + pos] = new_v31; - - // insert V[49-63] (== new_v[30-16]) into other v: - dest[272 + pos] = new_v30; - dest[288 + pos] = new_v29; - dest[304 + pos] = new_v28; - dest[320 + pos] = new_v27; - dest[336 + pos] = new_v26; - dest[352 + pos] = new_v25; - dest[368 + pos] = new_v24; - dest[384 + pos] = new_v23; - dest[400 + pos] = new_v22; - dest[416 + pos] = new_v21; - dest[432 + pos] = new_v20; - dest[448 + pos] = new_v19; - dest[464 + pos] = new_v18; - dest[480 + pos] = new_v17; - dest[496 + pos] = new_v16; -/* - } - else - { - v1[0 + actual_write_pos] = -new_v0; - // insert V[33-48] (== new_v[16-31]) into other v: - v1[16 + actual_write_pos] = new_v16; - v1[32 + actual_write_pos] = new_v17; - v1[48 + actual_write_pos] = new_v18; - v1[64 + actual_write_pos] = new_v19; - v1[80 + actual_write_pos] = new_v20; - v1[96 + actual_write_pos] = new_v21; - v1[112 + actual_write_pos] = new_v22; - v1[128 + actual_write_pos] = new_v23; - v1[144 + actual_write_pos] = new_v24; - v1[160 + actual_write_pos] = new_v25; - v1[176 + actual_write_pos] = new_v26; - v1[192 + actual_write_pos] = new_v27; - v1[208 + actual_write_pos] = new_v28; - v1[224 + actual_write_pos] = new_v29; - v1[240 + actual_write_pos] = new_v30; - v1[256 + actual_write_pos] = new_v31; - - // insert V[49-63] (== new_v[30-16]) into other v: - v1[272 + actual_write_pos] = new_v30; - v1[288 + actual_write_pos] = new_v29; - v1[304 + actual_write_pos] = new_v28; - v1[320 + actual_write_pos] = new_v27; - v1[336 + actual_write_pos] = new_v26; - v1[352 + actual_write_pos] = new_v25; - v1[368 + actual_write_pos] = new_v24; - v1[384 + actual_write_pos] = new_v23; - v1[400 + actual_write_pos] = new_v22; - v1[416 + actual_write_pos] = new_v21; - v1[432 + actual_write_pos] = new_v20; - v1[448 + actual_write_pos] = new_v19; - v1[464 + actual_write_pos] = new_v18; - v1[480 + actual_write_pos] = new_v17; - v1[496 + actual_write_pos] = new_v16; - } -*/ - } - - /** - * Compute new values via a fast cosine transform. - */ - @SuppressWarnings("unused") - private void compute_new_v_old() - { - // p is fully initialized from x1 - //float[] p = _p; - // pp is fully initialized from p - //float[] pp = _pp; - - //float[] new_v = _new_v; - - float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3 - float[] p = new float[16]; - float[] pp = new float[16]; - - - for (int i=31; i>=0; i--) - { - new_v[i] = 0.0f; - } - -// float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3 -// float[] p = new float[16]; -// float[] pp = new float[16]; - - float[] x1 = samples; - - p[0] = x1[0] + x1[31]; - p[1] = x1[1] + x1[30]; - p[2] = x1[2] + x1[29]; - p[3] = x1[3] + x1[28]; - p[4] = x1[4] + x1[27]; - p[5] = x1[5] + x1[26]; - p[6] = x1[6] + x1[25]; - p[7] = x1[7] + x1[24]; - p[8] = x1[8] + x1[23]; - p[9] = x1[9] + x1[22]; - p[10] = x1[10] + x1[21]; - p[11] = x1[11] + x1[20]; - p[12] = x1[12] + x1[19]; - p[13] = x1[13] + x1[18]; - p[14] = x1[14] + x1[17]; - p[15] = x1[15] + x1[16]; - - pp[0] = p[0] + p[15]; - pp[1] = p[1] + p[14]; - pp[2] = p[2] + p[13]; - pp[3] = p[3] + p[12]; - pp[4] = p[4] + p[11]; - pp[5] = p[5] + p[10]; - pp[6] = p[6] + p[9]; - pp[7] = p[7] + p[8]; - pp[8] = (p[0] - p[15]) * cos1_32; - pp[9] = (p[1] - p[14]) * cos3_32; - pp[10] = (p[2] - p[13]) * cos5_32; - pp[11] = (p[3] - p[12]) * cos7_32; - pp[12] = (p[4] - p[11]) * cos9_32; - pp[13] = (p[5] - p[10]) * cos11_32; - pp[14] = (p[6] - p[9]) * cos13_32; - pp[15] = (p[7] - p[8]) * cos15_32; - - p[0] = pp[0] + pp[7]; - p[1] = pp[1] + pp[6]; - p[2] = pp[2] + pp[5]; - p[3] = pp[3] + pp[4]; - p[4] = (pp[0] - pp[7]) * cos1_16; - p[5] = (pp[1] - pp[6]) * cos3_16; - p[6] = (pp[2] - pp[5]) * cos5_16; - p[7] = (pp[3] - pp[4]) * cos7_16; - p[8] = pp[8] + pp[15]; - p[9] = pp[9] + pp[14]; - p[10] = pp[10] + pp[13]; - p[11] = pp[11] + pp[12]; - p[12] = (pp[8] - pp[15]) * cos1_16; - p[13] = (pp[9] - pp[14]) * cos3_16; - p[14] = (pp[10] - pp[13]) * cos5_16; - p[15] = (pp[11] - pp[12]) * cos7_16; - - - pp[0] = p[0] + p[3]; - pp[1] = p[1] + p[2]; - pp[2] = (p[0] - p[3]) * cos1_8; - pp[3] = (p[1] - p[2]) * cos3_8; - pp[4] = p[4] + p[7]; - pp[5] = p[5] + p[6]; - pp[6] = (p[4] - p[7]) * cos1_8; - pp[7] = (p[5] - p[6]) * cos3_8; - pp[8] = p[8] + p[11]; - pp[9] = p[9] + p[10]; - pp[10] = (p[8] - p[11]) * cos1_8; - pp[11] = (p[9] - p[10]) * cos3_8; - pp[12] = p[12] + p[15]; - pp[13] = p[13] + p[14]; - pp[14] = (p[12] - p[15]) * cos1_8; - pp[15] = (p[13] - p[14]) * cos3_8; - - p[0] = pp[0] + pp[1]; - p[1] = (pp[0] - pp[1]) * cos1_4; - p[2] = pp[2] + pp[3]; - p[3] = (pp[2] - pp[3]) * cos1_4; - p[4] = pp[4] + pp[5]; - p[5] = (pp[4] - pp[5]) * cos1_4; - p[6] = pp[6] + pp[7]; - p[7] = (pp[6] - pp[7]) * cos1_4; - p[8] = pp[8] + pp[9]; - p[9] = (pp[8] - pp[9]) * cos1_4; - p[10] = pp[10] + pp[11]; - p[11] = (pp[10] - pp[11]) * cos1_4; - p[12] = pp[12] + pp[13]; - p[13] = (pp[12] - pp[13]) * cos1_4; - p[14] = pp[14] + pp[15]; - p[15] = (pp[14] - pp[15]) * cos1_4; - - // this is pretty insane coding - float tmp1; - new_v[36-17] = -(new_v[4] = (new_v[12] = p[7]) + p[5]) - p[6]; - new_v[44-17] = -p[6] - p[7] - p[4]; - new_v[6] = (new_v[10] = (new_v[14] = p[15]) + p[11]) + p[13]; - new_v[34-17] = -(new_v[2] = p[15] + p[13] + p[9]) - p[14]; - new_v[38-17] = (tmp1 = -p[14] - p[15] - p[10] - p[11]) - p[13]; - new_v[46-17] = -p[14] - p[15] - p[12] - p[8]; - new_v[42-17] = tmp1 - p[12]; - new_v[48-17] = -p[0]; - new_v[0] = p[1]; - new_v[40-17] = -(new_v[8] = p[3]) - p[2]; - - p[0] = (x1[0] - x1[31]) * cos1_64; - p[1] = (x1[1] - x1[30]) * cos3_64; - p[2] = (x1[2] - x1[29]) * cos5_64; - p[3] = (x1[3] - x1[28]) * cos7_64; - p[4] = (x1[4] - x1[27]) * cos9_64; - p[5] = (x1[5] - x1[26]) * cos11_64; - p[6] = (x1[6] - x1[25]) * cos13_64; - p[7] = (x1[7] - x1[24]) * cos15_64; - p[8] = (x1[8] - x1[23]) * cos17_64; - p[9] = (x1[9] - x1[22]) * cos19_64; - p[10] = (x1[10] - x1[21]) * cos21_64; - p[11] = (x1[11] - x1[20]) * cos23_64; - p[12] = (x1[12] - x1[19]) * cos25_64; - p[13] = (x1[13] - x1[18]) * cos27_64; - p[14] = (x1[14] - x1[17]) * cos29_64; - p[15] = (x1[15] - x1[16]) * cos31_64; - - - pp[0] = p[0] + p[15]; - pp[1] = p[1] + p[14]; - pp[2] = p[2] + p[13]; - pp[3] = p[3] + p[12]; - pp[4] = p[4] + p[11]; - pp[5] = p[5] + p[10]; - pp[6] = p[6] + p[9]; - pp[7] = p[7] + p[8]; - pp[8] = (p[0] - p[15]) * cos1_32; - pp[9] = (p[1] - p[14]) * cos3_32; - pp[10] = (p[2] - p[13]) * cos5_32; - pp[11] = (p[3] - p[12]) * cos7_32; - pp[12] = (p[4] - p[11]) * cos9_32; - pp[13] = (p[5] - p[10]) * cos11_32; - pp[14] = (p[6] - p[9]) * cos13_32; - pp[15] = (p[7] - p[8]) * cos15_32; - - - p[0] = pp[0] + pp[7]; - p[1] = pp[1] + pp[6]; - p[2] = pp[2] + pp[5]; - p[3] = pp[3] + pp[4]; - p[4] = (pp[0] - pp[7]) * cos1_16; - p[5] = (pp[1] - pp[6]) * cos3_16; - p[6] = (pp[2] - pp[5]) * cos5_16; - p[7] = (pp[3] - pp[4]) * cos7_16; - p[8] = pp[8] + pp[15]; - p[9] = pp[9] + pp[14]; - p[10] = pp[10] + pp[13]; - p[11] = pp[11] + pp[12]; - p[12] = (pp[8] - pp[15]) * cos1_16; - p[13] = (pp[9] - pp[14]) * cos3_16; - p[14] = (pp[10] - pp[13]) * cos5_16; - p[15] = (pp[11] - pp[12]) * cos7_16; - - - pp[0] = p[0] + p[3]; - pp[1] = p[1] + p[2]; - pp[2] = (p[0] - p[3]) * cos1_8; - pp[3] = (p[1] - p[2]) * cos3_8; - pp[4] = p[4] + p[7]; - pp[5] = p[5] + p[6]; - pp[6] = (p[4] - p[7]) * cos1_8; - pp[7] = (p[5] - p[6]) * cos3_8; - pp[8] = p[8] + p[11]; - pp[9] = p[9] + p[10]; - pp[10] = (p[8] - p[11]) * cos1_8; - pp[11] = (p[9] - p[10]) * cos3_8; - pp[12] = p[12] + p[15]; - pp[13] = p[13] + p[14]; - pp[14] = (p[12] - p[15]) * cos1_8; - pp[15] = (p[13] - p[14]) * cos3_8; - - - p[0] = pp[0] + pp[1]; - p[1] = (pp[0] - pp[1]) * cos1_4; - p[2] = pp[2] + pp[3]; - p[3] = (pp[2] - pp[3]) * cos1_4; - p[4] = pp[4] + pp[5]; - p[5] = (pp[4] - pp[5]) * cos1_4; - p[6] = pp[6] + pp[7]; - p[7] = (pp[6] - pp[7]) * cos1_4; - p[8] = pp[8] + pp[9]; - p[9] = (pp[8] - pp[9]) * cos1_4; - p[10] = pp[10] + pp[11]; - p[11] = (pp[10] - pp[11]) * cos1_4; - p[12] = pp[12] + pp[13]; - p[13] = (pp[12] - pp[13]) * cos1_4; - p[14] = pp[14] + pp[15]; - p[15] = (pp[14] - pp[15]) * cos1_4; - - - // manually doing something that a compiler should handle sucks - // coding like this is hard to read - float tmp2; - new_v[5] = (new_v[11] = (new_v[13] = (new_v[15] = p[15]) + p[7]) + p[11]) - + p[5] + p[13]; - new_v[7] = (new_v[9] = p[15] + p[11] + p[3]) + p[13]; - new_v[33-17] = -(new_v[1] = (tmp1 = p[13] + p[15] + p[9]) + p[1]) - p[14]; - new_v[35-17] = -(new_v[3] = tmp1 + p[5] + p[7]) - p[6] - p[14]; - - new_v[39-17] = (tmp1 = -p[10] - p[11] - p[14] - p[15]) - - p[13] - p[2] - p[3]; - new_v[37-17] = tmp1 - p[13] - p[5] - p[6] - p[7]; - new_v[41-17] = tmp1 - p[12] - p[2] - p[3]; - new_v[43-17] = tmp1 - p[12] - (tmp2 = p[4] + p[6] + p[7]); - new_v[47-17] = (tmp1 = -p[8] - p[12] - p[14] - p[15]) - p[0]; - new_v[45-17] = tmp1 - tmp2; - - // insert V[0-15] (== new_v[0-15]) into actual v: - x1 = new_v; - // float[] x2 = actual_v + actual_write_pos; - float[] dest = actual_v; - - dest[0 + actual_write_pos] = x1[0]; - dest[16 + actual_write_pos] = x1[1]; - dest[32 + actual_write_pos] = x1[2]; - dest[48 + actual_write_pos] = x1[3]; - dest[64 + actual_write_pos] = x1[4]; - dest[80 + actual_write_pos] = x1[5]; - dest[96 + actual_write_pos] = x1[6]; - dest[112 + actual_write_pos] = x1[7]; - dest[128 + actual_write_pos] = x1[8]; - dest[144 + actual_write_pos] = x1[9]; - dest[160 + actual_write_pos] = x1[10]; - dest[176 + actual_write_pos] = x1[11]; - dest[192 + actual_write_pos] = x1[12]; - dest[208 + actual_write_pos] = x1[13]; - dest[224 + actual_write_pos] = x1[14]; - dest[240 + actual_write_pos] = x1[15]; - - // V[16] is always 0.0: - dest[256 + actual_write_pos] = 0.0f; - - // insert V[17-31] (== -new_v[15-1]) into actual v: - dest[272 + actual_write_pos] = -x1[15]; - dest[288 + actual_write_pos] = -x1[14]; - dest[304 + actual_write_pos] = -x1[13]; - dest[320 + actual_write_pos] = -x1[12]; - dest[336 + actual_write_pos] = -x1[11]; - dest[352 + actual_write_pos] = -x1[10]; - dest[368 + actual_write_pos] = -x1[9]; - dest[384 + actual_write_pos] = -x1[8]; - dest[400 + actual_write_pos] = -x1[7]; - dest[416 + actual_write_pos] = -x1[6]; - dest[432 + actual_write_pos] = -x1[5]; - dest[448 + actual_write_pos] = -x1[4]; - dest[464 + actual_write_pos] = -x1[3]; - dest[480 + actual_write_pos] = -x1[2]; - dest[496 + actual_write_pos] = -x1[1]; - - // insert V[32] (== -new_v[0]) into other v: - - } - - /** - * Compute PCM Samples. - */ - - private float[] _tmpOut = new float[32]; - - - private void compute_pcm_samples0(Obuffer buffer) - { - final float[] vp = actual_v; - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - float pcm_sample; - final float[] dp = d16[i]; - pcm_sample = (float)(((vp[0 + dvp] * dp[0]) + - (vp[15 + dvp] * dp[1]) + - (vp[14 + dvp] * dp[2]) + - (vp[13 + dvp] * dp[3]) + - (vp[12 + dvp] * dp[4]) + - (vp[11 + dvp] * dp[5]) + - (vp[10 + dvp] * dp[6]) + - (vp[9 + dvp] * dp[7]) + - (vp[8 + dvp] * dp[8]) + - (vp[7 + dvp] * dp[9]) + - (vp[6 + dvp] * dp[10]) + - (vp[5 + dvp] * dp[11]) + - (vp[4 + dvp] * dp[12]) + - (vp[3 + dvp] * dp[13]) + - (vp[2 + dvp] * dp[14]) + - (vp[1 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - - private void compute_pcm_samples1(Obuffer buffer) - { - final float[] vp = actual_v; - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[1 + dvp] * dp[0]) + - (vp[0 + dvp] * dp[1]) + - (vp[15 + dvp] * dp[2]) + - (vp[14 + dvp] * dp[3]) + - (vp[13 + dvp] * dp[4]) + - (vp[12 + dvp] * dp[5]) + - (vp[11 + dvp] * dp[6]) + - (vp[10 + dvp] * dp[7]) + - (vp[9 + dvp] * dp[8]) + - (vp[8 + dvp] * dp[9]) + - (vp[7 + dvp] * dp[10]) + - (vp[6 + dvp] * dp[11]) + - (vp[5 + dvp] * dp[12]) + - (vp[4 + dvp] * dp[13]) + - (vp[3 + dvp] * dp[14]) + - (vp[2 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - private void compute_pcm_samples2(Obuffer buffer) - { - final float[] vp = actual_v; - - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[2 + dvp] * dp[0]) + - (vp[1 + dvp] * dp[1]) + - (vp[0 + dvp] * dp[2]) + - (vp[15 + dvp] * dp[3]) + - (vp[14 + dvp] * dp[4]) + - (vp[13 + dvp] * dp[5]) + - (vp[12 + dvp] * dp[6]) + - (vp[11 + dvp] * dp[7]) + - (vp[10 + dvp] * dp[8]) + - (vp[9 + dvp] * dp[9]) + - (vp[8 + dvp] * dp[10]) + - (vp[7 + dvp] * dp[11]) + - (vp[6 + dvp] * dp[12]) + - (vp[5 + dvp] * dp[13]) + - (vp[4 + dvp] * dp[14]) + - (vp[3 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - - private void compute_pcm_samples3(Obuffer buffer) - { - final float[] vp = actual_v; - - @SuppressWarnings("unused") - int idx = 0; - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[3 + dvp] * dp[0]) + - (vp[2 + dvp] * dp[1]) + - (vp[1 + dvp] * dp[2]) + - (vp[0 + dvp] * dp[3]) + - (vp[15 + dvp] * dp[4]) + - (vp[14 + dvp] * dp[5]) + - (vp[13 + dvp] * dp[6]) + - (vp[12 + dvp] * dp[7]) + - (vp[11 + dvp] * dp[8]) + - (vp[10 + dvp] * dp[9]) + - (vp[9 + dvp] * dp[10]) + - (vp[8 + dvp] * dp[11]) + - (vp[7 + dvp] * dp[12]) + - (vp[6 + dvp] * dp[13]) + - (vp[5 + dvp] * dp[14]) + - (vp[4 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - - private void compute_pcm_samples4(Obuffer buffer) - { - final float[] vp = actual_v; - - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[4 + dvp] * dp[0]) + - (vp[3 + dvp] * dp[1]) + - (vp[2 + dvp] * dp[2]) + - (vp[1 + dvp] * dp[3]) + - (vp[0 + dvp] * dp[4]) + - (vp[15 + dvp] * dp[5]) + - (vp[14 + dvp] * dp[6]) + - (vp[13 + dvp] * dp[7]) + - (vp[12 + dvp] * dp[8]) + - (vp[11 + dvp] * dp[9]) + - (vp[10 + dvp] * dp[10]) + - (vp[9 + dvp] * dp[11]) + - (vp[8 + dvp] * dp[12]) + - (vp[7 + dvp] * dp[13]) + - (vp[6 + dvp] * dp[14]) + - (vp[5 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - - private void compute_pcm_samples5(Obuffer buffer) - { - final float[] vp = actual_v; - - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[5 + dvp] * dp[0]) + - (vp[4 + dvp] * dp[1]) + - (vp[3 + dvp] * dp[2]) + - (vp[2 + dvp] * dp[3]) + - (vp[1 + dvp] * dp[4]) + - (vp[0 + dvp] * dp[5]) + - (vp[15 + dvp] * dp[6]) + - (vp[14 + dvp] * dp[7]) + - (vp[13 + dvp] * dp[8]) + - (vp[12 + dvp] * dp[9]) + - (vp[11 + dvp] * dp[10]) + - (vp[10 + dvp] * dp[11]) + - (vp[9 + dvp] * dp[12]) + - (vp[8 + dvp] * dp[13]) + - (vp[7 + dvp] * dp[14]) + - (vp[6 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - - private void compute_pcm_samples6(Obuffer buffer) - { - final float[] vp = actual_v; - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[6 + dvp] * dp[0]) + - (vp[5 + dvp] * dp[1]) + - (vp[4 + dvp] * dp[2]) + - (vp[3 + dvp] * dp[3]) + - (vp[2 + dvp] * dp[4]) + - (vp[1 + dvp] * dp[5]) + - (vp[0 + dvp] * dp[6]) + - (vp[15 + dvp] * dp[7]) + - (vp[14 + dvp] * dp[8]) + - (vp[13 + dvp] * dp[9]) + - (vp[12 + dvp] * dp[10]) + - (vp[11 + dvp] * dp[11]) + - (vp[10 + dvp] * dp[12]) + - (vp[9 + dvp] * dp[13]) + - (vp[8 + dvp] * dp[14]) + - (vp[7 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - - private void compute_pcm_samples7(Obuffer buffer) - { - final float[] vp = actual_v; - - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[7 + dvp] * dp[0]) + - (vp[6 + dvp] * dp[1]) + - (vp[5 + dvp] * dp[2]) + - (vp[4 + dvp] * dp[3]) + - (vp[3 + dvp] * dp[4]) + - (vp[2 + dvp] * dp[5]) + - (vp[1 + dvp] * dp[6]) + - (vp[0 + dvp] * dp[7]) + - (vp[15 + dvp] * dp[8]) + - (vp[14 + dvp] * dp[9]) + - (vp[13 + dvp] * dp[10]) + - (vp[12 + dvp] * dp[11]) + - (vp[11 + dvp] * dp[12]) + - (vp[10 + dvp] * dp[13]) + - (vp[9 + dvp] * dp[14]) + - (vp[8 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - private void compute_pcm_samples8(Obuffer buffer) - { - final float[] vp = actual_v; - - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[8 + dvp] * dp[0]) + - (vp[7 + dvp] * dp[1]) + - (vp[6 + dvp] * dp[2]) + - (vp[5 + dvp] * dp[3]) + - (vp[4 + dvp] * dp[4]) + - (vp[3 + dvp] * dp[5]) + - (vp[2 + dvp] * dp[6]) + - (vp[1 + dvp] * dp[7]) + - (vp[0 + dvp] * dp[8]) + - (vp[15 + dvp] * dp[9]) + - (vp[14 + dvp] * dp[10]) + - (vp[13 + dvp] * dp[11]) + - (vp[12 + dvp] * dp[12]) + - (vp[11 + dvp] * dp[13]) + - (vp[10 + dvp] * dp[14]) + - (vp[9 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - - private void compute_pcm_samples9(Obuffer buffer) - { - final float[] vp = actual_v; - - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[9 + dvp] * dp[0]) + - (vp[8 + dvp] * dp[1]) + - (vp[7 + dvp] * dp[2]) + - (vp[6 + dvp] * dp[3]) + - (vp[5 + dvp] * dp[4]) + - (vp[4 + dvp] * dp[5]) + - (vp[3 + dvp] * dp[6]) + - (vp[2 + dvp] * dp[7]) + - (vp[1 + dvp] * dp[8]) + - (vp[0 + dvp] * dp[9]) + - (vp[15 + dvp] * dp[10]) + - (vp[14 + dvp] * dp[11]) + - (vp[13 + dvp] * dp[12]) + - (vp[12 + dvp] * dp[13]) + - (vp[11 + dvp] * dp[14]) + - (vp[10 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - - private void compute_pcm_samples10(Obuffer buffer) - { - final float[] vp = actual_v; - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[10 + dvp] * dp[0]) + - (vp[9 + dvp] * dp[1]) + - (vp[8 + dvp] * dp[2]) + - (vp[7 + dvp] * dp[3]) + - (vp[6 + dvp] * dp[4]) + - (vp[5 + dvp] * dp[5]) + - (vp[4 + dvp] * dp[6]) + - (vp[3 + dvp] * dp[7]) + - (vp[2 + dvp] * dp[8]) + - (vp[1 + dvp] * dp[9]) + - (vp[0 + dvp] * dp[10]) + - (vp[15 + dvp] * dp[11]) + - (vp[14 + dvp] * dp[12]) + - (vp[13 + dvp] * dp[13]) + - (vp[12 + dvp] * dp[14]) + - (vp[11 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - private void compute_pcm_samples11(Obuffer buffer) - { - final float[] vp = actual_v; - - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[11 + dvp] * dp[0]) + - (vp[10 + dvp] * dp[1]) + - (vp[9 + dvp] * dp[2]) + - (vp[8 + dvp] * dp[3]) + - (vp[7 + dvp] * dp[4]) + - (vp[6 + dvp] * dp[5]) + - (vp[5 + dvp] * dp[6]) + - (vp[4 + dvp] * dp[7]) + - (vp[3 + dvp] * dp[8]) + - (vp[2 + dvp] * dp[9]) + - (vp[1 + dvp] * dp[10]) + - (vp[0 + dvp] * dp[11]) + - (vp[15 + dvp] * dp[12]) + - (vp[14 + dvp] * dp[13]) + - (vp[13 + dvp] * dp[14]) + - (vp[12 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - private void compute_pcm_samples12(Obuffer buffer) - { - final float[] vp = actual_v; - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[12 + dvp] * dp[0]) + - (vp[11 + dvp] * dp[1]) + - (vp[10 + dvp] * dp[2]) + - (vp[9 + dvp] * dp[3]) + - (vp[8 + dvp] * dp[4]) + - (vp[7 + dvp] * dp[5]) + - (vp[6 + dvp] * dp[6]) + - (vp[5 + dvp] * dp[7]) + - (vp[4 + dvp] * dp[8]) + - (vp[3 + dvp] * dp[9]) + - (vp[2 + dvp] * dp[10]) + - (vp[1 + dvp] * dp[11]) + - (vp[0 + dvp] * dp[12]) + - (vp[15 + dvp] * dp[13]) + - (vp[14 + dvp] * dp[14]) + - (vp[13 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - private void compute_pcm_samples13(Obuffer buffer) - { - final float[] vp = actual_v; - - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[13 + dvp] * dp[0]) + - (vp[12 + dvp] * dp[1]) + - (vp[11 + dvp] * dp[2]) + - (vp[10 + dvp] * dp[3]) + - (vp[9 + dvp] * dp[4]) + - (vp[8 + dvp] * dp[5]) + - (vp[7 + dvp] * dp[6]) + - (vp[6 + dvp] * dp[7]) + - (vp[5 + dvp] * dp[8]) + - (vp[4 + dvp] * dp[9]) + - (vp[3 + dvp] * dp[10]) + - (vp[2 + dvp] * dp[11]) + - (vp[1 + dvp] * dp[12]) + - (vp[0 + dvp] * dp[13]) + - (vp[15 + dvp] * dp[14]) + - (vp[14 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - private void compute_pcm_samples14(Obuffer buffer) - { - final float[] vp = actual_v; - - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - final float[] dp = d16[i]; - float pcm_sample; - - pcm_sample = (float)(((vp[14 + dvp] * dp[0]) + - (vp[13 + dvp] * dp[1]) + - (vp[12 + dvp] * dp[2]) + - (vp[11 + dvp] * dp[3]) + - (vp[10 + dvp] * dp[4]) + - (vp[9 + dvp] * dp[5]) + - (vp[8 + dvp] * dp[6]) + - (vp[7 + dvp] * dp[7]) + - (vp[6 + dvp] * dp[8]) + - (vp[5 + dvp] * dp[9]) + - (vp[4 + dvp] * dp[10]) + - (vp[3 + dvp] * dp[11]) + - (vp[2 + dvp] * dp[12]) + - (vp[1 + dvp] * dp[13]) + - (vp[0 + dvp] * dp[14]) + - (vp[15 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - - dvp += 16; - } // for - } - private void compute_pcm_samples15(Obuffer buffer) - { - final float[] vp = actual_v; - - //int inc = v_inc; - final float[] tmpOut = _tmpOut; - int dvp =0; - - // fat chance of having this loop unroll - for( int i=0; i<32; i++) - { - float pcm_sample; - final float dp[] = d16[i]; - pcm_sample = (float)(((vp[15 + dvp] * dp[0]) + - (vp[14 + dvp] * dp[1]) + - (vp[13 + dvp] * dp[2]) + - (vp[12 + dvp] * dp[3]) + - (vp[11 + dvp] * dp[4]) + - (vp[10 + dvp] * dp[5]) + - (vp[9 + dvp] * dp[6]) + - (vp[8 + dvp] * dp[7]) + - (vp[7 + dvp] * dp[8]) + - (vp[6 + dvp] * dp[9]) + - (vp[5 + dvp] * dp[10]) + - (vp[4 + dvp] * dp[11]) + - (vp[3 + dvp] * dp[12]) + - (vp[2 + dvp] * dp[13]) + - (vp[1 + dvp] * dp[14]) + - (vp[0 + dvp] * dp[15]) - ) * scalefactor); - - tmpOut[i] = pcm_sample; - dvp += 16; - } // for - } - -private void compute_pcm_samples(Obuffer buffer) -{ - - switch (actual_write_pos) - { - case 0: - compute_pcm_samples0(buffer); - break; - case 1: - compute_pcm_samples1(buffer); - break; - case 2: - compute_pcm_samples2(buffer); - break; - case 3: - compute_pcm_samples3(buffer); - break; - case 4: - compute_pcm_samples4(buffer); - break; - case 5: - compute_pcm_samples5(buffer); - break; - case 6: - compute_pcm_samples6(buffer); - break; - case 7: - compute_pcm_samples7(buffer); - break; - case 8: - compute_pcm_samples8(buffer); - break; - case 9: - compute_pcm_samples9(buffer); - break; - case 10: - compute_pcm_samples10(buffer); - break; - case 11: - compute_pcm_samples11(buffer); - break; - case 12: - compute_pcm_samples12(buffer); - break; - case 13: - compute_pcm_samples13(buffer); - break; - case 14: - compute_pcm_samples14(buffer); - break; - case 15: - compute_pcm_samples15(buffer); - break; - } - - if (buffer!=null) - { - buffer.appendSamples(channel, _tmpOut); - } - -/* - // MDM: I was considering putting in quality control for - // low-spec CPUs, but the performance gain (about 10-15%) - // did not justify the considerable drop in audio quality. - switch (inc) - { - case 16: - buffer.appendSamples(channel, tmpOut); - break; - case 32: - for (int i=0; i<16; i++) - { - buffer.append(channel, (short)tmpOut[i]); - buffer.append(channel, (short)tmpOut[i]); - } - break; - case 64: - for (int i=0; i<8; i++) - { - buffer.append(channel, (short)tmpOut[i]); - buffer.append(channel, (short)tmpOut[i]); - buffer.append(channel, (short)tmpOut[i]); - buffer.append(channel, (short)tmpOut[i]); - } - break; - - } -*/ - } - - /** - * Calculate 32 PCM samples and put the into the Obuffer-object. - */ - - public void calculate_pcm_samples(Obuffer buffer) - { - compute_new_v(); - compute_pcm_samples(buffer); - - actual_write_pos = (actual_write_pos + 1) & 0xf; - actual_v = (actual_v == v1) ? v2 : v1; - - // initialize samples[]: - //for (register float *floatp = samples + 32; floatp > samples; ) - // *--floatp = 0.0f; - - // MDM: this may not be necessary. The Layer III decoder always - // outputs 32 subband samples, but I haven't checked layer I & II. - for (int p=0;p<32;p++) - samples[p] = 0.0f; - } - - - private static final double MY_PI = 3.14159265358979323846; - private static final float cos1_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 64.0))); - private static final float cos3_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 64.0))); - private static final float cos5_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 5.0 / 64.0))); - private static final float cos7_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 7.0 / 64.0))); - private static final float cos9_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 9.0 / 64.0))); - private static final float cos11_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 11.0 / 64.0))); - private static final float cos13_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 13.0 / 64.0))); - private static final float cos15_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 15.0 / 64.0))); - private static final float cos17_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 17.0 / 64.0))); - private static final float cos19_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 19.0 / 64.0))); - private static final float cos21_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 21.0 / 64.0))); - private static final float cos23_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 23.0 / 64.0))); - private static final float cos25_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 25.0 / 64.0))); - private static final float cos27_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 27.0 / 64.0))); - private static final float cos29_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 29.0 / 64.0))); - private static final float cos31_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 31.0 / 64.0))); - private static final float cos1_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 32.0))); - private static final float cos3_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 32.0))); - private static final float cos5_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 5.0 / 32.0))); - private static final float cos7_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 7.0 / 32.0))); - private static final float cos9_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 9.0 / 32.0))); - private static final float cos11_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 11.0 / 32.0))); - private static final float cos13_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 13.0 / 32.0))); - private static final float cos15_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 15.0 / 32.0))); - private static final float cos1_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 16.0))); - private static final float cos3_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 16.0))); - private static final float cos5_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 5.0 / 16.0))); - private static final float cos7_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 7.0 / 16.0))); - private static final float cos1_8 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 8.0))); - private static final float cos3_8 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 8.0))); - private static final float cos1_4 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 4.0))); - - // Note: These values are not in the same order - // as in Annex 3-B.3 of the ISO/IEC DIS 11172-3 - // private float d[] = {0.000000000, -4.000442505}; - - private static float d[] = null; - - /** - * d[] split into subarrays of length 16. This provides for - * more faster access by allowing a block of 16 to be addressed - * with constant offset. - **/ - private static float d16[][] = null; - - /** - * Loads the data for the d[] from the resource SFd.ser. - * @return the loaded values for d[]. - */ - @SuppressWarnings("unchecked") - static private float[] load_d() - { - try - { - Class elemType = Float.TYPE; - Object o = JavaLayerUtils.deserializeArrayResource("sfd.ser", elemType, 512); - return (float[])o; - } - catch (IOException ex) - { - throw new ExceptionInInitializerError(ex); - } - } - - /** - * Converts a 1D array into a number of smaller arrays. This is used - * to achieve offset + constant indexing into an array. Each sub-array - * represents a block of values of the original array. - * @param array The array to split up into blocks. - * @param blockSize The size of the blocks to split the array - * into. This must be an exact divisor of - * the length of the array, or some data - * will be lost from the main array. - * - * @return An array of arrays in which each element in the returned - * array will be of length blockSize. - */ - static private float[][] splitArray(final float[] array, final int blockSize) - { - int size = array.length / blockSize; - float[][] split = new float[size][]; - for (int i=0; i array.length) - { - len = array.length-offs; - } - - if (len < 0) - len = 0; - - float[] subarray = new float[len]; - for (int i=0; i>> 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); - } -} diff --git a/src/javazoom/jl/decoder/l3reorder.ser b/src/javazoom/jl/decoder/l3reorder.ser deleted file mode 100644 index da216fcf469..00000000000 Binary files a/src/javazoom/jl/decoder/l3reorder.ser and /dev/null differ diff --git a/src/javazoom/jl/decoder/lin2au.ser b/src/javazoom/jl/decoder/lin2au.ser deleted file mode 100644 index ec1c83d30ea..00000000000 Binary files a/src/javazoom/jl/decoder/lin2au.ser and /dev/null differ diff --git a/src/javazoom/jl/decoder/readme.txt b/src/javazoom/jl/decoder/readme.txt deleted file mode 100644 index 6533d1a80d7..00000000000 --- a/src/javazoom/jl/decoder/readme.txt +++ /dev/null @@ -1,15 +0,0 @@ - -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. \ No newline at end of file diff --git a/src/javazoom/jl/decoder/sfd.ser b/src/javazoom/jl/decoder/sfd.ser deleted file mode 100644 index 440c7c67822..00000000000 Binary files a/src/javazoom/jl/decoder/sfd.ser and /dev/null differ diff --git a/src/javazoom/jl/player/AudioDevice.java b/src/javazoom/jl/player/AudioDevice.java deleted file mode 100644 index 59a0ead25de..00000000000 --- a/src/javazoom/jl/player/AudioDevice.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 AudioDevice 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: - *


- * 
- *		l0, r0, l1, r1, l2, r2...
- * 
- * where 
- *	lx indicates the xth sample on channel 0
- *  rx indicates the xth sample on channel 1
- * 
- * - * @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 true if this audio device is open and playing - * audio samples, or false otherwise. - */ - public boolean isOpen(); - - /** - * Writes a number of samples to this AudioDevice. - * - * @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 write or flush - * 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(); -} diff --git a/src/javazoom/jl/player/AudioDeviceBase.java b/src/javazoom/jl/player/AudioDeviceBase.java deleted file mode 100644 index 37860f4a3c3..00000000000 --- a/src/javazoom/jl/player/AudioDeviceBase.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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 AudioDeviceBase class provides a simple thread-safe - * implementation of the AudioDevice interface. - * Template methods are provided for subclasses to override and - * in doing so provide the implementation for the main operations - * of the AudioDevice 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 true if the audio device is open, - * false 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; - } -} diff --git a/src/javazoom/jl/player/AudioDeviceFactory.java b/src/javazoom/jl/player/AudioDeviceFactory.java deleted file mode 100644 index 0bff24ffcb6..00000000000 --- a/src/javazoom/jl/player/AudioDeviceFactory.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 AudioDeviceFactory class is responsible for creating - * a specific AudioDevice 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. - *

- * 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 AudioDevice. - * - * @return a new instance of a specific class of AudioDevice. - * @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 ClassLoader 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. - */ - @SuppressWarnings("unchecked") - 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; - } -} diff --git a/src/javazoom/jl/player/FactoryRegistry.java b/src/javazoom/jl/player/FactoryRegistry.java deleted file mode 100644 index 8e401f1bab4..00000000000 --- a/src/javazoom/jl/player/FactoryRegistry.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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 FactoryRegistry class stores the factories - * for all the audio device implementations available in the system. - *

- * 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; - } - - - @SuppressWarnings("unchecked") - protected Hashtable, AudioDeviceFactory> factories = new Hashtable(); - - /** - * Registers an AudioDeviceFactory 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 e = factories.elements(); - while (e.hasMoreElements()) - { - AudioDeviceFactory factory = (AudioDeviceFactory)e.nextElement(); - fa[idx++] = factory; - } - } - } - return fa; - } - - protected void registerDefaultFactories() - { - addFactory(new JavaSoundAudioDeviceFactory()); - } -} diff --git a/src/javazoom/jl/player/JavaSoundAudioDevice.java b/src/javazoom/jl/player/JavaSoundAudioDevice.java deleted file mode 100644 index 4dc9edb5bbd..00000000000 --- a/src/javazoom/jl/player/JavaSoundAudioDevice.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * 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 JavaSoundAudioDevice 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); - } - - } -} diff --git a/src/javazoom/jl/player/JavaSoundAudioDeviceFactory.java b/src/javazoom/jl/player/JavaSoundAudioDeviceFactory.java deleted file mode 100644 index 55856629f35..00000000000 --- a/src/javazoom/jl/player/JavaSoundAudioDeviceFactory.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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(); - } -} diff --git a/src/javazoom/jl/player/NullAudioDevice.java b/src/javazoom/jl/player/NullAudioDevice.java deleted file mode 100644 index 77fd87b3a37..00000000000 --- a/src/javazoom/jl/player/NullAudioDevice.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 NullAudioDevice 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; - } -} diff --git a/src/javazoom/jl/player/Player.java b/src/javazoom/jl/player/Player.java deleted file mode 100644 index c46a4efe761..00000000000 --- a/src/javazoom/jl/player/Player.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 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 Player 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 Player 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 - * AudioDevice 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; - } - - -} diff --git a/src/javazoom/jl/player/PlayerApplet.java b/src/javazoom/jl/player/PlayerApplet.java deleted file mode 100644 index bc66d3b8df7..00000000000 --- a/src/javazoom/jl/player/PlayerApplet.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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 -{ - private static final long serialVersionUID = 713230088845043034L; - - 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 AudioDevice 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); - } - } - } -} diff --git a/src/javazoom/jl/player/advanced/AdvancedPlayer.java b/src/javazoom/jl/player/advanced/AdvancedPlayer.java deleted file mode 100644 index a2725e3a3c5..00000000000 --- a/src/javazoom/jl/player/advanced/AdvancedPlayer.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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 play(startFrame, endFrame) - * 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 Player 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 PlaybackEvent - */ - private PlaybackEvent createEvent(int id) - { - return createEvent(audio, id); - } - - /** - * Constructs a PlaybackEvent - */ - private PlaybackEvent createEvent(AudioDevice dev, int id) - { - return new PlaybackEvent(this, id, dev.getPosition()); - } - - /** - * sets the PlaybackListener - */ - public void setPlayBackListener(PlaybackListener listener) - { - this.listener = listener; - } - - /** - * gets the PlaybackListener - */ - public PlaybackListener getPlayBackListener() - { - return listener; - } - - /** - * closes the player and notifies PlaybackListener - */ - public void stop() - { - listener.playbackFinished(createEvent(PlaybackEvent.STOPPED)); - close(); - } -} \ No newline at end of file diff --git a/src/javazoom/jl/player/advanced/PlaybackEvent.java b/src/javazoom/jl/player/advanced/PlaybackEvent.java deleted file mode 100644 index d46edcc3c40..00000000000 --- a/src/javazoom/jl/player/advanced/PlaybackEvent.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 Player 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;} - -} diff --git a/src/javazoom/jl/player/advanced/PlaybackListener.java b/src/javazoom/jl/player/advanced/PlaybackListener.java deleted file mode 100644 index a0149bfd279..00000000000 --- a/src/javazoom/jl/player/advanced/PlaybackListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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){} -} diff --git a/src/javazoom/jl/player/advanced/jlap.java b/src/javazoom/jl/player/advanced/jlap.java deleted file mode 100644 index 1ec8db3b7ae..00000000000 --- a/src/javazoom/jl/player/advanced/jlap.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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 "); - 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 static 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); - } - } -} \ No newline at end of file diff --git a/src/javazoom/jl/player/jlp.java b/src/javazoom/jl/player/jlp.java deleted file mode 100644 index cdd8817df77..00000000000 --- a/src/javazoom/jl/player/jlp.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * 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 jlp 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] "); - 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(); - } - -} diff --git a/src/org/jdesktop/beans/AbstractBean.java b/src/org/jdesktop/beans/AbstractBean.java new file mode 100644 index 00000000000..8f5beb8a1d9 --- /dev/null +++ b/src/org/jdesktop/beans/AbstractBean.java @@ -0,0 +1,501 @@ +/* + * $Id$ + * + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package org.jdesktop.beans; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; +import java.beans.VetoableChangeSupport; + +/** + *

+ * A convenience class from which to extend all non-visual AbstractBeans. It + * manages the PropertyChange notification system, making it relatively trivial + * to add support for property change events in getters/setters. + *

+ * + *

+ * A non-visual java bean is a Java class that conforms to the AbstractBean + * patterns to allow visual manipulation of the bean's properties and event + * handlers at design-time. + *

+ * + *

+ * Here is a simple example bean that contains one property, foo, and the proper + * pattern for implementing property change notification: + * + *


+ * public class ABean extends AbstractBean {
+ *     private String foo;
+ * 
+ *     public void setFoo(String newFoo) {
+ *         String old = getFoo();
+ *         this.foo = newFoo;
+ *         firePropertyChange("foo", old, getFoo());
+ *     }
+ * 
+ *     public String getFoo() {
+ *         return foo;
+ *     }
+ * }
+ * 
+ * + *

+ * + *

+ * You will notice that "getFoo()" is used in the setFoo method rather than + * accessing "foo" directly for the gets. This is done intentionally so that if + * a subclass overrides getFoo() to return, for instance, a constant value the + * property change notification system will continue to work properly. + *

+ * + *

+ * The firePropertyChange method takes into account the old value and the new + * value. Only if the two differ will it fire a property change event. So you + * can be assured from the above code fragment that a property change event will + * only occur if old is indeed different from getFoo() + *

+ * + *

+ * AbstractBean also supports vetoable + * {@link PropertyChangeEvent} events. These events are similar to + * PropertyChange events, except a special exception can be used + * to veto changing the property. For example, perhaps the property is changing + * from "fred" to "red", but a listener deems that "red" is unexceptable. In + * this case, the listener can fire a veto exception and the property must + * remain "fred". For example: + * + *


+ *  public class ABean extends AbstractBean {
+ *    private String foo;
+ *    
+ *    public void setFoo(String newFoo) throws PropertyVetoException {
+ *      String old = getFoo();
+ *      this.foo = newFoo;
+ *      fireVetoableChange("foo", old, getFoo());
+ *    }
+ *    public String getFoo() {
+ *      return foo;
+ *    }
+ *  }
+ * 
+ *  public class Tester {
+ *    public static void main(String... args) {
+ *      try {
+ *        ABean a = new ABean();
+ *        a.setFoo("fred");
+ *        a.addVetoableChangeListener(new VetoableChangeListener() {
+ *          public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
+ *            if ("red".equals(evt.getNewValue()) {
+ *              throw new PropertyVetoException("Cannot be red!", evt);
+ *            }
+ *          }
+ *        }
+ *        a.setFoo("red");
+ *      } catch (Exception e) {
+ *        e.printStackTrace(); // this will be executed
+ *      }
+ *    }
+ *  }
+ * 
+ * + *

+ *

+ * {@code AbstractBean} is not {@link java.io.Serializable}. Special care must + * be taken when creating {@code Serializable} subclasses, as the + * {@code Serializable} listeners will not be saved. Subclasses will need to + * manually save the serializable listeners. The {@link AbstractSerializableBean} + * is {@code Serializable} and already handles the listeners correctly. If + * possible, it is recommended that {@code Serializable} beans should extend + * {@code AbstractSerializableBean}. If it is not possible, the + * {@code AbstractSerializableBean} bean implementation provides details on + * how to correctly serialize an {@code AbstractBean} subclass. + *

+ * + * @see AbstractSerializableBean + * @status REVIEWED + * @author rbair + */ +public abstract class AbstractBean { + /** + * Helper class that manages all the property change notification machinery. + * PropertyChangeSupport cannot be extended directly because it requires + * a bean in the constructor, and the "this" argument is not valid until + * after super construction. Hence, delegation instead of extension + */ + private transient PropertyChangeSupport pcs; + + /** + * Helper class that manages all the veto property change notification machinery. + */ + private transient VetoableChangeSupport vcs; + + /** Creates a new instance of AbstractBean */ + protected AbstractBean() { + pcs = new PropertyChangeSupport(this); + vcs = new VetoableChangeSupport(this); + } + + /** + * Creates a new instance of AbstractBean, using the supplied PropertyChangeSupport and + * VetoableChangeSupport delegates. Neither of these may be null. + */ + protected AbstractBean(PropertyChangeSupport pcs, VetoableChangeSupport vcs) { + if (pcs == null) { + throw new NullPointerException("PropertyChangeSupport must not be null"); + } + if (vcs == null) { + throw new NullPointerException("VetoableChangeSupport must not be null"); + } + + this.pcs = pcs; + this.vcs = vcs; + } + + /** + * Add a PropertyChangeListener to the listener list. + * The listener is registered for all properties. + * The same listener object may be added more than once, and will be called + * as many times as it is added. + * If listener is null, no exception is thrown and no action + * is taken. + * + * @param listener The PropertyChangeListener to be added + */ + public final void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + /** + * Remove a PropertyChangeListener from the listener list. + * This removes a PropertyChangeListener that was registered + * for all properties. + * If listener was added more than once to the same event + * source, it will be notified one less time after being removed. + * If listener is null, or was never added, no exception is + * thrown and no action is taken. + * + * @param listener The PropertyChangeListener to be removed + */ + public final void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + /** + * Returns an array of all the listeners that were added to the + * PropertyChangeSupport object with addPropertyChangeListener(). + *

+ * If some listeners have been added with a named property, then + * the returned array will be a mixture of PropertyChangeListeners + * and PropertyChangeListenerProxys. If the calling + * method is interested in distinguishing the listeners then it must + * test each element to see if it's a + * PropertyChangeListenerProxy, perform the cast, and examine + * the parameter. + * + *

+     * PropertyChangeListener[] listeners = bean.getPropertyChangeListeners();
+     * for (int i = 0; i < listeners.length; i++) {
+     *     if (listeners[i] instanceof PropertyChangeListenerProxy) {
+     *     PropertyChangeListenerProxy proxy = 
+     *                    (PropertyChangeListenerProxy)listeners[i];
+     *     if (proxy.getPropertyName().equals("foo")) {
+     *       // proxy is a PropertyChangeListener which was associated
+     *       // with the property named "foo"
+     *     }
+     *   }
+     * }
+     *
+ * + * @see java.beans.PropertyChangeListenerProxy + * @return all of the PropertyChangeListeners added or an + * empty array if no listeners have been added + */ + public final PropertyChangeListener[] getPropertyChangeListeners() { + return pcs.getPropertyChangeListeners(); + } + + /** + * Add a PropertyChangeListener for a specific property. The listener + * will be invoked only when a call on firePropertyChange names that + * specific property. + * The same listener object may be added more than once. For each + * property, the listener will be invoked the number of times it was added + * for that property. + * If propertyName or listener is null, no + * exception is thrown and no action is taken. + * + * @param propertyName The name of the property to listen on. + * @param listener The PropertyChangeListener to be added + */ + public final void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + /** + * Remove a PropertyChangeListener for a specific property. + * If listener was added more than once to the same event + * source for the specified property, it will be notified one less time + * after being removed. + * If propertyName is null, no exception is thrown and no + * action is taken. + * If listener is null, or was never added for the specified + * property, no exception is thrown and no action is taken. + * + * @param propertyName The name of the property that was listened on. + * @param listener The PropertyChangeListener to be removed + */ + public final void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + /** + * Returns an array of all the listeners which have been associated + * with the named property. + * + * @param propertyName The name of the property being listened to + * @return all of the PropertyChangeListeners associated with + * the named property. If no such listeners have been added, + * or if propertyName is null, an empty array is + * returned. + */ + public final PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { + return pcs.getPropertyChangeListeners(propertyName); + } + + /** + * Report a bound property update to any registered listeners. + * No event is fired if old and new are equal and non-null. + * + *

+ * This is merely a convenience wrapper around the more general + * firePropertyChange method that takes {@code + * PropertyChangeEvent} value. + * + * @param propertyName The programmatic name of the property + * that was changed. + * @param oldValue The old value of the property. + * @param newValue The new value of the property. + */ + protected final void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Fire an existing PropertyChangeEvent to any registered listeners. + * No event is fired if the given event's old and new values are + * equal and non-null. + * @param evt The PropertyChangeEvent object. + */ + protected final void firePropertyChange(PropertyChangeEvent evt) { + pcs.firePropertyChange(evt); + } + + + /** + * Report a bound indexed property update to any registered + * listeners. + *

+ * No event is fired if old and new values are equal + * and non-null. + * + *

+ * This is merely a convenience wrapper around the more general + * firePropertyChange method that takes {@code PropertyChangeEvent} value. + * + * @param propertyName The programmatic name of the property that + * was changed. + * @param index index of the property element that was changed. + * @param oldValue The old value of the property. + * @param newValue The new value of the property. + */ + protected final void fireIndexedPropertyChange(String propertyName, int index, + Object oldValue, Object newValue) { + pcs.fireIndexedPropertyChange(propertyName, index, oldValue, newValue); + } + + /** + * Check if there are any listeners for a specific property, including + * those registered on all properties. If propertyName + * is null, only check for listeners registered on all properties. + * + * @param propertyName the property name. + * @return true if there are one or more listeners for the given property + */ + protected final boolean hasPropertyChangeListeners(String propertyName) { + return pcs.hasListeners(propertyName); + } + + /** + * Check if there are any listeners for a specific property, including + * those registered on all properties. If propertyName + * is null, only check for listeners registered on all properties. + * + * @param propertyName the property name. + * @return true if there are one or more listeners for the given property + */ + protected final boolean hasVetoableChangeListeners(String propertyName) { + return vcs.hasListeners(propertyName); + } + + /** + * Add a VetoableListener to the listener list. + * The listener is registered for all properties. + * The same listener object may be added more than once, and will be called + * as many times as it is added. + * If listener is null, no exception is thrown and no action + * is taken. + * + * @param listener The VetoableChangeListener to be added + */ + + public final void addVetoableChangeListener(VetoableChangeListener listener) { + vcs.addVetoableChangeListener(listener); + } + + /** + * Remove a VetoableChangeListener from the listener list. + * This removes a VetoableChangeListener that was registered + * for all properties. + * If listener was added more than once to the same event + * source, it will be notified one less time after being removed. + * If listener is null, or was never added, no exception is + * thrown and no action is taken. + * + * @param listener The VetoableChangeListener to be removed + */ + public final void removeVetoableChangeListener(VetoableChangeListener listener) { + vcs.removeVetoableChangeListener(listener); + } + + /** + * Returns the list of VetoableChangeListeners. If named vetoable change listeners + * were added, then VetoableChangeListenerProxy wrappers will returned + *

+ * @return List of VetoableChangeListeners and VetoableChangeListenerProxys + * if named property change listeners were added. + */ + public final VetoableChangeListener[] getVetoableChangeListeners(){ + return vcs.getVetoableChangeListeners(); + } + + /** + * Add a VetoableChangeListener for a specific property. The listener + * will be invoked only when a call on fireVetoableChange names that + * specific property. + * The same listener object may be added more than once. For each + * property, the listener will be invoked the number of times it was added + * for that property. + * If propertyName or listener is null, no + * exception is thrown and no action is taken. + * + * @param propertyName The name of the property to listen on. + * @param listener The VetoableChangeListener to be added + */ + + public final void addVetoableChangeListener(String propertyName, + VetoableChangeListener listener) { + vcs.addVetoableChangeListener(propertyName, listener); + } + + /** + * Remove a VetoableChangeListener for a specific property. + * If listener was added more than once to the same event + * source for the specified property, it will be notified one less time + * after being removed. + * If propertyName is null, no exception is thrown and no + * action is taken. + * If listener is null, or was never added for the specified + * property, no exception is thrown and no action is taken. + * + * @param propertyName The name of the property that was listened on. + * @param listener The VetoableChangeListener to be removed + */ + + public final void removeVetoableChangeListener(String propertyName, + VetoableChangeListener listener) { + vcs.removeVetoableChangeListener(propertyName, listener); + } + + /** + * Returns an array of all the listeners which have been associated + * with the named property. + * + * @param propertyName The name of the property being listened to + * @return all the VetoableChangeListeners associated with + * the named property. If no such listeners have been added, + * or if propertyName is null, an empty array is + * returned. + */ + public final VetoableChangeListener[] getVetoableChangeListeners(String propertyName) { + return vcs.getVetoableChangeListeners(propertyName); + } + + /** + * Report a vetoable property update to any registered listeners. If + * anyone vetos the change, then fire a new event reverting everyone to + * the old value and then rethrow the PropertyVetoException. + *

+ * No event is fired if old and new are equal and non-null. + * + * @param propertyName The programmatic name of the property + * that is about to change.. + * @param oldValue The old value of the property. + * @param newValue The new value of the property. + * @exception PropertyVetoException if the recipient wishes the property + * change to be rolled back. + */ + protected final void fireVetoableChange(String propertyName, + Object oldValue, Object newValue) + throws PropertyVetoException { + vcs.fireVetoableChange(propertyName, oldValue, newValue); + } + + /** + * Fire a vetoable property update to any registered listeners. If + * anyone vetos the change, then fire a new event reverting everyone to + * the old value and then rethrow the PropertyVetoException. + *

+ * No event is fired if old and new are equal and non-null. + * + * @param evt The PropertyChangeEvent to be fired. + * @exception PropertyVetoException if the recipient wishes the property + * change to be rolled back. + */ + protected final void fireVetoableChange(PropertyChangeEvent evt) + throws PropertyVetoException { + vcs.fireVetoableChange(evt); + } + + /** + * {@inheritDoc} + */ + @Override + public Object clone() throws CloneNotSupportedException { + AbstractBean result = (AbstractBean) super.clone(); + result.pcs = new PropertyChangeSupport(result); + result.vcs = new VetoableChangeSupport(result); + return result; + } +} \ No newline at end of file diff --git a/src/org/jdesktop/swingx/JXMultiSplitPane.java b/src/org/jdesktop/swingx/JXMultiSplitPane.java new file mode 100644 index 00000000000..3e70372390d --- /dev/null +++ b/src/org/jdesktop/swingx/JXMultiSplitPane.java @@ -0,0 +1,566 @@ +/* + * $Id: JXMultiSplitPane.java 3475 2009-08-28 08:30:47Z kleopatra $ + * + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package org.jdesktop.swingx; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.JPanel; +import javax.swing.event.MouseInputAdapter; + +import org.jdesktop.swingx.MultiSplitLayout.Divider; +import org.jdesktop.swingx.MultiSplitLayout.Node; +import org.jdesktop.swingx.painter.AbstractPainter; +import org.jdesktop.swingx.painter.Painter; + +/** + * + *

+ * All properties in this class are bound: when a properties value + * is changed, all PropertyChangeListeners are fired. + * + * @author Hans Muller + * @author Luan O'Carroll + */ +public class JXMultiSplitPane extends JPanel { + private AccessibleContext accessibleContext = null; + private boolean continuousLayout = true; + private DividerPainter dividerPainter = new DefaultDividerPainter(); + private Painter backgroundPainter; + + /** + * Creates a MultiSplitPane with it's LayoutManager set to + * to an empty MultiSplitLayout. + */ + public JXMultiSplitPane() { + this(new MultiSplitLayout()); + } + + /** + * Creates a MultiSplitPane. + * @param layout the new split pane's layout + */ + public JXMultiSplitPane( MultiSplitLayout layout ) { + super(layout); + InputHandler inputHandler = new InputHandler(); + addMouseListener(inputHandler); + addMouseMotionListener(inputHandler); + addKeyListener(inputHandler); + setFocusable(true); + } + + /** + * A convenience method that returns the layout manager cast + * to MutliSplitLayout. + * + * @return this MultiSplitPane's layout manager + * @see java.awt.Container#getLayout + * @see #setModel + */ + public final MultiSplitLayout getMultiSplitLayout() { + return (MultiSplitLayout)getLayout(); + } + + /** + * A convenience method that sets the MultiSplitLayout model. + * Equivalent to getMultiSplitLayout.setModel(model) + * + * @param model the root of the MultiSplitLayout model + * @see #getMultiSplitLayout + * @see MultiSplitLayout#setModel + */ + public final void setModel(Node model) { + getMultiSplitLayout().setModel(model); + } + + /** + * A convenience method that sets the MultiSplitLayout dividerSize + * property. Equivalent to + * getMultiSplitLayout().setDividerSize(newDividerSize). + * + * @param dividerSize the value of the dividerSize property + * @see #getMultiSplitLayout + * @see MultiSplitLayout#setDividerSize + */ + public final void setDividerSize(int dividerSize) { + getMultiSplitLayout().setDividerSize(dividerSize); + } + + /** + * A convenience method that returns the MultiSplitLayout dividerSize + * property. Equivalent to + * getMultiSplitLayout().getDividerSize(). + * + * @see #getMultiSplitLayout + * @see MultiSplitLayout#getDividerSize + */ + public final int getDividerSize() { + return getMultiSplitLayout().getDividerSize(); + } + + /** + * Sets the value of the continuousLayout property. + * If true, then the layout is revalidated continuously while + * a divider is being moved. The default value of this property + * is true. + * + * @param continuousLayout value of the continuousLayout property + * @see #isContinuousLayout + */ + public void setContinuousLayout(boolean continuousLayout) { + boolean oldContinuousLayout = isContinuousLayout(); + this.continuousLayout = continuousLayout; + firePropertyChange("continuousLayout", oldContinuousLayout, isContinuousLayout()); + } + + /** + * Returns true if dragging a divider only updates + * the layout when the drag gesture ends (typically, when the + * mouse button is released). + * + * @return the value of the continuousLayout property + * @see #setContinuousLayout + */ + public boolean isContinuousLayout() { + return continuousLayout; + } + + /** + * Returns the Divider that's currently being moved, typically + * because the user is dragging it, or null. + * + * @return the Divider that's being moved or null. + */ + public Divider activeDivider() { + return dragDivider; + } + + /** + * Draws a single Divider. Typically used to specialize the + * way the active Divider is painted. + * + * @see #getDividerPainter + * @see #setDividerPainter + */ + public static abstract class DividerPainter extends AbstractPainter { + } + + private class DefaultDividerPainter extends DividerPainter { + @Override + protected void doPaint(Graphics2D g, Divider divider, int width, int height) { + if ((divider == activeDivider()) && !isContinuousLayout()) { + g.setColor(Color.black); + g.fillRect(0, 0, width, height); + } + } + } + + /** + * The DividerPainter that's used to paint Dividers on this MultiSplitPane. + * This property may be null. + * + * @return the value of the dividerPainter Property + * @see #setDividerPainter + */ + public DividerPainter getDividerPainter() { + return dividerPainter; + } + + /** + * Sets the DividerPainter that's used to paint Dividers on this + * MultiSplitPane. The default DividerPainter only draws + * the activeDivider (if there is one) and then, only if + * continuousLayout is false. The value of this property is + * used by the paintChildren method: Dividers are painted after + * the MultiSplitPane's children have been rendered so that + * the activeDivider can appear "on top of" the children. + * + * @param dividerPainter the value of the dividerPainter property, can be null + * @see #paintChildren + * @see #activeDivider + */ + public void setDividerPainter(DividerPainter dividerPainter) { + DividerPainter old = getDividerPainter(); + this.dividerPainter = dividerPainter; + firePropertyChange("dividerPainter", old, getDividerPainter()); + } + + /** + * Calls the UI delegate's paint method, if the UI delegate + * is non-null. We pass the delegate a copy of the + * Graphics object to protect the rest of the + * paint code from irrevocable changes + * (for example, Graphics.translate). + *

+ * If you override this in a subclass you should not make permanent + * changes to the passed in Graphics. For example, you + * should not alter the clip Rectangle or modify the + * transform. If you need to do these operations you may find it + * easier to create a new Graphics from the passed in + * Graphics and manipulate it. Further, if you do not + * invoker super's implementation you must honor the opaque property, + * that is + * if this component is opaque, you must completely fill in the background + * in a non-opaque color. If you do not honor the opaque property you + * will likely see visual artifacts. + *

+ * The passed in Graphics object might + * have a transform other than the identify transform + * installed on it. In this case, you might get + * unexpected results if you cumulatively apply + * another transform. + * + * @param g the Graphics object to protect + * @see #paint(Graphics) + * @see javax.swing.plaf.ComponentUI + */ + @Override + protected void paintComponent(Graphics g) + { + if (backgroundPainter != null) { + Graphics2D g2 = (Graphics2D)g.create(); + + try { + Insets ins = this.getInsets(); + g2.translate(ins.left, ins.top); + backgroundPainter.paint(g2, this, this.getWidth() - ins.left + - ins.right, this.getHeight() - ins.top - ins.bottom); + } finally { + g2.dispose(); + } + } else { + super.paintComponent(g); + } + } + + /** + * Specifies a Painter to use to paint the background of this JXPanel. + * If p is not null, then setOpaque(false) will be called + * as a side effect. A component should not be opaque if painters are + * being used, because Painters may paint transparent pixels or not + * paint certain pixels, such as around the border insets. + */ + public void setBackgroundPainter(Painter p) + { + Painter old = getBackgroundPainter(); + this.backgroundPainter = p; + + if (p != null) { + setOpaque(false); + } + + firePropertyChange("backgroundPainter", old, getBackgroundPainter()); + repaint(); + } + + public Painter getBackgroundPainter() { + return backgroundPainter; + } + /** + * Uses the DividerPainter (if any) to paint each Divider that + * overlaps the clip Rectangle. This is done after the call to + * super.paintChildren() so that Dividers can be + * rendered "on top of" the children. + *

+ * {@inheritDoc} + */ + @Override + protected void paintChildren(Graphics g) { + super.paintChildren(g); + DividerPainter dp = getDividerPainter(); + Rectangle clipR = g.getClipBounds(); + if ((dp != null) && (clipR != null)) { + MultiSplitLayout msl = getMultiSplitLayout(); + if ( msl.hasModel()) { + for(Divider divider : msl.dividersThatOverlap(clipR)) { + Rectangle bounds = divider.getBounds(); + Graphics cg = g.create( bounds.x, bounds.y, bounds.width, bounds.height ); + try { + dp.paint((Graphics2D)cg, divider, bounds.width, bounds.height ); + } finally { + cg.dispose(); + } + } + } + } + } + + private boolean dragUnderway = false; + private MultiSplitLayout.Divider dragDivider = null; + private Rectangle initialDividerBounds = null; + private boolean oldFloatingDividers = true; + private int dragOffsetX = 0; + private int dragOffsetY = 0; + private int dragMin = -1; + private int dragMax = -1; + + private void startDrag(int mx, int my) { + requestFocusInWindow(); + MultiSplitLayout msl = getMultiSplitLayout(); + MultiSplitLayout.Divider divider = msl.dividerAt(mx, my); + if (divider != null) { + MultiSplitLayout.Node prevNode = divider.previousSibling(); + MultiSplitLayout.Node nextNode = divider.nextSibling(); + if ((prevNode == null) || (nextNode == null)) { + dragUnderway = false; + } + else { + initialDividerBounds = divider.getBounds(); + dragOffsetX = mx - initialDividerBounds.x; + dragOffsetY = my - initialDividerBounds.y; + dragDivider = divider; + + Rectangle prevNodeBounds = prevNode.getBounds(); + Rectangle nextNodeBounds = nextNode.getBounds(); + if (dragDivider.isVertical()) { + dragMin = prevNodeBounds.x; + dragMax = nextNodeBounds.x + nextNodeBounds.width; + dragMax -= dragDivider.getBounds().width; + if ( msl.getLayoutMode() == MultiSplitLayout.USER_MIN_SIZE_LAYOUT ) + dragMax -= msl.getUserMinSize(); + } + else { + dragMin = prevNodeBounds.y; + dragMax = nextNodeBounds.y + nextNodeBounds.height; + dragMax -= dragDivider.getBounds().height; + if ( msl.getLayoutMode() == MultiSplitLayout.USER_MIN_SIZE_LAYOUT ) + dragMax -= msl.getUserMinSize(); + } + + if ( msl.getLayoutMode() == MultiSplitLayout.USER_MIN_SIZE_LAYOUT ) { + dragMin = dragMin + msl.getUserMinSize(); + } + else { + if (dragDivider.isVertical()) { + dragMin = Math.max( dragMin, dragMin + getMinNodeSize(msl,prevNode).width ); + dragMax = Math.min( dragMax, dragMax - getMinNodeSize(msl,nextNode).width ); + + Dimension maxDim = getMaxNodeSize(msl,prevNode); + if ( maxDim != null ) + dragMax = Math.min( dragMax, prevNodeBounds.x + maxDim.width ); + } + else { + dragMin = Math.max( dragMin, dragMin + getMinNodeSize(msl,prevNode).height ); + dragMax = Math.min( dragMax, dragMax - getMinNodeSize(msl,nextNode).height ); + + Dimension maxDim = getMaxNodeSize(msl,prevNode); + if ( maxDim != null ) + dragMax = Math.min( dragMax, prevNodeBounds.y + maxDim.height ); + } + } + + oldFloatingDividers = getMultiSplitLayout().getFloatingDividers(); + getMultiSplitLayout().setFloatingDividers(false); + dragUnderway = true; + } + } + else { + dragUnderway = false; + } + } + + /** + * Set the maximum node size. This method can be overridden to limit the + * size of a node during a drag operation on a divider. When implementing + * this method in a subclass the node instance should be checked, for + * example: + * + * class MyMultiSplitPane extends JXMultiSplitPane + * { + * protected Dimension getMaxNodeSize( MultiSplitLayout msl, Node n ) + * { + * if (( n instanceof Leaf ) && ((Leaf)n).getName().equals( "top" )) + * return msl.maximumNodeSize( n ); + * return null; + * } + * } + * + * @param msl the MultiSplitLayout used by this pane + * @param n the node being resized + * @return the maximum size or null (by default) to ignore the maximum size. + */ + protected Dimension getMaxNodeSize( MultiSplitLayout msl, Node n ) { + return null; + } + + /** + * Set the minimum node size. This method can be overridden to limit the + * size of a node during a drag operation on a divider. + * @param msl the MultiSplitLayout used by this pane + * @param n the node being resized + * @return the maximum size or null (by default) to ignore the maximum size. + */ + protected Dimension getMinNodeSize( MultiSplitLayout msl, Node n ) { + return msl.minimumNodeSize(n); + } + + private void repaintDragLimits() { + Rectangle damageR = dragDivider.getBounds(); + if (dragDivider.isVertical()) { + damageR.x = dragMin; + damageR.width = dragMax - dragMin; + } + else { + damageR.y = dragMin; + damageR.height = dragMax - dragMin; + } + repaint(damageR); + } + + private void updateDrag(int mx, int my) { + if (!dragUnderway) { + return; + } + Rectangle oldBounds = dragDivider.getBounds(); + Rectangle bounds = new Rectangle(oldBounds); + if (dragDivider.isVertical()) { + bounds.x = mx - dragOffsetX; + bounds.x = Math.max(bounds.x, dragMin ); + bounds.x = Math.min(bounds.x, dragMax); + } + else { + bounds.y = my - dragOffsetY; + bounds.y = Math.max(bounds.y, dragMin ); + bounds.y = Math.min(bounds.y, dragMax); + } + dragDivider.setBounds(bounds); + if (isContinuousLayout()) { + revalidate(); + repaintDragLimits(); + } + else { + repaint(oldBounds.union(bounds)); + } + } + + private void clearDragState() { + dragDivider = null; + initialDividerBounds = null; + oldFloatingDividers = true; + dragOffsetX = dragOffsetY = 0; + dragMin = dragMax = -1; + dragUnderway = false; + } + + private void finishDrag(int x, int y) { + if (dragUnderway) { + clearDragState(); + if (!isContinuousLayout()) { + revalidate(); + repaint(); + } + } + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + private void cancelDrag() { + if (dragUnderway) { + dragDivider.setBounds(initialDividerBounds); + getMultiSplitLayout().setFloatingDividers(oldFloatingDividers); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + repaint(); + revalidate(); + clearDragState(); + } + } + + private void updateCursor(int x, int y, boolean show) { + if (dragUnderway) { + return; + } + int cursorID = Cursor.DEFAULT_CURSOR; + if (show) { + MultiSplitLayout.Divider divider = getMultiSplitLayout().dividerAt(x, y); + if (divider != null) { + cursorID = (divider.isVertical()) ? + Cursor.E_RESIZE_CURSOR : + Cursor.N_RESIZE_CURSOR; + } + } + setCursor(Cursor.getPredefinedCursor(cursorID)); + } + + + private class InputHandler extends MouseInputAdapter implements KeyListener { + + @Override + public void mouseEntered(MouseEvent e) { + updateCursor(e.getX(), e.getY(), true); + } + + @Override + public void mouseMoved(MouseEvent e) { + updateCursor(e.getX(), e.getY(), true); + } + + @Override + public void mouseExited(MouseEvent e) { + updateCursor(e.getX(), e.getY(), false); + } + + @Override + public void mousePressed(MouseEvent e) { + startDrag(e.getX(), e.getY()); + } + @Override + public void mouseReleased(MouseEvent e) { + finishDrag(e.getX(), e.getY()); + } + @Override + public void mouseDragged(MouseEvent e) { + updateDrag(e.getX(), e.getY()); + } + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + cancelDrag(); + } + } + public void keyReleased(KeyEvent e) { } + + public void keyTyped(KeyEvent e) { } + } + + @Override + public AccessibleContext getAccessibleContext() { + if( accessibleContext == null ) { + accessibleContext = new AccessibleMultiSplitPane(); + } + return accessibleContext; + } + + protected class AccessibleMultiSplitPane extends AccessibleJPanel { + @Override + public AccessibleRole getAccessibleRole() { + return AccessibleRole.SPLIT_PANE; + } + } +} \ No newline at end of file diff --git a/src/org/jdesktop/swingx/MultiSplitLayout.java b/src/org/jdesktop/swingx/MultiSplitLayout.java index cf078ab6a1c..fba82d3b55e 100644 --- a/src/org/jdesktop/swingx/MultiSplitLayout.java +++ b/src/org/jdesktop/swingx/MultiSplitLayout.java @@ -1,5 +1,5 @@ /* - * $Id: MultiSplitLayout.java,v 1.15 2005/10/26 14:29:54 hansmuller Exp $ + * $Id: MultiSplitLayout.java 3471 2009-08-27 13:10:39Z kleopatra $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. @@ -8,12 +8,12 @@ * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA @@ -34,12 +34,14 @@ import java.io.Reader; import java.io.StreamTokenizer; import java.io.StringReader; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; + import javax.swing.UIManager; @@ -47,1312 +49,2167 @@ import javax.swing.UIManager; * The MultiSplitLayout layout manager recursively arranges its * components in row and column groups called "Splits". Elements of * the layout are separated by gaps called "Dividers". The overall - * layout is defined with a simple tree model whose nodes are - * instances of MultiSplitLayout.Split, MultiSplitLayout.Divider, - * and MultiSplitLayout.Leaf. Named Leaf nodes represent the space + * layout is defined with a simple tree model whose nodes are + * instances of MultiSplitLayout.Split, MultiSplitLayout.Divider, + * and MultiSplitLayout.Leaf. Named Leaf nodes represent the space * allocated to a component that was added with a constraint that * matches the Leaf's name. Extra space is distributed * among row/column siblings according to their 0.0 to 1.0 weight. * If no weights are specified then the last sibling always gets * all of the extra space, or space reduction. - * + * *

* Although MultiSplitLayout can be used with any Container, it's * the default layout manager for MultiSplitPane. MultiSplitPane - * supports interactively dragging the Dividers, accessibility, + * supports interactively dragging the Dividers, accessibility, * and other features associated with split panes. - * + * *

* All properties in this class are bound: when a properties value * is changed, all PropertyChangeListeners are fired. + * * - * @author Hans Muller - * @see MultiSplitPane + * @author Hans Muller + * @author Luan O'Carroll + * @see JXMultiSplitPane */ -public class MultiSplitLayout implements LayoutManager { - private final Map childMap = new HashMap(); - private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); - private Node model; - private int dividerSize; - private boolean floatingDividers = true; +/* + * Changes by Luan O'Carroll + * 1 Support for visibility added. + */ +public class MultiSplitLayout implements LayoutManager +{ + public static final int DEFAULT_LAYOUT = 0; + public static final int NO_MIN_SIZE_LAYOUT = 1; + public static final int USER_MIN_SIZE_LAYOUT = 2; - /** - * Create a MultiSplitLayout with a default model with a single - * Leaf node named "default". - * - * #see setModel - */ - public MultiSplitLayout() { - this(new Leaf("default")); + private final Map childMap = new HashMap(); + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private Node model; + private int dividerSize; + private boolean floatingDividers = true; + + private boolean removeDividers = true; + private boolean layoutByWeight = false; + + private int layoutMode; + private int userMinSize = 20; + + /** + * Create a MultiSplitLayout with a default model with a single + * Leaf node named "default". + * + * #see setModel + */ + public MultiSplitLayout() + { + this(new Leaf("default")); + } + + /** + * Create a MultiSplitLayout with a default model with a single + * Leaf node named "default". + * + * @param layoutByWeight if true the layout is initialized in proportion to + * the node weights rather than the component preferred sizes. + * #see setModel + */ + public MultiSplitLayout(boolean layoutByWeight) + { + this(new Leaf("default")); + this.layoutByWeight = layoutByWeight; + } + + /** + * Set the size of the child components to match the weights of the children. + * If the components to not all specify a weight then the available layout + * space is divided equally between the components. + */ + public void layoutByWeight( Container parent ) + { + doLayoutByWeight( parent ); + + layoutContainer( parent ); + } + + /** + * Set the size of the child components to match the weights of the children. + * If the components to not all specify a weight then the available layout + * space is divided equally between the components. + */ + private void doLayoutByWeight( Container parent ) + { + Dimension size = parent.getSize(); + Insets insets = parent.getInsets(); + int width = size.width - (insets.left + insets.right); + int height = size.height - (insets.top + insets.bottom); + Rectangle bounds = new Rectangle(insets.left, insets.top, width, height); + + if (model instanceof Leaf) + model.setBounds(bounds); + else if (model instanceof Split) + doLayoutByWeight( model, bounds ); + } + + private void doLayoutByWeight( Node node, Rectangle bounds ) + { + int width = bounds.width; + int height = bounds.height; + Split split = (Split)node; + List splitChildren = split.getChildren(); + double distributableWeight = 1.0; + int unweightedComponents = 0; + int dividerSpace = 0; + for( Node splitChild : splitChildren ) { + if ( !splitChild.isVisible()) + continue; + else if ( splitChild instanceof Divider ) { + dividerSpace += dividerSize; + continue; + } + + double weight = splitChild.getWeight(); + if ( weight > 0.0 ) + distributableWeight -= weight; + else + unweightedComponents++; + } + + if ( split.isRowLayout()) { + width -= dividerSpace; + double distributableWidth = width * distributableWeight; + for( Node splitChild : splitChildren ) { + if ( !splitChild.isVisible() || ( splitChild instanceof Divider )) + continue; + + double weight = splitChild.getWeight(); + Rectangle splitChildBounds = splitChild.getBounds(); + if ( weight >= 0 ) + splitChildBounds = new Rectangle( splitChildBounds.x, splitChildBounds.y, (int)( width * weight ), height ); + else + splitChildBounds = new Rectangle( splitChildBounds.x, splitChildBounds.y, (int)( distributableWidth / unweightedComponents ), height ); + + if ( layoutMode == USER_MIN_SIZE_LAYOUT ) { + splitChildBounds.setSize( Math.max( splitChildBounds.width, userMinSize ), splitChildBounds.height ); + } + + splitChild.setBounds( splitChildBounds ); + + if ( splitChild instanceof Split ) + doLayoutByWeight( splitChild, splitChildBounds ); + else { + Component comp = getComponentForNode( splitChild ); + if ( comp != null ) + comp.setPreferredSize( splitChildBounds.getSize()); + } + } + } + else { + height -= dividerSpace; + double distributableHeight = height * distributableWeight; + for( Node splitChild : splitChildren ) { + if ( !splitChild.isVisible() || ( splitChild instanceof Divider )) + continue; + + double weight = splitChild.getWeight(); + Rectangle splitChildBounds = splitChild.getBounds(); + if ( weight >= 0 ) + splitChildBounds = new Rectangle( splitChildBounds.x, splitChildBounds.y, width, (int)( height * weight )); + else + splitChildBounds = new Rectangle( splitChildBounds.x, splitChildBounds.y, width, (int)( distributableHeight / unweightedComponents )); + + if ( layoutMode == USER_MIN_SIZE_LAYOUT ) { + splitChildBounds.setSize( splitChildBounds.width, Math.max( splitChildBounds.height, userMinSize ) ); + } + + splitChild.setBounds( splitChildBounds ); + + if ( splitChild instanceof Split ) + doLayoutByWeight( splitChild, splitChildBounds ); + else { + Component comp = getComponentForNode( splitChild ); + if ( comp != null ) + comp.setPreferredSize( splitChildBounds.getSize()); + } + } + } + } + + /** + * Get the component associated with a MultiSplitLayout.Node + * @param n the layout node + * @return the component handled by the layout or null if not found + */ + public Component getComponentForNode( Node n ) + { + String name = ((Leaf)n).getName(); + return (name != null) ? (Component)childMap.get(name) : null; + } + + /** + * Get the MultiSplitLayout.Node associated with a component + * @param comp the component being positioned by the layout + * @return the node associated with the component + */ + public Node getNodeForComponent( Component comp ) + { + return getNodeForName( getNameForComponent( comp )); + } + + /** + * Get the MultiSplitLayout.Node associated with a component + * @param name the name used to associate a component with the layout + * @return the node associated with the component + */ + public Node getNodeForName( String name ) + { + if ( model instanceof Split ) { + Split split = ((Split)model); + return getNodeForName( split, name ); + } + else + return null; + } + + /** + * Get the name used to map a component + * @param child the component + * @return the name used to map the component or null if no mapping is found + */ + public String getNameForComponent( Component child ) + { + String name = null; + for(Map.Entry kv : childMap.entrySet()) { + if (kv.getValue() == child) { + name = kv.getKey(); + break; + } } - /** - * Create a MultiSplitLayout with the specified model. - * - * #see setModel - */ - public MultiSplitLayout(Node model) { - this.model = model; - this.dividerSize = UIManager.getInt("SplitPane.dividerSize"); - if (this.dividerSize == 0) { - this.dividerSize = 7; + return name; + } + + /** + * Get the MultiSplitLayout.Node associated with a component + * @param split the layout split that owns the requested node + * @param comp the component being positioned by the layout + * @return the node associated with the component + */ + public Node getNodeForComponent( Split split, Component comp ) + { + return getNodeForName( split, getNameForComponent( comp )); + } + + /** + * Get the MultiSplitLayout.Node associated with a component + * @param split the layout split that owns the requested node + * @param name the name used to associate a component with the layout + * @return the node associated with the component + */ + public Node getNodeForName( Split split, String name ) + { + for(Node n : split.getChildren()) { + if ( n instanceof Leaf ) { + if ( ((Leaf)n).getName().equals( name )) + return n; } - } - - public void addPropertyChangeListener(PropertyChangeListener listener) { - if (listener != null) { - pcs.addPropertyChangeListener(listener); + else if ( n instanceof Split ) { + Node n1 = getNodeForName( (Split)n, name ); + if ( n1 != null ) + return n1; } + } + return null; + } + + /** + * Is there a valid model for the layout? + * @return true if there is a model + */ + public boolean hasModel() + { + return model != null; + } + + /** + * Create a MultiSplitLayout with the specified model. + * + * #see setModel + */ + public MultiSplitLayout(Node model) { + this.model = model; + this.dividerSize = UIManager.getInt("SplitPane.dividerSize"); + if (this.dividerSize == 0) { + this.dividerSize = 7; } - public void removePropertyChangeListener(PropertyChangeListener listener) { - if (listener != null) { - pcs.removePropertyChangeListener(listener); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + if (listener != null) { + pcs.addPropertyChangeListener(listener); + } + } + public void removePropertyChangeListener(PropertyChangeListener listener) { + if (listener != null) { + pcs.removePropertyChangeListener(listener); + } + } + public PropertyChangeListener[] getPropertyChangeListeners() { + return pcs.getPropertyChangeListeners(); + } + + private void firePCS(String propertyName, Object oldValue, Object newValue) { + if (!(oldValue != null && newValue != null && oldValue.equals(newValue))) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + } + + /** + * Return the root of the tree of Split, Leaf, and Divider nodes + * that define this layout. + * + * @return the value of the model property + * @see #setModel + */ + public Node getModel() { return model; } + + /** + * Set the root of the tree of Split, Leaf, and Divider nodes + * that define this layout. The model can be a Split node + * (the typical case) or a Leaf. The default value of this + * property is a Leaf named "default". + * + * @param model the root of the tree of Split, Leaf, and Divider node + * @throws IllegalArgumentException if model is a Divider or null + * @see #getModel + */ + public void setModel(Node model) { + if ((model == null) || (model instanceof Divider)) { + throw new IllegalArgumentException("invalid model"); + } + Node oldModel = getModel(); + this.model = model; + firePCS("model", oldModel, getModel()); + } + + /** + * Returns the width of Dividers in Split rows, and the height of + * Dividers in Split columns. + * + * @return the value of the dividerSize property + * @see #setDividerSize + */ + public int getDividerSize() { return dividerSize; } + + /** + * Sets the width of Dividers in Split rows, and the height of + * Dividers in Split columns. The default value of this property + * is the same as for JSplitPane Dividers. + * + * @param dividerSize the size of dividers (pixels) + * @throws IllegalArgumentException if dividerSize < 0 + * @see #getDividerSize + */ + public void setDividerSize(int dividerSize) { + if (dividerSize < 0) { + throw new IllegalArgumentException("invalid dividerSize"); + } + int oldDividerSize = this.dividerSize; + this.dividerSize = dividerSize; + firePCS("dividerSize", new Integer( oldDividerSize ), new Integer( dividerSize )); + } + + /** + * @return the value of the floatingDividers property + * @see #setFloatingDividers + */ + public boolean getFloatingDividers() { return floatingDividers; } + + + /** + * If true, Leaf node bounds match the corresponding component's + * preferred size and Splits/Dividers are resized accordingly. + * If false then the Dividers define the bounds of the adjacent + * Split and Leaf nodes. Typically this property is set to false + * after the (MultiSplitPane) user has dragged a Divider. + * + * @see #getFloatingDividers + */ + public void setFloatingDividers(boolean floatingDividers) + { + boolean oldFloatingDividers = this.floatingDividers; + this.floatingDividers = floatingDividers; + firePCS("floatingDividers", new Boolean( oldFloatingDividers ), new Boolean( floatingDividers )); + } + + /** + * @return the value of the removeDividers property + * @see #setRemoveDividers + */ + public boolean getRemoveDividers() { return removeDividers; } + + /** + * If true, the next divider is removed when a component is removed from the + * layout. If false, only the node itself is removed. Normally the next + * divider should be removed from the layout when a component is removed. + * @param removeDividers true to removed the next divider whena component is + * removed from teh layout + */ + public void setRemoveDividers( boolean removeDividers ) + { + boolean oldRemoveDividers = this.removeDividers; + this.removeDividers = removeDividers; + firePCS("removeDividers", new Boolean( oldRemoveDividers ), new Boolean( removeDividers )); + } + + /** + * Add a component to this MultiSplitLayout. The + * name should match the name property of the Leaf + * node that represents the bounds of child. After + * layoutContainer() recomputes the bounds of all of the nodes in + * the model, it will set this child's bounds to the bounds of the + * Leaf node with name. Note: if a component was already + * added with the same name, this method does not remove it from + * its parent. + * + * @param name identifies the Leaf node that defines the child's bounds + * @param child the component to be added + * @see #removeLayoutComponent + */ + public void addLayoutComponent(String name, Component child) { + if (name == null) { + throw new IllegalArgumentException("name not specified"); + } + childMap.put(name, child); + } + + /** + * Removes the specified component from the layout. + * + * @param child the component to be removed + * @see #addLayoutComponent + */ + public void removeLayoutComponent(Component child) { + String name = getNameForComponent( child ); + + if ( name != null ) { + childMap.remove( name ); + } + } + + /** + * Removes the specified node from the layout. + * + * @param name the name of the component to be removed + * @see #addLayoutComponent + */ + public void removeLayoutNode(String name) { + + if ( name != null ) { + Node n; + if ( !( model instanceof Split )) + n = model; + else + n = getNodeForName( name ); + + childMap.remove(name); + + if ( n != null ) { + Split s = n.getParent(); + s.remove( n ); + if (removeDividers) { + while ( s.getChildren().size() < 2 ) { + Split p = s.getParent(); + if ( p == null ) { + if ( s.getChildren().size() > 0 ) + model = (Node)s.getChildren().get( 0 ); + else + model = null; + return; + } + if ( s.getChildren().size() == 1 ) { + Node next = s.getChildren().get( 0 ); + p.replace( s, next ); + next.setParent( p ); + } + else + p.remove( s ); + s = p; + } } + } + else { + childMap.remove( name ); + } } - public PropertyChangeListener[] getPropertyChangeListeners() { - return pcs.getPropertyChangeListeners(); - } + } + + /** + * Show/Hide nodes. Any dividers that are no longer required due to one of the + * nodes being made visible/invisible are also shown/hidder. The visibility of + * the component managed by the node is also changed by this method + * @param name the node name + * @param visible the new node visible state + */ + public void displayNode( String name, boolean visible ) + { + Node node = getNodeForName( name ); + if ( node != null ) { + Component comp = getComponentForNode( node ); + comp.setVisible( visible ); + node.setVisible( visible ); + + MultiSplitLayout.Split p = node.getParent(); + if ( !visible ) { + p.hide( node ); + if ( !p.isVisible()) + p.getParent().hide( p ); - private void firePCS(String propertyName, Object oldValue, Object newValue) { - if (!(oldValue != null && newValue != null && oldValue.equals(newValue))) { - pcs.firePropertyChange(propertyName, oldValue, newValue); + p.checkDividers( p ); + // If the split has become invisible then the parent may also have a + // divider that needs to be hidden. + while ( !p.isVisible()) { + p = p.getParent(); + if ( p != null ) + p.checkDividers( p ); + else + break; } + } + else + p.restoreDividers( p ); } - - /** - * Return the root of the tree of Split, Leaf, and Divider nodes - * that define this layout. - * - * @return the value of the model property - * @see #setModel - */ - public Node getModel() { return model; } - - /** - * Set the root of the tree of Split, Leaf, and Divider nodes - * that define this layout. The model can be a Split node - * (the typical case) or a Leaf. The default value of this - * property is a Leaf named "default". - * - * @param model the root of the tree of Split, Leaf, and Divider node - * @throws IllegalArgumentException if model is a Divider or null - * @see #getModel - */ - public void setModel(Node model) { - if ((model == null) || (model instanceof Divider)) { - throw new IllegalArgumentException("invalid model"); - } - Node oldModel = model; - this.model = model; - firePCS("model", oldModel, model); + setFloatingDividers( false ); + } + + private Component childForNode(Node node) { + if (node instanceof Leaf) { + Leaf leaf = (Leaf)node; + String name = leaf.getName(); + return (name != null) ? childMap.get(name) : null; } + return null; + } + + + private Dimension preferredComponentSize(Node node) { + if ( layoutMode == NO_MIN_SIZE_LAYOUT ) + return new Dimension(0, 0); - /** - * Returns the width of Dividers in Split rows, and the height of - * Dividers in Split columns. - * - * @return the value of the dividerSize property - * @see #setDividerSize - */ - public int getDividerSize() { return dividerSize; } + Component child = childForNode(node); + return ((child != null) && child.isVisible() ) ? child.getPreferredSize() : new Dimension(0, 0); + } + + private Dimension minimumComponentSize(Node node) { + if ( layoutMode == NO_MIN_SIZE_LAYOUT ) + return new Dimension(0, 0); - /** - * Sets the width of Dividers in Split rows, and the height of - * Dividers in Split columns. The default value of this property - * is the same as for JSplitPane Dividers. - * - * @param dividerSize the size of dividers (pixels) - * @throws IllegalArgumentException if dividerSize < 0 - * @see #getDividerSize - */ - public void setDividerSize(int dividerSize) { - if (dividerSize < 0) { - throw new IllegalArgumentException("invalid dividerSize"); - } - int oldDividerSize = this.dividerSize; - this.dividerSize = dividerSize; - firePCS("dividerSize", oldDividerSize, dividerSize); + Component child = childForNode(node); + return ((child != null) && child.isVisible() ) ? child.getMinimumSize() : new Dimension(0, 0); + } + + private Dimension preferredNodeSize(Node root) { + if (root instanceof Leaf) { + return preferredComponentSize(root); } - - /** - * @return the value of the floatingDividers property - * @see #setFloatingDividers - */ - public boolean getFloatingDividers() { return floatingDividers; } - - - /** - * If true, Leaf node bounds match the corresponding component's - * preferred size and Splits/Dividers are resized accordingly. - * If false then the Dividers define the bounds of the adjacent - * Split and Leaf nodes. Typically this property is set to false - * after the (MultiSplitPane) user has dragged a Divider. - * - * @see #getFloatingDividers - */ - public void setFloatingDividers(boolean floatingDividers) { - boolean oldFloatingDividers = this.floatingDividers; - this.floatingDividers = floatingDividers; - firePCS("floatingDividers", oldFloatingDividers, floatingDividers); + else if (root instanceof Divider) { + if ( !((Divider)root).isVisible()) + return new Dimension(0,0); + int divSize = getDividerSize(); + return new Dimension(divSize, divSize); } - - - /** - * Add a component to this MultiSplitLayout. The - * name should match the name property of the Leaf - * node that represents the bounds of child. After - * layoutContainer() recomputes the bounds of all of the nodes in - * the model, it will set this child's bounds to the bounds of the - * Leaf node with name. Note: if a component was already - * added with the same name, this method does not remove it from - * its parent. - * - * @param name identifies the Leaf node that defines the child's bounds - * @param child the component to be added - * @see #removeLayoutComponent - */ - public void addLayoutComponent(String name, Component child) { - if (name == null) { - throw new IllegalArgumentException("name not specified"); - } - childMap.put(name, child); + else { + Split split = (Split)root; + List splitChildren = split.getChildren(); + int width = 0; + int height = 0; + if (split.isRowLayout()) { + for(Node splitChild : splitChildren) { + if ( !splitChild.isVisible()) + continue; + Dimension size = preferredNodeSize(splitChild); + width += size.width; + height = Math.max(height, size.height); + } + } + else { + for(Node splitChild : splitChildren) { + if ( !splitChild.isVisible()) + continue; + Dimension size = preferredNodeSize(splitChild); + width = Math.max(width, size.width); + height += size.height; + } + } + return new Dimension(width, height); } + } + + /** + * Get the minimum size of this node. Sums the minumum sizes of rows or + * columns to get the overall minimum size for the layout node, including the + * dividers. + * @param root the node whose size is required. + * @return the minimum size. + */ + public Dimension minimumNodeSize(Node root) { + assert( root.isVisible ); + if (root instanceof Leaf) { + if ( layoutMode == NO_MIN_SIZE_LAYOUT ) + return new Dimension(0, 0); - /** - * Removes the specified component from the layout. - * - * @param child the component to be removed - * @see #addLayoutComponent - */ - public void removeLayoutComponent(Component child) { - String name = child.getName(); - if (name != null) { - childMap.remove(name); - } + Component child = childForNode(root); + return ((child != null) && child.isVisible() ) ? child.getMinimumSize() : new Dimension(0, 0); } - - private Component childForNode(Node node) { - if (node instanceof Leaf) { - Leaf leaf = (Leaf)node; - String name = leaf.getName(); - return (name != null) ? childMap.get(name) : null; - } - return null; + else if (root instanceof Divider) { + if ( !((Divider)root).isVisible() ) + return new Dimension(0,0); + int divSize = getDividerSize(); + return new Dimension(divSize, divSize); } - - - private Dimension preferredComponentSize(Node node) { - Component child = childForNode(node); - return (child != null) ? child.getPreferredSize() : new Dimension(0, 0); - + else { + Split split = (Split)root; + List splitChildren = split.getChildren(); + int width = 0; + int height = 0; + if (split.isRowLayout()) { + for(Node splitChild : splitChildren) { + if ( !splitChild.isVisible()) + continue; + Dimension size = minimumNodeSize(splitChild); + width += size.width; + height = Math.max(height, size.height); + } + } + else { + for(Node splitChild : splitChildren) { + if ( !splitChild.isVisible()) + continue; + Dimension size = minimumNodeSize(splitChild); + width = Math.max(width, size.width); + height += size.height; + } + } + return new Dimension(width, height); } - - @SuppressWarnings("unused") - private Dimension minimumComponentSize(Node node) { - Component child = childForNode(node); - return (child != null) ? child.getMinimumSize() : new Dimension(0, 0); - + } + + /** + * Get the maximum size of this node. Sums the minumum sizes of rows or + * columns to get the overall maximum size for the layout node, including the + * dividers. + * @param root the node whose size is required. + * @return the minimum size. + */ + public Dimension maximumNodeSize(Node root) { + assert( root.isVisible ); + if (root instanceof Leaf) { + Component child = childForNode(root); + return ((child != null) && child.isVisible() ) ? child.getMaximumSize() : new Dimension(0, 0); } - - private Dimension preferredNodeSize(Node root) { - if (root instanceof Leaf) { - return preferredComponentSize(root); - } - else if (root instanceof Divider) { - int dividerSize = getDividerSize(); - return new Dimension(dividerSize, dividerSize); - } - else { - Split split = (Split)root; - List splitChildren = split.getChildren(); - int width = 0; - int height = 0; - if (split.isRowLayout()) { - for(Node splitChild : splitChildren) { - Dimension size = preferredNodeSize(splitChild); - width += size.width; - height = Math.max(height, size.height); - } - } - else { - for(Node splitChild : splitChildren) { - Dimension size = preferredNodeSize(splitChild); - width = Math.max(width, size.width); - height += size.height; - } - } - return new Dimension(width, height); - } + else if (root instanceof Divider) { + if ( !((Divider)root).isVisible() ) + return new Dimension(0,0); + int divSize = getDividerSize(); + return new Dimension(divSize, divSize); } - - private Dimension minimumNodeSize(Node root) { - if (root instanceof Leaf) { - Component child = childForNode(root); - return (child != null) ? child.getMinimumSize() : new Dimension(0, 0); - } - else if (root instanceof Divider) { - int dividerSize = getDividerSize(); - return new Dimension(dividerSize, dividerSize); - } - else { - Split split = (Split)root; - List splitChildren = split.getChildren(); - int width = 0; - int height = 0; - if (split.isRowLayout()) { - for(Node splitChild : splitChildren) { - Dimension size = minimumNodeSize(splitChild); - width += size.width; - height = Math.max(height, size.height); - } - } - else { - for(Node splitChild : splitChildren) { - Dimension size = minimumNodeSize(splitChild); - width = Math.max(width, size.width); - height += size.height; - } - } - return new Dimension(width, height); - } + else { + Split split = (Split)root; + List splitChildren = split.getChildren(); + int width = Integer.MAX_VALUE; + int height = Integer.MAX_VALUE; + if (split.isRowLayout()) { + for(Node splitChild : splitChildren) { + if ( !splitChild.isVisible()) + continue; + Dimension size = maximumNodeSize(splitChild); + width += size.width; + height = Math.min(height, size.height); + } + } + else { + for(Node splitChild : splitChildren) { + if ( !splitChild.isVisible()) + continue; + Dimension size = maximumNodeSize(splitChild); + width = Math.min(width, size.width); + height += size.height; + } + } + return new Dimension(width, height); } - - private Dimension sizeWithInsets(Container parent, Dimension size) { - Insets insets = parent.getInsets(); - int width = size.width + insets.left + insets.right; - int height = size.height + insets.top + insets.bottom; - return new Dimension(width, height); + } + + private Dimension sizeWithInsets(Container parent, Dimension size) { + Insets insets = parent.getInsets(); + int width = size.width + insets.left + insets.right; + int height = size.height + insets.top + insets.bottom; + return new Dimension(width, height); + } + + public Dimension preferredLayoutSize(Container parent) { + Dimension size = preferredNodeSize(getModel()); + return sizeWithInsets(parent, size); + } + + public Dimension minimumLayoutSize(Container parent) { + Dimension size = minimumNodeSize(getModel()); + return sizeWithInsets(parent, size); + } + + + private Rectangle boundsWithYandHeight(Rectangle bounds, double y, double height) { + Rectangle r = new Rectangle(); + r.setBounds((int)(bounds.getX()), (int)y, (int)(bounds.getWidth()), (int)height); + return r; + } + + private Rectangle boundsWithXandWidth(Rectangle bounds, double x, double width) { + Rectangle r = new Rectangle(); + r.setBounds((int)x, (int)(bounds.getY()), (int)width, (int)(bounds.getHeight())); + return r; + } + + + private void minimizeSplitBounds(Split split, Rectangle bounds) { + assert ( split.isVisible()); + Rectangle splitBounds = new Rectangle(bounds.x, bounds.y, 0, 0); + List splitChildren = split.getChildren(); + Node lastChild = null; + int lastVisibleChildIdx = splitChildren.size(); + do { + lastVisibleChildIdx--; + lastChild = splitChildren.get( lastVisibleChildIdx ); + } while (( lastVisibleChildIdx > 0 ) && !lastChild.isVisible()); + + if ( !lastChild.isVisible()) + return; + if ( lastVisibleChildIdx >= 0 ) { + Rectangle lastChildBounds = lastChild.getBounds(); + if (split.isRowLayout()) { + int lastChildMaxX = lastChildBounds.x + lastChildBounds.width; + splitBounds.add(lastChildMaxX, bounds.y + bounds.height); + } + else { + int lastChildMaxY = lastChildBounds.y + lastChildBounds.height; + splitBounds.add(bounds.x + bounds.width, lastChildMaxY); + } } - - public Dimension preferredLayoutSize(Container parent) { - Dimension size = preferredNodeSize(getModel()); - return sizeWithInsets(parent, size); + split.setBounds(splitBounds); + } + + + private void layoutShrink(Split split, Rectangle bounds) { + Rectangle splitBounds = split.getBounds(); + ListIterator splitChildren = split.getChildren().listIterator(); + Node lastWeightedChild = split.lastWeightedChild(); + + if (split.isRowLayout()) { + int totalWidth = 0; // sum of the children's widths + int minWeightedWidth = 0; // sum of the weighted childrens' min widths + int totalWeightedWidth = 0; // sum of the weighted childrens' widths + for(Node splitChild : split.getChildren()) { + if ( !splitChild.isVisible()) + continue; + int nodeWidth = splitChild.getBounds().width; + int nodeMinWidth = 0; + if (( layoutMode == USER_MIN_SIZE_LAYOUT ) && !( splitChild instanceof Divider )) + nodeMinWidth = userMinSize; + else if ( layoutMode == DEFAULT_LAYOUT ) + nodeMinWidth = Math.min(nodeWidth, minimumNodeSize(splitChild).width); + totalWidth += nodeWidth; + if (splitChild.getWeight() > 0.0) { + minWeightedWidth += nodeMinWidth; + totalWeightedWidth += nodeWidth; + } + } + + double x = bounds.getX(); + double extraWidth = splitBounds.getWidth() - bounds.getWidth(); + double availableWidth = extraWidth; + boolean onlyShrinkWeightedComponents = + (totalWeightedWidth - minWeightedWidth) > extraWidth; + + while(splitChildren.hasNext()) { + Node splitChild = splitChildren.next(); + if ( !splitChild.isVisible()) { + if ( splitChildren.hasNext()) + splitChildren.next(); + continue; + } + Rectangle splitChildBounds = splitChild.getBounds(); + double minSplitChildWidth = 0.0; + if (( layoutMode == USER_MIN_SIZE_LAYOUT ) && !( splitChild instanceof Divider )) + minSplitChildWidth = userMinSize; + else if ( layoutMode == DEFAULT_LAYOUT ) + minSplitChildWidth = minimumNodeSize(splitChild).getWidth(); + double splitChildWeight = (onlyShrinkWeightedComponents) + ? splitChild.getWeight() + : (splitChildBounds.getWidth() / (double)totalWidth); + + if (!splitChildren.hasNext()) { + double newWidth = Math.max(minSplitChildWidth, bounds.getMaxX() - x); + Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); + layout2(splitChild, newSplitChildBounds); + } + if ( splitChild.isVisible()) { + if ((availableWidth > 0.0) && (splitChildWeight > 0.0)) { + double oldWidth = splitChildBounds.getWidth(); + double newWidth; + if ( splitChild instanceof Divider ) { + newWidth = dividerSize; + } + else { + double allocatedWidth = Math.rint(splitChildWeight * extraWidth); + newWidth = Math.max(minSplitChildWidth, oldWidth - allocatedWidth); + } + Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); + layout2(splitChild, newSplitChildBounds); + availableWidth -= (oldWidth - splitChild.getBounds().getWidth()); + } + else { + double existingWidth = splitChildBounds.getWidth(); + Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, existingWidth); + layout2(splitChild, newSplitChildBounds); + } + x = splitChild.getBounds().getMaxX(); + } + } } - - public Dimension minimumLayoutSize(Container parent) { - Dimension size = minimumNodeSize(getModel()); - return sizeWithInsets(parent, size); + + else { + int totalHeight = 0; // sum of the children's heights + int minWeightedHeight = 0; // sum of the weighted childrens' min heights + int totalWeightedHeight = 0; // sum of the weighted childrens' heights + for(Node splitChild : split.getChildren()) { + if ( !splitChild.isVisible()) + continue; + int nodeHeight = splitChild.getBounds().height; + int nodeMinHeight = 0; + if (( layoutMode == USER_MIN_SIZE_LAYOUT ) && !( splitChild instanceof Divider )) + nodeMinHeight = userMinSize; + else if ( layoutMode == DEFAULT_LAYOUT ) + nodeMinHeight = Math.min(nodeHeight, minimumNodeSize(splitChild).height); + totalHeight += nodeHeight; + if (splitChild.getWeight() > 0.0) { + minWeightedHeight += nodeMinHeight; + totalWeightedHeight += nodeHeight; + } + } + + double y = bounds.getY(); + double extraHeight = splitBounds.getHeight() - bounds.getHeight(); + double availableHeight = extraHeight; + boolean onlyShrinkWeightedComponents = + (totalWeightedHeight - minWeightedHeight) > extraHeight; + + while(splitChildren.hasNext()) { + Node splitChild = splitChildren.next(); + if ( !splitChild.isVisible()) { + if ( splitChildren.hasNext()) + splitChildren.next(); + continue; + } + Rectangle splitChildBounds = splitChild.getBounds(); + double minSplitChildHeight = 0.0; + if (( layoutMode == USER_MIN_SIZE_LAYOUT ) && !( splitChild instanceof Divider )) + minSplitChildHeight = userMinSize; + else if ( layoutMode == DEFAULT_LAYOUT ) + minSplitChildHeight = minimumNodeSize(splitChild).getHeight(); + double splitChildWeight = (onlyShrinkWeightedComponents) + ? splitChild.getWeight() + : (splitChildBounds.getHeight() / (double)totalHeight); + + // If this split child is the last visible node it should all the + // remaining space + if ( !hasMoreVisibleSiblings( splitChild )) { + double oldHeight = splitChildBounds.getHeight(); + double newHeight; + if ( splitChild instanceof Divider ) { + newHeight = dividerSize; + } + else { + newHeight = Math.max(minSplitChildHeight, bounds.getMaxY() - y); + } + Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); + layout2(splitChild, newSplitChildBounds); + availableHeight -= (oldHeight - splitChild.getBounds().getHeight()); + } + else /*if ( splitChild.isVisible()) {*/ + if ((availableHeight > 0.0) && (splitChildWeight > 0.0)) { + double newHeight; + double oldHeight = splitChildBounds.getHeight(); + // Prevent the divider from shrinking + if ( splitChild instanceof Divider ) { + newHeight = dividerSize; + } + else { + double allocatedHeight = Math.rint(splitChildWeight * extraHeight); + newHeight = Math.max(minSplitChildHeight, oldHeight - allocatedHeight); + } + Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); + layout2(splitChild, newSplitChildBounds); + availableHeight -= (oldHeight - splitChild.getBounds().getHeight()); + } + else { + double existingHeight = splitChildBounds.getHeight(); + Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, existingHeight); + layout2(splitChild, newSplitChildBounds); + } + y = splitChild.getBounds().getMaxY(); + } } - - - private Rectangle boundsWithYandHeight(Rectangle bounds, double y, double height) { - Rectangle r = new Rectangle(); - r.setBounds((int)(bounds.getX()), (int)y, (int)(bounds.getWidth()), (int)height); - return r; + + /* The bounds of the Split node root are set to be + * big enough to contain all of its children. Since + * Leaf children can't be reduced below their + * (corresponding java.awt.Component) minimum sizes, + * the size of the Split's bounds maybe be larger than + * the bounds we were asked to fit within. + */ + minimizeSplitBounds(split, bounds); + } + + /** + * Check if the specified node has any following visible siblings + * @param splitChild the node to check + * @param true if there are visible children following + */ + private boolean hasMoreVisibleSiblings( Node splitChild ) { + Node next = splitChild.nextSibling(); + if ( next == null ) + return false; + + do { + if ( next.isVisible()) + return true; + next = next.nextSibling(); + } while ( next != null ); + + return false; + } + + private void layoutGrow(Split split, Rectangle bounds) { + Rectangle splitBounds = split.getBounds(); + ListIterator splitChildren = split.getChildren().listIterator(); + Node lastWeightedChild = split.lastWeightedChild(); + + /* Layout the Split's child Nodes' along the X axis. The bounds + * of each child will have the same y coordinate and height as the + * layoutGrow() bounds argument. Extra width is allocated to the + * to each child with a non-zero weight: + * newWidth = currentWidth + (extraWidth * splitChild.getWeight()) + * Any extraWidth "left over" (that's availableWidth in the loop + * below) is given to the last child. Note that Dividers always + * have a weight of zero, and they're never the last child. + */ + if (split.isRowLayout()) { + double x = bounds.getX(); + double extraWidth = bounds.getWidth() - splitBounds.getWidth(); + double availableWidth = extraWidth; + + while(splitChildren.hasNext()) { + Node splitChild = splitChildren.next(); + if ( !splitChild.isVisible()) { + continue; + } + Rectangle splitChildBounds = splitChild.getBounds(); + double splitChildWeight = splitChild.getWeight(); + + if ( !hasMoreVisibleSiblings( splitChild )) { + double newWidth = bounds.getMaxX() - x; + Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); + layout2(splitChild, newSplitChildBounds); + } + else if ((availableWidth > 0.0) && (splitChildWeight > 0.0)) { + double allocatedWidth = (splitChild.equals(lastWeightedChild)) + ? availableWidth + : Math.rint(splitChildWeight * extraWidth); + double newWidth = splitChildBounds.getWidth() + allocatedWidth; + Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); + layout2(splitChild, newSplitChildBounds); + availableWidth -= allocatedWidth; + } + else { + double existingWidth = splitChildBounds.getWidth(); + Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, existingWidth); + layout2(splitChild, newSplitChildBounds); + } + x = splitChild.getBounds().getMaxX(); + } } - - private Rectangle boundsWithXandWidth(Rectangle bounds, double x, double width) { - Rectangle r = new Rectangle(); - r.setBounds((int)x, (int)(bounds.getY()), (int)width, (int)(bounds.getHeight())); - return r; + + /* Layout the Split's child Nodes' along the Y axis. The bounds + * of each child will have the same x coordinate and width as the + * layoutGrow() bounds argument. Extra height is allocated to the + * to each child with a non-zero weight: + * newHeight = currentHeight + (extraHeight * splitChild.getWeight()) + * Any extraHeight "left over" (that's availableHeight in the loop + * below) is given to the last child. Note that Dividers always + * have a weight of zero, and they're never the last child. + */ + else { + double y = bounds.getY(); + double extraHeight = bounds.getHeight() - splitBounds.getHeight(); + double availableHeight = extraHeight; + + while(splitChildren.hasNext()) { + Node splitChild = splitChildren.next(); + if ( !splitChild.isVisible()) { + continue; + } + Rectangle splitChildBounds = splitChild.getBounds(); + double splitChildWeight = splitChild.getWeight(); + + if (!splitChildren.hasNext()) { + double newHeight = bounds.getMaxY() - y; + Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); + layout2(splitChild, newSplitChildBounds); + } + else if ((availableHeight > 0.0) && (splitChildWeight > 0.0)) { + double allocatedHeight = (splitChild.equals(lastWeightedChild)) + ? availableHeight + : Math.rint(splitChildWeight * extraHeight); + double newHeight = splitChildBounds.getHeight() + allocatedHeight; + Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); + layout2(splitChild, newSplitChildBounds); + availableHeight -= allocatedHeight; + } + else { + double existingHeight = splitChildBounds.getHeight(); + Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, existingHeight); + layout2(splitChild, newSplitChildBounds); + } + y = splitChild.getBounds().getMaxY(); + } } - - - private void minimizeSplitBounds(Split split, Rectangle bounds) { - Rectangle splitBounds = new Rectangle(bounds.x, bounds.y, 0, 0); - List splitChildren = split.getChildren(); - Node lastChild = splitChildren.get(splitChildren.size() - 1); - Rectangle lastChildBounds = lastChild.getBounds(); - if (split.isRowLayout()) { - int lastChildMaxX = lastChildBounds.x + lastChildBounds.width; - splitBounds.add(lastChildMaxX, bounds.y + bounds.height); - } - else { - int lastChildMaxY = lastChildBounds.y + lastChildBounds.height; - splitBounds.add(bounds.x + bounds.width, lastChildMaxY); - } - split.setBounds(splitBounds); - } - - - private void layoutShrink(Split split, Rectangle bounds) { - Rectangle splitBounds = split.getBounds(); - ListIterator splitChildren = split.getChildren().listIterator(); - @SuppressWarnings("unused") - Node lastWeightedChild = split.lastWeightedChild(); - - if (split.isRowLayout()) { - int totalWidth = 0; // sum of the children's widths - int minWeightedWidth = 0; // sum of the weighted childrens' min widths - int totalWeightedWidth = 0; // sum of the weighted childrens' widths - for(Node splitChild : split.getChildren()) { - int nodeWidth = splitChild.getBounds().width; - int nodeMinWidth = Math.min(nodeWidth, minimumNodeSize(splitChild).width); - totalWidth += nodeWidth; - if (splitChild.getWeight() > 0.0) { - minWeightedWidth += nodeMinWidth; - totalWeightedWidth += nodeWidth; - } - } - - double x = bounds.getX(); - double extraWidth = splitBounds.getWidth() - bounds.getWidth(); - double availableWidth = extraWidth; - boolean onlyShrinkWeightedComponents = - (totalWeightedWidth - minWeightedWidth) > extraWidth; - - while(splitChildren.hasNext()) { - Node splitChild = splitChildren.next(); - Rectangle splitChildBounds = splitChild.getBounds(); - double minSplitChildWidth = minimumNodeSize(splitChild).getWidth(); - double splitChildWeight = (onlyShrinkWeightedComponents) - ? splitChild.getWeight() - : (splitChildBounds.getWidth() / (double)totalWidth); - - if (!splitChildren.hasNext()) { - double newWidth = Math.max(minSplitChildWidth, bounds.getMaxX() - x); - Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); - layout2(splitChild, newSplitChildBounds); - } - else if ((availableWidth > 0.0) && (splitChildWeight > 0.0)) { - double allocatedWidth = Math.rint(splitChildWeight * extraWidth); - double oldWidth = splitChildBounds.getWidth(); - double newWidth = Math.max(minSplitChildWidth, oldWidth - allocatedWidth); - Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); - layout2(splitChild, newSplitChildBounds); - availableWidth -= (oldWidth - splitChild.getBounds().getWidth()); - } - else { - double existingWidth = splitChildBounds.getWidth(); - Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, existingWidth); - layout2(splitChild, newSplitChildBounds); - } - x = splitChild.getBounds().getMaxX(); - } - } - - else { - int totalHeight = 0; // sum of the children's heights - int minWeightedHeight = 0; // sum of the weighted childrens' min heights - int totalWeightedHeight = 0; // sum of the weighted childrens' heights - for(Node splitChild : split.getChildren()) { - int nodeHeight = splitChild.getBounds().height; - int nodeMinHeight = Math.min(nodeHeight, minimumNodeSize(splitChild).height); - totalHeight += nodeHeight; - if (splitChild.getWeight() > 0.0) { - minWeightedHeight += nodeMinHeight; - totalWeightedHeight += nodeHeight; - } - } - - double y = bounds.getY(); - double extraHeight = splitBounds.getHeight() - bounds.getHeight(); - double availableHeight = extraHeight; - boolean onlyShrinkWeightedComponents = - (totalWeightedHeight - minWeightedHeight) > extraHeight; - - while(splitChildren.hasNext()) { - Node splitChild = splitChildren.next(); - Rectangle splitChildBounds = splitChild.getBounds(); - double minSplitChildHeight = minimumNodeSize(splitChild).getHeight(); - double splitChildWeight = (onlyShrinkWeightedComponents) - ? splitChild.getWeight() - : (splitChildBounds.getHeight() / (double)totalHeight); - - if (!splitChildren.hasNext()) { - double oldHeight = splitChildBounds.getHeight(); - double newHeight = Math.max(minSplitChildHeight, bounds.getMaxY() - y); - Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); - layout2(splitChild, newSplitChildBounds); - availableHeight -= (oldHeight - splitChild.getBounds().getHeight()); - } - else if ((availableHeight > 0.0) && (splitChildWeight > 0.0)) { - double allocatedHeight = Math.rint(splitChildWeight * extraHeight); - double oldHeight = splitChildBounds.getHeight(); - double newHeight = Math.max(minSplitChildHeight, oldHeight - allocatedHeight); - Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); - layout2(splitChild, newSplitChildBounds); - availableHeight -= (oldHeight - splitChild.getBounds().getHeight()); - } - else { - double existingHeight = splitChildBounds.getHeight(); - Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, existingHeight); - layout2(splitChild, newSplitChildBounds); - } - y = splitChild.getBounds().getMaxY(); - } - } - - /* The bounds of the Split node root are set to be - * big enough to contain all of its children. Since - * Leaf children can't be reduced below their - * (corresponding java.awt.Component) minimum sizes, - * the size of the Split's bounds maybe be larger than - * the bounds we were asked to fit within. - */ - minimizeSplitBounds(split, bounds); - } - - - private void layoutGrow(Split split, Rectangle bounds) { - Rectangle splitBounds = split.getBounds(); - ListIterator splitChildren = split.getChildren().listIterator(); - Node lastWeightedChild = split.lastWeightedChild(); - - /* Layout the Split's child Nodes' along the X axis. The bounds - * of each child will have the same y coordinate and height as the - * layoutGrow() bounds argument. Extra width is allocated to the - * to each child with a non-zero weight: - * newWidth = currentWidth + (extraWidth * splitChild.getWeight()) - * Any extraWidth "left over" (that's availableWidth in the loop - * below) is given to the last child. Note that Dividers always - * have a weight of zero, and they're never the last child. - */ - if (split.isRowLayout()) { - double x = bounds.getX(); - double extraWidth = bounds.getWidth() - splitBounds.getWidth(); - double availableWidth = extraWidth; - - while(splitChildren.hasNext()) { - Node splitChild = splitChildren.next(); - Rectangle splitChildBounds = splitChild.getBounds(); - double splitChildWeight = splitChild.getWeight(); - - if (!splitChildren.hasNext()) { - double newWidth = bounds.getMaxX() - x; - Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); - layout2(splitChild, newSplitChildBounds); - } - else if ((availableWidth > 0.0) && (splitChildWeight > 0.0)) { - double allocatedWidth = (splitChild.equals(lastWeightedChild)) - ? availableWidth - : Math.rint(splitChildWeight * extraWidth); - double newWidth = splitChildBounds.getWidth() + allocatedWidth; - Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); - layout2(splitChild, newSplitChildBounds); - availableWidth -= allocatedWidth; - } - else { - double existingWidth = splitChildBounds.getWidth(); - Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, existingWidth); - layout2(splitChild, newSplitChildBounds); - } - x = splitChild.getBounds().getMaxX(); - } - } - - /* Layout the Split's child Nodes' along the Y axis. The bounds - * of each child will have the same x coordinate and width as the - * layoutGrow() bounds argument. Extra height is allocated to the - * to each child with a non-zero weight: - * newHeight = currentHeight + (extraHeight * splitChild.getWeight()) - * Any extraHeight "left over" (that's availableHeight in the loop - * below) is given to the last child. Note that Dividers always - * have a weight of zero, and they're never the last child. - */ - else { - double y = bounds.getY(); - double extraHeight = bounds.getMaxY() - splitBounds.getHeight(); - double availableHeight = extraHeight; - - while(splitChildren.hasNext()) { - Node splitChild = splitChildren.next(); - Rectangle splitChildBounds = splitChild.getBounds(); - double splitChildWeight = splitChild.getWeight(); - - if (!splitChildren.hasNext()) { - double newHeight = bounds.getMaxY() - y; - Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); - layout2(splitChild, newSplitChildBounds); - } - else if ((availableHeight > 0.0) && (splitChildWeight > 0.0)) { - double allocatedHeight = (splitChild.equals(lastWeightedChild)) - ? availableHeight - : Math.rint(splitChildWeight * extraHeight); - double newHeight = splitChildBounds.getHeight() + allocatedHeight; - Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); - layout2(splitChild, newSplitChildBounds); - availableHeight -= allocatedHeight; - } - else { - double existingHeight = splitChildBounds.getHeight(); - Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, existingHeight); - layout2(splitChild, newSplitChildBounds); - } - y = splitChild.getBounds().getMaxY(); - } - } - } - - + } + + /* Second pass of the layout algorithm: branch to layoutGrow/Shrink * as needed. */ - private void layout2(Node root, Rectangle bounds) { - if (root instanceof Leaf) { - Component child = childForNode(root); - if (child != null) { - child.setBounds(bounds); - } - root.setBounds(bounds); - } - else if (root instanceof Divider) { - root.setBounds(bounds); - } - else if (root instanceof Split) { - Split split = (Split)root; - boolean grow = split.isRowLayout() - ? (split.getBounds().width <= bounds.width) - : (split.getBounds().height <= bounds.height); - if (grow) { - layoutGrow(split, bounds); - root.setBounds(bounds); - } - else { - layoutShrink(split, bounds); - // split.setBounds() called in layoutShrink() - } - } + private void layout2(Node root, Rectangle bounds) { + if (root instanceof Leaf) { + Component child = childForNode(root); + if (child != null) { + child.setBounds(bounds); + } + root.setBounds(bounds); } - - + else if (root instanceof Divider) { + root.setBounds(bounds); + } + else if (root instanceof Split) { + Split split = (Split)root; + boolean grow = split.isRowLayout() + ? (split.getBounds().width <= bounds.width) + : (split.getBounds().height <= bounds.height); + if (grow) { + layoutGrow(split, bounds); + root.setBounds(bounds); + } + else { + layoutShrink(split, bounds); + // split.setBounds() called in layoutShrink() + } + } + } + + /* First pass of the layout algorithm. - * + * * If the Dividers are "floating" then set the bounds of each - * node to accomodate the preferred size of all of the + * node to accomodate the preferred size of all of the * Leaf's java.awt.Components. Otherwise, just set the bounds * of each Leaf/Split node so that it's to the left of (for * Split.isRowLayout() Split children) or directly above * the Divider that follows. - * + * * This pass sets the bounds of each Node in the layout model. It * does not resize any of the parent Container's * (java.awt.Component) children. That's done in the second pass, * see layoutGrow() and layoutShrink(). */ - private void layout1(Node root, Rectangle bounds) { - if (root instanceof Leaf) { - root.setBounds(bounds); - } - else if (root instanceof Split) { - Split split = (Split)root; - Iterator splitChildren = split.getChildren().iterator(); - Rectangle childBounds = null; - int dividerSize = getDividerSize(); - - /* Layout the Split's child Nodes' along the X axis. The bounds - * of each child will have the same y coordinate and height as the - * layout1() bounds argument. - * - * Note: the column layout code - that's the "else" clause below - * this if, is identical to the X axis (rowLayout) code below. - */ - if (split.isRowLayout()) { - double x = bounds.getX(); - while(splitChildren.hasNext()) { - Node splitChild = splitChildren.next(); - Divider dividerChild = - (splitChildren.hasNext()) ? (Divider)(splitChildren.next()) : null; - - double childWidth = 0.0; - if (getFloatingDividers()) { - childWidth = preferredNodeSize(splitChild).getWidth(); - } - else { - if (dividerChild != null) { - childWidth = dividerChild.getBounds().getX() - x; - } - else { - childWidth = split.getBounds().getMaxX() - x; - } - } - childBounds = boundsWithXandWidth(bounds, x, childWidth); - layout1(splitChild, childBounds); - - if (getFloatingDividers() && (dividerChild != null)) { - double dividerX = childBounds.getMaxX(); - Rectangle dividerBounds = boundsWithXandWidth(bounds, dividerX, dividerSize); - dividerChild.setBounds(dividerBounds); - } - if (dividerChild != null) { - x = dividerChild.getBounds().getMaxX(); - } - } - } - - /* Layout the Split's child Nodes' along the Y axis. The bounds - * of each child will have the same x coordinate and width as the - * layout1() bounds argument. The algorithm is identical to what's - * explained above, for the X axis case. - */ - else { - double y = bounds.getY(); - while(splitChildren.hasNext()) { - Node splitChild = splitChildren.next(); - Divider dividerChild = - (splitChildren.hasNext()) ? (Divider)(splitChildren.next()) : null; - - double childHeight = 0.0; - if (getFloatingDividers()) { - childHeight = preferredNodeSize(splitChild).getHeight(); - } - else { - if (dividerChild != null) { - childHeight = dividerChild.getBounds().getY() - y; - } - else { - childHeight = split.getBounds().getMaxY() - y; - } - } - childBounds = boundsWithYandHeight(bounds, y, childHeight); - layout1(splitChild, childBounds); - - if (getFloatingDividers() && (dividerChild != null)) { - double dividerY = childBounds.getMaxY(); - Rectangle dividerBounds = boundsWithYandHeight(bounds, dividerY, dividerSize); - dividerChild.setBounds(dividerBounds); - } - if (dividerChild != null) { - y = dividerChild.getBounds().getMaxY(); - } - } - } - /* The bounds of the Split node root are set to be just - * big enough to contain all of its children, but only - * along the axis it's allocating space on. That's - * X for rows, Y for columns. The second pass of the - * layout algorithm - see layoutShrink()/layoutGrow() - * allocates extra space. - */ - minimizeSplitBounds(split, bounds); - } + private void layout1(Node root, Rectangle bounds) { + if (root instanceof Leaf) { + root.setBounds(bounds); } + else if (root instanceof Split) { + Split split = (Split)root; + Iterator splitChildren = split.getChildren().iterator(); + Rectangle childBounds = null; + int divSize = getDividerSize(); + boolean initSplit = false; + + + /* Layout the Split's child Nodes' along the X axis. The bounds + * of each child will have the same y coordinate and height as the + * layout1() bounds argument. + * + * Note: the column layout code - that's the "else" clause below + * this if, is identical to the X axis (rowLayout) code below. + */ + if (split.isRowLayout()) { + double x = bounds.getX(); + while(splitChildren.hasNext()) { + Node splitChild = splitChildren.next(); + if ( !splitChild.isVisible()) { + if ( splitChildren.hasNext()) + splitChildren.next(); + continue; + } + Divider dividerChild = + (splitChildren.hasNext()) ? (Divider)(splitChildren.next()) : null; + + double childWidth = 0.0; + if (getFloatingDividers()) { + childWidth = preferredNodeSize(splitChild).getWidth(); + } + else { + if ((dividerChild != null) && dividerChild.isVisible()) { + double cw = dividerChild.getBounds().getX() - x; + if ( cw > 0.0 ) + childWidth = cw; + else { + childWidth = preferredNodeSize(splitChild).getWidth(); + initSplit = true; + } + } + else { + childWidth = split.getBounds().getMaxX() - x; + } + } + childBounds = boundsWithXandWidth(bounds, x, childWidth); + layout1(splitChild, childBounds); + + if (( initSplit || getFloatingDividers()) && (dividerChild != null) && dividerChild.isVisible()) { + double dividerX = childBounds.getMaxX(); + Rectangle dividerBounds; + dividerBounds = boundsWithXandWidth(bounds, dividerX, divSize); + dividerChild.setBounds(dividerBounds); + } + if ((dividerChild != null) && dividerChild.isVisible()) { + x = dividerChild.getBounds().getMaxX(); + } + } + } + + /* Layout the Split's child Nodes' along the Y axis. The bounds + * of each child will have the same x coordinate and width as the + * layout1() bounds argument. The algorithm is identical to what's + * explained above, for the X axis case. + */ + else { + double y = bounds.getY(); + while(splitChildren.hasNext()) { + Node splitChild = splitChildren.next(); + if ( !splitChild.isVisible()) { + if ( splitChildren.hasNext()) + splitChildren.next(); + continue; + } + Divider dividerChild = + (splitChildren.hasNext()) ? (Divider)(splitChildren.next()) : null; + + double childHeight = 0.0; + if (getFloatingDividers()) { + childHeight = preferredNodeSize(splitChild).getHeight(); + } + else { + if ((dividerChild != null) && dividerChild.isVisible()) { + double cy = dividerChild.getBounds().getY() - y; + if ( cy > 0.0 ) + childHeight = cy; + else { + childHeight = preferredNodeSize(splitChild).getHeight(); + initSplit = true; + } + } + else { + childHeight = split.getBounds().getMaxY() - y; + } + } + childBounds = boundsWithYandHeight(bounds, y, childHeight); + layout1(splitChild, childBounds); + + if (( initSplit || getFloatingDividers()) && (dividerChild != null) && dividerChild.isVisible()) { + double dividerY = childBounds.getMaxY(); + Rectangle dividerBounds = boundsWithYandHeight(bounds, dividerY, divSize); + dividerChild.setBounds(dividerBounds); + } + if ((dividerChild != null) && dividerChild.isVisible()) { + y = dividerChild.getBounds().getMaxY(); + } + } + } + /* The bounds of the Split node root are set to be just + * big enough to contain all of its children, but only + * along the axis it's allocating space on. That's + * X for rows, Y for columns. The second pass of the + * layout algorithm - see layoutShrink()/layoutGrow() + * allocates extra space. + */ + minimizeSplitBounds(split, bounds); + } + } - /** - * The specified Node is either the wrong type or was configured - * incorrectly. + /** + * Get the layout mode + * @return current layout mode + */ + public int getLayoutMode() + { + return layoutMode; + } + + /** + * Set the layout mode. By default this layout uses the preferred and minimum + * sizes of the child components. To ignore the minimum size set the layout + * mode to MultiSplitLayout.LAYOUT_NO_MIN_SIZE. + * @param layoutMode the layout mode + *

    + *
  • DEFAULT_LAYOUT - use the preferred and minimum sizes when sizing the children
  • + *
  • LAYOUT_NO_MIN_SIZE - ignore the minimum size when sizing the children
  • + * + */ + public void setLayoutMode( int layoutMode ) + { + this.layoutMode = layoutMode; + } + + /** + * Get the minimum node size + * @return the minimum size + */ + public int getUserMinSize() + { + return userMinSize; + } + + /** + * Set the user defined minimum size support in the USER_MIN_SIZE_LAYOUT + * layout mode. + * @param minSize the new minimum size + */ + public void setUserMinSize( int minSize ) + { + userMinSize = minSize; + } + + /** + * Get the layoutByWeight falg. If the flag is true the layout initializes + * itself using the model weights + * @return the layoutByWeight + */ + public boolean getLayoutByWeight() + { + return layoutByWeight; + } + + /** + * Sset the layoutByWeight falg. If the flag is true the layout initializes + * itself using the model weights + * @param state the new layoutByWeight to set + */ + public void setLayoutByWeight( boolean state ) + { + layoutByWeight = state; + } + + /** + * The specified Node is either the wrong type or was configured + * incorrectly. + */ + public static class InvalidLayoutException extends RuntimeException { + private final Node node; + public InvalidLayoutException(String msg, Node node) { + super(msg); + this.node = node; + } + /** + * @return the invalid Node. */ - - public static class InvalidLayoutException extends RuntimeException { - - private static final long serialVersionUID = -5960249230256779327L; - private final Node node; - public InvalidLayoutException (String msg, Node node) { - super(msg); - this.node = node; - } - /** - * @return the invalid Node. - */ - public Node getNode() { return node; } + public Node getNode() { return node; } + } + + private void throwInvalidLayout(String msg, Node node) { + throw new InvalidLayoutException(msg, node); + } + + private void checkLayout(Node root) { + if (root instanceof Split) { + Split split = (Split)root; + if (split.getChildren().size() <= 2) { + throwInvalidLayout("Split must have > 2 children", root); + } + Iterator splitChildren = split.getChildren().iterator(); + double weight = 0.0; + while(splitChildren.hasNext()) { + Node splitChild = splitChildren.next(); + if ( !splitChild.isVisible()) { + if ( splitChildren.hasNext()) + splitChildren.next(); + continue; + } + if (splitChild instanceof Divider) { + continue; + //throwInvalidLayout("expected a Split or Leaf Node", splitChild); + } + if (splitChildren.hasNext()) { + Node dividerChild = splitChildren.next(); + if (!(dividerChild instanceof Divider)) { + throwInvalidLayout("expected a Divider Node", dividerChild); + } + } + weight += splitChild.getWeight(); + checkLayout(splitChild); + } + if (weight > 1.0) { + throwInvalidLayout("Split children's total weight > 1.0", root); + } } + } + + /** + * Compute the bounds of all of the Split/Divider/Leaf Nodes in + * the layout model, and then set the bounds of each child component + * with a matching Leaf Node. + */ + public void layoutContainer(Container parent) + { + if ( layoutByWeight && floatingDividers ) + doLayoutByWeight( parent ); - private void throwInvalidLayout(String msg, Node node) { - throw new InvalidLayoutException(msg, node); + checkLayout(getModel()); + Insets insets = parent.getInsets(); + Dimension size = parent.getSize(); + int width = size.width - (insets.left + insets.right); + int height = size.height - (insets.top + insets.bottom); + Rectangle bounds = new Rectangle( insets.left, insets.top, width, height); + layout1(getModel(), bounds); + layout2(getModel(), bounds); + } + + + private Divider dividerAt(Node root, int x, int y) { + if (root instanceof Divider) { + Divider divider = (Divider)root; + return (divider.getBounds().contains(x, y)) ? divider : null; } - - private void checkLayout(Node root) { - if (root instanceof Split) { - Split split = (Split)root; - if (split.getChildren().size() <= 2) { - throwInvalidLayout("Split must have > 2 children", root); - } - Iterator splitChildren = split.getChildren().iterator(); - double weight = 0.0; - while(splitChildren.hasNext()) { - Node splitChild = splitChildren.next(); - if (splitChild instanceof Divider) { - throwInvalidLayout("expected a Split or Leaf Node", splitChild); - } - if (splitChildren.hasNext()) { - Node dividerChild = splitChildren.next(); - if (!(dividerChild instanceof Divider)) { - throwInvalidLayout("expected a Divider Node", dividerChild); - } - } - weight += splitChild.getWeight(); - checkLayout(splitChild); - } - if (weight > 1.0) { - throwInvalidLayout("Split children's total weight > 1.0", root); - } - } + else if (root instanceof Split) { + Split split = (Split)root; + for(Node child : split.getChildren()) { + if ( !child.isVisible()) + continue; + if (child.getBounds().contains(x, y)) { + return dividerAt(child, x, y); + } + } } - - /** - * Compute the bounds of all of the Split/Divider/Leaf Nodes in - * the layout model, and then set the bounds of each child component - * with a matching Leaf Node. + return null; + } + + /** + * Return the Divider whose bounds contain the specified + * point, or null if there isn't one. + * + * @param x x coordinate + * @param y y coordinate + * @return the Divider at x,y + */ + public Divider dividerAt(int x, int y) { + return dividerAt(getModel(), x, y); + } + + private boolean nodeOverlapsRectangle(Node node, Rectangle r2) { + Rectangle r1 = node.getBounds(); + return + (r1.x <= (r2.x + r2.width)) && ((r1.x + r1.width) >= r2.x) && + (r1.y <= (r2.y + r2.height)) && ((r1.y + r1.height) >= r2.y); + } + + private List dividersThatOverlap(Node root, Rectangle r) { + if (nodeOverlapsRectangle(root, r) && (root instanceof Split)) { + List dividers = new ArrayList(); + for(Node child : ((Split)root).getChildren()) { + if (child instanceof Divider) { + if (nodeOverlapsRectangle(child, r)) { + dividers.add((Divider)child); + } + } + else if (child instanceof Split) { + dividers.addAll(dividersThatOverlap(child, r)); + } + } + return dividers; + } + else { + return Collections.emptyList(); + } + } + + /** + * Return the Dividers whose bounds overlap the specified + * Rectangle. + * + * @param r target Rectangle + * @return the Dividers that overlap r + * @throws IllegalArgumentException if the Rectangle is null + */ + public List dividersThatOverlap(Rectangle r) { + if (r == null) { + throw new IllegalArgumentException("null Rectangle"); + } + return dividersThatOverlap(getModel(), r); + } + + + /** + * Base class for the nodes that model a MultiSplitLayout. + */ + public static abstract class Node { + private Split parent = null; + private Rectangle bounds = new Rectangle(); + private double weight = 0.0; + private boolean isVisible = true; + public void setVisible( boolean b ) { + isVisible = b; + } + + /** + * Determines whether this node should be visible when its + * parent is visible. Nodes are + * initially visible + * @return true if the node is visible, + * false otherwise */ - public void layoutContainer(Container parent) { - checkLayout(getModel()); - Insets insets = parent.getInsets(); - Dimension size = parent.getSize(); - int width = size.width - (insets.left + insets.right); - int height = size.height - (insets.top + insets.bottom); - Rectangle bounds = new Rectangle(insets.left, insets.top, width, height); - layout1(getModel(), bounds); - layout2(getModel(), bounds); + public boolean isVisible() { + return isVisible; + } + + /** + * Returns the Split parent of this Node, or null. + * + * @return the value of the parent property. + * @see #setParent + */ + public Split getParent() { return parent; } + + /** + * Set the value of this Node's parent property. The default + * value of this property is null. + * + * @param parent a Split or null + * @see #getParent + */ + public void setParent(Split parent) { + this.parent = parent; + } + + /** + * Returns the bounding Rectangle for this Node. + * + * @return the value of the bounds property. + * @see #setBounds + */ + public Rectangle getBounds() { + return new Rectangle(this.bounds); + } + + /** + * Set the bounding Rectangle for this node. The value of + * bounds may not be null. The default value of bounds + * is equal to new Rectangle(0,0,0,0). + * + * @param bounds the new value of the bounds property + * @throws IllegalArgumentException if bounds is null + * @see #getBounds + */ + public void setBounds(Rectangle bounds) { + if (bounds == null) { + throw new IllegalArgumentException("null bounds"); + } + this.bounds = new Rectangle(bounds); + } + + /** + * Value between 0.0 and 1.0 used to compute how much space + * to add to this sibling when the layout grows or how + * much to reduce when the layout shrinks. + * + * @return the value of the weight property + * @see #setWeight + */ + public double getWeight() { return weight; } + + /** + * The weight property is a between 0.0 and 1.0 used to + * compute how much space to add to this sibling when the + * layout grows or how much to reduce when the layout shrinks. + * If rowLayout is true then this node's width grows + * or shrinks by (extraSpace * weight). If rowLayout is false, + * then the node's height is changed. The default value + * of weight is 0.0. + * + * @param weight a double between 0.0 and 1.0 + * @see #getWeight + * @see MultiSplitLayout#layoutContainer + * @throws IllegalArgumentException if weight is not between 0.0 and 1.0 + */ + public void setWeight(double weight) { + if ((weight < 0.0)|| (weight > 1.0)) { + throw new IllegalArgumentException("invalid weight"); + } + this.weight = weight; + } + + private Node siblingAtOffset(int offset) { + Split p = getParent(); + if (p == null) { return null; } + List siblings = p.getChildren(); + int index = siblings.indexOf(this); + if (index == -1) { return null; } + index += offset; + return ((index > -1) && (index < siblings.size())) ? siblings.get(index) : null; + } + + /** + * Return the Node that comes after this one in the parent's + * list of children, or null. If this node's parent is null, + * or if it's the last child, then return null. + * + * @return the Node that comes after this one in the parent's list of children. + * @see #previousSibling + * @see #getParent + */ + public Node nextSibling() { + return siblingAtOffset(+1); + } + + /** + * Return the Node that comes before this one in the parent's + * list of children, or null. If this node's parent is null, + * or if it's the last child, then return null. + * + * @return the Node that comes before this one in the parent's list of children. + * @see #nextSibling + * @see #getParent + */ + public Node previousSibling() { + return siblingAtOffset(-1); + } + } + + public static class RowSplit extends Split { + public RowSplit() { } - - private Divider dividerAt(Node root, int x, int y) { - if (root instanceof Divider) { - Divider divider = (Divider)root; - return (divider.getBounds().contains(x, y)) ? divider : null; - } - else if (root instanceof Split) { - Split split = (Split)root; - for(Node child : split.getChildren()) { - if (child.getBounds().contains(x, y)) { - return dividerAt(child, x, y); - } - } - } - return null; + public RowSplit(Node... children) { + setChildren(children); } - - /** - * Return the Divider whose bounds contain the specified - * point, or null if there isn't one. + + /** + * Returns true if the this Split's children are to be + * laid out in a row: all the same height, left edge + * equal to the previous Node's right edge. If false, + * children are laid on in a column. * - * @param x x coordinate - * @param y y coordinate - * @return the Divider at x,y + * @return the value of the rowLayout property. + * @see #setRowLayout */ - public Divider dividerAt(int x, int y) { - return dividerAt(getModel(), x, y); + @Override + public final boolean isRowLayout() { return true; } + } + + public static class ColSplit extends Split { + public ColSplit() { } - private boolean nodeOverlapsRectangle(Node node, Rectangle r2) { - Rectangle r1 = node.getBounds(); - return - (r1.x <= (r2.x + r2.width)) && ((r1.x + r1.width) >= r2.x) && - (r1.y <= (r2.y + r2.height)) && ((r1.y + r1.height) >= r2.y); + public ColSplit(Node... children) { + setChildren(children); } + + /** + * Returns true if the this Split's children are to be + * laid out in a row: all the same height, left edge + * equal to the previous Node's right edge. If false, + * children are laid on in a column. + * + * @return the value of the rowLayout property. + * @see #setRowLayout + */ + @Override + public final boolean isRowLayout() { return false; } + } - @SuppressWarnings("unchecked") - private List dividersThatOverlap(Node root, Rectangle r) { - if (nodeOverlapsRectangle(root, r) && (root instanceof Split)) { - List dividers = new ArrayList(); - for(Node child : ((Split)root).getChildren()) { - if (child instanceof Divider) { - if (nodeOverlapsRectangle(child, r)) { - dividers.add((Divider)child); - } - } - else if (child instanceof Split) { - dividers.addAll(dividersThatOverlap(child, r)); - } - } - return dividers; - } - else { - return Collections.emptyList(); - } + /** + * Defines a vertical or horizontal subdivision into two or more + * tiles. + */ + public static class Split extends Node { + private List children = Collections.emptyList(); + private boolean rowLayout = true; + private String name; + + public Split(Node... children) { + setChildren(children); + } + + /** + * Default constructor to support xml (de)serialization and other bean spec dependent ops. + * Resulting instance of Split is invalid until setChildren() is called. + */ + public Split() { } /** - * Return the Dividers whose bounds overlap the specified - * Rectangle. - * - * @param r target Rectangle - * @return the Dividers that overlap r - * @throws IllegalArgumentException if the Rectangle is null + * Determines whether this node should be visible when its + * parent is visible. Nodes are + * initially visible + * @return true if the node is visible, + * false otherwise */ - public List dividersThatOverlap(Rectangle r) { - if (r == null) { - throw new IllegalArgumentException("null Rectangle"); - } - return dividersThatOverlap(getModel(), r); + @Override + public boolean isVisible() { + for(Node child : children) { + if ( child.isVisible() && !( child instanceof Divider )) + return true; + } + return false; } - - - /** - * Base class for the nodes that model a MultiSplitLayout. - */ - public static abstract class Node { - private Split parent = null; - private Rectangle bounds = new Rectangle(); - private double weight = 0.0; - - /** - * Returns the Split parent of this Node, or null. - * - * @return the value of the parent property. - * @see #setParent - */ - public Split getParent() { return parent; } - - /** - * Set the value of this Node's parent property. The default - * value of this property is null. - * - * @param parent a Split or null - * @see #getParent - */ - public void setParent(Split parent) { - this.parent = parent; - } - - /** - * Returns the bounding Rectangle for this Node. - * - * @return the value of the bounds property. - * @see #setBounds - */ - public Rectangle getBounds() { - return new Rectangle(this.bounds); - } - - /** - * Set the bounding Rectangle for this node. The value of - * bounds may not be null. The default value of bounds - * is equal to new Rectangle(0,0,0,0). - * - * @param bounds the new value of the bounds property - * @throws IllegalArgumentException if bounds is null - * @see #getBounds - */ - public void setBounds(Rectangle bounds) { - if (bounds == null) { - throw new IllegalArgumentException("null bounds"); - } - this.bounds = new Rectangle(bounds); - } - - /** - * Value between 0.0 and 1.0 used to compute how much space - * to add to this sibling when the layout grows or how - * much to reduce when the layout shrinks. - * - * @return the value of the weight property - * @see #setWeight - */ - public double getWeight() { return weight; } - - /** - * The weight property is a between 0.0 and 1.0 used to - * compute how much space to add to this sibling when the - * layout grows or how much to reduce when the layout shrinks. - * If rowLayout is true then this node's width grows - * or shrinks by (extraSpace * weight). If rowLayout is false, - * then the node's height is changed. The default value - * of weight is 0.0. - * - * @param weight a double between 0.0 and 1.0 - * @see #getWeight - * @see MultiSplitLayout#layoutContainer - * @throws IllegalArgumentException if weight is not between 0.0 and 1.0 - */ - public void setWeight(double weight) { - if ((weight < 0.0)|| (weight > 1.0)) { - throw new IllegalArgumentException("invalid weight"); - } - this.weight = weight; - } - - private Node siblingAtOffset(int offset) { - Split parent = getParent(); - if (parent == null) { return null; } - List siblings = parent.getChildren(); - int index = siblings.indexOf(this); - if (index == -1) { return null; } - index += offset; - return ((index > -1) && (index < siblings.size())) ? siblings.get(index) : null; - } - - /** - * Return the Node that comes after this one in the parent's - * list of children, or null. If this node's parent is null, - * or if it's the last child, then return null. - * - * @return the Node that comes after this one in the parent's list of children. - * @see #previousSibling - * @see #getParent - */ - public Node nextSibling() { - return siblingAtOffset(+1); - } - - /** - * Return the Node that comes before this one in the parent's - * list of children, or null. If this node's parent is null, - * or if it's the last child, then return null. - * - * @return the Node that comes before this one in the parent's list of children. - * @see #nextSibling - * @see #getParent - */ - public Node previousSibling() { - return siblingAtOffset(-1); - } - } - - /** - * Defines a vertical or horizontal subdivision into two or more - * tiles. - */ - public static class Split extends Node { - private List children = Collections.emptyList(); - private boolean rowLayout = true; - - /** - * Returns true if the this Split's children are to be - * laid out in a row: all the same height, left edge - * equal to the previous Node's right edge. If false, - * children are laid on in a column. - * - * @return the value of the rowLayout property. - * @see #setRowLayout - */ - public boolean isRowLayout() { return rowLayout; } - - /** - * Set the rowLayout property. If true, all of this Split's - * children are to be laid out in a row: all the same height, - * each node's left edge equal to the previous Node's right - * edge. If false, children are laid on in a column. Default - * value is true. - * - * @param rowLayout true for horizontal row layout, false for column - * @see #isRowLayout - */ - public void setRowLayout(boolean rowLayout) { - this.rowLayout = rowLayout; - } - - /** - * Returns this Split node's children. The returned value - * is not a reference to the Split's internal list of children - * - * @return the value of the children property. - * @see #setChildren - */ - public List getChildren() { - return new ArrayList(children); - } - - /** - * Set's the children property of this Split node. The parent - * of each new child is set to this Split node, and the parent - * of each old child (if any) is set to null. This method - * defensively copies the incoming List. Default value is - * an empty List. - * - * @param children List of children - * @see #getChildren - * @throws IllegalArgumentException if children is null - */ - public void setChildren(List children) { - if (children == null) { - throw new IllegalArgumentException("children must be a non-null List"); - } - for(Node child : this.children) { - child.setParent(null); - } - this.children = new ArrayList(children); - for(Node child : this.children) { - child.setParent(this); - } - } - - /** - * Convenience method that returns the last child whose weight - * is > 0.0. - * - * @return the last child whose weight is > 0.0. - * @see #getChildren - * @see Node#getWeight - */ - public final Node lastWeightedChild() { - List children = getChildren(); - Node weightedChild = null; - for(Node child : children) { - if (child.getWeight() > 0.0) { - weightedChild = child; - } - } - return weightedChild; - } - - public String toString() { - int nChildren = getChildren().size(); - StringBuffer sb = new StringBuffer("MultiSplitLayout.Split"); - sb.append(isRowLayout() ? " ROW [" : " COLUMN ["); - sb.append(nChildren + ((nChildren == 1) ? " child" : " children")); - sb.append("] "); - sb.append(getBounds()); - return sb.toString(); - } - } - - + /** - * Models a java.awt Component child. + * Returns true if the this Split's children are to be + * laid out in a row: all the same height, left edge + * equal to the previous Node's right edge. If false, + * children are laid on in a column. + * + * @return the value of the rowLayout property. + * @see #setRowLayout */ - public static class Leaf extends Node { - private String name = ""; - - /** - * Create a Leaf node. The default value of name is "". - */ - public Leaf() { } - - /** - * Create a Leaf node with the specified name. Name can not - * be null. - * - * @param name value of the Leaf's name property - * @throws IllegalArgumentException if name is null - */ - public Leaf(String name) { - if (name == null) { - throw new IllegalArgumentException("name is null"); - } - this.name = name; - } - - /** - * Return the Leaf's name. - * - * @return the value of the name property. - * @see #setName - */ - public String getName() { return name; } - - /** - * Set the value of the name property. Name may not be null. - * - * @param name value of the name property - * @throws IllegalArgumentException if name is null - */ - public void setName(String name) { - if (name == null) { - throw new IllegalArgumentException("name is null"); - } - this.name = name; - } - - public String toString() { - StringBuffer sb = new StringBuffer("MultiSplitLayout.Leaf"); - sb.append(" \""); - sb.append(getName()); - sb.append("\""); - sb.append(" weight="); - sb.append(getWeight()); - sb.append(" "); - sb.append(getBounds()); - return sb.toString(); - } - } - - - /** - * Models a single vertical/horiztonal divider. - */ - public static class Divider extends Node { - /** - * Convenience method, returns true if the Divider's parent - * is a Split row (a Split with isRowLayout() true), false - * otherwise. In other words if this Divider's major axis - * is vertical, return true. - * - * @return true if this Divider is part of a Split row. - */ - public final boolean isVertical() { - Split parent = getParent(); - return (parent != null) ? parent.isRowLayout() : false; - } - - /** - * Dividers can't have a weight, they don't grow or shrink. - * @throws UnsupportedOperationException - */ - public void setWeight(double weight) { - throw new UnsupportedOperationException(); - } - - public String toString() { - return "MultiSplitLayout.Divider " + getBounds().toString(); - } - } - - - private static void throwParseException(StreamTokenizer st, String msg) throws Exception { - throw new Exception("MultiSplitLayout.parseModel Error: " + msg); - } - - private static void parseAttribute(String name, StreamTokenizer st, Node node) throws Exception { - if ((st.nextToken() != '=')) { - throwParseException(st, "expected '=' after " + name); - } - if (name.equalsIgnoreCase("WEIGHT")) { - if (st.nextToken() == StreamTokenizer.TT_NUMBER) { - node.setWeight(st.nval); - } - else { - throwParseException(st, "invalid weight"); - } - } - else if (name.equalsIgnoreCase("NAME")) { - if (st.nextToken() == StreamTokenizer.TT_WORD) { - if (node instanceof Leaf) { - ((Leaf)node).setName(st.sval); - } - else { - throwParseException(st, "can't specify name for " + node); - } - } - else { - throwParseException(st, "invalid name"); - } - } - else { - throwParseException(st, "unrecognized attribute \"" + name + "\""); - } - } - - @SuppressWarnings("unchecked") - private static void addSplitChild(Split parent, Node child) { - List children = new ArrayList(parent.getChildren()); - if (children.size() == 0) { - children.add(child); - } - else { - children.add(new Divider()); - children.add(child); - } - parent.setChildren(children); - } - - private static void parseLeaf(StreamTokenizer st, Split parent) throws Exception { - Leaf leaf = new Leaf(); - int token; - while ((token = st.nextToken()) != StreamTokenizer.TT_EOF) { - if (token == ')') { - break; - } - if (token == StreamTokenizer.TT_WORD) { - parseAttribute(st.sval, st, leaf); - } - else { - throwParseException(st, "Bad Leaf: " + leaf); - } - } - addSplitChild(parent, leaf); - } - - private static void parseSplit(StreamTokenizer st, Split parent) throws Exception { - int token; - while ((token = st.nextToken()) != StreamTokenizer.TT_EOF) { - if (token == ')') { - break; - } - else if (token == StreamTokenizer.TT_WORD) { - if (st.sval.equalsIgnoreCase("WEIGHT")) { - parseAttribute(st.sval, st, parent); - } - else { - addSplitChild(parent, new Leaf(st.sval)); - } - } - else if (token == '(') { - if ((token = st.nextToken()) != StreamTokenizer.TT_WORD) { - throwParseException(st, "invalid node type"); - } - String nodeType = st.sval.toUpperCase(); - if (nodeType.equals("LEAF")) { - parseLeaf(st, parent); - } - else if (nodeType.equals("ROW") || nodeType.equals("COLUMN")) { - Split split = new Split(); - split.setRowLayout(nodeType.equals("ROW")); - addSplitChild(parent, split); - parseSplit(st, split); - } - else { - throwParseException(st, "unrecognized node type '" + nodeType + "'"); - } - } - } - } - - private static Node parseModel (Reader r) { - StreamTokenizer st = new StreamTokenizer(r); - try { - Split root = new Split(); - parseSplit(st, root); - return root.getChildren().get(0); - } - catch (Exception e) { - System.err.println(e); - } - finally { - try { r.close(); } catch (IOException ignore) {} - } - return null; - } - + public boolean isRowLayout() { return rowLayout; } + /** - * A convenience method that converts a string to a - * MultiSplitLayout model (a tree of Nodes) using a - * a simple syntax. Nodes are represented by - * parenthetical expressions whose first token - * is one of ROW/COLUMN/LEAF. ROW and COLUMN specify - * horizontal and vertical Split nodes respectively, - * LEAF specifies a Leaf node. A Leaf's name and - * weight can be specified with attributes, - * name=myLeafName weight=myLeafWeight. - * Similarly, a Split's weight can be specified with - * weight=mySplitWeight. - * - *

    For example, the following expression generates - * a horizontal Split node with three children: - * the Leafs named left and right, and a Divider in - * between: - *

    -     * (ROW (LEAF name=left) (LEAF name=right weight=1.0))
    -     * 
    - * - *

    Dividers should not be included in the string, - * they're added automatcially as needed. Because - * Leaf nodes often only need to specify a name, one - * can specify a Leaf by just providing the name. - * The previous example can be written like this: - *

    -     * (ROW left (LEAF name=right weight=1.0))
    -     * 
    - * - *

    Here's a more complex example. One row with - * three elements, the first and last of which are columns - * with two leaves each: - *

    -     * (ROW (COLUMN weight=0.5 left.top left.bottom) 
    -     *      (LEAF name=middle)
    -     *      (COLUMN weight=0.5 right.top right.bottom))
    -     * 
    - * - * - *

    This syntax is not intended for archiving or - * configuration files . It's just a convenience for - * examples and tests. - * - * @return the Node root of a tree based on s. + * Set the rowLayout property. If true, all of this Split's + * children are to be laid out in a row: all the same height, + * each node's left edge equal to the previous Node's right + * edge. If false, children are laid on in a column. Default + * value is true. + * + * @param rowLayout true for horizontal row layout, false for column + * @see #isRowLayout */ - public static Node parseModel(String s) { - return parseModel(new StringReader(s)); + public void setRowLayout(boolean rowLayout) { + this.rowLayout = rowLayout; } - - - private static void printModel(String indent, Node root) { - if (root instanceof Split) { - Split split = (Split)root; - System.out.println(indent + split); - for(Node child : split.getChildren()) { - printModel(indent + " ", child); - } - } - else { - System.out.println(indent + root); - } - } - - /** - * Print the tree with enough detail for simple debugging. + + /** + * Returns this Split node's children. The returned value + * is not a reference to the Split's internal list of children + * + * @return the value of the children property. + * @see #setChildren */ - public static void printModel(Node root) { - printModel("", root); + public List getChildren() { + return new ArrayList(children); } -} + + + /** + * Remove a node from the layout. Any sibling dividers will also be removed + * @param n the node to be removed + */ + public void remove( Node n ) { + if ( n.nextSibling() instanceof Divider ) + children.remove( n.nextSibling() ); + else if ( n.previousSibling() instanceof Divider ) + children.remove( n.previousSibling() ); + children.remove( n ); + } + + /** + * Replace one node with another. This method is used when a child is removed + * from a split and the split is no longer required, in which case the + * remaining node in the child split can replace the split in the parent + * node + * @param target the node being replaced + * @param replacement the replacement node + */ + public void replace( Node target, Node replacement ) { + int idx = children.indexOf( target ); + children.remove( target ); + children.add( idx, replacement ); + + replacement.setParent ( this ); + target.setParent( this ); + } + + /** + * Change a node to being hidden. Any associated divider nodes are also hidden + * @param target the node to hide + */ + public void hide( Node target ){ + Node next = target.nextSibling(); + if ( next instanceof Divider ) + next.setVisible( false ); + else { + Node prev = target.previousSibling(); + if ( prev instanceof Divider ) + prev.setVisible( false ); + } + target.setVisible( false ); + } + + /** + * Check the dividers to ensure that redundant dividers are hidden and do + * not interfere in the layout, for example when all the children of a split + * are hidden (the split is then invisible), so two dividers may otherwise + * appear next to one another. + * @param split the split to check + */ + public void checkDividers( Split split ) { + ListIterator splitChildren = split.getChildren().listIterator(); + while( splitChildren.hasNext()) { + Node splitChild = splitChildren.next(); + if ( !splitChild.isVisible()) { + continue; + } + else if ( splitChildren.hasNext()) { + Node dividerChild = splitChildren.next(); + if ( dividerChild instanceof Divider ) { + if ( splitChildren.hasNext()) { + Node rightChild = splitChildren.next(); + while ( !rightChild.isVisible()) { + rightChild = rightChild.nextSibling(); + if ( rightChild == null ) { + // No visible right sibling found, so hide the divider + dividerChild.setVisible( false ); + break; + } + } + + // A visible child is found but it's a divider and therefore + // we have to visible and adjacent dividers - so we hide one + if (( rightChild != null ) && ( rightChild instanceof Divider )) + dividerChild.setVisible( false ); + } + } + else if (( splitChild instanceof Divider ) && ( dividerChild instanceof Divider )) { + splitChild.setVisible( false ); + } + } + } + } + + /** + * Restore any of the hidden dividers that are required to separate visible nodes + * @param split the node to check + */ + public void restoreDividers( Split split ) { + boolean nextDividerVisible = false; + ListIterator splitChildren = split.getChildren().listIterator(); + while( splitChildren.hasNext()) { + Node splitChild = splitChildren.next(); + if ( splitChild instanceof Divider ) { + Node prev = splitChild.previousSibling(); + if ( prev.isVisible()) { + Node next = splitChild.nextSibling(); + while ( next != null ) { + if ( next.isVisible()) { + splitChild.setVisible( true ); + break; + } + next = next.nextSibling(); + } + } + } + } + if ( split.getParent() != null ) + restoreDividers( split.getParent()); + } + + /** + * Set's the children property of this Split node. The parent + * of each new child is set to this Split node, and the parent + * of each old child (if any) is set to null. This method + * defensively copies the incoming List. Default value is + * an empty List. + * + * @param children List of children + * @see #getChildren + * @throws IllegalArgumentException if children is null + */ + public void setChildren(List children) { + if (children == null) { + throw new IllegalArgumentException("children must be a non-null List"); + } + for(Node child : this.children) { + child.setParent(null); + } + + this.children = new ArrayList(children); + for(Node child : this.children) { + child.setParent(this); + } + } + + /** + * Convenience method for setting the children of this Split node. The parent + * of each new child is set to this Split node, and the parent + * of each old child (if any) is set to null. This method + * defensively copies the incoming array. + * + * @param children array of children + * @see #getChildren + * @throws IllegalArgumentException if children is null + */ + public void setChildren(Node... children) { + setChildren(children == null ? null : Arrays.asList(children)); + } + + /** + * Convenience method that returns the last child whose weight + * is > 0.0. + * + * @return the last child whose weight is > 0.0. + * @see #getChildren + * @see Node#getWeight + */ + public final Node lastWeightedChild() { + List kids = getChildren(); + Node weightedChild = null; + for(Node child : kids) { + if ( !child.isVisible()) + continue; + if (child.getWeight() > 0.0) { + weightedChild = child; + } + } + return weightedChild; + } + + /** + * Return the Leaf's name. + * + * @return the value of the name property. + * @see #setName + */ + public String getName() { return name; } + + /** + * Set the value of the name property. Name may not be null. + * + * @param name value of the name property + * @throws IllegalArgumentException if name is null + */ + public void setName(String name) { + if (name == null) { + throw new IllegalArgumentException("name is null"); + } + this.name = name; + } + + @Override + public String toString() { + int nChildren = getChildren().size(); + StringBuffer sb = new StringBuffer("MultiSplitLayout.Split"); + sb.append(" \""); + sb.append(getName()); + sb.append("\""); + sb.append(isRowLayout() ? " ROW [" : " COLUMN ["); + sb.append(nChildren + ((nChildren == 1) ? " child" : " children")); + sb.append("] "); + sb.append(getBounds()); + return sb.toString(); + } + } + + + /** + * Models a java.awt Component child. + */ + public static class Leaf extends Node { + private String name = ""; + + /** + * Create a Leaf node. The default value of name is "". + */ + public Leaf() { } + + + /** + * Create a Leaf node with the specified name. Name can not + * be null. + * + * @param name value of the Leaf's name property + * @throws IllegalArgumentException if name is null + */ + public Leaf(String name) { + if (name == null) { + throw new IllegalArgumentException("name is null"); + } + this.name = name; + } + + /** + * Return the Leaf's name. + * + * @return the value of the name property. + * @see #setName + */ + public String getName() { return name; } + + /** + * Set the value of the name property. Name may not be null. + * + * @param name value of the name property + * @throws IllegalArgumentException if name is null + */ + public void setName(String name) { + if (name == null) { + throw new IllegalArgumentException("name is null"); + } + this.name = name; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer("MultiSplitLayout.Leaf"); + sb.append(" \""); + sb.append(getName()); + sb.append("\""); + sb.append(" weight="); + sb.append(getWeight()); + sb.append(" "); + sb.append(getBounds()); + return sb.toString(); + } + } + + + /** + * Models a single vertical/horiztonal divider. + */ + public static class Divider extends Node { + /** + * Convenience method, returns true if the Divider's parent + * is a Split row (a Split with isRowLayout() true), false + * otherwise. In other words if this Divider's major axis + * is vertical, return true. + * + * @return true if this Divider is part of a Split row. + */ + public final boolean isVertical() { + Split parent = getParent(); + return (parent != null) ? parent.isRowLayout() : false; + } + + /** + * Dividers can't have a weight, they don't grow or shrink. + * @throws UnsupportedOperationException + */ + @Override + public void setWeight(double weight) { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return "MultiSplitLayout.Divider " + getBounds().toString(); + } + } + + + private static void throwParseException(StreamTokenizer st, String msg) throws Exception { + throw new Exception("MultiSplitLayout.parseModel Error: " + msg); + } + + private static void parseAttribute(String name, StreamTokenizer st, Node node) throws Exception { + if ((st.nextToken() != '=')) { + throwParseException(st, "expected '=' after " + name); + } + if (name.equalsIgnoreCase("WEIGHT")) { + if (st.nextToken() == StreamTokenizer.TT_NUMBER) { + node.setWeight(st.nval); + } + else { + throwParseException(st, "invalid weight"); + } + } + else if (name.equalsIgnoreCase("NAME")) { + if (st.nextToken() == StreamTokenizer.TT_WORD) { + if (node instanceof Leaf) { + ((Leaf)node).setName(st.sval); + } + else if (node instanceof Split) { + ((Split)node).setName(st.sval); + } + else { + throwParseException(st, "can't specify name for " + node); + } + } + else { + throwParseException(st, "invalid name"); + } + } + else { + throwParseException(st, "unrecognized attribute \"" + name + "\""); + } + } + + private static void addSplitChild(Split parent, Node child) { + List children = new ArrayList(parent.getChildren()); + if (children.size() == 0) { + children.add(child); + } + else { + children.add(new Divider()); + children.add(child); + } + parent.setChildren(children); + } + + private static void parseLeaf(StreamTokenizer st, Split parent) throws Exception { + Leaf leaf = new Leaf(); + int token; + while ((token = st.nextToken()) != StreamTokenizer.TT_EOF) { + if (token == ')') { + break; + } + if (token == StreamTokenizer.TT_WORD) { + parseAttribute(st.sval, st, leaf); + } + else { + throwParseException(st, "Bad Leaf: " + leaf); + } + } + addSplitChild(parent, leaf); + } + + private static void parseSplit(StreamTokenizer st, Split parent) throws Exception { + int token; + while ((token = st.nextToken()) != StreamTokenizer.TT_EOF) { + if (token == ')') { + break; + } + else if (token == StreamTokenizer.TT_WORD) { + if (st.sval.equalsIgnoreCase("WEIGHT")) { + parseAttribute(st.sval, st, parent); + } + else if (st.sval.equalsIgnoreCase("NAME")) { + parseAttribute(st.sval, st, parent); + } + else { + addSplitChild(parent, new Leaf(st.sval)); + } + } + else if (token == '(') { + if ((token = st.nextToken()) != StreamTokenizer.TT_WORD) { + throwParseException(st, "invalid node type"); + } + String nodeType = st.sval.toUpperCase(); + if (nodeType.equals("LEAF")) { + parseLeaf(st, parent); + } + else if (nodeType.equals("ROW") || nodeType.equals("COLUMN")) { + Split split = new Split(); + split.setRowLayout(nodeType.equals("ROW")); + addSplitChild(parent, split); + parseSplit(st, split); + } + else { + throwParseException(st, "unrecognized node type '" + nodeType + "'"); + } + } + } + } + + private static Node parseModel(Reader r) { + StreamTokenizer st = new StreamTokenizer(r); + try { + Split root = new Split(); + parseSplit(st, root); + return root.getChildren().get(0); + } + catch (Exception e) { + System.err.println(e); + } + finally { + try { r.close(); } catch (IOException ignore) {} + } + return null; + } + + /** + * A convenience method that converts a string to a + * MultiSplitLayout model (a tree of Nodes) using a + * a simple syntax. Nodes are represented by + * parenthetical expressions whose first token + * is one of ROW/COLUMN/LEAF. ROW and COLUMN specify + * horizontal and vertical Split nodes respectively, + * LEAF specifies a Leaf node. A Leaf's name and + * weight can be specified with attributes, + * name=myLeafName weight=myLeafWeight. + * Similarly, a Split's weight can be specified with + * weight=mySplitWeight. + * + *

    For example, the following expression generates + * a horizontal Split node with three children: + * the Leafs named left and right, and a Divider in + * between: + *

    +   * (ROW (LEAF name=left) (LEAF name=right weight=1.0))
    +   * 
    + * + *

    Dividers should not be included in the string, + * they're added automatcially as needed. Because + * Leaf nodes often only need to specify a name, one + * can specify a Leaf by just providing the name. + * The previous example can be written like this: + *

    +   * (ROW left (LEAF name=right weight=1.0))
    +   * 
    + * + *

    Here's a more complex example. One row with + * three elements, the first and last of which are columns + * with two leaves each: + *

    +   * (ROW (COLUMN weight=0.5 left.top left.bottom)
    +   *      (LEAF name=middle)
    +   *      (COLUMN weight=0.5 right.top right.bottom))
    +   * 
    + * + * + *

    This syntax is not intended for archiving or + * configuration files . It's just a convenience for + * examples and tests. + * + * @return the Node root of a tree based on s. + */ + public static Node parseModel(String s) { + return parseModel(new StringReader(s)); + } + + + private static void printModel(String indent, Node root) { + if (root instanceof Split) { + Split split = (Split)root; + System.out.println(indent + split); + for(Node child : split.getChildren()) { + printModel(indent + " ", child); + } + } + else { + System.out.println(indent + root); + } + } + + /** + * Print the tree with enough detail for simple debugging. + */ + public static void printModel(Node root) { + printModel("", root); + } +} \ No newline at end of file diff --git a/src/org/jdesktop/swingx/MultiSplitPane.java b/src/org/jdesktop/swingx/MultiSplitPane.java deleted file mode 100644 index 5f462f4178f..00000000000 --- a/src/org/jdesktop/swingx/MultiSplitPane.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * $Id: MultiSplitPane.java,v 1.15 2005/10/26 14:29:54 hansmuller Exp $ - * - * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, - * Santa Clara, California 95054, U.S.A. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package org.jdesktop.swingx; - -import java.awt.Color; -import java.awt.Cursor; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseEvent; -import javax.accessibility.AccessibleContext; -import javax.accessibility.AccessibleRole; -import javax.swing.JPanel; -import javax.swing.event.MouseInputAdapter; -import org.jdesktop.swingx.MultiSplitLayout.Divider; -import org.jdesktop.swingx.MultiSplitLayout.Node; - -/** - * - *

    - * All properties in this class are bound: when a properties value - * is changed, all PropertyChangeListeners are fired. - * - * @author Hans Muller - */ - -public class MultiSplitPane extends JPanel { - - private static final long serialVersionUID = 3379001167792141242L; - - private AccessibleContext accessibleContext = null; - private boolean continuousLayout = true; - private DividerPainter dividerPainter = new DefaultDividerPainter(); - - /** - * Creates a MultiSplitPane with it's LayoutManager set to - * to an empty MultiSplitLayout. - */ - public MultiSplitPane() { - super(new MultiSplitLayout()); - InputHandler inputHandler = new InputHandler(); - addMouseListener(inputHandler); - addMouseMotionListener(inputHandler); - addKeyListener(inputHandler); - setFocusable(true); - } - - /** - * A convenience method that returns the layout manager cast - * to MutliSplitLayout. - * - * @return this MultiSplitPane's layout manager - * @see java.awt.Container#getLayout - * @see #setModel - */ - public final MultiSplitLayout getMultiSplitLayout() { - return (MultiSplitLayout)getLayout(); - } - - /** - * A convenience method that sets the MultiSplitLayout model. - * Equivalent to getMultiSplitLayout.setModel(model) - * - * @param model the root of the MultiSplitLayout model - * @see #getMultiSplitLayout - * @see MultiSplitLayout#setModel - */ - public final void setModel(Node model) { - getMultiSplitLayout().setModel(model); - } - - /** - * A convenience method that sets the MultiSplitLayout dividerSize - * property. Equivalent to - * getMultiSplitLayout().setDividerSize(newDividerSize). - * - * @param dividerSize the value of the dividerSize property - * @see #getMultiSplitLayout - * @see MultiSplitLayout#setDividerSize - */ - public final void setDividerSize(int dividerSize) { - getMultiSplitLayout().setDividerSize(dividerSize); - } - - /** - * Sets the value of the continuousLayout property. - * If true, then the layout is revalidated continuously while - * a divider is being moved. The default value of this property - * is true. - * - * @param continuousLayout value of the continuousLayout property - * @see #isContinuousLayout - */ - public void setContinuousLayout(boolean continuousLayout) { - boolean oldContinuousLayout = continuousLayout; - this.continuousLayout = continuousLayout; - firePropertyChange("continuousLayout", oldContinuousLayout, continuousLayout); - } - - /** - * Returns true if dragging a divider only updates - * the layout when the drag gesture ends (typically, when the - * mouse button is released). - * - * @return the value of the continuousLayout property - * @see #setContinuousLayout - */ - public boolean isContinuousLayout() { - return continuousLayout; - } - - /** - * Returns the Divider that's currently being moved, typically - * because the user is dragging it, or null. - * - * @return the Divider that's being moved or null. - */ - public Divider activeDivider() { - return dragDivider; - } - - /** - * Draws a single Divider. Typically used to specialize the - * way the active Divider is painted. - * - * @see #getDividerPainter - * @see #setDividerPainter - */ - public static abstract class DividerPainter { - /** - * Paint a single Divider. - * - * @param g the Graphics object to paint with - * @param divider the Divider to paint - */ - public abstract void paint(Graphics g, Divider divider); - } - - private class DefaultDividerPainter extends DividerPainter { - public void paint(Graphics g, Divider divider) { - if ((divider == activeDivider()) && !isContinuousLayout()) { - Graphics2D g2d = (Graphics2D)g; - g2d.setColor(Color.black); - g2d.fill(divider.getBounds()); - } - } - } - - /** - * The DividerPainter that's used to paint Dividers on this MultiSplitPane. - * This property may be null. - * - * @return the value of the dividerPainter Property - * @see #setDividerPainter - */ - public DividerPainter getDividerPainter() { - return dividerPainter; - } - - /** - * Sets the DividerPainter that's used to paint Dividers on this - * MultiSplitPane. The default DividerPainter only draws - * the activeDivider (if there is one) and then, only if - * continuousLayout is false. The value of this property is - * used by the paintChildren method: Dividers are painted after - * the MultiSplitPane's children have been rendered so that - * the activeDivider can appear "on top of" the children. - * - * @param dividerPainter the value of the dividerPainter property, can be null - * @see #paintChildren - * @see #activeDivider - */ - public void setDividerPainter(DividerPainter dividerPainter) { - this.dividerPainter = dividerPainter; - } - - /** - * Uses the DividerPainter (if any) to paint each Divider that - * overlaps the clip Rectangle. This is done after the call to - * super.paintChildren() so that Dividers can be - * rendered "on top of" the children. - *

    - * {@inheritDoc} - */ - protected void paintChildren(Graphics g) { - super.paintChildren(g); - DividerPainter dp = getDividerPainter(); - Rectangle clipR = g.getClipBounds(); - if ((dp != null) && (clipR != null)) { - Graphics dpg = g.create(); - try { - MultiSplitLayout msl = getMultiSplitLayout(); - for(Divider divider : msl.dividersThatOverlap(clipR)) { - dp.paint(dpg, divider); - } - } - finally { - dpg.dispose(); - } - } - } - - private boolean dragUnderway = false; - private MultiSplitLayout.Divider dragDivider = null; - private Rectangle initialDividerBounds = null; - private boolean oldFloatingDividers = true; - private int dragOffsetX = 0; - private int dragOffsetY = 0; - private int dragMin = -1; - private int dragMax = -1; - - private void startDrag(int mx, int my) { - requestFocusInWindow(); - MultiSplitLayout msl = getMultiSplitLayout(); - MultiSplitLayout.Divider divider = msl.dividerAt(mx, my); - if (divider != null) { - MultiSplitLayout.Node prevNode = divider.previousSibling(); - MultiSplitLayout.Node nextNode = divider.nextSibling(); - if ((prevNode == null) || (nextNode == null)) { - dragUnderway = false; - } - else { - initialDividerBounds = divider.getBounds(); - dragOffsetX = mx - initialDividerBounds.x; - dragOffsetY = my - initialDividerBounds.y; - dragDivider = divider; - Rectangle prevNodeBounds = prevNode.getBounds(); - Rectangle nextNodeBounds = nextNode.getBounds(); - if (dragDivider.isVertical()) { - dragMin = prevNodeBounds.x; - dragMax = nextNodeBounds.x + nextNodeBounds.width; - dragMax -= dragDivider.getBounds().width; - } - else { - dragMin = prevNodeBounds.y; - dragMax = nextNodeBounds.y + nextNodeBounds.height; - dragMax -= dragDivider.getBounds().height; - } - oldFloatingDividers = getMultiSplitLayout().getFloatingDividers(); - getMultiSplitLayout().setFloatingDividers(false); - dragUnderway = true; - } - } - else { - dragUnderway = false; - } - } - - private void repaintDragLimits() { - Rectangle damageR = dragDivider.getBounds(); - if (dragDivider.isVertical()) { - damageR.x = dragMin; - damageR.width = dragMax - dragMin; - } - else { - damageR.y = dragMin; - damageR.height = dragMax - dragMin; - } - repaint(damageR); - } - - private void updateDrag(int mx, int my) { - if (!dragUnderway) { - return; - } - Rectangle oldBounds = dragDivider.getBounds(); - Rectangle bounds = new Rectangle(oldBounds); - if (dragDivider.isVertical()) { - bounds.x = mx - dragOffsetX; - bounds.x = Math.max(bounds.x, dragMin); - bounds.x = Math.min(bounds.x, dragMax); - } - else { - bounds.y = my - dragOffsetY; - bounds.y = Math.max(bounds.y, dragMin); - bounds.y = Math.min(bounds.y, dragMax); - } - dragDivider.setBounds(bounds); - if (isContinuousLayout()) { - revalidate(); - repaintDragLimits(); - } - else { - repaint(oldBounds.union(bounds)); - } - } - - private void clearDragState() { - dragDivider = null; - initialDividerBounds = null; - oldFloatingDividers = true; - dragOffsetX = dragOffsetY = 0; - dragMin = dragMax = -1; - dragUnderway = false; - } - - private void finishDrag(int x, int y) { - if (dragUnderway) { - clearDragState(); - if (!isContinuousLayout()) { - revalidate(); - repaint(); - } - } - } - - private void cancelDrag() { - if (dragUnderway) { - dragDivider.setBounds(initialDividerBounds); - getMultiSplitLayout().setFloatingDividers(oldFloatingDividers); - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - repaint(); - revalidate(); - clearDragState(); - } - } - - private void updateCursor(int x, int y, boolean show) { - if (dragUnderway) { - return; - } - int cursorID = Cursor.DEFAULT_CURSOR; - if (show) { - MultiSplitLayout.Divider divider = getMultiSplitLayout().dividerAt(x, y); - if (divider != null) { - cursorID = (divider.isVertical()) ? - Cursor.E_RESIZE_CURSOR : - Cursor.N_RESIZE_CURSOR; - } - } - setCursor(Cursor.getPredefinedCursor(cursorID)); - } - - - private class InputHandler extends MouseInputAdapter implements KeyListener { - - public void mouseEntered(MouseEvent e) { - updateCursor(e.getX(), e.getY(), true); - } - - public void mouseMoved(MouseEvent e) { - updateCursor(e.getX(), e.getY(), true); - } - - public void mouseExited(MouseEvent e) { - updateCursor(e.getX(), e.getY(), false); - } - - public void mousePressed(MouseEvent e) { - startDrag(e.getX(), e.getY()); - } - public void mouseReleased(MouseEvent e) { - finishDrag(e.getX(), e.getY()); - } - public void mouseDragged(MouseEvent e) { - updateDrag(e.getX(), e.getY()); - } - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { - cancelDrag(); - } - } - public void keyReleased(KeyEvent e) { } - public void keyTyped(KeyEvent e) { } - } - - public AccessibleContext getAccessibleContext() { - if( accessibleContext == null ) { - accessibleContext = new AccessibleMultiSplitPane(); - } - return accessibleContext; - } - - protected class AccessibleMultiSplitPane extends AccessibleJPanel { - - private static final long serialVersionUID = 4177114112369591280L; - - public AccessibleRole getAccessibleRole() { - return AccessibleRole.SPLIT_PANE; - } - } -} diff --git a/src/org/jdesktop/swingx/graphics/GraphicsUtilities.java b/src/org/jdesktop/swingx/graphics/GraphicsUtilities.java new file mode 100644 index 00000000000..4c1980eb1ff --- /dev/null +++ b/src/org/jdesktop/swingx/graphics/GraphicsUtilities.java @@ -0,0 +1,765 @@ +/* + * $Id$ + * + * Dual-licensed under LGPL (Sun and Romain Guy) and BSD (Romain Guy). + * + * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * Copyright (c) 2006 Romain Guy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jdesktop.swingx.graphics; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Transparency; +import java.awt.geom.Area; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.imageio.ImageIO; + +/** + *

    GraphicsUtilities contains a set of tools to perform + * common graphics operations easily. These operations are divided into + * several themes, listed below.

    + * + *

    Compatible Images

    + * + *

    Compatible images can, and should, be used to increase drawing + * performance. This class provides a number of methods to load compatible + * images directly from files or to convert existing images to compatibles + * images.

    + * + *

    Creating Thumbnails

    + * + *

    This class provides a number of methods to easily scale down images. + * Some of these methods offer a trade-off between speed and result quality and + * shouuld be used all the time. They also offer the advantage of producing + * compatible images, thus automatically resulting into better runtime + * performance.

    + * + *

    All these methodes are both faster than + * {@link java.awt.Image#getScaledInstance(int, int, int)} and produce + * better-looking results than the various drawImage() methods + * in {@link java.awt.Graphics}, which can be used for image scaling.

    + *

    Image Manipulation

    + * + *

    This class provides two methods to get and set pixels in a buffered image. + * These methods try to avoid unmanaging the image in order to keep good + * performance.

    + * + * @author Romain Guy + * @author rbair + */ +public class GraphicsUtilities { + private GraphicsUtilities() { + } + + // Returns the graphics configuration for the primary screen + private static GraphicsConfiguration getGraphicsConfiguration() { + return GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + } + + private static boolean isHeadless() { + return GraphicsEnvironment.isHeadless(); + } + + /** + * Converts the specified image into a compatible buffered image. + * + * @param img + * the image to convert + * @return a compatible buffered image of the input + */ + public static BufferedImage convertToBufferedImage(Image img) { + BufferedImage buff = createCompatibleTranslucentImage( + img.getWidth(null), img.getHeight(null)); + Graphics2D g2 = buff.createGraphics(); + + try { + g2.drawImage(img, 0, 0, null); + } finally { + g2.dispose(); + } + + return buff; + } + + /** + *

    Returns a new BufferedImage using the same color model + * as the image passed as a parameter. The returned image is only compatible + * with the image passed as a parameter. This does not mean the returned + * image is compatible with the hardware.

    + * + * @param image the reference image from which the color model of the new + * image is obtained + * @return a new BufferedImage, compatible with the color model + * of image + */ + public static BufferedImage createColorModelCompatibleImage(BufferedImage image) { + ColorModel cm = image.getColorModel(); + return new BufferedImage(cm, + cm.createCompatibleWritableRaster(image.getWidth(), + image.getHeight()), + cm.isAlphaPremultiplied(), null); + } + + /** + *

    Returns a new compatible image with the same width, height and + * transparency as the image specified as a parameter. That is, the + * returned BufferedImage will be compatible with the graphics hardware. + * If this method is called in a headless environment, then + * the returned BufferedImage will be compatible with the source + * image.

    + * + * @see java.awt.Transparency + * @see #createCompatibleImage(int, int) + * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) + * @see #createCompatibleTranslucentImage(int, int) + * @see #loadCompatibleImage(java.net.URL) + * @see #toCompatibleImage(java.awt.image.BufferedImage) + * @param image the reference image from which the dimension and the + * transparency of the new image are obtained + * @return a new compatible BufferedImage with the same + * dimension and transparency as image + */ + public static BufferedImage createCompatibleImage(BufferedImage image) { + return createCompatibleImage(image, image.getWidth(), image.getHeight()); + } + + /** + *

    Returns a new compatible image of the specified width and height, and + * the same transparency setting as the image specified as a parameter. + * That is, the returned BufferedImage is compatible with + * the graphics hardware. If the method is called in a headless + * environment, then the returned BufferedImage will be compatible with + * the source image.

    + * + * @see java.awt.Transparency + * @see #createCompatibleImage(java.awt.image.BufferedImage) + * @see #createCompatibleImage(int, int) + * @see #createCompatibleTranslucentImage(int, int) + * @see #loadCompatibleImage(java.net.URL) + * @see #toCompatibleImage(java.awt.image.BufferedImage) + * @param width the width of the new image + * @param height the height of the new image + * @param image the reference image from which the transparency of the new + * image is obtained + * @return a new compatible BufferedImage with the same + * transparency as image and the specified dimension + */ + public static BufferedImage createCompatibleImage(BufferedImage image, + int width, int height) { + return isHeadless() ? + new BufferedImage(width, height, image.getType()) : + getGraphicsConfiguration().createCompatibleImage(width, height, + image.getTransparency()); + } + + /** + *

    Returns a new opaque compatible image of the specified width and + * height. That is, the returned BufferedImage is compatible with + * the graphics hardware. If the method is called in a headless + * environment, then the returned BufferedImage will be compatible with + * the source image.

    + * + * @see #createCompatibleImage(java.awt.image.BufferedImage) + * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) + * @see #createCompatibleTranslucentImage(int, int) + * @see #loadCompatibleImage(java.net.URL) + * @see #toCompatibleImage(java.awt.image.BufferedImage) + * @param width the width of the new image + * @param height the height of the new image + * @return a new opaque compatible BufferedImage of the + * specified width and height + */ + public static BufferedImage createCompatibleImage(int width, int height) { + return isHeadless() ? + new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB) : + getGraphicsConfiguration().createCompatibleImage(width, height); + } + + /** + *

    Returns a new translucent compatible image of the specified width and + * height. That is, the returned BufferedImage is compatible with + * the graphics hardware. If the method is called in a headless + * environment, then the returned BufferedImage will be compatible with + * the source image.

    + * + * @see #createCompatibleImage(java.awt.image.BufferedImage) + * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) + * @see #createCompatibleImage(int, int) + * @see #loadCompatibleImage(java.net.URL) + * @see #toCompatibleImage(java.awt.image.BufferedImage) + * @param width the width of the new image + * @param height the height of the new image + * @return a new translucent compatible BufferedImage of the + * specified width and height + */ + public static BufferedImage createCompatibleTranslucentImage(int width, + int height) { + return isHeadless() ? + new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) : + getGraphicsConfiguration().createCompatibleImage(width, height, + Transparency.TRANSLUCENT); + } + + /** + *

    + * Returns a new compatible image from a stream. The image is loaded from + * the specified stream and then turned, if necessary into a compatible + * image. + *

    + * + * @see #createCompatibleImage(java.awt.image.BufferedImage) + * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) + * @see #createCompatibleImage(int, int) + * @see #createCompatibleTranslucentImage(int, int) + * @see #toCompatibleImage(java.awt.image.BufferedImage) + * @param in + * the stream of the picture to load as a compatible image + * @return a new translucent compatible BufferedImage of the + * specified width and height + * @throws java.io.IOException + * if the image cannot be read or loaded + */ + public static BufferedImage loadCompatibleImage(InputStream in) throws IOException { + BufferedImage image = ImageIO.read(in); + if(image == null) return null; + return toCompatibleImage(image); + } + + /** + *

    Returns a new compatible image from a URL. The image is loaded from the + * specified location and then turned, if necessary into a compatible + * image.

    + * + * @see #createCompatibleImage(java.awt.image.BufferedImage) + * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) + * @see #createCompatibleImage(int, int) + * @see #createCompatibleTranslucentImage(int, int) + * @see #toCompatibleImage(java.awt.image.BufferedImage) + * @param resource the URL of the picture to load as a compatible image + * @return a new translucent compatible BufferedImage of the + * specified width and height + * @throws java.io.IOException if the image cannot be read or loaded + */ + public static BufferedImage loadCompatibleImage(URL resource) + throws IOException { + BufferedImage image = ImageIO.read(resource); + return toCompatibleImage(image); + } + + /** + *

    Return a new compatible image that contains a copy of the specified + * image. This method ensures an image is compatible with the hardware, + * and therefore optimized for fast blitting operations.

    + * + *

    If the method is called in a headless environment, then the returned + * BufferedImage will be the source image.

    + * + * @see #createCompatibleImage(java.awt.image.BufferedImage) + * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) + * @see #createCompatibleImage(int, int) + * @see #createCompatibleTranslucentImage(int, int) + * @see #loadCompatibleImage(java.net.URL) + * @param image the image to copy into a new compatible image + * @return a new compatible copy, with the + * same width and height and transparency and content, of image + */ + public static BufferedImage toCompatibleImage(BufferedImage image) { + if (isHeadless()) { + return image; + } + + if (image.getColorModel().equals( + getGraphicsConfiguration().getColorModel())) { + return image; + } + + BufferedImage compatibleImage = + getGraphicsConfiguration().createCompatibleImage( + image.getWidth(), image.getHeight(), + image.getTransparency()); + Graphics g = compatibleImage.getGraphics(); + + try { + g.drawImage(image, 0, 0, null); + } finally { + g.dispose(); + } + + return compatibleImage; + } + + /** + *

    Returns a thumbnail of a source image. newSize defines + * the length of the longest dimension of the thumbnail. The other + * dimension is then computed according to the dimensions ratio of the + * original picture.

    + *

    This method favors speed over quality. When the new size is less than + * half the longest dimension of the source image, + * {@link #createThumbnail(BufferedImage, int)} or + * {@link #createThumbnail(BufferedImage, int, int)} should be used instead + * to ensure the quality of the result without sacrificing too much + * performance.

    + * + * @see #createThumbnailFast(java.awt.image.BufferedImage, int, int) + * @see #createThumbnail(java.awt.image.BufferedImage, int) + * @see #createThumbnail(java.awt.image.BufferedImage, int, int) + * @param image the source image + * @param newSize the length of the largest dimension of the thumbnail + * @return a new compatible BufferedImage containing a + * thumbnail of image + * @throws IllegalArgumentException if newSize is larger than + * the largest dimension of image or <= 0 + */ + public static BufferedImage createThumbnailFast(BufferedImage image, + int newSize) { + float ratio; + int width = image.getWidth(); + int height = image.getHeight(); + + if (width > height) { + if (newSize >= width) { + throw new IllegalArgumentException("newSize must be lower than" + + " the image width"); + } else if (newSize <= 0) { + throw new IllegalArgumentException("newSize must" + + " be greater than 0"); + } + + ratio = (float) width / (float) height; + width = newSize; + height = (int) (newSize / ratio); + } else { + if (newSize >= height) { + throw new IllegalArgumentException("newSize must be lower than" + + " the image height"); + } else if (newSize <= 0) { + throw new IllegalArgumentException("newSize must" + + " be greater than 0"); + } + + ratio = (float) height / (float) width; + height = newSize; + width = (int) (newSize / ratio); + } + + BufferedImage temp = createCompatibleImage(image, width, height); + Graphics2D g2 = temp.createGraphics(); + + try { + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(image, 0, 0, temp.getWidth(), temp.getHeight(), null); + } finally { + g2.dispose(); + } + + return temp; + } + + /** + *

    Returns a thumbnail of a source image.

    + *

    This method favors speed over quality. When the new size is less than + * half the longest dimension of the source image, + * {@link #createThumbnail(BufferedImage, int)} or + * {@link #createThumbnail(BufferedImage, int, int)} should be used instead + * to ensure the quality of the result without sacrificing too much + * performance.

    + * + * @see #createThumbnailFast(java.awt.image.BufferedImage, int) + * @see #createThumbnail(java.awt.image.BufferedImage, int) + * @see #createThumbnail(java.awt.image.BufferedImage, int, int) + * @param image the source image + * @param newWidth the width of the thumbnail + * @param newHeight the height of the thumbnail + * @return a new compatible BufferedImage containing a + * thumbnail of image + * @throws IllegalArgumentException if newWidth is larger than + * the width of image or if code>newHeight is larger + * than the height of image or if one of the dimensions + * is <= 0 + */ + public static BufferedImage createThumbnailFast(BufferedImage image, + int newWidth, int newHeight) { + if (newWidth >= image.getWidth() || + newHeight >= image.getHeight()) { + throw new IllegalArgumentException("newWidth and newHeight cannot" + + " be greater than the image" + + " dimensions"); + } else if (newWidth <= 0 || newHeight <= 0) { + throw new IllegalArgumentException("newWidth and newHeight must" + + " be greater than 0"); + } + + BufferedImage temp = createCompatibleImage(image, newWidth, newHeight); + Graphics2D g2 = temp.createGraphics(); + + try { + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(image, 0, 0, temp.getWidth(), temp.getHeight(), null); + } finally { + g2.dispose(); + } + + return temp; + } + + /** + *

    Returns a thumbnail of a source image. newSize defines + * the length of the longest dimension of the thumbnail. The other + * dimension is then computed according to the dimensions ratio of the + * original picture.

    + *

    This method offers a good trade-off between speed and quality. + * The result looks better than + * {@link #createThumbnailFast(java.awt.image.BufferedImage, int)} when + * the new size is less than half the longest dimension of the source + * image, yet the rendering speed is almost similar.

    + * + * @see #createThumbnailFast(java.awt.image.BufferedImage, int, int) + * @see #createThumbnailFast(java.awt.image.BufferedImage, int) + * @see #createThumbnail(java.awt.image.BufferedImage, int, int) + * @param image the source image + * @param newSize the length of the largest dimension of the thumbnail + * @return a new compatible BufferedImage containing a + * thumbnail of image + * @throws IllegalArgumentException if newSize is larger than + * the largest dimension of image or <= 0 + */ + public static BufferedImage createThumbnail(BufferedImage image, + int newSize) { + int width = image.getWidth(); + int height = image.getHeight(); + + boolean isTranslucent = image.getTransparency() != Transparency.OPAQUE; + boolean isWidthGreater = width > height; + + if (isWidthGreater) { + if (newSize >= width) { + throw new IllegalArgumentException("newSize must be lower than" + + " the image width"); + } + } else if (newSize >= height) { + throw new IllegalArgumentException("newSize must be lower than" + + " the image height"); + } + + if (newSize <= 0) { + throw new IllegalArgumentException("newSize must" + + " be greater than 0"); + } + + float ratioWH = (float) width / (float) height; + float ratioHW = (float) height / (float) width; + + BufferedImage thumb = image; + BufferedImage temp = null; + + Graphics2D g2 = null; + + try { + int previousWidth = width; + int previousHeight = height; + + do { + if (isWidthGreater) { + width /= 2; + if (width < newSize) { + width = newSize; + } + height = (int) (width / ratioWH); + } else { + height /= 2; + if (height < newSize) { + height = newSize; + } + width = (int) (height / ratioHW); + } + + if (temp == null || isTranslucent) { + if (g2 != null) { + //do not need to wrap with finally + //outer finally block will ensure + //that resources are properly reclaimed + g2.dispose(); + } + temp = createCompatibleImage(image, width, height); + g2 = temp.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + } + g2.drawImage(thumb, 0, 0, width, height, + 0, 0, previousWidth, previousHeight, null); + + previousWidth = width; + previousHeight = height; + + thumb = temp; + } while (newSize != (isWidthGreater ? width : height)); + } finally { + g2.dispose(); + } + + if (width != thumb.getWidth() || height != thumb.getHeight()) { + temp = createCompatibleImage(image, width, height); + g2 = temp.createGraphics(); + + try { + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(thumb, 0, 0, width, height, 0, 0, width, height, null); + } finally { + g2.dispose(); + } + + thumb = temp; + } + + return thumb; + } + + /** + *

    Returns a thumbnail of a source image.

    + *

    This method offers a good trade-off between speed and quality. + * The result looks better than + * {@link #createThumbnailFast(java.awt.image.BufferedImage, int)} when + * the new size is less than half the longest dimension of the source + * image, yet the rendering speed is almost similar.

    + * + * @see #createThumbnailFast(java.awt.image.BufferedImage, int) + * @see #createThumbnailFast(java.awt.image.BufferedImage, int, int) + * @see #createThumbnail(java.awt.image.BufferedImage, int) + * @param image the source image + * @param newWidth the width of the thumbnail + * @param newHeight the height of the thumbnail + * @return a new compatible BufferedImage containing a + * thumbnail of image + * @throws IllegalArgumentException if newWidth is larger than + * the width of image or if code>newHeight is larger + * than the height of image or if one the dimensions is not > 0 + */ + public static BufferedImage createThumbnail(BufferedImage image, + int newWidth, int newHeight) { + int width = image.getWidth(); + int height = image.getHeight(); + + boolean isTranslucent = image.getTransparency() != Transparency.OPAQUE; + + if (newWidth >= width || newHeight >= height) { + throw new IllegalArgumentException("newWidth and newHeight cannot" + + " be greater than the image" + + " dimensions"); + } else if (newWidth <= 0 || newHeight <= 0) { + throw new IllegalArgumentException("newWidth and newHeight must" + + " be greater than 0"); + } + + BufferedImage thumb = image; + BufferedImage temp = null; + + Graphics2D g2 = null; + + try { + int previousWidth = width; + int previousHeight = height; + + do { + if (width > newWidth) { + width /= 2; + if (width < newWidth) { + width = newWidth; + } + } + + if (height > newHeight) { + height /= 2; + if (height < newHeight) { + height = newHeight; + } + } + + if (temp == null || isTranslucent) { + if (g2 != null) { + //do not need to wrap with finally + //outer finally block will ensure + //that resources are properly reclaimed + g2.dispose(); + } + temp = createCompatibleImage(image, width, height); + g2 = temp.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + } + g2.drawImage(thumb, 0, 0, width, height, + 0, 0, previousWidth, previousHeight, null); + + previousWidth = width; + previousHeight = height; + + thumb = temp; + } while (width != newWidth || height != newHeight); + } finally { + g2.dispose(); + } + + if (width != thumb.getWidth() || height != thumb.getHeight()) { + temp = createCompatibleImage(image, width, height); + g2 = temp.createGraphics(); + + try { + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(thumb, 0, 0, width, height, 0, 0, width, height, null); + } finally { + g2.dispose(); + } + + thumb = temp; + } + + return thumb; + } + + /** + *

    Returns an array of pixels, stored as integers, from a + * BufferedImage. The pixels are grabbed from a rectangular + * area defined by a location and two dimensions. Calling this method on + * an image of type different from BufferedImage.TYPE_INT_ARGB + * and BufferedImage.TYPE_INT_RGB will unmanage the image.

    + * + * @param img the source image + * @param x the x location at which to start grabbing pixels + * @param y the y location at which to start grabbing pixels + * @param w the width of the rectangle of pixels to grab + * @param h the height of the rectangle of pixels to grab + * @param pixels a pre-allocated array of pixels of size w*h; can be null + * @return pixels if non-null, a new array of integers + * otherwise + * @throws IllegalArgumentException is pixels is non-null and + * of length < w*h + */ + public static int[] getPixels(BufferedImage img, + int x, int y, int w, int h, int[] pixels) { + if (w == 0 || h == 0) { + return new int[0]; + } + + if (pixels == null) { + pixels = new int[w * h]; + } else if (pixels.length < w * h) { + throw new IllegalArgumentException("pixels array must have a length" + + " >= w*h"); + } + + int imageType = img.getType(); + if (imageType == BufferedImage.TYPE_INT_ARGB || + imageType == BufferedImage.TYPE_INT_RGB) { + Raster raster = img.getRaster(); + return (int[]) raster.getDataElements(x, y, w, h, pixels); + } + + // Unmanages the image + return img.getRGB(x, y, w, h, pixels, 0, w); + } + + /** + *

    Writes a rectangular area of pixels in the destination + * BufferedImage. Calling this method on + * an image of type different from BufferedImage.TYPE_INT_ARGB + * and BufferedImage.TYPE_INT_RGB will unmanage the image.

    + * + * @param img the destination image + * @param x the x location at which to start storing pixels + * @param y the y location at which to start storing pixels + * @param w the width of the rectangle of pixels to store + * @param h the height of the rectangle of pixels to store + * @param pixels an array of pixels, stored as integers + * @throws IllegalArgumentException is pixels is non-null and + * of length < w*h + */ + public static void setPixels(BufferedImage img, + int x, int y, int w, int h, int[] pixels) { + if (pixels == null || w == 0 || h == 0) { + return; + } else if (pixels.length < w * h) { + throw new IllegalArgumentException("pixels array must have a length" + + " >= w*h"); + } + + int imageType = img.getType(); + if (imageType == BufferedImage.TYPE_INT_ARGB || + imageType == BufferedImage.TYPE_INT_RGB) { + WritableRaster raster = img.getRaster(); + raster.setDataElements(x, y, w, h, pixels); + } else { + // Unmanages the image + img.setRGB(x, y, w, h, pixels, 0, w); + } + } + + /** + * Sets the clip on a graphics object by merging a supplied clip with the + * existing one. The new clip will be an intersection of the old clip and + * the supplied clip. The old clip shape will be returned. This is useful + * for resetting the old clip after an operation is performed. + * + * @param g + * the graphics object to update + * @param clip + * a new clipping region to add to the graphics clip. This may + * return {@code null} if the current clip is {@code null}. + * @return the current clipping region of the supplied graphics object + * @throws NullPointerException + * if any parameter is {@code null} + */ + public static Shape mergeClip(Graphics g, Shape clip) { + Shape oldClip = g.getClip(); + if(oldClip == null) { + g.setClip(clip); + return null; + } + Area area = new Area(oldClip); + area.intersect(new Area(clip));//new Rectangle(0,0,width,height))); + g.setClip(area); + return oldClip; + } +} \ No newline at end of file diff --git a/src/org/jdesktop/swingx/painter/AbstractPainter.java b/src/org/jdesktop/swingx/painter/AbstractPainter.java new file mode 100644 index 00000000000..00552c42f95 --- /dev/null +++ b/src/org/jdesktop/swingx/painter/AbstractPainter.java @@ -0,0 +1,427 @@ +/* + * $Id$ + * + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package org.jdesktop.swingx.painter; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.lang.ref.SoftReference; + +import org.jdesktop.beans.AbstractBean; +import org.jdesktop.swingx.graphics.GraphicsUtilities; + +/** + *

    A convenient base class from which concrete {@link Painter} implementations may + * extend. It extends {@link org.jdesktop.beans.AbstractBean} as a convenience for + * adding property change notification support. In addition, AbstractPainter + * provides subclasses with the ability to cacheable painting operations, configure the + * drawing surface with common settings (such as antialiasing and interpolation), and + * toggle whether a subclass paints or not via the visibility property.

    + * + *

    Subclasses of AbstractPainter generally need only override the + * {@link #doPaint(Graphics2D, Object, int, int)} method. If a subclass requires more control + * over whether cacheing is enabled, or for configuring the graphics state, then it + * may override the appropriate protected methods to interpose its own behavior.

    + * + *

    For example, here is the doPaint method of a simple Painter that + * paints an opaque rectangle: + *

    
    + *  public void doPaint(Graphics2D g, T obj, int width, int height) {
    + *      g.setPaint(Color.BLUE);
    + *      g.fillRect(0, 0, width, height);
    + *  }
    + * 

    + * + * @author rbair + */ +public abstract class AbstractPainter extends AbstractBean implements Painter { + /** + * An enum representing the possible interpolation values of Bicubic, Bilinear, and + * Nearest Neighbor. These map to the underlying RenderingHints, + * but are easier to use and serialization safe. + */ + public enum Interpolation { + /** + * use bicubic interpolation + */ + Bicubic(RenderingHints.VALUE_INTERPOLATION_BICUBIC), + /** + * use bilinear interpolation + */ + Bilinear(RenderingHints.VALUE_INTERPOLATION_BILINEAR), + /** + * use nearest neighbor interpolation + */ + NearestNeighbor(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); + + private Object value; + Interpolation(Object value) { + this.value = value; + } + private void configureGraphics(Graphics2D g) { + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, value); + } + } + + //--------------------------------------------------- Instance Variables + /** + * The cached image, if shouldUseCache() returns true + */ + private transient SoftReference cachedImage; + private boolean cacheCleared = true; + private boolean cacheable = false; + private boolean dirty = false; + private BufferedImageOp[] filters = new BufferedImageOp[0]; + private boolean antialiasing = true; + private Interpolation interpolation = Interpolation.NearestNeighbor; + private boolean visible = true; + + /** + * Creates a new instance of AbstractPainter. + */ + public AbstractPainter() { } + + /** + * Creates a new instance of AbstractPainter. + * @param cacheable indicates if this painter should be cacheable + */ + public AbstractPainter(boolean cacheable) { + setCacheable(cacheable); + } + + /** + * A defensive copy of the Effects to apply to the results + * of the AbstractPainter's painting operation. The array may + * be empty but it will never be null. + * @return the array of filters applied to this painter + */ + public final BufferedImageOp[] getFilters() { + BufferedImageOp[] results = new BufferedImageOp[filters.length]; + System.arraycopy(filters, 0, results, 0, results.length); + return results; + } + + /** + *

    A convenience method for specifying the filters to use based on + * BufferedImageOps. These will each be individually wrapped by an ImageFilter + * and then setFilters(Effect... filters) will be called with the resulting + * array

    + * + * + * @param effects the BufferedImageOps to wrap as filters + */ + public void setFilters(BufferedImageOp ... effects) { + if (effects == null) effects = new BufferedImageOp[0]; + BufferedImageOp[] old = getFilters(); + this.filters = new BufferedImageOp[effects == null ? 0 : effects.length]; + System.arraycopy(effects, 0, this.filters, 0, this.filters.length); + setDirty(true); + firePropertyChange("filters", old, getFilters()); + } + + /** + * Returns if antialiasing is turned on or not. The default value is true. + * This is a bound property. + * @return the current antialiasing setting + */ + public boolean isAntialiasing() { + return antialiasing; + } + /** + * Sets the antialiasing setting. This is a bound property. + * @param value the new antialiasing setting + */ + public void setAntialiasing(boolean value) { + boolean old = isAntialiasing(); + antialiasing = value; + if (old != value) setDirty(true); + firePropertyChange("antialiasing", old, isAntialiasing()); + } + + /** + * Gets the current interpolation setting. This property determines if interpolation will + * be used when drawing scaled images. @see java.awt.RenderingHints.KEY_INTERPOLATION. + * @return the current interpolation setting + */ + public Interpolation getInterpolation() { + return interpolation; + } + + /** + * Sets a new value for the interpolation setting. This setting determines if interpolation + * should be used when drawing scaled images. @see java.awt.RenderingHints.KEY_INTERPOLATION. + * @param value the new interpolation setting + */ + public void setInterpolation(Interpolation value) { + Object old = getInterpolation(); + this.interpolation = value == null ? Interpolation.NearestNeighbor : value; + if (old != value) setDirty(true); + firePropertyChange("interpolation", old, getInterpolation()); + } + + /** + * Gets the visible property. This controls if the painter should + * paint itself. It is true by default. Setting visible to false + * is good when you want to temporarily turn off a painter. An example + * of this is a painter that you only use when a button is highlighted. + * + * @return current value of visible property + */ + public boolean isVisible() { + return this.visible; + } + + /** + *

    Sets the visible property. This controls if the painter should + * paint itself. It is true by default. Setting visible to false + * is good when you want to temporarily turn off a painter. An example + * of this is a painter that you only use when a button is highlighted.

    + * + * @param visible New value of visible property. + */ + public void setVisible(boolean visible) { + boolean old = isVisible(); + this.visible = visible; + if (old != visible) setDirty(true); //not the most efficient, but I must do this otherwise a CompoundPainter + //or other aggregate painter won't know that it is now invalid + //there might be a tricky solution but that is a performance optimization + firePropertyChange("visible", old, isVisible()); + } + + /** + *

    Gets whether this AbstractPainter can be cached as an image. + * If cacheing is enabled, then it is the responsibility of the developer to + * invalidate the painter (via {@link #clearCache}) if external state has + * changed in such a way that the painter is invalidated and needs to be + * repainted.

    + * + * @return whether this is cacheable + */ + public boolean isCacheable() { + return cacheable; + } + + /** + *

    Sets whether this AbstractPainter can be cached as an image. + * If true, this is treated as a hint. That is, a cacheable may or may not be used. + * The {@link #shouldUseCache} method actually determines whether the cacheable is used. + * However, if false, then this is treated as an absolute value. That is, no + * cacheable will be used.

    + * + *

    If set to false, then #clearCache is called to free system resources.

    + * + * @param cacheable + */ + public void setCacheable(boolean cacheable) { + boolean old = isCacheable(); + this.cacheable = cacheable; + firePropertyChange("cacheable", old, isCacheable()); + if (!isCacheable()) { + clearCache(); + } + } + + /** + *

    Call this method to clear the cacheable. This may be called whether there is + * a cacheable being used or not. If cleared, on the next call to paint, + * the painting routines will be called.

    + * + *

    SubclassesIf overridden in subclasses, you + * must call super.clearCache, or physical + * resources (such as an Image) may leak.

    + */ + public void clearCache() { + BufferedImage cache = cachedImage == null ? null : cachedImage.get(); + if (cache != null) { + cache.flush(); + } + cacheCleared = true; + if (!isCacheable()) { + cachedImage = null; + } + } + + /** + * Only made package private for testing. Don't call this method outside + * of this class! This is NOT a bound property + */ + boolean isCacheCleared() { + return cacheCleared; + } + + /** + *

    Called to allow Painter subclasses a chance to see if any state + * in the given object has changed from the last paint operation. If it has, then + * the Painter has a chance to mark itself as dirty, thus causing a + * repaint, even if cached.

    + * + * @param object + */ + protected void validate(T object) { } + + /** + * Ye olde dirty bit. If true, then the painter is considered dirty and in need of + * being repainted. This is a bound property. + * + * @return true if the painter state has changed and the painter needs to be + * repainted. + */ + protected boolean isDirty() { + return dirty; + } + + /** + * Sets the dirty bit. If true, then the painter is considered dirty, and the cache + * will be cleared. This property is bound. + * + * @param d whether this Painter is dirty. + */ + protected void setDirty(boolean d) { + boolean old = isDirty(); + this.dirty = d; + firePropertyChange("dirty", old, isDirty()); + if (isDirty()) { + clearCache(); + } + } + + /** + *

    Returns true if the painter should use caching. This method allows subclasses to + * specify the heuristics regarding whether to cache or not. If a Painter + * has intelligent rules regarding painting times, and can more accurately indicate + * whether it should be cached, it could implement that logic in this method.

    + * + * @return whether or not a cache should be used + */ + protected boolean shouldUseCache() { + return isCacheable() || filters.length > 0; //NOTE, I can only do this because getFilters() is final + } + + /** + *

    This method is called by the paint method prior to + * any drawing operations to configure the drawing surface. The default + * implementation sets the rendering hints that have been specified for + * this AbstractPainter.

    + * + *

    This method can be overridden by subclasses to modify the drawing + * surface before any painting happens.

    + * + * @param g the graphics surface to configure. This will never be null. + * @see #paint(Graphics2D, Object, int, int) + */ + protected void configureGraphics(Graphics2D g) { + //configure antialiasing + if(isAntialiasing()) { + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + } else { + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + } + + getInterpolation().configureGraphics(g); + } + + + /** + * Subclasses must implement this method and perform custom painting operations + * here. + * @param width + * @param height + * @param g The Graphics2D object in which to paint + * @param object + */ + protected abstract void doPaint(Graphics2D g, T object, int width, int height); + + /** + * @inheritDoc + */ + public final void paint(Graphics2D g, T obj, int width, int height) { + if (g == null) { + throw new NullPointerException("The Graphics2D must be supplied"); + } + + if(!isVisible() || width < 1 || height < 1) { + return; + } + + configureGraphics(g); + + //paint to a temporary image if I'm caching, or if there are filters to apply + if (shouldUseCache() || filters.length > 0) { + validate(obj); + BufferedImage cache = cachedImage == null ? null : cachedImage.get(); + boolean invalidCache = null == cache || + cache.getWidth() != width || + cache.getHeight() != height; + + if (cacheCleared || invalidCache || isDirty()) { + //rebuild the cacheable. I do this both if a cacheable is needed, and if any + //filters exist. I only *save* the resulting image if caching is turned on + if (invalidCache) { + cache = GraphicsUtilities.createCompatibleTranslucentImage(width, height); + } + Graphics2D gfx = cache.createGraphics(); + + try { + gfx.setClip(0, 0, width, height); + + if (!invalidCache) { + // If we are doing a repaint, but we didn't have to + // recreate the image, we need to clear it back + // to a fully transparent background. + Composite composite = gfx.getComposite(); + gfx.setComposite(AlphaComposite.Clear); + gfx.fillRect(0, 0, width, height); + gfx.setComposite(composite); + } + + configureGraphics(gfx); + doPaint(gfx, obj, width, height); + } finally { + gfx.dispose(); + } + + for (BufferedImageOp f : getFilters()) { + cache = f.filter(cache, null); + } + + //only save the temporary image as the cacheable if I'm caching + if (shouldUseCache()) { + cachedImage = new SoftReference(cache); + cacheCleared = false; + } + } + + g.drawImage(cache, 0, 0, null); + } else { + //can't use the cacheable, so just paint + doPaint(g, obj, width, height); + } + + //painting has occured, so restore the dirty bit to false + setDirty(false); + } +} \ No newline at end of file diff --git a/src/org/jdesktop/swingx/painter/Painter.java b/src/org/jdesktop/swingx/painter/Painter.java new file mode 100644 index 00000000000..dd1dffc2ed2 --- /dev/null +++ b/src/org/jdesktop/swingx/painter/Painter.java @@ -0,0 +1,106 @@ +/* + * $Id$ + * + * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package org.jdesktop.swingx.painter; + +import java.awt.Graphics2D; + +/** + *

    A painting delegate. The Painter interface defines exactly one method, + * paint. It is used in situations where the developer can change + * the painting routine of a component without having to resort to subclassing + * the component.

    + * + *

    Painters are simply encapsulations of Java2D code and make + * it fairly trivial to reuse existing Painters or to combine + * them together. Implementations of this interface are also trivial to write, + * such that if you can't find a Painter that does what you need, + * you can write one with minimal effort. Writing a Painter requires + * knowledge of Java2D.

    + * + *

    A Painter may be created with a type parameter. This type will be + * expected in the paint method. For example, you may wish to write a + * Painter that only works with subclasses of {@link java.awt.Component}. + * In that case, when the Painter is declared, you may declare that + * it requires a Component, allowing the paint method to be type safe. Ex: + *

    
    + *     Painter<Component> p = new Painter<Component>() {
    + *         public void paint(Graphics2D g, Component c, int width, int height) {
    + *             g.setColor(c.getBackground());
    + *             //and so forth
    + *         }
    + *     }
    + * 

    + * + *

    This class is not threadsafe.

    + * + * @author rbair + * @see AbstractPainter + * @see CompoundPainter + * @see org.jdesktop.swingx.JXPanel + * @see org.jdesktop.swingx.JXLabel + * @see org.jdesktop.swingx.JXButton + */ +public interface Painter { + /** + *

    Renders to the given {@link java.awt.Graphics2D} object. Implementations + * of this method may modify state on the Graphics2D, and are not + * required to restore that state upon completion. In most cases, it is recommended + * that the caller pass in a scratch graphics object. The Graphics2D + * must never be null.

    + * + *

    State on the graphics object may be honored by the paint method, + * but may not be. For instance, setting the antialiasing rendering hint on the + * graphics may or may not be respected by the Painter implementation.

    + * + *

    The supplied object parameter acts as an optional configuration argument. + * For example, it could be of type Component. A Painter + * that expected it could then read state from that Component and + * use the state for painting. For example, an implementation may read the + * backgroundColor and use that.

    + * + *

    Generally, to enhance reusability, most standard Painters ignore + * this parameter. They can thus be reused in any context. The object + * may be null. Implementations must not throw a NullPointerException if the object + * parameter is null.

    + * + *

    Finally, the width and height arguments specify the + * width and height that the Painter should paint into. More + * specifically, the specified width and height instruct the painter that it should + * paint fully within this width and height. Any specified clip on the + * g param will further constrain the region.

    + * + *

    For example, suppose I have a Painter implementation that draws + * a gradient. The gradient goes from white to black. It "stretches" to fill the + * painted region. Thus, if I use this Painter to paint a 500 x 500 + * region, the far left would be black, the far right would be white, and a smooth + * gradient would be painted between. I could then, without modification, reuse the + * Painter to paint a region that is 20x20 in size. This region would + * also be black on the left, white on the right, and a smooth gradient painted + * between.

    + * + * @param g The Graphics2D to render to. This must not be null. + * @param object an optional configuration parameter. This may be null. + * @param width width of the area to paint. + * @param height height of the area to paint. + */ + public void paint(Graphics2D g, T object, int width, int height); +} \ No newline at end of file