From 71efa27a4136963201e594a0766b3dcbff077fc8 Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 05:10:28 +0000 Subject: [PATCH] * cleanups --- .classpath | 1 + .gitattributes | 59 +- res/lib/jdom-1.0.jar | Bin 153253 -> 0 bytes src/forge/GUI_DeckAnalysis.java | 6 - src/forge/GUI_Filter.java | 3 - src/forge/GUI_Quest_Filter.java | 19 +- src/forge/GuiDisplay3.java | 4 +- src/forge/Gui_DeckEditorNew.java | 6 +- src/javazoom/jl/converter/Converter.java | 411 -- src/javazoom/jl/converter/RiffFile.java | 497 --- src/javazoom/jl/converter/WaveFile.java | 522 --- .../jl/converter/WaveFileObuffer.java | 144 - src/javazoom/jl/converter/jlc.java | 218 -- src/javazoom/jl/decoder/BitReserve.java | 224 -- src/javazoom/jl/decoder/Bitstream.java | 658 ---- src/javazoom/jl/decoder/BitstreamErrors.java | 72 - .../jl/decoder/BitstreamException.java | 72 - src/javazoom/jl/decoder/Control.java | 57 - src/javazoom/jl/decoder/Crc16.java | 70 - src/javazoom/jl/decoder/Decoder.java | 358 -- src/javazoom/jl/decoder/DecoderErrors.java | 45 - src/javazoom/jl/decoder/DecoderException.java | 62 - src/javazoom/jl/decoder/Equalizer.java | 227 -- src/javazoom/jl/decoder/FrameDecoder.java | 39 - src/javazoom/jl/decoder/Header.java | 762 ---- .../jl/decoder/InputStreamSource.java | 80 - src/javazoom/jl/decoder/JavaLayerError.java | 32 - src/javazoom/jl/decoder/JavaLayerErrors.java | 40 - .../jl/decoder/JavaLayerException.java | 80 - src/javazoom/jl/decoder/JavaLayerHook.java | 36 - src/javazoom/jl/decoder/JavaLayerUtils.java | 211 -- src/javazoom/jl/decoder/LayerIDecoder.java | 448 --- src/javazoom/jl/decoder/LayerIIDecoder.java | 1064 ------ src/javazoom/jl/decoder/LayerIIIDecoder.java | 2439 ------------ src/javazoom/jl/decoder/Manager.java | 46 - src/javazoom/jl/decoder/Obuffer.java | 88 - src/javazoom/jl/decoder/OutputChannels.java | 143 - src/javazoom/jl/decoder/SampleBuffer.java | 132 - src/javazoom/jl/decoder/Source.java | 49 - src/javazoom/jl/decoder/SynthesisFilter.java | 1820 --------- src/javazoom/jl/decoder/au2lin.ser | Bin 539 -> 0 bytes src/javazoom/jl/decoder/huffcodetab.java | 606 --- src/javazoom/jl/decoder/l3reorder.ser | Bin 13925 -> 0 bytes src/javazoom/jl/decoder/lin2au.ser | Bin 16411 -> 0 bytes src/javazoom/jl/decoder/readme.txt | 15 - src/javazoom/jl/decoder/sfd.ser | Bin 2075 -> 0 bytes src/javazoom/jl/player/AudioDevice.java | 103 - src/javazoom/jl/player/AudioDeviceBase.java | 177 - .../jl/player/AudioDeviceFactory.java | 88 - src/javazoom/jl/player/FactoryRegistry.java | 130 - .../jl/player/JavaSoundAudioDevice.java | 215 -- .../player/JavaSoundAudioDeviceFactory.java | 85 - src/javazoom/jl/player/NullAudioDevice.java | 37 - src/javazoom/jl/player/Player.java | 251 -- src/javazoom/jl/player/PlayerApplet.java | 248 -- .../jl/player/advanced/AdvancedPlayer.java | 244 -- .../jl/player/advanced/PlaybackEvent.java | 51 - .../jl/player/advanced/PlaybackListener.java | 30 - src/javazoom/jl/player/advanced/jlap.java | 116 - src/javazoom/jl/player/jlp.java | 176 - src/org/jdesktop/beans/AbstractBean.java | 501 +++ src/org/jdesktop/swingx/JXMultiSplitPane.java | 566 +++ src/org/jdesktop/swingx/MultiSplitLayout.java | 3305 +++++++++++------ src/org/jdesktop/swingx/MultiSplitPane.java | 403 -- .../swingx/graphics/GraphicsUtilities.java | 765 ++++ .../swingx/painter/AbstractPainter.java | 427 +++ src/org/jdesktop/swingx/painter/Painter.java | 106 + 67 files changed, 4460 insertions(+), 15429 deletions(-) delete mode 100644 res/lib/jdom-1.0.jar delete mode 100644 src/javazoom/jl/converter/Converter.java delete mode 100644 src/javazoom/jl/converter/RiffFile.java delete mode 100644 src/javazoom/jl/converter/WaveFile.java delete mode 100644 src/javazoom/jl/converter/WaveFileObuffer.java delete mode 100644 src/javazoom/jl/converter/jlc.java delete mode 100644 src/javazoom/jl/decoder/BitReserve.java delete mode 100644 src/javazoom/jl/decoder/Bitstream.java delete mode 100644 src/javazoom/jl/decoder/BitstreamErrors.java delete mode 100644 src/javazoom/jl/decoder/BitstreamException.java delete mode 100644 src/javazoom/jl/decoder/Control.java delete mode 100644 src/javazoom/jl/decoder/Crc16.java delete mode 100644 src/javazoom/jl/decoder/Decoder.java delete mode 100644 src/javazoom/jl/decoder/DecoderErrors.java delete mode 100644 src/javazoom/jl/decoder/DecoderException.java delete mode 100644 src/javazoom/jl/decoder/Equalizer.java delete mode 100644 src/javazoom/jl/decoder/FrameDecoder.java delete mode 100644 src/javazoom/jl/decoder/Header.java delete mode 100644 src/javazoom/jl/decoder/InputStreamSource.java delete mode 100644 src/javazoom/jl/decoder/JavaLayerError.java delete mode 100644 src/javazoom/jl/decoder/JavaLayerErrors.java delete mode 100644 src/javazoom/jl/decoder/JavaLayerException.java delete mode 100644 src/javazoom/jl/decoder/JavaLayerHook.java delete mode 100644 src/javazoom/jl/decoder/JavaLayerUtils.java delete mode 100644 src/javazoom/jl/decoder/LayerIDecoder.java delete mode 100644 src/javazoom/jl/decoder/LayerIIDecoder.java delete mode 100644 src/javazoom/jl/decoder/LayerIIIDecoder.java delete mode 100644 src/javazoom/jl/decoder/Manager.java delete mode 100644 src/javazoom/jl/decoder/Obuffer.java delete mode 100644 src/javazoom/jl/decoder/OutputChannels.java delete mode 100644 src/javazoom/jl/decoder/SampleBuffer.java delete mode 100644 src/javazoom/jl/decoder/Source.java delete mode 100644 src/javazoom/jl/decoder/SynthesisFilter.java delete mode 100644 src/javazoom/jl/decoder/au2lin.ser delete mode 100644 src/javazoom/jl/decoder/huffcodetab.java delete mode 100644 src/javazoom/jl/decoder/l3reorder.ser delete mode 100644 src/javazoom/jl/decoder/lin2au.ser delete mode 100644 src/javazoom/jl/decoder/readme.txt delete mode 100644 src/javazoom/jl/decoder/sfd.ser delete mode 100644 src/javazoom/jl/player/AudioDevice.java delete mode 100644 src/javazoom/jl/player/AudioDeviceBase.java delete mode 100644 src/javazoom/jl/player/AudioDeviceFactory.java delete mode 100644 src/javazoom/jl/player/FactoryRegistry.java delete mode 100644 src/javazoom/jl/player/JavaSoundAudioDevice.java delete mode 100644 src/javazoom/jl/player/JavaSoundAudioDeviceFactory.java delete mode 100644 src/javazoom/jl/player/NullAudioDevice.java delete mode 100644 src/javazoom/jl/player/Player.java delete mode 100644 src/javazoom/jl/player/PlayerApplet.java delete mode 100644 src/javazoom/jl/player/advanced/AdvancedPlayer.java delete mode 100644 src/javazoom/jl/player/advanced/PlaybackEvent.java delete mode 100644 src/javazoom/jl/player/advanced/PlaybackListener.java delete mode 100644 src/javazoom/jl/player/advanced/jlap.java delete mode 100644 src/javazoom/jl/player/jlp.java create mode 100644 src/org/jdesktop/beans/AbstractBean.java create mode 100644 src/org/jdesktop/swingx/JXMultiSplitPane.java delete mode 100644 src/org/jdesktop/swingx/MultiSplitPane.java create mode 100644 src/org/jdesktop/swingx/graphics/GraphicsUtilities.java create mode 100644 src/org/jdesktop/swingx/painter/AbstractPainter.java create mode 100644 src/org/jdesktop/swingx/painter/Painter.java 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 288e64cb5c435f34499a58b234c2106f9d9f0783..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153253 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

_4s+#N=7*_ zZl1~x89TwJ{%*^d6)xD7TN`oSH%w*p$?nwWLnwL{(@lF$EU>6x8#gb>l?xR&mPLK} zoR}WKRo*PrRJNU$lQW?h}Pl`xL7qWg% zbgG2CSE&(7O{rTt)3yb?Vt&33{j&F&R1NES1BbXku6U~Ac~t3|yl3*x97=TQ=%)X1 z6k{qg&*G&{^4CZd392lEL7b0a<0wpd2e{90r1fDa#)5m}-4D4s##z&X?b9)d#{z@c z>aek`+Qd4a{vatn{(y=>XU)q$9GzSwn|C*RvekjU)uIXysqa6%LoPfoxhDboPfkCl=AT+e`&_06AdGtIm-<|KG8Jwurh|PhLI!k~!1%-ZHI_-P|Aj+3++cY+P?4a(Xa1X%1m$6=sgRZgw{OX%5SIkgXo;U9 z`0io(3`kV0u2-)<&DA^U5u>6Mq5{HuC{VHH{Va7a(E{~K_$^u8Gns%rY_4u52r!U~ zNc!=mO`f^qKk~I*sw5D=)I@;OkjSuXpOBP-2z^&tcE_Nla;z<0GNa#HN=4kb40aZW zM0_v(yQf=T4Gr!lwV6%tDI(B%6{c|h+L;U=x$&DCU386B)@HhD5veK9H@Q_o${M@? zp;f~a8&A+O+n8S3lgVa2yP9qA%w}*+Tb^M60XjlBn2MBrTOH5@7`QX~vKXPN1m&?3 zn0J%&#$9W?vu(WrcvSCPCAHDzahv7Vn zk$wKNzfB_%!1Va3&RKh`*KI$4)uAkPcN1h*Bz__(r98wS3G5`6DBJwBq~2w28JVql zhwRoN!{WL#6l6cI;8Ju%HMYt|{<@PApI*OEN>8{&g4kIy$X4jzF@Q z^ZVz_CS$`}EP-1%{3rsT_wZ~v)^5_D=|Ly3?bhY)`6ap2>w15T9I{^ko7_9LgGdss z$v0s1VL6n5bXOlv{wVu7Qp#{pGb`vB&k^9JOu0XJL$e9>PNSdRcNo_*cw(Gg6vxwJ z*bU=&=7wXBv#GT+@sajX*D8ta9CrCFV|4Si4guIFmpv$1#CPjZ{YyZ{Fo!q`e;X@c zQc1xF{$|^QG5`aXn|iwRk3_mkX2`@hfA5qOW1>LQ~zitebGU2hLr#%HNgscg9^E}*lczoJD}72IwRIVsFhYgX4_785A_J6jw{ z00{k(nn?R|S)Ly=kk%CPrd0PQQj-Q3Xu=;Lqo@aH$4I_HJ}-Fvu@AfabF1Jp3|TXn z%G$dg>QjH>JpuAa^Y&|KUG%$x*i)292auw=lMy#Y%bPAT>+G|ix!{UijONiu} zCjSllHz@f$6~9j}hDJ*dr-|&V7V+IeTxI}wmeq=6Y^5B4*o9g~p}0rorBbC+W%6Z< zwh{Vd-pWGJ+MrPj21C&|P|HdJ3FlsTIkY=Znx&VvP20-F7Ek5)@voP#?x-)%c1VJ2 z&uHrBKY5&Jafn})F~5DA<^4}%iLWpGf9HClcFva09!jQW|GLtPQq^_BHbwP8kFOzW zkYv#-6l*DXk<+RtrFncV(?7f?02&#nNDYC_1TZ*7H2C%&ZkzO?{~1 zzK1BufAskT8+6ihO#*FV>GXK;p5&VJn1E>KeZAZ^Zea>sWzJ(ZVxAaHNp_GNK*Pd9 zsKc-DxXOZ9*I1v>H#HjXQ`nzQui*&bxDaV{)#JMg{qzr4$$=PS0L^Rf9 zX(r;;;-?AVB1nq8GQ@HqsABFIuL%buaD?TEyCa%ZFjz8Jr5ls*1EnH0B<0OqSAF=? zQiZwiK2c#Q_8brD=FZJPgnIG71sK$$ypqaSQL;wGcZIE97`a~0v?A-WNlEi?)1^~9 zDp98VvYL)6`XKgAe zBwy5)FU6TuitVDzG}e*FakTNPT#D1D;RjUUmwLn^_8;3uSK;LasoO zDm0qoD%Rn0P(cpHY@<=qSBa|iF4#HB>7&i)3BQ=vD=r2ze3e+~gbT3hJacMO%M6w9 z)@>zI8lq_0s*=z$n+j-sbyOZ@w6X%T%X#+*n%+Gci~g|E3vSe(UY3_iW$yC2wD-Jx zT?~q2SF8@=-$tuZL}=RHha_xGf=>maxZ}axEfgIep%kDIlkMGwA(ttoVIS2!9}T?Q^aLe<%OWOq&+cq z5hc_oqIP~s8J0ib7t6_IVdhJ=NFIU((s@Q@ssN$Q%;nR!{HJK2VFZLqE`v#4gYk}J za&MrP(}tp3-wa-jb4c)oNb-ep@1^7;#EiFCn*hH!$6}$j{T!al9Gvs9Qpih~4MFJKP zzDAh7hCh6bkw0TE^)ra{J%L1?z+Yjo$^ViDuGeJ;|M9goyY?S<{7L`akC^?F&YwZh z$jRC9>+JVm?Ee4qDc;Jqzh)FredwK?RUR&4ZMk_uifW>6cJd6(91K&L;^T&d>b#jS zN-7E(Bt5s?j*H3YuOXiDBa6Y%)%9lXGB%vD4qGSrj^A$|7k`O3fO;cIVp(EgVQFGP zFvFYTQiT%c5(3D;kdx4cG~^6W%6*oufXV<{I%Su&=nY#QzV~)ZDBwIpfO9Y6JTn|X zwsK`3q)L13;;7MV(IPBi3{F@vy+4Dbl_gz7`;VFHVXYB?%qnUztU5vCdt};&Rw>F5 zWx2Vmd`kxzU@5~l9O$1$9>m1RH(NVuMdWsdG0{rs#gy$^ei-rlI#Y`>QM&);+LLX( zhDkKUwUYH@lRuk90ZcEWR zRJdG(Hrz!TzmteMh1t~-#Ua6!AOoN9U@< zwrK3NLcV_X4!WxINaT&s1AK%4$Pj$Lh5|2;zP}IA4_8mg%su!X={eC(IjGJN;h5Xg z9%5fyA{U*KG^8Xh;Ik0{O~%MQs`2M7oSIk~S=|N8?qjHKLaDpP&8% zxrCbDWRIewWtgkUkAF(8uz^p3L4B!4sD8oge_zP{;xG9BLe&2YEjyEcN0p0;tul)G z*F7Hc5*cl1m|##DOx}Sk^3Mu#D}O@U6$`T zd{12f8rUiHhWeEts-lbtQxJ?IWlG|T3M%zR+|CXnz`+s|n_gNrxyv$@xsoWNTuCQ^ zxG*=g0MOo2was5;q0!%tEj2?ceNHmQZ1GYn0I+9PHRDW{QFVRdpG;k|+Gp1ptkDu> z&@c`q9lc4A_|gMja1#O274e%6k-tj6POG(#7uknX7<|Z6JoTIOyK1#&+In&-Z2QcNZRBqN3YjpdY%dEF7gH&XudIK6P}6X;Uq)1{fBYXyYYo z+eM}8)=jFwO7osvECkmNpOSkRy<2Q1m2W(U3(^$nCvv{Gm3DW zRm~!rpoBkYR+s(k=Jpgyxa#CHv`rxHI&-WS4oB$8Y4RvOpX9hrGhb#EjYy}FD{rTv zee9_REIC;wz#3Cfm|*(8e$VMl&69L6O>U2B%Bec6tg<}uv0ks!%}g(PS3#_;(cLs` znd9*7+~w}ru7a>($Y>+XyMDN5gyj?~m*pk4TO~v;vwmfbE2cpQJGzh~4oNpip`a0Q zmDr$=XYkzo9&Q>(o=QNcjHZ?i4xSk>IX*f`W zkSk0uK0S2HxNVIsau-F$5Qh6Xi8Ali?+LN_n|uOjO0gs~(adoj1gOuI#E*IB10Glr zJ(G{VtM6(oz6MW*FXnyqcfO(Z5S-F#0TrN{lMY;=WE~p3q0gy7$Uf8gJi?doe=RS# z`ILU-TM$R1+m_18NBD;@#!Oc|Sg2orix6Rs{&5i}KT~u_mE%2G@BfrCxQAHlx?+s- zy5n*x$Y44dxcGMWEo=CZ&TpmQES8kepSgQW2ND7^!J_LLSL(@AgqXr1+r4Gi$2O)3 zf6DA;9hTcmI)6C4P#tpxTbsYvg4Xe%lUo z!g3Rz=g-}j-RF{B?VroZdpYOMYl0$?3~XKwH~r%n1o|djus8c1=}i)>l+&>yA*A6_ zs0ozx(={R?WWVL|f>Z8-rasHHTp1_91dNZ7($DJBMZTloW7o(e$qf@5>ZyBKw;`brOQ&nvh{P-REE}) z8df!cz>fmEsJ*su{7pPD6t&J2C>b8p7p050AmaF&nSU%amwY46Mi8%jZ`O*cw7@Cj ze!6X`hpIA>ZtTQ>DSuB%ifWWk_OU6>$dY{w1!nTdA=p;2x6m=1aSH8+bN3?{8=;&Cf zfj#Q%Z6vmcjajXC`A?>7@kBLBwK3AkEb#PA=r3{)^vP0iRE=P0Ej1pV(g{W@v@Ma+ z6va`~IeLHgBx)?U-2mD?|AOCQ_1r12jX$ zOu+Z8d-$D3ikm6&6)_~EJJ@cil4y1%jH+a`^qvi?T5E&LrX~2LbM#dx&*XmBo{OfX z#u{OC?SOU5+V!Wcg&zKIu*rxE#fJC0>D%q}cT{}%ZGy4{$AfMLwuC;Dnf`a0E!nyF z8utT+++sY>Y*2Y>2^JdiKf+E$#yO6{LQ<>zj%AaI*ofN?YwOP^@&&R)V+@b^TUFgWkYD|0#d&nHQlG?lSwkXxl2M%qcIg^7OQMiR@MUi>r_}OKn z&O}#w^=4E}1LaGaW(A>zE0JpXU?Sy(1^7%)LdK(8TIR}rR>IS3wrwHnE`4@qXttHz z{*^kYShd-fEm*4wWex;-*oBb}sydzoU!|0c0$yZQ>T+Y~lw$Mwo8cZR|MKIU>H3@E zbQpr+H}u>`q%i&U;qDISQM<(>7q~eV{vX85tcas5)inQwAn{GFv?Bf*-3y@ zMImuRQ2)ER^$yHiq`uP%-Uw|W1;0b;|ICTa#$QSS*&=NN6pt?H0vm60O^4QuhQvhA zipQ4r4@7T8#ZaQQIswmH_tew%<9jCBS615rrmH1U!%0V`NS(BK1Sr#&wIbaX#t%mu zi%9o_s`>aBxDYb%RC_!ch2NU5u3$)AVScR~qEkyM$W}1X$Z20*sGqLe4tYgrwnk|_ z2uiTG3}g@S}}#(jNANEDc5io{#rN!AU&D_6?9#Vu4zoYKGC z;k?|9a(kc5zw>;6{38II#(AsNd|e6q!2bUY0ROco`R@V1TXpjv)C(U?lI_mRAB2Tu zvKBZ6R%s2SbVD&sYB>s(N$A>?Kctq)o6lY2;mC1JRB%Jgam7QD)%0=AD_C4{Q{uLs zwzeWBp2WF)+}tFEB;1#rF8Mq!p1W={J>5RvFJlC@fslRp849%pJMrP8)Jdv3ir2Z} zF)C{cwRyQ{hEZ`4Y){k0xnS?u4-)xCKhr{W@Z%5AEa69E1-Wo+f&uD<9lml7;ABOe;b8X3I9hQ}|>%wmI-C0XAhjn2dBs9>?k%=kx@pLptF>UE% z8OfFlZK@5e+L+5wSd0odH3|*cF-Or|62-ZnT2Y(3RJ((xPp2Xa)n+9d2i$SUM?V{; z(~~4;na`=ftc&wQLWlz+W~Hso#3IEf%th2R9wJj~ML$ACu)FZEO#E7G(Z@2_@Ui%q ze=Gf-z+&GWj2|`*+bb2h5h3;PdOHfct}XDQnjRoQb~kkn#wV6zV5l6+Qr^m*C=3p0 zI?hn7fg9ChXBMpjVIZcNn%I;K(`I*ofkwp-i{_d|zU@CN8`5W1V_C!Sk<>=R_0p7w z(z^5lJISp2t3z*Uk`&cJWyp8-Q&caelQ--Bm0iK1nv0A)izWqWMX4%99;zz!x4u>d zR)1tCWn{x>qjOM7 zCm)Zvx{GB-XdFBJG#P2ZMV5Ipj1fGAsZ|9_u-pM|not$c%n8ikUayI)VYEtT)r$$O zaZRCx8fBaS)n~fmc(rmR07G-zux{gvaskHt;ePe}$Cy>m1P+zF7nnDLZFCR~b8}Ml ziI}t=>Jn^SJ%>#E+N)$C9Vh6sC73`YQAVHU)r`}8U#+Ci6=yd^w+F8F@veBn1FAYy zH1y!X63UtPo=s|=twV-%O40oKw*p3>q8g`s%tXpQ{`C4gm4Z zmxc#=Nm)E@t_rqie1eQOgKQ>6?!V^XpzoC%K;cdH2Fx3NtTV48wu7x5cHh!C?^rwU z;>hf1D|suBMN)pv5{IyqE)E17CXj^U1jMQ#XHm@h_E*uJT3j#xUZ$U&!Tf4@D@b4a zUGREf;@&LQZtJ|w(|7It$CU)%pB`DSKRw!&AhFSN%aTKMdX6rmz@&^~nP0pPnVV`E zJ%HZdPCN(sK{3a+WUl{m^Ip~cP8ohnd1cbw@AAgStLI{~AC$kCQ(p~=MHSs_1Vv07 z`EnqnA$}W9Y?NE*8u<=W_ENdQ9e4@J>lX0aUDr?FBLLs=A(Tx(gu$m&i9|&V z&JgJrlFLl1D{_6Rd>Y4Wf9C}osZ2#vOSz|d80*@xkDN8bU`zuK?}Gr#GlFW)HnRmL zhrUR|CKe@&)ZSDW70{(ZOXd5F7|6LF=SYalJ*EhL#l$DHZ)jw(xQlhZ&nfqJ=$#h8$6j+jSzL|+~lKP;YG|ToN46rwc_LS z)in7XK#+J+2{RS1k6A_~QC?g-fTNyAv}C+-_)j`2Y%bc744s^1$(j}b@R+IZ!qgDQ zigWDz-FryTU|o=uCq4XqRJo%vwYutTSTx-8pp8M;wqL4t<7iZS~6XGeEcVQ6Pn9`r~+YO|wyJ#@>Au_f6KVHU)CW#yQ}k<9(?g#z*a@G|5~ z%?+JR|NWJCtE|eQD5B~XyN#&i2n9PHe^d4RUW6)Qfz*SHjQj%-KY-I?iM3LC4%?*6 z|F`=J!fQtmCAcJPT3ukIWzu;@4VwQhqw{guyt4Blb$!#f>)j8p-u#o;77vCLmYavswg=wr3$%mWR0D9Le6_F7^@h39TcbHHZ z4H1RE!WUJBi9PsXb}X=Bc|4}iGD*~RYKe7Xvh(4V0K(vVEk$aAQ`KXUN=zx)73Ss! z50=5LP@7v@${7b=27NVXG47WDL-LuZRoVLj2S+2LXfeB;UD7I5Rplr)!2A7>vkL5` zd0k>bL7#3RC5{w}Q*_{DMwlVD`ovsYnKhMzkDWgRI~5HXIZBu)Ra_#nw2=|nA00Wm zu?Rz<$-O%9)pSy-d;%KSuE?r+I87Eu$3j7$&FC_!_9!d8QoNyOXwkRzv`@Gu?BmU8 z7)LUSMHQdfHhwRsUleW8++<3|h}-M1C4 znj5y*VR4so?3`2C@Kr?@-g==hwpTaJS5V@NH$$EY$vqq;-7X7=@>(w$1~VQdhSjOg zGCcELIrfN*mvY7z{-qWGD(es92PYVW1P0`rHNMN2&$7W-R!%9nr}xlCZJxe}(#@kl z|NOB@!Scyp*=zyn&xc)5e3Z*4rk9f%C7$wKCL&)+_*q3W1q_A-HNw|#)&c($Y|`_| zID0$dGbp492J-OX7G2SA0M%Xelql-LnmCC`j?uPPA%ZaoO+-crTQ9n7zf3OyL$A7mJ7Zq)J9CgHxXxokm zO=KhEka%+1prS6YbnUdI)^Fquc9|N~bJUf2uC~$VqNDV>)x(7d?|8!q7OGSTVTpe6 z5|*zs63>dNhiCMFpEY}2PCT1lEDx!VpPfDtg!K8u#zJCZ1EyGuCa5N~(k*0$g1vb` zXi)l6Pt*aBV#G&-6i5=7Xe+IdCSKHi&pwnbjDFuEp=8mz9O9U(2qPwgT1Z8t1d$}c z7Oz_a(pyRlpl+e1dTC+Kab%cbOCSgU24B51Ot~WJ^p)r&7S{Sd+AcQhHfZYxQACNf z5hPi>iAt5fZUD+M?|)-u@wJ*R8;CHbKu$?s;%X_ z$Lp^_n~=b6pSG3qa9~}~lQI;|4gZoZPaKA^ntxC#7U@5W=9XmY%6D@fr7f9NcIvII z;7a65n4H|dVQGCsWAm+KbZTVeshp|kEnGQ~-#1MY9A4Ri4I~>q<4ilAW6hU-I1abF zXtB%Q-qXiz-PWgDE;=bjm0*1=w8*wtc zK)J8JENHUsO z#u1LlOI*}iV#_lF$gOfSt|)T0MsDU?)wW$8Llw?WDo?^Z>lm>@yQ7=`qzjru; z$&D-&ui5F)@Z1b=^K{Rrt9IDULQP=7)(Eq6WFv-)y@8GXOR=LS7}KsRrYP^vInGP6 z%dXpK4C^80M)l7M)`@tCpr8r|XaErR07L(#UlKh6h|qZborgQ*9qoK8W%B7^QOD{} zQCcV*2b(#*-WG-k#d*29upWIV1)?BAjFT9T-rl6H4qvU$Gcv7JKjAuQ<+UEji(Ov) zsUU(GffJt!7;q!^dmClnquj_v{&Q6VS6Oz6fXIlTUafbKr7XB~8{_kXUE-J_W z2!$W?m3WjuBmX)o_y{d66D{^!LZNRc@k+#OY+FJA=ETxjtPD9QhArVCmMdYDIKr?u zU?0bo>6{Y-2&Ht|TK(D=A4z64*X`|N^X1hxQW4Fxa+m{@FfxEFQo@~fJ1l6J@XZ32 z_%8xMS{WgcPL#F-i%FzV9220O zIX-m6Jsch|An~g#$JV;6RMW%7p)%)i%>i7$fP-cN4Nx>RA5QZed5Wp#lhLiz>9x!z zu zv)MEwjP}x`$ZSJXO8OGwVWj3%>O+W6ptPHRVjv_LNd_SvANJiRbs^k&IK7%&ZC47x zC1co3?a&sc%C4n|MOb&F=FYjbrHF^2fi2-gXfX_N^2URps((a9^9xBT>)vfyefAF(~NDV1mep-WcdE z&~KVrFou>eLrvTKMk==odnqNCVi=hSl*)PQw{ho@_&LSUO2H= z#dRBg5!{$xcc^~@Khh!0VKt#8jy$v&M2^$U@rKa+9!hlw(!1N2a>dCe7m&0-a^=4R zT?d?IfXvKU?G~3?C$eKH7)me>DXIP|4$AdsYS|VJc#*B&)#;?9dsq6cu3%7FWg89q zDlN1lcX@MWk48igWv{n*oYxV~q7SsR??{{gK4zv&yp-<+t+Bm?U&!G3TaWPsBbuoQ z$-{AnLrNcnvsH&bHzugYPnwPQ*@|`R1qn9u@uSr}HXJl23w|aI5Mc0(;PnR|oCy@~ zbHfbKI5c8pNdF&6=j{2&684vo+5E>a`rndHNgJE5eA7nI#N_{=$SzENb;6lP8|>!r zvB)3dbjkRcMeE~t#u>NM5t>=R)C5Iux3d&3Nr|{H)7UWadr^XB7gU1sP8TvJi6G?| z0ncJ|a?B5C{Zz{$3q$Ao{SNGH?3Ds=x!!2HJVPyo88f-zdBJt)GqLRCrmo)QeX2WW z0FgCsF99@!6PU9X5zYqiu-;i?PBE5j%fS`1u9a_7VB5e&1F+x_EQhRyEbZC$*v0@? zvxr%c+rx-H=)IG|Poj|Bu-ocHZ`?tfL07AYS3+wf?K zV1RrLe?X1QuE(E|J)a^Hoy_@;IwsK2rl$u|ZkL|yBH936Abg7#Kv!_kjC(VWV{jM}(a zIKEV-Qa5s!G||9u8)K~lv&aG!ZI$p8XPaamh7=cwRH~5*VKO&8$u+$NOCmN)Nz>wh z%W9KDZk9GO^Fmd-kTi6%^n5&^@<0VrJuD9%j#GV6=Ec5IgRzc*cZ0?GQ(vM?TPNNl zw6mzRw-j(KE;}P}c>~Q5eH`nf>8K__cCbik!ntBIRn4GNy&2a&KFo=w4ti9uTjqOG z=RPe=8h>&UiU)^9_B&eVE5r-3_xCIaYEQKaVbjgagv*@sw2M|nE)U&}L3DXBzsKqD z4H8WXDkm;%gk>&{bosU-V+fHIbtWaD39!O$j^Exm;rRY9fkn1$AzWOf26$mju1B`{ z@5Tv5WS)0Kqw$u&6X`~hVz18~I2M|tYw zM-;G#E@r=&!i3#WMuXLk+HD~nkXc|Dg`=sAMW?}@%me+yTK%Eru&d4^nF?d_lzD%r zQoCtd2?5$hTPa!6zI9XS5$Z_2eYA{r^i`CQ_h7GH(xbSPSwCSba7J2=PoKn!-M&M> z;kQX_jI^w*IABgn15WiDo23ehajk;XY!0hrH({{Hbf9M^$0PGXeLRAcB?a02X`;`u zEDMM2GM7L1W$T0;qnTO3xZrtE9EnY*7v(PvR>;D_@)N?Ew0tBn)AJ`PAP4w9Sd%D-H}b|eCZHWKq;CR1&U~cfLpjOH2NOUj_FxF z6~=`tp$eF{rSk2@%3E6-UT>^Q+0z4u(+7{UtwKvSQH;++B>g637}k+Vs&2y7WQzgy zH`v#-O^eN|^fRZ19hR7%kH#2~D_4vK;!_8;6*n3_xI;5X^=C@7<E(`y>^k`4ywa6{BDa`^1j|lWiF= zCX&fDxcUaqAeGi0Q5YI&Z|^*45o&#CMN5i+@`TRsk@41%I#7<8q>G$f7lJ%;xqX!$o zB*jL9$Fsi{;OpAX7g)xdNm#`@hZmSjTE#i16|hUrl4e!}u<8nNqf4}HP(rOA zEzg~^y2qfcXH~^XuYWe1-dd2H(!X-aR;2$_G5)tf?0<#2e+WbTAF(bfVN(u85Otv2 z5=K`FsZ;?>bl^wf=TVbEq>Aud9#m1DQiY=^z;(rL{UZK6>FHZn$mA9rY1-2_{>1CC zrcx%_pa?#vgE5ZH=ktrPO925NqEMG3Y%|uiX~yd9D!@GBjG;;IkQm~C3g~W2Zk;8X zomj1(HuacjT%Qf9M;|6S^4gKZsB0^gcJH3->UKc)hQ}*_WvpoCPc$c58&yS;o(mq( ziq8N+Hd4o1Hteh`ih|F*hkzOVwwbG`ZIFX!?uk$Zh`dACS{g3XNRh5h}|?T7Co9G7q?MmstSiNOx5X z<0B$LO|P81)dpC1%?T$kkNyxn{b3#nW9D0wZJ?7(-@pW8Y9Yk{<(>+1jy>SWw=+H^ zhcc`sjH-b#klh1&Z>YHUGyrvh zL3q?Se#cX2m7;+<7Y}g-!b*{(AqMn1>>GR>nJoS#Z{JwXKBOYSm&TLG`m5K8dWCyu z(#MZ~S)fE|i%;uYG_Ip=pL~e-)W6N9VUop!L_ZEzSMAUg9<1I}vqs{KEfg;c@%DVY^b@`na^6>AktKEP{@8noubaG#nq&SRKh|SYp}ON!zx}&RM4D^6#a7TOhNZkYggQwa~7Zn_px=qzHh_cIv{3Rq(} zs8eSgeBqN{H-E2MXHQ&%_Tgl);(NsXvh;qljOoLO4o6SvE(huSwlr*(fneHcgi98@ zKIPu4L{LmTiX16rz@Y{SdyqUKawc46CwWT% zr3;X@*;5)rECoj`f2l8u(ow_EJ#jB> z9By{I4Hr5SK_;TRlHjbA;34g8irI6fiOqNj2XL;Dkd>bb(A|eEPqn#KkqIt?F)nGs zjrci<8IWodk{jE))(-2-h6P(7Ds1gzpSS!_`bwf1M|7vd!fKw};}y3&b~C3~$u{Mz zxevF_qou7OeBAM|mSFsdDwb zq2#UMnEq-cGCteIb&}MsLUgQEJa0RPg>Gf0&rCail!R-@iI*#H(fxq{13M}^9{ZXw zUE8p-qe0;{c4=iSTTgKpUBimODo&nO#HOOlP}U6&C#H4KcQVY8#)D{^Epg$FnMHbN z#G53RP2`cwN%7kfj)KHeM}evD-IoYB;HwiGOBQ@i#^TUMb0|`eg*uqwK;+NZso}Q` zZ@0@|dD;Lo#e$$9clmV{+1`LKg*~!AS^G2(T+7G2F4Nt43W6KiVL`3i@=Lb$tRSpv zVSmq1$%;;eFVw?ByA4TW5vP~VxtZV! zA$elE{r9%V9NO2bATIS)!ZUhpmW=nHz5AaFnzamw?%ZEsT>L7K|Mwm<<-dc`($3z+ znL)_K(#FKpQPk1#m!pKCor#U90DCx?7r460R78q7>45EJ#)Xs&UW0%#4v?3K( zv1PFdX)V3VXI)EX$0p*Jmsh&?6QB@YE@GJ1mW_x&gF{-~4mO-7vRZk%KQrEfnB2iH zK-U}%mi=GhdF{6h(UrFL2w_k_2cXO0e#k@LE4UpK#8@jo$lRKloyke|dm3@JcKcRj0j1 zn`Bcs0$V4Q^%(G*?8LTxqulY>^x0#Y-A&VPT#o`at-t8-0E+fQnt)Cf+visK&tG@4 zGy5OPe-uOkRI>)m15U2afuVn$bt$`WAn2+PG^LF^tL#imOvUtV# za#&3GQ)662gSn&OI(tzZ)vK^bxNm?O&Cd{qs)#Rp0_3i3g~Ax9 z)9-T#lP-!_&B)XOjbM++R-$kCJ$PfF7d@nTv>rI}RHK@oE@97PhV-!Q<}&TtLG4S~ zJ)Mnl1C7ogjavg&G$f6cp#DA#`X^ffm{?(PG=1pEW*4ach|GR+Sk;?fBfRMU2%7)4 z)%!2de5pkJ7jFKAl|Sk*UdsDupV^+P1+u^NEtP-&8PD_cHjJ?F{~J4lPA62_fT|BN z!v{efcHdTNPcjEtBI=k&97jjm(lQJ2Gz`o4&xKWe~ zcjWWD|2pBevB`DFv+0)o=5;8nz!W{hj5zWafknb)$A#j7=Nf?Wi~BkW1tPpB|clKVOf<+42%poM{3GA@E{W+Ei4i>_0WoGS=Or60(oo8n?-9buFPIGLu< z0dX;Arb+9Z>SII9uqH-@;15iRFz7Ugl8JCC1FT($P;PZ?DrKM0hwQsxF^24OYjpO6 z!0FMCPKlco<`|GwBShzon2r;2*TE>>@~VY%{6guFN|Z^HMi3JXQyG1QfpCnhYhiHM z?8cRVc85xU{Pn(^*4c5onK{+MO+z}ZHPzQZUfUV9I2lDHb zZ3}y;1I1gUfP*bMK#Hd>fP8<{WM35U$2-R6^c7dq=u|nn&!NbNZ|Ga6*@Qad4<*j(s7v;Bv{)I!@%kO;Ump^r^B(k=O_thumrJ{0%?k; z@}QNyQ)p*aQSKj3Uh9(aP|V6^5XO0lc$Q3q>_S?W`R@DMRDZO|eM+zgFuoFRX+kKT zW^c{EzhtP|V;S3=Io)O!PEM?~tu?*QFlt2G&i;CRH}>w^Y|GQ;rQ_o_7G8qHra1sh z@?t6nx{t}R^mL&*OvEd;kKsqVjnLAn9PG4LqQnYzE~X!VH`YrY}n2*5#=! z>SqJ}UPOP&#pzLvJftBg1F}OY!jo`Ui99!kdgNpZMi^tn2@9;E5vEyMaC+?U=z)cS zWKHsx38#(GELgav3eB#LC6vZmV~cUmADLkTi&j;i<8x$Bbk@TKi=Xx%@Yy}VDckxZ zocuch;X!>I#hYzypeJEsvXtXHt}ZF*TNWdgYe?5D@*%1g6=guV=qu5-6NoF#1>!Ih zitu0%kXRCf1sonMOiErsy_sE@>!eKSiuhePH}FW2{=o{DOdCNZ^6SI3EQC*wUJGK(#(L9A=h&aTX6QUwncE+MXJy2yX*ZTZMY{2TKei zCwWiGqhEVDhgVWcnM?Jt+G>4~Ka*ow+)YOnWBH%~JU=>}JT5f_SFc~xENKM~DE8pI zYjA_>w7`Ecv1&+J8rGAT2BCBnhg3>XDM?enHv#@4>&p*GaBo(4T5xQ~!k>~2+l0xY z7g=F?-2s|mx*DRFX>I0*D+BZ+22UV_C5DTALi5O3$b(DecrkRFy>EEeOZD(@N9|}@ zGtlXhRHAgeYWH>`;28L~6MsxZ)*A7g zV$}+&1roS0)4@4L&u3AptNs3^PKgVo{3w$Gc>=ivT?=h|Tj&l`4}adR#zZ+_K+ejP z*=4}RU%avcm%b|gelz0sSNG!^F2>o<9@ogW$;2n57_PDJv?k{;PqS7;cKd(Kh7q@m z{Yoz#wKu&E)Z8Cnr`7dp@v;O9?PiyADxI;QvC#WPlWHnch-N+bgXOjwjZ_E2I7s5AewT6 zn{szl056Jsa|_rDPAIEwT*GP(y=qLZyN5-UHmga*oAF6>honuaW5=snNQd&yZ%Rt7 z%aL?T9QL7OjmSHnF0k2l)t3jK;xg6S_q<7b!JBQzR#C$8F~+pH1Ir)m)>GjOJ8`PHyyUBWJiu%}j!(Wm6X3Am#&~c;)c9aCO%CaMUg=7y`*^dhubu z1GUrs>9buUfxdQ#n(KPyAw_Fu{viVADf-83YWGjKQ?MNcBF}>h@nLSW*}GmJ88d+! z83qrmK}fW6r{RRt;br$d>e;}?!AAo=qa+9$lFyQ@{nZ{PgcoJTEqNjjKD#=;;hifF zK4dmoMpM1|ru!eA3Xgq?8Q{O-&J7fCQ4(-pv<837GMj-oLMX@Qv z!?U#!b>_G}?yp|><7PPFa(LB!@18%chg!}U%?xrN)oiK%SSceTfuDQ1=n!E>^ArlI zjTj4$alp`e!hH3(=v_Y=;5+K?)ChiUQMc=7dt%Few_T%Z+BLVifr9xZjn`)3<0%@4zp zSTFC`Jr(;3nr)Y@?OXM%(OJH0hagdhB=}_Vj;+>s-Qq4^8`kA4xtB!xHInTh(Sr7eulKD6i$=^eV!57-&4pal|1M8x_GHX9E-#{fEdlGWuzlQlxmYwYh569B1Eau zvg~eRvB$>fDF)Ujv?|qWiIzvi0L|sq8&S1DF4TzO&X2sXvWZ)Xw2CZA1=-()8rOneiE-0DBcDWuI{ZTWG$9gIf82Cpk zCu(nhoP^0uTx|XEd(UUqu~vGyBPnUTWo*F_F`<>8Nx^PqNPXpLWOERGeMGA3&<9xOG4dPW8gAAYNAO*KYtX(N=6Q~HfFkeb zc^~bYwoS=;Nk0;R_XJv|Hyevusk&c-H{c$#r_}=>pX_3+o+=MUs5^1Ab$`YfS00~5 ze;igkO2i+Ybj5lrWoGxK&co-YL%y)JHxR!;8Qs@^!APKH^hB?GaPaxhf{{KX53i z{~yZUF*uVb!1tcuiEVS@Ol;e>ZQGid6HIK|ww~BdCbn(oX1DJ9R_(35TXn0tPk-z$ zeNOfHoj>3shkitc2BV1NRh=Z*^v~6HY;0WTsaj_}=4G8U#`>PEOqFI?ok`ca7I!~g zoycr)@w%g01VFjEJ#KnWy<{~Uoo#mcf8MBz z116wn09c?hAcU}#P^p-;Lk+)=NqL=AFcF!}~kpu`oeob_YQb7-VGZOw_zxd}PgF(R~NC z;235Sy!(h}a7@wlp&x{yBI`T*C3sKRQ_PK0#ips{2egvyI}*w1Y)R72_qkrXOjNr>g7lD>I$;#;MG%Gk6s)y*DHOHKs>FPEev4&4Lc5`(syyEA=rjPlZ z94RT%Y&M*d5F2E~e{BC?Db4*c{DsUQAOIX|W60QE7B@03PjHM`0N18yErY>CnQyRK zJ+a;xS;c8R{mi!Nr3!uA7P}V%!-V-)dA6Bt<>2(}f$o=th*EFsy#E|+N=rHKxd;#s z%sA{URCj3XR`&G`Yh`m!CbR%S|@K4Im_dfq&r zzU$`n_u@_o_Vo`?_;F?A{n2v^n#T zPB{&Fg4S`tY=nuGN5Fe54tA2E_ri>=_-qz5nLg30!vf_#vt2CBOJ_X!SfiVGtb*tR z3N-0Ggp@A6bGIM#ft4p_eevu+qggVR8==#x@27HDVAQnm=UO?%)+*!}WmTsc7E0hZ z6j?U9^XVAFEv1VBs}duSwMLTp`nJatDheDk%k%GjYTu9J*fQN=oZD6EUg7x&RzB?F~Q05WkmFFpA>G$M58jlR)Z;}17| zAhjz9tKmaI$g8)kGlNU__YUTKt?*i9t!gc>IsLM@Sx+4^bYpUe6g{GxVWDxAGzAic z6n!hD*@_^vtHugHwBSs{5s0n*F{!$(#kQM3)6)v0k=5n|`mQb*n&npJZKEt%5f2#L z?L)C|d><~PMiPaLPR={Ob@I%@jzRPNQ>P^G<%c_?=pCC+xODLD zm_JZj!XR}pXU|{-_nHmU@#ppf1~I^b1I<4?YiAYHBGu*|!YbwFaQx5X(CQI~j52;s zB*(RN=g+HcBc@JRkn@sQQ1g?2nr@{zmomL5UF;Fg8FW(a$8s(yGf&4|@?1|6XU=#7 zm=?g4<9_wy!DW*j+_{e>__=MrwUifUB3nJU|itOSb zJ^V0+{6ik{oj80jOwS*nVRGo|a<3DjAYn%}GDMv!bBOdZW=Of4dr!g~l@ zA?|O*{`3|o4O@VYrA!|_9*|GW7)CoIoqNSTx&a6CkkY+{-5|_Sik3g#eeTL&E<=mY zKyR(kKFBmRj1Mg#!Gyc&fMx%PeYCj{Vr`syHDQH4Cw1lBTFF3n07E0XVAw)IPGs>uD=x-4xKiSPV zGFi5ArP1m#u?IHc^PJmVt4SXkdTSV0h%)1)^10Q>GHKC<-Q!3@W!@x?@9va%TIO|I z_m!Z?9K=mU_{HwwS~q^iY_z>;n4;zK;{Cz4-M_=~2kAvTmFkJE+N?1wVOi@)dn`pZ zr5H)KMr^!5SkZsQ%xyAeT4Vc#=h3O72hJ_GZI+ulajsTQmqq7FV$rD9c{*C@znGq3 z4o4&t@@d5c9D z646_Hb#pApE#vLc=&-H@W})Qtb4?+9pd5XmF3Ae%{~qK6B~MwP3dseD9agyFLZTB$-vfs z%$YD>x7e+3Ob+os3N`;5;;AgC@n48%l@_$mcNGBtQP=2%$t{Y31~6X{188EbOjHjA zP00o#MTAvYBzzbG7o5hyEU2(v1skZ*q@@U=zHTZTP->vv*R|TNt=-YOqqVlGwf6ck z?Mwf6bRYiKw@2R3`LgRM+xe37DcgIhZJOt8>q9w1pA z>%J-F^PtGS^WL8RV_5p@VXj4woW3E2l|JY2;6#saW8B>1MTXvgdR$e{?)FxSez?=8 zET!h|7EI4?W*pJ;#gLwV_dvX>b7TCi>)o3EYY2Ej;5Pw`^?rs%B)q;BMC3o&$?<;1 zB={@}%elQKM*L3npC|Ae0#189b0YTa?x^#=r-$i3UE>n?%>(T{pKTGpmVj3t&+Y`D zU13`f*MvOp;)F?a_D>A*y0&5J{(EJvFkpYdjgc^FaQt9wqn`_T?04x`Mo0cMZ)H#O#ttlHTn#>K}~=! zU%KR5NVTp60qS*Y0ENk8KrE<>!h-LdIK}MrV5)vNPR~Rh_I+Y3^>JLR*t{WO7CDiC zJgf(K81;!}nlD|LT;7o{OS~RZ9)0ADKD5WExbe4#^Ysi5N4_VXRS%g}5B<-w$opCU zO{h#K6{`K{wJk^w`t_fHE$HX20C&JUG4AarWv4&NwK>QYw1>XSr+^pX*e>DdbvWfq z-8Nr5{+G(qvrO}c^S@DgkxhN@r=q_3)|7xxPzY!aIf1+Y5|BYqDey!XtX~G@eMi?m zL8$B60{kFAcss+MzN1@8kUe-kpf5aMP8fElS~&eSBZU6QU-<4|XSnV}ZyX=&9FuER zp1Eyn4!dhF1f0%zOx$-=0)y*^es3^LEFaPi_)n@1xbCzD_-KsC$~{k!%qqWA(&Gw zBGLfy7WqVGOX4Y_{YPnefuRq0B788vPVV!) z@uZ==!YnicCGGGqtuHPe__##f8g8jzDEbtWu{k%BOZkSb#vxJdkJuNufs6bbpttMV`KA%+y~R}7LI}giC_;06<=eTPi%81M2_6O=Xh{S zFy+vOf-`~p!bDL_s$_g_Iij5n%rCxy0D)UMqd8)OirFZb-N9w^C8qAUt*^)_MS$l; zBLcr!`uUCXnm!?79*=zL(k-zp41*ar-N0Y7Da|4}RO!-BoW+5!{$1$khfP?@1hNLy zANq5rR`gj3P$gw52y`=;IfQphMJ>uuG&6*GCjC{{O&IRkWDVb94fbbBxTXYErUBoh z(ZpwF_WAufj;aP4IbOH;s7$iVOvV0LL^lO;zJttap+yJmzurn5C~`7}<@{9+$0LD; zchpumaTa4mMroTUcA)ZQ7HXa423Tg3syiMWI8^jlx?G0&2Gl{&NU_+gRyzMmBTNg1 zFru>+_{?-(QlXhRxm!{G<{u=?N{gYx0TV`|FC$me$r=9V23P@4LR zF`~UyM6}a|%EPT9A%rPY&58|$%!F%;sPf9o4-IJThQ?qG>?~_JHMT60tJ!woZG8vs$1Iu5e1GJSm?bR-#Jxkpal`(=z0n&p8HoQtI>^hwHBMr5)5`xMc zMxZ+xb?uurat7kNweTUDvD7jXcA9Mq(UU2yAlcQ>c(b#N!%Pn{^8PaQuPAzGL(ys?{!;aH3Jnr8* zXe-q0D`^tO<9G~C23soH&*?)kI)~1^H0ya4vE1Vnz z%~?Tw=rt1$YzH|X@*?9rGUx5-yhQY?#YCoM7qy{lju&m(G5JXC48D?=25>)==^(iO z=CF7h=bs=C&-ML)Uoc8uAvnZp)MPk490g8Z*uO#V+Q773dWL^G8+eITcPtuu@Gu=E zyMZzqQo=UEO1|nrt{ig{vAaevx-4eaO%sV1fXrsJ@#b*e{3uK;Z40{gEIPyn6Pqnj z%3q`puT7)gAdIAwNb&pyQNJRk(h4kqV~YV9{|wV`Tr`-`f;7iT6eHA_(`7XO@x_G1 z>;xZVC+BA|uA(T~4(;`s8g=7H&<4F6Yaha5K&CdDWdB2v&o0H%Y9P;MP@jU)oKw#F z*URBqL)5^Cm1A3t!FfCxC5GCZ|1AWI5OMZQTW?cp^LD!8`cnc&YetJ=L#=5hh6Ix# zHL>rPNDxCm=lDyS>*_Sz_?t8Jt5S(U;6dS5F-NDUrd0sLS4NrfF9dA-*?;qz5~H%S z7K5j-xLqgWWtEI-<^RnFazxZ#z?@#EH8QX~gpn?ZEfqe?UZL&lyul(|Dst3Qw}Z}e z?s%ATn5_~V!Bhm@hh8KGhx{x}lv1El6&#e1eTvJLd2~+5!_40JRRjE*XX2ISCQKOia3oC(nuspsOI)|1JPeg9$Q^R2`RVnqcaW7L*p3aTIb62>*Cr}h3M?_br z5wMC3l@B@6QFZu-&ViX{m0cU)WU~QkvQpk{(uLS7xpifS+2_&fiN&jo6y&&<7&dP3 zp9%Mw!E=`wy7^B2mxnF~1v$W9L2 z(^aY^h?NWpc`~ClOi|fv9n|^vF9c6LpApXX4rLbG?J+B&6_6m(NXmEmtB#!LTnDPC zK~2-OT)fE{#{hz7QY&39cT`16gx8Wt{Z_~*J0f1pFWS5)I_xj`SBCKG?U%308`WXa zM<%Yy8+JzdN3d}D2Q0n%g%?7(TghZgJZ8nCZwIf@Ue7kVMb~XlcC8)r=(jne*pa>$ z8!IM=JbDR#X6?8VKhhc@7ttd>M+swNgkNO3wv>gPUX%s}#ui#xQoS)-09k}q0`rEU z?Sz;tKS$IoN8kc0pY@nlLI6_jh{u4%E<%cqawe1hHQV#Up}Q<1ZS*GMvkNrJthSWo29n z>r(vddK+>FuAkk5wkpm77lH_%F-=LQkm@8|?0&wK(pS=)Ui?h=pH_W8f(2Ea`aXT| zr$d5iIds@^;9cRyc4$12O;n?BL6zk~r1E|@3(cQ*O%7tnR?%1$l&fjg^R`jgDM~CW zosY}XrHpqxzab^ldDZ^n0+$x;+c4jz#h6`0C9As!s=*A1J8Zk)KI!T4Y zjUTPO;>L38ZZNcpzYLA37oBeDn%7^DYEh?o89cdF^_Uay#|EQP|Cgf!tkIFrWKegG zklawiwXZ7vfMWRv6-nXbnwuo!ihByyakA><-u=d~2=Y(i62fSY7>7c(%^de(z@JJA-rCox>Ln{Cl1*6xr!X->?vJLW|Jp>^;l zXTw#2wsdm}>?a=bs?^b$_UPnshqk3`8~c`bxYVkpk}h{l`Q4L!0Vfl(eNn?lwVGDu z6~Lls^5xP;9(R&|TOy4~|58rrzJW@M>t{GZx}u&VJc>q0#xiS#g?1$K1-PU zJm{u$lqY{kYgTfQ9~r+Sv|r@Xtzmm$PF}^cW_xl@LB@;c>OhZBqj$vRL5d~jS9-Si z8%mGR)pf-^!7AdcU*IFGUr_fx`-!$+6z@Cv+svcLT3E}i<2xN@F8YU=TqRtB@HT+XqMu6wd9C>>G+ zhQ+(i+vT6lIn&L~HT<Ot}>7f_ABFkFJWb6ip_(fTZ+HRv^e9_)(SpXIY2^ z#kOuqz_^Ja$$GpD<>EvOb#ghqOpP0|2W!#NF%gMTE1!%KN=L$)7}d7GjV`3AsZpup zM-MDjzOKmR>Yxk4Yel291?%;Zb;_JpBc^4_{GbK>{L(Df1eiCJStW6n&K1-rF*5%}}3QLy!VpA^;U+as;?!5$%91AqtS;h1A*io>4^PG;M! z3F{In*OjdUTNQ29L=68ID4(l6w3N{Xbryle9i|i~dG5K#!78LKzHMrW&O@Y_WHb6- z6)I3YCKKe_^xB#{ zhg}pIY|v?GDW@Dn+ZU-eNMpShxq5NOeE%6W&I*kP+5=W*bU@0Z5ayz(RZ)a1I!|}O z@IO^tQpH}ww7FW8oN2OXipr||5Gz7Y3mON_B#lnw!H~&^3lcW}{7QDi#FJiS10M&w z$LT8TFSR-CVnJC;{3Q=NwgmU?KVT0fI|nguQWYRKFPD2a zqnC>>k7)(mW&%0}iOo#UY(~1lu2%Kh&x_3gw>PTMXA!DW-7Je5arfA4@h(Kyss!Fi@`B&M$LFL6#mTS+|uz2u?}^4yYRLyV(7OH zjb0SG%MCWL2N)G{G`axy<3*_!TOphHoBWUwofO$wc}LpP$YWwZKJ`N=Hm{Fs_qOrVQ+vQ6YjlQJMzV3D_X`wmkZ+R+r967 zX?Kp+>?JUStCU|XY?iNrUylAveg@ZKYYB0N@FD0Pc~$;CXI?)K*z+K4a~#&z@|o#W zOtqv~5f+5j{qfAJ8tUbVRI}T#jkkB~?Dw0@_>Z{R*6(asWN-GGLzpqC_8AS4nv9iN zV~w;(EFqw z7nAO!4}^)Gu(`1tb^J7Y;~cQN+xsMa2b0b7*4x#_B+mrWyNy2+>Ltv}TufVMBb{V1 zX`8Mln?t;KsqDpss(D}yJEhEI58HAiZ^k-E`L=Bw)9ux`)_rwB*nZ?GLt}Bns}<^Qf?(7@_!2Q z!SurlxDm`3+xwG>n!@-CQuA||XpJIO!*aK7V*9|xz@xpu{w#li6e56;Y1&TKUdX_6 z9`1O5Nfo%_Nb&#SCF(bjm+EC0(lQcd5q^I@W5QeDW`H$Qt=F^I1&OFXv9NRChp2%G=wrhLi9awVn=Hd@s zS+17w2BF+D@K*84Pv`pTdH>d%u~VbqKxF(uk-*c3`M2dsv|A&~fR1<6`vtOANlKAZ zA9L)KC(|B&>dxkELbs9Npg1vK_v(>-%CCoQqoh0R&BF{rf5Y>Ox+-@PK8ytla_)Y{?f(k$)=J^(ojluChf8-O-v2XJzvkIeBv!0*NNf4v6hfQHOYwsP>6(Beu98XYM_ArriL30hLa%& zPJs6Tz|~i^RwK2Hq5>)N!(rpFPK+=WJE#|zmR3dAv?{7xEidvPxR1Ko>FvpbUSE7a z{nouN+rDZ4w`Kfu+S9oEYiqb08YXcYlDf0FKS$L=H-uf~ISR&Kbw?Kcv$$WIy0faE zo4T{2e@pc_EK-#ERfSfqPG!)NT29@uIMS4QN~um~5LPv_VwVS%I*-|;|L=5sA-&&hy2=ZzzU-&(|$ zB&=Zz(W-&O>_!!BahGbzRA3V`p}QIL_HY&~;YmXkec9j*U@ z$C10{tsIuRH4RMPSr8d-Bv`4H6xFORi;glVsB<5Q-MuaV*m-#gXLY%A2vyUOl2Nd} zJ`8$!L^iB32G+R;lFcy{MYw-ROu#oWNy@|1w;*XJcT<~E#%D)hs`xSC9i1`1?vq94 zACzHl*3a^cp&aXcXNx%zd}Y!fa;JNhiaF-bEwJpPMdL3!sGLY{*LGF`(z{Mt{F4+6=3};y>uX2>^ErDxgQ9- zy)5$)+VYXy^6@7lrOh*>vtJ{y`jD-bJy6@^WRWqMTfn8Gc0z`bu_DIY!^!p zXt~*IrOe7aLfdr{N8tushr-aRZ!tE}l0_@DxZ~bzEouYnxll(avR+HbptxgrsAJ`# z1C5%s2lk&O2i)x8NfLPaVLZD|oXa6j9K9gnHtd3(rpi87pP>hzp_o^iU4(*;LfoROc9g9X1E= z?W@#><(osvL&fP{Ml`52IxgFVfTjxTa%2Z4+sujgz<#aZ9YBcdcZcvt5wX9A@yQ%~ z258j{tn$B@8w-Zc_!Ux=^Ggo~6)jvuk&m0|(z zDFKe`_D*s%hLwWK^T9>wGt6gg$xpXE6X){2E$nd7_bQ(OhO+@Cf0Y!Lxox{MxTK-? zHL0_9EqK|J)yaC@Aco>xt83OH_m&n&kD{vF=Gw?Bg^VQ(o{fpf#p0YCC5Dw+OWUjr zJ7PfK)HF3WUN-Kb|21VCcwJF$~3uG$S66{fqckGYT8*_xX*z> zPcXu>S`aGRrmNLJDUaP=RMps<0gdvBO|4pQAF(9_bhgaqVYh0NCmr4feh7+qtZTj` zdD2X-iC-?tTqeU!@TBoy(UJU<91Ts5pWsVl8qer5%~SpBS#eFq;iPb_^nP)}ckA!+ zqLQLP#i8X#*1G85B)&aw#^%kPx3EE;irj_y7Q8 z=(nF9I$S#ZlX5_a)eOOpdW&4%)|hIsdneyj$)6P5w_u8jW^AsEK|@Xra?x-#3n6n;{R^M zEaEM63p-@BNEi%oP!4V88<;mpZs<;e0~|91ghYx3PudT$NR^Q;$lu6%!$(fZg%B~< zScr*(AepKUV6sLQBCLe65!wdAz4hvg)(DL#0L`NBbCMuHUL~oxBzKCs=Cd)*wFe3z z$0dT(Kdvg8G9@-}anzg(>A!6}qBK;g%$$*HxD2yod=0QhY_YK&YsO3C#}F(=m@t0c zr-=lu#_Z4`nCzjEny9;i??FqO&6Kwbc#vv~7<&;tdsx(Q)+}ss{L8T*h0t6ax~TKW z{R{R_lJo-xAz!V!ba5FcLeQqLYYM@?QZN(&VpOb;P02?i4&BtI;WQbYWg$go6&ns$ zt_2b}cf{GpP{71pROc-mJt-Tt3c8k@puCuy7QfziZLn+#soY#H2$nJ09%PV%ARPi3 zIDQ`|kBJj-GiI^SleNQ3tm=gMVvK*A)DBq!q4bNBF^(!>4m9l-8j+7jFUm^ft z^&`>gm*+rxU-Uy>kW;d2+6!N3iL{Jb6K&opr#UDN4||;7NY=?;`7vnM67*;#K^j~ zg4>KIYh9wfMl7;a;t9eFbRjgbN+-rt3~EZ|Zk`2l9)p*}M!Vg#IZ`t>W;-nO?t_uH ze!b2m7abQ)>#tD`c!`Jksq%Dj^8BH|X#{}Yd_CM2K`D|IHGmfb8ldS-tyBQlRL_2% zH}+fPFKre}fx=&7Wv^mBmf-dS3Hh=6pQI>=E~9m-f-jWDg(V`ifacCj9mtQ5nD#NgL`^*(){MU^jIMLGh4`7x4P@4b|B{--@%P{BW?^$ zbBw5c@(1N`wdJ(5baXSEz(`r=M%sO(8*eIzQvn)A2M)7O2MeOW5kd`g7x05Q6tF@}b?T^0jY#3FAi17eCLem(m zRGg@%sNCCL?jAPxsy)Q+8o;D=Q!B;9XPq+CDd zby#E$n6CW2mW=Dk4Xo(ZcxOyLgU6;jwZx@s#AHO@HGbyoV@ZEYAF!FgfX)I z&JW`<4g?Gcp5lwHK)Qmxw(pM(kI;WOo{xurW5pW<2K4Z(E-Py_9Tgk&H*^IKbE)l;L+X$7$|!1M*1YWSx)Zb>L$( zdZlnM=UY$FD(QDAPl8UBYuieXe+JhQvO%>wo&~(p7;rSn2f(ulKw#73avdYvgerd5 zi6DhU%*YaZkfr%jOa$Q?@@4)8T>qra>;4V51j-*Qy(5kkOel<(P5i`5Jjo!`Q*H=R z%+X18cKap5DDz5LrC6#jvy3hHs(Utd9D>gGn!;R%nOsB72R833FZ3tV3E6uQd1P1c zPf7{dAZ*kmKG+j=5bcixsah&^!Q^_dP-3TxBTZmb;R@VEv2h~2oA=)IGlZq~#x_$)0^_x~2bn!}3PrFO|Tg9Bv} ze}=0PtYLo`5oGw)#UHxzxZUw}p7O*_Ry_zg^mGqg6l#v6j5;?&qm}HMLvhlD6KfFHVikwv>E*6z*?Og zS~f#(g=2R@!*CUCe>p21qi762$GsFqfp|KB!>@Bhn>w`_>voLAEJy0p+ z+A=!xG~`#AG8j2!$rH?&jY5*sOkx{@R2rmm5=?55f|D{`=!+DYs2e&9)nct$*>9`| z?WB-vfN3$yEa3G)2K9nfwsDzdR&PTj7%Igu8b95nlIEE8%&xQFWAg9c&ELNs@C%1d zJsc8>YVtKUB$fXGWIlvH$^0g*OVh|A)6Q;ZLBHRU_4}lo}3+h5Tpn2-I?Ya&D@sa10 zd`An7JTeIO$PRqa9G5hn&ul~;#-aF_g&H)orgVaO5CCyK^V+F*${2pMO>N6j0z3Lm zs-Ux9$BSTEVz7aHogEs9AxC-1=v%A7Wdy}qXhTT*q9!F00nCl`K33d-1r8`;(Od@c zIP!mgv$TJJGP~0lvAsHupjHEt8glnijx(Uhlf@P3bz2Uq%-JkN`Plw+#749mFBBT` zExMBKNh)&}HA99&7u+!moNc8CKO5IpIk-_~!OCS)_*&FK3&$|Gk^+$;VRfX)$pUP! z^7fIQ5kq*$fC+^VgQ^KA?5T7d0&`f3)W^q@d~fVfkcqoP7}}BrdcdE9T^r$Vs-lBr zzB7pkMGqr2q49;|;N`5arBk$hgAROTW1b#$03fvtJk7*NO`N2pMC9KDbfC>UCRpea z>mjZI+(k&uy^ux;9kv2l24U(k31v)xb}&EFr=~|gy*p~Gs)n3;S2rXJpD_h5BlOmr zVJ3Q?&&Q0B(b{ohnszj{azNQC8nv{54v3s1862{@;Gbta;*TRk>WBG3J&m8;aN`39 z82)tZRZVyu%I_z;{Mig+u{4&fH92AcOGSPc=yDL)v(jxWb(c`5UmM3iiY%n|t({;l z!Nvcar8-4ldQR4vAX1A%vt1TEw-XLg4;w_@BB5ha^p@Ofxul1F5y=KbCP*d{(v$1P zeFXv;_L!LXaWkTFUFC%^dQ_h@{8A@8MtJPOg#(;mIg+%AmD^&bx{{_g>>ZcGS%_`{ z9$T%BR5{XJSvyt&mBLK=E#Y+;2WNT%EE)C^|0*+OJ6@tx?hrORPc&}L@Y3DxQnq_6 z*}{|-{pc?a=}UM$#ZO0-=k2=ZX=RtNi$;+)*TJeuG=nN-eL1SovTWmiy(hDC4@CD9 zne2^9Q4zyA!ao@E&W@HMmA?o z4knN6+xX+3`d~(1%$ot+rciG~Y~VdxYS5b@-(xRmXBJ<%$k<8eZ{QNj*oKQe_W{OcaV7`yPEU; z?(@>S(!XS6OQ_J(YFY{TDhjJcDwU}mLWW10hXsLQQ2c}tgb&I$;E6kurG>ai{LQQRPZb8ThH-1urd^|*9Bd8Y7^pzzYw#QT!n zehXEExj956tEVlVO3JttVvqRAA)LvcvWftJ%QfVkuAVI#6W~yH!h-$;vS(6akgeL_FD!LhzyPWNY9iU7GJ_%y z{L3zPvbd(fW>v3GBH*xqR^pEG%i?pOex;S(cn#j%WO2%BV+L^z*=wgbF=G$TVXix# zW5elAkvy^|67~K~Y0&nl9ODC;+o)~B9pdmUTE33cj@CU9P1?&N!rOxWoX$C!vMo4= zJ%yVGVXL6FX?+xe`jO*}I9H(UBYXmyxIchRP&j}235XdVIS@?}+lBZ@V~X%;7Db%M z8QUAAQSD{Z_Qx-L{uVB4UF_QpPmg&`DKf^yOXto9&_dJ^TtL%Y;QAx5vUh7D@j!Rm zik5DOuE{xBaPn5O{h>YHuwRl-{3!*}mX=-Vr(qlBv?x$hIO?ZiT0k}0;=SPa+zGnO z#jqTI#`C;W4ldq!wG(4~IdDxh!o zM@fB$HQRl2ApQ(HT}L#4o@Cz+s})~bBtNA z-O&$bK4{?~7yUb>)L%0?sAa(8nfu{t{ynTe>fbKUM4n$^YOp5>SV<%mhcMbUo?^Ia zJ`^T$mk8P(4kP;V9xhYBpFRbI1d$)8ratXR|8W=jw=lPw`H0_^udb~&NC^?~C1=Lj5;84kpywU7t~xRRp*z7EWGKgR%J z+g#_lu4xX*bI#m1EP=<4SVW$hlJdv$(7pXoH_u?_g`atidS42w3&LB$JbW^JInNqn zGd*$-TV&NwZPR~2+>)lVC?Z;?c_mRYd@mysR<@nxlSQKFoB&J4LGKt$kw>7PpuAw3 z1Q|>Po5l^37Bl<`cPJdBH$}kWo|M9C;?#faNW2%@#J8B+DD;8io!|w7R|W|l*f0Y$ z_sFl*GN}H6oV%>4^q+9j17|ZoHv^;x^iQa|C6VvhkCE*AOm}TzZru%1JTR*<343LC zd#=fDh}ZL=II35+gFX6g`@H6YtNudRG$}jYDW5zbM9%a`)aXMv-yql!<8BF}uhYG% zNq@?ou{Lx=&GUrj+MM4)}^aQ_M)3M5mOAlAYf2ByM#vd|%83Z|u+DtacD-O?7=IVk=h z?4?#R{~1!PlBVK=IE;PBC1d>QT5xXMleai9ZDr~IoajZJK}i}~>Tq7z&nOdOj47i= zaxd5nFr&Um-s&2Y;T@mQQ8ha(XW~_tJUt8Yd$LM4uYM=|56yn{8|$|BH^-l0`hVp3 zDyAMTLat_J|6ihwtIC!<-ghBQ=m%h&cIH=Q5pAn&nQkayhYi(S(ZU!>V0Eg5uuwW$ zsA+D{_=K4ohIT=>MgC2Zm5+k8EUxTz9-=LYLFGwB#8+(1srwZizw|$c%eEuGC!Ztk zr_GnQE&goc0KbU^QdPuXfy*SV7=35R(c%o)2U^x>#EqiJB0?VY(9Y!`$c?bhT#*c1 z`S%H+b5usUpttpr1evJC+Nq6^hMgo60Q8#gIvZrT($?rZ>S`DX5ObBzh{{NJ2Q?5h z@HyUj7_E8UK~`Vk=|op+R^~IV;wCO?%p)}L`FW$6IY^=_x+-ikcbC`HxNos}&h!({ zpogvLpo7FhQn%vv5GEK2K|mT%U1r>+hFYUNnQ!^;sb394hf#8j&uP2k+QT&%iR_kG zc}B%hs3xl|O%4to7V>ZC4KlWrNd(jSHW@dLq^`{An0a9C^_{KELpQ??)9R^|6~Qdp=YgWf!@6 z+_QoF!rI}Mzkjjt#%C}!Iu=9P&CwBsicZ-Z#UU@QMUprn`2!{1EU)6l&aoH$gx~2K zt>lq2uVmdWiP}S+$)~J!EKYUS1*Pp1>}2Hp#T(e@_ri`lN|6~X)Mtlo&^CuP6U*%I zJ!!|4SYqvJ5*4XCevab~YA@(gbkW>{&aEx-AD-DKCa{JqUZAo|UJt*c_y$t)apktn zQk0_-67Vmg?h17ut~AvB*{2_Yb|>e=TNg3bX27PVM}XvB4dnlNie17;%(_H`3TKd2 z>5;FBM|#e-egAFpG!sbp@Ayq(o8obgPm(b1p7_C^VjSnT6!Dm_Ky8!MjhOzSh2aP{ z6OeiYN{)q!pV5!q^G?-+3Vk&q^jp0D-w?Fo+HL`a_}Ky!bNUh2HPd8IqoT&9ELaH)nYs;%{A58b9C2h zCgvS%n673M&DEsFdRoz`)#rqZ zfhnnGvOVSj>?*O_l@9LPbBSblNezLLdkLf2zn`@!Uv~ zFDjVwfb!rPbFn!o9PUJ^jgLQmSKc*SXBRIQYy2PB)HA=Y#2wjScq47lj1_%&BGV|V zsh%4HOVE78`pnUNfFc|nN)jAmNBA1lJ%VZz{I_pXWNvI!sMV-9V zQ$_f0K%^9BW&ekhhX4X((YWy3Y|wXHktIBWoMmfpXDE%+^N&B)&qOlc`9+1H!wwq2 zy%CFNB#3>1TOiiLH8M}(PJu@c9>LNzBi`(FaH1ay1&a^NFpH0Lx<9n|0mIKQL-?&E z@1C$H=t?`=@yz9tdlfnQ=#p1wuew&H5AmWGL zHkHJ|2FRFsa&c|6F|IM^P!bM9rt{LV(TeHPmBX!g;Nn#zClU4m`IY1_fP{M@@Z=l~ zYi(n70mGi)l#qbgS&YliVr%Dj+wEy0#%js#qzXgv1c~O!bMn+>RYHTjd+FB3;^N=a zQ#seC!4?}y`wO|JN6DSs?2_yE(j@+l0~__uG=jHS#2nsM`P_2-99o=$oA_}QiP9|` zR`BEp?U4Ke%*;J6y9AeczqRJ`)}%?fRkozbz$n^kd71r*%F961@L!@dwIs$E(S4)u z;f92NiSN$Ayp5r^?BRZ^f*fGLR(^38w%*vGBaLfl^1AD^$d+9QS59j@dPp78G!c=X zRsfd@vse*QmFSxr*FC<#?=euPbg)Adab_+Y)fXw5wtjMiG~6QX`%FzJmN3zv@0U65 zmF^sy{ej)vEzB-(3o%>+9ZNO!#+h{lo;<;|O1G&C>^UKDY$V_@M2h-mS|!mDGxuV( z60k)6Vbm(_nlqJ4!Hs(irL|uAyY3c!jLBK|(0^=$RA20S5w4k9Pv=lKM|(+yF?kax za}TmM#;gx=P@8&&4pw2Q*lzxSp?BKZ4B86$V$M~Z&0K@ktUVLl@LY&d+c}0(3g119 zajItqa|e4pv6w61WC8@*btHp{kC-4OC@$lQa&9BWC-x(|P{lXX3{iq4WaAS7F(%RO@ z?awG(seei=tL1Az37NL3u!Uj^DpTt9GDSo>i8F2@wKIDEt?oeW0lUF5gNQ=L${xg- zR72*37ayV!f^Jo9;4vilO4pEy?Y)$zWm=jfdtd4_)F+!-ugN$4Q%p1aZ!*|k>W)EI%qsFO2eNHGDHRIY2zG1* zRh~)$Q*2c7G`ZviNh5MPsm4Y8Lbd)yv?why>{jm~Ts@Xtg7T;&Q%$suZE7ORvhoe~ymL!|j_OdcbI^WW z!z`jCDqvO_=xIN>(r(hfH0;CG&;E}%6$4i_F&z`` z3t|bm=sr&p#LLIzp%}D{B^!=*#e)rgcGoE50JrFdcA%~_)yj*DB!)JiE@(c%*2jve zO@JB0&v4z2nZwUi`aSsLL(16>X(L1Q5fVcOq498LWWj~K!g>(im!{|x><0f z6DO3}67S@X@cOe2hmSz04@tkz;*w9qBfs!Fn+miyIx;(!4`0YkhP}5>|GWG%n>W9I z4kcuoKGYyk-@f4>{-;9;_J3`@|7R=lZ;>gLsycS7jHsRTsG6&lbZ0|tl3ptfJq`4$ zg|R( zBq3pBcnSSXL=m`X4v)9Jm@U}fXK%~Ub;+JYu*LN@Y78yY{-TSiG4vrk1|4j(nudcL zW$ZC@J!Z>zM$~p$fqmM#77-sJWl6I6%y?}c9T#nHe?DZ0W#W2MhZHHM1LsR2+HAEm z{Qg05_joyaAIHYD03J(-f3cNt@($sF)*1z?@vy zrIVliyB163FgO!$-7i$;ICq z#+z94gI!06R<1p{VMJ0IyRl|%U_9QW&6VT%7_}rz)_TxQnaSe(_2y9hdvf^Lzz*SZ zniPc4PP+IwF+5;ZH2(&)$;Jkv$N%YCFHepZgM}91JnnFq%oV9(PZ0=pOa5admL~qR z+{B0;^=|PxyjWF}^LKY$C?2tT{oj@WaxB*{eUa)ya0fKzw&;QWU5$nb{@TJq0pn+q zZsO2FZ^V7jg-&fo$Gvr;W!MB;=^g4YnWfrvmz`k6QF*{5yGZYEhdC@olI0!3{r<#r z+@T6UAq_o#60$FM9@v64xna!k5qdk)2$4Dn*sV*d*fm5pC=_o11q{6U(v!ko${+w{ zE4-T!c}qlf2U2}OeY&Ocn&jNdyW&P+hho@beY&N9s5Cwm+Gj$>W>Af>$u(Voq=aZxB$f@D$Lxl z|40-(J&Q85JJppg%GxBrCd%3^A6cGx_EeP0m2r*T6iI(5OU46(M4qX~*0eShdKJsA z`lo?2lVeysNfaD2GpXQUJ*cwyWNt=02nhBIxG3h#3=LrfJ_r*oTHGHHkf}W^5Da_G zKfjMr?2#bBJ9>u6G7rD~IABXik0W-ZEsl~DSLSwY&??_iP!=()iU}Oh*^LtV1Nbpkl-U`C4^PzI?f<%&>refr+ceMn-5-U};E?U0kS%ObxUYjy?q$ z*=m@W;(Rp;bk<7GXns!D@}{dy*dkb7MPA+<4H_2{G~|kT0b~?u3ZG%(<6dmalguOG z0XZu!!%m?^7NZR`q-Q;3tIKKLM}F?CJC3;ihV-h|(eYv357<+?N0?0z;jEzku_%uvoH= z-xNPdVw{tr2vpkM{@~ou!9+W2M%e)%mV0aSr>*wN=W z`(RFHY`xS%cjByxX~~OFCuDonis{gv>qwPal7F{L9#dg|;#oO>mYlFTCCG`@^o(pu zG*la2F*~VDG=_B+j{i+)MGqWea*jWM%9`whd1y8RK_eliaJ*A@!&x{i6Ga`L3jt4x z9^boJTXuxi5c1LG8Hi1{W+lq8skI9P-4uuC=*K-FM~4Wj9` zhbS%!`ykJ-bhnpP{zHqhb?0jHK$pLpi>DzdWN)Tq*8w`=lU7 z(Xuhg$ZyYQ8QV^QRXz%=;&De)@Hq^y|GVN&{j>9t-qO*!+FZVtk9;^(Jwu4b#1K1u zA)kbdfoTQHEPu|K9EOYj895T`7kuiF^d4GGZE3l+bws&!>#U4oun>VVJ+%ZDy%9>) zG;Sw6!DbJ>=GqOt=QTdWHGj-DN!>H1fw%D70~P#VGk4e}d$gRyeQbxW-d`|8`G@iQMtSyFld)PzV4|00i%9C}NZ5%>Mn=Q7H795+bHcVo)j8s#pJ{h(uXhUo=1ZFZu zQ`3nsqn>cDxan5lpWPJyw+keiFHuJ7KXS*3|LY6K&c*qk`0}qkmHhww<@~=@-Yj)! zckKn2k0~5UyObl@ChOQg5AI7{%Y&F{vWuX-b;eqC#@`3=rAfTT-NnbFIuMb8pr-Js z5_mF_pb&e4^_ZZ{0bn9ZP(dk$(}hJAb7XO>7T;y1rTo9WPkG4~#Ip{5+@5&3aXkt= zW;;!}0tDWkPRw?MimV@ZeHnbW2gY>Yh9e2QZa8#14hPP3-(uD1uSbJ*PgsgZlPrOj zGG%Ng;Z)MH8m6Nf#k3p;)562La5g=G1TJEYV2KoJ#B&=a5&R{akDCN)Fw$56XSRw*Ni-9muq zJIMHuZPw+CX*K(6L#t-S)YDgu=7|X;=dTeuf60U|-M8ua|;Y-V%}oO&*j0tu1nd68lS6z zKL<0=eXA$D-1~Z8IZb!Icj)h+@R~wjCy@mV(J@`yNb_v_b0S+XN6X4FzW$e8#GEM zh;7iVfV-?)b%n|Rlc#L5gC|&NYWw~KZeH^dDI4zV3ic_jIw1#~8y{)*9WiP8K9&^i zm@D-FlM*vgstYx3~@htsUiaGizd@a##S z_b+n>Tq|7%O~NU{<8d#Xo59pb2qQ)D*jMBlx~43VO2dWBrp-F^$e(qF<-j{*jLMvdlHwS zVrcG`IXmhv6GzJ1F_e2vS`azirTB2$9mNY&a_&iy-%UNuMu)I0@#Q9JAVp#lEyn1_VKA@&$p0~wK~dA z)?~-yteU(&w0Mnps2KgU3E!+$GfA{IBLMKps+OUkX5vHx=8j;AF;d1E;OW%2re`ps z#ZHBzFRWHCUJc5tl<;U=L(%Q|>Uh%gLl=WBf2S-^7cpg$drQhr)Sad~m0P8RSf+f9 z+7}E>6hq~;El#&TWtEOC51h9q@3)b(bOB+tzY-KVE9vp$j(ZyoF3xsGX>D1nuZY!A z%FEzOW0ve$Gi$@5n=@2#6pBO~lVvFdl6+{vjf5R#)^T-|m@B}LU3Td~bdE>Z;stv_ zXM2?;k_f|EZf-MMqFdZ>*dc)x9%uB)TY`~>!caXsu@WJN{@QF2$O;yDUZ^TH$6jNl zMY>XkG?X#ySP7>|V_H?Gm0BNj0B4f2l$f-;C@Rmnh$bhFb|l3_r#22t9vgR|v|D2) zk!GmK$-n!YJB+kakV~TY%f-7`DT>^z`@1m7e&WG`Bne`3)Hr@#kXPS(N31eiR^=vE zEJO?37KQhf+m*-{0fis|mN^uw6xsGCle_)H*%=8FCtuouR{vlMRv_3HJP zhiu~Q5RO@D;>p^*`FFZRe> z=Fkz70C>%h*IkO0IEABF;cn+1#jrPa`dwqYlRmsNs8j1+&eGAz)nmos76i0mU&nDt zr1c9IT_8>zd^6RD!4k2MF3dprezPgFYqmJ9_(PnjsoyaEVn^L4wry0BP_8mM#Dxr& z*~3~AOUw}l1}J~2M_wR0HjkBV>Ycp97X48Ruo|q-BtncmcQ97AIvBV(8;e})vN12a z?*}%{hqabU-PtVI4_3`~up~5s-wleei>JCOt>pIJG)5!GR9Sa~*SgSUBsug`?OAHF z)9$4Q@10>Wu#0pA?V79<*?XrM@x9y=55-}t?1Gv3YWk1qPAYEJ#g1vLYtz+BL4BVLM7o={gW|~ETrO499d&ukf@Sp!7 z?#nz&Kr&DX?=d18@TyT(VJ)I%CeMZ-k1uBLXi1H-=TUaNaL!A$z{GIjZsrM4o>S#! z!X?l4Ckh$7g9hx&+M>C66fS>*k5#Wx9(*zoI`a!rl% zw<*K<-B?V)ITOwcunC;q0rn%l^5B~>&IeviT5S9HgecDW`>3|+2dO2%HB|!XXV!3E z@^$S}Rxyvc8%2zDyg9!8wB$Xd{DRo~!&$uaNcw?qPKqB|$G2M2ri8 z7+3ee+abn_Qx)V>+8b}Mf99F4ugAue{$#Q6mVg z`QzV0t1VGaSoXWGJE4+G{K9Qc-<$RE*Y?&;!nRmaLrN5bt{kUOQe{`Qy<@|OvadnW zYZ;0@irmo-Shdk!H6O;zyXvovvLCT0k39K&160m4t{*$z)!cWdp5I{?cXDb$K1c7i zdeI7lJ^I#`0oMe_eLN2r3?f~dR)-I-CfHohQa>?1BlQ$d>zNDS(`L4i(*X0htCdm6 zJSki9IAwHd=$e%#f#wWJLfZBW)MW?7wgm`k1n?q+0qlrlU^eRv_6GruuMkzErzK2w7h- zn^h~t@$u8Ij-*P9e7D&($R_TauMv%abi}n=!%&z?5XMcW6Vf33`k4I4xLJ+;oI_G| zEyI3(TL-g>Nw6GtsC`*3{U@a^%pt;#V+?En_>|EiQ3V`2Z>WZgsm63g1!oM+X-Be1 zOX@eh>BsLf<#3*%HS^#44q#|%p)cQ!R}^I&Xf@2g zxFxY}X~q%SeS9%6O|Qr6IXk0lZ~Q|w8?jg|F?mlOA-jL!I={32jfQK@z%u37AzqJg zT@R64pS*5^*K*(hu7dPCAhzF-d83DhwT15ZGN}Eyz2f%{_Cwem;|zGcVZ{H#^dP_c zTLvQ3qT==1hgUSv2VS6;1a2R21N+du|HhHDqci#!zbpLlhHj*!|CCg(8E+ET6*=Y& z&UN9EWKEKH{uqS|vb#7t@rH({=B{)`z7ScU0I0mf<47-0ovYf&jQ2ShB@akg!^17jYz%c?lm%N*GW8lJ%DHoAa7VD|Z@;Ua;H(WL*@2XWnS(1d}Cv^@{FliajFgxuv<$*rG>>DY4*P`F}j%-WBoL+me?Z2-5xu0x8embd-Q z%b~5q$iVFGBCU;X%BvoEUxIOg6cx`7xf6|FI-XxZLeT6#_B-)v@rKr&Lsy@eV+4$b z0{zO~{SvQ;cTm|3y`}65lQ+nRVQ93t7!d=s{QhEQ#O%zw&7;QW2~-kHDb*=uEt00Y zw$Qt|sCzY;{(yZMUh?|uit#~MX2@!3C_DRij5N?iin!m)SBKs?6-ibH+O0y9iCUapBIqMT8e|BP zfw;-yT;i7{`@~#C7-M6z#MMq8Kn*&9U#cF`i^Dv#EM zM)(%6MPsE&wnk~z%=B^5;+@)-737t&^c-!*^|cyJm^}M1MkUs4vxOJ&HiNz=Y*oMT z_kP}Eag4g|$vr@l8LpG?MD=M45c5Ra4JQwx)QxcxG3|MT<5b5zlxv%GkW22FB{2Jr zd@N;ts$xey8du-=pR@4Ccj8xT??DeA@uC=am#A0$9XILz`A)o2-Kyhy3qDoBnYqR_ z`$qdP?D6eb!l@mSKi1&r+#A*XwkRXEhqr=Jw^qvU@gc98Dds8`IH}J_Yn) zdbV$_U7DOCx0+tL&*5l&2^-t#Gola8iJh@v2mJJP`Sp%@Gb>#ce>bwThcdl$J%;>? zgm8jBRBSEFYzeD6b33p!%=2mAL?(BrQ#PhqVy(Pngr`vUpnbv)?1|@qgkRZbP-d2v zU+sO6nZK~NB9y;?KX6SZQKS+S?$?epZj?DN8nm4NOj# z?^KZX6#1ftk6+iz=RdN6zREQA5yH1`rbPd#2t)ec$Od9gMh5mKKxan-XA?7z|D{>` z#PY%P3L*w?iG~w?fL#nI!ESt4ho}rdM}lpiFdaddNuH?MUZCau8H&tdZnTHmmoc=L zk#=jIvs9?@Ow1Y+R}&iCJyc!@$g*j+3^LLe}lr%Sb)xXeA#$@0G1g z&k>Qdz2JYApVocIs>E$%QZ6T>;Zz&)KC2pJTTy}T2xRq;-w(>w=%MzVT&AZgVhkGb zgUeGp8dW_Ra&6A&DD@foo=0Vg0&xi}nReL-{Dk;tFvPgrTiU-K_3i8P|Br+I^3Z*= zb2MYHG`6#0_?LzvZs%xY;7lrNVrt-G?fl;j%~!a;9jeM#xc}wQI6bfpFIP#*B3^84 zc7u+vQBTmoqDX0UC}lAqVD9ANvSBWbnMZ2?1LYG`*L%8zKb4i#=lVCQB2;>qW-uiJ zHk){KIKfT0pCF%`tJZ66YRky_SJv%OcI+0HlNrWGn*%I=KNH#B�s*dMq>JLX-P3 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 z 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 Y`CYb)y=1%oI@n19M~1g#Z8m 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}_?=j-U~>Fw(7>+kIF?eXsO@AUAr@ipgn^*Qyr_B!^v z_dEBz_&oTX_}%#(`Cj>+`QG{-`d|8=`rrE>`(XQ^`{4W_{9*i&{IUGe{PFz}{WASh z{c`=1{j&Yi{qp`2{xkkl{&W6|{+s@*{=5Fm{@ecR{`>z6{~Z4;|2+Rp|6KoU|9t<5 z|B(Nf|DgY<|FHkK|G@vq|Iq)~|KR`V|M36#004dfdHi+warABPY3pU@VdGujS=v?B zQPNG$Ny$aULBT%0JiI!&IJY*nG_x|XFt0AHEUPN0D5fT)B%&gqAf6u_9vdAR92pxJ z8W$NB7!?;3784Z`6cG~;5)Tm#5DX7Y4$BTp4ayBl49N^g3&;yc3dagY3C0OU2*n6Q z2gCa0Hgqv0E7T|0B`_k d0AK)E08ju(06+jZ05AY303ZMu01yBO001A}1w;S< diff --git a/src/javazoom/jl/decoder/huffcodetab.java b/src/javazoom/jl/decoder/huffcodetab.java deleted file mode 100644 index 94b18295c8d..00000000000 --- a/src/javazoom/jl/decoder/huffcodetab.java +++ /dev/null @@ -1,606 +0,0 @@ -/* - * 11/19/04 1.0 moved to LGPL. - * 16/11/99 Renamed class, added javadoc, and changed table - * name from String to 3 chars. mdm@techie.com - * 02/15/99 Java Conversion by E.B, javalayer@javazoom.net - * - * 04/19/97 : Adapted from the ISO MPEG Audio Subgroup Software Simulation - * Group's public c source for its MPEG audio decoder. Miscellaneous - * changes by Jeff Tsay (ctsay@pasteur.eecs.berkeley.edu). - *----------------------------------------------------------------------- - * Copyright (c) 1991 MPEG/audio software simulation group, All Rights Reserved - * MPEG/audio coding/decoding software, work in progress - * NOT for public distribution until verified and approved by the - * MPEG/audio committee. For further information, please contact - * Davis Pan, 508-493-2241, e-mail: pan@3d.enet.dec.com - * - * VERSION 4.1 - * changes made since last update: - * date programmers comment - * 27.2.92 F.O.Witte (ITT Intermetall) - * 8/24/93 M. Iwadare Changed for 1 pass decoding. - * 7/14/94 J. Koller useless 'typedef' before huffcodetab removed - *----------------------------------------------------------------------- - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as published - * by the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - *---------------------------------------------------------------------- - */ - -package javazoom.jl.decoder; - -/** - * Class to implements Huffman decoder. - */ -final class huffcodetab -{ - private static final int MXOFF=250; - private static final int HTN=34; - - private char tablename0 = ' '; /* string, containing table_description */ - private char tablename1 = ' '; /* string, containing table_description */ - //private char tablename2 = ' '; /* string, containing table_description */ - - private int xlen; /* max. x-index+ */ - private int ylen; /* max. y-index+ */ - private int linbits; /* number of linbits */ - @SuppressWarnings("unused") - private int linmax; /* max number to be stored in linbits */ - @SuppressWarnings("unused") - private int ref; /* a positive value indicates a reference */ - - //private int[] table=null; /* pointer to array[xlen][ylen] */ - - //private int[] hlen=null; /* pointer to array[xlen][ylen] */ - private int[][] val=null; /* decoder tree */ - private int treelen; /* length of decoder tree */ - - private static int ValTab0[][] = { - {0,0} // dummy - }; - - private static int ValTab1[][] = { - {2,1},{0,0},{2,1},{0,16},{2,1},{0,1},{0,17}, - }; - - private static int ValTab2[][] = { - {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1},{2,1}, - {0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34}, - }; - - private static int ValTab3[][] = { - {4,1},{2,1},{0,0},{0,1},{2,1},{0,17},{2,1},{0,16},{4,1},{2,1}, - {0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34}, - }; - - private static int ValTab4[][] = {{0,0}}; // dummy - - private static int ValTab5[][] = { - {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{8,1},{4,1}, - {2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{8,1},{4,1},{2,1},{0,34}, - {0,48},{2,1},{0,3},{0,19},{2,1},{0,49},{2,1},{0,50},{2,1},{0,35}, - {0,51}, - }; - - private static int ValTab6[][] = { - {6,1},{4,1},{2,1},{0,0},{0,16},{0,17},{6,1},{2,1},{0,1},{2,1}, - {0,32},{0,33},{6,1},{2,1},{0,18},{2,1},{0,2},{0,34},{4,1},{2,1}, - {0,49},{0,19},{4,1},{2,1},{0,48},{0,50},{2,1},{0,35},{2,1},{0,3}, - {0,51}, - }; - - private static int ValTab7[][] = { - {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{8,1},{2,1},{0,17},{4,1}, - {2,1},{0,32},{0,2},{0,33},{18,1},{6,1},{2,1},{0,18},{2,1},{0,34}, - {0,48},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1},{0,3},{0,50},{2,1}, - {0,35},{0,4},{10,1},{4,1},{2,1},{0,64},{0,65},{2,1},{0,20},{2,1}, - {0,66},{0,36},{12,1},{6,1},{4,1},{2,1},{0,51},{0,67},{0,80},{4,1}, - {2,1},{0,52},{0,5},{0,81},{6,1},{2,1},{0,21},{2,1},{0,82},{0,37}, - {4,1},{2,1},{0,68},{0,53},{4,1},{2,1},{0,83},{0,84},{2,1},{0,69}, - {0,85}, - }; - - private static int ValTab8[][] = { - {6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1},{2,1}, - {0,33},{0,18},{14,1},{4,1},{2,1},{0,32},{0,2},{2,1},{0,34},{4,1}, - {2,1},{0,48},{0,3},{2,1},{0,49},{0,19},{14,1},{8,1},{4,1},{2,1}, - {0,50},{0,35},{2,1},{0,64},{0,4},{2,1},{0,65},{2,1},{0,20},{0,66}, - {12,1},{6,1},{2,1},{0,36},{2,1},{0,51},{0,80},{4,1},{2,1},{0,67}, - {0,52},{0,81},{6,1},{2,1},{0,21},{2,1},{0,5},{0,82},{6,1},{2,1}, - {0,37},{2,1},{0,68},{0,53},{2,1},{0,83},{2,1},{0,69},{2,1},{0,84}, - {0,85}, - }; - - private static int ValTab9[][] = { - {8,1},{4,1},{2,1},{0,0},{0,16},{2,1},{0,1},{0,17},{10,1},{4,1}, - {2,1},{0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34},{12,1},{6,1}, - {4,1},{2,1},{0,48},{0,3},{0,49},{2,1},{0,19},{2,1},{0,50},{0,35}, - {12,1},{4,1},{2,1},{0,65},{0,20},{4,1},{2,1},{0,64},{0,51},{2,1}, - {0,66},{0,36},{10,1},{6,1},{4,1},{2,1},{0,4},{0,80},{0,67},{2,1}, - {0,52},{0,81},{8,1},{4,1},{2,1},{0,21},{0,82},{2,1},{0,37},{0,68}, - {6,1},{4,1},{2,1},{0,5},{0,84},{0,83},{2,1},{0,53},{2,1},{0,69}, - {0,85}, - }; - - private static int ValTab10[][] = { - {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{10,1},{2,1},{0,17},{4,1}, - {2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{28,1},{8,1},{4,1},{2,1}, - {0,34},{0,48},{2,1},{0,49},{0,19},{8,1},{4,1},{2,1},{0,3},{0,50}, - {2,1},{0,35},{0,64},{4,1},{2,1},{0,65},{0,20},{4,1},{2,1},{0,4}, - {0,51},{2,1},{0,66},{0,36},{28,1},{10,1},{6,1},{4,1},{2,1},{0,80}, - {0,5},{0,96},{2,1},{0,97},{0,22},{12,1},{6,1},{4,1},{2,1},{0,67}, - {0,52},{0,81},{2,1},{0,21},{2,1},{0,82},{0,37},{4,1},{2,1},{0,38}, - {0,54},{0,113},{20,1},{8,1},{2,1},{0,23},{4,1},{2,1},{0,68},{0,83}, - {0,6},{6,1},{4,1},{2,1},{0,53},{0,69},{0,98},{2,1},{0,112},{2,1}, - {0,7},{0,100},{14,1},{4,1},{2,1},{0,114},{0,39},{6,1},{2,1},{0,99}, - {2,1},{0,84},{0,85},{2,1},{0,70},{0,115},{8,1},{4,1},{2,1},{0,55}, - {0,101},{2,1},{0,86},{0,116},{6,1},{2,1},{0,71},{2,1},{0,102},{0,117}, - {4,1},{2,1},{0,87},{0,118},{2,1},{0,103},{0,119}, - }; - - private static int ValTab11[][] = { - {6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{8,1},{2,1},{0,17},{4,1}, - {2,1},{0,32},{0,2},{0,18},{24,1},{8,1},{2,1},{0,33},{2,1},{0,34}, - {2,1},{0,48},{0,3},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1},{0,50}, - {0,35},{4,1},{2,1},{0,64},{0,4},{2,1},{0,65},{0,20},{30,1},{16,1}, - {10,1},{4,1},{2,1},{0,66},{0,36},{4,1},{2,1},{0,51},{0,67},{0,80}, - {4,1},{2,1},{0,52},{0,81},{0,97},{6,1},{2,1},{0,22},{2,1},{0,6}, - {0,38},{2,1},{0,98},{2,1},{0,21},{2,1},{0,5},{0,82},{16,1},{10,1}, - {6,1},{4,1},{2,1},{0,37},{0,68},{0,96},{2,1},{0,99},{0,54},{4,1}, - {2,1},{0,112},{0,23},{0,113},{16,1},{6,1},{4,1},{2,1},{0,7},{0,100}, - {0,114},{2,1},{0,39},{4,1},{2,1},{0,83},{0,53},{2,1},{0,84},{0,69}, - {10,1},{4,1},{2,1},{0,70},{0,115},{2,1},{0,55},{2,1},{0,101},{0,86}, - {10,1},{6,1},{4,1},{2,1},{0,85},{0,87},{0,116},{2,1},{0,71},{0,102}, - {4,1},{2,1},{0,117},{0,118},{2,1},{0,103},{0,119}, - }; - - private static int ValTab12[][] = { - {12,1},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{2,1},{0,0},{2,1}, - {0,32},{0,2},{16,1},{4,1},{2,1},{0,33},{0,18},{4,1},{2,1},{0,34}, - {0,49},{2,1},{0,19},{2,1},{0,48},{2,1},{0,3},{0,64},{26,1},{8,1}, - {4,1},{2,1},{0,50},{0,35},{2,1},{0,65},{0,51},{10,1},{4,1},{2,1}, - {0,20},{0,66},{2,1},{0,36},{2,1},{0,4},{0,80},{4,1},{2,1},{0,67}, - {0,52},{2,1},{0,81},{0,21},{28,1},{14,1},{8,1},{4,1},{2,1},{0,82}, - {0,37},{2,1},{0,83},{0,53},{4,1},{2,1},{0,96},{0,22},{0,97},{4,1}, - {2,1},{0,98},{0,38},{6,1},{4,1},{2,1},{0,5},{0,6},{0,68},{2,1}, - {0,84},{0,69},{18,1},{10,1},{4,1},{2,1},{0,99},{0,54},{4,1},{2,1}, - {0,112},{0,7},{0,113},{4,1},{2,1},{0,23},{0,100},{2,1},{0,70},{0,114}, - {10,1},{6,1},{2,1},{0,39},{2,1},{0,85},{0,115},{2,1},{0,55},{0,86}, - {8,1},{4,1},{2,1},{0,101},{0,116},{2,1},{0,71},{0,102},{4,1},{2,1}, - {0,117},{0,87},{2,1},{0,118},{2,1},{0,103},{0,119}, - }; - - private static int ValTab13[][] = { - {2,1},{0,0},{6,1},{2,1},{0,16},{2,1},{0,1},{0,17},{28,1},{8,1}, - {4,1},{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{8,1},{4,1},{2,1}, - {0,34},{0,48},{2,1},{0,3},{0,49},{6,1},{2,1},{0,19},{2,1},{0,50}, - {0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{70,1},{28,1},{14,1},{6,1}, - {2,1},{0,20},{2,1},{0,51},{0,66},{4,1},{2,1},{0,36},{0,80},{2,1}, - {0,67},{0,52},{4,1},{2,1},{0,81},{0,21},{4,1},{2,1},{0,5},{0,82}, - {2,1},{0,37},{2,1},{0,68},{0,83},{14,1},{8,1},{4,1},{2,1},{0,96}, - {0,6},{2,1},{0,97},{0,22},{4,1},{2,1},{0,128},{0,8},{0,129},{16,1}, - {8,1},{4,1},{2,1},{0,53},{0,98},{2,1},{0,38},{0,84},{4,1},{2,1}, - {0,69},{0,99},{2,1},{0,54},{0,112},{6,1},{4,1},{2,1},{0,7},{0,85}, - {0,113},{2,1},{0,23},{2,1},{0,39},{0,55},{72,1},{24,1},{12,1},{4,1}, - {2,1},{0,24},{0,130},{2,1},{0,40},{4,1},{2,1},{0,100},{0,70},{0,114}, - {8,1},{4,1},{2,1},{0,132},{0,72},{2,1},{0,144},{0,9},{2,1},{0,145}, - {0,25},{24,1},{14,1},{8,1},{4,1},{2,1},{0,115},{0,101},{2,1},{0,86}, - {0,116},{4,1},{2,1},{0,71},{0,102},{0,131},{6,1},{2,1},{0,56},{2,1}, - {0,117},{0,87},{2,1},{0,146},{0,41},{14,1},{8,1},{4,1},{2,1},{0,103}, - {0,133},{2,1},{0,88},{0,57},{2,1},{0,147},{2,1},{0,73},{0,134},{6,1}, - {2,1},{0,160},{2,1},{0,104},{0,10},{2,1},{0,161},{0,26},{68,1},{24,1}, - {12,1},{4,1},{2,1},{0,162},{0,42},{4,1},{2,1},{0,149},{0,89},{2,1}, - {0,163},{0,58},{8,1},{4,1},{2,1},{0,74},{0,150},{2,1},{0,176},{0,11}, - {2,1},{0,177},{0,27},{20,1},{8,1},{2,1},{0,178},{4,1},{2,1},{0,118}, - {0,119},{0,148},{6,1},{4,1},{2,1},{0,135},{0,120},{0,164},{4,1},{2,1}, - {0,105},{0,165},{0,43},{12,1},{6,1},{4,1},{2,1},{0,90},{0,136},{0,179}, - {2,1},{0,59},{2,1},{0,121},{0,166},{6,1},{4,1},{2,1},{0,106},{0,180}, - {0,192},{4,1},{2,1},{0,12},{0,152},{0,193},{60,1},{22,1},{10,1},{6,1}, - {2,1},{0,28},{2,1},{0,137},{0,181},{2,1},{0,91},{0,194},{4,1},{2,1}, - {0,44},{0,60},{4,1},{2,1},{0,182},{0,107},{2,1},{0,196},{0,76},{16,1}, - {8,1},{4,1},{2,1},{0,168},{0,138},{2,1},{0,208},{0,13},{2,1},{0,209}, - {2,1},{0,75},{2,1},{0,151},{0,167},{12,1},{6,1},{2,1},{0,195},{2,1}, - {0,122},{0,153},{4,1},{2,1},{0,197},{0,92},{0,183},{4,1},{2,1},{0,29}, - {0,210},{2,1},{0,45},{2,1},{0,123},{0,211},{52,1},{28,1},{12,1},{4,1}, - {2,1},{0,61},{0,198},{4,1},{2,1},{0,108},{0,169},{2,1},{0,154},{0,212}, - {8,1},{4,1},{2,1},{0,184},{0,139},{2,1},{0,77},{0,199},{4,1},{2,1}, - {0,124},{0,213},{2,1},{0,93},{0,224},{10,1},{4,1},{2,1},{0,225},{0,30}, - {4,1},{2,1},{0,14},{0,46},{0,226},{8,1},{4,1},{2,1},{0,227},{0,109}, - {2,1},{0,140},{0,228},{4,1},{2,1},{0,229},{0,186},{0,240},{38,1},{16,1}, - {4,1},{2,1},{0,241},{0,31},{6,1},{4,1},{2,1},{0,170},{0,155},{0,185}, - {2,1},{0,62},{2,1},{0,214},{0,200},{12,1},{6,1},{2,1},{0,78},{2,1}, - {0,215},{0,125},{2,1},{0,171},{2,1},{0,94},{0,201},{6,1},{2,1},{0,15}, - {2,1},{0,156},{0,110},{2,1},{0,242},{0,47},{32,1},{16,1},{6,1},{4,1}, - {2,1},{0,216},{0,141},{0,63},{6,1},{2,1},{0,243},{2,1},{0,230},{0,202}, - {2,1},{0,244},{0,79},{8,1},{4,1},{2,1},{0,187},{0,172},{2,1},{0,231}, - {0,245},{4,1},{2,1},{0,217},{0,157},{2,1},{0,95},{0,232},{30,1},{12,1}, - {6,1},{2,1},{0,111},{2,1},{0,246},{0,203},{4,1},{2,1},{0,188},{0,173}, - {0,218},{8,1},{2,1},{0,247},{4,1},{2,1},{0,126},{0,127},{0,142},{6,1}, - {4,1},{2,1},{0,158},{0,174},{0,204},{2,1},{0,248},{0,143},{18,1},{8,1}, - {4,1},{2,1},{0,219},{0,189},{2,1},{0,234},{0,249},{4,1},{2,1},{0,159}, - {0,235},{2,1},{0,190},{2,1},{0,205},{0,250},{14,1},{4,1},{2,1},{0,221}, - {0,236},{6,1},{4,1},{2,1},{0,233},{0,175},{0,220},{2,1},{0,206},{0,251}, - {8,1},{4,1},{2,1},{0,191},{0,222},{2,1},{0,207},{0,238},{4,1},{2,1}, - {0,223},{0,239},{2,1},{0,255},{2,1},{0,237},{2,1},{0,253},{2,1},{0,252}, - {0,254}, - }; - - private static int ValTab14[][] = { - {0,0} // dummy - }; - - private static int ValTab15[][] = { - {16,1},{6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1}, - {2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{50,1},{16,1},{6,1},{2,1}, - {0,34},{2,1},{0,48},{0,49},{6,1},{2,1},{0,19},{2,1},{0,3},{0,64}, - {2,1},{0,50},{0,35},{14,1},{6,1},{4,1},{2,1},{0,4},{0,20},{0,65}, - {4,1},{2,1},{0,51},{0,66},{2,1},{0,36},{0,67},{10,1},{6,1},{2,1}, - {0,52},{2,1},{0,80},{0,5},{2,1},{0,81},{0,21},{4,1},{2,1},{0,82}, - {0,37},{4,1},{2,1},{0,68},{0,83},{0,97},{90,1},{36,1},{18,1},{10,1}, - {6,1},{2,1},{0,53},{2,1},{0,96},{0,6},{2,1},{0,22},{0,98},{4,1}, - {2,1},{0,38},{0,84},{2,1},{0,69},{0,99},{10,1},{6,1},{2,1},{0,54}, - {2,1},{0,112},{0,7},{2,1},{0,113},{0,85},{4,1},{2,1},{0,23},{0,100}, - {2,1},{0,114},{0,39},{24,1},{16,1},{8,1},{4,1},{2,1},{0,70},{0,115}, - {2,1},{0,55},{0,101},{4,1},{2,1},{0,86},{0,128},{2,1},{0,8},{0,116}, - {4,1},{2,1},{0,129},{0,24},{2,1},{0,130},{0,40},{16,1},{8,1},{4,1}, - {2,1},{0,71},{0,102},{2,1},{0,131},{0,56},{4,1},{2,1},{0,117},{0,87}, - {2,1},{0,132},{0,72},{6,1},{4,1},{2,1},{0,144},{0,25},{0,145},{4,1}, - {2,1},{0,146},{0,118},{2,1},{0,103},{0,41},{92,1},{36,1},{18,1},{10,1}, - {4,1},{2,1},{0,133},{0,88},{4,1},{2,1},{0,9},{0,119},{0,147},{4,1}, - {2,1},{0,57},{0,148},{2,1},{0,73},{0,134},{10,1},{6,1},{2,1},{0,104}, - {2,1},{0,160},{0,10},{2,1},{0,161},{0,26},{4,1},{2,1},{0,162},{0,42}, - {2,1},{0,149},{0,89},{26,1},{14,1},{6,1},{2,1},{0,163},{2,1},{0,58}, - {0,135},{4,1},{2,1},{0,120},{0,164},{2,1},{0,74},{0,150},{6,1},{4,1}, - {2,1},{0,105},{0,176},{0,177},{4,1},{2,1},{0,27},{0,165},{0,178},{14,1}, - {8,1},{4,1},{2,1},{0,90},{0,43},{2,1},{0,136},{0,151},{2,1},{0,179}, - {2,1},{0,121},{0,59},{8,1},{4,1},{2,1},{0,106},{0,180},{2,1},{0,75}, - {0,193},{4,1},{2,1},{0,152},{0,137},{2,1},{0,28},{0,181},{80,1},{34,1}, - {16,1},{6,1},{4,1},{2,1},{0,91},{0,44},{0,194},{6,1},{4,1},{2,1}, - {0,11},{0,192},{0,166},{2,1},{0,167},{0,122},{10,1},{4,1},{2,1},{0,195}, - {0,60},{4,1},{2,1},{0,12},{0,153},{0,182},{4,1},{2,1},{0,107},{0,196}, - {2,1},{0,76},{0,168},{20,1},{10,1},{4,1},{2,1},{0,138},{0,197},{4,1}, - {2,1},{0,208},{0,92},{0,209},{4,1},{2,1},{0,183},{0,123},{2,1},{0,29}, - {2,1},{0,13},{0,45},{12,1},{4,1},{2,1},{0,210},{0,211},{4,1},{2,1}, - {0,61},{0,198},{2,1},{0,108},{0,169},{6,1},{4,1},{2,1},{0,154},{0,184}, - {0,212},{4,1},{2,1},{0,139},{0,77},{2,1},{0,199},{0,124},{68,1},{34,1}, - {18,1},{10,1},{4,1},{2,1},{0,213},{0,93},{4,1},{2,1},{0,224},{0,14}, - {0,225},{4,1},{2,1},{0,30},{0,226},{2,1},{0,170},{0,46},{8,1},{4,1}, - {2,1},{0,185},{0,155},{2,1},{0,227},{0,214},{4,1},{2,1},{0,109},{0,62}, - {2,1},{0,200},{0,140},{16,1},{8,1},{4,1},{2,1},{0,228},{0,78},{2,1}, - {0,215},{0,125},{4,1},{2,1},{0,229},{0,186},{2,1},{0,171},{0,94},{8,1}, - {4,1},{2,1},{0,201},{0,156},{2,1},{0,241},{0,31},{6,1},{4,1},{2,1}, - {0,240},{0,110},{0,242},{2,1},{0,47},{0,230},{38,1},{18,1},{8,1},{4,1}, - {2,1},{0,216},{0,243},{2,1},{0,63},{0,244},{6,1},{2,1},{0,79},{2,1}, - {0,141},{0,217},{2,1},{0,187},{0,202},{8,1},{4,1},{2,1},{0,172},{0,231}, - {2,1},{0,126},{0,245},{8,1},{4,1},{2,1},{0,157},{0,95},{2,1},{0,232}, - {0,142},{2,1},{0,246},{0,203},{34,1},{18,1},{10,1},{6,1},{4,1},{2,1}, - {0,15},{0,174},{0,111},{2,1},{0,188},{0,218},{4,1},{2,1},{0,173},{0,247}, - {2,1},{0,127},{0,233},{8,1},{4,1},{2,1},{0,158},{0,204},{2,1},{0,248}, - {0,143},{4,1},{2,1},{0,219},{0,189},{2,1},{0,234},{0,249},{16,1},{8,1}, - {4,1},{2,1},{0,159},{0,220},{2,1},{0,205},{0,235},{4,1},{2,1},{0,190}, - {0,250},{2,1},{0,175},{0,221},{14,1},{6,1},{4,1},{2,1},{0,236},{0,206}, - {0,251},{4,1},{2,1},{0,191},{0,237},{2,1},{0,222},{0,252},{6,1},{4,1}, - {2,1},{0,207},{0,253},{0,238},{4,1},{2,1},{0,223},{0,254},{2,1},{0,239}, - {0,255}, - }; - - private static int ValTab16[][] = { - {2,1},{0,0},{6,1},{2,1},{0,16},{2,1},{0,1},{0,17},{42,1},{8,1}, - {4,1},{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{10,1},{6,1},{2,1}, - {0,34},{2,1},{0,48},{0,3},{2,1},{0,49},{0,19},{10,1},{4,1},{2,1}, - {0,50},{0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{6,1},{2,1},{0,20}, - {2,1},{0,51},{0,66},{4,1},{2,1},{0,36},{0,80},{2,1},{0,67},{0,52}, - {138,1},{40,1},{16,1},{6,1},{4,1},{2,1},{0,5},{0,21},{0,81},{4,1}, - {2,1},{0,82},{0,37},{4,1},{2,1},{0,68},{0,53},{0,83},{10,1},{6,1}, - {4,1},{2,1},{0,96},{0,6},{0,97},{2,1},{0,22},{0,98},{8,1},{4,1}, - {2,1},{0,38},{0,84},{2,1},{0,69},{0,99},{4,1},{2,1},{0,54},{0,112}, - {0,113},{40,1},{18,1},{8,1},{2,1},{0,23},{2,1},{0,7},{2,1},{0,85}, - {0,100},{4,1},{2,1},{0,114},{0,39},{4,1},{2,1},{0,70},{0,101},{0,115}, - {10,1},{6,1},{2,1},{0,55},{2,1},{0,86},{0,8},{2,1},{0,128},{0,129}, - {6,1},{2,1},{0,24},{2,1},{0,116},{0,71},{2,1},{0,130},{2,1},{0,40}, - {0,102},{24,1},{14,1},{8,1},{4,1},{2,1},{0,131},{0,56},{2,1},{0,117}, - {0,132},{4,1},{2,1},{0,72},{0,144},{0,145},{6,1},{2,1},{0,25},{2,1}, - {0,9},{0,118},{2,1},{0,146},{0,41},{14,1},{8,1},{4,1},{2,1},{0,133}, - {0,88},{2,1},{0,147},{0,57},{4,1},{2,1},{0,160},{0,10},{0,26},{8,1}, - {2,1},{0,162},{2,1},{0,103},{2,1},{0,87},{0,73},{6,1},{2,1},{0,148}, - {2,1},{0,119},{0,134},{2,1},{0,161},{2,1},{0,104},{0,149},{220,1},{126,1}, - {50,1},{26,1},{12,1},{6,1},{2,1},{0,42},{2,1},{0,89},{0,58},{2,1}, - {0,163},{2,1},{0,135},{0,120},{8,1},{4,1},{2,1},{0,164},{0,74},{2,1}, - {0,150},{0,105},{4,1},{2,1},{0,176},{0,11},{0,177},{10,1},{4,1},{2,1}, - {0,27},{0,178},{2,1},{0,43},{2,1},{0,165},{0,90},{6,1},{2,1},{0,179}, - {2,1},{0,166},{0,106},{4,1},{2,1},{0,180},{0,75},{2,1},{0,12},{0,193}, - {30,1},{14,1},{6,1},{4,1},{2,1},{0,181},{0,194},{0,44},{4,1},{2,1}, - {0,167},{0,195},{2,1},{0,107},{0,196},{8,1},{2,1},{0,29},{4,1},{2,1}, - {0,136},{0,151},{0,59},{4,1},{2,1},{0,209},{0,210},{2,1},{0,45},{0,211}, - {18,1},{6,1},{4,1},{2,1},{0,30},{0,46},{0,226},{6,1},{4,1},{2,1}, - {0,121},{0,152},{0,192},{2,1},{0,28},{2,1},{0,137},{0,91},{14,1},{6,1}, - {2,1},{0,60},{2,1},{0,122},{0,182},{4,1},{2,1},{0,76},{0,153},{2,1}, - {0,168},{0,138},{6,1},{2,1},{0,13},{2,1},{0,197},{0,92},{4,1},{2,1}, - {0,61},{0,198},{2,1},{0,108},{0,154},{88,1},{86,1},{36,1},{16,1},{8,1}, - {4,1},{2,1},{0,139},{0,77},{2,1},{0,199},{0,124},{4,1},{2,1},{0,213}, - {0,93},{2,1},{0,224},{0,14},{8,1},{2,1},{0,227},{4,1},{2,1},{0,208}, - {0,183},{0,123},{6,1},{4,1},{2,1},{0,169},{0,184},{0,212},{2,1},{0,225}, - {2,1},{0,170},{0,185},{24,1},{10,1},{6,1},{4,1},{2,1},{0,155},{0,214}, - {0,109},{2,1},{0,62},{0,200},{6,1},{4,1},{2,1},{0,140},{0,228},{0,78}, - {4,1},{2,1},{0,215},{0,229},{2,1},{0,186},{0,171},{12,1},{4,1},{2,1}, - {0,156},{0,230},{4,1},{2,1},{0,110},{0,216},{2,1},{0,141},{0,187},{8,1}, - {4,1},{2,1},{0,231},{0,157},{2,1},{0,232},{0,142},{4,1},{2,1},{0,203}, - {0,188},{0,158},{0,241},{2,1},{0,31},{2,1},{0,15},{0,47},{66,1},{56,1}, - {2,1},{0,242},{52,1},{50,1},{20,1},{8,1},{2,1},{0,189},{2,1},{0,94}, - {2,1},{0,125},{0,201},{6,1},{2,1},{0,202},{2,1},{0,172},{0,126},{4,1}, - {2,1},{0,218},{0,173},{0,204},{10,1},{6,1},{2,1},{0,174},{2,1},{0,219}, - {0,220},{2,1},{0,205},{0,190},{6,1},{4,1},{2,1},{0,235},{0,237},{0,238}, - {6,1},{4,1},{2,1},{0,217},{0,234},{0,233},{2,1},{0,222},{4,1},{2,1}, - {0,221},{0,236},{0,206},{0,63},{0,240},{4,1},{2,1},{0,243},{0,244},{2,1}, - {0,79},{2,1},{0,245},{0,95},{10,1},{2,1},{0,255},{4,1},{2,1},{0,246}, - {0,111},{2,1},{0,247},{0,127},{12,1},{6,1},{2,1},{0,143},{2,1},{0,248}, - {0,249},{4,1},{2,1},{0,159},{0,250},{0,175},{8,1},{4,1},{2,1},{0,251}, - {0,191},{2,1},{0,252},{0,207},{4,1},{2,1},{0,253},{0,223},{2,1},{0,254}, - {0,239}, - }; - - private static int ValTab24[][] = { - {60,1},{8,1},{4,1},{2,1},{0,0},{0,16},{2,1},{0,1},{0,17},{14,1}, - {6,1},{4,1},{2,1},{0,32},{0,2},{0,33},{2,1},{0,18},{2,1},{0,34}, - {2,1},{0,48},{0,3},{14,1},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1}, - {0,50},{0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{8,1},{4,1},{2,1}, - {0,20},{0,51},{2,1},{0,66},{0,36},{6,1},{4,1},{2,1},{0,67},{0,52}, - {0,81},{6,1},{4,1},{2,1},{0,80},{0,5},{0,21},{2,1},{0,82},{0,37}, - {250,1},{98,1},{34,1},{18,1},{10,1},{4,1},{2,1},{0,68},{0,83},{2,1}, - {0,53},{2,1},{0,96},{0,6},{4,1},{2,1},{0,97},{0,22},{2,1},{0,98}, - {0,38},{8,1},{4,1},{2,1},{0,84},{0,69},{2,1},{0,99},{0,54},{4,1}, - {2,1},{0,113},{0,85},{2,1},{0,100},{0,70},{32,1},{14,1},{6,1},{2,1}, - {0,114},{2,1},{0,39},{0,55},{2,1},{0,115},{4,1},{2,1},{0,112},{0,7}, - {0,23},{10,1},{4,1},{2,1},{0,101},{0,86},{4,1},{2,1},{0,128},{0,8}, - {0,129},{4,1},{2,1},{0,116},{0,71},{2,1},{0,24},{0,130},{16,1},{8,1}, - {4,1},{2,1},{0,40},{0,102},{2,1},{0,131},{0,56},{4,1},{2,1},{0,117}, - {0,87},{2,1},{0,132},{0,72},{8,1},{4,1},{2,1},{0,145},{0,25},{2,1}, - {0,146},{0,118},{4,1},{2,1},{0,103},{0,41},{2,1},{0,133},{0,88},{92,1}, - {34,1},{16,1},{8,1},{4,1},{2,1},{0,147},{0,57},{2,1},{0,148},{0,73}, - {4,1},{2,1},{0,119},{0,134},{2,1},{0,104},{0,161},{8,1},{4,1},{2,1}, - {0,162},{0,42},{2,1},{0,149},{0,89},{4,1},{2,1},{0,163},{0,58},{2,1}, - {0,135},{2,1},{0,120},{0,74},{22,1},{12,1},{4,1},{2,1},{0,164},{0,150}, - {4,1},{2,1},{0,105},{0,177},{2,1},{0,27},{0,165},{6,1},{2,1},{0,178}, - {2,1},{0,90},{0,43},{2,1},{0,136},{0,179},{16,1},{10,1},{6,1},{2,1}, - {0,144},{2,1},{0,9},{0,160},{2,1},{0,151},{0,121},{4,1},{2,1},{0,166}, - {0,106},{0,180},{12,1},{6,1},{2,1},{0,26},{2,1},{0,10},{0,176},{2,1}, - {0,59},{2,1},{0,11},{0,192},{4,1},{2,1},{0,75},{0,193},{2,1},{0,152}, - {0,137},{67,1},{34,1},{16,1},{8,1},{4,1},{2,1},{0,28},{0,181},{2,1}, - {0,91},{0,194},{4,1},{2,1},{0,44},{0,167},{2,1},{0,122},{0,195},{10,1}, - {6,1},{2,1},{0,60},{2,1},{0,12},{0,208},{2,1},{0,182},{0,107},{4,1}, - {2,1},{0,196},{0,76},{2,1},{0,153},{0,168},{16,1},{8,1},{4,1},{2,1}, - {0,138},{0,197},{2,1},{0,92},{0,209},{4,1},{2,1},{0,183},{0,123},{2,1}, - {0,29},{0,210},{9,1},{4,1},{2,1},{0,45},{0,211},{2,1},{0,61},{0,198}, - {85,250},{4,1},{2,1},{0,108},{0,169},{2,1},{0,154},{0,212},{32,1},{16,1}, - {8,1},{4,1},{2,1},{0,184},{0,139},{2,1},{0,77},{0,199},{4,1},{2,1}, - {0,124},{0,213},{2,1},{0,93},{0,225},{8,1},{4,1},{2,1},{0,30},{0,226}, - {2,1},{0,170},{0,185},{4,1},{2,1},{0,155},{0,227},{2,1},{0,214},{0,109}, - {20,1},{10,1},{6,1},{2,1},{0,62},{2,1},{0,46},{0,78},{2,1},{0,200}, - {0,140},{4,1},{2,1},{0,228},{0,215},{4,1},{2,1},{0,125},{0,171},{0,229}, - {10,1},{4,1},{2,1},{0,186},{0,94},{2,1},{0,201},{2,1},{0,156},{0,110}, - {8,1},{2,1},{0,230},{2,1},{0,13},{2,1},{0,224},{0,14},{4,1},{2,1}, - {0,216},{0,141},{2,1},{0,187},{0,202},{74,1},{2,1},{0,255},{64,1},{58,1}, - {32,1},{16,1},{8,1},{4,1},{2,1},{0,172},{0,231},{2,1},{0,126},{0,217}, - {4,1},{2,1},{0,157},{0,232},{2,1},{0,142},{0,203},{8,1},{4,1},{2,1}, - {0,188},{0,218},{2,1},{0,173},{0,233},{4,1},{2,1},{0,158},{0,204},{2,1}, - {0,219},{0,189},{16,1},{8,1},{4,1},{2,1},{0,234},{0,174},{2,1},{0,220}, - {0,205},{4,1},{2,1},{0,235},{0,190},{2,1},{0,221},{0,236},{8,1},{4,1}, - {2,1},{0,206},{0,237},{2,1},{0,222},{0,238},{0,15},{4,1},{2,1},{0,240}, - {0,31},{0,241},{4,1},{2,1},{0,242},{0,47},{2,1},{0,243},{0,63},{18,1}, - {8,1},{4,1},{2,1},{0,244},{0,79},{2,1},{0,245},{0,95},{4,1},{2,1}, - {0,246},{0,111},{2,1},{0,247},{2,1},{0,127},{0,143},{10,1},{4,1},{2,1}, - {0,248},{0,249},{4,1},{2,1},{0,159},{0,175},{0,250},{8,1},{4,1},{2,1}, - {0,251},{0,191},{2,1},{0,252},{0,207},{4,1},{2,1},{0,253},{0,223},{2,1}, - {0,254},{0,239}, - }; - - private static int ValTab32[][] = { - {2,1},{0,0},{8,1},{4,1},{2,1},{0,8},{0,4},{2,1},{0,1},{0,2}, - {8,1},{4,1},{2,1},{0,12},{0,10},{2,1},{0,3},{0,6},{6,1},{2,1}, - {0,9},{2,1},{0,5},{0,7},{4,1},{2,1},{0,14},{0,13},{2,1},{0,15}, - {0,11}, - }; - - private static int ValTab33[][] = { - {16,1},{8,1},{4,1},{2,1},{0,0},{0,1},{2,1},{0,2},{0,3},{4,1}, - {2,1},{0,4},{0,5},{2,1},{0,6},{0,7},{8,1},{4,1},{2,1},{0,8}, - {0,9},{2,1},{0,10},{0,11},{4,1},{2,1},{0,12},{0,13},{2,1},{0,14}, - {0,15}, - }; - - - public static huffcodetab[] ht = null; /* Simulate extern struct */ - - @SuppressWarnings("unused") - private static int[] bitbuf = new int[32]; - - /** - * Big Constructor : Computes all Huffman Tables. - */ - private huffcodetab(String S,int XLEN, int YLEN, int LINBITS, int LINMAX, int REF, - int[] TABLE, int[] HLEN, int[][] VAL, int TREELEN) - { - tablename0 = S.charAt(0); - tablename1 = S.charAt(1); - //tablename2 = S.charAt(2); - xlen = XLEN; - ylen = YLEN; - linbits = LINBITS; - //linmax = LINMAX; - //ref = REF; - //table = TABLE; - //hlen = HLEN; - val = VAL; - treelen = TREELEN; - } - - - - /** - * Do the huffman-decoding. - * note! for counta,countb -the 4 bit value is returned in y, - * discard x. - */ - public static int huffman_decoder(huffcodetab h, int[] x, int[] y, int[] v, int[] w, BitReserve br) - { - // array of all huffcodtable headers - // 0..31 Huffman code table 0..31 - // 32,33 count1-tables - - int dmask = 1 << ((4 * 8) - 1); - @SuppressWarnings("unused") - int hs = 4 * 8; - int level; - int point = 0; - int error = 1; - level = dmask; - - if (h.val == null) return 2; - - /* table 0 needs no bits */ - if ( h.treelen == 0) - { - x[0] = y[0] = 0; - return 0; - } - - /* Lookup in Huffman table. */ - - /*int bitsAvailable = 0; - int bitIndex = 0; - - int bits[] = bitbuf;*/ - do - { - if (h.val[point][0]==0) - { /*end of tree*/ - x[0] = h.val[point][1] >>> 4; - y[0] = h.val[point][1] & 0xf; - error = 0; - break; - } - - // hget1bit() is called thousands of times, and so needs to be - // ultra fast. - /* - if (bitIndex==bitsAvailable) - { - bitsAvailable = br.readBits(bits, 32); - bitIndex = 0; - } - */ - //if (bits[bitIndex++]!=0) - if (br.hget1bit()!=0) - { - while (h.val[point][1] >= MXOFF) point += h.val[point][1]; - point += h.val[point][1]; - } - else - { - while (h.val[point][0] >= MXOFF) point += h.val[point][0]; - point += h.val[point][0]; - } - level >>>= 1; - // MDM: ht[0] is always 0; - } while ((level !=0 ) || (point < 0 /*ht[0].treelen*/) ); - - // put back any bits not consumed - /* - int unread = (bitsAvailable-bitIndex); - if (unread>0) - br.rewindNbits(unread); - */ - /* Process sign encodings for quadruples tables. */ - // System.out.println(h.tablename); - if (h.tablename0 == '3' && (h.tablename1 == '2' || h.tablename1 == '3')) - { - v[0] = (y[0]>>3) & 1; - w[0] = (y[0]>>2) & 1; - x[0] = (y[0]>>1) & 1; - y[0] = y[0] & 1; - - /* v, w, x and y are reversed in the bitstream. - switch them around to make test bistream work. */ - - if (v[0]!=0) - if (br.hget1bit() != 0) v[0] = -v[0]; - if (w[0]!=0) - if (br.hget1bit() != 0) w[0] = -w[0]; - if (x[0]!=0) - if (br.hget1bit() != 0) x[0] = -x[0]; - if (y[0]!=0) - if (br.hget1bit() != 0) y[0] = -y[0]; - } - else - { - // Process sign and escape encodings for dual tables. - // x and y are reversed in the test bitstream. - // Reverse x and y here to make test bitstream work. - - if (h.linbits != 0) - if ((h.xlen-1) == x[0]) - x[0] += br.hgetbits(h.linbits); - if (x[0] != 0) - if (br.hget1bit() != 0) x[0] = -x[0]; - if (h.linbits != 0) - if ((h.ylen-1) == y[0]) - y[0] += br.hgetbits(h.linbits); - if (y[0] != 0) - if (br.hget1bit() != 0) y[0] = -y[0]; - } - return error; - } - - public static void inithuff() - { - - if (ht!=null) - return; - - ht = new huffcodetab[HTN]; - ht[0] = new huffcodetab("0 ",0,0,0,0,-1,null,null,ValTab0,0); - ht[1] = new huffcodetab("1 ",2,2,0,0,-1,null,null,ValTab1,7); - ht[2] = new huffcodetab("2 ",3,3,0,0,-1,null,null,ValTab2,17); - ht[3] = new huffcodetab("3 ",3,3,0,0,-1,null,null,ValTab3,17); - ht[4] = new huffcodetab("4 ",0,0,0,0,-1,null,null,ValTab4,0); - ht[5] = new huffcodetab("5 ",4,4,0,0,-1,null,null,ValTab5,31); - ht[6] = new huffcodetab("6 ",4,4,0,0,-1,null,null,ValTab6,31); - ht[7] = new huffcodetab("7 ",6,6,0,0,-1,null,null,ValTab7,71); - ht[8] = new huffcodetab("8 ",6,6,0,0,-1,null,null,ValTab8,71); - ht[9] = new huffcodetab("9 ",6,6,0,0,-1,null,null,ValTab9,71); - ht[10] = new huffcodetab("10 ",8,8,0,0,-1,null,null,ValTab10,127); - ht[11] = new huffcodetab("11 ",8,8,0,0,-1,null,null,ValTab11,127); - ht[12] = new huffcodetab("12 ",8,8,0,0,-1,null,null,ValTab12,127); - ht[13] = new huffcodetab("13 ",16,16,0,0,-1,null,null,ValTab13,511); - ht[14] = new huffcodetab("14 ",0,0,0,0,-1,null,null,ValTab14,0); - ht[15] = new huffcodetab("15 ",16,16,0,0,-1,null,null,ValTab15,511); - ht[16] = new huffcodetab("16 ",16,16,1,1,-1,null,null,ValTab16,511); - ht[17] = new huffcodetab("17 ",16,16,2,3,16,null,null,ValTab16,511); - ht[18] = new huffcodetab("18 ",16,16,3,7,16,null,null,ValTab16,511); - ht[19] = new huffcodetab("19 ",16,16,4,15,16,null,null,ValTab16,511); - ht[20] = new huffcodetab("20 ",16,16,6,63,16,null,null,ValTab16,511); - ht[21] = new huffcodetab("21 ",16,16,8,255,16,null,null,ValTab16,511); - ht[22] = new huffcodetab("22 ",16,16,10,1023,16,null,null,ValTab16,511); - ht[23] = new huffcodetab("23 ",16,16,13,8191,16,null,null,ValTab16,511); - ht[24] = new huffcodetab("24 ",16,16,4,15,-1,null,null,ValTab24,512); - ht[25] = new huffcodetab("25 ",16,16,5,31,24,null,null,ValTab24,512); - ht[26] = new huffcodetab("26 ",16,16,6,63,24,null,null,ValTab24,512); - ht[27] = new huffcodetab("27 ",16,16,7,127,24,null,null,ValTab24,512); - ht[28] = new huffcodetab("28 ",16,16,8,255,24,null,null,ValTab24,512); - ht[29] = new huffcodetab("29 ",16,16,9,511,24,null,null,ValTab24,512); - ht[30] = new huffcodetab("30 ",16,16,11,2047,24,null,null,ValTab24,512); - ht[31] = new huffcodetab("31 ",16,16,13,8191,24,null,null,ValTab24,512); - ht[32] = new huffcodetab("32 ",1,16,0,0,-1,null,null,ValTab32,31); - ht[33] = new huffcodetab("33 ",1,16,0,0,-1,null,null,ValTab33,31); - } -} diff --git a/src/javazoom/jl/decoder/l3reorder.ser b/src/javazoom/jl/decoder/l3reorder.ser deleted file mode 100644 index da216fcf469620b74fadec2ab33eb91cc99572d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13925 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�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 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