summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichiel Van Der Kolk <not.valid@email.address>2005-07-11 15:42:37 +0000
committerMichiel Van Der Kolk <not.valid@email.address>2005-07-11 15:42:37 +0000
commit9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e (patch)
tree4c304cd4151020bd5494d279ee68a105ae3a5a3a
parentdfa8ecbe609ca8ea194d08560a44fb9a92e94b4b (diff)
downloadrockbox-9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e.tar.gz
rockbox-9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e.zip
Songdb java version, source. only 1.5 compatible
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7101 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--songdbj/AlbumEntry.java76
-rw-r--r--songdbj/ArtistEntry.java56
-rw-r--r--songdbj/Entry.java14
-rw-r--r--songdbj/FileEntry.java155
-rw-r--r--songdbj/MpegInfo.java367
-rw-r--r--songdbj/OggVorbisInfo.java311
-rw-r--r--songdbj/RundbEntry.java28
-rw-r--r--songdbj/RuntimeDatabase.java81
-rw-r--r--songdbj/SongDB.java74
-rw-r--r--songdbj/SongEntry.java167
-rw-r--r--songdbj/TagDatabase.java377
-rw-r--r--songdbj/TagInfo.java112
-rwxr-xr-xsongdbj/build.sh2
-rw-r--r--songdbj/classes/META-INF/MANIFEST.MF4
-rw-r--r--songdbj/classes/META-INF/services/javax.sound.sampled.spi.AudioFileReader4
-rw-r--r--songdbj/classes/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider3
-rw-r--r--songdbj/com/jcraft/jogg/Buffer.java541
-rw-r--r--songdbj/com/jcraft/jogg/Packet.java82
-rw-r--r--songdbj/com/jcraft/jogg/Page.java973
-rw-r--r--songdbj/com/jcraft/jogg/StreamState.java657
-rw-r--r--songdbj/com/jcraft/jogg/SyncState.java275
-rw-r--r--songdbj/com/jcraft/jorbis/AllocChain.java31
-rw-r--r--songdbj/com/jcraft/jorbis/Block.java188
-rw-r--r--songdbj/com/jcraft/jorbis/ChainingExample.java61
-rw-r--r--songdbj/com/jcraft/jorbis/CodeBook.java742
-rw-r--r--songdbj/com/jcraft/jorbis/Comment.java252
-rw-r--r--songdbj/com/jcraft/jorbis/DecodeExample.java316
-rw-r--r--songdbj/com/jcraft/jorbis/Drft.java1317
-rw-r--r--songdbj/com/jcraft/jorbis/DspState.java459
-rw-r--r--songdbj/com/jcraft/jorbis/EncodeAuxNearestMatch.java36
-rw-r--r--songdbj/com/jcraft/jorbis/EncodeAuxThreshMatch.java33
-rw-r--r--songdbj/com/jcraft/jorbis/Floor0.java352
-rw-r--r--songdbj/com/jcraft/jorbis/Floor1.java653
-rw-r--r--songdbj/com/jcraft/jorbis/FuncFloor.java45
-rw-r--r--songdbj/com/jcraft/jorbis/FuncMapping.java40
-rw-r--r--songdbj/com/jcraft/jorbis/FuncResidue.java43
-rw-r--r--songdbj/com/jcraft/jorbis/FuncTime.java40
-rw-r--r--songdbj/com/jcraft/jorbis/Info.java516
-rw-r--r--songdbj/com/jcraft/jorbis/InfoMode.java33
-rw-r--r--songdbj/com/jcraft/jorbis/JOrbisException.java35
-rw-r--r--songdbj/com/jcraft/jorbis/Lookup.java154
-rw-r--r--songdbj/com/jcraft/jorbis/Lpc.java254
-rw-r--r--songdbj/com/jcraft/jorbis/Lsp.java111
-rw-r--r--songdbj/com/jcraft/jorbis/Mapping0.java566
-rw-r--r--songdbj/com/jcraft/jorbis/Mdct.java249
-rw-r--r--songdbj/com/jcraft/jorbis/PsyInfo.java72
-rw-r--r--songdbj/com/jcraft/jorbis/PsyLook.java187
-rw-r--r--songdbj/com/jcraft/jorbis/Residue0.java454
-rw-r--r--songdbj/com/jcraft/jorbis/Residue1.java51
-rw-r--r--songdbj/com/jcraft/jorbis/Residue2.java44
-rw-r--r--songdbj/com/jcraft/jorbis/StaticCodeBook.java588
-rw-r--r--songdbj/com/jcraft/jorbis/Time0.java38
-rw-r--r--songdbj/com/jcraft/jorbis/VorbisFile.java1361
-rw-r--r--songdbj/com/jcraft/jorbis/VorbisFile.java.new1240
-rw-r--r--songdbj/de/jarnbjo/ogg/BasicStream.java121
-rw-r--r--songdbj/de/jarnbjo/ogg/CachedUrlStream.java252
-rw-r--r--songdbj/de/jarnbjo/ogg/EndOfOggStreamException.java45
-rw-r--r--songdbj/de/jarnbjo/ogg/FileStream.java154
-rw-r--r--songdbj/de/jarnbjo/ogg/LogicalOggStream.java151
-rw-r--r--songdbj/de/jarnbjo/ogg/LogicalOggStreamImpl.java213
-rw-r--r--songdbj/de/jarnbjo/ogg/OggFormatException.java50
-rw-r--r--songdbj/de/jarnbjo/ogg/OggPage.java431
-rw-r--r--songdbj/de/jarnbjo/ogg/OnDemandUrlStream.java127
-rw-r--r--songdbj/de/jarnbjo/ogg/PhysicalOggStream.java124
-rw-r--r--songdbj/de/jarnbjo/ogg/UncachedUrlStream.java207
-rw-r--r--songdbj/de/jarnbjo/util/audio/FadeableAudioInputStream.java62
-rw-r--r--songdbj/de/jarnbjo/util/io/BitInputStream.java185
-rw-r--r--songdbj/de/jarnbjo/util/io/ByteArrayBitInputStream.java352
-rw-r--r--songdbj/de/jarnbjo/util/io/HuffmanNode.java144
-rw-r--r--songdbj/de/jarnbjo/vorbis/AudioPacket.java328
-rw-r--r--songdbj/de/jarnbjo/vorbis/CodeBook.java275
-rw-r--r--songdbj/de/jarnbjo/vorbis/CommentHeader.java244
-rw-r--r--songdbj/de/jarnbjo/vorbis/Floor.java124
-rw-r--r--songdbj/de/jarnbjo/vorbis/Floor0.java74
-rw-r--r--songdbj/de/jarnbjo/vorbis/Floor1.java324
-rw-r--r--songdbj/de/jarnbjo/vorbis/IdentificationHeader.java120
-rw-r--r--songdbj/de/jarnbjo/vorbis/Mapping.java59
-rw-r--r--songdbj/de/jarnbjo/vorbis/Mapping0.java146
-rw-r--r--songdbj/de/jarnbjo/vorbis/MdctFloat.java321
-rw-r--r--songdbj/de/jarnbjo/vorbis/Mode.java75
-rw-r--r--songdbj/de/jarnbjo/vorbis/Residue.java260
-rw-r--r--songdbj/de/jarnbjo/vorbis/Residue0.java53
-rw-r--r--songdbj/de/jarnbjo/vorbis/Residue1.java55
-rw-r--r--songdbj/de/jarnbjo/vorbis/Residue2.java123
-rw-r--r--songdbj/de/jarnbjo/vorbis/SetupHeader.java131
-rw-r--r--songdbj/de/jarnbjo/vorbis/Util.java127
-rw-r--r--songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java217
-rw-r--r--songdbj/de/jarnbjo/vorbis/VorbisFormatException.java51
-rw-r--r--songdbj/de/jarnbjo/vorbis/VorbisStream.java247
-rw-r--r--songdbj/entagged/audioformats/AudioFile.java186
-rw-r--r--songdbj/entagged/audioformats/EncodingInfo.java116
-rw-r--r--songdbj/entagged/audioformats/Tag.java116
-rw-r--r--songdbj/entagged/audioformats/asf/AsfFileReader.java112
-rw-r--r--songdbj/entagged/audioformats/asf/data/AsfHeader.java279
-rw-r--r--songdbj/entagged/audioformats/asf/data/AudioStreamChunk.java292
-rw-r--r--songdbj/entagged/audioformats/asf/data/Chunk.java135
-rw-r--r--songdbj/entagged/audioformats/asf/data/ContentDescription.java251
-rw-r--r--songdbj/entagged/audioformats/asf/data/ContentDescriptor.java517
-rw-r--r--songdbj/entagged/audioformats/asf/data/EncodingChunk.java95
-rw-r--r--songdbj/entagged/audioformats/asf/data/ExtendedContentDescription.java299
-rw-r--r--songdbj/entagged/audioformats/asf/data/FileHeader.java235
-rw-r--r--songdbj/entagged/audioformats/asf/data/GUID.java329
-rw-r--r--songdbj/entagged/audioformats/asf/data/StreamChunk.java173
-rw-r--r--songdbj/entagged/audioformats/asf/data/VideoStreamChunk.java98
-rw-r--r--songdbj/entagged/audioformats/asf/data/wrapper/ContentDescriptorTagField.java130
-rw-r--r--songdbj/entagged/audioformats/asf/io/AsfHeaderReader.java178
-rw-r--r--songdbj/entagged/audioformats/asf/io/ChunkHeaderReader.java57
-rw-r--r--songdbj/entagged/audioformats/asf/io/ContentDescriptionReader.java175
-rw-r--r--songdbj/entagged/audioformats/asf/io/EncodingChunkReader.java118
-rw-r--r--songdbj/entagged/audioformats/asf/io/ExtContentDescReader.java182
-rw-r--r--songdbj/entagged/audioformats/asf/io/FileHeaderReader.java116
-rw-r--r--songdbj/entagged/audioformats/asf/io/StreamChunkReader.java187
-rw-r--r--songdbj/entagged/audioformats/asf/util/ChunkPositionComparator.java52
-rw-r--r--songdbj/entagged/audioformats/asf/util/TagConverter.java234
-rw-r--r--songdbj/entagged/audioformats/asf/util/Utils.java306
-rw-r--r--songdbj/entagged/audioformats/exceptions/CannotReadException.java33
-rw-r--r--songdbj/entagged/audioformats/exceptions/CannotWriteException.java33
-rw-r--r--songdbj/entagged/audioformats/generic/AbstractTag.java308
-rw-r--r--songdbj/entagged/audioformats/generic/AbstractTagCreator.java66
-rw-r--r--songdbj/entagged/audioformats/generic/AudioFileReader.java126
-rw-r--r--songdbj/entagged/audioformats/generic/GenericTag.java133
-rw-r--r--songdbj/entagged/audioformats/generic/OldTag.java382
-rw-r--r--songdbj/entagged/audioformats/generic/TagField.java43
-rw-r--r--songdbj/entagged/audioformats/generic/TagTextField.java33
-rw-r--r--songdbj/entagged/audioformats/generic/Utils.java95
-rw-r--r--songdbj/javazoom/jl/converter/Converter.java411
-rw-r--r--songdbj/javazoom/jl/converter/RiffFile.java495
-rw-r--r--songdbj/javazoom/jl/converter/WaveFile.java522
-rw-r--r--songdbj/javazoom/jl/converter/WaveFileObuffer.java141
-rw-r--r--songdbj/javazoom/jl/converter/jlc.java216
-rw-r--r--songdbj/javazoom/jl/decoder/BitReserve.java223
-rw-r--r--songdbj/javazoom/jl/decoder/Bitstream.java655
-rw-r--r--songdbj/javazoom/jl/decoder/BitstreamErrors.java72
-rw-r--r--songdbj/javazoom/jl/decoder/BitstreamException.java71
-rw-r--r--songdbj/javazoom/jl/decoder/Control.java57
-rw-r--r--songdbj/javazoom/jl/decoder/Crc16.java70
-rw-r--r--songdbj/javazoom/jl/decoder/Decoder.java357
-rw-r--r--songdbj/javazoom/jl/decoder/DecoderErrors.java38
-rw-r--r--songdbj/javazoom/jl/decoder/DecoderException.java61
-rw-r--r--songdbj/javazoom/jl/decoder/Equalizer.java227
-rw-r--r--songdbj/javazoom/jl/decoder/FrameDecoder.java38
-rw-r--r--songdbj/javazoom/jl/decoder/Header.java762
-rw-r--r--songdbj/javazoom/jl/decoder/InputStreamSource.java80
-rw-r--r--songdbj/javazoom/jl/decoder/JavaLayerError.java31
-rw-r--r--songdbj/javazoom/jl/decoder/JavaLayerErrors.java40
-rw-r--r--songdbj/javazoom/jl/decoder/JavaLayerException.java80
-rw-r--r--songdbj/javazoom/jl/decoder/JavaLayerHook.java36
-rw-r--r--songdbj/javazoom/jl/decoder/JavaLayerUtils.java207
-rw-r--r--songdbj/javazoom/jl/decoder/LayerIDecoder.java444
-rw-r--r--songdbj/javazoom/jl/decoder/LayerIIDecoder.java1064
-rw-r--r--songdbj/javazoom/jl/decoder/LayerIIIDecoder.java2439
-rw-r--r--songdbj/javazoom/jl/decoder/Manager.java46
-rw-r--r--songdbj/javazoom/jl/decoder/Obuffer.java88
-rw-r--r--songdbj/javazoom/jl/decoder/OutputChannels.java143
-rw-r--r--songdbj/javazoom/jl/decoder/SampleBuffer.java132
-rw-r--r--songdbj/javazoom/jl/decoder/Source.java49
-rw-r--r--songdbj/javazoom/jl/decoder/SynthesisFilter.java1817
-rw-r--r--songdbj/javazoom/jl/decoder/au2lin.serbin0 -> 539 bytes
-rw-r--r--songdbj/javazoom/jl/decoder/huffcodetab.java600
-rw-r--r--songdbj/javazoom/jl/decoder/l3reorder.serbin0 -> 13925 bytes
-rw-r--r--songdbj/javazoom/jl/decoder/lin2au.serbin0 -> 16411 bytes
-rw-r--r--songdbj/javazoom/jl/decoder/readme.txt15
-rw-r--r--songdbj/javazoom/jl/decoder/sfd.serbin0 -> 2075 bytes
-rw-r--r--songdbj/javazoom/jl/player/AudioDevice.java103
-rw-r--r--songdbj/javazoom/jl/player/AudioDeviceBase.java177
-rw-r--r--songdbj/javazoom/jl/player/AudioDeviceFactory.java87
-rw-r--r--songdbj/javazoom/jl/player/FactoryRegistry.java129
-rw-r--r--songdbj/javazoom/jl/player/JavaSoundAudioDevice.java215
-rw-r--r--songdbj/javazoom/jl/player/JavaSoundAudioDeviceFactory.java85
-rw-r--r--songdbj/javazoom/jl/player/NullAudioDevice.java37
-rw-r--r--songdbj/javazoom/jl/player/Player.java251
-rw-r--r--songdbj/javazoom/jl/player/PlayerApplet.java246
-rw-r--r--songdbj/javazoom/jl/player/advanced/AdvancedPlayer.java242
-rw-r--r--songdbj/javazoom/jl/player/advanced/PlaybackEvent.java51
-rw-r--r--songdbj/javazoom/jl/player/advanced/PlaybackListener.java30
-rw-r--r--songdbj/javazoom/jl/player/advanced/jlap.java116
-rw-r--r--songdbj/javazoom/jl/player/jlp.java176
-rw-r--r--songdbj/javazoom/spi/PropertiesContainer.java31
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java334
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/convert/MpegFormatConversionProvider.java120
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/IcyListener.java131
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileFormat.java103
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileReader.java772
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFormat.java67
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/MpegEncoding.java47
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/MpegFileFormatType.java40
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyInputStream.java412
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyTag.java42
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3MetadataParser.java50
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3Tag.java52
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3TagParseSupport.java62
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/StringableTag.java36
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseEvent.java44
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseListener.java37
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java519
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java244
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileFormat.java85
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileReader.java502
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFormat.java66
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/file/VorbisEncoding.java41
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/file/VorbisFileFormatType.java41
-rw-r--r--songdbj/net/shredzone/ifish/ltr/FormatDecodeException.java66
-rw-r--r--songdbj/net/shredzone/ifish/ltr/LTR.java251
-rw-r--r--songdbj/net/shredzone/ifish/ltr/LTRmp3.java165
-rw-r--r--songdbj/net/shredzone/ifish/ltr/OggFastFileStream.java249
-rw-r--r--songdbj/net/shredzone/ifish/ltr/TagAsf.java170
-rw-r--r--songdbj/net/shredzone/ifish/ltr/TagMp3v1.java184
-rw-r--r--songdbj/net/shredzone/ifish/ltr/TagMp3v2.java441
-rw-r--r--songdbj/net/shredzone/ifish/ltr/TagMp3v200.java373
-rw-r--r--songdbj/net/shredzone/ifish/ltr/TagOggVorbis.java207
-rw-r--r--songdbj/org/tritonus/file/AiffAudioFileReader.java244
-rw-r--r--songdbj/org/tritonus/file/AiffAudioFileWriter.java104
-rw-r--r--songdbj/org/tritonus/file/AiffAudioOutputStream.java205
-rw-r--r--songdbj/org/tritonus/file/AiffTool.java82
-rw-r--r--songdbj/org/tritonus/file/AuAudioFileReader.java185
-rw-r--r--songdbj/org/tritonus/file/AuAudioFileWriter.java104
-rw-r--r--songdbj/org/tritonus/file/AuAudioOutputStream.java121
-rw-r--r--songdbj/org/tritonus/file/AuTool.java95
-rw-r--r--songdbj/org/tritonus/file/WaveAudioFileReader.java300
-rw-r--r--songdbj/org/tritonus/file/WaveAudioFileWriter.java103
-rw-r--r--songdbj/org/tritonus/file/WaveAudioOutputStream.java201
-rw-r--r--songdbj/org/tritonus/file/WaveTool.java115
-rw-r--r--songdbj/org/tritonus/file/gsm/GSMAudioFileReader.java142
-rw-r--r--songdbj/org/tritonus/file/gsm/GSMAudioFileWriter.java77
-rw-r--r--songdbj/org/tritonus/file/gsm/package.html10
-rw-r--r--songdbj/org/tritonus/file/jorbis/JorbisAudioFileReader.java231
-rw-r--r--songdbj/org/tritonus/file/jorbis/package.html10
-rw-r--r--songdbj/org/tritonus/file/mpeg/MpegAudioFileWriter.java75
-rw-r--r--songdbj/org/tritonus/file/mpeg/package.html10
-rw-r--r--songdbj/org/tritonus/file/package.html10
-rw-r--r--songdbj/org/tritonus/file/pvorbis/VorbisAudioFileReader.java302
-rw-r--r--songdbj/org/tritonus/file/pvorbis/VorbisAudioFileWriter.java75
-rw-r--r--songdbj/org/tritonus/file/pvorbis/package.html12
-rw-r--r--songdbj/org/tritonus/file/vorbis/VorbisAudioFileReader.java302
-rw-r--r--songdbj/org/tritonus/file/vorbis/VorbisAudioFileWriter.java75
-rw-r--r--songdbj/org/tritonus/file/vorbis/package.html12
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/Buffer.java173
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/Ogg.java104
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/Packet.java113
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/Page.java131
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/StreamState.java143
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/SyncState.java127
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/package.html12
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/Buffer.java284
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/Ogg.java104
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/Packet.java133
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/Page.java298
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/StreamState.java703
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/SyncState.java339
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/package.html12
-rw-r--r--songdbj/org/tritonus/share/ArraySet.java87
-rw-r--r--songdbj/org/tritonus/share/GlobalInfo.java60
-rw-r--r--songdbj/org/tritonus/share/StringHashedSet.java112
-rw-r--r--songdbj/org/tritonus/share/TCircularBuffer.java268
-rw-r--r--songdbj/org/tritonus/share/TDebug.java192
-rw-r--r--songdbj/org/tritonus/share/TNotifier.java140
-rw-r--r--songdbj/org/tritonus/share/TSettings.java75
-rw-r--r--songdbj/org/tritonus/share/package.html10
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioFileTypes.java155
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioFormatSet.java155
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioFormats.java131
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioSystemShadow.java115
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioUtils.java181
-rw-r--r--songdbj/org/tritonus/share/sampled/Encodings.java183
-rw-r--r--songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java734
-rw-r--r--songdbj/org/tritonus/share/sampled/FloatSampleTools.java696
-rw-r--r--songdbj/org/tritonus/share/sampled/TAudioFormat.java110
-rw-r--r--songdbj/org/tritonus/share/sampled/TConversionTool.java1224
-rw-r--r--songdbj/org/tritonus/share/sampled/TVolumeUtils.java55
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java256
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java120
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java129
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java170
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java182
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java367
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java271
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/package.html17
-rw-r--r--songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java113
-rw-r--r--songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java58
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java113
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java510
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java484
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java197
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java79
-rw-r--r--songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java84
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java109
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java86
-rw-r--r--songdbj/org/tritonus/share/sampled/file/package.html18
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java107
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java128
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TClip.java340
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java90
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java55
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TControlController.java98
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TControllable.java62
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TDataLine.java304
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java92
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java134
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TLine.java362
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TMixer.java506
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java56
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java240
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TPort.java77
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java318
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/package.html14
-rw-r--r--songdbj/org/tritonus/share/sampled/package.html10
306 files changed, 63685 insertions, 0 deletions
diff --git a/songdbj/AlbumEntry.java b/songdbj/AlbumEntry.java
new file mode 100644
index 0000000000..14c209547b
--- /dev/null
+++ b/songdbj/AlbumEntry.java
@@ -0,0 +1,76 @@
+import java.util.*;
+import java.io.*;
+
+public class AlbumEntry extends Entry implements Comparable {
+ protected String name;
+ protected ArtistEntry artist;
+ protected Vector songs;
+ protected int songcount;
+
+ public AlbumEntry(String n) {
+ name=n;
+ songs=new Vector();
+ artist=null;
+ songcount=0;
+ }
+
+ protected class SongSorter implements Comparator {
+ public int compare(Object o1, Object o2) {
+ SongEntry s1=(SongEntry)o1;
+ SongEntry s2=(SongEntry)o2;
+ int track1=s1.getTrack(),track2=s2.getTrack();
+ if(track1>track2)
+ return 1;
+ else if(track1<track2)
+ return -1;
+ return s1.getFile().getFile().getName().compareTo(s2.getFile().getFile().getName());
+ }
+ }
+
+ public void addSong(SongEntry e) {
+ songs.add(e);
+ e.setAlbum(this);
+ e.setArtist(artist);
+ songcount++;
+ Collections.sort(songs,new SongSorter());
+ }
+
+ public int size() { return songcount; }
+ public void setArtist(ArtistEntry a) {
+ a.addAlbum(this);
+ if(artist!=null&&artist!=a&&!artist.getName().equals("<various artists>")) {
+ artist.removeAlbum(this);
+ artist=TagDatabase.getInstance().getArtistEntry("<various artists>");
+ }
+ else
+ artist=a;
+ }
+ public ArtistEntry getArtist() { return artist; }
+
+ public int compareTo(Object o) {
+ return String.CASE_INSENSITIVE_ORDER.compare(name,((AlbumEntry)o).getName());
+ }
+
+ public String getName() { return name; }
+ public Collection getSongs() { return songs; }
+ public void write(DataOutputStream w) throws IOException {
+ int x;
+ w.writeBytes(name);
+ for(x=TagDatabase.getInstance().albumlen-name.length();x>0;x--)
+ w.write(0);
+ w.writeInt(artist.getOffset());
+ Iterator i2 = songs.iterator();
+ x=0;
+ while(i2.hasNext()) {
+ Entry e = (Entry) i2.next();
+ w.writeInt(e.getOffset());
+ x++;
+ }
+ for(;x<TagDatabase.getInstance().songarraylen;x++)
+ w.writeInt(0);
+ }
+ public static int entrySize() {
+ TagDatabase td=TagDatabase.getInstance();
+ return td.albumlen+4+td.songarraylen*4;
+ }
+} \ No newline at end of file
diff --git a/songdbj/ArtistEntry.java b/songdbj/ArtistEntry.java
new file mode 100644
index 0000000000..fcaaac7dee
--- /dev/null
+++ b/songdbj/ArtistEntry.java
@@ -0,0 +1,56 @@
+import java.util.*;
+import java.io.*;
+
+public class ArtistEntry extends Entry implements Comparable {
+ protected String name;
+ protected Vector albums;
+ protected int albumcount;
+
+ public ArtistEntry(String n) {
+ name=n;
+ albums=new Vector();
+ albumcount=0;
+ }
+
+ public void addAlbum(AlbumEntry e) {
+ if(!albums.contains(e)) {
+ albums.add(e);
+ e.setArtist(this);
+ albumcount++;
+ Collections.sort(albums);
+ }
+ }
+
+ public void removeAlbum(AlbumEntry e) {
+ albums.remove(e);
+ albumcount--;
+ }
+
+ public int size() { return albumcount; }
+
+ public int compareTo(Object o) {
+ return String.CASE_INSENSITIVE_ORDER.compare(name,((ArtistEntry)o).getName());
+ }
+
+ public String getName() { return name; }
+ public Collection getAlbums() { return albums; }
+ public void write(DataOutputStream w) throws IOException {
+ int x;
+ w.writeBytes(name);
+ for(x=TagDatabase.getInstance().artistlen-name.length();x>0;x--)
+ w.write(0);
+ Iterator i2 = albums.iterator();
+ x=0;
+ while(i2.hasNext()) {
+ Entry e = (Entry) i2.next();
+ w.writeInt(e.getOffset());
+ x++;
+ }
+ for(;x<TagDatabase.getInstance().albumarraylen;x++)
+ w.writeInt(0);
+ }
+ public static int entrySize() {
+ TagDatabase td=TagDatabase.getInstance();
+ return td.artistlen+4*td.albumarraylen;
+ }
+} \ No newline at end of file
diff --git a/songdbj/Entry.java b/songdbj/Entry.java
new file mode 100644
index 0000000000..19ead66c06
--- /dev/null
+++ b/songdbj/Entry.java
@@ -0,0 +1,14 @@
+import java.io.*;
+
+public abstract class Entry {
+ protected int offset;
+
+ public Entry() {
+ offset=-1;
+ }
+
+ public void setOffset(int pos) { offset=pos; }
+ public int getOffset() { return offset; }
+
+ public abstract void write(DataOutputStream w) throws IOException;
+} \ No newline at end of file
diff --git a/songdbj/FileEntry.java b/songdbj/FileEntry.java
new file mode 100644
index 0000000000..9af5b3d70a
--- /dev/null
+++ b/songdbj/FileEntry.java
@@ -0,0 +1,155 @@
+import java.io.*;
+
+public class FileEntry extends Entry implements Comparable {
+ protected String filename;
+ protected int hash;
+ protected SongEntry sentry;
+ protected RundbEntry rentry;
+ protected File file;
+
+ public FileEntry(File f) throws FileNotFoundException, IOException {
+ filename=convertPath(f.getAbsolutePath());
+ file=f;
+ sentry=null;
+ rentry=null;
+ }
+
+ public int compareTo(Object o) {
+ return String.CASE_INSENSITIVE_ORDER.compare(filename,((FileEntry)o).getFilename());
+ }
+
+ public String getFilename() { return filename; }
+
+ public File getFile() { return file; }
+
+ protected void calcHash() throws FileNotFoundException, IOException {
+ DataInputStream r = new DataInputStream(new FileInputStream(file));
+ byte[] buf = new byte[32768];
+ if(sentry!=null)
+ r.skip(sentry.getFirstFrameOffset());
+ r.read(buf);
+ hash=CalcCRC32(buf);
+ r.close();
+ }
+
+ public int getHash() { return hash; }
+
+ public static String add(String t) {
+ String add=TagDatabase.getInstance().add;
+ if(add!=null)
+ return add+t;
+ else
+ return t;
+ }
+
+ public static String convertPath(String t) {
+ String temp = add(strip(t)).replace('\\','/');
+ if (temp.charAt(0)!='/')
+ temp="/"+temp;
+ return temp;
+ }
+
+ public static String strip(String t) {
+ return stripPrefix(stripDriveletter(stripPrefix(t)));
+ }
+
+ public static String stripPrefix(String t) {
+ String prefix=TagDatabase.getInstance().strip;
+ if(prefix!=null&&t.toLowerCase().startsWith(prefix.toLowerCase())) {
+ return t.substring(prefix.length());
+ }
+ return t;
+ }
+
+ public static String stripDriveletter(String t) {
+ if(t.indexOf(':')==1) { // second char is ':'
+ return t.substring(2);
+ }
+ return t;
+ }
+
+ public void setSongEntry(SongEntry e) { sentry=e; try { calcHash(); } catch(Exception d) { } }
+ public void setRundbEntry(RundbEntry e) { rentry=e; }
+ public SongEntry getSongEntry() { return sentry; }
+ public RundbEntry getRundbEntry() { return rentry; }
+ public int getSongEntryOffset() {
+ if(sentry!=null)
+ return sentry.getOffset();
+ else
+ return -1;
+ }
+ public int getRundbEntryOffset() {
+/* if(rentry!=null)
+ return rentry.getOffset();
+ else*/
+ return -1;
+ }
+ public void write(DataOutputStream w) throws IOException {
+ String name=getFilename();
+ w.writeBytes(name);
+ for(int x=TagDatabase.getInstance().filelen-name.length();x>0;x--)
+ w.write(0);
+ w.writeInt(hash);
+ w.writeInt(getSongEntryOffset());
+ w.writeInt(getRundbEntryOffset());
+ }
+
+ public static int entrySize() {
+ return TagDatabase.getInstance().filelen+12;
+ }
+
+ static final int crc_table[] =
+ { // CRC32 lookup table for polynomial 0x04C11DB7
+ 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
+ 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
+ 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7,
+ 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
+ 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3,
+ 0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
+ 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF,
+ 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
+ 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB,
+ 0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
+ 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
+ 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
+ 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4,
+ 0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
+ 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08,
+ 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
+ 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC,
+ 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
+ 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050,
+ 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
+ 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
+ 0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
+ 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1,
+ 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
+ 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5,
+ 0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
+ 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9,
+ 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
+ 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD,
+ 0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
+ 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
+ 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
+ 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2,
+ 0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
+ 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E,
+ 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
+ 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A,
+ 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
+ 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676,
+ 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
+ 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
+ 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
+ 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
+ };
+
+ public static int CalcCRC32(byte[] buf) {
+ int i;
+ int crc = 0xffffffff;
+ for (i = 0; i < buf.length; i++)
+ crc = (crc << 8) ^ crc_table[(int)((crc >> 24) ^ buf[i]) & 0xFF];
+ return crc;
+ }
+} \ No newline at end of file
diff --git a/songdbj/MpegInfo.java b/songdbj/MpegInfo.java
new file mode 100644
index 0000000000..6f57879883
--- /dev/null
+++ b/songdbj/MpegInfo.java
@@ -0,0 +1,367 @@
+/*
+ * MpegInfo.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.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.
+ *----------------------------------------------------------------------
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import org.tritonus.share.sampled.file.TAudioFileFormat;
+
+/**
+ * This class gives information (audio format and comments) about MPEG file or URL.
+ */
+public class MpegInfo implements TagInfo
+{
+ protected int channels = -1;
+ protected String channelsMode = null;
+ protected String version = null;
+ protected int rate = 0;
+ protected String layer = null;
+ protected String emphasis = null;
+ protected int nominalbitrate = 0;
+ protected long total = 0;
+ protected String vendor = null;
+ protected String location = null;
+ protected long size = 0;
+ protected boolean copyright = false;
+ protected boolean crc = false;
+ protected boolean original = false;
+ protected boolean priv = false;
+ protected boolean vbr = false;
+ protected int track = -1;
+ protected int offset = 0;
+ protected String year = null;
+ protected String genre = null;
+ protected String title = null;
+ protected String artist = null;
+ protected String album = null;
+ protected Vector comments = null;
+
+ /**
+ * Constructor.
+ */
+ public MpegInfo()
+ {
+ super();
+ }
+
+ /**
+ * Load and parse MPEG info from File.
+ * @param input
+ * @throws IOException
+ */
+ public void load(File input) throws IOException, UnsupportedAudioFileException
+ {
+ size = input.length();
+ location = input.getPath();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse MPEG info from URL.
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(URL input) throws IOException, UnsupportedAudioFileException
+ {
+ location = input.toString();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse MPEG info from InputStream.
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(InputStream input) throws IOException, UnsupportedAudioFileException
+ {
+ loadInfo(input);
+ }
+
+ /**
+ * Load info from input stream.
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(InputStream input) throws IOException, UnsupportedAudioFileException
+ {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ }
+
+ /**
+ * Load MP3 info from file.
+ * @param file
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(File file) throws IOException, UnsupportedAudioFileException
+ {
+ InputStream in = new BufferedInputStream(new FileInputStream(file));
+ loadInfo(in);
+ in.close();
+ }
+
+ /**
+ * Load info from AudioFileFormat.
+ * @param aff
+ */
+ protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException
+ {
+ String type = aff.getType().toString();
+ if (!type.equalsIgnoreCase("mp3")) throw new UnsupportedAudioFileException("Not MP3 audio format");
+ if (aff instanceof TAudioFileFormat)
+ {
+ Map props = ((TAudioFileFormat) aff).properties();
+ if (props.containsKey("mp3.channels")) channels = ((Integer)props.get("mp3.channels")).intValue();
+ if (props.containsKey("mp3.frequency.hz")) rate = ((Integer)props.get("mp3.frequency.hz")).intValue();
+ if (props.containsKey("mp3.bitrate.nominal.bps")) nominalbitrate = ((Integer)props.get("mp3.bitrate.nominal.bps")).intValue();
+ if (props.containsKey("mp3.version.layer")) layer = "Layer "+(String)props.get("mp3.version.layer");
+ if (props.containsKey("mp3.version.mpeg"))
+ {
+ version = (String)props.get("mp3.version.mpeg");
+ if (version.equals("1")) version = "MPEG1";
+ else if (version.equals("2")) version = "MPEG2-LSF";
+ else if (version.equals("2.5")) version = "MPEG2.5-LSF";
+ }
+ if (props.containsKey("mp3.mode"))
+ {
+ int mode = ((Integer)props.get("mp3.mode")).intValue();
+ if (mode==0) channelsMode = "Stereo";
+ else if (mode==1) channelsMode = "Joint Stereo";
+ else if (mode==2) channelsMode = "Dual Channel";
+ else if (mode==3) channelsMode = "Single Channel";
+ }
+ if (props.containsKey("mp3.crc")) crc = ((Boolean)props.get("mp3.crc")).booleanValue();
+ if (props.containsKey("mp3.vbr")) vbr = ((Boolean)props.get("mp3.vbr")).booleanValue();
+ if (props.containsKey("mp3.copyright")) copyright = ((Boolean)props.get("mp3.copyright")).booleanValue();
+ if (props.containsKey("mp3.original")) original = ((Boolean)props.get("mp3.original")).booleanValue();
+ emphasis="none";
+
+ if (props.containsKey("title")) title = (String)props.get("title");
+ if (props.containsKey("author")) artist = (String)props.get("author");
+ if (props.containsKey("album")) album = (String)props.get("album");
+ if (props.containsKey("date")) year = (String)props.get("date");
+ if (props.containsKey("duration")) total = (long) Math.round((((Long)props.get("duration")).longValue())/1000000);
+ if (props.containsKey("mp3.id3tag.genre")) genre = (String)props.get("mp3.id3tag.genre");
+
+ if (props.containsKey("mp3.header.pos")) {
+ offset = ((Integer)props.get("mp3.header.pos")).intValue();
+ }
+ else
+ offset = 0;
+ if (props.containsKey("mp3.id3tag.track"))
+ {
+ try
+ {
+ track = Integer.parseInt((String)props.get("mp3.id3tag.track"));
+ }
+ catch (NumberFormatException e1)
+ {
+ // Not a number
+ }
+ }
+ }
+ }
+
+ /**
+ * Load MP3 info from URL.
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(URL input) throws IOException, UnsupportedAudioFileException
+ {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ loadShoutastInfo(aff);
+ }
+
+ /**
+ * Load Shoutcast info from AudioFileFormat.
+ * @param aff
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadShoutastInfo(AudioFileFormat aff) throws IOException, UnsupportedAudioFileException
+ {
+ String type = aff.getType().toString();
+ if (!type.equalsIgnoreCase("mp3")) throw new UnsupportedAudioFileException("Not MP3 audio format");
+ if (aff instanceof TAudioFileFormat)
+ {
+ Map props = ((TAudioFileFormat) aff).properties();
+ // Try shoutcast meta data (if any).
+ Iterator it = props.keySet().iterator();
+ comments = new Vector();
+ while (it.hasNext())
+ {
+ String key = (String) it.next();
+ if (key.startsWith("mp3.shoutcast.metadata."))
+ {
+ String value = (String) props.get(key);
+ key = key.substring(23,key.length());
+ if (key.equalsIgnoreCase("icy-name"))
+ {
+ title = value;
+ }
+ else if (key.equalsIgnoreCase("icy-genre"))
+ {
+ genre = value;
+ }
+ else
+ {
+ comments.add(key+"="+value);
+ }
+ }
+ }
+ }
+ }
+
+ public boolean getVBR()
+ {
+ return vbr;
+ }
+
+ public int getChannels()
+ {
+ return channels;
+ }
+
+ public String getVersion()
+ {
+ return version;
+ }
+
+ public String getEmphasis()
+ {
+ return emphasis;
+ }
+
+ public boolean getCopyright()
+ {
+ return copyright;
+ }
+
+ public boolean getCRC()
+ {
+ return crc;
+ }
+
+ public boolean getOriginal()
+ {
+ return original;
+ }
+
+ public String getLayer()
+ {
+ return layer;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getLocation()
+ {
+ return location;
+ }
+
+ /*-- TagInfo Implementation --*/
+
+ public int getSamplingRate()
+ {
+ return rate;
+ }
+
+ public int getBitRate()
+ {
+ return nominalbitrate;
+ }
+
+ public long getPlayTime()
+ {
+ return total;
+ }
+
+ public String getTitle()
+ {
+ return title;
+ }
+
+ public String getArtist()
+ {
+ return artist;
+ }
+
+ public String getAlbum()
+ {
+ return album;
+ }
+
+ public int getTrack()
+ {
+ return track;
+ }
+
+ public String getGenre()
+ {
+ return genre;
+ }
+
+ public Vector getComment()
+ {
+ return comments;
+ }
+
+ public String getYear()
+ {
+ return year;
+ }
+
+ /**
+ * Get channels mode.
+ * @return
+ */
+ public String getChannelsMode()
+ {
+ return channelsMode;
+ }
+
+ public int getFirstFrameOffset() {
+ return offset;
+ }
+
+} \ No newline at end of file
diff --git a/songdbj/OggVorbisInfo.java b/songdbj/OggVorbisInfo.java
new file mode 100644
index 0000000000..ab07299e77
--- /dev/null
+++ b/songdbj/OggVorbisInfo.java
@@ -0,0 +1,311 @@
+/*
+ * OggVorbisInfo.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.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.
+ *----------------------------------------------------------------------
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.net.URL;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import org.tritonus.share.sampled.file.TAudioFileFormat;
+
+/**
+ * This class gives information (audio format and comments) about Ogg Vorbis file or URL.
+ */
+public class OggVorbisInfo implements TagInfo
+{
+ protected int serial = 0;
+ protected int channels = 0;
+ protected int version = 0;
+ protected int rate = 0;
+ protected int minbitrate = 0;
+ protected int maxbitrate = 0;
+ protected int averagebitrate = 0;
+ protected int nominalbitrate = 0;
+ protected long totalms = 0;
+ protected String vendor = "";
+ protected String location = null;
+
+ protected long size = 0;
+ protected int track = -1;
+ protected String year = null;
+ protected String genre = null;
+ protected String title = null;
+ protected String artist = null;
+ protected String album = null;
+ protected Vector comments = new Vector();
+
+
+ /***
+ * Constructor.
+ */
+ public OggVorbisInfo()
+ {
+ super();
+ }
+
+ /**
+ * Load and parse Ogg Vorbis info from File.
+ * @param input
+ * @throws IOException
+ */
+ public void load(File input) throws IOException, UnsupportedAudioFileException
+ {
+ size = input.length();
+ location = input.getPath();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse Ogg Vorbis info from URL.
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(URL input) throws IOException, UnsupportedAudioFileException
+ {
+ location = input.toString();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse Ogg Vorbis info from InputStream.
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(InputStream input) throws IOException, UnsupportedAudioFileException
+ {
+ loadInfo(input);
+ }
+
+ /**
+ * Load info from input stream.
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(InputStream input) throws IOException, UnsupportedAudioFileException
+ {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ }
+
+ /**
+ * Load Ogg Vorbis info from file.
+ * @param file
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(File file) throws IOException, UnsupportedAudioFileException
+ {
+ InputStream in = new BufferedInputStream(new FileInputStream(file));
+ loadInfo(in);
+ in.close();
+ }
+
+ /**
+ * Load Ogg Vorbis info from URL.
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(URL input) throws IOException, UnsupportedAudioFileException
+ {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ loadExtendedInfo(aff);
+ }
+
+ /**
+ * Load info from AudioFileFormat.
+ * @param aff
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException
+ {
+ String type = aff.getType().toString();
+ if (!type.equalsIgnoreCase("ogg")) throw new UnsupportedAudioFileException("Not Ogg Vorbis audio format");
+ if (aff instanceof TAudioFileFormat)
+ {
+ Map props = ((TAudioFileFormat) aff).properties();
+ if (props.containsKey("ogg.channels")) channels = ((Integer)props.get("ogg.channels")).intValue();
+ if (props.containsKey("ogg.frequency.hz")) rate = ((Integer)props.get("ogg.frequency.hz")).intValue();
+ if (props.containsKey("ogg.bitrate.nominal.bps")) nominalbitrate = ((Integer)props.get("ogg.bitrate.nominal.bps")).intValue();
+ averagebitrate = nominalbitrate;
+ if (props.containsKey("ogg.bitrate.max.bps")) maxbitrate = ((Integer)props.get("ogg.bitrate.max.bps")).intValue();
+ if (props.containsKey("ogg.bitrate.min.bps")) minbitrate = ((Integer)props.get("ogg.bitrate.min.bps")).intValue();
+ if (props.containsKey("ogg.version")) version = ((Integer)props.get("ogg.version")).intValue();
+ if (props.containsKey("ogg.serial")) serial = ((Integer)props.get("ogg.serial")).intValue();
+ if (props.containsKey("ogg.comment.encodedby")) vendor = (String)props.get("ogg.comment.encodedby");
+
+ if (props.containsKey("copyright")) comments.add((String)props.get("copyright"));
+ if (props.containsKey("title")) title = (String)props.get("title");
+ if (props.containsKey("author")) artist = (String)props.get("author");
+ if (props.containsKey("album")) album = (String)props.get("album");
+ if (props.containsKey("date")) year = (String)props.get("date");
+ if (props.containsKey("comment")) comments.add((String)props.get("comment"));
+ if (props.containsKey("duration")) totalms = (long) Math.round((((Long)props.get("duration")).longValue())/1000000);
+ if (props.containsKey("ogg.comment.genre")) genre = (String)props.get("ogg.comment.genre");
+ if (props.containsKey("ogg.comment.track"))
+ {
+ try
+ {
+ track = Integer.parseInt((String)props.get("ogg.comment.track"));
+ }
+ catch (NumberFormatException e1)
+ {
+ // Not a number
+ }
+ }
+ if (props.containsKey("ogg.comment.ext.1")) comments.add((String)props.get("ogg.comment.ext.1"));
+ if (props.containsKey("ogg.comment.ext.2")) comments.add((String)props.get("ogg.comment.ext.2"));
+ if (props.containsKey("ogg.comment.ext.3")) comments.add((String)props.get("ogg.comment.ext.3"));
+ }
+ }
+
+ /**
+ * Load extended info from AudioFileFormat.
+ * @param aff
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadExtendedInfo(AudioFileFormat aff) throws IOException, UnsupportedAudioFileException
+ {
+ String type = aff.getType().toString();
+ if (!type.equalsIgnoreCase("ogg")) throw new UnsupportedAudioFileException("Not Ogg Vorbis audio format");
+ if (aff instanceof TAudioFileFormat)
+ {
+ Map props = ((TAudioFileFormat) aff).properties();
+ // How to load icecast meta data (if any) ??
+ }
+ }
+
+ public int getSerial()
+ {
+ return serial;
+ }
+
+ public int getChannels()
+ {
+ return channels;
+ }
+
+ public int getVersion()
+ {
+ return version;
+ }
+
+ public int getMinBitrate()
+ {
+ return minbitrate;
+ }
+
+ public int getMaxBitrate()
+ {
+ return maxbitrate;
+ }
+
+ public int getAverageBitrate()
+ {
+ return averagebitrate;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getVendor()
+ {
+ return vendor;
+ }
+
+ public String getLocation()
+ {
+ return location;
+ }
+
+ /*-- TagInfo Implementation --*/
+
+ public int getSamplingRate()
+ {
+ return rate;
+ }
+
+ public int getBitRate()
+ {
+ return nominalbitrate;
+ }
+
+ public long getPlayTime()
+ {
+ return totalms;
+ }
+
+ public String getTitle()
+ {
+ return title;
+ }
+
+ public String getArtist()
+ {
+ return artist;
+ }
+
+ public String getAlbum()
+ {
+ return album;
+ }
+
+ public int getTrack()
+ {
+ return track;
+ }
+
+ public String getGenre()
+ {
+ return genre;
+ }
+
+ public Vector getComment()
+ {
+ return comments;
+ }
+
+ public String getYear()
+ {
+ return year;
+ }
+
+ public int getFirstFrameOffset() {
+ return 0;
+ }
+} \ No newline at end of file
diff --git a/songdbj/RundbEntry.java b/songdbj/RundbEntry.java
new file mode 100644
index 0000000000..c13cbe4924
--- /dev/null
+++ b/songdbj/RundbEntry.java
@@ -0,0 +1,28 @@
+import java.io.*;
+
+public class RundbEntry extends Entry {
+ protected FileEntry file;
+ protected short rating, voladj;
+ protected int playcount,lastplayed;
+
+ public RundbEntry(FileEntry f) {
+ file=f;
+ rating=0;
+ voladj=0;
+ playcount=0;
+ lastplayed=0;
+ }
+
+ public void write(DataOutputStream w) throws IOException {
+ w.writeInt(file.getOffset());
+ w.writeInt(file.getHash());
+ w.writeShort(rating);
+ w.writeShort(voladj);
+ w.writeInt(playcount);
+ w.writeInt(lastplayed);
+ }
+
+ public static int entrySize() {
+ return 20;
+ }
+} \ No newline at end of file
diff --git a/songdbj/RuntimeDatabase.java b/songdbj/RuntimeDatabase.java
new file mode 100644
index 0000000000..e96e8207cc
--- /dev/null
+++ b/songdbj/RuntimeDatabase.java
@@ -0,0 +1,81 @@
+import java.util.*;
+import java.io.*;
+import java.lang.reflect.Array;
+
+/*
+ TreeSet for runtimedatabase with entry hash used in compareto
+ fix commandline interface.
+*/
+
+public class RuntimeDatabase {
+ protected static RuntimeDatabase instance=null;
+ protected TreeMap entries;
+ protected int entrycount;
+ public static final int headersize = 8;
+
+ protected RuntimeDatabase() {
+ entries=new TreeMap();
+ }
+
+ public static RuntimeDatabase getInstance() {
+ if(instance==null)
+ instance=new RuntimeDatabase();
+ return instance;
+ }
+
+ public RundbEntry getEntry(FileEntry file) {
+ Integer key = new Integer(file.getHash());
+ if(!entries.containsKey(key)) {
+ RundbEntry e = new RundbEntry(file);
+ entries.put(key,e);
+ return e;
+ }
+ else
+ return (RundbEntry)entries.get(key);
+ }
+
+ protected void calcOffsets() {
+ Collection values = entries.values();
+ Iterator i;
+ int offset=headersize;
+ i=values.iterator();
+ while(i.hasNext()) {
+ Entry e = (Entry) i.next();
+ e.setOffset(offset);
+ offset+=RundbEntry.entrySize();
+ }
+ entrycount=values.size();
+ }
+
+ public int isDirty() {
+ return 0;
+ }
+
+ protected void writeHeader(DataOutputStream w) throws IOException {
+ w.write('R');
+ w.write('R');
+ w.write('D');
+ w.write(0x1);
+ w.writeInt(entrycount);
+ }
+
+ public void prepareWrite() {
+ System.out.println("Calculating Runtime Database Offsets..");
+ calcOffsets();
+ }
+
+ public void writeDatabase(File f) throws IOException {
+ int x;
+ Iterator i;
+ DataOutputStream w = new DataOutputStream(new FileOutputStream(f));
+ System.out.println("Writing runtime database..");
+ writeHeader(w);
+ i=entries.values().iterator();
+ while(i.hasNext()) {
+ Entry e = (Entry) i.next();
+ e.write(w);
+ }
+ w.flush();
+ w.close();
+ }
+} \ No newline at end of file
diff --git a/songdbj/SongDB.java b/songdbj/SongDB.java
new file mode 100644
index 0000000000..4b7f2aae03
--- /dev/null
+++ b/songdbj/SongDB.java
@@ -0,0 +1,74 @@
+import java.io.*;
+import java.lang.reflect.Array;
+
+public class SongDB {
+
+ public static final void main(String[] args) {
+ TagDatabase td = TagDatabase.getInstance();
+ File tdfile = new File("rockbox.tagdb");
+ // RuntimeDatabase rd = RuntimeDatabase.getInstance();
+ int i = 0, j;
+ String arg,path = null;
+
+ while (i < args.length) {
+ arg = args[i++];
+ if (arg.equals("--dirisnotalbumname")) {
+ td.dirisalbumname=false;
+ }
+ else if(arg.equals("--dirisalbum")) {
+ td.dirisalbum=true;
+ }
+ else if(arg.equals("--dontshowduplicates")) {
+ td.showduplicates=false;
+ }
+ else if(arg.equals("--strip")) {
+ if (i < args.length)
+ td.strip = args[i++];
+ else {
+ System.err.println("--strip requires a path");
+ System.exit(0);
+ }
+ }
+ else if(arg.equals("--add")) {
+ if (i < args.length)
+ td.add = args[i++];
+ else {
+ System.err.println("--add requires a path");
+ System.exit(0);
+ }
+ }
+ else {
+ if(path!=null) {
+ System.err.println("you can't specify more than one path!");
+ System.exit(0);
+ }
+ path = arg;
+ }
+ }
+ if (i != args.length||path==null) {
+ System.out.println("Usage: SongDB [--showduplicates] [--strip <directory>] [--add <directory>] [--dirisnotalbumname] [--dirisalbum] <directory>");
+ return;
+ }
+ if(tdfile.exists()&&!tdfile.canWrite()) {
+ System.out.println("rockbox.tagdb is not writable.");
+ return;
+ }
+ try {
+ tdfile.createNewFile();
+ }
+ catch(Exception e) {
+ System.out.println("Error while trying to create rockbox.tagdb: "+e.getMessage());
+ return;
+ }
+ td.add(new File(path));
+ try {
+ td.prepareWrite();
+ // rd.prepareWrite();
+ td.writeDatabase(new File("rockbox.tagdb"));
+ // rd.writeDatabase(new File("rockbox.rundb"));
+ }
+ catch(IOException e) {
+ System.out.println(e);
+ }
+ }
+} \ No newline at end of file
diff --git a/songdbj/SongEntry.java b/songdbj/SongEntry.java
new file mode 100644
index 0000000000..cf6f887a7b
--- /dev/null
+++ b/songdbj/SongEntry.java
@@ -0,0 +1,167 @@
+import java.util.*;
+import java.io.*;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import java.lang.NumberFormatException;
+import net.shredzone.ifish.ltr.LTR;
+
+public class SongEntry extends Entry implements Comparable {
+ protected TagInfo info;
+ protected LTR tag;
+ protected ArtistEntry artist;
+ protected AlbumEntry album;
+ protected FileEntry file;
+
+ public SongEntry(FileEntry f) {
+ file=f;
+ file.setSongEntry(this);
+ readTagInfo();
+ }
+
+ public void setAlbum(AlbumEntry a) { album=a; }
+ public void setArtist(ArtistEntry a) { artist=a; }
+ public AlbumEntry getAlbum() { return album; }
+ public ArtistEntry getArtist() { return artist; }
+ public FileEntry getFile() { return file; }
+
+ public int compareTo(Object o) {
+ return String.CASE_INSENSITIVE_ORDER.compare(getName(),((SongEntry)o).getName());
+ }
+
+ public String getName() {
+ String title=tag.getTitle();
+ if(title==null)
+ title = stripExt(file.getFile().getName());
+ title=title.trim();
+ if(title.equals(""))
+ title = stripExt(file.getFile().getName());
+ return title;
+ }
+
+ public static String stripExt(String t) {
+ return t.substring(0,t.lastIndexOf('.'));
+ }
+
+ public String getAlbumTag() {
+ String album=tag.getAlbum();
+ if(album==null)
+ album = "<no album tag>";
+ album=album.trim();
+ if(album.equals(""))
+ album = "<no album tag>";
+ if(TagDatabase.getInstance().dirisalbumname&&album.equals("<no album tag>")) {
+ album = file.getFile().getParentFile().getName();
+ }
+ return album;
+ }
+
+ public String getArtistTag() {
+ String artist=tag.getArtist();
+ if(artist==null)
+ artist = "<no artist tag>";
+ artist=artist.trim();
+ if(artist.equals(""))
+ artist = "<no artist tag>";
+ return artist;
+ }
+
+ public String getGenreTag() {
+ String genre=tag.getGenre();
+ if(genre==null)
+ genre = "<no genre tag>";
+ genre=genre.trim();
+ if(genre.equals(""))
+ genre = "<no genre tag>";
+ return genre;
+ }
+
+ public int getYear() {
+ try {
+ return Integer.parseInt(tag.getYear());
+ } catch(NumberFormatException e) {
+ return 0;
+ }
+ }
+
+ public int getTrack() {
+ try {
+ return Integer.parseInt(tag.getTrack());
+ } catch(NumberFormatException e) {
+ return 0;
+ }
+ }
+
+ public int getBitRate() { if(info==null) return -1; return info.getBitRate()/1000; }
+
+ public int getPlayTime() { if(info==null) return -1; return (int)info.getPlayTime(); }
+
+ public int getSamplingRate() { if(info==null) return -1; return info.getSamplingRate(); }
+
+ public int getFirstFrameOffset() { if(info==null) return 0; return info.getFirstFrameOffset(); }
+
+ public boolean gotTagInfo() { return tag!=null; }
+
+ protected void readTagInfo() {
+ // Check Mpeg format.
+ try
+ {
+ info = new MpegInfo();
+ info.load(file.getFile());
+ }
+/* catch (IOException ex)
+ {
+ //ex.printStackTrace();
+ System.out.println(ex);
+ info = null;
+ }*/
+ catch (Exception ex)
+ {
+ // Error..
+ info = null;
+ }
+
+ if (info == null)
+ {
+ // Check Ogg Vorbis format.
+ try
+ {
+ info = new OggVorbisInfo();
+ info.load(file.getFile());
+ }
+ /*catch (IOException ex)
+ {
+ //ex.printStackTrace();
+ System.out.println(ex);
+ info = null;
+ }*/
+ catch (Exception ex)
+ {
+ // Not Ogg Vorbis Format
+ //System.out.println("Failed reading tag for "+location.getAbsolutePath()+", tried mp3 and vorbis.");
+ info = null;
+ }
+ }
+ tag = LTR.create(file.getFile());
+ }
+
+ public void write(DataOutputStream w) throws IOException {
+ String name=getName();
+ w.writeBytes(name);
+ for(int x=TagDatabase.getInstance().songlen-name.length();x>0;x--)
+ w.write(0);
+ w.writeInt(artist.getOffset());
+ w.writeInt(album.getOffset());
+ w.writeInt(file.getOffset());
+ w.writeBytes(getGenreTag());
+ for(int x=TagDatabase.getInstance().genrelen-getGenreTag().length();x>0;x--)
+ w.write(0);
+ w.writeShort(getBitRate());
+ w.writeShort(getYear());
+ w.writeInt(getPlayTime());
+ w.writeShort(getTrack());
+ w.writeShort(getSamplingRate());
+ }
+ public static int entrySize() {
+ TagDatabase td=TagDatabase.getInstance();
+ return td.songlen+12+td.genrelen+12;
+ }
+} \ No newline at end of file
diff --git a/songdbj/TagDatabase.java b/songdbj/TagDatabase.java
new file mode 100644
index 0000000000..36c2c09f37
--- /dev/null
+++ b/songdbj/TagDatabase.java
@@ -0,0 +1,377 @@
+import java.util.*;
+import java.io.*;
+import java.lang.reflect.Array;
+
+/*
+ TreeSet for runtimedatabase with entry hash used in compareto
+ fix commandline interface.
+*/
+
+public class TagDatabase {
+ protected static TagDatabase instance=null;
+ protected TreeMap songs;
+ protected TreeMap files;
+ protected TreeMap filehashes;
+ protected TreeMap albums;
+ protected TreeMap artists;
+ protected int artiststart,albumstart,songstart,filestart;
+ protected int artistcount,albumcount,songcount,filecount;
+ public int artistlen,albumlen,songlen,genrelen,filelen,songarraylen,albumarraylen;
+ public String strip,add;
+ public boolean haveOldDatabase,dirisalbum,dirisalbumname,showduplicates;
+ protected Vector sortedsongs,sortedfiles,sortedalbums,sortedartists;
+
+ protected TagDatabase() {
+ songs=new TreeMap();
+ files=new TreeMap();
+ filehashes=new TreeMap();
+ albums=new TreeMap();
+ artists=new TreeMap();
+ strip=null;
+ add=null;
+ haveOldDatabase=false;
+ dirisalbum=false;
+ dirisalbumname=true;
+ showduplicates=true;
+ }
+
+ public static TagDatabase getInstance() {
+ if(instance==null)
+ instance=new TagDatabase();
+ return instance;
+ }
+
+ public void removeFileEntry(File file) {
+ String key = file.getAbsolutePath();
+ files.remove(key);
+ }
+
+ public FileEntry getFileEntry(File file) throws FileNotFoundException, IOException {
+ String key = file.getAbsolutePath();
+ if(!files.containsKey(key)) {
+ FileEntry f = new FileEntry(file);
+ files.put(key,f);
+ return f;
+ }
+ else
+ return (FileEntry)files.get(key);
+ }
+
+ public ArtistEntry getArtistEntry(String name) {
+ String key = name.toLowerCase();
+ if(!artists.containsKey(key)) {
+ ArtistEntry a = new ArtistEntry(name);
+ artists.put(key,a);
+ return a;
+ }
+ else
+ return (ArtistEntry)artists.get(key);
+ }
+
+ public String getAlbumKey(String name, String directory) {
+ if(dirisalbum)
+ return directory;
+ else
+ return name.toLowerCase()+"___"+directory;
+ }
+
+ public AlbumEntry getAlbumEntry(String name,String directory) {
+ String key = getAlbumKey(name,directory);
+ if(!albums.containsKey(key)) {
+ AlbumEntry a = new AlbumEntry(name);
+ albums.put(key,a);
+ return a;
+ }
+ else
+ return (AlbumEntry)albums.get(key);
+ }
+
+ public void removeSongEntry(FileEntry file) {
+ String key = file.getFilename();
+ songs.remove(key);
+ file.setSongEntry(null);
+ }
+
+ public SongEntry getSongEntry(FileEntry file) {
+ String key = file.getFilename();
+ if(!songs.containsKey(key)) {
+ SongEntry s = new SongEntry(file);
+ songs.put(key,s);
+ return s;
+ }
+ else
+ return (SongEntry)songs.get(key);
+ }
+
+ private class SongFilter implements FileFilter {
+ public boolean accept(File f) {
+ if(f.isDirectory()) // always accept directories.
+ return true;
+ String name=f.getName();
+ return name.endsWith(".mp3")||name.endsWith(".ogg");
+ }
+ }
+
+ public void add(File f) {
+ if(!f.isDirectory()) {
+ if(f.isFile()) {
+ addSong(f);
+ }
+ }
+ else {
+ File[] files = f.listFiles(new SongFilter());
+ int length=Array.getLength(files);
+ System.out.println(FileEntry.convertPath(f.getAbsolutePath()));
+ for(int i=0;i<length;i++) {
+ add(files[i]);
+ }
+ }
+ }
+
+ protected FileEntry addSong(File f) {
+ FileEntry file = null;
+ try {
+ file = getFileEntry(f);
+ }
+ catch(Exception e) {
+ return null;
+ }
+ SongEntry song = getSongEntry(file);
+ if(!song.gotTagInfo()) {
+ removeSongEntry(file);
+ return null;
+ }
+ ArtistEntry artist = getArtistEntry(song.getArtistTag());
+ AlbumEntry album = getAlbumEntry(song.getAlbumTag(),f.getParent());
+ album.setArtist(artist);
+ album.addSong(song);
+ return file;
+ }
+
+ protected int align(int len) {
+ while((len&3)!=0) len++;
+ return len;
+ }
+
+ protected void calcLimits() {
+ ArtistEntry longartist=null,longalbumarray=null;
+ AlbumEntry longalbum=null, longsongarray=null;
+ SongEntry longsong=null,longgenre=null;
+ FileEntry longfile=null;
+ Iterator i;
+ artistlen=0;
+ albumarraylen=0;
+ i=sortedartists.iterator();
+ while(i.hasNext()) {
+ ArtistEntry artist = (ArtistEntry) i.next();
+ int length=artist.getName().length();
+ int albumcount=artist.size();
+ if(length > artistlen) {
+ artistlen=align(length);
+ longartist=artist;
+ }
+ if(albumcount> albumarraylen) {
+ albumarraylen=albumcount;
+ longalbumarray=artist;
+ }
+ }
+ artistcount=sortedartists.size();
+ if(longartist!=null)
+ System.out.println("Artist with longest name ("+artistlen+") :"+longartist.getName());
+ if(longalbumarray!=null)
+ System.out.println("Artist with most albums ("+albumarraylen+") :"+longalbumarray.getName());
+ albumlen=0;
+ songarraylen=0;
+ i=sortedalbums.iterator();
+ while(i.hasNext()) {
+ AlbumEntry album = (AlbumEntry) i.next();
+ int length=album.getName().length();
+ int songcount=album.size();
+ if(length > albumlen) {
+ albumlen=align(length);
+ longalbum=album;
+ }
+ if(songcount> songarraylen) {
+ songarraylen=songcount;
+ longsongarray=album;
+ }
+ }
+ albumcount=sortedalbums.size();
+ if(longalbum!=null)
+ System.out.println("Album with longest name ("+albumlen+") :"+longalbum.getName());
+ if(longsongarray!=null)
+ System.out.println("Album with most songs ("+songarraylen+") :"+longsongarray.getName());
+ filelen=0;
+ i=sortedfiles.iterator();
+ while(i.hasNext()) {
+ FileEntry file = (FileEntry) i.next();
+ int length=file.getFilename().length();
+ if(length> filelen) {
+ filelen=align(length);
+ longfile=file;
+ }
+ }
+ filecount=sortedfiles.size();
+ if(longfile!=null)
+ System.out.println("File with longest filename ("+filelen+") :"+longfile.getFilename());
+ songlen=0;
+ genrelen=0;
+ i=sortedsongs.iterator();
+ while(i.hasNext()) {
+ SongEntry song = (SongEntry) i.next();
+ int tlength=song.getName().length();
+ int glength=song.getGenreTag().length();
+ if(tlength> songlen) {
+ songlen=align(tlength);
+ longsong=song;
+ }
+ if(glength> genrelen) {
+ genrelen=align(glength);
+ longgenre=song;
+ }
+ }
+ songcount=sortedsongs.size();
+ if(longsong!=null)
+ System.out.println("Song with longest name ("+songlen+") :"+longsong.getName());
+ if(longsong!=null)
+ System.out.println("Song with longest genre ("+genrelen+") :"+longgenre.getGenreTag());
+ System.out.println("Artistcount: "+artistcount);
+ System.out.println("Albumcount : "+albumcount);
+ System.out.println("Songcount : "+songcount);
+ System.out.println("Filecount : "+filecount);
+ artiststart=68;
+ albumstart=artiststart+artistcount*ArtistEntry.entrySize();
+ songstart=albumstart+albumcount*AlbumEntry.entrySize();
+ filestart=songstart+songcount*SongEntry.entrySize();
+ }
+
+ protected void calcOffsets() {
+ Iterator i;
+ int offset=artiststart;
+ i=sortedartists.iterator();
+ while(i.hasNext()) {
+ Entry e = (Entry) i.next();
+ e.setOffset(offset);
+ offset+=ArtistEntry.entrySize();
+ }
+// assert(offset==albumstart);
+ i=sortedalbums.iterator();
+ while(i.hasNext()) {
+ Entry e = (Entry) i.next();
+ e.setOffset(offset);
+ offset+=AlbumEntry.entrySize();
+ }
+// assert(offset==songstart);
+ i=sortedsongs.iterator();
+ while(i.hasNext()) {
+ Entry e = (Entry) i.next();
+ e.setOffset(offset);
+ offset+=SongEntry.entrySize();
+ }
+// assert(offset==filestart);
+ i=sortedfiles.iterator();
+ while(i.hasNext()) {
+ Entry e = (Entry) i.next();
+ e.setOffset(offset);
+ offset+=FileEntry.entrySize();
+ }
+ }
+
+ protected void calcHashes() {
+ Iterator i;
+ i=sortedfiles.iterator();
+ while(i.hasNext()) {
+ FileEntry file = (FileEntry) i.next();
+ Integer key = new Integer(file.getHash());
+ if(!filehashes.containsKey(key))
+ filehashes.put(key,file);
+ else {
+ System.out.println("Duplicate hash:");
+ System.out.println(((FileEntry)filehashes.get(key)).getFilename());
+ System.out.println(file.getFilename());
+ }
+ }
+ }
+
+ protected void writeHeader(DataOutputStream w) throws IOException {
+ w.write('R');
+ w.write('D');
+ w.write('B');
+ w.write(0x3);
+ w.writeInt(artiststart);
+ w.writeInt(albumstart);
+ w.writeInt(songstart);
+ w.writeInt(filestart);
+ w.writeInt(artistcount);
+ w.writeInt(albumcount);
+ w.writeInt(songcount);
+ w.writeInt(filecount);
+ w.writeInt(artistlen);
+ w.writeInt(albumlen);
+ w.writeInt(songlen);
+ w.writeInt(genrelen);
+ w.writeInt(filelen);
+ w.writeInt(songarraylen);
+ w.writeInt(albumarraylen);
+ w.writeInt(RuntimeDatabase.getInstance().isDirty());
+ }
+
+ public void prepareWrite() {
+ System.out.println("Sorting artists..");
+ sortedartists=new Vector();
+ sortedartists.addAll(artists.values());
+ Collections.sort(sortedartists);
+ System.out.println("Sorting albums..");
+ sortedalbums=new Vector();
+ sortedalbums.addAll(albums.values());
+ Collections.sort(sortedalbums);
+ System.out.println("Sorting songs..");
+ sortedsongs=new Vector();
+ sortedsongs.addAll(songs.values());
+ Collections.sort(sortedsongs);
+ System.out.println("Sorting files..");
+ sortedfiles=new Vector();
+ sortedfiles.addAll(files.values());
+ Collections.sort(sortedfiles);
+ System.out.println("Calculating tag database limits..");
+ calcLimits();
+ System.out.println("Calculating tag database offsets..");
+ calcOffsets();
+ if(showduplicates) {
+ System.out.println("Comparing file hashes..");
+ calcHashes();
+ }
+ }
+
+ public void writeDatabase(File f) throws IOException {
+ int x;
+ Iterator i;
+ DataOutputStream w = new DataOutputStream(new FileOutputStream(f));
+ System.out.println("Writing tag database..");
+ writeHeader(w);
+
+ i=sortedartists.iterator();
+ while(i.hasNext()) {
+ Entry e = (Entry) i.next();
+ e.write(w);
+ }
+ i=sortedalbums.iterator();
+ while(i.hasNext()) {
+ Entry e = (Entry) i.next();
+ e.write(w);
+ }
+ i=sortedsongs.iterator();
+ while(i.hasNext()) {
+ Entry e = (Entry) i.next();
+ e.write(w);
+ }
+ i=sortedfiles.iterator();
+ while(i.hasNext()) {
+ Entry e = (Entry) i.next();
+ e.write(w);
+ }
+ // done...
+ w.flush();
+ w.close();
+ }
+} \ No newline at end of file
diff --git a/songdbj/TagInfo.java b/songdbj/TagInfo.java
new file mode 100644
index 0000000000..2259226025
--- /dev/null
+++ b/songdbj/TagInfo.java
@@ -0,0 +1,112 @@
+/*
+ * TagInfo.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.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.
+ *----------------------------------------------------------------------
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Vector;
+
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * This interface define needed features for song information.
+ * Adapted from Scott Pennell interface.
+ */
+public interface TagInfo
+{
+
+ public void load(InputStream input) throws IOException, UnsupportedAudioFileException;
+
+ public void load(URL input) throws IOException, UnsupportedAudioFileException;
+
+ public void load(File input) throws IOException, UnsupportedAudioFileException;
+
+ /**
+ * Get Sampling Rate
+ * @return
+ */
+ public int getSamplingRate();
+
+ /**
+ * Get Nominal Bitrate
+ * @return bitrate in bps
+ */
+ public int getBitRate();
+
+ /**
+ * Get channels.
+ * @return channels
+ */
+ public int getChannels();
+
+ /**
+ * Get play time in seconds.
+ * @return
+ */
+ public long getPlayTime();
+
+ /**
+ * Get the title of the song.
+ * @return the title of the song
+ */
+ public String getTitle();
+
+ /**
+ * Get the artist that performed the song
+ * @return the artist that performed the song
+ */
+ public String getArtist();
+
+ /**
+ * Get the name of the album upon which the song resides
+ * @return the album name
+ */
+ public String getAlbum();
+
+ /**
+ * Get the track number of this track on the album
+ * @return the track number
+ */
+ public int getTrack();
+
+ /**
+ * Get the genre string of the music
+ * @return the genre string
+ */
+ public String getGenre();
+
+ /**
+ * Get the year the track was released
+ * @return the year the track was released
+ */
+ public String getYear();
+
+ /**
+ * Get any comments provided about the song
+ * @return the comments
+ */
+ public Vector getComment();
+
+ public int getFirstFrameOffset();
+} \ No newline at end of file
diff --git a/songdbj/build.sh b/songdbj/build.sh
new file mode 100755
index 0000000000..e8b6b850a0
--- /dev/null
+++ b/songdbj/build.sh
@@ -0,0 +1,2 @@
+javac -d classes -cp . -source 1.5 -target 1.5 `find -name '*.java'`
+jar cvfm SongDB.jar classes/META-INF/MANIFEST.MF -C classes/ .
diff --git a/songdbj/classes/META-INF/MANIFEST.MF b/songdbj/classes/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..14ecfed112
--- /dev/null
+++ b/songdbj/classes/META-INF/MANIFEST.MF
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Created-By: Apache Ant 1.5.1
+Main-Class: SongDB
+
diff --git a/songdbj/classes/META-INF/services/javax.sound.sampled.spi.AudioFileReader b/songdbj/classes/META-INF/services/javax.sound.sampled.spi.AudioFileReader
new file mode 100644
index 0000000000..48c0ea73ca
--- /dev/null
+++ b/songdbj/classes/META-INF/services/javax.sound.sampled.spi.AudioFileReader
@@ -0,0 +1,4 @@
+# for the javalayer mp3 decoder
+javazoom.spi.mpeg.sampled.file.MpegAudioFileReader
+# for the vorbis decoder
+javazoom.spi.vorbis.sampled.file.VorbisAudioFileReader \ No newline at end of file
diff --git a/songdbj/classes/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider b/songdbj/classes/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider
new file mode 100644
index 0000000000..f7f32618ac
--- /dev/null
+++ b/songdbj/classes/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider
@@ -0,0 +1,3 @@
+# for the javalayer mp3 decoder
+javazoom.spi.mpeg.sampled.convert.MpegFormatConversionProvider
+org.tritonus.sampled.convert.vorbis.VorbisFormatConversionProvider
diff --git a/songdbj/com/jcraft/jogg/Buffer.java b/songdbj/com/jcraft/jogg/Buffer.java
new file mode 100644
index 0000000000..a40a9def9c
--- /dev/null
+++ b/songdbj/com/jcraft/jogg/Buffer.java
@@ -0,0 +1,541 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jogg;
+
+public class Buffer{
+ private static final int BUFFER_INCREMENT=256;
+
+ private static final int[] mask={
+ 0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
+ 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
+ 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,
+ 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
+ 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff,
+ 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
+ 0x3fffffff,0x7fffffff,0xffffffff
+ };
+
+ int ptr=0;
+ byte[] buffer=null;
+ int endbit=0;
+ int endbyte=0;
+ int storage=0;
+
+ public void writeinit(){
+ buffer=new byte[BUFFER_INCREMENT];
+ ptr=0;
+ buffer[0]=(byte)'\0';
+ storage=BUFFER_INCREMENT;
+ }
+
+ public void write(byte[] s){
+ for(int i=0; i<s.length; i++){
+ if(s[i]==0)break;
+ write(s[i],8);
+ }
+ }
+
+ public void read(byte[] s, int bytes){
+ int i=0;
+ while(bytes--!=0){
+ s[i++]=(byte)(read(8));
+ }
+ }
+
+ void reset(){
+ ptr=0;
+ buffer[0]=(byte)'\0';
+ endbit=endbyte=0;
+ }
+
+ public void writeclear(){
+ buffer=null;
+ }
+
+ public void readinit(byte[] buf, int bytes){
+ readinit(buf, 0, bytes);
+ }
+
+ public void readinit(byte[] buf, int start, int bytes){
+//System.err.println("readinit: start="+start+", bytes="+bytes);
+//for(int i=0;i<bytes; i++){
+//System.err.println(i+": "+Integer.toHexString(buf[i+start]));
+//}
+ ptr=start;
+ buffer=buf;
+ endbit=endbyte=0;
+ storage=bytes;
+ }
+
+ public void write(int value, int bits){
+//System.err.println("write: "+Integer.toHexString(value)+", bits="+bits+" ptr="+ptr+", storage="+storage+", endbyte="+endbyte);
+ if(endbyte+4>=storage){
+ byte[] foo=new byte[storage+BUFFER_INCREMENT];
+ System.arraycopy(buffer, 0, foo, 0, storage);
+ buffer=foo;
+ storage+=BUFFER_INCREMENT;
+ }
+
+ value&=mask[bits];
+ bits+=endbit;
+ buffer[ptr]|=(byte)(value<<endbit);
+
+ if(bits>=8){
+ buffer[ptr+1]=(byte)(value>>>(8-endbit));
+ if(bits>=16){
+ buffer[ptr+2]=(byte)(value>>>(16-endbit));
+ if(bits>=24){
+ buffer[ptr+3]=(byte)(value>>>(24-endbit));
+ if(bits>=32){
+ if(endbit>0)
+ buffer[ptr+4]=(byte)(value>>>(32-endbit));
+ else
+ buffer[ptr+4]=0;
+ }
+ }
+ }
+ }
+
+ endbyte+=bits/8;
+ ptr+=bits/8;
+ endbit=bits&7;
+ }
+
+ public int look(int bits){
+ int ret;
+ int m=mask[bits];
+
+ bits+=endbit;
+
+//System.err.println("look ptr:"+ptr+", bits="+bits+", endbit="+endbit+", storage="+storage);
+
+ if(endbyte+4>=storage){
+ if(endbyte+(bits-1)/8>=storage)return(-1);
+ }
+
+ ret=((buffer[ptr])&0xff)>>>endbit;
+// ret=((byte)(buffer[ptr]))>>>endbit;
+ if(bits>8){
+ ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
+// ret|=((byte)(buffer[ptr+1]))<<(8-endbit);
+ if(bits>16){
+ ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
+// ret|=((byte)(buffer[ptr+2]))<<(16-endbit);
+ if(bits>24){
+ ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
+//System.err.print("ret="+Integer.toHexString(ret)+", ((byte)(buffer[ptr+3]))="+Integer.toHexString(((buffer[ptr+3])&0xff)));
+// ret|=((byte)(buffer[ptr+3]))<<(24-endbit);
+//System.err.println(" ->ret="+Integer.toHexString(ret));
+ if(bits>32 && endbit!=0){
+ ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
+// ret|=((byte)(buffer[ptr+4]))<<(32-endbit);
+ }
+ }
+ }
+ }
+ return(m&ret);
+ }
+
+ public int look1(){
+ if(endbyte>=storage)return(-1);
+ return((buffer[ptr]>>endbit)&1);
+ }
+
+ public void adv(int bits){
+ bits+=endbit;
+ ptr+=bits/8;
+ endbyte+=bits/8;
+ endbit=bits&7;
+ }
+
+ public void adv1(){
+ ++endbit;
+ if(endbit>7){
+ endbit=0;
+ ptr++;
+ endbyte++;
+ }
+ }
+
+ public int read(int bits){
+//System.err.println(this+" read: bits="+bits+", storage="+storage+", endbyte="+endbyte);
+//System.err.println(this+" read: bits="+bits+", storage="+storage+", endbyte="+endbyte+
+// ", ptr="+ptr+", endbit="+endbit+", buf[ptr]="+buffer[ptr]);
+
+ int ret;
+ int m=mask[bits];
+
+ bits+=endbit;
+
+ if(endbyte+4>=storage){
+ ret=-1;
+ if(endbyte+(bits-1)/8>=storage){
+ ptr+=bits/8;
+ endbyte+=bits/8;
+ endbit=bits&7;
+ return(ret);
+ }
+ }
+
+/*
+ ret=(byte)(buffer[ptr]>>>endbit);
+ if(bits>8){
+ ret|=(buffer[ptr+1]<<(8-endbit));
+ if(bits>16){
+ ret|=(buffer[ptr+2]<<(16-endbit));
+ if(bits>24){
+ ret|=(buffer[ptr+3]<<(24-endbit));
+ if(bits>32 && endbit>0){
+ ret|=(buffer[ptr+4]<<(32-endbit));
+ }
+ }
+ }
+ }
+*/
+ ret=((buffer[ptr])&0xff)>>>endbit;
+ if(bits>8){
+ ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
+// ret|=((byte)(buffer[ptr+1]))<<(8-endbit);
+ if(bits>16){
+ ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
+// ret|=((byte)(buffer[ptr+2]))<<(16-endbit);
+ if(bits>24){
+ ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
+// ret|=((byte)(buffer[ptr+3]))<<(24-endbit);
+ if(bits>32 && endbit!=0){
+ ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
+// ret|=((byte)(buffer[ptr+4]))<<(32-endbit);
+ }
+ }
+ }
+ }
+
+ ret&=m;
+
+ ptr+=bits/8;
+// ptr=bits/8;
+ endbyte+=bits/8;
+// endbyte=bits/8;
+ endbit=bits&7;
+ return(ret);
+ }
+
+ public int readB(int bits){
+ //System.err.println(this+" read: bits="+bits+", storage="+storage+", endbyte="+endbyte+
+ // ", ptr="+ptr+", endbit="+endbit+", buf[ptr]="+buffer[ptr]);
+ int ret;
+ int m=32-bits;
+
+ bits+=endbit;
+
+ if(endbyte+4>=storage){
+ /* not the main path */
+ ret=-1;
+ if(endbyte*8+bits>storage*8) {
+ ptr+=bits/8;
+ endbyte+=bits/8;
+ endbit=bits&7;
+ return(ret);
+ }
+ }
+
+ ret=(buffer[ptr]&0xff)<<(24+endbit);
+ if(bits>8){
+ ret|=(buffer[ptr+1]&0xff)<<(16+endbit);
+ if(bits>16){
+ ret|=(buffer[ptr+2]&0xff)<<(8+endbit);
+ if(bits>24){
+ ret|=(buffer[ptr+3]&0xff)<<(endbit);
+ if(bits>32 && (endbit != 0))
+ ret|=(buffer[ptr+4]&0xff)>>(8-endbit);
+ }
+ }
+ }
+ ret=(ret>>>(m>>1))>>>((m+1)>>1);
+
+ ptr+=bits/8;
+ endbyte+=bits/8;
+ endbit=bits&7;
+ return(ret);
+ }
+
+ public int read1(){
+ int ret;
+ if(endbyte>=storage){
+ ret=-1;
+ endbit++;
+ if(endbit>7){
+ endbit=0;
+ ptr++;
+ endbyte++;
+ }
+ return(ret);
+ }
+
+ ret=(buffer[ptr]>>endbit)&1;
+
+ endbit++;
+ if(endbit>7){
+ endbit=0;
+ ptr++;
+ endbyte++;
+ }
+ return(ret);
+ }
+
+ public int bytes(){
+ return(endbyte+(endbit+7)/8);
+ }
+
+ public int bits(){
+ return(endbyte*8+endbit);
+ }
+
+ public byte[] buffer(){
+ return(buffer);
+ }
+
+ public static int ilog(int v){
+ int ret=0;
+ while(v>0){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+
+ public static void report(String in){
+ System.err.println(in);
+ System.exit(1);
+ }
+
+ /*
+ static void cliptest(int[] b, int vals, int bits, int[] comp, int compsize){
+ int bytes;
+ byte[] buffer;
+
+ o.reset();
+ for(int i=0;i<vals;i++){
+ o.write(b[i],((bits!=0)?bits:ilog(b[i])));
+ }
+ buffer=o.buffer();
+ bytes=o.bytes();
+System.err.println("cliptest: bytes="+bytes);
+ if(bytes!=compsize)report("wrong number of bytes!\n");
+ for(int i=0;i<bytes;i++){
+ if(buffer[i]!=(byte)comp[i]){
+ for(int j=0;j<bytes;j++){
+ System.err.println(j+": "+Integer.toHexString(buffer[j])+" "+
+ Integer.toHexString(comp[j]));
+ }
+ report("wrote incorrect value!\n");
+ }
+ }
+System.err.println("bits: "+bits);
+ r.readinit(buffer,bytes);
+ for(int i=0;i<vals;i++){
+ int tbit=(bits!=0)?bits:ilog(b[i]);
+System.err.println(Integer.toHexString(b[i])+" tbit: "+tbit);
+ if(r.look(tbit)==-1){
+ report("out of data!\n");
+ }
+ if(r.look(tbit)!=(b[i]&mask[tbit])){
+ report(i+" looked at incorrect value! "+Integer.toHexString(r.look(tbit))+", "+Integer.toHexString(b[i]&mask[tbit])+":"+b[i]+" bit="+tbit);
+ }
+ if(tbit==1){
+ if(r.look1()!=(b[i]&mask[tbit])){
+ report("looked at single bit incorrect value!\n");
+ }
+ }
+ if(tbit==1){
+ if(r.read1()!=(b[i]&mask[tbit])){
+ report("read incorrect single bit value!\n");
+ }
+ }
+ else{
+ if(r.read(tbit)!=(b[i]&mask[tbit])){
+ report("read incorrect value!\n");
+ }
+ }
+ }
+ if(r.bytes()!=bytes){
+ report("leftover bytes after read!\n");
+ }
+ }
+
+ static int[] testbuffer1=
+ {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
+ 567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
+ static int test1size=43;
+
+ static int[] testbuffer2=
+ {216531625,1237861823,56732452,131,3212421,12325343,34547562,12313212,
+ 1233432,534,5,346435231,14436467,7869299,76326614,167548585,
+ 85525151,0,12321,1,349528352};
+ static int test2size=21;
+
+ static int[] large=
+ {2136531625,2137861823,56732452,131,3212421,12325343,34547562,12313212,
+ 1233432,534,5,2146435231,14436467,7869299,76326614,167548585,
+ 85525151,0,12321,1,2146528352};
+
+ static int[] testbuffer3=
+ {1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1,
+ 0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1};
+ static int test3size=56;
+
+ static int onesize=33;
+ static int[] one={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40,
+ 34,242,223,136,35,222,211,86,171,50,225,135,214,75,172,
+ 223,4};
+
+ static int twosize=6;
+ static int[] two={61,255,255,251,231,29};
+
+ static int threesize=54;
+ static int[] three={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254,
+ 142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83,
+ 58,135,196,61,55,129,183,54,101,100,170,37,127,126,10,
+ 100,52,4,14,18,86,77,1};
+
+ static int foursize=38;
+ static int[] four={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72,
+ 132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169,
+ 28,2,133,0,1};
+
+ static int fivesize=45;
+ static int[] five={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62,
+ 241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169,
+ 84,75,159,2,1,0,132,192,8,0,0,18,22};
+
+ static int sixsize=7;
+ static int[] six={17,177,170,242,169,19,148};
+
+ static Buffer o=new Buffer();
+ static Buffer r=new Buffer();
+
+ public static void main(String[] arg){
+ byte[] buffer;
+ int bytes;
+// o=new Buffer();
+// r=new Buffer();
+
+ o.writeinit();
+
+ System.err.print("\nSmall preclipped packing: ");
+ cliptest(testbuffer1,test1size,0,one,onesize);
+ System.err.print("ok.");
+
+ System.err.print("\nNull bit call: ");
+ cliptest(testbuffer3,test3size,0,two,twosize);
+ System.err.print("ok.");
+
+ System.err.print("\nLarge preclipped packing: ");
+ cliptest(testbuffer2,test2size,0,three,threesize);
+ System.err.print("ok.");
+
+ System.err.print("\n32 bit preclipped packing: ");
+ o.reset();
+ for(int i=0;i<test2size;i++)
+ o.write(large[i],32);
+ buffer=o.buffer();
+ bytes=o.bytes();
+
+
+ r.readinit(buffer,bytes);
+ for(int i=0;i<test2size;i++){
+ if(r.look(32)==-1){
+ report("out of data. failed!");
+ }
+ if(r.look(32)!=large[i]){
+ System.err.print(r.look(32)+" != "+large[i]+" ("+
+ Integer.toHexString(r.look(32))+"!="+
+ Integer.toHexString(large[i])+")");
+ report("read incorrect value!\n");
+ }
+ r.adv(32);
+ }
+ if(r.bytes()!=bytes)report("leftover bytes after read!\n");
+ System.err.print("ok.");
+
+ System.err.print("\nSmall unclipped packing: ");
+ cliptest(testbuffer1,test1size,7,four,foursize);
+ System.err.print("ok.");
+
+ System.err.print("\nLarge unclipped packing: ");
+ cliptest(testbuffer2,test2size,17,five,fivesize);
+ System.err.print("ok.");
+
+ System.err.print("\nSingle bit unclicpped packing: ");
+ cliptest(testbuffer3,test3size,1,six,sixsize);
+ System.err.print("ok.");
+
+ System.err.print("\nTesting read past end: ");
+ r.readinit("\0\0\0\0\0\0\0\0".getBytes(),8);
+ for(int i=0;i<64;i++){
+ if(r.read(1)!=0){
+ System.err.print("failed; got -1 prematurely.\n");
+ System.exit(1);
+ }
+ }
+
+ if(r.look(1)!=-1 ||
+ r.read(1)!=-1){
+ System.err.print("failed; read past end without -1.\n");
+ System.exit(1);
+ }
+
+ r.readinit("\0\0\0\0\0\0\0\0".getBytes(),8);
+ if(r.read(30)!=0 || r.read(16)!=0){
+ System.err.print("failed 2; got -1 prematurely.\n");
+ System.exit(1);
+ }
+
+ if(r.look(18)!=0 ||
+ r.look(18)!=0){
+ System.err.print("failed 3; got -1 prematurely.\n");
+ System.exit(1);
+ }
+ if(r.look(19)!=-1 ||
+ r.look(19)!=-1){
+ System.err.print("failed; read past end without -1.\n");
+ System.exit(1);
+ }
+ if(r.look(32)!=-1 ||
+ r.look(32)!=-1){
+ System.err.print("failed; read past end without -1.\n");
+ System.exit(1);
+ }
+ System.err.print("ok.\n\n");
+ }
+ */
+}
+
+
+
+
+
diff --git a/songdbj/com/jcraft/jogg/Packet.java b/songdbj/com/jcraft/jogg/Packet.java
new file mode 100644
index 0000000000..22a8a5439b
--- /dev/null
+++ b/songdbj/com/jcraft/jogg/Packet.java
@@ -0,0 +1,82 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jogg;
+
+public class Packet{
+ public byte[] packet_base;
+ public int packet;
+ public int bytes;
+ public int b_o_s;
+ public int e_o_s;
+
+ public long granulepos;
+
+ public long packetno; // sequence number for decode; the framing
+ // knows where there's a hole in the data,
+ // but we need coupling so that the codec
+ // (which is in a seperate abstraction
+ // layer) also knows about the gap
+
+ /*
+ // TEST
+ static int sequence=0;
+ static int lastno=0;
+ void checkpacket(int len, int no, int pos){
+ if(bytes!=len){
+ System.err.println("incorrect packet length!");
+ System.exit(1);
+ }
+ if(granulepos!=pos){
+ System.err.println("incorrect packet position!");
+ System.exit(1);
+ }
+
+ // packet number just follows sequence/gap; adjust the input number
+ // for that
+ if(no==0){
+ sequence=0;
+ }
+ else{
+ sequence++;
+ if(no>lastno+1)
+ sequence++;
+ }
+ lastno=no;
+ if(packetno!=sequence){
+ System.err.println("incorrect packet sequence "+packetno+" != "+sequence);
+ System.exit(1);
+ }
+
+ // Test data
+ for(int j=0;j<bytes;j++){
+ if((packet_base[packet+j]&0xff)!=((j+no)&0xff)){
+ System.err.println("body data mismatch at pos "+ j+": "+(packet_base[packet+j]&0xff)+"!="+((j+no)&0xff)+"!\n");
+ System.exit(1);
+ }
+ }
+ }
+ */
+}
diff --git a/songdbj/com/jcraft/jogg/Page.java b/songdbj/com/jcraft/jogg/Page.java
new file mode 100644
index 0000000000..fc1add010e
--- /dev/null
+++ b/songdbj/com/jcraft/jogg/Page.java
@@ -0,0 +1,973 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jogg;
+
+public class Page{
+ private static int[] crc_lookup=new int[256];
+ static {
+ for(int i=0; i<crc_lookup.length; i++){
+ crc_lookup[i]=crc_entry(i);
+ }
+ }
+
+ private static int crc_entry(int index){
+ int r=index<<24;
+ for(int i=0; i<8; i++){
+ if((r& 0x80000000)!=0){
+ r=(r << 1)^0x04c11db7; /* The same as the ethernet generator
+ polynomial, although we use an
+ unreflected alg and an init/final
+ of 0, not 0xffffffff */
+ }
+ else{
+ r<<=1;
+ }
+ }
+ return(r&0xffffffff);
+ }
+
+ public byte[] header_base;
+ public int header;
+ public int header_len;
+ public byte[] body_base;
+ public int body;
+ public int body_len;
+
+ int version(){
+ return header_base[header+4]&0xff;
+ }
+ int continued(){
+ return (header_base[header+5]&0x01);
+ }
+ public int bos(){
+ return (header_base[header+5]&0x02);
+ }
+ public int eos(){
+ return (header_base[header+5]&0x04);
+ }
+ public long granulepos(){
+ long foo=header_base[header+13]&0xff;
+ foo=(foo<<8)|(header_base[header+12]&0xff);
+ foo=(foo<<8)|(header_base[header+11]&0xff);
+ foo=(foo<<8)|(header_base[header+10]&0xff);
+ foo=(foo<<8)|(header_base[header+9]&0xff);
+ foo=(foo<<8)|(header_base[header+8]&0xff);
+ foo=(foo<<8)|(header_base[header+7]&0xff);
+ foo=(foo<<8)|(header_base[header+6]&0xff);
+ return(foo);
+ }
+ public int serialno(){
+ return (header_base[header+14]&0xff)|
+ ((header_base[header+15]&0xff)<<8)|
+ ((header_base[header+16]&0xff)<<16)|
+ ((header_base[header+17]&0xff)<<24);
+ }
+ int pageno(){
+ return (header_base[header+18]&0xff)|
+ ((header_base[header+19]&0xff)<<8)|
+ ((header_base[header+20]&0xff)<<16)|
+ ((header_base[header+21]&0xff)<<24);
+ }
+
+ void checksum(){
+ int crc_reg=0;
+
+// for(int i=0;i<header_len;i++){
+// System.err.println("chksum: "+Integer.toHexString(header_base[header+i]&0xff));
+// }
+
+ for(int i=0;i<header_len;i++){
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg>>>24)&0xff)^(header_base[header+i]&0xff)];
+ }
+ for(int i=0;i<body_len;i++){
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg>>>24)&0xff)^(body_base[body+i]&0xff)];
+ }
+ header_base[header+22]=(byte)crc_reg/*&0xff*/;
+ header_base[header+23]=(byte)(crc_reg>>>8)/*&0xff*/;
+ header_base[header+24]=(byte)(crc_reg>>>16)/*&0xff*/;
+ header_base[header+25]=(byte)(crc_reg>>>24)/*&0xff*/;
+ }
+ public Page copy(){
+ return copy(new Page());
+ }
+ public Page copy(Page p){
+ byte[] tmp=new byte[header_len];
+ System.arraycopy(header_base, header, tmp, 0, header_len);
+ p.header_len=header_len;
+ p.header_base=tmp;
+ p.header=0;
+ tmp=new byte[body_len];
+ System.arraycopy(body_base, body, tmp, 0, body_len);
+ p.body_len=body_len;
+ p.body_base=tmp;
+ p.body=0;
+ return p;
+ }
+ /*
+ // TEST
+ static StreamState os_en, os_de;
+ static SyncState oy;
+ void check_page(byte[] data_base, int data, int[] _header){
+ // Test data
+ for(int j=0;j<body_len;j++)
+ if(body_base[body+j]!=data_base[data+j]){
+ System.err.println("body data mismatch at pos "+j+": "+data_base[data+j]+"!="+body_base[body+j]+"!\n");
+ System.exit(1);
+ }
+
+ // Test header
+ for(int j=0;j<header_len;j++){
+ if((header_base[header+j]&0xff)!=_header[j]){
+ System.err.println("header content mismatch at pos "+j);
+ for(int jj=0;jj<_header[26]+27;jj++)
+ System.err.print(" ("+jj+")"+Integer.toHexString(_header[jj])+":"+Integer.toHexString(header_base[header+jj]));
+ System.err.println("");
+ System.exit(1);
+ }
+ }
+ if(header_len!=_header[26]+27){
+ System.err.print("header length incorrect! ("+header_len+"!="+(_header[26]+27)+")");
+ System.exit(1);
+ }
+ }
+
+ void print_header(){
+ System.err.println("\nHEADER:");
+ System.err.println(" capture: "+
+ (header_base[header+0]&0xff)+" "+
+ (header_base[header+1]&0xff)+" "+
+ (header_base[header+2]&0xff)+" "+
+ (header_base[header+3]&0xff)+" "+
+ " version: "+(header_base[header+4]&0xff)+" flags: "+
+ (header_base[header+5]&0xff));
+ System.err.println(" pcmpos: "+
+ (((header_base[header+9]&0xff)<<24)|
+ ((header_base[header+8]&0xff)<<16)|
+ ((header_base[header+7]&0xff)<<8)|
+ ((header_base[header+6]&0xff)))+
+ " serialno: "+
+ (((header_base[header+17]&0xff)<<24)|
+ ((header_base[header+16]&0xff)<<16)|
+ ((header_base[header+15]&0xff)<<8)|
+ ((header_base[header+14]&0xff)))+
+ " pageno: "+
+ (((header_base[header+21]&0xff)<<24)|
+ ((header_base[header+20]&0xff)<<16)|
+ ((header_base[header+19]&0xff)<<8)|
+ ((header_base[header+18]&0xff))));
+
+ System.err.println(" checksum: "+
+ (header_base[header+22]&0xff)+":"+
+ (header_base[header+23]&0xff)+":"+
+ (header_base[header+24]&0xff)+":"+
+ (header_base[header+25]&0xff)+"\n segments: "+
+ (header_base[header+26]&0xff)+" (");
+ for(int j=27;j<header_len;j++){
+ System.err.println((header_base[header+j]&0xff)+" ");
+ }
+ System.err.println(")\n");
+ }
+
+ void copy_page(){
+ byte[] tmp=new byte[header_len];
+ System.arraycopy(header_base, header, tmp, 0, header_len);
+ header_base=tmp;
+ header=0;
+ tmp=new byte[body_len];
+ System.arraycopy(body_base, body, tmp, 0, body_len);
+ body_base=tmp;
+ body=0;
+ }
+
+ static void test_pack(int[] pl, int[][] headers){
+ byte[] data=new byte[1024*1024]; // for scripted test cases only
+ int inptr=0;
+ int outptr=0;
+ int deptr=0;
+ int depacket=0;
+ int pcm_pos=7;
+ int packets,pageno=0,pageout=0;
+ int eosflag=0;
+ int bosflag=0;
+
+ os_en.reset();
+ os_de.reset();
+ oy.reset();
+
+ for(packets=0;;packets++){
+ if(pl[packets]==-1)break;
+ }
+
+ for(int i=0;i<packets;i++){
+ // construct a test packet
+ Packet op=new Packet();
+ int len=pl[i];
+ op.packet_base=data;
+ op.packet=inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=pcm_pos;
+
+ pcm_pos+=1024;
+
+ for(int j=0;j<len;j++){
+ data[inptr++]=(byte)(i+j);
+ }
+
+ // submit the test packet
+ os_en.packetin(op);
+
+ // retrieve any finished pages
+ {
+ Page og=new Page();
+
+ while(os_en.pageout(og)!=0){
+ // We have a page. Check it carefully
+ //System.err.print(pageno+", ");
+ if(headers[pageno]==null){
+ System.err.println("coded too many pages!");
+ System.exit(1);
+ }
+ og.check_page(data, outptr, headers[pageno]);
+
+ outptr+=og.body_len;
+ pageno++;
+
+//System.err.println("1# pageno="+pageno+", pageout="+pageout);
+
+ // have a complete page; submit it to sync/decode
+
+ {
+ Page og_de=new Page();
+ Packet op_de=new Packet();
+ int index=oy.buffer(og.header_len+og.body_len);
+ byte[] buf=oy.data;
+ System.arraycopy(og.header_base, og.header, buf, index, og.header_len);
+ System.arraycopy(og.body_base, og.body, buf, index+og.header_len, og.body_len);
+ oy.wrote(og.header_len+og.body_len);
+
+//System.err.println("2# pageno="+pageno+", pageout="+pageout);
+
+ while(oy.pageout(og_de)>0){
+ // got a page. Happy happy. Verify that it's good.
+
+ og_de.check_page(data, deptr, headers[pageout]);
+ deptr+=og_de.body_len;
+ pageout++;
+
+ // submit it to deconstitution
+ os_de.pagein(og_de);
+
+ // packets out?
+ while(os_de.packetout(op_de)>0){
+
+ // verify the packet!
+ // check data
+ boolean check=false;
+ for(int ii=0; ii<op_de.bytes; ii++){
+ if(data[depacket+ii]!=op_de.packet_base[op_de.packet+ii]){
+ check=true;
+ break;
+ }
+ }
+ if(check){
+ System.err.println("packet data mismatch in decode! pos="+
+ depacket);
+ System.exit(1);
+ }
+
+ // check bos flag
+ if(bosflag==0 && op_de.b_o_s==0){
+ System.err.println("b_o_s flag not set on packet!");
+ System.exit(1);
+ }
+ if(bosflag!=0 && op_de.b_o_s!=0){
+ System.err.println("b_o_s flag incorrectly set on packet!");
+ System.exit(1);
+ }
+
+ bosflag=1;
+ depacket+=op_de.bytes;
+
+ // check eos flag
+ if(eosflag!=0){
+ System.err.println("Multiple decoded packets with eos flag!");
+ System.exit(1);
+ }
+
+ if(op_de.e_o_s!=0)eosflag=1;
+
+ // check pcmpos flag
+ if(op_de.granulepos!=-1){
+ System.err.print(" pcm:"+op_de.granulepos+" ");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ //free(data);
+ if(headers[pageno]!=null){
+ System.err.println("did not write last page!");
+ System.exit(1);
+ }
+ if(headers[pageout]!=null){
+ System.err.println("did not decode last page!");
+ System.exit(1);
+ }
+ if(inptr!=outptr){
+ System.err.println("encoded page data incomplete!");
+ System.exit(1);
+ }
+ if(inptr!=deptr){
+ System.err.println("decoded page data incomplete!");
+ System.exit(1);
+ }
+ if(inptr!=depacket){
+ System.err.println("decoded packet data incomplete!");
+ System.exit(1);
+ }
+ if(eosflag==0){
+ System.err.println("Never got a packet with EOS set!");
+ }
+ System.err.println("ok.");
+ }
+
+ static void error(){
+ System.err.println("error!");
+ System.exit(1);
+ }
+ public static void main(String[] arg){
+
+ os_en=new StreamState(0x04030201);
+ os_de=new StreamState(0x04030201);
+
+ oy=new SyncState();
+
+ // Exercise each code path in the framing code. Also verify that
+ // the checksums are working.
+
+ {
+ // 17 only
+ int[] packets={17, -1};
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x06,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x15,0xed,0xec,0x91,
+ 1,
+ 17};
+ int[][] headret={head1, null};
+
+ System.err.print("testing single page encoding... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // 17, 254, 255, 256, 500, 510, 600 byte, pad
+ int[] packets={17, 254, 255, 256, 500, 510, 600, -1};
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x59,0x10,0x6c,0x2c,
+ 1,
+ 17};
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x89,0x33,0x85,0xce,
+ 13,
+ 254,255,0,255,1,255,245,255,255,0,
+ 255,255,90};
+ int[][] headret={head1,head2,null};
+
+ System.err.print("testing basic page encoding... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // nil packets; beginning,middle,end
+ int[] packets={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x5c,0x3f,0x66,0xcb,
+ 17,
+ 17,254,255,0,0,255,1,0,255,245,255,255,0,
+ 255,255,90,0};
+ int[][] headret={head1,head2,null};
+
+ System.err.print("testing basic nil packets... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // large initial packet
+ int[] packets={4345,259,255,-1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x01,0x27,0x31,0xaa,
+ 18,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,10};
+
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x7f,0x4e,0x8a,0xd2,
+ 4,
+ 255,4,255,0};
+ int[][] headret={head1,head2,null};
+
+ System.err.print("testing initial-packet lacing > 4k... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // continuing packet test
+ int[] packets={0,4345,259,255,-1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x34,0x24,0xd5,0x29,
+ 17,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255};
+
+ int[] head3={0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xc8,0xc3,0xcb,0xed,
+ 5,
+ 10,255,4,255,0};
+ int[][] headret={head1,head2,head3,null};
+
+ System.err.print("testing single packet page span... ");
+ test_pack(packets,headret);
+ }
+
+ // page with the 255 segment limit
+ {
+
+ int[] packets={0,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,50,-1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xed,0x2a,0x2e,0xa7,
+ 255,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10};
+
+ int[] head3={0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x6c,0x3b,0x82,0x3d,
+ 1,
+ 50};
+ int[][] headret={head1,head2,head3,null};
+
+ System.err.print("testing max packet segments... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // packet that overspans over an entire page
+
+ int[] packets={0,100,9000,259,255,-1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x3c,0xd9,0x4d,0x3f,
+ 17,
+ 100,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+
+ int[] head3={0x4f,0x67,0x67,0x53,0,0x01,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xbd,0xd5,0xb5,0x8b,
+ 17,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255};
+
+ int[] head4={0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,3,0,0,0,
+ 0xef,0xdd,0x88,0xde,
+ 7,
+ 255,255,75,255,4,255,0};
+ int[][] headret={head1,head2,head3,head4,null};
+
+ System.err.print("testing very large packets... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // term only page. why not?
+
+ int[] packets={0,100,4080,-1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x3c,0xd9,0x4d,0x3f,
+ 17,
+ 100,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+
+ int[] head3={0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xd4,0xe0,0x60,0xe5,
+ 1,0};
+
+ int[][] headret={head1,head2,head3,null};
+
+ System.err.print("testing zero data page (1 nil packet)... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // build a bunch of pages for testing
+ byte[] data=new byte[1024*1024];
+ int[] pl={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
+ int inptr=0;
+ Page[] og=new Page[5];
+ for(int i=0; i<5; i++){
+ og[i]=new Page();
+ }
+
+ os_en.reset();
+
+ for(int i=0;pl[i]!=-1;i++){
+ Packet op=new Packet();
+ int len=pl[i];
+
+ op.packet_base=data;
+ op.packet=inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=(i+1)*1000;
+
+ for(int j=0;j<len;j++)data[inptr++]=(byte)(i+j);
+ os_en.packetin(op);
+ }
+
+// free(data);
+
+ // retrieve finished pages
+ for(int i=0;i<5;i++){
+ if(os_en.pageout(og[i])==0){
+ System.err.print("Too few pages output building sync tests!\n");
+ System.exit(1);
+ }
+ og[i].copy_page();
+ }
+
+ // Test lost pages on pagein/packetout: no rollback
+ {
+ Page temp=new Page();
+ Packet test=new Packet();
+
+ System.err.print("Testing loss of pages... ");
+
+ oy.reset();
+ os_de.reset();
+ for(int i=0;i<5;i++){
+ int index=oy.buffer(og[i].header_len);
+ System.arraycopy(og[i].header_base, og[i].header,
+ oy.data, index, og[i].header_len);
+ oy.wrote(og[i].header_len);
+ index=oy.buffer(og[i].body_len);
+ System.arraycopy(og[i].body_base, og[i].body,
+ oy.data, index, og[i].body_len);
+ oy.wrote(og[i].body_len);
+ }
+
+ oy.pageout(temp);
+ os_de.pagein(temp);
+ oy.pageout(temp);
+ os_de.pagein(temp);
+ oy.pageout(temp);
+
+ // skip
+ oy.pageout(temp);
+ os_de.pagein(temp);
+
+ // do we get the expected results/packets?
+
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(0,0,0);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(100,1,-1);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(4079,2,3000);
+ if(os_de.packetout(test)!=-1){
+ System.err.println("Error: loss of page did not return error");
+ System.exit(1);
+ }
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(76,5,-1);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(34,6,-1);
+ System.err.println("ok.");
+ }
+
+ // Test lost pages on pagein/packetout: rollback with continuation
+ {
+ Page temp=new Page();
+ Packet test=new Packet();
+
+ System.err.print("Testing loss of pages (rollback required)... ");
+
+ oy.reset();
+ os_de.reset();
+ for(int i=0;i<5;i++){
+ int index=oy.buffer(og[i].header_len);
+ System.arraycopy(og[i].header_base, og[i].header,
+ oy.data, index, og[i].header_len);
+ oy.wrote(og[i].header_len);
+ index=oy.buffer(og[i].body_len);
+ System.arraycopy(og[i].body_base, og[i].body,
+ oy.data, index, og[i].body_len);
+ oy.wrote(og[i].body_len);
+ }
+
+ oy.pageout(temp);
+ os_de.pagein(temp);
+ oy.pageout(temp);
+ os_de.pagein(temp);
+ oy.pageout(temp);
+ os_de.pagein(temp);
+ oy.pageout(temp);
+ // skip
+ oy.pageout(temp);
+ os_de.pagein(temp);
+
+ // do we get the expected results/packets?
+
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(0,0,0);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(100,1,-1);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(4079,2,3000);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(2956,3,4000);
+ if(os_de.packetout(test)!=-1){
+ System.err.println("Error: loss of page did not return error");
+ System.exit(1);
+ }
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(300,13,14000);
+ System.err.println("ok.");
+ }
+
+ // the rest only test sync
+ {
+ Page og_de=new Page();
+ // Test fractional page inputs: incomplete capture
+ System.err.print("Testing sync on partial inputs... ");
+ oy.reset();
+ int index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header,
+ oy.data, index, 3);
+ oy.wrote(3);
+ if(oy.pageout(og_de)>0)error();
+
+ // Test fractional page inputs: incomplete fixed header
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header+3,
+ oy.data, index, 20);
+
+ oy.wrote(20);
+ if(oy.pageout(og_de)>0)error();
+
+ // Test fractional page inputs: incomplete header
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header+23,
+ oy.data, index, 5);
+ oy.wrote(5);
+ if(oy.pageout(og_de)>0)error();
+
+ // Test fractional page inputs: incomplete body
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header+28,
+ oy.data, index, og[1].header_len-28);
+ oy.wrote(og[1].header_len-28);
+ if(oy.pageout(og_de)>0)error();
+
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, 1000);
+ oy.wrote(1000);
+ if(oy.pageout(og_de)>0)error();
+
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body+1000,
+ oy.data, index, og[1].body_len-1000);
+ oy.wrote(og[1].body_len-1000);
+ if(oy.pageout(og_de)<=0)error();
+ System.err.println("ok.");
+ }
+
+ // Test fractional page inputs: page + incomplete capture
+ {
+ Page og_de=new Page();
+ System.err.print("Testing sync on 1+partial inputs... ");
+ oy.reset();
+
+ int index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header,
+ oy.data, index, og[1].header_len);
+ oy.wrote(og[1].header_len);
+
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, og[1].body_len);
+ oy.wrote(og[1].body_len);
+
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header,
+ oy.data, index, 20);
+ oy.wrote(20);
+ if(oy.pageout(og_de)<=0)error();
+ if(oy.pageout(og_de)>0)error();
+
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header+20,
+ oy.data, index, og[1].header_len-20);
+ oy.wrote(og[1].header_len-20);
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, og[1].body_len);
+
+ oy.wrote(og[1].body_len);
+ if(oy.pageout(og_de)<=0)error();
+
+ System.err.println("ok.");
+ }
+
+// // // // // // // // //
+ // Test recapture: garbage + page
+ {
+ Page og_de=new Page();
+ System.err.print("Testing search for capture... ");
+ oy.reset();
+
+ // 'garbage'
+ int index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, og[1].body_len);
+ oy.wrote(og[1].body_len);
+
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header,
+ oy.data, index, og[1].header_len);
+ oy.wrote(og[1].header_len);
+
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, og[1].body_len);
+ oy.wrote(og[1].body_len);
+
+ index=oy.buffer(og[2].header_len);
+ System.arraycopy(og[2].header_base, og[2].header,
+ oy.data, index, 20);
+
+ oy.wrote(20);
+ if(oy.pageout(og_de)>0)error();
+ if(oy.pageout(og_de)<=0)error();
+ if(oy.pageout(og_de)>0)error();
+
+ index=oy.buffer(og[2].header_len);
+ System.arraycopy(og[2].header_base, og[2].header+20,
+ oy.data, index, og[2].header_len-20);
+ oy.wrote(og[2].header_len-20);
+ index=oy.buffer(og[2].body_len);
+ System.arraycopy(og[2].body_base, og[2].body,
+ oy.data, index, og[2].body_len);
+ oy.wrote(og[2].body_len);
+ if(oy.pageout(og_de)<=0)error();
+
+ System.err.println("ok.");
+ }
+
+ // Test recapture: page + garbage + page
+ {
+ Page og_de=new Page();
+ System.err.print("Testing recapture... ");
+ oy.reset();
+
+ int index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header,
+ oy.data, index, og[1].header_len);
+ oy.wrote(og[1].header_len);
+
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, og[1].body_len);
+ oy.wrote(og[1].body_len);
+
+ index=oy.buffer(og[2].header_len);
+ System.arraycopy(og[2].header_base, og[2].header,
+ oy.data, index, og[2].header_len);
+ oy.wrote(og[2].header_len);
+
+ index=oy.buffer(og[2].header_len);
+ System.arraycopy(og[2].header_base, og[2].header,
+ oy.data, index, og[2].header_len);
+ oy.wrote(og[2].header_len);
+
+ if(oy.pageout(og_de)<=0)error();
+
+ index=oy.buffer(og[2].body_len);
+ System.arraycopy(og[2].body_base, og[2].body,
+ oy.data, index, og[2].body_len-5);
+ oy.wrote(og[2].body_len-5);
+
+ index=oy.buffer(og[3].header_len);
+ System.arraycopy(og[3].header_base, og[3].header,
+ oy.data, index, og[3].header_len);
+ oy.wrote(og[3].header_len);
+
+ index=oy.buffer(og[3].body_len);
+ System.arraycopy(og[3].body_base, og[3].body,
+ oy.data, index, og[3].body_len);
+ oy.wrote(og[3].body_len);
+
+ if(oy.pageout(og_de)>0)error();
+ if(oy.pageout(og_de)<=0)error();
+
+ System.err.println("ok.");
+ }
+ }
+ //return(0);
+ }
+ */
+}
diff --git a/songdbj/com/jcraft/jogg/StreamState.java b/songdbj/com/jcraft/jogg/StreamState.java
new file mode 100644
index 0000000000..2f34b374f8
--- /dev/null
+++ b/songdbj/com/jcraft/jogg/StreamState.java
@@ -0,0 +1,657 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jogg;
+
+public class StreamState{
+ byte[] body_data; /* bytes from packet bodies */
+ int body_storage; /* storage elements allocated */
+ int body_fill; /* elements stored; fill mark */
+private int body_returned; /* elements of fill returned */
+
+
+ int[] lacing_vals; /* The values that will go to the segment table */
+ long[] granule_vals; /* pcm_pos values for headers. Not compact
+ this way, but it is simple coupled to the
+ lacing fifo */
+ int lacing_storage;
+ int lacing_fill;
+ int lacing_packet;
+ int lacing_returned;
+
+ byte[] header=new byte[282]; /* working space for header encode */
+ int header_fill;
+
+ public int e_o_s; /* set when we have buffered the last packet in the
+ logical bitstream */
+ int b_o_s; /* set after we've written the initial page
+ of a logical bitstream */
+ int serialno;
+ int pageno;
+ long packetno; /* sequence number for decode; the framing
+ knows where there's a hole in the data,
+ but we need coupling so that the codec
+ (which is in a seperate abstraction
+ layer) also knows about the gap */
+ long granulepos;
+
+ public StreamState(){
+ init();
+ }
+
+ StreamState(int serialno){
+ this();
+ init(serialno);
+ }
+ void init(){
+ body_storage=16*1024;
+ body_data=new byte[body_storage];
+ lacing_storage=1024;
+ lacing_vals=new int[lacing_storage];
+ granule_vals=new long[lacing_storage];
+ }
+ public void init(int serialno){
+ if(body_data==null){ init(); }
+ else{
+ for(int i=0; i<body_data.length; i++) body_data[i]=0;
+ for(int i=0; i<lacing_vals.length; i++) lacing_vals[i]=0;
+ for(int i=0; i<granule_vals.length; i++) granule_vals[i]=0;
+ }
+ this.serialno=serialno;
+ }
+ public void clear(){
+ body_data=null;
+ lacing_vals=null;
+ granule_vals=null;
+ //memset(os,0,sizeof(ogg_stream_state));
+ }
+ void destroy(){
+ clear();
+ }
+ void body_expand(int needed){
+ if(body_storage<=body_fill+needed){
+ body_storage+=(needed+1024);
+ byte[] foo=new byte[body_storage];
+ System.arraycopy(body_data, 0, foo, 0, body_data.length);
+ body_data=foo;
+//System.out.println("expand: body_fill="+body_fill+", body_storage="+body_data.length);
+ }
+ }
+ void lacing_expand(int needed){
+ if(lacing_storage<=lacing_fill+needed){
+ lacing_storage+=(needed+32);
+ int[] foo=new int[lacing_storage];
+ System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length);
+ lacing_vals=foo;
+
+ long[] bar=new long[lacing_storage];
+ System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
+ granule_vals=bar;
+ }
+ }
+
+ /* submit data to the internal buffer of the framing engine */
+ public int packetin(Packet op){
+ int lacing_val=op.bytes/255+1;
+
+ if(body_returned!=0){
+ /* advance packet data according to the body_returned pointer. We
+ had to keep it around to return a pointer into the buffer last
+ call */
+
+ body_fill-=body_returned;
+ if(body_fill!=0){
+// memmove(os->body_data,os->body_data+os->body_returned,
+// os->body_fill*sizeof(char));
+ System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
+ }
+ body_returned=0;
+ }
+
+ /* make sure we have the buffer storage */
+ body_expand(op.bytes);
+ lacing_expand(lacing_val);
+
+ /* Copy in the submitted packet. Yes, the copy is a waste; this is
+ the liability of overly clean abstraction for the time being. It
+ will actually be fairly easy to eliminate the extra copy in the
+ future */
+
+ System.arraycopy(op.packet_base, op.packet, body_data, body_fill, op.bytes);
+ body_fill+=op.bytes;
+//System.out.println("add: "+body_fill);
+
+ /* Store lacing vals for this packet */
+ int j;
+ for(j=0;j<lacing_val-1;j++){
+ lacing_vals[lacing_fill+j]=255;
+ granule_vals[lacing_fill+j]=granulepos;
+ }
+ lacing_vals[lacing_fill+j]=(op.bytes)%255;
+ granulepos=granule_vals[lacing_fill+j]=op.granulepos;
+
+ /* flag the first segment as the beginning of the packet */
+ lacing_vals[lacing_fill]|= 0x100;
+
+ lacing_fill+=lacing_val;
+
+ /* for the sake of completeness */
+ packetno++;
+
+ if(op.e_o_s!=0)e_o_s=1;
+ return(0);
+ }
+
+ public int packetout(Packet op){
+
+ /* The last part of decode. We have the stream broken into packet
+ segments. Now we need to group them into packets (or return the
+ out of sync markers) */
+
+ int ptr=lacing_returned;
+
+ if(lacing_packet<=ptr){
+ return(0);
+ }
+
+ if((lacing_vals[ptr]&0x400)!=0){
+ /* We lost sync here; let the app know */
+ lacing_returned++;
+
+ /* we need to tell the codec there's a gap; it might need to
+ handle previous packet dependencies. */
+ packetno++;
+ return(-1);
+ }
+
+ /* Gather the whole packet. We'll have no holes or a partial packet */
+ {
+ int size=lacing_vals[ptr]&0xff;
+ int bytes=0;
+
+ op.packet_base=body_data;
+ op.packet=body_returned;
+ op.e_o_s=lacing_vals[ptr]&0x200; /* last packet of the stream? */
+ op.b_o_s=lacing_vals[ptr]&0x100; /* first packet of the stream? */
+ bytes+=size;
+
+ while(size==255){
+ int val=lacing_vals[++ptr];
+ size=val&0xff;
+ if((val&0x200)!=0)op.e_o_s=0x200;
+ bytes+=size;
+ }
+
+ op.packetno=packetno;
+ op.granulepos=granule_vals[ptr];
+ op.bytes=bytes;
+
+//System.out.println(this+" # body_returned="+body_returned);
+ body_returned+=bytes;
+//System.out.println(this+"## body_returned="+body_returned);
+
+ lacing_returned=ptr+1;
+ }
+ packetno++;
+ return(1);
+ }
+
+
+ // add the incoming page to the stream state; we decompose the page
+ // into packet segments here as well.
+
+ public int pagein(Page og){
+ byte[] header_base=og.header_base;
+ int header=og.header;
+ byte[] body_base=og.body_base;
+ int body=og.body;
+ int bodysize=og.body_len;
+ int segptr=0;
+
+ int version=og.version();
+ int continued=og.continued();
+ int bos=og.bos();
+ int eos=og.eos();
+ long granulepos=og.granulepos();
+ int _serialno=og.serialno();
+ int _pageno=og.pageno();
+ int segments=header_base[header+26]&0xff;
+
+ // clean up 'returned data'
+ {
+ int lr=lacing_returned;
+ int br=body_returned;
+
+ // body data
+
+//System.out.println("br="+br+", body_fill="+body_fill);
+
+ if(br!=0){
+ body_fill-=br;
+ if(body_fill!=0){
+ System.arraycopy(body_data, br, body_data, 0, body_fill);
+ }
+ body_returned=0;
+ }
+
+//System.out.println("?? br="+br+", body_fill="+body_fill+" body_returned="+body_returned);
+
+ if(lr!=0){
+ // segment table
+ if((lacing_fill-lr)!=0){
+ System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill-lr);
+ System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill-lr);
+ }
+ lacing_fill-=lr;
+ lacing_packet-=lr;
+ lacing_returned=0;
+ }
+ }
+
+ // check the serial number
+ if(_serialno!=serialno)return(-1);
+ if(version>0)return(-1);
+
+ lacing_expand(segments+1);
+
+ // are we in sequence?
+ if(_pageno!=pageno){
+ int i;
+
+ // unroll previous partial packet (if any)
+ for(i=lacing_packet;i<lacing_fill;i++){
+ body_fill-=lacing_vals[i]&0xff;
+//System.out.println("??");
+ }
+ lacing_fill=lacing_packet;
+
+ // make a note of dropped data in segment table
+ if(pageno!=-1){
+ lacing_vals[lacing_fill++]=0x400;
+ lacing_packet++;
+ }
+
+ // are we a 'continued packet' page? If so, we'll need to skip
+ // some segments
+ if(continued!=0){
+ bos=0;
+ for(;segptr<segments;segptr++){
+ int val=(header_base[header+27+segptr]&0xff);
+ body+=val;
+ bodysize-=val;
+ if(val<255){
+ segptr++;
+ break;
+ }
+ }
+ }
+ }
+
+//System.out.println("bodysize="+bodysize);
+
+ if(bodysize!=0){
+ body_expand(bodysize);
+ System.arraycopy(body_base, body, body_data, body_fill, bodysize);
+ body_fill+=bodysize;
+ }
+
+//System.out.println("bodyfill="+body_fill);
+
+ {
+ int saved=-1;
+ while(segptr<segments){
+ int val=(header_base[header+27+segptr]&0xff);
+ lacing_vals[lacing_fill]=val;
+ granule_vals[lacing_fill]=-1;
+
+ if(bos!=0){
+ lacing_vals[lacing_fill]|=0x100;
+ bos=0;
+ }
+
+ if(val<255)saved=lacing_fill;
+
+ lacing_fill++;
+ segptr++;
+
+ if(val<255)lacing_packet=lacing_fill;
+ }
+
+ /* set the granulepos on the last pcmval of the last full packet */
+ if(saved!=-1){
+ granule_vals[saved]=granulepos;
+ }
+ }
+
+ if(eos!=0){
+ e_o_s=1;
+ if(lacing_fill>0)
+ lacing_vals[lacing_fill-1]|=0x200;
+ }
+
+ pageno=_pageno+1;
+ return(0);
+ }
+
+
+/* This will flush remaining packets into a page (returning nonzero),
+ even if there is not enough data to trigger a flush normally
+ (undersized page). If there are no packets or partial packets to
+ flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
+ try to flush a normal sized page like ogg_stream_pageout; a call to
+ ogg_stream_flush does not gurantee that all packets have flushed.
+ Only a return value of 0 from ogg_stream_flush indicates all packet
+ data is flushed into pages.
+
+ ogg_stream_page will flush the last page in a stream even if it's
+ undersized; you almost certainly want to use ogg_stream_pageout
+ (and *not* ogg_stream_flush) unless you need to flush an undersized
+ page in the middle of a stream for some reason. */
+
+ public int flush(Page og){
+
+//System.out.println(this+" ---body_returned: "+body_returned);
+
+ int i;
+ int vals=0;
+ int maxvals=(lacing_fill>255?255:lacing_fill);
+ int bytes=0;
+ int acc=0;
+ long granule_pos=granule_vals[0];
+
+ if(maxvals==0)return(0);
+
+ /* construct a page */
+ /* decide how many segments to include */
+
+ /* If this is the initial header case, the first page must only include
+ the initial header packet */
+ if(b_o_s==0){ /* 'initial header page' case */
+ granule_pos=0;
+ for(vals=0;vals<maxvals;vals++){
+ if((lacing_vals[vals]&0x0ff)<255){
+ vals++;
+ break;
+ }
+ }
+ }
+ else{
+ for(vals=0;vals<maxvals;vals++){
+ if(acc>4096)break;
+ acc+=(lacing_vals[vals]&0x0ff);
+ granule_pos=granule_vals[vals];
+ }
+ }
+
+ /* construct the header in temp storage */
+ System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
+
+ /* stream structure version */
+ header[4]=0x00;
+
+ /* continued packet flag? */
+ header[5]=0x00;
+ if((lacing_vals[0]&0x100)==0)header[5]|=0x01;
+ /* first page flag? */
+ if(b_o_s==0) header[5]|=0x02;
+ /* last page flag? */
+ if(e_o_s!=0 && lacing_fill==vals) header[5]|=0x04;
+ b_o_s=1;
+
+ /* 64 bits of PCM position */
+ for(i=6;i<14;i++){
+ header[i]=(byte)granule_pos;
+ granule_pos>>>=8;
+ }
+
+ /* 32 bits of stream serial number */
+ {
+ int _serialno=serialno;
+ for(i=14;i<18;i++){
+ header[i]=(byte)_serialno;
+ _serialno>>>=8;
+ }
+ }
+
+ /* 32 bits of page counter (we have both counter and page header
+ because this val can roll over) */
+ if(pageno==-1)pageno=0; /* because someone called
+ stream_reset; this would be a
+ strange thing to do in an
+ encode stream, but it has
+ plausible uses */
+ {
+ int _pageno=pageno++;
+ for(i=18;i<22;i++){
+ header[i]=(byte)_pageno;
+ _pageno>>>=8;
+ }
+ }
+
+ /* zero for computation; filled in later */
+ header[22]=0;
+ header[23]=0;
+ header[24]=0;
+ header[25]=0;
+
+ /* segment table */
+ header[26]=(byte)vals;
+ for(i=0;i<vals;i++){
+ header[i+27]=(byte)lacing_vals[i];
+ bytes+=(header[i+27]&0xff);
+ }
+
+ /* set pointers in the ogg_page struct */
+ og.header_base=header;
+ og.header=0;
+ og.header_len=header_fill=vals+27;
+ og.body_base=body_data;
+ og.body=body_returned;
+ og.body_len=bytes;
+
+ /* advance the lacing data and set the body_returned pointer */
+
+//System.out.println("###body_returned: "+body_returned);
+
+ lacing_fill-=vals;
+ System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill*4);
+ System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill*8);
+ body_returned+=bytes;
+
+//System.out.println("####body_returned: "+body_returned);
+
+ /* calculate the checksum */
+
+ og.checksum();
+
+ /* done */
+ return(1);
+ }
+
+
+/* This constructs pages from buffered packet segments. The pointers
+returned are to static buffers; do not free. The returned buffers are
+good only until the next call (using the same ogg_stream_state) */
+ public int pageout(Page og){
+// if(body_returned!=0){
+// /* advance packet data according to the body_returned pointer. We
+// had to keep it around to return a pointer into the buffer last
+// call */
+//
+// body_fill-=body_returned;
+// if(body_fill!=0){ // overlap?
+// System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
+// }
+// body_returned=0;
+// }
+//
+//System.out.println("pageout: e_o_s="+e_o_s+" lacing_fill="+lacing_fill+" body_fill="+body_fill+", lacing_fill="+lacing_fill+" b_o_s="+b_o_s);
+//
+// if((e_o_s!=0&&lacing_fill!=0) || /* 'were done, now flush' case */
+// body_fill > 4096 || /* 'page nominal size' case */
+// lacing_fill>=255 || /* 'segment table full' case */
+// (lacing_fill!=0&&b_o_s==0)){ /* 'initial header page' case */
+// int vals=0,bytes=0;
+// int maxvals=(lacing_fill>255?255:lacing_fill);
+// long acc=0;
+// long pcm_pos=granule_vals[0];
+//
+// /* construct a page */
+// /* decide how many segments to include */
+//
+// /* If this is the initial header case, the first page must only include
+// the initial header packet */
+// if(b_o_s==0){ /* 'initial header page' case */
+// pcm_pos=0;
+// for(vals=0;vals<maxvals;vals++){
+// if((lacing_vals[vals]&0x0ff)<255){
+// vals++;
+// break;
+// }
+// }
+// }
+// else{
+// for(vals=0;vals<maxvals;vals++){
+// if(acc>4096)break;
+// acc+=lacing_vals[vals]&0x0ff;
+// pcm_pos=granule_vals[vals];
+// }
+// }
+//
+// /* construct the header in temp storage */
+// System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
+//
+// /* stream structure version */
+// header[4]=0x00;
+//
+// /* continued packet flag? */
+// header[5]=0x00;
+// if((lacing_vals[0]&0x100)==0)header[5]|=0x01;
+// /* first page flag? */
+// if(b_o_s==0)header[5]|=0x02;
+// /* last page flag? */
+// if(e_o_s!=0 && lacing_fill==vals)header[5]|=0x04;
+// b_o_s=1;
+//
+// /* 64 bits of PCM position */
+// for(int i=6;i<14;i++){
+// header[i]=(byte)pcm_pos;
+// pcm_pos>>>=8;
+// }
+//
+// /* 32 bits of stream serial number */
+// {
+// int serialn=serialno;
+// for(int i=14;i<18;i++){
+// header[i]=(byte)serialn;
+// serialn>>>=8;
+// }
+// }
+//
+//
+///* 32 bits of page counter (we have both counter and page header
+// because this val can roll over) */
+// if(pageno==-1)pageno=0; /* because someone called
+// stream_reset; this would be a
+// strange thing to do in an
+// encode stream, but it has
+// plausible uses */
+// {
+// int pagen=pageno++;
+// for(int i=18;i<22;i++){
+// header[i]=(byte)pagen;
+// pagen>>>=8;
+// }
+// }
+//
+// /* zero for computation; filled in later */
+// header[22]=0;
+// header[23]=0;
+// header[24]=0;
+// header[25]=0;
+//
+// /* segment table */
+// header[26]=(byte)vals;
+// for(int i=0;i<vals;i++){
+// header[i+27]=(byte)lacing_vals[i];
+// bytes+=header[i+27]&0xff;
+//// bytes+=header[i+27]=(lacing_vals[i]&0xff);
+// }
+//
+// /* advance the lacing data and set the body_returned pointer */
+//
+// lacing_fill-=vals;
+// System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill);
+// System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill);
+// body_returned=bytes;
+//
+// /* set pointers in the ogg_page struct */
+// og.header_base=header;
+// og.header=0;
+// og.header_len=header_fill=vals+27;
+//
+// og.body_base=body_data;
+// og.body=0;
+// og.body_len=bytes;
+//
+// /* calculate the checksum */
+//
+// og.checksum();
+// return(1);
+// }
+// /* not enough data to construct a page and not end of stream */
+// return(0);
+//System.out.println("pageout: "+body_returned);
+ if((e_o_s!=0&&lacing_fill!=0) || /* 'were done, now flush' case */
+ body_fill-body_returned> 4096 || /* 'page nominal size' case */
+ lacing_fill>=255 || /* 'segment table full' case */
+ (lacing_fill!=0&&b_o_s==0)){ /* 'initial header page' case */
+ return flush(og);
+ }
+ return 0;
+ }
+
+ public int eof(){
+ return e_o_s;
+ }
+
+ public int reset(){
+ body_fill=0;
+ body_returned=0;
+
+ lacing_fill=0;
+ lacing_packet=0;
+ lacing_returned=0;
+
+ header_fill=0;
+
+ e_o_s=0;
+ b_o_s=0;
+ pageno=-1;
+ packetno=0;
+ granulepos=0;
+ return(0);
+ }
+}
diff --git a/songdbj/com/jcraft/jogg/SyncState.java b/songdbj/com/jcraft/jogg/SyncState.java
new file mode 100644
index 0000000000..b3705e54dd
--- /dev/null
+++ b/songdbj/com/jcraft/jogg/SyncState.java
@@ -0,0 +1,275 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jogg;
+
+// DECODING PRIMITIVES: packet streaming layer
+
+// This has two layers to place more of the multi-serialno and paging
+// control in the application's hands. First, we expose a data buffer
+// using ogg_decode_buffer(). The app either copies into the
+// buffer, or passes it directly to read(), etc. We then call
+// ogg_decode_wrote() to tell how many bytes we just added.
+//
+// Pages are returned (pointers into the buffer in ogg_sync_state)
+// by ogg_decode_stream(). The page is then submitted to
+// ogg_decode_page() along with the appropriate
+// ogg_stream_state* (ie, matching serialno). We then get raw
+// packets out calling ogg_stream_packet() with a
+// ogg_stream_state. See the 'frame-prog.txt' docs for details and
+// example code.
+
+public class SyncState{
+
+ public byte[] data;
+ int storage;
+ int fill;
+ int returned;
+
+ int unsynced;
+ int headerbytes;
+ int bodybytes;
+
+ public int clear(){
+ data=null;
+ return(0);
+ }
+
+// !!!!!!!!!!!!
+// byte[] buffer(int size){
+ public int buffer(int size){
+ // first, clear out any space that has been previously returned
+ if(returned!=0){
+ fill-=returned;
+ if(fill>0){
+ System.arraycopy(data, returned, data, 0, fill);
+ }
+ returned=0;
+ }
+
+ if(size>storage-fill){
+ // We need to extend the internal buffer
+ int newsize=size+fill+4096; // an extra page to be nice
+ if(data!=null){
+ byte[] foo=new byte[newsize];
+ System.arraycopy(data, 0, foo, 0, data.length);
+ data=foo;
+ }
+ else{
+ data=new byte[newsize];
+ }
+ storage=newsize;
+ }
+
+ // expose a segment at least as large as requested at the fill mark
+// return((char *)oy->data+oy->fill);
+// return(data);
+ return(fill);
+ }
+
+ public int wrote(int bytes){
+ if(fill+bytes>storage)return(-1);
+ fill+=bytes;
+ return(0);
+ }
+
+// sync the stream. This is meant to be useful for finding page
+// boundaries.
+//
+// return values for this:
+// -n) skipped n bytes
+// 0) page not ready; more data (no bytes skipped)
+// n) page synced at current location; page length n bytes
+ private Page pageseek=new Page();
+ private byte[] chksum=new byte[4];
+ public int pageseek(Page og){
+ int page=returned;
+ int next;
+ int bytes=fill-returned;
+
+ if(headerbytes==0){
+ int _headerbytes,i;
+ if(bytes<27)return(0); // not enough for a header
+
+ /* verify capture pattern */
+//!!!!!!!!!!!
+ if(data[page]!='O' ||
+ data[page+1]!='g' ||
+ data[page+2]!='g' ||
+ data[page+3]!='S'){
+ headerbytes=0;
+ bodybytes=0;
+
+ // search for possible capture
+ next=0;
+ for(int ii=0; ii<bytes-1; ii++){
+ if(data[page+1+ii]=='O'){next=page+1+ii; break;}
+ }
+ //next=memchr(page+1,'O',bytes-1);
+ if(next==0) next=fill;
+
+ returned=next;
+ return(-(next-page));
+ }
+ _headerbytes=(data[page+26]&0xff)+27;
+ if(bytes<_headerbytes)return(0); // not enough for header + seg table
+
+ // count up body length in the segment table
+
+ for(i=0;i<(data[page+26]&0xff);i++){
+ bodybytes+=(data[page+27+i]&0xff);
+ }
+ headerbytes=_headerbytes;
+ }
+
+ if(bodybytes+headerbytes>bytes)return(0);
+
+ // The whole test page is buffered. Verify the checksum
+ synchronized(chksum){
+ // Grab the checksum bytes, set the header field to zero
+
+ System.arraycopy(data, page+22, chksum, 0, 4);
+ data[page+22]=0;
+ data[page+23]=0;
+ data[page+24]=0;
+ data[page+25]=0;
+
+ // set up a temp page struct and recompute the checksum
+ Page log=pageseek;
+ log.header_base=data;
+ log.header=page;
+ log.header_len=headerbytes;
+
+ log.body_base=data;
+ log.body=page+headerbytes;
+ log.body_len=bodybytes;
+ log.checksum();
+
+ // Compare
+ if(chksum[0]!=data[page+22] ||
+ chksum[1]!=data[page+23] ||
+ chksum[2]!=data[page+24] ||
+ chksum[3]!=data[page+25]){
+ // D'oh. Mismatch! Corrupt page (or miscapture and not a page at all)
+ // replace the computed checksum with the one actually read in
+ System.arraycopy(chksum, 0, data, page+22, 4);
+ // Bad checksum. Lose sync */
+
+ headerbytes=0;
+ bodybytes=0;
+ // search for possible capture
+ next=0;
+ for(int ii=0; ii<bytes-1; ii++){
+ if(data[page+1+ii]=='O'){next=page+1+ii; break;}
+ }
+ //next=memchr(page+1,'O',bytes-1);
+ if(next==0) next=fill;
+ returned=next;
+ return(-(next-page));
+ }
+ }
+
+ // yes, have a whole page all ready to go
+ {
+ page=returned;
+
+ if(og!=null){
+ og.header_base=data;
+ og.header=page;
+ og.header_len=headerbytes;
+ og.body_base=data;
+ og.body=page+headerbytes;
+ og.body_len=bodybytes;
+ }
+
+ unsynced=0;
+ returned+=(bytes=headerbytes+bodybytes);
+ headerbytes=0;
+ bodybytes=0;
+ return(bytes);
+ }
+// headerbytes=0;
+// bodybytes=0;
+// next=0;
+// for(int ii=0; ii<bytes-1; ii++){
+// if(data[page+1+ii]=='O'){next=page+1+ii;}
+// }
+// //next=memchr(page+1,'O',bytes-1);
+// if(next==0) next=fill;
+// returned=next;
+// return(-(next-page));
+ }
+
+
+// sync the stream and get a page. Keep trying until we find a page.
+// Supress 'sync errors' after reporting the first.
+//
+// return values:
+// -1) recapture (hole in data)
+// 0) need more data
+// 1) page returned
+//
+// Returns pointers into buffered data; invalidated by next call to
+// _stream, _clear, _init, or _buffer
+
+ public int pageout(Page og){
+ // all we need to do is verify a page at the head of the stream
+ // buffer. If it doesn't verify, we look for the next potential
+ // frame
+
+ while(true){
+ int ret=pageseek(og);
+ if(ret>0){
+ // have a page
+ return(1);
+ }
+ if(ret==0){
+ // need more data
+ return(0);
+ }
+
+ // head did not start a synced page... skipped some bytes
+ if(unsynced==0){
+ unsynced=1;
+ return(-1);
+ }
+ // loop. keep looking
+ }
+ }
+
+// clear things to an initial state. Good to call, eg, before seeking
+ public int reset(){
+ fill=0;
+ returned=0;
+ unsynced=0;
+ headerbytes=0;
+ bodybytes=0;
+ return(0);
+ }
+ public void init(){}
+
+ public int getDataOffset(){ return returned; }
+ public int getBufferOffset(){ return fill; }
+}
diff --git a/songdbj/com/jcraft/jorbis/AllocChain.java b/songdbj/com/jcraft/jorbis/AllocChain.java
new file mode 100644
index 0000000000..b3492d5c94
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/AllocChain.java
@@ -0,0 +1,31 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+class AllocChain{
+ Object ptr;
+ AllocChain next;
+};
diff --git a/songdbj/com/jcraft/jorbis/Block.java b/songdbj/com/jcraft/jorbis/Block.java
new file mode 100644
index 0000000000..8fd15f76bf
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Block.java
@@ -0,0 +1,188 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+public class Block{
+ ///necessary stream state for linking to the framing abstraction
+ float[][] pcm=new float[0][]; // this is a pointer into local storage
+ Buffer opb=new Buffer();
+
+ int lW;
+ int W;
+ int nW;
+ int pcmend;
+ int mode;
+
+ int eofflag;
+ long granulepos;
+ long sequence;
+ DspState vd; // For read-only access of configuration
+
+ // local storage to avoid remallocing; it's up to the mapping to
+ // structure it
+//byte[] localstore;
+//int localtop;
+//int localalloc;
+//int totaluse;
+//AllocChain reap;
+
+ // bitmetrics for the frame
+ int glue_bits;
+ int time_bits;
+ int floor_bits;
+ int res_bits;
+
+ public Block(DspState vd){
+ this.vd=vd;
+// localalloc=0;
+// localstore=null;
+ if(vd.analysisp!=0){
+ opb.writeinit();
+ }
+ }
+
+ public void init(DspState vd){
+ this.vd=vd;
+ }
+
+// int alloc(int bytes){
+// bytes=(bytes+(8-1))&(~(8-1));
+// if(bytes+localtop>localalloc){
+// if(localstore!=null){
+// AllocChain link=new AllocChain();
+// totaluse+=localtop;
+// link.next=reap;
+// link.ptr=localstore;
+// reap=link;
+// }
+// // highly conservative
+// localalloc=bytes;
+// localstore=new byte[localalloc];
+// localtop=0;
+// }
+// {
+// int foo=localtop;
+// //void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
+// localtop+=bytes;
+// return foo;
+// }
+// }
+
+ // reap the chain, pull the ripcord
+// void ripcord(){
+// // reap the chain
+// while(reap!=null){
+// AllocChain next=reap.next;
+// //free(reap->ptr);
+// reap.ptr=null;
+// //memset(reap,0,sizeof(struct alloc_chain));
+// //free(reap);
+// reap=next;
+// }
+// // consolidate storage
+// if(totaluse!=0){
+// //vb->localstore=realloc(vb->localstore,vb->totaluse+vb->localalloc);
+// byte[] foo=new byte[totaluse+localalloc];
+// System.arraycopy(localstore, 0, foo, 0, localstore.length);
+// localstore=foo;
+// localalloc+=totaluse;
+// totaluse=0;
+// }
+// // pull the ripcord
+// localtop=0;
+// reap=null;
+// }
+
+ public int clear(){
+ if(vd!=null){
+ if(vd.analysisp!=0){
+ opb.writeclear();
+ }
+ }
+ //ripcord();
+ //if(localstore!=null)
+ // localstore=null;
+ //memset(vb,0,sizeof(vorbis_block));
+ return(0);
+ }
+
+ public int synthesis(Packet op){
+ Info vi=vd.vi;
+
+ // first things first. Make sure decode is ready
+ // ripcord();
+ opb.readinit(op.packet_base, op.packet, op.bytes);
+
+ // Check the packet type
+ if(opb.read(1)!=0){
+ // Oops. This is not an audio data packet
+ return(-1);
+ }
+
+ // read our mode and pre/post windowsize
+ int _mode=opb.read(vd.modebits);
+ if(_mode==-1)return(-1);
+
+ mode=_mode;
+ W=vi.mode_param[mode].blockflag;
+ if(W!=0){
+ lW=opb.read(1);
+ nW=opb.read(1);
+ if(nW==-1) return(-1);
+ }
+ else{
+ lW=0;
+ nW=0;
+ }
+
+ // more setup
+ granulepos=op.granulepos;
+ sequence=op.packetno-3; // first block is third packet
+ eofflag=op.e_o_s;
+
+ // alloc pcm passback storage
+ pcmend=vi.blocksizes[W];
+ //pcm=alloc(vi.channels);
+ if(pcm.length<vi.channels){
+ pcm=new float[vi.channels][];
+ }
+ for(int i=0;i<vi.channels;i++){
+ if(pcm[i]==null || pcm[i].length<pcmend){
+ pcm[i]=new float[pcmend];
+ //pcm[i]=alloc(pcmend);
+ }
+ else{
+ for(int j=0;j<pcmend;j++){ pcm[i][j]=0; }
+ }
+ }
+
+ // unpack_header enforces range checking
+ int type=vi.map_type[vi.mode_param[mode].mapping];
+ return(FuncMapping.mapping_P[type].inverse(this, vd.mode[mode]));
+ }
+}
diff --git a/songdbj/com/jcraft/jorbis/ChainingExample.java b/songdbj/com/jcraft/jorbis/ChainingExample.java
new file mode 100644
index 0000000000..82592f29c4
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/ChainingExample.java
@@ -0,0 +1,61 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+class ChainingExample{
+ public static void main(String[] arg){
+ VorbisFile ov=null;
+
+ try{
+ ov=new VorbisFile(System.in, null, -1);
+ }
+ catch(Exception e){
+ System.err.println(e);
+ return;
+ }
+
+ if(ov.seekable()){
+ System.out.println("Input bitstream contained "+ov.streams()+" logical bitstream section(s).");
+ System.out.println("Total bitstream playing time: "+ov.time_total(-1)+" seconds\n");
+ }
+ else{
+ System.out.println("Standard input was not seekable.");
+ System.out.println("First logical bitstream information:\n");
+ }
+
+ for(int i=0;i<ov.streams();i++){
+ Info vi=ov.getInfo(i);
+ System.out.println("\tlogical bitstream section "+(i+1)+" information:");
+ System.out.println("\t\t"+vi.rate+"Hz "+vi.channels+" channels bitrate "+
+ (ov.bitrate(i)/1000)+"kbps serial number="+ov.serialnumber(i));
+ System.out.print("\t\tcompressed length: "+ov.raw_total(i)+" bytes ");
+ System.out.println(" play time: "+ov.time_total(i)+"s");
+ Comment vc=ov.getComment(i);
+ System.out.println(vc);
+ }
+ //clear(&ov);
+ }
+}
diff --git a/songdbj/com/jcraft/jorbis/CodeBook.java b/songdbj/com/jcraft/jorbis/CodeBook.java
new file mode 100644
index 0000000000..9708e066a4
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/CodeBook.java
@@ -0,0 +1,742 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class CodeBook{
+ int dim; // codebook dimensions (elements per vector)
+ int entries; // codebook entries
+ StaticCodeBook c=new StaticCodeBook();
+
+ float[] valuelist; // list of dim*entries actual entry values
+ int[] codelist; // list of bitstream codewords for each entry
+ DecodeAux decode_tree;
+
+ // returns the number of bits
+ int encode(int a, Buffer b){
+ b.write(codelist[a], c.lengthlist[a]);
+ return(c.lengthlist[a]);
+ }
+
+ // One the encode side, our vector writers are each designed for a
+ // specific purpose, and the encoder is not flexible without modification:
+ //
+ // The LSP vector coder uses a single stage nearest-match with no
+ // interleave, so no step and no error return. This is specced by floor0
+ // and doesn't change.
+ //
+ // Residue0 encoding interleaves, uses multiple stages, and each stage
+ // peels of a specific amount of resolution from a lattice (thus we want
+ // to match by threshhold, not nearest match). Residue doesn't *have* to
+ // be encoded that way, but to change it, one will need to add more
+ // infrastructure on the encode side (decode side is specced and simpler)
+
+ // floor0 LSP (single stage, non interleaved, nearest match)
+ // returns entry number and *modifies a* to the quantization value
+ int errorv(float[] a){
+ int best=best(a,1);
+ for(int k=0;k<dim;k++){
+ a[k]=valuelist[best*dim+k];
+ }
+ return(best);
+ }
+
+ // returns the number of bits and *modifies a* to the quantization value
+ int encodev(int best, float[] a, Buffer b){
+ for(int k=0;k<dim;k++){
+ a[k]=valuelist[best*dim+k];
+ }
+ return(encode(best,b));
+ }
+
+ // res0 (multistage, interleave, lattice)
+ // returns the number of bits and *modifies a* to the remainder value
+ int encodevs(float[] a, Buffer b, int step,int addmul){
+ int best=besterror(a,step,addmul);
+ return(encode(best,b));
+ }
+
+ private int[] t=new int[15]; // decodevs_add is synchronized for re-using t.
+ synchronized int decodevs_add(float[]a, int offset, Buffer b, int n){
+ int step=n/dim;
+ int entry;
+ int i,j,o;
+
+ if(t.length<step){
+ t=new int[step];
+ }
+
+ for(i = 0; i < step; i++){
+ entry=decode(b);
+ if(entry==-1)return(-1);
+ t[i]=entry*dim;
+ }
+ for(i=0,o=0;i<dim;i++,o+=step){
+ for(j=0;j<step;j++){
+ a[offset+o+j]+=valuelist[t[j]+i];
+ }
+ }
+
+ return(0);
+ }
+
+ int decodev_add(float[]a, int offset, Buffer b,int n){
+ int i,j,entry;
+ int t;
+
+ if(dim>8){
+ for(i=0;i<n;){
+ entry = decode(b);
+ if(entry==-1)return(-1);
+ t=entry*dim;
+ for(j=0;j<dim;){
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ }
+ }
+ }
+ else{
+ for(i=0;i<n;){
+ entry=decode(b);
+ if(entry==-1)return(-1);
+ t=entry*dim;
+ j=0;
+ switch(dim){
+ case 8:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 7:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 6:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 5:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 4:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 3:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 2:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 1:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 0:
+ break;
+ }
+ }
+ }
+ return(0);
+ }
+
+ int decodev_set(float[] a,int offset, Buffer b, int n){
+ int i,j,entry;
+ int t;
+
+ for(i=0;i<n;){
+ entry = decode(b);
+ if(entry==-1)return(-1);
+ t=entry*dim;
+ for(j=0;j<dim;){
+ a[offset+i++]=valuelist[t+(j++)];
+ }
+ }
+ return(0);
+ }
+
+ int decodevv_add(float[][] a, int offset,int ch, Buffer b,int n){
+ int i,j,k,entry;
+ int chptr=0;
+ //System.out.println("decodevv_add: a="+a+",b="+b+",valuelist="+valuelist);
+
+ for(i=offset/ch;i<(offset+n)/ch;){
+ entry = decode(b);
+ if(entry==-1)return(-1);
+
+ int t = entry*dim;
+ for(j=0;j<dim;j++){
+ a[chptr++][i]+=valuelist[t+j];
+ if(chptr==ch){
+ chptr=0;
+ i++;
+ }
+ }
+ }
+ return(0);
+ }
+
+
+ // Decode side is specced and easier, because we don't need to find
+ // matches using different criteria; we simply read and map. There are
+ // two things we need to do 'depending':
+ //
+ // We may need to support interleave. We don't really, but it's
+ // convenient to do it here rather than rebuild the vector later.
+ //
+ // Cascades may be additive or multiplicitive; this is not inherent in
+ // the codebook, but set in the code using the codebook. Like
+ // interleaving, it's easiest to do it here.
+ // stage==0 -> declarative (set the value)
+ // stage==1 -> additive
+ // stage==2 -> multiplicitive
+
+ // returns the entry number or -1 on eof
+ int decode(Buffer b){
+ int ptr=0;
+ DecodeAux t=decode_tree;
+ int lok=b.look(t.tabn);
+ //System.err.println(this+" "+t+" lok="+lok+", tabn="+t.tabn);
+
+ if(lok>=0){
+ ptr=t.tab[lok];
+ b.adv(t.tabl[lok]);
+ if(ptr<=0){
+ return -ptr;
+ }
+ }
+ do{
+ switch(b.read1()){
+ case 0:
+ ptr=t.ptr0[ptr];
+ break;
+ case 1:
+ ptr=t.ptr1[ptr];
+ break;
+ case -1:
+ default:
+ return(-1);
+ }
+ }
+ while(ptr>0);
+ return(-ptr);
+ }
+
+ // returns the entry number or -1 on eof
+ int decodevs(float[] a, int index, Buffer b, int step,int addmul){
+ int entry=decode(b);
+ if(entry==-1)return(-1);
+ switch(addmul){
+ case -1:
+ for(int i=0,o=0;i<dim;i++,o+=step)
+ a[index+o]=valuelist[entry*dim+i];
+ break;
+ case 0:
+ for(int i=0,o=0;i<dim;i++,o+=step)
+ a[index+o]+=valuelist[entry*dim+i];
+ break;
+ case 1:
+ for(int i=0,o=0;i<dim;i++,o+=step)
+ a[index+o]*=valuelist[entry*dim+i];
+ break;
+ default:
+ //System.err.println("CodeBook.decodeves: addmul="+addmul);
+ }
+ return(entry);
+ }
+
+ int best(float[] a, int step){
+ EncodeAuxNearestMatch nt=c.nearest_tree;
+ EncodeAuxThreshMatch tt=c.thresh_tree;
+ int ptr=0;
+
+ // we assume for now that a thresh tree is the only other possibility
+ if(tt!=null){
+ int index=0;
+ // find the quant val of each scalar
+ for(int k=0,o=step*(dim-1);k<dim;k++,o-=step){
+ int i;
+ // linear search the quant list for now; it's small and although
+ // with > 8 entries, it would be faster to bisect, this would be
+ // a misplaced optimization for now
+ for(i=0;i<tt.threshvals-1;i++){
+ if(a[o]<tt.quantthresh[i]){
+ break;
+ }
+ }
+ index=(index*tt.quantvals)+tt.quantmap[i];
+ }
+ // regular lattices are easy :-)
+ if(c.lengthlist[index]>0){
+ // is this unused? If so, we'll
+ // use a decision tree after all
+ // and fall through
+ return(index);
+ }
+ }
+ if(nt!=null){
+ // optimized using the decision tree
+ while(true){
+ float c=0.f;
+ int p=nt.p[ptr];
+ int q=nt.q[ptr];
+ for(int k=0,o=0;k<dim;k++,o+=step){
+ c+=(valuelist[p+k]-valuelist[q+k])*
+ (a[o]-(valuelist[p+k]+valuelist[q+k])*.5);
+ }
+ if(c>0.){ // in A
+ ptr= -nt.ptr0[ptr];
+ }
+ else{ // in B
+ ptr= -nt.ptr1[ptr];
+ }
+ if(ptr<=0)break;
+ }
+ return(-ptr);
+ }
+
+ // brute force it!
+ {
+ int besti=-1;
+ float best=0.f;
+ int e=0;
+ for(int i=0;i<entries;i++){
+ if(c.lengthlist[i]>0){
+ float _this=dist(dim, valuelist, e, a, step);
+ if(besti==-1 || _this<best){
+ best=_this;
+ besti=i;
+ }
+ }
+ e+=dim;
+ }
+ return(besti);
+ }
+ }
+
+ // returns the entry number and *modifies a* to the remainder value
+ int besterror(float[] a, int step, int addmul){
+ int best=best(a,step);
+ switch(addmul){
+ case 0:
+ for(int i=0,o=0;i<dim;i++,o+=step)
+ a[o]-=valuelist[best*dim+i];
+ break;
+ case 1:
+ for(int i=0,o=0;i<dim;i++,o+=step){
+ float val=valuelist[best*dim+i];
+ if(val==0){
+ a[o]=0;
+ }else{
+ a[o]/=val;
+ }
+ }
+ break;
+ }
+ return(best);
+ }
+
+ void clear(){
+ // static book is not cleared; we're likely called on the lookup and
+ // the static codebook belongs to the info struct
+ //if(decode_tree!=null){
+ // free(b->decode_tree->ptr0);
+ // free(b->decode_tree->ptr1);
+ // memset(b->decode_tree,0,sizeof(decode_aux));
+ // free(b->decode_tree);
+ //}
+ //if(valuelist!=null)free(b->valuelist);
+ //if(codelist!=null)free(b->codelist);
+ //memset(b,0,sizeof(codebook));
+ }
+
+ private static float dist(int el, float[] ref, int index, float[] b, int step){
+ float acc=(float)0.;
+ for(int i=0; i<el; i++){
+ float val=(ref[index+i]-b[i*step]);
+ acc+=val*val;
+ }
+ return(acc);
+ }
+
+/*
+ int init_encode(StaticCodeBook s){
+ //memset(c,0,sizeof(codebook));
+ c=s;
+ entries=s.entries;
+ dim=s.dim;
+ codelist=make_words(s.lengthlist, s.entries);
+ valuelist=s.unquantize();
+ return(0);
+ }
+*/
+
+ int init_decode(StaticCodeBook s){
+ //memset(c,0,sizeof(codebook));
+ c=s;
+ entries=s.entries;
+ dim=s.dim;
+ valuelist=s.unquantize();
+
+ decode_tree=make_decode_tree();
+ if(decode_tree==null){
+ //goto err_out;
+ clear();
+ return(-1);
+ }
+ return(0);
+// err_out:
+// vorbis_book_clear(c);
+// return(-1);
+ }
+
+ // given a list of word lengths, generate a list of codewords. Works
+ // for length ordered or unordered, always assigns the lowest valued
+ // codewords first. Extended to handle unused entries (length 0)
+ static int[] make_words(int[] l, int n){
+ int[] marker=new int[33];
+ int[] r=new int[n];
+ //memset(marker,0,sizeof(marker));
+
+ for(int i=0;i<n;i++){
+ int length=l[i];
+ if(length>0){
+ int entry=marker[length];
+
+ // when we claim a node for an entry, we also claim the nodes
+ // below it (pruning off the imagined tree that may have dangled
+ // from it) as well as blocking the use of any nodes directly
+ // above for leaves
+
+ // update ourself
+ if(length<32 && (entry>>>length)!=0){
+ // error condition; the lengths must specify an overpopulated tree
+ //free(r);
+ return(null);
+ }
+ r[i]=entry;
+
+ // Look to see if the next shorter marker points to the node
+ // above. if so, update it and repeat.
+ {
+ for(int j=length;j>0;j--){
+ if((marker[j]&1)!=0){
+ // have to jump branches
+ if(j==1)marker[1]++;
+ else marker[j]=marker[j-1]<<1;
+ break; // invariant says next upper marker would already
+ // have been moved if it was on the same path
+ }
+ marker[j]++;
+ }
+ }
+
+ // prune the tree; the implicit invariant says all the longer
+ // markers were dangling from our just-taken node. Dangle them
+ // from our *new* node.
+ for(int j=length+1;j<33;j++){
+ if((marker[j]>>>1) == entry){
+ entry=marker[j];
+ marker[j]=marker[j-1]<<1;
+ }
+ else{
+ break;
+ }
+ }
+ }
+ }
+
+ // bitreverse the words because our bitwise packer/unpacker is LSb
+ // endian
+ for(int i=0;i<n;i++){
+ int temp=0;
+ for(int j=0;j<l[i];j++){
+ temp<<=1;
+ temp|=(r[i]>>>j)&1;
+ }
+ r[i]=temp;
+ }
+
+ return(r);
+ }
+
+ // build the decode helper tree from the codewords
+ DecodeAux make_decode_tree(){
+ int top=0;
+ DecodeAux t=new DecodeAux();
+ int[] ptr0=t.ptr0=new int[entries*2];
+ int[] ptr1=t.ptr1=new int[entries*2];
+ int[] codelist=make_words(c.lengthlist, c.entries);
+
+ if(codelist==null)return(null);
+ t.aux=entries*2;
+
+ for(int i=0;i<entries;i++){
+ if(c.lengthlist[i]>0){
+ int ptr=0;
+ int j;
+ for(j=0;j<c.lengthlist[i]-1;j++){
+ int bit=(codelist[i]>>>j)&1;
+ if(bit==0){
+ if(ptr0[ptr]==0){
+ ptr0[ptr]=++top;
+ }
+ ptr=ptr0[ptr];
+ }
+ else{
+ if(ptr1[ptr]==0){
+ ptr1[ptr]= ++top;
+ }
+ ptr=ptr1[ptr];
+ }
+ }
+
+ if(((codelist[i]>>>j)&1)==0){ ptr0[ptr]=-i; }
+ else{ ptr1[ptr]=-i; }
+
+ }
+ }
+ //free(codelist);
+
+ t.tabn = ilog(entries)-4;
+
+ if(t.tabn<5)t.tabn=5;
+ int n = 1<<t.tabn;
+ t.tab = new int[n];
+ t.tabl = new int[n];
+ for(int i = 0; i < n; i++){
+ int p = 0;
+ int j=0;
+ for(j = 0; j < t.tabn && (p > 0 || j == 0); j++){
+ if ((i&(1<<j))!=0){
+ p = ptr1[p];
+ }
+ else{
+ p = ptr0[p];
+ }
+ }
+ t.tab[i]=p; // -code
+ t.tabl[i]=j; // length
+ }
+
+ return(t);
+ }
+
+ private static int ilog(int v){
+ int ret=0;
+ while(v!=0){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+
+/*
+ // TEST
+ // Simple enough; pack a few candidate codebooks, unpack them. Code a
+ // number of vectors through (keeping track of the quantized values),
+ // and decode using the unpacked book. quantized version of in should
+ // exactly equal out
+
+ //#include "vorbis/book/lsp20_0.vqh"
+ //#include "vorbis/book/lsp32_0.vqh"
+ //#include "vorbis/book/res0_1a.vqh"
+ static final int TESTSIZE=40;
+
+ static float[] test1={
+ 0.105939,
+ 0.215373,
+ 0.429117,
+ 0.587974,
+
+ 0.181173,
+ 0.296583,
+ 0.515707,
+ 0.715261,
+
+ 0.162327,
+ 0.263834,
+ 0.342876,
+ 0.406025,
+
+ 0.103571,
+ 0.223561,
+ 0.368513,
+ 0.540313,
+
+ 0.136672,
+ 0.395882,
+ 0.587183,
+ 0.652476,
+
+ 0.114338,
+ 0.417300,
+ 0.525486,
+ 0.698679,
+
+ 0.147492,
+ 0.324481,
+ 0.643089,
+ 0.757582,
+
+ 0.139556,
+ 0.215795,
+ 0.324559,
+ 0.399387,
+
+ 0.120236,
+ 0.267420,
+ 0.446940,
+ 0.608760,
+
+ 0.115587,
+ 0.287234,
+ 0.571081,
+ 0.708603,
+ };
+
+ static float[] test2={
+ 0.088654,
+ 0.165742,
+ 0.279013,
+ 0.395894,
+
+ 0.110812,
+ 0.218422,
+ 0.283423,
+ 0.371719,
+
+ 0.136985,
+ 0.186066,
+ 0.309814,
+ 0.381521,
+
+ 0.123925,
+ 0.211707,
+ 0.314771,
+ 0.433026,
+
+ 0.088619,
+ 0.192276,
+ 0.277568,
+ 0.343509,
+
+ 0.068400,
+ 0.132901,
+ 0.223999,
+ 0.302538,
+
+ 0.202159,
+ 0.306131,
+ 0.360362,
+ 0.416066,
+
+ 0.072591,
+ 0.178019,
+ 0.304315,
+ 0.376516,
+
+ 0.094336,
+ 0.188401,
+ 0.325119,
+ 0.390264,
+
+ 0.091636,
+ 0.223099,
+ 0.282899,
+ 0.375124,
+ };
+
+ static float[] test3={
+ 0,1,-2,3,4,-5,6,7,8,9,
+ 8,-2,7,-1,4,6,8,3,1,-9,
+ 10,11,12,13,14,15,26,17,18,19,
+ 30,-25,-30,-1,-5,-32,4,3,-2,0};
+
+// static_codebook *testlist[]={&_vq_book_lsp20_0,
+// &_vq_book_lsp32_0,
+// &_vq_book_res0_1a,NULL};
+ static[][] float testvec={test1,test2,test3};
+
+ static void main(String[] arg){
+ Buffer write=new Buffer();
+ Buffer read=new Buffer();
+ int ptr=0;
+ write.writeinit();
+
+ System.err.println("Testing codebook abstraction...:");
+
+ while(testlist[ptr]!=null){
+ CodeBook c=new CodeBook();
+ StaticCodeBook s=new StaticCodeBook();;
+ float *qv=alloca(sizeof(float)*TESTSIZE);
+ float *iv=alloca(sizeof(float)*TESTSIZE);
+ memcpy(qv,testvec[ptr],sizeof(float)*TESTSIZE);
+ memset(iv,0,sizeof(float)*TESTSIZE);
+
+ System.err.print("\tpacking/coding "+ptr+"... ");
+
+ // pack the codebook, write the testvector
+ write.reset();
+ vorbis_book_init_encode(&c,testlist[ptr]); // get it into memory
+ // we can write
+ vorbis_staticbook_pack(testlist[ptr],&write);
+ System.err.print("Codebook size "+write.bytes()+" bytes... ");
+ for(int i=0;i<TESTSIZE;i+=c.dim){
+ vorbis_book_encodev(&c,qv+i,&write);
+ }
+ c.clear();
+
+ System.err.print("OK.\n");
+ System.err.print("\tunpacking/decoding "+ptr+"... ");
+
+ // transfer the write data to a read buffer and unpack/read
+ _oggpack_readinit(&read,_oggpack_buffer(&write),_oggpack_bytes(&write));
+ if(s.unpack(read)){
+ System.err.print("Error unpacking codebook.\n");
+ System.exit(1);
+ }
+ if(vorbis_book_init_decode(&c,&s)){
+ System.err.print("Error initializing codebook.\n");
+ System.exit(1);
+ }
+ for(int i=0;i<TESTSIZE;i+=c.dim){
+ if(vorbis_book_decodevs(&c,iv+i,&read,1,-1)==-1){
+ System.err.print("Error reading codebook test data (EOP).\n");
+ System.exit(1);
+ }
+ }
+ for(int i=0;i<TESTSIZE;i++){
+ if(fabs(qv[i]-iv[i])>.000001){
+ System.err.print("read ("+iv[i]+") != written ("+qv[i]+") at position ("+i+")\n");
+ System.exit(1);
+ }
+ }
+
+ System.err.print("OK\n");
+ ptr++;
+ }
+ // The above is the trivial stuff;
+ // now try unquantizing a log scale codebook
+ }
+*/
+}
+
+class DecodeAux{
+ int[] tab;
+ int[] tabl;
+ int tabn;
+
+ int[] ptr0;
+ int[] ptr1;
+ int aux; // number of tree entries
+}
diff --git a/songdbj/com/jcraft/jorbis/Comment.java b/songdbj/com/jcraft/jorbis/Comment.java
new file mode 100644
index 0000000000..f83b7cb985
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Comment.java
@@ -0,0 +1,252 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+// the comments are not part of vorbis_info so that vorbis_info can be
+// static storage
+public class Comment{
+ private static byte[] _vorbis="vorbis".getBytes();
+
+ private static final int OV_EFAULT=-129;
+ private static final int OV_EIMPL=-130;
+
+ // unlimited user comment fields. libvorbis writes 'libvorbis'
+ // whatever vendor is set to in encode
+ public byte[][] user_comments;
+ public int[] comment_lengths;
+ public int comments;
+ public byte[] vendor;
+
+ public void init(){
+ user_comments=null;
+ comments=0;
+ vendor=null;
+ }
+
+ public void add(String comment){
+ add(comment.getBytes());
+ }
+
+ private void add(byte[] comment){
+ byte[][] foo=new byte[comments+2][];
+ if(user_comments!=null){
+ System.arraycopy(user_comments, 0, foo, 0, comments);
+ }
+ user_comments=foo;
+
+ int[] goo=new int[comments+2];
+ if(comment_lengths!=null){
+ System.arraycopy(comment_lengths, 0, goo, 0, comments);
+ }
+ comment_lengths=goo;
+
+ byte[] bar=new byte[comment.length+1];
+ System.arraycopy(comment, 0, bar, 0, comment.length);
+ user_comments[comments]=bar;
+ comment_lengths[comments]=comment.length;
+ comments++;
+ user_comments[comments]=null;
+ }
+
+ public void add_tag(String tag, String contents){
+ if(contents==null) contents="";
+ add(tag+"="+contents);
+ }
+
+/*
+ private void add_tag(byte[] tag, byte[] contents){
+ byte[] foo=new byte[tag.length+contents.length+1];
+ int j=0;
+ for(int i=0; i<tag.length; i++){foo[j++]=tag[i];}
+ foo[j++]=(byte)'='; j++;
+ for(int i=0; i<contents.length; i++){foo[j++]=tag[i];}
+ add(foo);
+ }
+*/
+
+ // This is more or less the same as strncasecmp - but that doesn't exist
+ // * everywhere, and this is a fairly trivial function, so we include it
+ static boolean tagcompare(byte[] s1, byte[] s2, int n){
+ int c=0;
+ byte u1, u2;
+ while(c < n){
+ u1=s1[c]; u2=s2[c];
+ if('Z'>=u1 && u1>='A')u1=(byte)(u1-'A'+'a');
+ if('Z'>=u2 && u2>='A')u2=(byte)(u2-'A'+'a');
+ if(u1!=u2){ return false; }
+ c++;
+ }
+ return true;
+ }
+
+ public String query(String tag){
+ return query(tag, 0);
+ }
+
+ public String query(String tag, int count){
+ int foo=query(tag.getBytes(), count);
+ if(foo==-1)return null;
+ byte[] comment=user_comments[foo];
+ for(int i=0; i<comment_lengths[foo]; i++){
+ if(comment[i]=='='){
+ return new String(comment, i+1, comment_lengths[foo]-(i+1));
+ }
+ }
+ return null;
+ }
+
+ private int query(byte[] tag, int count){
+ int i=0;
+ int found = 0;
+ int fulltaglen = tag.length + 1;
+ byte[] fulltag = new byte[fulltaglen];
+ System.arraycopy(tag, 0, fulltag, 0, tag.length);
+ fulltag[tag.length]=(byte)'=';
+
+ for(i=0;i<comments;i++){
+ if(tagcompare(user_comments[i], fulltag, fulltaglen)){
+ if(count==found){
+ // We return a pointer to the data, not a copy
+ //return user_comments[i] + taglen + 1;
+ return i;
+ }
+ else{ found++; }
+ }
+ }
+ return -1;
+ }
+
+ int unpack(Buffer opb){
+ int vendorlen=opb.read(32);
+ if(vendorlen<0){
+ //goto err_out;
+ clear();
+ return(-1);
+ }
+ vendor=new byte[vendorlen+1];
+ opb.read(vendor,vendorlen);
+ comments=opb.read(32);
+ if(comments<0){
+ //goto err_out;
+ clear();
+ return(-1);
+ }
+ user_comments=new byte[comments+1][];
+ comment_lengths=new int[comments+1];
+
+ for(int i=0;i<comments;i++){
+ int len=opb.read(32);
+ if(len<0){
+ //goto err_out;
+ clear();
+ return(-1);
+ }
+ comment_lengths[i]=len;
+ user_comments[i]=new byte[len+1];
+ opb.read(user_comments[i], len);
+ }
+ if(opb.read(1)!=1){
+ //goto err_out; // EOP check
+ clear();
+ return(-1);
+
+ }
+ return(0);
+// err_out:
+// comment_clear(vc);
+// return(-1);
+ }
+
+ int pack(Buffer opb){
+ byte[] temp="Xiphophorus libVorbis I 20000508".getBytes();
+
+ // preamble
+ opb.write(0x03,8);
+ opb.write(_vorbis);
+
+ // vendor
+ opb.write(temp.length,32);
+ opb.write(temp);
+
+ // comments
+
+ opb.write(comments,32);
+ if(comments!=0){
+ for(int i=0;i<comments;i++){
+ if(user_comments[i]!=null){
+ opb.write(comment_lengths[i],32);
+ opb.write(user_comments[i]);
+ }
+ else{
+ opb.write(0,32);
+ }
+ }
+ }
+ opb.write(1,1);
+ return(0);
+ }
+
+ public int header_out(Packet op){
+ Buffer opb=new Buffer();
+ opb.writeinit();
+
+ if(pack(opb)!=0) return OV_EIMPL;
+
+ op.packet_base = new byte[opb.bytes()];
+ op.packet=0;
+ op.bytes=opb.bytes();
+ System.arraycopy(opb.buffer(), 0, op.packet_base, 0, op.bytes);
+ op.b_o_s=0;
+ op.e_o_s=0;
+ op.granulepos=0;
+ return 0;
+ }
+
+ void clear(){
+ for(int i=0;i<comments;i++)
+ user_comments[i]=null;
+ user_comments=null;
+ vendor=null;
+ }
+
+ public String getVendor(){
+ return new String(vendor, 0, vendor.length-1);
+ }
+ public String getComment(int i){
+ if(comments<=i)return null;
+ return new String(user_comments[i], 0, user_comments[i].length-1);
+ }
+ public String toString(){
+ String foo="Vendor: "+new String(vendor, 0, vendor.length-1);
+ for(int i=0; i<comments; i++){
+ foo=foo+"\nComment: "+new String(user_comments[i], 0, user_comments[i].length-1);
+ }
+ foo=foo+"\n";
+ return foo;
+ }
+}
diff --git a/songdbj/com/jcraft/jorbis/DecodeExample.java b/songdbj/com/jcraft/jorbis/DecodeExample.java
new file mode 100644
index 0000000000..f8768969a2
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/DecodeExample.java
@@ -0,0 +1,316 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+// Takes a vorbis bitstream from stdin and writes raw stereo PCM to
+// stdout. Decodes simple and chained OggVorbis files from beginning
+// to end. Vorbisfile.a is somewhat more complex than the code below.
+
+class DecodeExample{
+ static int convsize=4096*2;
+ static byte[] convbuffer=new byte[convsize]; // take 8k out of the data segment, not the stack
+
+ public static void main(String[] arg){
+ java.io.InputStream input=System.in;
+ if(arg.length>0){
+ try{
+ input=new java.io.FileInputStream(arg[0]);
+ }
+ catch(Exception e){
+ System.err.println(e);
+ }
+ }
+
+ SyncState oy=new SyncState(); // sync and verify incoming physical bitstream
+ StreamState os=new StreamState(); // take physical pages, weld into a logical stream of packets
+ Page og=new Page(); // one Ogg bitstream page. Vorbis packets are inside
+ Packet op=new Packet(); // one raw packet of data for decode
+
+ Info vi=new Info(); // struct that stores all the static vorbis bitstream settings
+ Comment vc=new Comment(); // struct that stores all the bitstream user comments
+ DspState vd=new DspState(); // central working state for the packet->PCM decoder
+ Block vb=new Block(vd); // local working space for packet->PCM decode
+
+ byte[] buffer;
+ int bytes=0;
+
+ // Decode setup
+
+ oy.init(); // Now we can read pages
+
+ while(true){ // we repeat if the bitstream is chained
+ int eos=0;
+
+ // grab some data at the head of the stream. We want the first page
+ // (which is guaranteed to be small and only contain the Vorbis
+ // stream initial header) We need the first page to get the stream
+ // serialno.
+
+ // submit a 4k block to libvorbis' Ogg layer
+ int index=oy.buffer(4096);
+ buffer=oy.data;
+ try{
+ bytes=input.read(buffer, index, 4096);
+ }
+ catch(Exception e){
+ System.err.println(e);
+ System.exit(-1);
+ }
+ oy.wrote(bytes);
+
+ // Get the first page.
+ if(oy.pageout(og)!=1){
+ // have we simply run out of data? If so, we're done.
+ if(bytes<4096)break;
+
+ // error case. Must not be Vorbis data
+ System.err.println("Input does not appear to be an Ogg bitstream.");
+ System.exit(1);
+ }
+
+ // Get the serial number and set up the rest of decode.
+ // serialno first; use it to set up a logical stream
+ os.init(og.serialno());
+
+ // extract the initial header from the first page and verify that the
+ // Ogg bitstream is in fact Vorbis data
+
+ // I handle the initial header first instead of just having the code
+ // read all three Vorbis headers at once because reading the initial
+ // header is an easy way to identify a Vorbis bitstream and it's
+ // useful to see that functionality seperated out.
+
+ vi.init();
+ vc.init();
+ if(os.pagein(og)<0){
+ // error; stream version mismatch perhaps
+ System.err.println("Error reading first page of Ogg bitstream data.");
+ System.exit(1);
+ }
+
+ if(os.packetout(op)!=1){
+ // no page? must not be vorbis
+ System.err.println("Error reading initial header packet.");
+ System.exit(1);
+ }
+
+ if(vi.synthesis_headerin(vc,op)<0){
+ // error case; not a vorbis header
+ System.err.println("This Ogg bitstream does not contain Vorbis audio data.");
+ System.exit(1);
+ }
+
+ // At this point, we're sure we're Vorbis. We've set up the logical
+ // (Ogg) bitstream decoder. Get the comment and codebook headers and
+ // set up the Vorbis decoder
+
+ // The next two packets in order are the comment and codebook headers.
+ // They're likely large and may span multiple pages. Thus we reead
+ // and submit data until we get our two pacakets, watching that no
+ // pages are missing. If a page is missing, error out; losing a
+ // header page is the only place where missing data is fatal. */
+
+ int i=0;
+ while(i<2){
+ while(i<2){
+
+ int result=oy.pageout(og);
+ if(result==0) break; // Need more data
+ // Don't complain about missing or corrupt data yet. We'll
+ // catch it at the packet output phase
+
+ if(result==1){
+ os.pagein(og); // we can ignore any errors here
+ // as they'll also become apparent
+ // at packetout
+ while(i<2){
+ result=os.packetout(op);
+ if(result==0)break;
+ if(result==-1){
+ // Uh oh; data at some point was corrupted or missing!
+ // We can't tolerate that in a header. Die.
+ System.err.println("Corrupt secondary header. Exiting.");
+ System.exit(1);
+ }
+ vi.synthesis_headerin(vc,op);
+ i++;
+ }
+ }
+ }
+ // no harm in not checking before adding more
+ index=oy.buffer(4096);
+ buffer=oy.data;
+ try{
+ bytes=input.read(buffer, index, 4096);
+ }
+ catch(Exception e){
+ System.err.println(e);
+ System.exit(1);
+ }
+ if(bytes==0 && i<2){
+ System.err.println("End of file before finding all Vorbis headers!");
+ System.exit(1);
+ }
+ oy.wrote(bytes);
+ }
+
+ // Throw the comments plus a few lines about the bitstream we're
+ // decoding
+ {
+ byte[][] ptr=vc.user_comments;
+ for(int j=0; j<ptr.length;j++){
+ if(ptr[j]==null) break;
+ System.err.println(new String(ptr[j], 0, ptr[j].length-1));
+ }
+ System.err.println("\nBitstream is "+vi.channels+" channel, "+vi.rate+"Hz");
+ System.err.println("Encoded by: "+new String(vc.vendor, 0, vc.vendor.length-1)+"\n");
+ }
+
+ convsize=4096/vi.channels;
+
+ // OK, got and parsed all three headers. Initialize the Vorbis
+ // packet->PCM decoder.
+ vd.synthesis_init(vi); // central decode state
+ vb.init(vd); // local state for most of the decode
+ // so multiple block decodes can
+ // proceed in parallel. We could init
+ // multiple vorbis_block structures
+ // for vd here
+
+ float[][][] _pcm=new float[1][][];
+ int[] _index=new int[vi.channels];
+ // The rest is just a straight decode loop until end of stream
+ while(eos==0){
+ while(eos==0){
+
+ int result=oy.pageout(og);
+ if(result==0)break; // need more data
+ if(result==-1){ // missing or corrupt data at this page position
+ System.err.println("Corrupt or missing data in bitstream; continuing...");
+ }
+ else{
+ os.pagein(og); // can safely ignore errors at
+ // this point
+ while(true){
+ result=os.packetout(op);
+
+ if(result==0)break; // need more data
+ if(result==-1){ // missing or corrupt data at this page position
+ // no reason to complain; already complained above
+ }
+ else{
+ // we have a packet. Decode it
+ int samples;
+ if(vb.synthesis(op)==0){ // test for success!
+ vd.synthesis_blockin(vb);
+ }
+
+ // **pcm is a multichannel float vector. In stereo, for
+ // example, pcm[0] is left, and pcm[1] is right. samples is
+ // the size of each channel. Convert the float values
+ // (-1.<=range<=1.) to whatever PCM format and write it out
+
+ while((samples=vd.synthesis_pcmout(_pcm, _index))>0){
+ float[][] pcm=_pcm[0];
+ boolean clipflag=false;
+ int bout=(samples<convsize?samples:convsize);
+
+ // convert floats to 16 bit signed ints (host order) and
+ // interleave
+ for(i=0;i<vi.channels;i++){
+ int ptr=i*2;
+ //int ptr=i;
+ int mono=_index[i];
+ for(int j=0;j<bout;j++){
+ int val=(int)(pcm[i][mono+j]*32767.);
+// short val=(short)(pcm[i][mono+j]*32767.);
+// int val=(int)Math.round(pcm[i][mono+j]*32767.);
+ // might as well guard against clipping
+ if(val>32767){
+ val=32767;
+ clipflag=true;
+ }
+ if(val<-32768){
+ val=-32768;
+ clipflag=true;
+ }
+ if(val<0) val=val|0x8000;
+ convbuffer[ptr]=(byte)(val);
+ convbuffer[ptr+1]=(byte)(val>>>8);
+ ptr+=2*(vi.channels);
+ }
+ }
+
+ //if(clipflag)
+ // System.err.println("Clipping in frame "+vd.sequence);
+
+ System.out.write(convbuffer, 0, 2*vi.channels*bout);
+
+ vd.synthesis_read(bout); // tell libvorbis how
+ // many samples we
+ // actually consumed
+ }
+ }
+ }
+ if(og.eos()!=0)eos=1;
+ }
+ }
+ if(eos==0){
+ index=oy.buffer(4096);
+ buffer=oy.data;
+ try{
+ bytes=input.read(buffer,index,4096);
+ }
+ catch(Exception e){
+ System.err.println(e);
+ System.exit(1);
+ }
+ oy.wrote(bytes);
+ if(bytes==0)eos=1;
+ }
+ }
+
+ // clean up this logical bitstream; before exit we see if we're
+ // followed by another [chained]
+
+ os.clear();
+
+ // ogg_page and ogg_packet structs always point to storage in
+ // libvorbis. They're never freed or manipulated directly
+
+ vb.clear();
+ vd.clear();
+ vi.clear(); // must be called last
+ }
+
+ // OK, clean up the framer
+ oy.clear();
+ System.err.println("Done.");
+ }
+}
+
diff --git a/songdbj/com/jcraft/jorbis/Drft.java b/songdbj/com/jcraft/jorbis/Drft.java
new file mode 100644
index 0000000000..c7ff2032e7
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Drft.java
@@ -0,0 +1,1317 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+class Drft{
+ int n;
+ float[] trigcache;
+ int[] splitcache;
+
+ void backward(float[] data){
+ //System.err.println("Drft.backward");
+ if(n==1)return;
+ drftb1(n,data,trigcache,trigcache,n,splitcache);
+ }
+
+ void init(int n){
+ //System.err.println("Drft.init");
+ this.n=n;
+ trigcache=new float[3*n];
+ splitcache=new int[32];
+ fdrffti(n, trigcache, splitcache);
+ }
+
+ void clear(){
+ //System.err.println("Drft.clear");
+ if(trigcache!=null)trigcache=null;
+ if(splitcache!=null)splitcache=null;
+// memset(l,0,sizeof(drft_lookup));
+ }
+
+ static int[] ntryh = { 4,2,3,5 };
+ static float tpi = 6.28318530717958647692528676655900577f;
+ static float hsqt2 = .70710678118654752440084436210485f;
+ static float taui = .86602540378443864676372317075293618f;
+ static float taur = -.5f;
+ static float sqrt2 = 1.4142135623730950488016887242097f;
+
+ static void drfti1(int n, float[] wa, int index, int[] ifac){
+ float arg,argh,argld,fi;
+ int ntry=0,i,j=-1;
+ int k1, l1, l2, ib;
+ int ld, ii, ip, is, nq, nr;
+ int ido, ipm, nfm1;
+ int nl=n;
+ int nf=0;
+
+ int state=101;
+
+ loop: while(true){
+ switch(state){
+ case 101:
+ j++;
+ if (j < 4)
+ ntry=ntryh[j];
+ else
+ ntry+=2;
+ case 104:
+ nq=nl/ntry;
+ nr=nl-ntry*nq;
+ if(nr!=0){
+ state=101;
+ break;
+ }
+ nf++;
+ ifac[nf+1]=ntry;
+ nl=nq;
+ if(ntry!=2){
+ state=107;
+ break;
+ }
+ if(nf==1){
+ state=107;
+ break;
+ }
+
+ for(i=1;i<nf;i++){
+ ib=nf-i+1;
+ ifac[ib+1]=ifac[ib];
+ }
+ ifac[2] = 2;
+ case 107:
+ if(nl!=1){
+ state=104;
+ break;
+ }
+ ifac[0]=n;
+ ifac[1]=nf;
+ argh=tpi/n;
+ is=0;
+ nfm1=nf-1;
+ l1=1;
+
+ if(nfm1==0)return;
+
+ for (k1=0;k1<nfm1;k1++){
+ ip=ifac[k1+2];
+ ld=0;
+ l2=l1*ip;
+ ido=n/l2;
+ ipm=ip-1;
+
+ for (j=0;j<ipm;j++){
+ ld+=l1;
+ i=is;
+ argld=(float)ld*argh;
+ fi=0.f;
+ for (ii=2;ii<ido;ii+=2){
+ fi+=1.f;
+ arg=fi*argld;
+ wa[index+i++]=(float)Math.cos(arg);
+ wa[index+i++]=(float)Math.sin(arg);
+ }
+ is+=ido;
+ }
+ l1=l2;
+ }
+ break loop;
+ }
+ }
+ }
+
+ static void fdrffti(int n, float[] wsave, int[] ifac){
+//System.err.println("fdrffti: n="+n);
+ if(n == 1) return;
+ drfti1(n, wsave, n, ifac);
+ }
+
+ static void dradf2(int ido,int l1,float[] cc, float[] ch, float[] wa1, int index){
+ int i,k;
+ float ti2,tr2;
+ int t0,t1,t2,t3,t4,t5,t6;
+
+ t1=0;
+ t0=(t2=l1*ido);
+ t3=ido<<1;
+ for(k=0;k<l1;k++){
+ ch[t1<<1]=cc[t1]+cc[t2];
+ ch[(t1<<1)+t3-1]=cc[t1]-cc[t2];
+ t1+=ido;
+ t2+=ido;
+ }
+
+ if(ido<2)return;
+
+ if(ido!=2){
+ t1=0;
+ t2=t0;
+ for(k=0;k<l1;k++){
+ t3=t2;
+ t4=(t1<<1)+(ido<<1);
+ t5=t1;
+ t6=t1+t1;
+ for(i=2;i<ido;i+=2){
+ t3+=2;
+ t4-=2;
+ t5+=2;
+ t6+=2;
+ tr2=wa1[index+i-2]*cc[t3-1]+wa1[index+i-1]*cc[t3];
+ ti2=wa1[index+i-2]*cc[t3]-wa1[index+i-1]*cc[t3-1];
+ ch[t6]=cc[t5]+ti2;
+ ch[t4]=ti2-cc[t5];
+ ch[t6-1]=cc[t5-1]+tr2;
+ ch[t4-1]=cc[t5-1]-tr2;
+ }
+ t1+=ido;
+ t2+=ido;
+ }
+ if(ido%2==1)return;
+ }
+
+ t3=(t2=(t1=ido)-1);
+ t2+=t0;
+ for(k=0;k<l1;k++){
+ ch[t1]=-cc[t2];
+ ch[t1-1]=cc[t3];
+ t1+=ido<<1;
+ t2+=ido;
+ t3+=ido;
+ }
+ }
+
+ static void dradf4(int ido,int l1,float[] cc, float[] ch,
+ float[] wa1, int index1,
+ float[] wa2, int index2,
+ float[] wa3, int index3){
+ int i,k,t0,t1,t2,t3,t4,t5,t6;
+ float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
+ t0=l1*ido;
+
+ t1=t0;
+ t4=t1<<1;
+ t2=t1+(t1<<1);
+ t3=0;
+
+ for(k=0;k<l1;k++){
+ tr1=cc[t1]+cc[t2];
+ tr2=cc[t3]+cc[t4];
+
+ ch[t5=t3<<2]=tr1+tr2;
+ ch[(ido<<2)+t5-1]=tr2-tr1;
+ ch[(t5+=(ido<<1))-1]=cc[t3]-cc[t4];
+ ch[t5]=cc[t2]-cc[t1];
+
+ t1+=ido;
+ t2+=ido;
+ t3+=ido;
+ t4+=ido;
+ }
+ if(ido<2)return;
+
+ if(ido!=2){
+ t1=0;
+ for(k=0;k<l1;k++){
+ t2=t1;
+ t4=t1<<2;
+ t5=(t6=ido<<1)+t4;
+ for(i=2;i<ido;i+=2){
+ t3=(t2+=2);
+ t4+=2;
+ t5-=2;
+
+ t3+=t0;
+ cr2=wa1[index1+i-2]*cc[t3-1]+wa1[index1+i-1]*cc[t3];
+ ci2=wa1[index1+i-2]*cc[t3]-wa1[index1+i-1]*cc[t3-1];
+ t3+=t0;
+ cr3=wa2[index2+i-2]*cc[t3-1]+wa2[index2+i-1]*cc[t3];
+ ci3=wa2[index2+i-2]*cc[t3]-wa2[index2+i-1]*cc[t3-1];
+ t3+=t0;
+ cr4=wa3[index3+i-2]*cc[t3-1]+wa3[index3+i-1]*cc[t3];
+ ci4=wa3[index3+i-2]*cc[t3]-wa3[index3+i-1]*cc[t3-1];
+
+ tr1=cr2+cr4;
+ tr4=cr4-cr2;
+ ti1=ci2+ci4;
+ ti4=ci2-ci4;
+
+ ti2=cc[t2]+ci3;
+ ti3=cc[t2]-ci3;
+ tr2=cc[t2-1]+cr3;
+ tr3=cc[t2-1]-cr3;
+
+ ch[t4-1]=tr1+tr2;
+ ch[t4]=ti1+ti2;
+
+ ch[t5-1]=tr3-ti4;
+ ch[t5]=tr4-ti3;
+
+ ch[t4+t6-1]=ti4+tr3;
+ ch[t4+t6]=tr4+ti3;
+
+ ch[t5+t6-1]=tr2-tr1;
+ ch[t5+t6]=ti1-ti2;
+ }
+ t1+=ido;
+ }
+ if((ido&1)!=0)return;
+ }
+
+ t2=(t1=t0+ido-1)+(t0<<1);
+ t3=ido<<2;
+ t4=ido;
+ t5=ido<<1;
+ t6=ido;
+
+ for(k=0;k<l1;k++){
+ ti1=-hsqt2*(cc[t1]+cc[t2]);
+ tr1=hsqt2*(cc[t1]-cc[t2]);
+
+ ch[t4-1]=tr1+cc[t6-1];
+ ch[t4+t5-1]=cc[t6-1]-tr1;
+
+ ch[t4]=ti1-cc[t1+t0];
+ ch[t4+t5]=ti1+cc[t1+t0];
+
+ t1+=ido;
+ t2+=ido;
+ t4+=t3;
+ t6+=ido;
+ }
+ }
+
+ static void dradfg(int ido,int ip,int l1,int idl1,float[] cc,float[] c1,
+ float[] c2, float[] ch, float[] ch2, float[] wa, int index){
+ int idij,ipph,i,j,k,l,ic,ik,is;
+ int t0,t1,t2=0,t3,t4,t5,t6,t7,t8,t9,t10;
+ float dc2,ai1,ai2,ar1,ar2,ds2;
+ int nbd;
+ float dcp=0,arg,dsp=0,ar1h,ar2h;
+ int idp2,ipp2;
+
+ arg=tpi/(float)ip;
+ dcp=(float)Math.cos(arg);
+ dsp=(float)Math.sin(arg);
+ ipph=(ip+1)>>1;
+ ipp2=ip;
+ idp2=ido;
+ nbd=(ido-1)>>1;
+ t0=l1*ido;
+ t10=ip*ido;
+
+ int state=100;
+ loop: while(true){
+ switch(state){
+ case 101:
+ if(ido==1){
+ state=119;
+ break;
+ }
+ for(ik=0;ik<idl1;ik++)ch2[ik]=c2[ik];
+
+ t1=0;
+ for(j=1;j<ip;j++){
+ t1+=t0;
+ t2=t1;
+ for(k=0;k<l1;k++){
+ ch[t2]=c1[t2];
+ t2+=ido;
+ }
+ }
+
+ is=-ido;
+ t1=0;
+ if(nbd>l1){
+ for(j=1;j<ip;j++){
+ t1+=t0;
+ is+=ido;
+ t2= -ido+t1;
+ for(k=0;k<l1;k++){
+ idij=is-1;
+ t2+=ido;
+ t3=t2;
+ for(i=2;i<ido;i+=2){
+ idij+=2;
+ t3+=2;
+ ch[t3-1]=wa[index+idij-1]*c1[t3-1]+wa[index+idij]*c1[t3];
+ ch[t3]=wa[index+idij-1]*c1[t3]-wa[index+idij]*c1[t3-1];
+ }
+ }
+ }
+ }
+ else{
+
+ for(j=1;j<ip;j++){
+ is+=ido;
+ idij=is-1;
+ t1+=t0;
+ t2=t1;
+ for(i=2;i<ido;i+=2){
+ idij+=2;
+ t2+=2;
+ t3=t2;
+ for(k=0;k<l1;k++){
+ ch[t3-1]=wa[index+idij-1]*c1[t3-1]+wa[index+idij]*c1[t3];
+ ch[t3]=wa[index+idij-1]*c1[t3]-wa[index+idij]*c1[t3-1];
+ t3+=ido;
+ }
+ }
+ }
+ }
+
+ t1=0;
+ t2=ipp2*t0;
+ if(nbd<l1){
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ for(i=2;i<ido;i+=2){
+ t3+=2;
+ t4+=2;
+ t5=t3-ido;
+ t6=t4-ido;
+ for(k=0;k<l1;k++){
+ t5+=ido;
+ t6+=ido;
+ c1[t5-1]=ch[t5-1]+ch[t6-1];
+ c1[t6-1]=ch[t5]-ch[t6];
+ c1[t5]=ch[t5]+ch[t6];
+ c1[t6]=ch[t6-1]-ch[t5-1];
+ }
+ }
+ }
+ }
+ else{
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ for(k=0;k<l1;k++){
+ t5=t3;
+ t6=t4;
+ for(i=2;i<ido;i+=2){
+ t5+=2;
+ t6+=2;
+ c1[t5-1]=ch[t5-1]+ch[t6-1];
+ c1[t6-1]=ch[t5]-ch[t6];
+ c1[t5]=ch[t5]+ch[t6];
+ c1[t6]=ch[t6-1]-ch[t5-1];
+ }
+ t3+=ido;
+ t4+=ido;
+ }
+ }
+ }
+ case 119:
+ for(ik=0;ik<idl1;ik++)c2[ik]=ch2[ik];
+
+ t1=0;
+ t2=ipp2*idl1;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1-ido;
+ t4=t2-ido;
+ for(k=0;k<l1;k++){
+ t3+=ido;
+ t4+=ido;
+ c1[t3]=ch[t3]+ch[t4];
+ c1[t4]=ch[t4]-ch[t3];
+ }
+ }
+
+ ar1=1.f;
+ ai1=0.f;
+ t1=0;
+ t2=ipp2*idl1;
+ t3=(ip-1)*idl1;
+ for(l=1;l<ipph;l++){
+ t1+=idl1;
+ t2-=idl1;
+ ar1h=dcp*ar1-dsp*ai1;
+ ai1=dcp*ai1+dsp*ar1;
+ ar1=ar1h;
+ t4=t1;
+ t5=t2;
+ t6=t3;
+ t7=idl1;
+
+ for(ik=0;ik<idl1;ik++){
+ ch2[t4++]=c2[ik]+ar1*c2[t7++];
+ ch2[t5++]=ai1*c2[t6++];
+ }
+
+ dc2=ar1;
+ ds2=ai1;
+ ar2=ar1;
+ ai2=ai1;
+
+ t4=idl1;
+ t5=(ipp2-1)*idl1;
+ for(j=2;j<ipph;j++){
+ t4+=idl1;
+ t5-=idl1;
+
+ ar2h=dc2*ar2-ds2*ai2;
+ ai2=dc2*ai2+ds2*ar2;
+ ar2=ar2h;
+
+ t6=t1;
+ t7=t2;
+ t8=t4;
+ t9=t5;
+ for(ik=0;ik<idl1;ik++){
+ ch2[t6++]+=ar2*c2[t8++];
+ ch2[t7++]+=ai2*c2[t9++];
+ }
+ }
+ }
+ t1=0;
+ for(j=1;j<ipph;j++){
+ t1+=idl1;
+ t2=t1;
+ for(ik=0;ik<idl1;ik++)ch2[ik]+=c2[t2++];
+ }
+
+ if(ido<l1){
+ state=132;
+ break;
+ }
+
+ t1=0;
+ t2=0;
+ for(k=0;k<l1;k++){
+ t3=t1;
+ t4=t2;
+ for(i=0;i<ido;i++)cc[t4++]=ch[t3++];
+ t1+=ido;
+ t2+=t10;
+ }
+ state=135;
+ break;
+
+ case 132:
+ for(i=0;i<ido;i++){
+ t1=i;
+ t2=i;
+ for(k=0;k<l1;k++){
+ cc[t2]=ch[t1];
+ t1+=ido;
+ t2+=t10;
+ }
+ }
+ case 135:
+ t1=0;
+ t2=ido<<1;
+ t3=0;
+ t4=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t2;
+ t3+=t0;
+ t4-=t0;
+
+ t5=t1;
+ t6=t3;
+ t7=t4;
+
+ for(k=0;k<l1;k++){
+ cc[t5-1]=ch[t6];
+ cc[t5]=ch[t7];
+ t5+=t10;
+ t6+=ido;
+ t7+=ido;
+ }
+ }
+
+ if(ido==1)return;
+ if(nbd<l1){
+ state=141;
+ break;
+ }
+
+ t1=-ido;
+ t3=0;
+ t4=0;
+ t5=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t2;
+ t3+=t2;
+ t4+=t0;
+ t5-=t0;
+ t6=t1;
+ t7=t3;
+ t8=t4;
+ t9=t5;
+ for(k=0;k<l1;k++){
+ for(i=2;i<ido;i+=2){
+ ic=idp2-i;
+ cc[i+t7-1]=ch[i+t8-1]+ch[i+t9-1];
+ cc[ic+t6-1]=ch[i+t8-1]-ch[i+t9-1];
+ cc[i+t7]=ch[i+t8]+ch[i+t9];
+ cc[ic+t6]=ch[i+t9]-ch[i+t8];
+ }
+ t6+=t10;
+ t7+=t10;
+ t8+=ido;
+ t9+=ido;
+ }
+ }
+ return;
+ case 141:
+ t1=-ido;
+ t3=0;
+ t4=0;
+ t5=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t2;
+ t3+=t2;
+ t4+=t0;
+ t5-=t0;
+ for(i=2;i<ido;i+=2){
+ t6=idp2+t1-i;
+ t7=i+t3;
+ t8=i+t4;
+ t9=i+t5;
+ for(k=0;k<l1;k++){
+ cc[t7-1]=ch[t8-1]+ch[t9-1];
+ cc[t6-1]=ch[t8-1]-ch[t9-1];
+ cc[t7]=ch[t8]+ch[t9];
+ cc[t6]=ch[t9]-ch[t8];
+ t6+=t10;
+ t7+=t10;
+ t8+=ido;
+ t9+=ido;
+ }
+ }
+ }
+ break loop;
+ }
+ }
+ }
+
+ static void drftf1(int n,float[] c, float[] ch, float[] wa, int[] ifac){
+ int i,k1,l1,l2;
+ int na,kh,nf;
+ int ip,iw,ido,idl1,ix2,ix3;
+
+ nf=ifac[1];
+ na=1;
+ l2=n;
+ iw=n;
+
+ for(k1=0;k1<nf;k1++){
+ kh=nf-k1;
+ ip=ifac[kh+1];
+ l1=l2/ip;
+ ido=n/l2;
+ idl1=ido*l1;
+ iw-=(ip-1)*ido;
+ na=1-na;
+
+ int state=100;
+ loop: while(true){
+ switch(state){
+ case 100:
+ if(ip!=4){
+ state=102;
+ break;
+ }
+
+ ix2=iw+ido;
+ ix3=ix2+ido;
+ if(na!=0)
+ dradf4(ido,l1,ch,c,wa,iw-1,wa,ix2-1,wa,ix3-1);
+ else
+ dradf4(ido,l1,c,ch,wa,iw-1,wa,ix2-1,wa,ix3-1);
+ state=110;
+ break;
+ case 102:
+ if(ip!=2){
+ state=104;
+ break;
+ }
+ if(na!=0){
+ state=103;
+ break;
+ }
+ dradf2(ido,l1,c,ch,wa, iw-1);
+ state=110;
+ break;
+ case 103:
+ dradf2(ido,l1,ch,c,wa, iw-1);
+ case 104:
+ if(ido==1)na=1-na;
+ if(na!=0){
+ state=109;
+ break;
+ }
+ dradfg(ido,ip,l1,idl1,c,c,c,ch,ch,wa,iw-1);
+ na=1;
+ state=110;
+ break;
+ case 109:
+ dradfg(ido,ip,l1,idl1,ch,ch,ch,c,c,wa,iw-1);
+ na=0;
+ case 110:
+ l2=l1;
+ break loop;
+ }
+ }
+ }
+ if(na==1)return;
+ for(i=0;i<n;i++)c[i]=ch[i];
+ }
+
+ static void dradb2(int ido,int l1,float[] cc,float[] ch,float[] wa1, int index){
+ int i,k,t0,t1,t2,t3,t4,t5,t6;
+ float ti2,tr2;
+
+ t0=l1*ido;
+
+ t1=0;
+ t2=0;
+ t3=(ido<<1)-1;
+ for(k=0;k<l1;k++){
+ ch[t1]=cc[t2]+cc[t3+t2];
+ ch[t1+t0]=cc[t2]-cc[t3+t2];
+ t2=(t1+=ido)<<1;
+ }
+
+ if(ido<2)return;
+ if(ido!=2){
+ t1=0;
+ t2=0;
+ for(k=0;k<l1;k++){
+ t3=t1;
+ t5=(t4=t2)+(ido<<1);
+ t6=t0+t1;
+ for(i=2;i<ido;i+=2){
+ t3+=2;
+ t4+=2;
+ t5-=2;
+ t6+=2;
+ ch[t3-1]=cc[t4-1]+cc[t5-1];
+ tr2=cc[t4-1]-cc[t5-1];
+ ch[t3]=cc[t4]-cc[t5];
+ ti2=cc[t4]+cc[t5];
+ ch[t6-1]=wa1[index+i-2]*tr2-wa1[index+i-1]*ti2;
+ ch[t6]=wa1[index+i-2]*ti2+wa1[index+i-1]*tr2;
+ }
+ t2=(t1+=ido)<<1;
+ }
+ if((ido%2)==1)return;
+ }
+
+ t1=ido-1;
+ t2=ido-1;
+ for(k=0;k<l1;k++){
+ ch[t1]=cc[t2]+cc[t2];
+ ch[t1+t0]=-(cc[t2+1]+cc[t2+1]);
+ t1+=ido;
+ t2+=ido<<1;
+ }
+ }
+
+ static void dradb3(int ido,int l1,float[] cc,float[] ch,
+ float[] wa1, int index1,
+ float[] wa2, int index2){
+ int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10;
+ float ci2,ci3,di2,di3,cr2,cr3,dr2,dr3,ti2,tr2;
+ t0=l1*ido;
+
+ t1=0;
+ t2=t0<<1;
+ t3=ido<<1;
+ t4=ido+(ido<<1);
+ t5=0;
+ for(k=0;k<l1;k++){
+ tr2=cc[t3-1]+cc[t3-1];
+ cr2=cc[t5]+(taur*tr2);
+ ch[t1]=cc[t5]+tr2;
+ ci3=taui*(cc[t3]+cc[t3]);
+ ch[t1+t0]=cr2-ci3;
+ ch[t1+t2]=cr2+ci3;
+ t1+=ido;
+ t3+=t4;
+ t5+=t4;
+ }
+
+ if(ido==1)return;
+
+ t1=0;
+ t3=ido<<1;
+ for(k=0;k<l1;k++){
+ t7=t1+(t1<<1);
+ t6=(t5=t7+t3);
+ t8=t1;
+ t10=(t9=t1+t0)+t0;
+
+ for(i=2;i<ido;i+=2){
+ t5+=2;
+ t6-=2;
+ t7+=2;
+ t8+=2;
+ t9+=2;
+ t10+=2;
+ tr2=cc[t5-1]+cc[t6-1];
+ cr2=cc[t7-1]+(taur*tr2);
+ ch[t8-1]=cc[t7-1]+tr2;
+ ti2=cc[t5]-cc[t6];
+ ci2=cc[t7]+(taur*ti2);
+ ch[t8]=cc[t7]+ti2;
+ cr3=taui*(cc[t5-1]-cc[t6-1]);
+ ci3=taui*(cc[t5]+cc[t6]);
+ dr2=cr2-ci3;
+ dr3=cr2+ci3;
+ di2=ci2+cr3;
+ di3=ci2-cr3;
+ ch[t9-1]=wa1[index1+i-2]*dr2-wa1[index1+i-1]*di2;
+ ch[t9]=wa1[index1+i-2]*di2+wa1[index1+i-1]*dr2;
+ ch[t10-1]=wa2[index2+i-2]*dr3-wa2[index2+i-1]*di3;
+ ch[t10]=wa2[index2+i-2]*di3+wa2[index2+i-1]*dr3;
+ }
+ t1+=ido;
+ }
+ }
+
+ static void dradb4(int ido,int l1,float[] cc,float[] ch,
+ float[] wa1, int index1,
+ float[] wa2, int index2,
+ float[] wa3, int index3){
+ int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8;
+ float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
+ t0=l1*ido;
+
+ t1=0;
+ t2=ido<<2;
+ t3=0;
+ t6=ido<<1;
+ for(k=0;k<l1;k++){
+ t4=t3+t6;
+ t5=t1;
+ tr3=cc[t4-1]+cc[t4-1];
+ tr4=cc[t4]+cc[t4];
+ tr1=cc[t3]-cc[(t4+=t6)-1];
+ tr2=cc[t3]+cc[t4-1];
+ ch[t5]=tr2+tr3;
+ ch[t5+=t0]=tr1-tr4;
+ ch[t5+=t0]=tr2-tr3;
+ ch[t5+=t0]=tr1+tr4;
+ t1+=ido;
+ t3+=t2;
+ }
+
+ if(ido<2)return;
+ if(ido!=2){
+ t1=0;
+ for(k=0;k<l1;k++){
+ t5=(t4=(t3=(t2=t1<<2)+t6))+t6;
+ t7=t1;
+ for(i=2;i<ido;i+=2){
+ t2+=2;
+ t3+=2;
+ t4-=2;
+ t5-=2;
+ t7+=2;
+ ti1=cc[t2]+cc[t5];
+ ti2=cc[t2]-cc[t5];
+ ti3=cc[t3]-cc[t4];
+ tr4=cc[t3]+cc[t4];
+ tr1=cc[t2-1]-cc[t5-1];
+ tr2=cc[t2-1]+cc[t5-1];
+ ti4=cc[t3-1]-cc[t4-1];
+ tr3=cc[t3-1]+cc[t4-1];
+ ch[t7-1]=tr2+tr3;
+ cr3=tr2-tr3;
+ ch[t7]=ti2+ti3;
+ ci3=ti2-ti3;
+ cr2=tr1-tr4;
+ cr4=tr1+tr4;
+ ci2=ti1+ti4;
+ ci4=ti1-ti4;
+
+ ch[(t8=t7+t0)-1]=wa1[index1+i-2]*cr2-wa1[index1+i-1]*ci2;
+ ch[t8]=wa1[index1+i-2]*ci2+wa1[index1+i-1]*cr2;
+ ch[(t8+=t0)-1]=wa2[index2+i-2]*cr3-wa2[index2+i-1]*ci3;
+ ch[t8]=wa2[index2+i-2]*ci3+wa2[index2+i-1]*cr3;
+ ch[(t8+=t0)-1]=wa3[index3+i-2]*cr4-wa3[index3+i-1]*ci4;
+ ch[t8]=wa3[index3+i-2]*ci4+wa3[index3+i-1]*cr4;
+ }
+ t1+=ido;
+ }
+ if(ido%2 == 1)return;
+ }
+
+ t1=ido;
+ t2=ido<<2;
+ t3=ido-1;
+ t4=ido+(ido<<1);
+ for(k=0;k<l1;k++){
+ t5=t3;
+ ti1=cc[t1]+cc[t4];
+ ti2=cc[t4]-cc[t1];
+ tr1=cc[t1-1]-cc[t4-1];
+ tr2=cc[t1-1]+cc[t4-1];
+ ch[t5]=tr2+tr2;
+ ch[t5+=t0]=sqrt2*(tr1-ti1);
+ ch[t5+=t0]=ti2+ti2;
+ ch[t5+=t0]=-sqrt2*(tr1+ti1);
+
+ t3+=ido;
+ t1+=t2;
+ t4+=t2;
+ }
+ }
+
+ static void dradbg(int ido,int ip,int l1,int idl1,float[] cc,float[] c1,
+ float[] c2,float[] ch,float[] ch2,float[] wa, int index ){
+
+ int idij,ipph=0,i,j,k,l,ik,is,t0=0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10=0,
+ t11,t12;
+ float dc2,ai1,ai2,ar1,ar2,ds2;
+ int nbd=0;
+ float dcp=0,arg,dsp=0,ar1h,ar2h;
+ int ipp2=0;
+
+ int state=100;
+
+ loop: while(true){
+ switch(state){
+ case 100:
+ t10=ip*ido;
+ t0=l1*ido;
+ arg=tpi/(float)ip;
+ dcp=(float)Math.cos(arg);
+ dsp=(float)Math.sin(arg);
+ nbd=(ido-1)>>>1;
+ ipp2=ip;
+ ipph=(ip+1)>>>1;
+ if(ido<l1){
+ state=103;
+ break;
+ }
+ t1=0;
+ t2=0;
+ for(k=0;k<l1;k++){
+ t3=t1;
+ t4=t2;
+ for(i=0;i<ido;i++){
+ ch[t3]=cc[t4];
+ t3++;
+ t4++;
+ }
+ t1+=ido;
+ t2+=t10;
+ }
+ state=106;
+ break;
+ case 103:
+ t1=0;
+ for(i=0;i<ido;i++){
+ t2=t1;
+ t3=t1;
+ for(k=0;k<l1;k++){
+ ch[t2]=cc[t3];
+ t2+=ido;
+ t3+=t10;
+ }
+ t1++;
+ }
+ case 106:
+ t1=0;
+ t2=ipp2*t0;
+ t7=(t5=ido<<1);
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ t6=t5;
+ for(k=0;k<l1;k++){
+ ch[t3]=cc[t6-1]+cc[t6-1];
+ ch[t4]=cc[t6]+cc[t6];
+ t3+=ido;
+ t4+=ido;
+ t6+=t10;
+ }
+ t5+=t7;
+ }
+ if (ido == 1){
+ state=116;
+ break;
+ }
+ if(nbd<l1){
+ state=112;
+ break;
+ }
+
+ t1=0;
+ t2=ipp2*t0;
+ t7=0;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+
+ t7+=(ido<<1);
+ t8=t7;
+ for(k=0;k<l1;k++){
+ t5=t3;
+ t6=t4;
+ t9=t8;
+ t11=t8;
+ for(i=2;i<ido;i+=2){
+ t5+=2;
+ t6+=2;
+ t9+=2;
+ t11-=2;
+ ch[t5-1]=cc[t9-1]+cc[t11-1];
+ ch[t6-1]=cc[t9-1]-cc[t11-1];
+ ch[t5]=cc[t9]-cc[t11];
+ ch[t6]=cc[t9]+cc[t11];
+ }
+ t3+=ido;
+ t4+=ido;
+ t8+=t10;
+ }
+ }
+ state=116;
+ break;
+ case 112:
+ t1=0;
+ t2=ipp2*t0;
+ t7=0;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ t7+=(ido<<1);
+ t8=t7;
+ t9=t7;
+ for(i=2;i<ido;i+=2){
+ t3+=2;
+ t4+=2;
+ t8+=2;
+ t9-=2;
+ t5=t3;
+ t6=t4;
+ t11=t8;
+ t12=t9;
+ for(k=0;k<l1;k++){
+ ch[t5-1]=cc[t11-1]+cc[t12-1];
+ ch[t6-1]=cc[t11-1]-cc[t12-1];
+ ch[t5]=cc[t11]-cc[t12];
+ ch[t6]=cc[t11]+cc[t12];
+ t5+=ido;
+ t6+=ido;
+ t11+=t10;
+ t12+=t10;
+ }
+ }
+ }
+ case 116:
+ ar1=1.f;
+ ai1=0.f;
+ t1=0;
+ t9=(t2=ipp2*idl1);
+ t3=(ip-1)*idl1;
+ for(l=1;l<ipph;l++){
+ t1+=idl1;
+ t2-=idl1;
+
+ ar1h=dcp*ar1-dsp*ai1;
+ ai1=dcp*ai1+dsp*ar1;
+ ar1=ar1h;
+ t4=t1;
+ t5=t2;
+ t6=0;
+ t7=idl1;
+ t8=t3;
+ for(ik=0;ik<idl1;ik++){
+ c2[t4++]=ch2[t6++]+ar1*ch2[t7++];
+ c2[t5++]=ai1*ch2[t8++];
+ }
+ dc2=ar1;
+ ds2=ai1;
+ ar2=ar1;
+ ai2=ai1;
+
+ t6=idl1;
+ t7=t9-idl1;
+ for(j=2;j<ipph;j++){
+ t6+=idl1;
+ t7-=idl1;
+ ar2h=dc2*ar2-ds2*ai2;
+ ai2=dc2*ai2+ds2*ar2;
+ ar2=ar2h;
+ t4=t1;
+ t5=t2;
+ t11=t6;
+ t12=t7;
+ for(ik=0;ik<idl1;ik++){
+ c2[t4++]+=ar2*ch2[t11++];
+ c2[t5++]+=ai2*ch2[t12++];
+ }
+ }
+ }
+
+ t1=0;
+ for(j=1;j<ipph;j++){
+ t1+=idl1;
+ t2=t1;
+ for(ik=0;ik<idl1;ik++)ch2[ik]+=ch2[t2++];
+ }
+
+ t1=0;
+ t2=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ for(k=0;k<l1;k++){
+ ch[t3]=c1[t3]-c1[t4];
+ ch[t4]=c1[t3]+c1[t4];
+ t3+=ido;
+ t4+=ido;
+ }
+ }
+
+ if(ido==1){
+ state=132;
+ break;
+ }
+ if(nbd<l1){
+ state=128;
+ break;
+ }
+
+ t1=0;
+ t2=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ for(k=0;k<l1;k++){
+ t5=t3;
+ t6=t4;
+ for(i=2;i<ido;i+=2){
+ t5+=2;
+ t6+=2;
+ ch[t5-1]=c1[t5-1]-c1[t6];
+ ch[t6-1]=c1[t5-1]+c1[t6];
+ ch[t5]=c1[t5]+c1[t6-1];
+ ch[t6]=c1[t5]-c1[t6-1];
+ }
+ t3+=ido;
+ t4+=ido;
+ }
+ }
+ state=132;
+ break;
+ case 128:
+ t1=0;
+ t2=ipp2*t0;
+ for(j=1;j<ipph;j++){
+ t1+=t0;
+ t2-=t0;
+ t3=t1;
+ t4=t2;
+ for(i=2;i<ido;i+=2){
+ t3+=2;
+ t4+=2;
+ t5=t3;
+ t6=t4;
+ for(k=0;k<l1;k++){
+ ch[t5-1]=c1[t5-1]-c1[t6];
+ ch[t6-1]=c1[t5-1]+c1[t6];
+ ch[t5]=c1[t5]+c1[t6-1];
+ ch[t6]=c1[t5]-c1[t6-1];
+ t5+=ido;
+ t6+=ido;
+ }
+ }
+ }
+ case 132:
+ if(ido==1)return;
+
+ for(ik=0;ik<idl1;ik++)c2[ik]=ch2[ik];
+
+ t1=0;
+ for(j=1;j<ip;j++){
+ t2=(t1+=t0);
+ for(k=0;k<l1;k++){
+ c1[t2]=ch[t2];
+ t2+=ido;
+ }
+ }
+
+ if(nbd>l1){
+ state=139;
+ break;
+ }
+
+ is= -ido-1;
+ t1=0;
+ for(j=1;j<ip;j++){
+ is+=ido;
+ t1+=t0;
+ idij=is;
+ t2=t1;
+ for(i=2;i<ido;i+=2){
+ t2+=2;
+ idij+=2;
+ t3=t2;
+ for(k=0;k<l1;k++){
+ c1[t3-1]=wa[index+idij-1]*ch[t3-1]-wa[index+idij]*ch[t3];
+ c1[t3]=wa[index+idij-1]*ch[t3]+wa[index+idij]*ch[t3-1];
+ t3+=ido;
+ }
+ }
+ }
+ return;
+
+ case 139:
+ is= -ido-1;
+ t1=0;
+ for(j=1;j<ip;j++){
+ is+=ido;
+ t1+=t0;
+ t2=t1;
+ for(k=0;k<l1;k++){
+ idij=is;
+ t3=t2;
+ for(i=2;i<ido;i+=2){
+ idij+=2;
+ t3+=2;
+ c1[t3-1]=wa[index+idij-1]*ch[t3-1]-wa[index+idij]*ch[t3];
+ c1[t3]=wa[index+idij-1]*ch[t3]+wa[index+idij]*ch[t3-1];
+ }
+ t2+=ido;
+ }
+ }
+ break loop;
+ }
+ }
+ }
+
+ static void drftb1(int n, float[] c, float[] ch, float[] wa, int index, int[] ifac){
+ int i,k1,l1,l2=0;
+ int na;
+ int nf,ip=0,iw,ix2,ix3,ido=0,idl1=0;
+
+ nf=ifac[1];
+ na=0;
+ l1=1;
+ iw=1;
+
+ for(k1=0;k1<nf;k1++){
+ int state=100;
+ loop: while(true){
+ switch(state){
+ case 100:
+ ip=ifac[k1 + 2];
+ l2=ip*l1;
+ ido=n/l2;
+ idl1=ido*l1;
+ if(ip!=4){
+ state=103;
+ break;
+ }
+ ix2=iw+ido;
+ ix3=ix2+ido;
+
+ if(na!=0)
+ dradb4(ido,l1,ch,c,wa,index+iw-1,wa,index+ix2-1,wa,index+ix3-1);
+ else
+ dradb4(ido,l1,c,ch,wa,index+iw-1,wa,index+ix2-1,wa,index+ix3-1);
+ na=1-na;
+ state=115;
+ break;
+ case 103:
+ if(ip!=2){
+ state=106;
+ break;
+ }
+
+ if(na!=0)
+ dradb2(ido,l1,ch,c,wa,index+iw-1);
+ else
+ dradb2(ido,l1,c,ch,wa,index+iw-1);
+ na=1-na;
+ state=115;
+ break;
+
+ case 106:
+ if(ip!=3){
+ state=109;
+ break;
+ }
+
+ ix2=iw+ido;
+ if(na!=0)
+ dradb3(ido,l1,ch,c,wa,index+iw-1,wa,index+ix2-1);
+ else
+ dradb3(ido,l1,c,ch,wa,index+iw-1,wa,index+ix2-1);
+ na=1-na;
+ state=115;
+ break;
+ case 109:
+ // The radix five case can be translated later.....
+ // if(ip!=5)goto L112;
+ //
+ //ix2=iw+ido;
+ //ix3=ix2+ido;
+ //ix4=ix3+ido;
+ //if(na!=0)
+ // dradb5(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1,wa+ix4-1);
+ //else
+ // dradb5(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1,wa+ix4-1);
+ //na=1-na;
+ //state=115;
+ //break;
+ if(na!=0)
+ dradbg(ido,ip,l1,idl1,ch,ch,ch,c,c,wa,index+iw-1);
+ else
+ dradbg(ido,ip,l1,idl1,c,c,c,ch,ch,wa,index+iw-1);
+ if(ido==1)na=1-na;
+
+ case 115:
+ l1=l2;
+ iw+=(ip-1)*ido;
+ break loop;
+ }
+ }
+ }
+ if(na==0)return;
+ for(i=0;i<n;i++)c[i]=ch[i];
+ }
+}
diff --git a/songdbj/com/jcraft/jorbis/DspState.java b/songdbj/com/jcraft/jorbis/DspState.java
new file mode 100644
index 0000000000..5676f640c1
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/DspState.java
@@ -0,0 +1,459 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+public class DspState{
+ static final float M_PI=3.1415926539f;
+ static final int VI_TRANSFORMB=1;
+ static final int VI_WINDOWB=1;
+
+ int analysisp;
+ Info vi;
+ int modebits;
+
+ float[][] pcm;
+ //float[][] pcmret;
+ int pcm_storage;
+ int pcm_current;
+ int pcm_returned;
+
+ float[] multipliers;
+ int envelope_storage;
+ int envelope_current;
+
+ int eofflag;
+
+ int lW;
+ int W;
+ int nW;
+ int centerW;
+
+ long granulepos;
+ long sequence;
+
+ long glue_bits;
+ long time_bits;
+ long floor_bits;
+ long res_bits;
+
+ // local lookup storage
+//!! Envelope ve=new Envelope(); // envelope
+//float **window[2][2][2]; // block, leadin, leadout, type
+ float[][][][][] window; // block, leadin, leadout, type
+ //vorbis_look_transform **transform[2]; // block, type
+ Object[][] transform;
+ CodeBook[] fullbooks;
+ // backend lookups are tied to the mode, not the backend or naked mapping
+ Object[] mode;
+
+ // local storage, only used on the encoding side. This way the
+ // application does not need to worry about freeing some packets'
+ // memory and not others'; packet storage is always tracked.
+ // Cleared next call to a _dsp_ function
+ byte[] header;
+ byte[] header1;
+ byte[] header2;
+
+ public DspState(){
+ transform=new Object[2][];
+ window=new float[2][][][][];
+ window[0]=new float[2][][][];
+ window[0][0]=new float[2][][];
+ window[0][1]=new float[2][][];
+ window[0][0][0]=new float[2][];
+ window[0][0][1]=new float[2][];
+ window[0][1][0]=new float[2][];
+ window[0][1][1]=new float[2][];
+ window[1]=new float[2][][][];
+ window[1][0]=new float[2][][];
+ window[1][1]=new float[2][][];
+ window[1][0][0]=new float[2][];
+ window[1][0][1]=new float[2][];
+ window[1][1][0]=new float[2][];
+ window[1][1][1]=new float[2][];
+ }
+
+ private static int ilog2(int v){
+ int ret=0;
+ while(v>1){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+
+ static float[] window(int type, int window, int left, int right){
+ float[] ret=new float[window];
+ switch(type){
+ case 0:
+ // The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*2pi)
+ {
+ int leftbegin=window/4-left/2;
+ int rightbegin=window-window/4-right/2;
+
+ for(int i=0;i<left;i++){
+ float x=(float)((i+.5)/left*M_PI/2.);
+ x=(float)Math.sin(x);
+ x*=x;
+ x*=M_PI/2.;
+ x=(float)Math.sin(x);
+ ret[i+leftbegin]=x;
+ }
+
+ for(int i=leftbegin+left;i<rightbegin;i++){
+ ret[i]=1.f;
+ }
+
+ for(int i=0;i<right;i++){
+ float x=(float)((right-i-.5)/right*M_PI/2.);
+ x=(float)Math.sin(x);
+ x*=x;
+ x*=M_PI/2.;
+ x=(float)Math.sin(x);
+ ret[i+rightbegin]=x;
+ }
+ }
+ break;
+ default:
+ //free(ret);
+ return(null);
+ }
+ return(ret);
+ }
+
+ // Analysis side code, but directly related to blocking. Thus it's
+ // here and not in analysis.c (which is for analysis transforms only).
+ // The init is here because some of it is shared
+
+ int init(Info vi, boolean encp){
+//System.err.println("DspState.init: vi="+vi+", encp="+encp);
+ //memset(v,0,sizeof(vorbis_dsp_state));
+ this.vi=vi;
+ modebits=ilog2(vi.modes);
+
+ transform[0]=new Object[VI_TRANSFORMB];
+ transform[1]=new Object[VI_TRANSFORMB];
+
+ // MDCT is tranform 0
+
+ transform[0][0]=new Mdct();
+ transform[1][0]=new Mdct();
+ ((Mdct)transform[0][0]).init(vi.blocksizes[0]);
+ ((Mdct)transform[1][0]).init(vi.blocksizes[1]);
+
+ window[0][0][0]=new float[VI_WINDOWB][];
+ window[0][0][1]=window[0][0][0];
+ window[0][1][0]=window[0][0][0];
+ window[0][1][1]=window[0][0][0];
+ window[1][0][0]=new float[VI_WINDOWB][];
+ window[1][0][1]=new float[VI_WINDOWB][];
+ window[1][1][0]=new float[VI_WINDOWB][];
+ window[1][1][1]=new float[VI_WINDOWB][];
+
+ for(int i=0;i<VI_WINDOWB;i++){
+ window[0][0][0][i]=
+ window(i,vi.blocksizes[0],vi.blocksizes[0]/2,vi.blocksizes[0]/2);
+ window[1][0][0][i]=
+ window(i,vi.blocksizes[1],vi.blocksizes[0]/2,vi.blocksizes[0]/2);
+ window[1][0][1][i]=
+ window(i,vi.blocksizes[1],vi.blocksizes[0]/2,vi.blocksizes[1]/2);
+ window[1][1][0][i]=
+ window(i,vi.blocksizes[1],vi.blocksizes[1]/2,vi.blocksizes[0]/2);
+ window[1][1][1][i]=
+ window(i,vi.blocksizes[1],vi.blocksizes[1]/2,vi.blocksizes[1]/2);
+ }
+
+// if(encp){ // encode/decode differ here
+// // finish the codebooks
+// fullbooks=new CodeBook[vi.books];
+// for(int i=0;i<vi.books;i++){
+// fullbooks[i]=new CodeBook();
+// fullbooks[i].init_encode(vi.book_param[i]);
+// }
+// analysisp=1;
+// }
+// else{
+ // finish the codebooks
+ fullbooks=new CodeBook[vi.books];
+ for(int i=0;i<vi.books;i++){
+ fullbooks[i]=new CodeBook();
+ fullbooks[i].init_decode(vi.book_param[i]);
+ }
+// }
+
+ // initialize the storage vectors to a decent size greater than the
+ // minimum
+
+ pcm_storage=8192; // we'll assume later that we have
+ // a minimum of twice the blocksize of
+ // accumulated samples in analysis
+ pcm=new float[vi.channels][];
+ //pcmret=new float[vi.channels][];
+ {
+ for(int i=0;i<vi.channels;i++){
+ pcm[i]=new float[pcm_storage];
+ }
+ }
+
+ // all 1 (large block) or 0 (small block)
+ // explicitly set for the sake of clarity
+ lW=0; // previous window size
+ W=0; // current window size
+
+ // all vector indexes; multiples of samples_per_envelope_step
+ centerW=vi.blocksizes[1]/2;
+
+ pcm_current=centerW;
+
+ // initialize all the mapping/backend lookups
+ mode=new Object[vi.modes];
+ for(int i=0;i<vi.modes;i++){
+ int mapnum=vi.mode_param[i].mapping;
+ int maptype=vi.map_type[mapnum];
+ mode[i]=FuncMapping.mapping_P[maptype].look(this,vi.mode_param[i],
+ vi.map_param[mapnum]);
+ }
+ return(0);
+ }
+
+ public int synthesis_init(Info vi){
+ init(vi, false);
+ // Adjust centerW to allow an easier mechanism for determining output
+ pcm_returned=centerW;
+ centerW-= vi.blocksizes[W]/4+vi.blocksizes[lW]/4;
+ granulepos=-1;
+ sequence=-1;
+ return(0);
+ }
+
+ DspState(Info vi){
+ this();
+ init(vi, false);
+ // Adjust centerW to allow an easier mechanism for determining output
+ pcm_returned=centerW;
+ centerW-= vi.blocksizes[W]/4+vi.blocksizes[lW]/4;
+ granulepos=-1;
+ sequence=-1;
+ }
+
+ // Unike in analysis, the window is only partially applied for each
+ // block. The time domain envelope is not yet handled at the point of
+ // calling (as it relies on the previous block).
+
+ public int synthesis_blockin(Block vb){
+ // Shift out any PCM/multipliers that we returned previously
+ // centerW is currently the center of the last block added
+ if(centerW>vi.blocksizes[1]/2 && pcm_returned>8192){
+ // don't shift too much; we need to have a minimum PCM buffer of
+ // 1/2 long block
+
+ int shiftPCM=centerW-vi.blocksizes[1]/2;
+ shiftPCM=(pcm_returned<shiftPCM?pcm_returned:shiftPCM);
+
+ pcm_current-=shiftPCM;
+ centerW-=shiftPCM;
+ pcm_returned-=shiftPCM;
+ if(shiftPCM!=0){
+ for(int i=0;i<vi.channels;i++){
+ System.arraycopy(pcm[i], shiftPCM, pcm[i], 0, pcm_current);
+ }
+ }
+ }
+
+ lW=W;
+ W=vb.W;
+ nW=-1;
+
+ glue_bits+=vb.glue_bits;
+ time_bits+=vb.time_bits;
+ floor_bits+=vb.floor_bits;
+ res_bits+=vb.res_bits;
+
+ if(sequence+1 != vb.sequence)granulepos=-1; // out of sequence; lose count
+
+ sequence=vb.sequence;
+
+ {
+ int sizeW=vi.blocksizes[W];
+ int _centerW=centerW+vi.blocksizes[lW]/4+sizeW/4;
+ int beginW=_centerW-sizeW/2;
+ int endW=beginW+sizeW;
+ int beginSl=0;
+ int endSl=0;
+
+ // Do we have enough PCM/mult storage for the block?
+ if(endW>pcm_storage){
+ // expand the storage
+ pcm_storage=endW+vi.blocksizes[1];
+ for(int i=0;i<vi.channels;i++){
+ float[] foo=new float[pcm_storage];
+ System.arraycopy(pcm[i], 0, foo, 0, pcm[i].length);
+ pcm[i]=foo;
+ }
+ }
+
+ // overlap/add PCM
+ switch(W){
+ case 0:
+ beginSl=0;
+ endSl=vi.blocksizes[0]/2;
+ break;
+ case 1:
+ beginSl=vi.blocksizes[1]/4-vi.blocksizes[lW]/4;
+ endSl=beginSl+vi.blocksizes[lW]/2;
+ break;
+ }
+
+ for(int j=0;j<vi.channels;j++){
+ int _pcm=beginW;
+ // the overlap/add section
+ int i=0;
+ for(i=beginSl;i<endSl;i++){
+ pcm[j][_pcm+i]+=vb.pcm[j][i];
+ }
+ // the remaining section
+ for(;i<sizeW;i++){
+ pcm[j][_pcm+i]=vb.pcm[j][i];
+ }
+ }
+
+ // track the frame number... This is for convenience, but also
+ // making sure our last packet doesn't end with added padding. If
+ // the last packet is partial, the number of samples we'll have to
+ // return will be past the vb->granulepos.
+ //
+ // This is not foolproof! It will be confused if we begin
+ // decoding at the last page after a seek or hole. In that case,
+ // we don't have a starting point to judge where the last frame
+ // is. For this reason, vorbisfile will always try to make sure
+ // it reads the last two marked pages in proper sequence
+
+ if(granulepos==-1){
+ granulepos=vb.granulepos;
+ }
+ else{
+ granulepos+=(_centerW-centerW);
+ if(vb.granulepos!=-1 && granulepos!=vb.granulepos){
+ if(granulepos>vb.granulepos && vb.eofflag!=0){
+ // partial last frame. Strip the padding off
+ _centerW-=(granulepos-vb.granulepos);
+ }// else{ Shouldn't happen *unless* the bitstream is out of
+ // spec. Either way, believe the bitstream }
+ granulepos=vb.granulepos;
+ }
+ }
+
+ // Update, cleanup
+
+ centerW=_centerW;
+ pcm_current=endW;
+ if(vb.eofflag!=0)eofflag=1;
+ }
+ return(0);
+ }
+
+ // pcm==NULL indicates we just want the pending samples, no more
+ public int synthesis_pcmout(float[][][] _pcm, int[] index){
+ if(pcm_returned<centerW){
+ if(_pcm!=null){
+ for(int i=0;i<vi.channels;i++){
+// pcmret[i]=pcm[i]+v.pcm_returned;
+//!!!!!!!!
+ index[i]=pcm_returned;
+ }
+ _pcm[0]=pcm;
+ }
+ return(centerW-pcm_returned);
+ }
+ return(0);
+ }
+
+ public int synthesis_read(int bytes){
+ if(bytes!=0 && pcm_returned+bytes>centerW)return(-1);
+ pcm_returned+=bytes;
+ return(0);
+ }
+
+ public void clear(){
+/*
+ if(window[0][0][0]!=0){
+ for(i=0;i<VI_WINDOWB;i++)
+ if(v->window[0][0][0][i])free(v->window[0][0][0][i]);
+ free(v->window[0][0][0]);
+
+ for(j=0;j<2;j++)
+ for(k=0;k<2;k++){
+ for(i=0;i<VI_WINDOWB;i++)
+ if(v->window[1][j][k][i])free(v->window[1][j][k][i]);
+ free(v->window[1][j][k]);
+ }
+ }
+
+ if(v->pcm){
+ for(i=0;i<vi->channels;i++)
+ if(v->pcm[i])free(v->pcm[i]);
+ free(v->pcm);
+ if(v->pcmret)free(v->pcmret);
+ }
+ if(v->multipliers)free(v->multipliers);
+
+ _ve_envelope_clear(&v->ve);
+ if(v->transform[0]){
+ mdct_clear(v->transform[0][0]);
+ free(v->transform[0][0]);
+ free(v->transform[0]);
+ }
+ if(v->transform[1]){
+ mdct_clear(v->transform[1][0]);
+ free(v->transform[1][0]);
+ free(v->transform[1]);
+ }
+
+ // free mode lookups; these are actually vorbis_look_mapping structs
+ if(vi){
+ for(i=0;i<vi->modes;i++){
+ int mapnum=vi->mode_param[i]->mapping;
+ int maptype=vi->map_type[mapnum];
+ _mapping_P[maptype]->free_look(v->mode[i]);
+ }
+ // free codebooks
+ for(i=0;i<vi->books;i++)
+ vorbis_book_clear(v->fullbooks+i);
+ }
+
+ if(v->mode)free(v->mode);
+ if(v->fullbooks)free(v->fullbooks);
+
+ // free header, header1, header2
+ if(v->header)free(v->header);
+ if(v->header1)free(v->header1);
+ if(v->header2)free(v->header2);
+
+ memset(v,0,sizeof(vorbis_dsp_state));
+ }
+*/
+}
+}
diff --git a/songdbj/com/jcraft/jorbis/EncodeAuxNearestMatch.java b/songdbj/com/jcraft/jorbis/EncodeAuxNearestMatch.java
new file mode 100644
index 0000000000..c4b3b06c6e
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/EncodeAuxNearestMatch.java
@@ -0,0 +1,36 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+class EncodeAuxNearestMatch{
+ int[] ptr0;
+ int[] ptr1;
+
+ int[] p; // decision points (each is an entry)
+ int[] q; // decision points (each is an entry)
+ int aux; // number of tree entries
+ int alloc;
+}
diff --git a/songdbj/com/jcraft/jorbis/EncodeAuxThreshMatch.java b/songdbj/com/jcraft/jorbis/EncodeAuxThreshMatch.java
new file mode 100644
index 0000000000..33cb58733c
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/EncodeAuxThreshMatch.java
@@ -0,0 +1,33 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+class EncodeAuxThreshMatch{
+ float[] quantthresh;
+ int[] quantmap;
+ int quantvals;
+ int threshvals;
+}
diff --git a/songdbj/com/jcraft/jorbis/Floor0.java b/songdbj/com/jcraft/jorbis/Floor0.java
new file mode 100644
index 0000000000..3f1d1c32d5
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Floor0.java
@@ -0,0 +1,352 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Floor0 extends FuncFloor{
+
+ void pack(Object i, Buffer opb){
+ InfoFloor0 info=(InfoFloor0)i;
+ opb.write(info.order,8);
+ opb.write(info.rate,16);
+ opb.write(info.barkmap,16);
+ opb.write(info.ampbits,6);
+ opb.write(info.ampdB,8);
+ opb.write(info.numbooks-1,4);
+ for(int j=0;j<info.numbooks;j++)
+ opb.write(info.books[j],8);
+ }
+
+ Object unpack(Info vi , Buffer opb){
+ InfoFloor0 info=new InfoFloor0();
+ info.order=opb.read(8);
+ info.rate=opb.read(16);
+ info.barkmap=opb.read(16);
+ info.ampbits=opb.read(6);
+ info.ampdB=opb.read(8);
+ info.numbooks=opb.read(4)+1;
+
+ if((info.order<1)||
+ (info.rate<1)||
+ (info.barkmap<1)||
+ (info.numbooks<1)){
+ //free_info(info);
+ return(null);
+ }
+
+ for(int j=0;j<info.numbooks;j++){
+ info.books[j]=opb.read(8);
+ if(info.books[j]<0 || info.books[j]>=vi.books){
+ //free_info(info);
+ return(null);
+ }
+ }
+ return(info);
+// err_out:
+// free_info(info);
+// return(NULL);
+ }
+ Object look(DspState vd, InfoMode mi, Object i){
+ float scale;
+ Info vi=vd.vi;
+ InfoFloor0 info=(InfoFloor0)i;
+ LookFloor0 look=new LookFloor0();
+ look.m=info.order;
+ look.n=vi.blocksizes[mi.blockflag]/2;
+ look.ln=info.barkmap;
+ look.vi=info;
+ look.lpclook.init(look.ln,look.m);
+
+ // we choose a scaling constant so that:
+ // floor(bark(rate/2-1)*C)=mapped-1
+ // floor(bark(rate/2)*C)=mapped
+ scale=look.ln/toBARK((float)(info.rate/2.));
+
+ // the mapping from a linear scale to a smaller bark scale is
+ // straightforward. We do *not* make sure that the linear mapping
+ // does not skip bark-scale bins; the decoder simply skips them and
+ // the encoder may do what it wishes in filling them. They're
+ // necessary in some mapping combinations to keep the scale spacing
+ // accurate
+ look.linearmap=new int[look.n];
+ for(int j=0;j<look.n;j++){
+ int val=(int)Math.floor(toBARK((float)((info.rate/2.)/look.n*j))
+ *scale); // bark numbers represent band edges
+ if(val>=look.ln)val=look.ln; // guard against the approximation
+ look.linearmap[j]=val;
+ }
+ return look;
+ }
+
+ static float toBARK(float f){
+ return (float)(13.1*Math.atan(.00074*(f))+2.24*Math.atan((f)*(f)*1.85e-8)+1e-4*(f));
+ }
+
+ Object state(Object i){
+ EchstateFloor0 state=new EchstateFloor0();
+ InfoFloor0 info=(InfoFloor0)i;
+
+ // a safe size if usually too big (dim==1)
+ state.codewords=new int[info.order];
+ state.curve=new float[info.barkmap];
+ state.frameno=-1;
+ return(state);
+ }
+ void free_info(Object i){}
+ void free_look(Object i){}
+ void free_state(Object vs){}
+ int forward(Block vb, Object i, float[] in, float[] out, Object vs){return 0;}
+
+ float[] lsp=null;
+ int inverse(Block vb, Object i, float[] out){
+ //System.err.println("Floor0.inverse "+i.getClass()+"]");
+ LookFloor0 look=(LookFloor0)i;
+ InfoFloor0 info=look.vi;
+ int ampraw=vb.opb.read(info.ampbits);
+ if(ampraw>0){ // also handles the -1 out of data case
+ int maxval=(1<<info.ampbits)-1;
+ float amp=(float)ampraw/maxval*info.ampdB;
+ int booknum=vb.opb.read(ilog(info.numbooks));
+
+ if(booknum!=-1 && booknum<info.numbooks){
+
+ synchronized(this){
+ if(lsp==null||lsp.length<look.m){
+ lsp=new float[look.m];
+ }
+ else{
+ for(int j=0; j<look.m; j++)lsp[j]=0.f;
+ }
+
+ CodeBook b=vb.vd.fullbooks[info.books[booknum]];
+ float last=0.f;
+
+ //memset(out,0,sizeof(float)*look->m);
+ for(int j=0; j<look.m; j++)out[j]=0.0f;
+
+ for(int j=0;j<look.m;j+=b.dim){
+ if(b.decodevs(lsp, j, vb.opb, 1, -1)==-1){
+ //goto eop;
+ // memset(out,0,sizeof(float)*look->n);
+ for(int k=0; k<look.n; k++)out[k]=0.0f;
+ return(0);
+ }
+ }
+ for(int j=0;j<look.m;){
+ for(int k=0;k<b.dim;k++,j++)lsp[j]+=last;
+ last=lsp[j-1];
+ }
+ // take the coefficients back to a spectral envelope curve
+ /*
+ lsp_to_lpc(out,out,look.m);
+ lpc_to_curve(out,out,amp,look,"",0);
+ for(int j=0;j<look.n;j++){
+ out[j]=fromdB(out[j]-info.ampdB);
+ }
+ */
+ Lsp.lsp_to_curve(out,look.linearmap,look.n,look.ln,
+ lsp,look.m,amp,info.ampdB);
+
+ return(1);
+ }
+ }
+ }
+// eop:
+// memset(out,0,sizeof(float)*look->n);
+ return(0);
+ }
+
+ Object inverse1(Block vb, Object i, Object memo){
+ //System.err.println("Floor0.inverse "+i.getClass()+"]");
+ LookFloor0 look=(LookFloor0)i;
+ InfoFloor0 info=look.vi;
+ float[] lsp=null;
+ if(memo instanceof float[]){
+ lsp=(float[])memo;
+ }
+
+ int ampraw=vb.opb.read(info.ampbits);
+ if(ampraw>0){ // also handles the -1 out of data case
+ int maxval=(1<<info.ampbits)-1;
+ float amp=(float)ampraw/maxval*info.ampdB;
+ int booknum=vb.opb.read(ilog(info.numbooks));
+
+ if(booknum!=-1 && booknum<info.numbooks){
+ CodeBook b=vb.vd.fullbooks[info.books[booknum]];
+ float last=0.f;
+
+ if(lsp==null||lsp.length<look.m+1){
+ lsp=new float[look.m+1];
+ }
+ else{
+ for(int j=0; j<lsp.length; j++)lsp[j]=0.f;
+ }
+
+ for(int j=0;j<look.m;j+=b.dim){
+ if(b.decodev_set(lsp, j, vb.opb, b.dim)==-1){
+ //goto eop;
+ return(null);
+ }
+ }
+
+ for(int j=0;j<look.m;){
+ for(int k=0;k<b.dim;k++,j++)lsp[j]+=last;
+ last=lsp[j-1];
+ }
+ lsp[look.m]=amp;
+ return(lsp);
+ }
+ }
+// eop:
+ return(null);
+ }
+
+ int inverse2(Block vb, Object i, Object memo, float[] out){
+ //System.err.println("Floor0.inverse "+i.getClass()+"]");
+ LookFloor0 look=(LookFloor0)i;
+ InfoFloor0 info=look.vi;
+
+ if(memo!=null){
+ float[] lsp=(float[])memo;
+ float amp=lsp[look.m];
+
+ Lsp.lsp_to_curve(out,look.linearmap,look.n,look.ln,
+ lsp,look.m,amp,info.ampdB);
+ return(1);
+ }
+// eop:
+// memset(out,0,sizeof(float)*look->n);
+ for(int j=0; j<look.n; j++){
+ out[j]=0.f;
+ }
+ return(0);
+ }
+
+ static float fromdB(float x){
+ return (float)(Math.exp((x)*.11512925));
+ }
+ private static int ilog(int v){
+ int ret=0;
+ while(v!=0){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+
+ static void lsp_to_lpc(float[] lsp, float[] lpc, int m){
+ int i,j,m2=m/2;
+ float[] O=new float[m2];
+ float[] E=new float[m2];
+ float A;
+ float[] Ae=new float[m2+1];
+ float[] Ao=new float[m2+1];
+ float B;
+ float[] Be=new float[m2];
+ float[] Bo=new float[m2];
+ float temp;
+
+ // even/odd roots setup
+ for(i=0;i<m2;i++){
+ O[i]=(float)(-2.*Math.cos(lsp[i*2]));
+ E[i]=(float)(-2.*Math.cos(lsp[i*2+1]));
+ }
+
+ // set up impulse response
+ for(j=0;j<m2;j++){
+ Ae[j]=0.f;
+ Ao[j]=1.f;
+ Be[j]=0.f;
+ Bo[j]=1.f;
+ }
+ Ao[j]=1.f;
+ Ae[j]=1.f;
+
+ // run impulse response
+ for(i=1;i<m+1;i++){
+ A=B=0.f;
+ for(j=0;j<m2;j++){
+ temp=O[j]*Ao[j]+Ae[j];
+ Ae[j]=Ao[j];
+ Ao[j]=A;
+ A+=temp;
+
+ temp=E[j]*Bo[j]+Be[j];
+ Be[j]=Bo[j];
+ Bo[j]=B;
+ B+=temp;
+ }
+ lpc[i-1]=(A+Ao[j]+B-Ae[j])/2;
+ Ao[j]=A;
+ Ae[j]=B;
+ }
+ }
+
+ static void lpc_to_curve(float[] curve, float[] lpc,float amp,
+ LookFloor0 l, String name, int frameno){
+ // l->m+1 must be less than l->ln, but guard in case we get a bad stream
+ float[] lcurve=new float[Math.max(l.ln*2,l.m*2+2)];
+
+ if(amp==0){
+ //memset(curve,0,sizeof(float)*l->n);
+ for(int j=0; j<l.n; j++)curve[j]=0.0f;
+ return;
+ }
+ l.lpclook.lpc_to_curve(lcurve,lpc,amp);
+
+ for(int i=0;i<l.n;i++)curve[i]=lcurve[l.linearmap[i]];
+ }
+}
+
+class InfoFloor0{
+ int order;
+ int rate;
+ int barkmap;
+
+ int ampbits;
+ int ampdB;
+
+ int numbooks; // <= 16
+ int[] books=new int[16];
+}
+
+class LookFloor0{
+ int n;
+ int ln;
+ int m;
+ int[] linearmap;
+
+ InfoFloor0 vi;
+ Lpc lpclook=new Lpc();
+}
+
+class EchstateFloor0{
+ int[] codewords;
+ float[] curve;
+ long frameno;
+ long codes;
+}
diff --git a/songdbj/com/jcraft/jorbis/Floor1.java b/songdbj/com/jcraft/jorbis/Floor1.java
new file mode 100644
index 0000000000..1e52c3e537
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Floor1.java
@@ -0,0 +1,653 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Floor1 extends FuncFloor{
+ static final int floor1_rangedb=140;
+ static final int VIF_POSIT=63;
+
+ void pack(Object i, Buffer opb){
+ InfoFloor1 info=(InfoFloor1)i;
+
+ int count=0;
+ int rangebits;
+ int maxposit=info.postlist[1];
+ int maxclass=-1;
+
+ /* save out partitions */
+ opb.write(info.partitions,5); /* only 0 to 31 legal */
+ for(int j=0;j<info.partitions;j++){
+ opb.write(info.partitionclass[j],4); /* only 0 to 15 legal */
+ if(maxclass<info.partitionclass[j])
+ maxclass=info.partitionclass[j];
+ }
+
+ /* save out partition classes */
+ for(int j=0;j<maxclass+1;j++){
+ opb.write(info.class_dim[j]-1,3); /* 1 to 8 */
+ opb.write(info.class_subs[j],2); /* 0 to 3 */
+ if(info.class_subs[j]!=0){
+ opb.write(info.class_book[j],8);
+ }
+ for(int k=0;k<(1<<info.class_subs[j]);k++){
+ opb.write(info.class_subbook[j][k]+1,8);
+ }
+ }
+
+ /* save out the post list */
+ opb.write(info.mult-1,2); /* only 1,2,3,4 legal now */
+ opb.write(ilog2(maxposit),4);
+ rangebits=ilog2(maxposit);
+
+ for(int j=0,k=0;j<info.partitions;j++){
+ count+=info.class_dim[info.partitionclass[j]];
+ for(;k<count;k++){
+ opb.write(info.postlist[k+2],rangebits);
+ }
+ }
+ }
+
+ Object unpack(Info vi , Buffer opb){
+ int count=0,maxclass=-1,rangebits;
+ InfoFloor1 info=new InfoFloor1();
+
+ /* read partitions */
+ info.partitions=opb.read(5); /* only 0 to 31 legal */
+ for(int j=0;j<info.partitions;j++){
+ info.partitionclass[j]=opb.read(4); /* only 0 to 15 legal */
+ if(maxclass<info.partitionclass[j])
+ maxclass=info.partitionclass[j];
+ }
+
+ /* read partition classes */
+ for(int j=0;j<maxclass+1;j++){
+ info.class_dim[j]=opb.read(3)+1; /* 1 to 8 */
+ info.class_subs[j]=opb.read(2); /* 0,1,2,3 bits */
+ if(info.class_subs[j]<0){
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ if(info.class_subs[j]!=0){
+ info.class_book[j]=opb.read(8);
+ }
+ if(info.class_book[j]<0 || info.class_book[j]>=vi.books){
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ for(int k=0;k<(1<<info.class_subs[j]);k++){
+ info.class_subbook[j][k]=opb.read(8)-1;
+ if(info.class_subbook[j][k]<-1 || info.class_subbook[j][k]>=vi.books){
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ }
+ }
+
+ /* read the post list */
+ info.mult=opb.read(2)+1; /* only 1,2,3,4 legal now */
+ rangebits=opb.read(4);
+
+ for(int j=0,k=0;j<info.partitions;j++){
+ count+=info.class_dim[info.partitionclass[j]];
+ for(;k<count;k++){
+ int t=info.postlist[k+2]=opb.read(rangebits);
+ if(t<0 || t>=(1<<rangebits)){
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ }
+ }
+ info.postlist[0]=0;
+ info.postlist[1]=1<<rangebits;
+
+ return(info);
+// err_out:
+// info.free();
+// return(null);
+ }
+
+ Object look(DspState vd, InfoMode mi, Object i){
+ int _n=0;
+
+ int[] sortpointer=new int[VIF_POSIT+2];
+
+// Info vi=vd.vi;
+
+ InfoFloor1 info=(InfoFloor1)i;
+ LookFloor1 look=new LookFloor1();
+ look.vi=info;
+ look.n=info.postlist[1];
+
+ /* we drop each position value in-between already decoded values,
+ and use linear interpolation to predict each new value past the
+ edges. The positions are read in the order of the position
+ list... we precompute the bounding positions in the lookup. Of
+ course, the neighbors can change (if a position is declined), but
+ this is an initial mapping */
+
+ for(int j=0;j<info.partitions;j++){
+ _n+=info.class_dim[info.partitionclass[j]];
+ }
+ _n+=2;
+ look.posts=_n;
+
+ /* also store a sorted position index */
+ for(int j=0;j<_n;j++){
+ sortpointer[j]=j;
+ }
+// qsort(sortpointer,n,sizeof(int),icomp); // !!
+
+ int foo;
+ for(int j=0; j<_n-1; j++){
+ for(int k=j; k<_n; k++){
+ if(info.postlist[sortpointer[j]]>info.postlist[sortpointer[k]]){
+ foo=sortpointer[k];
+ sortpointer[k]=sortpointer[j];
+ sortpointer[j]=foo;
+ }
+ }
+ }
+
+ /* points from sort order back to range number */
+ for(int j=0;j<_n;j++){
+ look.forward_index[j]=sortpointer[j];
+ }
+ /* points from range order to sorted position */
+ for(int j=0;j<_n;j++){
+ look.reverse_index[look.forward_index[j]]=j;
+ }
+ /* we actually need the post values too */
+ for(int j=0;j<_n;j++){
+ look.sorted_index[j]=info.postlist[look.forward_index[j]];
+ }
+
+
+ /* quantize values to multiplier spec */
+ switch(info.mult){
+ case 1: /* 1024 -> 256 */
+ look.quant_q=256;
+ break;
+ case 2: /* 1024 -> 128 */
+ look.quant_q=128;
+ break;
+ case 3: /* 1024 -> 86 */
+ look.quant_q=86;
+ break;
+ case 4: /* 1024 -> 64 */
+ look.quant_q=64;
+ break;
+ default:
+ look.quant_q=-1;
+ }
+
+ /* discover our neighbors for decode where we don't use fit flags
+ (that would push the neighbors outward) */
+ for(int j=0;j<_n-2;j++){
+ int lo=0;
+ int hi=1;
+ int lx=0;
+ int hx=look.n;
+ int currentx=info.postlist[j+2];
+ for(int k=0;k<j+2;k++){
+ int x=info.postlist[k];
+ if(x>lx && x<currentx){
+ lo=k;
+ lx=x;
+ }
+ if(x<hx && x>currentx){
+ hi=k;
+ hx=x;
+ }
+ }
+ look.loneighbor[j]=lo;
+ look.hineighbor[j]=hi;
+ }
+
+ return look;
+ }
+
+ void free_info(Object i){}
+ void free_look(Object i){}
+ void free_state(Object vs){}
+
+ int forward(Block vb, Object i, float[] in, float[] out, Object vs){return 0;}
+
+ Object inverse1(Block vb, Object ii, Object memo){
+ //System.err.println("Floor1.inverse "+i.getClass()+"]");
+ LookFloor1 look=(LookFloor1)ii;
+ InfoFloor1 info=look.vi;
+ CodeBook[] books=vb.vd.fullbooks;
+
+ /* unpack wrapped/predicted values from stream */
+ if(vb.opb.read(1)==1){
+ int[] fit_value=null;
+ if(memo instanceof int[]){
+ fit_value=(int[])memo;
+ }
+ if(fit_value==null || fit_value.length<look.posts){
+ fit_value=new int[look.posts];
+ }
+ else{
+ for(int i=0; i<fit_value.length; i++) fit_value[i]=0;
+ }
+
+ fit_value[0]=vb.opb.read(ilog(look.quant_q-1));
+ fit_value[1]=vb.opb.read(ilog(look.quant_q-1));
+
+ /* partition by partition */
+ for(int i=0,j=2;i<info.partitions;i++){
+ int clss=info.partitionclass[i];
+ int cdim=info.class_dim[clss];
+ int csubbits=info.class_subs[clss];
+ int csub=1<<csubbits;
+ int cval=0;
+
+ /* decode the partition's first stage cascade value */
+ if(csubbits!=0){
+ cval=books[info.class_book[clss]].decode(vb.opb);
+
+ if(cval==-1){
+ //goto eop;
+ return(null);
+ }
+ }
+
+ for(int k=0;k<cdim;k++){
+ int book=info.class_subbook[clss][cval&(csub-1)];
+ cval>>>=csubbits;
+ if(book>=0){
+ if((fit_value[j+k]=books[book].decode(vb.opb))==-1){
+ //goto eop;
+ return(null);
+ }
+ }
+ else{
+ fit_value[j+k]=0;
+ }
+ }
+ j+=cdim;
+ }
+
+ /* unwrap positive values and reconsitute via linear interpolation */
+ for(int i=2;i<look.posts;i++){
+ int predicted=render_point(info.postlist[look.loneighbor[i-2]],
+ info.postlist[look.hineighbor[i-2]],
+ fit_value[look.loneighbor[i-2]],
+ fit_value[look.hineighbor[i-2]],
+ info.postlist[i]);
+ int hiroom=look.quant_q-predicted;
+ int loroom=predicted;
+ int room=(hiroom<loroom?hiroom:loroom)<<1;
+ int val=fit_value[i];
+
+ if(val!=0){
+ if(val>=room){
+ if(hiroom>loroom){
+ val = val-loroom;
+ }
+ else{
+ val = -1-(val-hiroom);
+ }
+ }
+ else{
+ if((val&1)!=0){
+ val= -((val+1)>>>1);
+ }
+ else{
+ val>>=1;
+ }
+ }
+
+ fit_value[i]=val+predicted;
+ fit_value[look.loneighbor[i-2]]&=0x7fff;
+ fit_value[look.hineighbor[i-2]]&=0x7fff;
+ }
+ else{
+ fit_value[i]=predicted|0x8000;
+ }
+ }
+ return(fit_value);
+ }
+
+// eop:
+// return(NULL);
+ return(null);
+ }
+
+ private static int render_point(int x0,int x1,int y0,int y1,int x){
+ y0&=0x7fff; /* mask off flag */
+ y1&=0x7fff;
+
+ {
+ int dy=y1-y0;
+ int adx=x1-x0;
+ int ady=Math.abs(dy);
+ int err=ady*(x-x0);
+
+ int off=(int)(err/adx);
+ if(dy<0)return(y0-off);
+ return(y0+off);
+ }
+ }
+
+ int inverse2(Block vb, Object i, Object memo, float[] out){
+ LookFloor1 look=(LookFloor1)i;
+ InfoFloor1 info=look.vi;
+ int n=vb.vd.vi.blocksizes[vb.mode]/2;
+
+ if(memo!=null){
+ /* render the lines */
+ int[] fit_value=(int[] )memo;
+ int hx=0;
+ int lx=0;
+ int ly=fit_value[0]*info.mult;
+ for(int j=1;j<look.posts;j++){
+ int current=look.forward_index[j];
+ int hy=fit_value[current]&0x7fff;
+ if(hy==fit_value[current]){
+ hy*=info.mult;
+ hx=info.postlist[current];
+
+ render_line(lx,hx,ly,hy,out);
+
+ lx=hx;
+ ly=hy;
+ }
+ }
+ for(int j=hx;j<n;j++){
+ out[j]*=out[j-1]; /* be certain */
+ }
+ return(1);
+ }
+ for(int j=0; j<n; j++){
+ out[j]=0.f;
+ }
+ return(0);
+ }
+
+
+ private static float[] FLOOR_fromdB_LOOKUP={
+ 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F,
+ 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F,
+ 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F,
+ 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F,
+ 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F,
+ 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F,
+ 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F,
+ 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F,
+ 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F,
+ 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F,
+ 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F,
+ 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F,
+ 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F,
+ 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F,
+ 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F,
+ 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F,
+ 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F,
+ 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F,
+ 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F,
+ 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F,
+ 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F,
+ 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F,
+ 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F,
+ 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F,
+ 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F,
+ 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F,
+ 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F,
+ 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F,
+ 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F,
+ 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F,
+ 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F,
+ 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F,
+ 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F,
+ 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F,
+ 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F,
+ 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F,
+ 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F,
+ 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F,
+ 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F,
+ 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F,
+ 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F,
+ 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F,
+ 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F,
+ 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F,
+ 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F,
+ 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F,
+ 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F,
+ 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F,
+ 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F,
+ 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F,
+ 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F,
+ 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F,
+ 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F,
+ 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F,
+ 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F,
+ 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F,
+ 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F,
+ 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F,
+ 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F,
+ 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F,
+ 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F,
+ 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F,
+ 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F,
+ 0.82788260F, 0.88168307F, 0.9389798F, 1.F
+ };
+
+ private static void render_line(int x0, int x1,int y0,int y1,float[] d){
+ int dy=y1-y0;
+ int adx=x1-x0;
+ int ady=Math.abs(dy);
+ int base=dy/adx;
+ int sy=(dy<0?base-1:base+1);
+ int x=x0;
+ int y=y0;
+ int err=0;
+
+ ady-=Math.abs(base*adx);
+
+ d[x]*=FLOOR_fromdB_LOOKUP[y];
+ while(++x<x1){
+ err=err+ady;
+ if(err>=adx){
+ err-=adx;
+ y+=sy;
+ }
+ else{
+ y+=base;
+ }
+ d[x]*=FLOOR_fromdB_LOOKUP[y];
+ }
+ }
+
+ static int ilog(int v){
+ int ret=0;
+ while(v!=0){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+
+ private static int ilog2(int v){
+ int ret=0;
+ while(v>1){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+}
+
+class InfoFloor1{
+ static final int VIF_POSIT=63;
+ static final int VIF_CLASS=16;
+ static final int VIF_PARTS=31;
+
+ int partitions; /* 0 to 31 */
+ int[] partitionclass=new int[VIF_PARTS]; /* 0 to 15 */
+
+ int[] class_dim=new int[VIF_CLASS]; /* 1 to 8 */
+ int[] class_subs=new int[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */
+ int[] class_book=new int[VIF_CLASS]; /* subs ^ dim entries */
+ int[][] class_subbook=new int[VIF_CLASS][]; /* [VIF_CLASS][subs] */
+
+
+ int mult; /* 1 2 3 or 4 */
+ int[] postlist=new int[VIF_POSIT+2]; /* first two implicit */
+
+
+ /* encode side analysis parameters */
+ float maxover;
+ float maxunder;
+ float maxerr;
+
+ int twofitminsize;
+ int twofitminused;
+ int twofitweight;
+ float twofitatten;
+ int unusedminsize;
+ int unusedmin_n;
+
+ int n;
+
+ InfoFloor1(){
+ for(int i=0; i<class_subbook.length; i++){
+ class_subbook[i]=new int[8];
+ }
+ }
+
+ void free(){
+ partitionclass=null;
+ class_dim=null;
+ class_subs=null;
+ class_book=null;
+ class_subbook=null;
+ postlist=null;
+ }
+
+ Object copy_info(){
+ InfoFloor1 info=this;
+ InfoFloor1 ret=new InfoFloor1();
+
+ ret.partitions=info.partitions;
+ System.arraycopy(info.partitionclass, 0, ret.partitionclass, 0, VIF_PARTS);
+ System.arraycopy(info.class_dim, 0, ret.class_dim, 0, VIF_CLASS);
+ System.arraycopy(info.class_subs, 0, ret.class_subs, 0, VIF_CLASS);
+ System.arraycopy(info.class_book, 0, ret.class_book, 0, VIF_CLASS);
+
+ for(int j=0; j<VIF_CLASS; j++){
+ System.arraycopy(info.class_subbook[j], 0,
+ ret.class_subbook[j], 0, 8);
+ }
+
+ ret.mult=info.mult;
+ System.arraycopy(info.postlist, 0, ret.postlist, 0, VIF_POSIT+2);
+
+ ret.maxover=info.maxover;
+ ret.maxunder=info.maxunder;
+ ret.maxerr=info.maxerr;
+
+ ret.twofitminsize=info.twofitminsize;
+ ret.twofitminused=info.twofitminused;
+ ret.twofitweight=info.twofitweight;
+ ret.twofitatten=info.twofitatten;
+ ret.unusedminsize=info.unusedminsize;
+ ret.unusedmin_n=info.unusedmin_n;
+
+ ret.n=info.n;
+
+ return(ret);
+ }
+
+}
+
+class LookFloor1{
+ static final int VIF_POSIT=63;
+
+ int[] sorted_index=new int[VIF_POSIT+2];
+ int[] forward_index=new int[VIF_POSIT+2];
+ int[] reverse_index=new int[VIF_POSIT+2];
+ int[] hineighbor=new int[VIF_POSIT];
+ int[] loneighbor=new int[VIF_POSIT];
+ int posts;
+
+ int n;
+ int quant_q;
+ InfoFloor1 vi;
+
+ int phrasebits;
+ int postbits;
+ int frames;
+
+ void free(){
+
+/*
+ System.out.println("floor 1 bit usage "+
+ (float)(phrasebits/frames)
+ +":"+
+ (float)(postbits/frames)
+ +"("+
+ (float)((postbits+phrasebits)/frames)
+ +" total)"
+
+*/
+
+ sorted_index=null;
+ forward_index=null;
+ reverse_index=null;
+ hineighbor=null;
+ loneighbor=null;
+ }
+}
+
+class Lsfit_acc{
+ long x0;
+ long x1;
+
+ long xa;
+ long ya;
+ long x2a;
+ long y2a;
+ long xya;
+ long n;
+ long an;
+ long un;
+ long edgey0;
+ long edgey1;
+}
+
+class EchstateFloor1{
+ int[] codewords;
+ float[] curve;
+ long frameno;
+ long codes;
+}
diff --git a/songdbj/com/jcraft/jorbis/FuncFloor.java b/songdbj/com/jcraft/jorbis/FuncFloor.java
new file mode 100644
index 0000000000..f438d0f260
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/FuncFloor.java
@@ -0,0 +1,45 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+abstract class FuncFloor{
+// public static FuncFloor[] floor_P={new Floor0()};
+ public static FuncFloor[] floor_P={new Floor0(),new Floor1()};
+
+ abstract void pack(Object i, Buffer opb);
+ abstract Object unpack(Info vi, Buffer opb);
+ abstract Object look(DspState vd, InfoMode mi, Object i);
+// abstract Object state(Object i);
+ abstract void free_info(Object i);
+ abstract void free_look(Object i);
+ abstract void free_state(Object vs);
+ abstract int forward(Block vb, Object i, float[] in, float[] out, Object vs);
+// abstract int inverse(Block vb, Object i, float[] out);
+ abstract Object inverse1(Block vb, Object i, Object memo);
+ abstract int inverse2(Block vb, Object i, Object memo, float[] out);
+}
diff --git a/songdbj/com/jcraft/jorbis/FuncMapping.java b/songdbj/com/jcraft/jorbis/FuncMapping.java
new file mode 100644
index 0000000000..c8ecf75fe7
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/FuncMapping.java
@@ -0,0 +1,40 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+abstract class FuncMapping{
+ public static FuncMapping[] mapping_P={new Mapping0()};
+
+ abstract void pack(Info info , Object imap, Buffer buffer);
+ abstract Object unpack(Info info , Buffer buffer);
+ abstract Object look(DspState vd, InfoMode vm, Object m);
+ abstract void free_info(Object imap);
+ abstract void free_look(Object imap);
+// abstract int forward(Block vd, Object lm);
+ abstract int inverse(Block vd, Object lm);
+}
diff --git a/songdbj/com/jcraft/jorbis/FuncResidue.java b/songdbj/com/jcraft/jorbis/FuncResidue.java
new file mode 100644
index 0000000000..4cbf6a1d53
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/FuncResidue.java
@@ -0,0 +1,43 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+abstract class FuncResidue{
+ public static FuncResidue[] residue_P={new Residue0(),
+ new Residue1(),
+ new Residue2()};
+
+ abstract void pack(Object vr, Buffer opb);
+ abstract Object unpack(Info vi, Buffer opb);
+ abstract Object look(DspState vd, InfoMode vm, Object vr);
+ abstract void free_info(Object i);
+ abstract void free_look(Object i);
+ abstract int forward(Block vb,Object vl, float[][] in, int ch);
+// abstract int inverse(Block vb, Object vl, float[][] in, int ch);
+abstract int inverse(Block vb, Object vl, float[][] in, int[] nonzero,int ch);
+}
diff --git a/songdbj/com/jcraft/jorbis/FuncTime.java b/songdbj/com/jcraft/jorbis/FuncTime.java
new file mode 100644
index 0000000000..b3cd080461
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/FuncTime.java
@@ -0,0 +1,40 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+abstract class FuncTime{
+ public static FuncTime[] time_P={new Time0()};
+
+ abstract void pack(Object i, Buffer opb);
+ abstract Object unpack(Info vi , Buffer opb);
+ abstract Object look(DspState vd, InfoMode vm, Object i);
+ abstract void free_info(Object i);
+ abstract void free_look(Object i);
+ abstract int forward(Block vb, Object i);
+ abstract int inverse(Block vb, Object i, float[] in, float[] out);
+}
diff --git a/songdbj/com/jcraft/jorbis/Info.java b/songdbj/com/jcraft/jorbis/Info.java
new file mode 100644
index 0000000000..dffd4d9de2
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Info.java
@@ -0,0 +1,516 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+public class Info{
+ private static final int OV_EBADPACKET=-136;
+ private static final int OV_ENOTAUDIO=-135;
+
+ private static byte[] _vorbis="vorbis".getBytes();
+ private static final int VI_TIMEB=1;
+// private static final int VI_FLOORB=1;
+ private static final int VI_FLOORB=2;
+// private static final int VI_RESB=1;
+ private static final int VI_RESB=3;
+ private static final int VI_MAPB=1;
+ private static final int VI_WINDOWB=1;
+
+ public int version;
+ public int channels;
+ public int rate;
+
+ // The below bitrate declarations are *hints*.
+ // Combinations of the three values carry the following implications:
+ //
+ // all three set to the same value:
+ // implies a fixed rate bitstream
+ // only nominal set:
+ // implies a VBR stream that averages the nominal bitrate. No hard
+ // upper/lower limit
+ // upper and or lower set:
+ // implies a VBR bitstream that obeys the bitrate limits. nominal
+ // may also be set to give a nominal rate.
+ // none set:
+ // the coder does not care to speculate.
+
+ int bitrate_upper;
+ int bitrate_nominal;
+ int bitrate_lower;
+
+ // Vorbis supports only short and long blocks, but allows the
+ // encoder to choose the sizes
+
+ int[] blocksizes=new int[2];
+
+ // modes are the primary means of supporting on-the-fly different
+ // blocksizes, different channel mappings (LR or mid-side),
+ // different residue backends, etc. Each mode consists of a
+ // blocksize flag and a mapping (along with the mapping setup
+
+ int modes;
+ int maps;
+ int times;
+ int floors;
+ int residues;
+ int books;
+ int psys; // encode only
+
+ InfoMode[] mode_param=null;
+
+ int[] map_type=null;
+ Object[] map_param=null;
+
+ int[] time_type=null;
+ Object[] time_param=null;
+
+ int[] floor_type=null;
+ Object[] floor_param=null;
+
+ int[] residue_type=null;
+ Object[] residue_param=null;
+
+ StaticCodeBook[] book_param=null;
+
+ PsyInfo[] psy_param=new PsyInfo[64]; // encode only
+
+ // for block long/sort tuning; encode only
+ int envelopesa;
+ float preecho_thresh;
+ float preecho_clamp;
+
+ // used by synthesis, which has a full, alloced vi
+ public void init(){
+ rate=0;
+ //memset(vi,0,sizeof(vorbis_info));
+ }
+
+ public void clear(){
+ for(int i=0;i<modes;i++){ mode_param[i]=null; }
+ mode_param=null;
+
+ for(int i=0;i<maps;i++){ // unpack does the range checking
+ FuncMapping.mapping_P[map_type[i]].free_info(map_param[i]);
+ }
+ map_param=null;
+
+ for(int i=0;i<times;i++){ // unpack does the range checking
+ FuncTime.time_P[time_type[i]].free_info(time_param[i]);
+ }
+ time_param=null;
+
+ for(int i=0;i<floors;i++){ // unpack does the range checking
+ FuncFloor.floor_P[floor_type[i]].free_info(floor_param[i]);
+ }
+ floor_param=null;
+
+ for(int i=0;i<residues;i++){ // unpack does the range checking
+ FuncResidue.residue_P[residue_type[i]].free_info(residue_param[i]);
+ }
+ residue_param=null;
+
+ // the static codebooks *are* freed if you call info_clear, because
+ // decode side does alloc a 'static' codebook. Calling clear on the
+ // full codebook does not clear the static codebook (that's our
+ // responsibility)
+ for(int i=0;i<books;i++){
+ // just in case the decoder pre-cleared to save space
+ if(book_param[i]!=null){
+ book_param[i].clear();
+ book_param[i]=null;
+ }
+ }
+ //if(vi->book_param)free(vi->book_param);
+ book_param=null;
+
+ for(int i=0;i<psys;i++){
+ psy_param[i].free();
+ }
+ //if(vi->psy_param)free(vi->psy_param);
+ //memset(vi,0,sizeof(vorbis_info));
+ }
+
+ // Header packing/unpacking
+ int unpack_info(Buffer opb){
+ version=opb.read(32);
+ if(version!=0)return(-1);
+
+ channels=opb.read(8);
+ rate=opb.read(32);
+
+ bitrate_upper=opb.read(32);
+ bitrate_nominal=opb.read(32);
+ bitrate_lower=opb.read(32);
+
+ blocksizes[0]=1<<opb.read(4);
+ blocksizes[1]=1<<opb.read(4);
+
+ if((rate<1) ||
+ (channels<1)||
+ (blocksizes[0]<8)||
+ (blocksizes[1]<blocksizes[0]) ||
+ (opb.read(1)!=1)){
+ //goto err_out; // EOP check
+ clear();
+ return(-1);
+ }
+ return(0);
+ // err_out:
+ // vorbis_info_clear(vi);
+ // return(-1);
+ }
+
+ // all of the real encoding details are here. The modes, books,
+ // everything
+ int unpack_books(Buffer opb){
+
+ //d* codebooks
+ books=opb.read(8)+1;
+
+ if(book_param==null || book_param.length!=books)
+ book_param=new StaticCodeBook[books];
+ for(int i=0;i<books;i++){
+ book_param[i]=new StaticCodeBook();
+ if(book_param[i].unpack(opb)!=0){
+ //goto err_out;
+ clear();
+ return(-1);
+ }
+ }
+
+ // time backend settings
+ times=opb.read(6)+1;
+ if(time_type==null || time_type.length!=times) time_type=new int[times];
+ if(time_param==null || time_param.length!=times)
+ time_param=new Object[times];
+ for(int i=0;i<times;i++){
+ time_type[i]=opb.read(16);
+ if(time_type[i]<0 || time_type[i]>=VI_TIMEB){
+ //goto err_out;
+ clear();
+ return(-1);
+ }
+ time_param[i]=FuncTime.time_P[time_type[i]].unpack(this, opb);
+ if(time_param[i]==null){
+ //goto err_out;
+ clear();
+ return(-1);
+ }
+ }
+
+ // floor backend settings
+ floors=opb.read(6)+1;
+ if(floor_type==null || floor_type.length!=floors)
+ floor_type=new int[floors];
+ if(floor_param==null || floor_param.length!=floors)
+ floor_param=new Object[floors];
+
+ for(int i=0;i<floors;i++){
+ floor_type[i]=opb.read(16);
+ if(floor_type[i]<0 || floor_type[i]>=VI_FLOORB){
+ //goto err_out;
+ clear();
+ return(-1);
+ }
+
+ floor_param[i]=FuncFloor.floor_P[floor_type[i]].unpack(this,opb);
+ if(floor_param[i]==null){
+ //goto err_out;
+ clear();
+ return(-1);
+ }
+ }
+
+ // residue backend settings
+ residues=opb.read(6)+1;
+
+ if(residue_type==null || residue_type.length!=residues)
+ residue_type=new int[residues];
+
+ if(residue_param==null || residue_param.length!=residues)
+ residue_param=new Object[residues];
+
+ for(int i=0;i<residues;i++){
+ residue_type[i]=opb.read(16);
+ if(residue_type[i]<0 || residue_type[i]>=VI_RESB){
+// goto err_out;
+ clear();
+ return(-1);
+ }
+ residue_param[i]=FuncResidue.residue_P[residue_type[i]].unpack(this,opb);
+ if(residue_param[i]==null){
+// goto err_out;
+ clear();
+ return(-1);
+ }
+ }
+
+ // map backend settings
+ maps=opb.read(6)+1;
+ if(map_type==null || map_type.length!=maps) map_type=new int[maps];
+ if(map_param==null || map_param.length!=maps) map_param=new Object[maps];
+ for(int i=0;i<maps;i++){
+ map_type[i]=opb.read(16);
+ if(map_type[i]<0 || map_type[i]>=VI_MAPB){
+// goto err_out;
+ clear();
+ return(-1);
+ }
+ map_param[i]=FuncMapping.mapping_P[map_type[i]].unpack(this,opb);
+ if(map_param[i]==null){
+// goto err_out;
+ clear();
+ return(-1);
+ }
+ }
+
+ // mode settings
+ modes=opb.read(6)+1;
+ if(mode_param==null || mode_param.length!=modes)
+ mode_param=new InfoMode[modes];
+ for(int i=0;i<modes;i++){
+ mode_param[i]=new InfoMode();
+ mode_param[i].blockflag=opb.read(1);
+ mode_param[i].windowtype=opb.read(16);
+ mode_param[i].transformtype=opb.read(16);
+ mode_param[i].mapping=opb.read(8);
+
+ if((mode_param[i].windowtype>=VI_WINDOWB)||
+ (mode_param[i].transformtype>=VI_WINDOWB)||
+ (mode_param[i].mapping>=maps)){
+// goto err_out;
+ clear();
+ return(-1);
+ }
+ }
+
+ if(opb.read(1)!=1){
+ //goto err_out; // top level EOP check
+ clear();
+ return(-1);
+ }
+
+ return(0);
+// err_out:
+// vorbis_info_clear(vi);
+// return(-1);
+ }
+
+ // The Vorbis header is in three packets; the initial small packet in
+ // the first page that identifies basic parameters, a second packet
+ // with bitstream comments and a third packet that holds the
+ // codebook.
+
+ public int synthesis_headerin(Comment vc, Packet op){
+ Buffer opb=new Buffer();
+
+ if(op!=null){
+ opb.readinit(op.packet_base, op.packet, op.bytes);
+
+ // Which of the three types of header is this?
+ // Also verify header-ness, vorbis
+ {
+ byte[] buffer=new byte[6];
+ int packtype=opb.read(8);
+ //memset(buffer,0,6);
+ opb.read(buffer,6);
+ if(buffer[0]!='v' || buffer[1]!='o' || buffer[2]!='r' ||
+ buffer[3]!='b' || buffer[4]!='i' || buffer[5]!='s'){
+ // not a vorbis header
+ return(-1);
+ }
+ switch(packtype){
+ case 0x01: // least significant *bit* is read first
+ if(op.b_o_s==0){
+ // Not the initial packet
+ return(-1);
+ }
+ if(rate!=0){
+ // previously initialized info header
+ return(-1);
+ }
+ return(unpack_info(opb));
+ case 0x03: // least significant *bit* is read first
+ if(rate==0){
+ // um... we didn't get the initial header
+ return(-1);
+ }
+ return(vc.unpack(opb));
+ case 0x05: // least significant *bit* is read first
+ if(rate==0 || vc.vendor==null){
+ // um... we didn;t get the initial header or comments yet
+ return(-1);
+ }
+ return(unpack_books(opb));
+ default:
+ // Not a valid vorbis header type
+ //return(-1);
+ break;
+ }
+ }
+ }
+ return(-1);
+ }
+
+ // pack side
+ int pack_info(Buffer opb){
+ // preamble
+ opb.write(0x01,8);
+ opb.write(_vorbis);
+
+ // basic information about the stream
+ opb.write(0x00,32);
+ opb.write(channels,8);
+ opb.write(rate,32);
+
+ opb.write(bitrate_upper,32);
+ opb.write(bitrate_nominal,32);
+ opb.write(bitrate_lower,32);
+
+ opb.write(ilog2(blocksizes[0]),4);
+ opb.write(ilog2(blocksizes[1]),4);
+ opb.write(1,1);
+ return(0);
+ }
+
+ int pack_books(Buffer opb){
+ opb.write(0x05,8);
+ opb.write(_vorbis);
+
+ // books
+ opb.write(books-1,8);
+ for(int i=0;i<books;i++){
+ if(book_param[i].pack(opb)!=0){
+ //goto err_out;
+ return(-1);
+ }
+ }
+
+ // times
+ opb.write(times-1,6);
+ for(int i=0;i<times;i++){
+ opb.write(time_type[i],16);
+ FuncTime.time_P[time_type[i]].pack(this.time_param[i],opb);
+ }
+
+ // floors
+ opb.write(floors-1,6);
+ for(int i=0;i<floors;i++){
+ opb.write(floor_type[i],16);
+ FuncFloor.floor_P[floor_type[i]].pack(floor_param[i],opb);
+ }
+
+ // residues
+ opb.write(residues-1,6);
+ for(int i=0;i<residues;i++){
+ opb.write(residue_type[i],16);
+ FuncResidue.residue_P[residue_type[i]].pack(residue_param[i],opb);
+ }
+
+ // maps
+ opb.write(maps-1,6);
+ for(int i=0;i<maps;i++){
+ opb.write(map_type[i],16);
+ FuncMapping.mapping_P[map_type[i]].pack(this,map_param[i],opb);
+ }
+
+ // modes
+ opb.write(modes-1,6);
+ for(int i=0;i<modes;i++){
+ opb.write(mode_param[i].blockflag,1);
+ opb.write(mode_param[i].windowtype,16);
+ opb.write(mode_param[i].transformtype,16);
+ opb.write(mode_param[i].mapping,8);
+ }
+ opb.write(1,1);
+ return(0);
+ //err_out:
+ //return(-1);
+ }
+
+// static void v_writestring(Buffer o, byte[] s){
+// int i=0;
+// while(s[i]!=0){
+// o.write(s[i++],8);
+// }
+// }
+
+// static void v_readstring(Buffer o, byte[] buf, int bytes){
+// int i=0
+// while(bytes--!=0){
+// buf[i++]=o.read(8);
+// }
+// }
+
+// private Buffer opb_blocksize=new Buffer();
+ public int blocksize(Packet op){
+ //codec_setup_info *ci=vi->codec_setup;
+ Buffer opb=new Buffer();
+// synchronized(opb_blocksize){
+ int mode;
+
+ opb.readinit(op.packet_base, op.packet, op.bytes);
+
+ /* Check the packet type */
+ if(opb.read(1)!=0){
+ /* Oops. This is not an audio data packet */
+ return(OV_ENOTAUDIO);
+ }
+ {
+ int modebits=0;
+ int v=modes;
+ while(v>1){
+ modebits++;
+ v>>>=1;
+ }
+
+ /* read our mode and pre/post windowsize */
+ mode=opb.read(modebits);
+ }
+ if(mode==-1)return(OV_EBADPACKET);
+ return(blocksizes[mode_param[mode].blockflag]);
+// }
+ }
+
+ private static int ilog2(int v){
+ int ret=0;
+ while(v>1){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+
+ public String toString(){
+ return "version:"+new Integer(version)+
+ ", channels:"+new Integer(channels)+
+ ", rate:"+new Integer(rate)+
+ ", bitrate:"+new Integer(bitrate_upper)+","+
+ new Integer(bitrate_nominal)+","+
+ new Integer(bitrate_lower);
+ }
+}
diff --git a/songdbj/com/jcraft/jorbis/InfoMode.java b/songdbj/com/jcraft/jorbis/InfoMode.java
new file mode 100644
index 0000000000..b570aa5c21
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/InfoMode.java
@@ -0,0 +1,33 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+class InfoMode{
+ int blockflag;
+ int windowtype;
+ int transformtype;
+ int mapping;
+}
diff --git a/songdbj/com/jcraft/jorbis/JOrbisException.java b/songdbj/com/jcraft/jorbis/JOrbisException.java
new file mode 100644
index 0000000000..ce09d4f9fc
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/JOrbisException.java
@@ -0,0 +1,35 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+public class JOrbisException extends Exception {
+ public JOrbisException () {
+ super();
+ }
+ public JOrbisException (String s) {
+ super ("JOrbis: "+s);
+ }
+}
diff --git a/songdbj/com/jcraft/jorbis/Lookup.java b/songdbj/com/jcraft/jorbis/Lookup.java
new file mode 100644
index 0000000000..fb7651a19f
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Lookup.java
@@ -0,0 +1,154 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+class Lookup{
+ static final int COS_LOOKUP_SZ=128;
+ static final float[] COS_LOOKUP={
+ +1.0000000000000f,+0.9996988186962f,+0.9987954562052f,+0.9972904566787f,
+ +0.9951847266722f,+0.9924795345987f,+0.9891765099648f,+0.9852776423889f,
+ +0.9807852804032f,+0.9757021300385f,+0.9700312531945f,+0.9637760657954f,
+ +0.9569403357322f,+0.9495281805930f,+0.9415440651830f,+0.9329927988347f,
+ +0.9238795325113f,+0.9142097557035f,+0.9039892931234f,+0.8932243011955f,
+ +0.8819212643484f,+0.8700869911087f,+0.8577286100003f,+0.8448535652497f,
+ +0.8314696123025f,+0.8175848131516f,+0.8032075314806f,+0.7883464276266f,
+ +0.7730104533627f,+0.7572088465065f,+0.7409511253550f,+0.7242470829515f,
+ +0.7071067811865f,+0.6895405447371f,+0.6715589548470f,+0.6531728429538f,
+ +0.6343932841636f,+0.6152315905806f,+0.5956993044924f,+0.5758081914178f,
+ +0.5555702330196f,+0.5349976198871f,+0.5141027441932f,+0.4928981922298f,
+ +0.4713967368260f,+0.4496113296546f,+0.4275550934303f,+0.4052413140050f,
+ +0.3826834323651f,+0.3598950365350f,+0.3368898533922f,+0.3136817403989f,
+ +0.2902846772545f,+0.2667127574749f,+0.2429801799033f,+0.2191012401569f,
+ +0.1950903220161f,+0.1709618887603f,+0.1467304744554f,+0.1224106751992f,
+ +0.0980171403296f,+0.0735645635997f,+0.0490676743274f,+0.0245412285229f,
+ +0.0000000000000f,-0.0245412285229f,-0.0490676743274f,-0.0735645635997f,
+ -0.0980171403296f,-0.1224106751992f,-0.1467304744554f,-0.1709618887603f,
+ -0.1950903220161f,-0.2191012401569f,-0.2429801799033f,-0.2667127574749f,
+ -0.2902846772545f,-0.3136817403989f,-0.3368898533922f,-0.3598950365350f,
+ -0.3826834323651f,-0.4052413140050f,-0.4275550934303f,-0.4496113296546f,
+ -0.4713967368260f,-0.4928981922298f,-0.5141027441932f,-0.5349976198871f,
+ -0.5555702330196f,-0.5758081914178f,-0.5956993044924f,-0.6152315905806f,
+ -0.6343932841636f,-0.6531728429538f,-0.6715589548470f,-0.6895405447371f,
+ -0.7071067811865f,-0.7242470829515f,-0.7409511253550f,-0.7572088465065f,
+ -0.7730104533627f,-0.7883464276266f,-0.8032075314806f,-0.8175848131516f,
+ -0.8314696123025f,-0.8448535652497f,-0.8577286100003f,-0.8700869911087f,
+ -0.8819212643484f,-0.8932243011955f,-0.9039892931234f,-0.9142097557035f,
+ -0.9238795325113f,-0.9329927988347f,-0.9415440651830f,-0.9495281805930f,
+ -0.9569403357322f,-0.9637760657954f,-0.9700312531945f,-0.9757021300385f,
+ -0.9807852804032f,-0.9852776423889f,-0.9891765099648f,-0.9924795345987f,
+ -0.9951847266722f,-0.9972904566787f,-0.9987954562052f,-0.9996988186962f,
+ -1.0000000000000f,
+ };
+ /* interpolated lookup based cos function, domain 0 to PI only */
+ static float coslook(float a){
+ double d=a*(.31830989*(float)COS_LOOKUP_SZ);
+ int i=(int)d;
+ return COS_LOOKUP[i]+ ((float)(d-i))*(COS_LOOKUP[i+1]-COS_LOOKUP[i]);
+ }
+
+ static final int INVSQ_LOOKUP_SZ=32;
+ static final float[] INVSQ_LOOKUP={
+ 1.414213562373f,1.392621247646f,1.371988681140f,1.352246807566f,
+ 1.333333333333f,1.315191898443f,1.297771369046f,1.281025230441f,
+ 1.264911064067f,1.249390095109f,1.234426799697f,1.219988562661f,
+ 1.206045378311f,1.192569588000f,1.179535649239f,1.166919931983f,
+ 1.154700538379f,1.142857142857f,1.131370849898f,1.120224067222f,
+ 1.109400392450f,1.098884511590f,1.088662107904f,1.078719779941f,
+ 1.069044967650f,1.059625885652f,1.050451462878f,1.041511287847f,
+ 1.032795558989f,1.024295039463f,1.016001016002f,1.007905261358f,
+ 1.000000000000f,
+ };
+ /* interpolated 1./sqrt(p) where .5 <= p < 1. */
+ static float invsqlook(float a){
+// System.out.println(a);
+ double d=a*(2.f*(float)INVSQ_LOOKUP_SZ)-(float)INVSQ_LOOKUP_SZ;
+ int i=(int)d;
+ return INVSQ_LOOKUP[i]+ ((float)(d-i))*(INVSQ_LOOKUP[i+1]-INVSQ_LOOKUP[i]);
+ }
+
+ static final int INVSQ2EXP_LOOKUP_MIN=-32;
+ static final int INVSQ2EXP_LOOKUP_MAX=32;
+ static final float[] INVSQ2EXP_LOOKUP={
+ 65536.f, 46340.95001f, 32768.f, 23170.47501f,
+ 16384.f, 11585.2375f, 8192.f, 5792.618751f,
+ 4096.f, 2896.309376f, 2048.f, 1448.154688f,
+ 1024.f, 724.0773439f, 512.f, 362.038672f,
+ 256.f, 181.019336f, 128.f, 90.50966799f,
+ 64.f, 45.254834f, 32.f, 22.627417f,
+ 16.f, 11.3137085f, 8.f, 5.656854249f,
+ 4.f, 2.828427125f, 2.f, 1.414213562f,
+ 1.f, 0.7071067812f, 0.5f, 0.3535533906f,
+ 0.25f, 0.1767766953f, 0.125f, 0.08838834765f,
+ 0.0625f, 0.04419417382f, 0.03125f, 0.02209708691f,
+ 0.015625f, 0.01104854346f, 0.0078125f, 0.005524271728f,
+ 0.00390625f, 0.002762135864f, 0.001953125f, 0.001381067932f,
+ 0.0009765625f, 0.000690533966f, 0.00048828125f, 0.000345266983f,
+ 0.000244140625f,0.0001726334915f,0.0001220703125f,8.631674575e-05f,
+ 6.103515625e-05f,4.315837288e-05f,3.051757812e-05f,2.157918644e-05f,
+ 1.525878906e-05f,
+ };
+ /* interpolated 1./sqrt(p) where .5 <= p < 1. */
+ static float invsq2explook(int a){
+ return INVSQ2EXP_LOOKUP[a-INVSQ2EXP_LOOKUP_MIN];
+ }
+
+ static final int FROMdB_LOOKUP_SZ=35;
+ static final int FROMdB2_LOOKUP_SZ=32;
+ static final int FROMdB_SHIFT=5;
+ static final int FROMdB2_SHIFT=3;
+ static final int FROMdB2_MASK=31;
+ static final float[] FROMdB_LOOKUP={
+ 1.f, 0.6309573445f, 0.3981071706f, 0.2511886432f,
+ 0.1584893192f, 0.1f, 0.06309573445f, 0.03981071706f,
+ 0.02511886432f, 0.01584893192f, 0.01f, 0.006309573445f,
+ 0.003981071706f, 0.002511886432f, 0.001584893192f, 0.001f,
+ 0.0006309573445f,0.0003981071706f,0.0002511886432f,0.0001584893192f,
+ 0.0001f,6.309573445e-05f,3.981071706e-05f,2.511886432e-05f,
+ 1.584893192e-05f, 1e-05f,6.309573445e-06f,3.981071706e-06f,
+ 2.511886432e-06f,1.584893192e-06f, 1e-06f,6.309573445e-07f,
+ 3.981071706e-07f,2.511886432e-07f,1.584893192e-07f,
+ };
+ static final float[] FROMdB2_LOOKUP={
+ 0.9928302478f, 0.9786445908f, 0.9646616199f, 0.9508784391f,
+ 0.9372921937f, 0.92390007f, 0.9106992942f, 0.8976871324f,
+ 0.8848608897f, 0.8722179097f, 0.8597555737f, 0.8474713009f,
+ 0.835362547f, 0.8234268041f, 0.8116616003f, 0.8000644989f,
+ 0.7886330981f, 0.7773650302f, 0.7662579617f, 0.755309592f,
+ 0.7445176537f, 0.7338799116f, 0.7233941627f, 0.7130582353f,
+ 0.7028699885f, 0.6928273125f, 0.6829281272f, 0.6731703824f,
+ 0.6635520573f, 0.6540711597f, 0.6447257262f, 0.6355138211f,
+ };
+ /* interpolated lookup based fromdB function, domain -140dB to 0dB only */
+ static float fromdBlook(float a){
+ int i=(int)(a*((float)(-(1<<FROMdB2_SHIFT))));
+ return (i<0)?1.f:
+ ((i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT))?0.f:
+ FROMdB_LOOKUP[i>>>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]);
+ }
+
+}
+
+
diff --git a/songdbj/com/jcraft/jorbis/Lpc.java b/songdbj/com/jcraft/jorbis/Lpc.java
new file mode 100644
index 0000000000..452ed86d91
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Lpc.java
@@ -0,0 +1,254 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+class Lpc{
+ // en/decode lookups
+ Drft fft=new Drft();;
+
+ int ln;
+ int m;
+
+ // Autocorrelation LPC coeff generation algorithm invented by
+ // N. Levinson in 1947, modified by J. Durbin in 1959.
+
+ // Input : n elements of time doamin data
+ // Output: m lpc coefficients, excitation energy
+
+ static float lpc_from_data(float[] data, float[] lpc,int n,int m){
+ float[] aut=new float[m+1];
+ float error;
+ int i,j;
+
+ // autocorrelation, p+1 lag coefficients
+
+ j=m+1;
+ while(j--!=0){
+ float d=0;
+ for(i=j;i<n;i++)d+=data[i]*data[i-j];
+ aut[j]=d;
+ }
+
+ // Generate lpc coefficients from autocorr values
+
+ error=aut[0];
+ /*
+ if(error==0){
+ for(int k=0; k<m; k++) lpc[k]=0.0f;
+ return 0;
+ }
+ */
+
+ for(i=0;i<m;i++){
+ float r=-aut[i+1];
+
+ if(error==0){
+ for(int k=0; k<m; k++) lpc[k]=0.0f;
+ return 0;
+ }
+
+ // Sum up this iteration's reflection coefficient; note that in
+ // Vorbis we don't save it. If anyone wants to recycle this code
+ // and needs reflection coefficients, save the results of 'r' from
+ // each iteration.
+
+ for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];
+ r/=error;
+
+ // Update LPC coefficients and total error
+
+ lpc[i]=r;
+ for(j=0;j<i/2;j++){
+ float tmp=lpc[j];
+ lpc[j]+=r*lpc[i-1-j];
+ lpc[i-1-j]+=r*tmp;
+ }
+ if(i%2!=0)lpc[j]+=lpc[j]*r;
+
+ error*=1.0-r*r;
+ }
+
+ // we need the error value to know how big an impulse to hit the
+ // filter with later
+
+ return error;
+ }
+
+ // Input : n element envelope spectral curve
+ // Output: m lpc coefficients, excitation energy
+
+ float lpc_from_curve(float[] curve, float[] lpc){
+ int n=ln;
+ float[] work=new float[n+n];
+ float fscale=(float)(.5/n);
+ int i,j;
+
+ // input is a real curve. make it complex-real
+ // This mixes phase, but the LPC generation doesn't care.
+ for(i=0;i<n;i++){
+ work[i*2]=curve[i]*fscale;
+ work[i*2+1]=0;
+ }
+ work[n*2-1]=curve[n-1]*fscale;
+
+ n*=2;
+ fft.backward(work);
+
+ // The autocorrelation will not be circular. Shift, else we lose
+ // most of the power in the edges.
+
+ for(i=0,j=n/2;i<n/2;){
+ float temp=work[i];
+ work[i++]=work[j];
+ work[j++]=temp;
+ }
+
+ return(lpc_from_data(work,lpc,n,m));
+ }
+
+ void init(int mapped, int m){
+ //memset(l,0,sizeof(lpc_lookup));
+
+ ln=mapped;
+ this.m=m;
+
+ // we cheat decoding the LPC spectrum via FFTs
+ fft.init(mapped*2);
+ }
+
+ void clear(){
+ fft.clear();
+ }
+
+ static float FAST_HYPOT(float a, float b){
+ return (float)Math.sqrt((a)*(a) + (b)*(b));
+ }
+
+ // One can do this the long way by generating the transfer function in
+ // the time domain and taking the forward FFT of the result. The
+ // results from direct calculation are cleaner and faster.
+ //
+ // This version does a linear curve generation and then later
+ // interpolates the log curve from the linear curve.
+
+ void lpc_to_curve(float[] curve, float[] lpc, float amp){
+
+ //memset(curve,0,sizeof(float)*l->ln*2);
+ for(int i=0; i<ln*2; i++)curve[i]=0.0f;
+
+ if(amp==0)return;
+
+ for(int i=0;i<m;i++){
+ curve[i*2+1]=lpc[i]/(4*amp);
+ curve[i*2+2]=-lpc[i]/(4*amp);
+ }
+
+ fft.backward(curve); // reappropriated ;-)
+
+ {
+ int l2=ln*2;
+ float unit=(float)(1./amp);
+ curve[0]=(float)(1./(curve[0]*2+unit));
+ for(int i=1;i<ln;i++){
+ float real=(curve[i]+curve[l2-i]);
+ float imag=(curve[i]-curve[l2-i]);
+
+ float a = real + unit;
+ curve[i] = (float)(1.0 / FAST_HYPOT(a, imag));
+ }
+ }
+ }
+
+/*
+ // subtract or add an lpc filter to data. Vorbis doesn't actually use this.
+
+ static void lpc_residue(float[] coeff, float[] prime,int m,
+ float[] data, int n){
+
+ // in: coeff[0...m-1] LPC coefficients
+ // prime[0...m-1] initial values
+ // data[0...n-1] data samples
+ // out: data[0...n-1] residuals from LPC prediction
+
+ float[] work=new float[m+n];
+ float y;
+
+ if(prime==null){
+ for(int i=0;i<m;i++){
+ work[i]=0;
+ }
+ }
+ else{
+ for(int i=0;i<m;i++){
+ work[i]=prime[i];
+ }
+ }
+
+ for(int i=0;i<n;i++){
+ y=0;
+ for(int j=0;j<m;j++){
+ y-=work[i+j]*coeff[m-j-1];
+ }
+ work[i+m]=data[i];
+ data[i]-=y;
+ }
+ }
+
+ static void lpc_predict(float[] coeff, float[] prime,int m,
+ float[] data, int n){
+
+ // in: coeff[0...m-1] LPC coefficients
+ // prime[0...m-1] initial values (allocated size of n+m-1)
+ // data[0...n-1] residuals from LPC prediction
+ // out: data[0...n-1] data samples
+
+ int o,p;
+ float y;
+ float[] work=new float[m+n];
+
+ if(prime==null){
+ for(int i=0;i<m;i++){
+ work[i]=0.f;
+ }
+ }
+ else{
+ for(int i=0;i<m;i++){
+ work[i]=prime[i];
+ }
+ }
+
+ for(int i=0;i<n;i++){
+ y=data[i];
+ o=i;
+ p=m;
+ for(int j=0;j<m;j++){
+ y-=work[o++]*coeff[--p];
+ }
+ data[i]=work[o]=y;
+ }
+ }
+*/
+}
diff --git a/songdbj/com/jcraft/jorbis/Lsp.java b/songdbj/com/jcraft/jorbis/Lsp.java
new file mode 100644
index 0000000000..550c7d62ee
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Lsp.java
@@ -0,0 +1,111 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+/*
+ function: LSP (also called LSF) conversion routines
+
+ The LSP generation code is taken (with minimal modification) from
+ "On the Computation of the LSP Frequencies" by Joseph Rothweiler
+ <rothwlr@altavista.net>, available at:
+
+ http://www2.xtdl.com/~rothwlr/lsfpaper/lsfpage.html
+ ********************************************************************/
+
+class Lsp{
+
+ static final float M_PI=(float)(3.1415926539);
+
+ static void lsp_to_curve(float[] curve,
+ int[] map, int n, int ln,
+ float[] lsp, int m,
+ float amp, float ampoffset){
+ int i;
+ float wdel=M_PI/ln;
+ for(i=0;i<m;i++)lsp[i]=Lookup.coslook(lsp[i]);
+ int m2=(m/2)*2;
+
+ i=0;
+ while(i<n){
+ int k=map[i];
+ float p=.7071067812f;
+ float q=.7071067812f;
+ float w=Lookup.coslook(wdel*k);
+ int ftmp=0;
+ int c=m>>>1;
+
+ for(int j=0;j<m2;j+=2){
+ q*=lsp[j]-w;
+ p*=lsp[j+1]-w;
+ }
+
+ if((m&1)!=0){
+ /* odd order filter; slightly assymetric */
+ /* the last coefficient */
+ q*=lsp[m-1]-w;
+ q*=q;
+ p*=p*(1.f-w*w);
+ }
+ else{
+ /* even order filter; still symmetric */
+ q*=q*(1.f+w);
+ p*=p*(1.f-w);
+ }
+
+ // q=frexp(p+q,&qexp);
+ q=p+q;
+ int hx=Float.floatToIntBits(q);
+ int ix=0x7fffffff&hx;
+ int qexp=0;
+
+ if(ix>=0x7f800000||(ix==0)){
+ // 0,inf,nan
+ }
+ else{
+ if(ix<0x00800000){ // subnormal
+ q*=3.3554432000e+07; // 0x4c000000
+ hx=Float.floatToIntBits(q);
+ ix=0x7fffffff&hx;
+ qexp=-25;
+ }
+ qexp += ((ix>>>23)-126);
+ hx=(hx&0x807fffff)|0x3f000000;
+ q=Float.intBitsToFloat(hx);
+ }
+
+ q=Lookup.fromdBlook(amp*
+ Lookup.invsqlook(q)*
+ Lookup.invsq2explook(qexp+m)-ampoffset);
+
+ do{curve[i++]*=q;}
+// do{curve[i++]=q;}
+ while(i<n&&map[i]==k);
+
+ }
+ }
+}
+
+
diff --git a/songdbj/com/jcraft/jorbis/Mapping0.java b/songdbj/com/jcraft/jorbis/Mapping0.java
new file mode 100644
index 0000000000..a2c3d06b5e
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Mapping0.java
@@ -0,0 +1,566 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Mapping0 extends FuncMapping{
+ static int seq=0;
+ void free_info(Object imap){};
+ void free_look(Object imap){
+/*
+ LookMapping0 l=(LookMapping0)imap;
+ InfoMapping0 info=l.map;
+ if(l!=null){
+ for(int i=0;i<l.map.submaps;i++){
+ l.time_func[i].free_look(l.time_look[i]);
+ l.floor_func[i].free_look(l.floor_look[i]);
+ l.residue_func[i].free_look(l.residue_look[i]);
+ if(l.psy_look!=null)l.psy_look[i].clear();
+ }
+ }
+
+ if(l.floor_state!=null){
+ for(int i=0;i<l.ch;i++)
+ l.floor_func[info.chmuxlist[i]].free_state(l.floor_state[i]);
+ //free(l.floor_state);
+ }
+
+ if(l.decay!=null){
+ for(int i=0;i<l.ch;i++){
+ //if(l.decay[i])free(l->decay[i]);
+ l.decay[i]=null;
+ }
+ //free(l->decay);
+ l.decay=null;
+ }
+ //free(l->time_func);
+ //free(l->floor_func);
+ //free(l->residue_func);
+ //free(l->time_look);
+ //free(l->floor_look);
+ //free(l->residue_look);
+ //f(l->psy_look)free(l->psy_look);
+ l.time_func=null;
+ l.floor_func=null;
+ l.residue_func=null;
+ l.time_look=null;
+ l.floor_look=null;
+ l.residue_look=null;
+ //memset(l,0,sizeof(vorbis_look_mapping0));
+ //free(l);
+*/
+ }
+
+ Object look(DspState vd, InfoMode vm, Object m){
+//System.err.println("Mapping0.look");
+ Info vi=vd.vi;
+ LookMapping0 look=new LookMapping0();
+ InfoMapping0 info=look.map=(InfoMapping0)m;
+ look.mode=vm;
+
+ look.time_look=new Object[info.submaps];
+ look.floor_look=new Object[info.submaps];
+ look.residue_look=new Object[info.submaps];
+
+/*
+ if(vd.analysisp!=0){
+ look.floor_state=new Object[vi.channels];
+ }
+ if(vi.psys!=0){
+ look.psy_look=new PsyLook[info.submaps];
+ for(int i=0; i<info.submaps; i++){ look.psy_look[i]=new PsyLook(); }
+ }
+*/
+
+ look.time_func=new FuncTime[info.submaps];
+ look.floor_func=new FuncFloor[info.submaps];
+ look.residue_func=new FuncResidue[info.submaps];
+
+ for(int i=0;i<info.submaps;i++){
+ int timenum=info.timesubmap[i];
+ int floornum=info.floorsubmap[i];
+ int resnum=info.residuesubmap[i];
+
+ look.time_func[i]=FuncTime.time_P[vi.time_type[timenum]];
+ look.time_look[i]=look.time_func[i].look(vd,vm,vi.time_param[timenum]);
+ look.floor_func[i]=FuncFloor.floor_P[vi.floor_type[floornum]];
+ look.floor_look[i]=look.floor_func[i].
+ look(vd,vm,vi.floor_param[floornum]);
+ look.residue_func[i]=FuncResidue.residue_P[vi.residue_type[resnum]];
+ look.residue_look[i]=look.residue_func[i].
+ look(vd,vm,vi.residue_param[resnum]);
+
+/*
+ if(vi.psys!=0 && vd.analysisp!=0){
+ int psynum=info.psysubmap[i];
+ look.psy_look[i].init(vi.psy_param[psynum],
+ vi.blocksizes[vm.blockflag]/2,vi.rate);
+ }
+*/
+ }
+
+ if(vi.psys!=0 && vd.analysisp!=0){
+ /*
+ if(info->psy[0] != info->psy[1]){
+
+ int psynum=info->psy[0];
+ look->psy_look[0]=_ogg_calloc(1,sizeof(vorbis_look_psy));
+ _vp_psy_init(look->psy_look[0],ci->psy_param[psynum],
+ ci->psy_g_param,
+ ci->blocksizes[vm->blockflag]/2,vi->rate);
+
+ psynum=info->psy[1];
+ look->psy_look[1]=_ogg_calloc(1,sizeof(vorbis_look_psy));
+ _vp_psy_init(look->psy_look[1],ci->psy_param[psynum],
+ ci->psy_g_param,
+ ci->blocksizes[vm->blockflag]/2,vi->rate);
+ }else{
+
+ int psynum=info->psy[0];
+ look->psy_look[0]=_ogg_calloc(1,sizeof(vorbis_look_psy));
+ look->psy_look[1]=look->psy_look[0];
+ _vp_psy_init(look->psy_look[0],ci->psy_param[psynum],
+ ci->psy_g_param,
+ ci->blocksizes[vm->blockflag]/2,vi->rate);
+
+ }
+ */
+ }
+
+ look.ch=vi.channels;
+// if(vd->analysisp)drft_init(&look->fft_look,ci->blocksizes[vm->blockflag]);
+
+ return(look);
+//return null;
+ }
+
+ void pack(Info vi, Object imap, Buffer opb){
+ InfoMapping0 info=(InfoMapping0)imap;
+
+ /* another 'we meant to do it this way' hack... up to beta 4, we
+ packed 4 binary zeros here to signify one submapping in use. We
+ now redefine that to mean four bitflags that indicate use of
+ deeper features; bit0:submappings, bit1:coupling,
+ bit2,3:reserved. This is backward compatable with all actual uses
+ of the beta code. */
+
+ if(info.submaps>1){
+ opb.write(1,1);
+ opb.write(info.submaps-1,4);
+ }
+ else{
+ opb.write(0,1);
+ }
+
+ if(info.coupling_steps>0){
+ opb.write(1,1);
+ opb.write(info.coupling_steps-1,8);
+ for(int i=0;i<info.coupling_steps;i++){
+ opb.write(info.coupling_mag[i],ilog2(vi.channels));
+ opb.write(info.coupling_ang[i],ilog2(vi.channels));
+ }
+ }
+ else{
+ opb.write(0,1);
+ }
+
+ opb.write(0,2); /* 2,3:reserved */
+
+ /* we don't write the channel submappings if we only have one... */
+ if(info.submaps>1){
+ for(int i=0;i<vi.channels;i++)
+ opb.write(info.chmuxlist[i],4);
+ }
+ for(int i=0;i<info.submaps;i++){
+ opb.write(info.timesubmap[i],8);
+ opb.write(info.floorsubmap[i],8);
+ opb.write(info.residuesubmap[i],8);
+ }
+ }
+
+ // also responsible for range checking
+ Object unpack(Info vi, Buffer opb){
+ InfoMapping0 info=new InfoMapping0();
+
+ // !!!!
+ if(opb.read(1)!=0){
+ info.submaps=opb.read(4)+1;
+ }
+ else{
+ info.submaps=1;
+ }
+
+ if(opb.read(1)!=0){
+ info.coupling_steps=opb.read(8)+1;
+
+ for(int i=0;i<info.coupling_steps;i++){
+ int testM=info.coupling_mag[i]=opb.read(ilog2(vi.channels));
+ int testA=info.coupling_ang[i]=opb.read(ilog2(vi.channels));
+
+ if(testM<0 ||
+ testA<0 ||
+ testM==testA ||
+ testM>=vi.channels ||
+ testA>=vi.channels){
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ }
+ }
+
+ if(opb.read(2)>0){ /* 2,3:reserved */
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+
+ if(info.submaps>1){
+ for(int i=0;i<vi.channels;i++){
+ info.chmuxlist[i]=opb.read(4);
+ if(info.chmuxlist[i]>=info.submaps){
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ }
+ }
+
+ for(int i=0;i<info.submaps;i++){
+ info.timesubmap[i]=opb.read(8);
+ if(info.timesubmap[i]>=vi.times){
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ info.floorsubmap[i]=opb.read(8);
+ if(info.floorsubmap[i]>=vi.floors){
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ info.residuesubmap[i]=opb.read(8);
+ if(info.residuesubmap[i]>=vi.residues){
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ }
+ return info;
+ //err_out:
+ //free_info(info);
+ //return(NULL);
+ }
+
+/*
+ // no time mapping implementation for now
+ static int seq=0;
+ int forward(Block vb, Object l){
+ DspState vd=vb.vd;
+ Info vi=vd.vi;
+ LookMapping0 look=(LookMapping0)l;
+ InfoMapping0 info=look.map;
+ InfoMode mode=look.mode;
+ int n=vb.pcmend;
+ float[] window=vd.window[vb.W][vb.lW][vb.nW][mode.windowtype];
+
+ float[][] pcmbundle=new float[vi.channles][];
+ int[] nonzero=new int[vi.channels];
+
+ // time domain pre-window: NONE IMPLEMENTED
+
+ // window the PCM data: takes PCM vector, vb; modifies PCM vector
+
+ for(int i=0;i<vi.channels;i++){
+ float[] pcm=vb.pcm[i];
+ for(int j=0;j<n;j++)
+ pcm[j]*=window[j];
+ }
+
+ // time-domain post-window: NONE IMPLEMENTED
+
+ // transform the PCM data; takes PCM vector, vb; modifies PCM vector
+ // only MDCT right now....
+ for(int i=0;i<vi.channels;i++){
+ float[] pcm=vb.pcm[i];
+ mdct_forward(vd.transform[vb.W][0],pcm,pcm);
+ }
+
+ {
+ float[] floor=_vorbis_block_alloc(vb,n*sizeof(float)/2);
+
+ for(int i=0;i<vi.channels;i++){
+ float[] pcm=vb.pcm[i];
+ float[] decay=look.decay[i];
+ int submap=info.chmuxlist[i];
+
+ // if some other mode/mapping was called last frame, our decay
+ // accumulator is out of date. Clear it.
+ //if(look.lastframe+1 != vb->sequence)
+ // memset(decay,0,n*sizeof(float)/2);
+
+ // perform psychoacoustics; do masking
+ _vp_compute_mask(look.psy_look[submap],pcm,floor,decay);
+
+ _analysis_output("mdct",seq,pcm,n/2,0,1);
+ _analysis_output("lmdct",seq,pcm,n/2,0,0);
+ _analysis_output("prefloor",seq,floor,n/2,0,1);
+
+ // perform floor encoding
+ nonzero[i]=look.floor_func[submap].
+ forward(vb,look.floor_look[submap],floor,floor,look.floor_state[i]);
+
+ _analysis_output("floor",seq,floor,n/2,0,1);
+
+ // apply the floor, do optional noise levelling
+ _vp_apply_floor(look->psy_look+submap,pcm,floor);
+
+ _analysis_output("res",seq++,pcm,n/2,0,0);
+ }
+
+ // perform residue encoding with residue mapping; this is
+ // multiplexed. All the channels belonging to one submap are
+ // encoded (values interleaved), then the next submap, etc
+
+ for(int i=0;i<info.submaps;i++){
+ int ch_in_bundle=0;
+ for(int j=0;j<vi.channels;j++){
+ if(info.chmuxlist[j]==i && nonzero[j]==1){
+ pcmbundle[ch_in_bundle++]=vb.pcm[j];
+ }
+ }
+ look.residue_func[i].forward(vb,look.residue_look[i], pcmbundle,ch_in_bundle);
+ }
+ }
+ look.lastframe=vb.sequence;
+ return(0);
+ }
+*/
+
+ float[][] pcmbundle=null;
+ int[] zerobundle=null;
+ int[] nonzero=null;
+ Object[] floormemo=null;
+
+ synchronized int inverse(Block vb, Object l){
+ //System.err.println("Mapping0.inverse");
+ DspState vd=vb.vd;
+ Info vi=vd.vi;
+ LookMapping0 look=(LookMapping0)l;
+ InfoMapping0 info=look.map;
+ InfoMode mode=look.mode;
+ int n=vb.pcmend=vi.blocksizes[vb.W];
+
+ float[] window=vd.window[vb.W][vb.lW][vb.nW][mode.windowtype];
+ // float[][] pcmbundle=new float[vi.channels][];
+ // int[] nonzero=new int[vi.channels];
+ if(pcmbundle==null || pcmbundle.length<vi.channels){
+ pcmbundle=new float[vi.channels][];
+ nonzero=new int[vi.channels];
+ zerobundle=new int[vi.channels];
+ floormemo=new Object[vi.channels];
+ }
+
+ // time domain information decode (note that applying the
+ // information would have to happen later; we'll probably add a
+ // function entry to the harness for that later
+ // NOT IMPLEMENTED
+
+ // recover the spectral envelope; store it in the PCM vector for now
+ for(int i=0;i<vi.channels;i++){
+ float[] pcm=vb.pcm[i];
+ int submap=info.chmuxlist[i];
+
+ floormemo[i]=look.floor_func[submap].inverse1(vb,look.
+ floor_look[submap],
+ floormemo[i]
+ );
+ if(floormemo[i]!=null){ nonzero[i]=1; }
+ else{ nonzero[i]=0; }
+ for(int j=0; j<n/2; j++){
+ pcm[j]=0;
+ }
+
+ //_analysis_output("ifloor",seq+i,pcm,n/2,0,1);
+ }
+
+ for(int i=0; i<info.coupling_steps; i++){
+ if(nonzero[info.coupling_mag[i]]!=0 ||
+ nonzero[info.coupling_ang[i]]!=0){
+ nonzero[info.coupling_mag[i]]=1;
+ nonzero[info.coupling_ang[i]]=1;
+ }
+ }
+
+ // recover the residue, apply directly to the spectral envelope
+
+ for(int i=0;i<info.submaps;i++){
+ int ch_in_bundle=0;
+ for(int j=0;j<vi.channels;j++){
+ if(info.chmuxlist[j]==i){
+ if(nonzero[j]!=0){
+ zerobundle[ch_in_bundle]=1;
+ }
+ else{
+ zerobundle[ch_in_bundle]=0;
+ }
+ pcmbundle[ch_in_bundle++]=vb.pcm[j];
+ }
+ }
+
+ look.residue_func[i].inverse(vb,look.residue_look[i],
+ pcmbundle,zerobundle,ch_in_bundle);
+ }
+
+
+ for(int i=info.coupling_steps-1;i>=0;i--){
+ float[] pcmM=vb.pcm[info.coupling_mag[i]];
+ float[] pcmA=vb.pcm[info.coupling_ang[i]];
+
+ for(int j=0;j<n/2;j++){
+ float mag=pcmM[j];
+ float ang=pcmA[j];
+
+ if(mag>0){
+ if(ang>0){
+ pcmM[j]=mag;
+ pcmA[j]=mag-ang;
+ }
+ else{
+ pcmA[j]=mag;
+ pcmM[j]=mag+ang;
+ }
+ }
+ else{
+ if(ang>0){
+ pcmM[j]=mag;
+ pcmA[j]=mag+ang;
+ }
+ else{
+ pcmA[j]=mag;
+ pcmM[j]=mag-ang;
+ }
+ }
+ }
+ }
+
+// /* compute and apply spectral envelope */
+
+ for(int i=0;i<vi.channels;i++){
+ float[] pcm=vb.pcm[i];
+ int submap=info.chmuxlist[i];
+ look.floor_func[submap].inverse2(vb,look.floor_look[submap],floormemo[i],pcm);
+ }
+
+ // transform the PCM data; takes PCM vector, vb; modifies PCM vector
+ // only MDCT right now....
+
+ for(int i=0;i<vi.channels;i++){
+ float[] pcm=vb.pcm[i];
+ //_analysis_output("out",seq+i,pcm,n/2,0,0);
+ ((Mdct)vd.transform[vb.W][0]).backward(pcm,pcm);
+ }
+
+ // now apply the decoded pre-window time information
+ // NOT IMPLEMENTED
+
+ // window the data
+ for(int i=0;i<vi.channels;i++){
+ float[] pcm=vb.pcm[i];
+ if(nonzero[i]!=0){
+ for(int j=0;j<n;j++){
+ pcm[j]*=window[j];
+ }
+ }
+ else{
+ for(int j=0;j<n;j++){
+ pcm[j]=0.f;
+ }
+ }
+ //_analysis_output("final",seq++,pcm,n,0,0);
+ }
+
+ // now apply the decoded post-window time information
+ // NOT IMPLEMENTED
+ // all done!
+ return(0);
+ }
+
+
+ private static int ilog2(int v){
+ int ret=0;
+ while(v>1){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+}
+
+class InfoMapping0{
+ int submaps; // <= 16
+ int[] chmuxlist=new int[256]; // up to 256 channels in a Vorbis stream
+
+ int[] timesubmap=new int[16]; // [mux]
+ int[] floorsubmap=new int[16]; // [mux] submap to floors
+ int[] residuesubmap=new int[16];// [mux] submap to residue
+ int[] psysubmap=new int[16]; // [mux]; encode only
+
+ int coupling_steps;
+ int[] coupling_mag=new int[256];
+ int[] coupling_ang=new int[256];
+
+ void free(){
+ chmuxlist=null;
+ timesubmap=null;
+ floorsubmap=null;
+ residuesubmap=null;
+ psysubmap=null;
+
+ coupling_mag=null;
+ coupling_ang=null;
+ }
+}
+
+class LookMapping0{
+ InfoMode mode;
+ InfoMapping0 map;
+ Object[] time_look;
+ Object[] floor_look;
+ Object[] floor_state;
+ Object[] residue_look;
+ PsyLook[] psy_look;
+
+ FuncTime[] time_func;
+ FuncFloor[] floor_func;
+ FuncResidue[] residue_func;
+
+ int ch;
+ float[][] decay;
+ int lastframe; // if a different mode is called, we need to
+ // invalidate decay and floor state
+}
diff --git a/songdbj/com/jcraft/jorbis/Mdct.java b/songdbj/com/jcraft/jorbis/Mdct.java
new file mode 100644
index 0000000000..bd5cc38fb7
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Mdct.java
@@ -0,0 +1,249 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+class Mdct{
+
+ static private final float cPI3_8=0.38268343236508977175f;
+ static private final float cPI2_8=0.70710678118654752441f;
+ static private final float cPI1_8=0.92387953251128675613f;
+
+ int n;
+ int log2n;
+
+ float[] trig;
+ int[] bitrev;
+
+ float scale;
+
+ void init(int n){
+ bitrev=new int[n/4];
+ trig=new float[n+n/4];
+
+ int n2=n>>>1;
+ log2n=(int)Math.rint(Math.log(n)/Math.log(2));
+ this.n=n;
+
+
+ int AE=0;
+ int AO=1;
+ int BE=AE+n/2;
+ int BO=BE+1;
+ int CE=BE+n/2;
+ int CO=CE+1;
+ // trig lookups...
+ for(int i=0;i<n/4;i++){
+ trig[AE+i*2]=(float)Math.cos((Math.PI/n)*(4*i));
+ trig[AO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i));
+ trig[BE+i*2]=(float)Math.cos((Math.PI/(2*n))*(2*i+1));
+ trig[BO+i*2]=(float)Math.sin((Math.PI/(2*n))*(2*i+1));
+ }
+ for(int i=0;i<n/8;i++){
+ trig[CE+i*2]=(float)Math.cos((Math.PI/n)*(4*i+2));
+ trig[CO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i+2));
+ }
+
+ {
+ int mask=(1<<(log2n-1))-1;
+ int msb=1<<(log2n-2);
+ for(int i=0;i<n/8;i++){
+ int acc=0;
+ for(int j=0;msb>>>j!=0;j++)
+ if(((msb>>>j)&i)!=0)acc|=1<<j;
+ bitrev[i*2]=((~acc)&mask);
+// bitrev[i*2]=((~acc)&mask)-1;
+ bitrev[i*2+1]=acc;
+ }
+ }
+ scale=4.f/n;
+ }
+
+ void clear(){
+ }
+
+ void forward(float[] in, float[] out){
+ }
+
+ float[] _x=new float[1024];
+ float[] _w=new float[1024];
+
+ synchronized void backward(float[] in, float[] out){
+ if(_x.length<n/2){_x=new float[n/2];}
+ if(_w.length<n/2){_w=new float[n/2];}
+ float[] x=_x;
+ float[] w=_w;
+ int n2=n>>>1;
+ int n4=n>>>2;
+ int n8=n>>>3;
+
+ // rotate + step 1
+ {
+ int inO=1;
+ int xO=0;
+ int A=n2;
+
+ int i;
+ for(i=0;i<n8;i++){
+ A-=2;
+ x[xO++]=-in[inO+2]*trig[A+1] - in[inO]*trig[A];
+ x[xO++]= in[inO]*trig[A+1] - in[inO+2]*trig[A];
+ inO+=4;
+ }
+
+ inO=n2-4;
+
+ for(i=0;i<n8;i++){
+ A-=2;
+ x[xO++]=in[inO]*trig[A+1] + in[inO+2]*trig[A];
+ x[xO++]=in[inO]*trig[A] - in[inO+2]*trig[A+1];
+ inO-=4;
+ }
+ }
+
+ float[] xxx=mdct_kernel(x,w,n,n2,n4,n8);
+ int xx=0;
+
+ // step 8
+
+ {
+ int B=n2;
+ int o1=n4,o2=o1-1;
+ int o3=n4+n2,o4=o3-1;
+
+ for(int i=0;i<n4;i++){
+ float temp1= (xxx[xx] * trig[B+1] - xxx[xx+1] * trig[B]);
+ float temp2=-(xxx[xx] * trig[B] + xxx[xx+1] * trig[B+1]);
+
+ out[o1]=-temp1;
+ out[o2]= temp1;
+ out[o3]= temp2;
+ out[o4]= temp2;
+
+ o1++;
+ o2--;
+ o3++;
+ o4--;
+ xx+=2;
+ B+=2;
+ }
+ }
+ }
+ private float[] mdct_kernel(float[] x, float[] w,
+ int n, int n2, int n4, int n8){
+ // step 2
+
+ int xA=n4;
+ int xB=0;
+ int w2=n4;
+ int A=n2;
+
+ for(int i=0;i<n4;){
+ float x0=x[xA] - x[xB];
+ float x1;
+ w[w2+i]=x[xA++]+x[xB++];
+
+ x1=x[xA]-x[xB];
+ A-=4;
+
+ w[i++]= x0 * trig[A] + x1 * trig[A+1];
+ w[i]= x1 * trig[A] - x0 * trig[A+1];
+
+ w[w2+i]=x[xA++]+x[xB++];
+ i++;
+ }
+
+ // step 3
+
+ {
+ for(int i=0;i<log2n-3;i++){
+ int k0=n>>>(i+2);
+ int k1=1<<(i+3);
+ int wbase=n2-2;
+
+ A=0;
+ float[] temp;
+
+ for(int r=0;r<(k0>>>2);r++){
+ int w1=wbase;
+ w2=w1-(k0>>1);
+ float AEv= trig[A],wA;
+ float AOv= trig[A+1],wB;
+ wbase-=2;
+
+ k0++;
+ for(int s=0;s<(2<<i);s++){
+ wB =w[w1] -w[w2];
+ x[w1] =w[w1] +w[w2];
+
+ wA =w[++w1] -w[++w2];
+ x[w1] =w[w1] +w[w2];
+
+ x[w2] =wA*AEv - wB*AOv;
+ x[w2-1]=wB*AEv + wA*AOv;
+
+ w1-=k0;
+ w2-=k0;
+ }
+ k0--;
+ A+=k1;
+ }
+
+ temp=w;
+ w=x;
+ x=temp;
+ }
+ }
+
+ // step 4, 5, 6, 7
+ {
+ int C=n;
+ int bit=0;
+ int x1=0;
+ int x2=n2-1;
+
+ for(int i=0;i<n8;i++){
+ int t1=bitrev[bit++];
+ int t2=bitrev[bit++];
+
+ float wA=w[t1]-w[t2+1];
+ float wB=w[t1-1]+w[t2];
+ float wC=w[t1]+w[t2+1];
+ float wD=w[t1-1]-w[t2];
+
+ float wACE=wA* trig[C];
+ float wBCE=wB* trig[C++];
+ float wACO=wA* trig[C];
+ float wBCO=wB* trig[C++];
+
+ x[x1++]=( wC+wACO+wBCE)*.5f;
+ x[x2--]=(-wD+wBCO-wACE)*.5f;
+ x[x1++]=( wD+wBCO-wACE)*.5f;
+ x[x2--]=( wC-wACO-wBCE)*.5f;
+ }
+ }
+ return(x);
+ }
+}
diff --git a/songdbj/com/jcraft/jorbis/PsyInfo.java b/songdbj/com/jcraft/jorbis/PsyInfo.java
new file mode 100644
index 0000000000..599c41e52d
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/PsyInfo.java
@@ -0,0 +1,72 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+// psychoacoustic setup
+class PsyInfo{
+ int athp;
+ int decayp;
+ int smoothp;
+ int noisefitp;
+ int noisefit_subblock;
+ float noisefit_threshdB;
+
+ float ath_att;
+
+ int tonemaskp;
+ float[] toneatt_125Hz=new float[5];
+ float[] toneatt_250Hz=new float[5];
+ float[] toneatt_500Hz=new float[5];
+ float[] toneatt_1000Hz=new float[5];
+ float[] toneatt_2000Hz=new float[5];
+ float[] toneatt_4000Hz=new float[5];
+ float[] toneatt_8000Hz=new float[5];
+
+ int peakattp;
+ float[] peakatt_125Hz=new float[5];
+ float[] peakatt_250Hz=new float[5];
+ float[] peakatt_500Hz=new float[5];
+ float[] peakatt_1000Hz=new float[5];
+ float[] peakatt_2000Hz=new float[5];
+ float[] peakatt_4000Hz=new float[5];
+ float[] peakatt_8000Hz=new float[5];
+
+ int noisemaskp;
+ float[] noiseatt_125Hz=new float[5];
+ float[] noiseatt_250Hz=new float[5];
+ float[] noiseatt_500Hz=new float[5];
+ float[] noiseatt_1000Hz=new float[5];
+ float[] noiseatt_2000Hz=new float[5];
+ float[] noiseatt_4000Hz=new float[5];
+ float[] noiseatt_8000Hz=new float[5];
+
+ float max_curve_dB;
+
+ float attack_coeff;
+ float decay_coeff;
+
+ void free(){}
+}
diff --git a/songdbj/com/jcraft/jorbis/PsyLook.java b/songdbj/com/jcraft/jorbis/PsyLook.java
new file mode 100644
index 0000000000..9da85edfb1
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/PsyLook.java
@@ -0,0 +1,187 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+class PsyLook {
+ int n;
+ PsyInfo vi;
+
+ float[][][] tonecurves;
+ float[][] peakatt;
+ float[][][] noisecurves;
+
+ float[] ath;
+ int[] octave;
+
+ void init(PsyInfo vi, int n, int rate){
+ /*
+ float rate2=rate/2.;
+ //memset(p,0,sizeof(vorbis_look_psy));
+ ath=new float[n];
+ octave=new int[n];
+ this.vi=vi;
+ this.n=n;
+
+ // set up the lookups for a given blocksize and sample rate
+ // Vorbis max sample rate is limited by 26 Bark (54kHz)
+ set_curve(ATH_Bark_dB, ath,n,rate);
+ for(int i=0;i<n;i++)
+ ath[i]=fromdB(ath[i]+vi.ath_att);
+
+ for(int i=0;i<n;i++){
+ int oc=rint(toOC((i+.5)*rate2/n)*2.);
+ if(oc<0)oc=0;
+ if(oc>12)oc=12;
+ octave[i]=oc;
+ }
+
+ tonecurves=malloc(13*sizeof(float **));
+ noisecurves=malloc(13*sizeof(float **));
+ peakatt=malloc(7*sizeof(float *));
+ for(int i=0;i<13;i++){
+ tonecurves[i]=malloc(9*sizeof(float *));
+ noisecurves[i]=malloc(9*sizeof(float *));
+ }
+ for(i=0;i<7;i++)
+ peakatt[i]=malloc(5*sizeof(float));
+
+ for(i=0;i<13;i++){
+ for(j=0;j<9;j++){
+ tonecurves[i][j]=malloc(EHMER_MAX*sizeof(float));
+ noisecurves[i][j]=malloc(EHMER_MAX*sizeof(float));
+ }
+ }
+
+ // OK, yeah, this was a silly way to do it
+ memcpy(tonecurves[0][2],tone_125_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[0][4],tone_125_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[0][6],tone_125_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[0][8],tone_125_100dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(tonecurves[2][2],tone_250_40dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[2][4],tone_250_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[2][6],tone_250_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[2][8],tone_250_80dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(tonecurves[4][2],tone_500_40dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[4][4],tone_500_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[4][6],tone_500_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[4][8],tone_500_100dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(tonecurves[6][2],tone_1000_40dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[6][4],tone_1000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[6][6],tone_1000_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[6][8],tone_1000_100dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(tonecurves[8][2],tone_2000_40dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[8][4],tone_2000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[8][6],tone_2000_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[8][8],tone_2000_100dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(tonecurves[10][2],tone_4000_40dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[10][4],tone_4000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[10][6],tone_4000_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[10][8],tone_4000_100dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(tonecurves[12][2],tone_4000_40dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[12][4],tone_4000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[12][6],tone_8000_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(tonecurves[12][8],tone_8000_100dB_SL,sizeof(float)*EHMER_MAX);
+
+
+ memcpy(noisecurves[0][2],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[0][4],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[0][6],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[0][8],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(noisecurves[2][2],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[2][4],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[2][6],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[2][8],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(noisecurves[4][2],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[4][4],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[4][6],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[4][8],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(noisecurves[6][2],noise_1000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[6][4],noise_1000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[6][6],noise_1000_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[6][8],noise_1000_80dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(noisecurves[8][2],noise_2000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[8][4],noise_2000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[8][6],noise_2000_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[8][8],noise_2000_80dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(noisecurves[10][2],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[10][4],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[10][6],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[10][8],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
+
+ memcpy(noisecurves[12][2],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[12][4],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[12][6],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
+ memcpy(noisecurves[12][8],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
+
+ setup_curve(tonecurves[0],0,vi.toneatt_125Hz);
+ setup_curve(tonecurves[2],2,vi.toneatt_250Hz);
+ setup_curve(tonecurves[4],4,vi.toneatt_500Hz);
+ setup_curve(tonecurves[6],6,vi.toneatt_1000Hz);
+ setup_curve(tonecurves[8],8,vi.toneatt_2000Hz);
+ setup_curve(tonecurves[10],10,vi.toneatt_4000Hz);
+ setup_curve(tonecurves[12],12,vi.toneatt_8000Hz);
+
+ setup_curve(noisecurves[0],0,vi.noiseatt_125Hz);
+ setup_curve(noisecurves[2],2,vi.noiseatt_250Hz);
+ setup_curve(noisecurves[4],4,vi.noiseatt_500Hz);
+ setup_curve(noisecurves[6],6,vi.noiseatt_1000Hz);
+ setup_curve(noisecurves[8],8,vi.noiseatt_2000Hz);
+ setup_curve(noisecurves[10],10,vi.noiseatt_4000Hz);
+ setup_curve(noisecurves[12],12,vi.noiseatt_8000Hz);
+
+ for(i=1;i<13;i+=2){
+ for(j=0;j<9;j++){
+ interp_curve_dB(tonecurves[i][j],
+ tonecurves[i-1][j],
+ tonecurves[i+1][j],.5);
+ interp_curve_dB(noisecurves[i][j],
+ noisecurves[i-1][j],
+ noisecurves[i+1][j],.5);
+ }
+ }
+ for(i=0;i<5;i++){
+ peakatt[0][i]=fromdB(vi.peakatt_125Hz[i]);
+ peakatt[1][i]=fromdB(vi.peakatt_250Hz[i]);
+ peakatt[2][i]=fromdB(vi.peakatt_500Hz[i]);
+ peakatt[3][i]=fromdB(vi.peakatt_1000Hz[i]);
+ peakatt[4][i]=fromdB(vi.peakatt_2000Hz[i]);
+ peakatt[5][i]=fromdB(vi.peakatt_4000Hz[i]);
+ peakatt[6][i]=fromdB(vi.peakatt_8000Hz[i]);
+ }
+ */
+ }
+}
diff --git a/songdbj/com/jcraft/jorbis/Residue0.java b/songdbj/com/jcraft/jorbis/Residue0.java
new file mode 100644
index 0000000000..be42518f1c
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Residue0.java
@@ -0,0 +1,454 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Residue0 extends FuncResidue{
+ void pack(Object vr, Buffer opb){
+ InfoResidue0 info=(InfoResidue0)vr;
+ int acc=0;
+ opb.write(info.begin,24);
+ opb.write(info.end,24);
+
+ opb.write(info.grouping-1,24); /* residue vectors to group and
+ code with a partitioned book */
+ opb.write(info.partitions-1,6); /* possible partition choices */
+ opb.write(info.groupbook,8); /* group huffman book */
+
+ /* secondstages is a bitmask; as encoding progresses pass by pass, a
+ bitmask of one indicates this partition class has bits to write
+ this pass */
+ for(int j=0;j<info.partitions;j++){
+ if(ilog(info.secondstages[j])>3){
+ /* yes, this is a minor hack due to not thinking ahead */
+ opb.write(info.secondstages[j],3);
+ opb.write(1,1);
+ opb.write(info.secondstages[j]>>>3,5);
+ }
+ else{
+ opb.write(info.secondstages[j],4); /* trailing zero */
+ }
+ acc+=icount(info.secondstages[j]);
+ }
+ for(int j=0;j<acc;j++){
+ opb.write(info.booklist[j],8);
+ }
+ }
+
+ Object unpack(Info vi, Buffer opb){
+ int acc=0;
+ InfoResidue0 info=new InfoResidue0();
+
+ info.begin=opb.read(24);
+ info.end=opb.read(24);
+ info.grouping=opb.read(24)+1;
+ info.partitions=opb.read(6)+1;
+ info.groupbook=opb.read(8);
+
+ for(int j=0;j<info.partitions;j++){
+ int cascade=opb.read(3);
+ if(opb.read(1)!=0){
+ cascade|=(opb.read(5)<<3);
+ }
+ info.secondstages[j]=cascade;
+ acc+=icount(cascade);
+ }
+
+ for(int j=0;j<acc;j++){
+ info.booklist[j]=opb.read(8);
+// if(info.booklist[j]==255)info.booklist[j]=-1;
+ }
+
+ if(info.groupbook>=vi.books){
+ free_info(info);
+ return(null);
+ }
+
+ for(int j=0;j<acc;j++){
+ if(info.booklist[j]>=vi.books){
+ free_info(info);
+ return(null);
+ }
+ }
+ return(info);
+// errout:
+// free_info(info);
+// return(NULL);
+ }
+
+ Object look(DspState vd, InfoMode vm, Object vr){
+ InfoResidue0 info=(InfoResidue0)vr;
+ LookResidue0 look=new LookResidue0();
+ int acc=0;
+ int dim;
+ int maxstage=0;
+ look.info=info;
+ look.map=vm.mapping;
+
+ look.parts=info.partitions;
+ look.fullbooks=vd.fullbooks;
+ look.phrasebook=vd.fullbooks[info.groupbook];
+
+ dim=look.phrasebook.dim;
+
+ look.partbooks=new int[look.parts][];
+
+ for(int j=0;j<look.parts;j++){
+ int stages=ilog(info.secondstages[j]);
+ if(stages!=0){
+ if(stages>maxstage)maxstage=stages;
+ look.partbooks[j]=new int[stages];
+ for(int k=0; k<stages; k++){
+ if((info.secondstages[j]&(1<<k))!=0){
+ look.partbooks[j][k]=info.booklist[acc++];
+ }
+ }
+ }
+ }
+
+ look.partvals=(int)Math.rint(Math.pow(look.parts,dim));
+ look.stages=maxstage;
+ look.decodemap=new int[look.partvals][];
+ for(int j=0;j<look.partvals;j++){
+ int val=j;
+ int mult=look.partvals/look.parts;
+ look.decodemap[j]=new int[dim];
+
+ for(int k=0;k<dim;k++){
+ int deco=val/mult;
+ val-=deco*mult;
+ mult/=look.parts;
+ look.decodemap[j][k]=deco;
+ }
+ }
+ return(look);
+ }
+ void free_info(Object i){}
+ void free_look(Object i){}
+ int forward(Block vb,Object vl, float[][] in, int ch){
+ System.err.println("Residue0.forward: not implemented");
+ return 0;
+ }
+
+ static int[][][] partword=new int[2][][]; // _01inverse is synchronized for
+ // re-using partword
+ synchronized static int _01inverse(Block vb, Object vl,
+ float[][] in,int ch,int decodepart){
+ int i,j,k,l,s;
+ LookResidue0 look=(LookResidue0 )vl;
+ InfoResidue0 info=look.info;
+
+ // move all this setup out later
+ int samples_per_partition=info.grouping;
+ int partitions_per_word=look.phrasebook.dim;
+ int n=info.end-info.begin;
+
+ int partvals=n/samples_per_partition;
+ int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
+
+ if(partword.length<ch){
+ partword=new int[ch][][];
+ for(j=0;j<ch;j++){
+ partword[j]=new int[partwords][];
+ }
+ }
+ else{
+ for(j=0;j<ch;j++){
+ if(partword[j]==null || partword[j].length<partwords)
+ partword[j]=new int[partwords][];
+ }
+ }
+
+ for(s=0;s<look.stages;s++){
+ // each loop decodes on partition codeword containing
+ // partitions_pre_word partitions
+ for(i=0,l=0;i<partvals;l++){
+ if(s==0){
+ // fetch the partition word for each channel
+ for(j=0;j<ch;j++){
+ int temp=look.phrasebook.decode(vb.opb);
+ if(temp==-1){
+ //goto eopbreak;
+ return(0);
+ }
+ partword[j][l]=look.decodemap[temp];
+ if(partword[j][l]==null){
+// goto errout;
+ return(0);
+ }
+ }
+ }
+
+ // now we decode residual values for the partitions
+ for(k=0;k<partitions_per_word && i<partvals;k++,i++)
+ for(j=0;j<ch;j++){
+ int offset=info.begin+i*samples_per_partition;
+ if((info.secondstages[partword[j][l][k]]&(1<<s))!=0){
+ CodeBook stagebook=look.fullbooks[look.partbooks[partword[j][l][k]][s]];
+// CodeBook stagebook=look.partbooks[partword[j][l][k]][s];
+ if(stagebook!=null){
+ if(decodepart==0){
+ if(stagebook.decodevs_add(in[j],offset,vb.opb,samples_per_partition)==-1){
+ // goto errout;
+ return(0);
+ }
+ }
+ else if(decodepart==1){
+ if(stagebook.decodev_add(in[j], offset, vb.opb,samples_per_partition)==-1){
+ // goto errout;
+ return(0);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+// errout:
+// eopbreak:
+ return(0);
+ }
+
+ static int _2inverse(Block vb, Object vl, float[][] in, int ch){
+ int i,j,k,l,s;
+ LookResidue0 look=(LookResidue0 )vl;
+ InfoResidue0 info=look.info;
+
+ // move all this setup out later
+ int samples_per_partition=info.grouping;
+ int partitions_per_word=look.phrasebook.dim;
+ int n=info.end-info.begin;
+
+ int partvals=n/samples_per_partition;
+ int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
+
+ int[][] partword=new int[partwords][];
+ for(s=0;s<look.stages;s++){
+ for(i=0,l=0;i<partvals;l++){
+ if(s==0){
+ // fetch the partition word for each channel
+ int temp=look.phrasebook.decode(vb.opb);
+ if(temp==-1){
+ // goto eopbreak;
+ return(0);
+ }
+ partword[l]=look.decodemap[temp];
+ if(partword[l]==null){
+ // goto errout;
+ return(0);
+ }
+ }
+
+ // now we decode residual values for the partitions
+ for(k=0;k<partitions_per_word && i<partvals;k++,i++){
+ int offset=info.begin+i*samples_per_partition;
+ if((info.secondstages[partword[l][k]]&(1<<s))!=0){
+ CodeBook stagebook=look.fullbooks[look.partbooks[partword[l][k]][s]];
+ if(stagebook!=null){
+ if(stagebook.decodevv_add(in, offset, ch, vb.opb,samples_per_partition)==-1){
+ // goto errout;
+ return(0);
+ }
+ }
+ }
+ }
+ }
+ }
+// errout:
+// eopbreak:
+ return(0);
+ }
+
+ int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
+ //System.err.println("Residue0.inverse");
+ int used=0;
+ for(int i=0;i<ch;i++){
+ if(nonzero[i]!=0){
+ in[used++]=in[i];
+ }
+ }
+ if(used!=0)
+ return(_01inverse(vb,vl,in,used,0));
+ else
+ return(0);
+ }
+
+/*
+ int inverse(Block vb, Object vl, float[][] in, int ch){
+//System.err.println("Residue0.inverse");
+ int i,j,k,l,transend=vb.pcmend/2;
+ LookResidue0 look=(LookResidue0 )vl;
+ InfoResidue0 info=look.info;
+
+ // move all this setup out later
+ int samples_per_partition=info.grouping;
+ int partitions_per_word=look.phrasebook.dim;
+ int n=info.end-info.begin;
+
+ int partvals=n/samples_per_partition;
+ int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
+ int[][] partword=new int[ch][];
+ float[] work=new float[samples_per_partition];
+ partvals=partwords*partitions_per_word;
+
+ // make sure we're zeroed up to the start
+ for(j=0;j<ch;j++){
+ for(k=0; k<info.begin; k++)in[j][k]=0.0f;
+ }
+
+ for(i=info.begin,l=0;i<info.end;){
+ // fetch the partition word for each channel
+ for(j=0;j<ch;j++){
+ int temp=look.phrasebook.decode(vb.opb);
+ if(temp==-1){
+ //goto eopbreak;
+ if(i<transend){
+ for(j=0;j<ch;j++){
+ for(k=0;k<transend-i;k++)in[j][i+k]=0.0f;
+ }
+ }
+ return(0);
+ }
+ partword[j]=look.decodemap[temp];
+ if(partword[j]==null){
+ //goto errout;
+ for(j=0;j<ch;j++){
+ for(k=0;k<transend;k++)in[j][k]=0.0f;
+ }
+ return(0);
+ }
+ }
+
+ // now we decode interleaved residual values for the partitions
+ for(k=0;k<partitions_per_word;k++,l++,i+=samples_per_partition){
+ for(j=0;j<ch;j++){
+ int part=partword[j][k];
+ if(decodepart(vb.opb,work, in[j], i,samples_per_partition,
+ info.secondstages[part],
+ look.partbooks[part])==-1){
+ //goto eopbreak;
+ if(i<transend){
+ for(j=0;j<ch;j++){
+ for(k=0;k<transend-i;k++)in[j][i+k]=0.0f;
+ }
+ }
+ return(0);
+ }
+ }
+ }
+ }
+
+// eopbreak:
+ if(i<transend){
+ for(j=0;j<ch;j++){
+ for(k=0;k<transend-i;k++)in[j][i+k]=0.0f;
+ }
+ }
+ return(0);
+
+// errout:
+// for(j=0;j<ch;j++)
+// for(k=0;k<transend;k++)in[j][k]=0.0f;
+// return(0);
+ }
+ int decodepart(Buffer opb, float[] work, float[] vec, int veci,
+ int n, int stages, CodeBook[] books){
+ int i,j;
+ for(i=0;i<n;i++)work[i]=0.0f;
+
+ for(j=0;j<stages;j++){
+ int dim=books[j].dim;
+ int step=n/dim;
+ for(i=0;i<step;i++){
+ if(books[j].decodevs(work, i, opb, step, 0)==-1){
+ return(-1);
+ }
+ }
+ }
+ for(i=0;i<n;i++){
+ vec[veci+i]*=work[i];
+ }
+ return(0);
+ }
+*/
+
+ private static int ilog(int v){
+ int ret=0;
+ while(v!=0){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+ private static int icount(int v){
+ int ret=0;
+ while(v!=0){
+ ret+=(v&1);
+ v>>>=1;
+ }
+ return(ret);
+ }
+}
+
+class LookResidue0 {
+ InfoResidue0 info;
+ int map;
+
+ int parts;
+ int stages;
+ CodeBook[] fullbooks;
+ CodeBook phrasebook;
+ int[][] partbooks;
+// CodeBook[][] partbooks;
+
+ int partvals;
+ int[][] decodemap;
+
+ int postbits;
+ int phrasebits;
+// int[][] frames;
+ int frames;
+}
+
+class InfoResidue0{
+ // block-partitioned VQ coded straight residue
+ int begin;
+ int end;
+
+ // first stage (lossless partitioning)
+ int grouping; // group n vectors per partition
+ int partitions; // possible codebooks for a partition
+ int groupbook; // huffbook for partitioning
+ int[] secondstages=new int[64]; // expanded out to pointers in lookup
+ int[] booklist=new int[256]; // list of second stage books
+
+ // encode-only heuristic settings
+ float[] entmax=new float[64]; // book entropy threshholds
+ float[] ampmax=new float[64]; // book amp threshholds
+ int[] subgrp=new int[64]; // book heuristic subgroup size
+ int[] blimit=new int[64]; // subgroup position limits
+}
diff --git a/songdbj/com/jcraft/jorbis/Residue1.java b/songdbj/com/jcraft/jorbis/Residue1.java
new file mode 100644
index 0000000000..c29ed8d671
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Residue1.java
@@ -0,0 +1,51 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Residue1 extends Residue0{
+ int forward(Block vb,Object vl, float[][] in, int ch){
+ System.err.println("Residue0.forward: not implemented");
+ return 0;
+ }
+
+ int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
+//System.err.println("Residue0.inverse");
+ int used=0;
+ for(int i=0; i<ch; i++){
+ if(nonzero[i]!=0){
+ in[used++]=in[i];
+ }
+ }
+ if(used!=0){
+ return(_01inverse(vb,vl,in,used,1));
+ }
+ else{
+ return 0;
+ }
+ }
+}
diff --git a/songdbj/com/jcraft/jorbis/Residue2.java b/songdbj/com/jcraft/jorbis/Residue2.java
new file mode 100644
index 0000000000..146a8341e5
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Residue2.java
@@ -0,0 +1,44 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Residue2 extends Residue0{
+ int forward(Block vb,Object vl, float[][] in, int ch){
+ System.err.println("Residue0.forward: not implemented");
+ return 0;
+ }
+
+ int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
+//System.err.println("Residue0.inverse");
+ int i=0;
+ for(i=0;i<ch;i++)if(nonzero[i]!=0)break;
+ if(i==ch)return(0); /* no nonzero vectors */
+
+ return(_2inverse(vb,vl,in, ch));
+ }
+}
diff --git a/songdbj/com/jcraft/jorbis/StaticCodeBook.java b/songdbj/com/jcraft/jorbis/StaticCodeBook.java
new file mode 100644
index 0000000000..7d9d6dc232
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/StaticCodeBook.java
@@ -0,0 +1,588 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class StaticCodeBook{
+ int dim; // codebook dimensions (elements per vector)
+ int entries; // codebook entries
+ int[] lengthlist; // codeword lengths in bits
+
+ // mapping
+ int maptype; // 0=none
+ // 1=implicitly populated values from map column
+ // 2=listed arbitrary values
+
+ // The below does a linear, single monotonic sequence mapping.
+ int q_min; // packed 32 bit float; quant value 0 maps to minval
+ int q_delta; // packed 32 bit float; val 1 - val 0 == delta
+ int q_quant; // bits: 0 < quant <= 16
+ int q_sequencep; // bitflag
+
+ // additional information for log (dB) mapping; the linear mapping
+ // is assumed to actually be values in dB. encodebias is used to
+ // assign an error weight to 0 dB. We have two additional flags:
+ // zeroflag indicates if entry zero is to represent -Inf dB; negflag
+ // indicates if we're to represent negative linear values in a
+ // mirror of the positive mapping.
+
+ int[] quantlist; // map == 1: (int)(entries/dim) element column map
+ // map == 2: list of dim*entries quantized entry vals
+
+ // encode helpers
+ EncodeAuxNearestMatch nearest_tree;
+ EncodeAuxThreshMatch thresh_tree;
+
+ StaticCodeBook(){}
+ StaticCodeBook(int dim, int entries, int[] lengthlist,
+ int maptype, int q_min, int q_delta,
+ int q_quant, int q_sequencep, int[] quantlist,
+ //EncodeAuxNearestmatch nearest_tree,
+ Object nearest_tree,
+ // EncodeAuxThreshmatch thresh_tree,
+ Object thresh_tree
+ ){
+ this();
+ this.dim=dim; this.entries=entries; this.lengthlist=lengthlist;
+ this.maptype=maptype; this.q_min=q_min; this.q_delta=q_delta;
+ this.q_quant=q_quant; this.q_sequencep=q_sequencep;
+ this.quantlist=quantlist;
+ }
+
+ int pack(Buffer opb){
+ int i;
+ boolean ordered=false;
+
+ opb.write(0x564342,24);
+ opb.write(dim, 16);
+ opb.write(entries, 24);
+
+ // pack the codewords. There are two packings; length ordered and
+ // length random. Decide between the two now.
+
+ for(i=1;i<entries;i++){
+ if(lengthlist[i]<lengthlist[i-1])break;
+ }
+ if(i==entries)ordered=true;
+
+ if(ordered){
+ // length ordered. We only need to say how many codewords of
+ // each length. The actual codewords are generated
+ // deterministically
+
+ int count=0;
+ opb.write(1,1); // ordered
+ opb.write(lengthlist[0]-1,5); // 1 to 32
+
+ for(i=1;i<entries;i++){
+ int _this=lengthlist[i];
+ int _last=lengthlist[i-1];
+ if(_this>_last){
+ for(int j=_last;j<_this;j++){
+ opb.write(i-count,ilog(entries-count));
+ count=i;
+ }
+ }
+ }
+ opb.write(i-count,ilog(entries-count));
+ }
+ else{
+ // length random. Again, we don't code the codeword itself, just
+ // the length. This time, though, we have to encode each length
+ opb.write(0,1); // unordered
+
+ // algortihmic mapping has use for 'unused entries', which we tag
+ // here. The algorithmic mapping happens as usual, but the unused
+ // entry has no codeword.
+ for(i=0;i<entries;i++){
+ if(lengthlist[i]==0)break;
+ }
+
+ if(i==entries){
+ opb.write(0,1); // no unused entries
+ for(i=0;i<entries;i++){
+ opb.write(lengthlist[i]-1,5);
+ }
+ }
+ else{
+ opb.write(1,1); // we have unused entries; thus we tag
+ for(i=0;i<entries;i++){
+ if(lengthlist[i]==0){
+ opb.write(0,1);
+ }
+ else{
+ opb.write(1,1);
+ opb.write(lengthlist[i]-1,5);
+ }
+ }
+ }
+ }
+
+ // is the entry number the desired return value, or do we have a
+ // mapping? If we have a mapping, what type?
+ opb.write(maptype,4);
+ switch(maptype){
+ case 0:
+ // no mapping
+ break;
+ case 1:
+ case 2:
+ // implicitly populated value mapping
+ // explicitly populated value mapping
+ if(quantlist==null){
+ // no quantlist? error
+ return(-1);
+ }
+
+ // values that define the dequantization
+ opb.write(q_min,32);
+ opb.write(q_delta,32);
+ opb.write(q_quant-1,4);
+ opb.write(q_sequencep,1);
+
+ {
+ int quantvals=0;
+ switch(maptype){
+ case 1:
+ // a single column of (c->entries/c->dim) quantized values for
+ // building a full value list algorithmically (square lattice)
+ quantvals=maptype1_quantvals();
+ break;
+ case 2:
+ // every value (c->entries*c->dim total) specified explicitly
+ quantvals=entries*dim;
+ break;
+ }
+
+ // quantized values
+ for(i=0;i<quantvals;i++){
+ opb.write(Math.abs(quantlist[i]),q_quant);
+ }
+ }
+ break;
+ default:
+ // error case; we don't have any other map types now
+ return(-1);
+ }
+ return(0);
+ }
+/*
+*/
+
+ // unpacks a codebook from the packet buffer into the codebook struct,
+ // readies the codebook auxiliary structures for decode
+ int unpack(Buffer opb){
+ int i;
+ //memset(s,0,sizeof(static_codebook));
+
+ // make sure alignment is correct
+ if(opb.read(24)!=0x564342){
+// goto _eofout;
+ clear();
+ return(-1);
+ }
+
+ // first the basic parameters
+ dim=opb.read(16);
+ entries=opb.read(24);
+ if(entries==-1){
+// goto _eofout;
+ clear();
+ return(-1);
+ }
+
+ // codeword ordering.... length ordered or unordered?
+ switch(opb.read(1)){
+ case 0:
+ // unordered
+ lengthlist=new int[entries];
+
+ // allocated but unused entries?
+ if(opb.read(1)!=0){
+ // yes, unused entries
+
+ for(i=0;i<entries;i++){
+ if(opb.read(1)!=0){
+ int num=opb.read(5);
+ if(num==-1){
+// goto _eofout;
+ clear();
+ return(-1);
+ }
+ lengthlist[i]=num+1;
+ }
+ else{
+ lengthlist[i]=0;
+ }
+ }
+ }
+ else{
+ // all entries used; no tagging
+ for(i=0;i<entries;i++){
+ int num=opb.read(5);
+ if(num==-1){
+// goto _eofout;
+ clear();
+ return(-1);
+ }
+ lengthlist[i]=num+1;
+ }
+ }
+ break;
+ case 1:
+ // ordered
+ {
+ int length=opb.read(5)+1;
+ lengthlist=new int[entries];
+
+ for(i=0;i<entries;){
+ int num=opb.read(ilog(entries-i));
+ if(num==-1){
+// goto _eofout;
+ clear();
+ return(-1);
+ }
+ for(int j=0;j<num;j++,i++){
+ lengthlist[i]=length;
+ }
+ length++;
+ }
+ }
+ break;
+ default:
+ // EOF
+ return(-1);
+ }
+
+ // Do we have a mapping to unpack?
+ switch((maptype=opb.read(4))){
+ case 0:
+ // no mapping
+ break;
+ case 1:
+ case 2:
+ // implicitly populated value mapping
+ // explicitly populated value mapping
+ q_min=opb.read(32);
+ q_delta=opb.read(32);
+ q_quant=opb.read(4)+1;
+ q_sequencep=opb.read(1);
+
+ {
+ int quantvals=0;
+ switch(maptype){
+ case 1:
+ quantvals=maptype1_quantvals();
+ break;
+ case 2:
+ quantvals=entries*dim;
+ break;
+ }
+
+ // quantized values
+ quantlist=new int[quantvals];
+ for(i=0;i<quantvals;i++){
+ quantlist[i]=opb.read(q_quant);
+ }
+ if(quantlist[quantvals-1]==-1){
+// goto _eofout;
+ clear();
+ return(-1);
+ }
+ }
+ break;
+ default:
+// goto _eofout;
+ clear();
+ return(-1);
+ }
+ // all set
+ return(0);
+// _errout:
+// _eofout:
+// vorbis_staticbook_clear(s);
+// return(-1);
+ }
+
+ // there might be a straightforward one-line way to do the below
+ // that's portable and totally safe against roundoff, but I haven't
+ // thought of it. Therefore, we opt on the side of caution
+ private int maptype1_quantvals(){
+ int vals=(int)(Math.floor(Math.pow(entries,1./dim)));
+
+ // the above *should* be reliable, but we'll not assume that FP is
+ // ever reliable when bitstream sync is at stake; verify via integer
+ // means that vals really is the greatest value of dim for which
+ // vals^b->bim <= b->entries
+ // treat the above as an initial guess
+ while(true){
+ int acc=1;
+ int acc1=1;
+ for(int i=0;i<dim;i++){
+ acc*=vals;
+ acc1*=vals+1;
+ }
+ if(acc<=entries && acc1>entries){ return(vals); }
+ else{
+ if(acc>entries){ vals--; }
+ else{ vals++; }
+ }
+ }
+ }
+
+ void clear(){
+// if(quantlist!=null)free(b->quantlist);
+// if(lengthlist!=null)free(b->lengthlist);
+// if(nearest_tree!=null){
+// free(b->nearest_tree->ptr0);
+// free(b->nearest_tree->ptr1);
+// free(b->nearest_tree->p);
+// free(b->nearest_tree->q);
+// memset(b->nearest_tree,0,sizeof(encode_aux_nearestmatch));
+// free(b->nearest_tree);
+// }
+// if(thresh_tree!=null){
+// free(b->thresh_tree->quantthresh);
+// free(b->thresh_tree->quantmap);
+// memset(b->thresh_tree,0,sizeof(encode_aux_threshmatch));
+// free(b->thresh_tree);
+// }
+// memset(b,0,sizeof(static_codebook));
+ }
+
+ // unpack the quantized list of values for encode/decode
+ // we need to deal with two map types: in map type 1, the values are
+ // generated algorithmically (each column of the vector counts through
+ // the values in the quant vector). in map type 2, all the values came
+ // in in an explicit list. Both value lists must be unpacked
+ float[] unquantize(){
+
+ if(maptype==1 || maptype==2){
+ int quantvals;
+ float mindel=float32_unpack(q_min);
+ float delta=float32_unpack(q_delta);
+ float[] r=new float[entries*dim];
+
+ //System.err.println("q_min="+q_min+", mindel="+mindel);
+
+ // maptype 1 and 2 both use a quantized value vector, but
+ // different sizes
+ switch(maptype){
+ case 1:
+ // most of the time, entries%dimensions == 0, but we need to be
+ // well defined. We define that the possible vales at each
+ // scalar is values == entries/dim. If entries%dim != 0, we'll
+ // have 'too few' values (values*dim<entries), which means that
+ // we'll have 'left over' entries; left over entries use zeroed
+ // values (and are wasted). So don't generate codebooks like that
+ quantvals=maptype1_quantvals();
+ for(int j=0;j<entries;j++){
+ float last=0.f;
+ int indexdiv=1;
+ for(int k=0;k<dim;k++){
+ int index=(j/indexdiv)%quantvals;
+ float val=quantlist[index];
+ val=Math.abs(val)*delta+mindel+last;
+ if(q_sequencep!=0)last=val;
+ r[j*dim+k]=val;
+ indexdiv*=quantvals;
+ }
+ }
+ break;
+ case 2:
+ for(int j=0;j<entries;j++){
+ float last=0.f;
+ for(int k=0;k<dim;k++){
+ float val=quantlist[j*dim+k];
+//if((j*dim+k)==0){System.err.println(" | 0 -> "+val+" | ");}
+ val=Math.abs(val)*delta+mindel+last;
+ if(q_sequencep!=0)last=val;
+ r[j*dim+k]=val;
+//if((j*dim+k)==0){System.err.println(" $ r[0] -> "+r[0]+" | ");}
+ }
+ }
+//System.err.println("\nr[0]="+r[0]);
+ }
+ return(r);
+ }
+ return(null);
+ }
+
+ private static int ilog(int v){
+ int ret=0;
+ while(v!=0){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+
+ // 32 bit float (not IEEE; nonnormalized mantissa +
+ // biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm
+ // Why not IEEE? It's just not that important here.
+
+ static final int VQ_FEXP=10;
+ static final int VQ_FMAN=21;
+ static final int VQ_FEXP_BIAS=768; // bias toward values smaller than 1.
+
+ // doesn't currently guard under/overflow
+ static long float32_pack(float val){
+ int sign=0;
+ int exp;
+ int mant;
+ if(val<0){
+ sign=0x80000000;
+ val= -val;
+ }
+ exp=(int)Math.floor(Math.log(val)/Math.log(2));
+ mant=(int)Math.rint(Math.pow(val,(VQ_FMAN-1)-exp));
+ exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN;
+ return(sign|exp|mant);
+ }
+
+ static float float32_unpack(int val){
+ float mant=val&0x1fffff;
+ float sign=val&0x80000000;
+ float exp =(val&0x7fe00000)>>>VQ_FMAN;
+//System.err.println("mant="+mant+", sign="+sign+", exp="+exp);
+ //if(sign!=0.0)mant= -mant;
+ if((val&0x80000000)!=0)mant= -mant;
+//System.err.println("mant="+mant);
+ return(ldexp(mant,((int)exp)-(VQ_FMAN-1)-VQ_FEXP_BIAS));
+ }
+
+ static float ldexp(float foo, int e){
+ return (float)(foo*Math.pow(2, e));
+ }
+
+/*
+ // TEST
+ // Unit tests of the dequantizer; this stuff will be OK
+ // cross-platform, I simply want to be sure that special mapping cases
+ // actually work properly; a bug could go unnoticed for a while
+
+ // cases:
+ //
+ // no mapping
+ // full, explicit mapping
+ // algorithmic mapping
+ //
+ // nonsequential
+ // sequential
+
+ static int[] full_quantlist1={0,1,2,3, 4,5,6,7, 8,3,6,1};
+ static int[] partial_quantlist1={0,7,2};
+
+ // no mapping
+ static StaticCodeBook test1=new StaticCodeBook(4,16,null,
+ 0,0,0,0,0,
+ null,null,null);
+ static float[] test1_result=null;
+
+ // linear, full mapping, nonsequential
+ static StaticCodeBook test2=new StaticCodeBook(4,3,null,
+ 2,-533200896,1611661312,4,0,
+ full_quantlist1, null, null);
+ static float[] test2_result={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2};
+
+ // linear, full mapping, sequential
+ static StaticCodeBook test3=new StaticCodeBook(4,3,null,
+ 2, -533200896,1611661312,4,1,
+ full_quantlist1,null, null);
+ static float[] test3_result={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6};
+
+ // linear, algorithmic mapping, nonsequential
+ static StaticCodeBook test4=new StaticCodeBook(3,27,null,
+ 1,-533200896,1611661312,4,0,
+ partial_quantlist1,null,null);
+ static float[] test4_result={-3,-3,-3, 4,-3,-3, -1,-3,-3,
+ -3, 4,-3, 4, 4,-3, -1, 4,-3,
+ -3,-1,-3, 4,-1,-3, -1,-1,-3,
+ -3,-3, 4, 4,-3, 4, -1,-3, 4,
+ -3, 4, 4, 4, 4, 4, -1, 4, 4,
+ -3,-1, 4, 4,-1, 4, -1,-1, 4,
+ -3,-3,-1, 4,-3,-1, -1,-3,-1,
+ -3, 4,-1, 4, 4,-1, -1, 4,-1,
+ -3,-1,-1, 4,-1,-1, -1,-1,-1};
+
+ // linear, algorithmic mapping, sequential
+ static StaticCodeBook test5=new StaticCodeBook(3,27,null,
+ 1,-533200896,1611661312,4,1,
+ partial_quantlist1,null,null);
+ static float[] test5_result={-3,-6,-9, 4, 1,-2, -1,-4,-7,
+ -3, 1,-2, 4, 8, 5, -1, 3, 0,
+ -3,-4,-7, 4, 3, 0, -1,-2,-5,
+ -3,-6,-2, 4, 1, 5, -1,-4, 0,
+ -3, 1, 5, 4, 8,12, -1, 3, 7,
+ -3,-4, 0, 4, 3, 7, -1,-2, 2,
+ -3,-6,-7, 4, 1, 0, -1,-4,-5,
+ -3, 1, 0, 4, 8, 7, -1, 3, 2,
+ -3,-4,-5, 4, 3, 2, -1,-2,-3};
+
+ void run_test(float[] comp){
+ float[] out=unquantize();
+ if(comp!=null){
+ if(out==null){
+ System.err.println("_book_unquantize incorrectly returned NULL");
+ System.exit(1);
+ }
+ for(int i=0;i<entries*dim;i++){
+ if(Math.abs(out[i]-comp[i])>.0001){
+ System.err.println("disagreement in unquantized and reference data:\nposition "+i+": "+out[i]+" != "+comp[i]);
+ System.exit(1);
+ }
+ }
+ }
+ else{
+ if(out!=null){
+ System.err.println("_book_unquantize returned a value array:\n correct result should have been NULL");
+ System.exit(1);
+ }
+ }
+ }
+
+ public static void main(String[] arg){
+ // run the nine dequant tests, and compare to the hand-rolled results
+ System.err.print("Dequant test 1... ");
+ test1.run_test(test1_result);
+ System.err.print("OK\nDequant test 2... ");
+ test2.run_test(test2_result);
+ System.err.print("OK\nDequant test 3... ");
+ test3.run_test(test3_result);
+ System.err.print("OK\nDequant test 4... ");
+ test4.run_test(test4_result);
+ System.err.print("OK\nDequant test 5... ");
+ test5.run_test(test5_result);
+ System.err.print("OK\n\n");
+ }
+*/
+}
+
+
+
+
+
diff --git a/songdbj/com/jcraft/jorbis/Time0.java b/songdbj/com/jcraft/jorbis/Time0.java
new file mode 100644
index 0000000000..f6a9fcb077
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/Time0.java
@@ -0,0 +1,38 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Time0 extends FuncTime{
+ void pack(Object i, Buffer opb){}
+ Object unpack(Info vi , Buffer opb){return "";}
+ Object look(DspState vd, InfoMode mi, Object i){return "";}
+ void free_info(Object i){}
+ void free_look(Object i){}
+ int forward(Block vb, Object i){return 0;}
+ int inverse(Block vb, Object i, float[] in, float[] out){return 0;}
+}
diff --git a/songdbj/com/jcraft/jorbis/VorbisFile.java b/songdbj/com/jcraft/jorbis/VorbisFile.java
new file mode 100644
index 0000000000..64edff006e
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/VorbisFile.java
@@ -0,0 +1,1361 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+public class VorbisFile{
+ static final int CHUNKSIZE=8500;
+ static final int SEEK_SET=0;
+ static final int SEEK_CUR=1;
+ static final int SEEK_END=2;
+
+ static final int OV_FALSE=-1;
+ static final int OV_EOF=-2;
+ static final int OV_HOLE=-3;
+
+ static final int OV_EREAD=-128;
+ static final int OV_EFAULT=-129;
+ static final int OV_EIMPL=-130;
+ static final int OV_EINVAL=-131;
+ static final int OV_ENOTVORBIS=-132;
+ static final int OV_EBADHEADER=-133;
+ static final int OV_EVERSION=-134;
+ static final int OV_ENOTAUDIO=-135;
+ static final int OV_EBADPACKET=-136;
+ static final int OV_EBADLINK=-137;
+ static final int OV_ENOSEEK=-138;
+
+ InputStream datasource;
+ boolean seekable=false;
+ long offset;
+ long end;
+
+ SyncState oy=new SyncState();
+
+ int links;
+ long[] offsets;
+ long[] dataoffsets;
+ int[] serialnos;
+ long[] pcmlengths;
+ Info[] vi;
+ Comment[] vc;
+
+ // Decoding working state local storage
+ long pcm_offset;
+ boolean decode_ready=false;
+ int current_serialno;
+ int current_link;
+
+ float bittrack;
+ float samptrack;
+
+ StreamState os=new StreamState(); // take physical pages, weld into a logical
+ // stream of packets
+ DspState vd=new DspState(); // central working state for
+ // the packet->PCM decoder
+ Block vb=new Block(vd); // local working space for packet->PCM decode
+
+ //ov_callbacks callbacks;
+
+ public VorbisFile(String file) throws JOrbisException {
+ super();
+ InputStream is=null;
+ try{
+ is=new SeekableInputStream(file);
+ int ret=open(is, null, 0);
+ if(ret==-1){
+ throw new JOrbisException("VorbisFile: open return -1");
+ }
+ }
+ catch(Exception e){
+ throw new JOrbisException("VorbisFile: "+e.toString());
+ }
+ finally{
+ if(is != null){
+ try {
+ is.close();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public VorbisFile(InputStream is, byte[] initial, int ibytes)
+ throws JOrbisException {
+ super();
+ int ret=open(is, initial, ibytes);
+ if(ret==-1){
+ }
+ }
+
+ private int get_data(){
+ int index=oy.buffer(CHUNKSIZE);
+ byte[] buffer=oy.data;
+// int bytes=callbacks.read_func(buffer, index, 1, CHUNKSIZE, datasource);
+ int bytes=0;
+ try{
+ bytes=datasource.read(buffer, index, CHUNKSIZE);
+ }
+ catch(Exception e){
+ //System.err.println(e);
+ return OV_EREAD;
+ }
+ oy.wrote(bytes);
+ if(bytes==-1){
+// System.out.println("bytes="+bytes);
+ bytes=0;
+ }
+ return bytes;
+ }
+
+ private void seek_helper(long offst){
+ //callbacks.seek_func(datasource, offst, SEEK_SET);
+ fseek(datasource, offst, SEEK_SET);
+ this.offset=offst;
+ oy.reset();
+ }
+
+ private int get_next_page(Page page, long boundary){
+ if(boundary>0) boundary+=offset;
+ while(true){
+ int more;
+ if(boundary>0 && offset>=boundary)return OV_FALSE;
+ more=oy.pageseek(page);
+ if(more<0){offset-=more;}
+ else{
+ if(more==0){
+ if(boundary==0)return OV_FALSE;
+// if(get_data()<=0)return -1;
+ int ret=get_data();
+ if(ret==0) return OV_EOF;
+ if(ret<0) return OV_EREAD;
+ }
+ else{
+ int ret=(int)offset; //!!!
+ offset+=more;
+ return ret;
+ }
+ }
+ }
+ }
+
+ private int get_prev_page(Page page) throws JOrbisException {
+ long begin=offset; //!!!
+ int ret;
+ int offst=-1;
+ while(offst==-1){
+ begin-=CHUNKSIZE;
+ if(begin<0)
+ begin=0;
+ seek_helper(begin);
+ while(offset<begin+CHUNKSIZE){
+ ret=get_next_page(page, begin+CHUNKSIZE-offset);
+ if(ret==OV_EREAD){ return OV_EREAD; }
+ if(ret<0){
+ if(offst == -1)
+ throw new JOrbisException();
+ break;
+ }
+ else{ offst=ret; }
+ }
+ }
+ seek_helper(offst); //!!!
+ ret=get_next_page(page, CHUNKSIZE);
+ if(ret<0){
+ //System.err.println("Missed page fencepost at end of logical bitstream Exiting");
+ //System.exit(1);
+ return OV_EFAULT;
+ }
+ return offst;
+ }
+
+ int bisect_forward_serialno(long begin, long searched, long end, int currentno, int m){
+ long endsearched=end;
+ long next=end;
+ Page page=new Page();
+ int ret;
+
+ while(searched<endsearched){
+ long bisect;
+ if(endsearched-searched<CHUNKSIZE){
+ bisect=searched;
+ }
+ else{
+ bisect=(searched+endsearched)/2;
+ }
+
+ seek_helper(bisect);
+ ret=get_next_page(page, -1);
+ if(ret==OV_EREAD) return OV_EREAD;
+ if(ret<0 || page.serialno()!=currentno){
+ endsearched=bisect;
+ if(ret>=0)next=ret;
+ }
+ else{
+ searched=ret+page.header_len+page.body_len;
+ }
+ }
+ seek_helper(next);
+ ret=get_next_page(page, -1);
+ if(ret==OV_EREAD) return OV_EREAD;
+
+ if(searched>=end || ret==-1){
+ links=m+1;
+ offsets=new long[m+2];
+ offsets[m+1]=searched;
+ }
+ else{
+ ret=bisect_forward_serialno(next, offset, end, page.serialno(), m+1);
+ if(ret==OV_EREAD)return OV_EREAD;
+ }
+ offsets[m]=begin;
+ return 0;
+ }
+
+ // uses the local ogg_stream storage in vf; this is important for
+ // non-streaming input sources
+ int fetch_headers(Info vi, Comment vc, int[] serialno, Page og_ptr){
+ //System.err.println("fetch_headers");
+ Page og=new Page();
+ Packet op=new Packet();
+ int ret;
+
+ if(og_ptr==null){
+ ret=get_next_page(og, CHUNKSIZE);
+ if(ret==OV_EREAD)return OV_EREAD;
+ if(ret<0) return OV_ENOTVORBIS;
+ og_ptr=og;
+ }
+
+ if(serialno!=null)serialno[0]=og_ptr.serialno();
+
+ os.init(og_ptr.serialno());
+
+ // extract the initial header from the first page and verify that the
+ // Ogg bitstream is in fact Vorbis data
+
+ vi.init();
+ vc.init();
+
+ int i=0;
+ while(i<3){
+ os.pagein(og_ptr);
+ while(i<3){
+ int result=os.packetout(op);
+ if(result==0)break;
+ if(result==-1){
+ //System.err.println("Corrupt header in logical bitstream.");
+ //goto bail_header;
+ vi.clear();
+ vc.clear();
+ os.clear();
+ return -1;
+ }
+ if(vi.synthesis_headerin(vc, op)!=0){
+ //System.err.println("Illegal header in logical bitstream.");
+ //goto bail_header;
+ vi.clear();
+ vc.clear();
+ os.clear();
+ return -1;
+ }
+ i++;
+ }
+ if(i<3)
+ if(get_next_page(og_ptr, 1)<0){
+ //System.err.println("Missing header in logical bitstream.");
+ //goto bail_header;
+ vi.clear();
+ vc.clear();
+ os.clear();
+ return -1;
+ }
+ }
+ return 0;
+
+// bail_header:
+// vorbis_info_clear(vi);
+// vorbis_comment_clear(vc);
+// ogg_stream_clear(&vf->os);
+// return -1;
+ }
+
+ // last step of the OggVorbis_File initialization; get all the
+ // vorbis_info structs and PCM positions. Only called by the seekable
+ // initialization (local stream storage is hacked slightly; pay
+ // attention to how that's done)
+ void prefetch_all_headers(Info first_i,Comment first_c,
+ int dataoffset) throws JOrbisException {
+ Page og=new Page();
+ int ret;
+
+ vi=new Info[links];
+ vc=new Comment[links];
+ dataoffsets=new long[links];
+ pcmlengths=new long[links];
+ serialnos=new int[links];
+
+ for(int i=0;i<links;i++){
+ if(first_i!=null && first_c!=null && i==0){
+ // we already grabbed the initial header earlier. This just
+ // saves the waste of grabbing it again
+ // !!!!!!!!!!!!!
+ vi[i]=first_i;
+ //memcpy(vf->vi+i,first_i,sizeof(vorbis_info));
+ vc[i]=first_c;
+ //memcpy(vf->vc+i,first_c,sizeof(vorbis_comment));
+ dataoffsets[i]=dataoffset;
+ }
+ else{
+ // seek to the location of the initial header
+ seek_helper(offsets[i]); //!!!
+ vi[i]=new Info();
+ vc[i]=new Comment();
+ if(fetch_headers(vi[i], vc[i], null, null)==-1){
+ //System.err.println("Error opening logical bitstream #"+(i+1)+"\n");
+ dataoffsets[i]=-1;
+ }
+ else{
+ dataoffsets[i]=offset;
+ os.clear();
+ }
+ }
+
+ // get the serial number and PCM length of this link. To do this,
+ // get the last page of the stream
+ {
+ long end=offsets[i+1]; //!!!
+ seek_helper(end);
+
+ while(true){
+ ret=get_prev_page(og);
+ if(ret==-1){
+ // this should not be possible
+ //System.err.println("Could not find last page of logical "+
+ // "bitstream #"+(i)+"\n");
+ vi[i].clear();
+ vc[i].clear();
+ break;
+ }
+ if(og.granulepos()!=-1){
+ serialnos[i]=og.serialno();
+ pcmlengths[i]=og.granulepos();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ int make_decode_ready(){
+ if(decode_ready)System.exit(1);
+ vd.synthesis_init(vi[0]);
+ vb.init(vd);
+ decode_ready=true;
+ return(0);
+ }
+
+ int open_seekable() throws JOrbisException {
+ Info initial_i=new Info();
+ Comment initial_c=new Comment();
+ int serialno;
+ long end;
+ int ret;
+ int dataoffset;
+ Page og=new Page();
+ // is this even vorbis...?
+ int[] foo=new int[1];
+ ret=fetch_headers(initial_i, initial_c, foo, null);
+ serialno=foo[0];
+ dataoffset=(int)offset; //!!
+ os.clear();
+ if(ret==-1)return(-1);
+ // we can seek, so set out learning all about this file
+ seekable=true;
+ //(callbacks.seek_func)(datasource, 0, SEEK_END);
+ fseek(datasource, 0, SEEK_END);
+ //offset=end=(callbacks.tell_func)(datasource);
+ offset=ftell(datasource);
+ end=offset;
+ // We get the offset for the last page of the physical bitstream.
+ // Most OggVorbis files will contain a single logical bitstream
+ end=get_prev_page(og);
+ // moer than one logical bitstream?
+ if(og.serialno()!=serialno){
+ // Chained bitstream. Bisect-search each logical bitstream
+ // section. Do so based on serial number only
+ if(bisect_forward_serialno(0,0,end+1,serialno,0)<0){
+ clear();
+ return OV_EREAD;
+ }
+ }
+ else{
+ // Only one logical bitstream
+ if(bisect_forward_serialno(0,end,end+1,serialno,0)<0){
+ clear();
+ return OV_EREAD;
+ }
+ }
+ prefetch_all_headers(initial_i, initial_c, dataoffset);
+ return(raw_seek(0));
+ }
+
+ int open_nonseekable(){
+ //System.err.println("open_nonseekable");
+ // we cannot seek. Set up a 'single' (current) logical bitstream entry
+ links=1;
+ vi=new Info[links]; vi[0]=new Info(); // ??
+ vc=new Comment[links]; vc[0]=new Comment(); // ?? bug?
+
+ // Try to fetch the headers, maintaining all the storage
+ int[]foo=new int[1];
+ if(fetch_headers(vi[0], vc[0], foo, null)==-1)return(-1);
+ current_serialno=foo[0];
+ make_decode_ready();
+ return 0;
+ }
+
+ // clear out the current logical bitstream decoder
+ void decode_clear(){
+ os.clear();
+ vd.clear();
+ vb.clear();
+ decode_ready=false;
+ bittrack=0.f;
+ samptrack=0.f;
+ }
+
+ // fetch and process a packet. Handles the case where we're at a
+ // bitstream boundary and dumps the decoding machine. If the decoding
+ // machine is unloaded, it loads it. It also keeps pcm_offset up to
+ // date (seek and read both use this. seek uses a special hack with
+ // readp).
+ //
+ // return: -1) hole in the data (lost packet)
+ // 0) need more date (only if readp==0)/eof
+ // 1) got a packet
+
+ int process_packet(int readp){
+ Page og=new Page();
+
+ // handle one packet. Try to fetch it from current stream state
+ // extract packets from page
+ while(true){
+ // process a packet if we can. If the machine isn't loaded,
+ // neither is a page
+ if(decode_ready){
+ Packet op=new Packet();
+ int result=os.packetout(op);
+ long granulepos;
+ // if(result==-1)return(-1); // hole in the data. For now, swallow
+ // and go. We'll need to add a real
+ // error code in a bit.
+ if(result>0){
+ // got a packet. process it
+ granulepos=op.granulepos;
+ if(vb.synthesis(op)==0){ // lazy check for lazy
+ // header handling. The
+ // header packets aren't
+ // audio, so if/when we
+ // submit them,
+ // vorbis_synthesis will
+ // reject them
+ // suck in the synthesis data and track bitrate
+ {
+ int oldsamples=vd.synthesis_pcmout(null, null);
+ vd.synthesis_blockin(vb);
+ samptrack+=vd.synthesis_pcmout(null, null)-oldsamples;
+ bittrack+=op.bytes*8;
+ }
+
+ // update the pcm offset.
+ if(granulepos!=-1 && op.e_o_s==0){
+ int link=(seekable?current_link:0);
+ int samples;
+ // this packet has a pcm_offset on it (the last packet
+ // completed on a page carries the offset) After processing
+ // (above), we know the pcm position of the *last* sample
+ // ready to be returned. Find the offset of the *first*
+ //
+ // As an aside, this trick is inaccurate if we begin
+ // reading anew right at the last page; the end-of-stream
+ // granulepos declares the last frame in the stream, and the
+ // last packet of the last page may be a partial frame.
+ // So, we need a previous granulepos from an in-sequence page
+ // to have a reference point. Thus the !op.e_o_s clause above
+
+ samples=vd.synthesis_pcmout(null, null);
+ granulepos-=samples;
+ for(int i=0;i<link;i++){
+ granulepos+=pcmlengths[i];
+ }
+ pcm_offset=granulepos;
+ }
+ return(1);
+ }
+ }
+ }
+
+ if(readp==0)return(0);
+ if(get_next_page(og,-1)<0)return(0); // eof. leave unitialized
+
+ // bitrate tracking; add the header's bytes here, the body bytes
+ // are done by packet above
+ bittrack+=og.header_len*8;
+
+ // has our decoding just traversed a bitstream boundary?
+ if(decode_ready){
+ if(current_serialno!=og.serialno()){
+ decode_clear();
+ }
+ }
+
+ // Do we need to load a new machine before submitting the page?
+ // This is different in the seekable and non-seekable cases.
+ //
+ // In the seekable case, we already have all the header
+ // information loaded and cached; we just initialize the machine
+ // with it and continue on our merry way.
+ //
+ // In the non-seekable (streaming) case, we'll only be at a
+ // boundary if we just left the previous logical bitstream and
+ // we're now nominally at the header of the next bitstream
+
+ if(!decode_ready){
+ int i;
+ if(seekable){
+ current_serialno=og.serialno();
+
+ // match the serialno to bitstream section. We use this rather than
+ // offset positions to avoid problems near logical bitstream
+ // boundaries
+ for(i=0;i<links;i++){
+ if(serialnos[i]==current_serialno)break;
+ }
+ if(i==links)return(-1); // sign of a bogus stream. error out,
+ // leave machine uninitialized
+ current_link=i;
+
+ os.init(current_serialno);
+ os.reset();
+
+ }
+ else{
+ // we're streaming
+ // fetch the three header packets, build the info struct
+ int foo[]=new int[1];
+ int ret=fetch_headers(vi[0], vc[0], foo, og);
+ current_serialno=foo[0];
+ if(ret!=0)return ret;
+ current_link++;
+ i=0;
+ }
+ make_decode_ready();
+ }
+ os.pagein(og);
+ }
+ }
+
+ //The helpers are over; it's all toplevel interface from here on out
+ // clear out the OggVorbis_File struct
+ int clear(){
+ vb.clear();
+ vd.clear();
+ os.clear();
+
+ if(vi!=null && links!=0){
+ for(int i=0;i<links;i++){
+ vi[i].clear();
+ vc[i].clear();
+ }
+ vi=null;
+ vc=null;
+ }
+ if(dataoffsets!=null)dataoffsets=null;
+ if(pcmlengths!=null)pcmlengths=null;
+ if(serialnos!=null)serialnos=null;
+ if(offsets!=null)offsets=null;
+ oy.clear();
+ //if(datasource!=null)(vf->callbacks.close_func)(vf->datasource);
+ //memset(vf,0,sizeof(OggVorbis_File));
+ return(0);
+ }
+
+ static int fseek(InputStream fis,
+ //int64_t off,
+ long off,
+ int whence){
+ if(fis instanceof SeekableInputStream){
+ SeekableInputStream sis=(SeekableInputStream)fis;
+ try{
+ if(whence==SEEK_SET){
+ sis.seek(off);
+ }
+ else if(whence==SEEK_END){
+ sis.seek(sis.getLength()-off);
+ }
+ else{
+ //System.out.println("seek: "+whence+" is not supported");
+ }
+ }
+ catch(Exception e){
+ }
+ return 0;
+ }
+ try{
+ if(whence==0){ fis.reset(); }
+ fis.skip(off);
+ }
+ catch(Exception e){return -1;}
+ return 0;
+ }
+
+ static long ftell(InputStream fis){
+ try{
+ if(fis instanceof SeekableInputStream){
+ SeekableInputStream sis=(SeekableInputStream)fis;
+ return (sis.tell());
+ }
+ }
+ catch(Exception e){
+ }
+ return 0;
+ }
+
+ // inspects the OggVorbis file and finds/documents all the logical
+ // bitstreams contained in it. Tries to be tolerant of logical
+ // bitstream sections that are truncated/woogie.
+ //
+ // return: -1) error
+ // 0) OK
+
+ int open(InputStream is, byte[] initial, int ibytes) throws JOrbisException {
+ //callbacks callbacks = {
+ // (size_t (*)(void *, size_t, size_t, void *)) fread,
+ // (int (*)(void *, int64_t, int)) _fseek,
+ // (int (*)(void *)) fclose,
+ // (long (*)(void *)) ftell
+ // };
+ return open_callbacks(is, initial, ibytes//, callbacks
+ );
+ }
+
+ int open_callbacks(InputStream is, byte[] initial,
+ int ibytes//, callbacks callbacks
+ ) throws JOrbisException {
+ int ret;
+ datasource=is;
+ //callbacks = _callbacks;
+ // init the framing state
+ oy.init();
+
+ // perhaps some data was previously read into a buffer for testing
+ // against other stream types. Allow initialization from this
+ // previously read data (as we may be reading from a non-seekable
+ // stream)
+ if(initial!=null){
+ int index=oy.buffer(ibytes);
+ System.arraycopy(initial, 0, oy.data, index, ibytes);
+ oy.wrote(ibytes);
+ }
+ // can we seek? Stevens suggests the seek test was portable
+ if(is instanceof SeekableInputStream){ ret=open_seekable(); }
+ else{ ret=open_nonseekable(); }
+ if(ret!=0){
+ datasource=null;
+ clear();
+ }
+ return ret;
+ }
+
+ // How many logical bitstreams in this physical bitstream?
+ public int streams(){
+ return links;
+ }
+
+ // Is the FILE * associated with vf seekable?
+ public boolean seekable(){
+ return seekable;
+ }
+
+ // returns the bitrate for a given logical bitstream or the entire
+ // physical bitstream. If the file is open for random access, it will
+ // find the *actual* average bitrate. If the file is streaming, it
+ // returns the nominal bitrate (if set) else the average of the
+ // upper/lower bounds (if set) else -1 (unset).
+ //
+ // If you want the actual bitrate field settings, get them from the
+ // vorbis_info structs
+
+ public int bitrate(int i){
+ if(i>=links)return(-1);
+ if(!seekable && i!=0)return(bitrate(0));
+ if(i<0){
+ long bits=0;
+ for(int j=0;j<links;j++){
+ bits+=(offsets[j+1]-dataoffsets[j])*8;
+ }
+ return((int)Math.rint(bits/time_total(-1)));
+ }
+ else{
+ if(seekable){
+ // return the actual bitrate
+ return((int)Math.rint((offsets[i+1]-dataoffsets[i])*8/time_total(i)));
+ }
+ else{
+ // return nominal if set
+ if(vi[i].bitrate_nominal>0){
+ return vi[i].bitrate_nominal;
+ }
+ else{
+ if(vi[i].bitrate_upper>0){
+ if(vi[i].bitrate_lower>0){
+ return (vi[i].bitrate_upper+vi[i].bitrate_lower)/2;
+ }else{
+ return vi[i].bitrate_upper;
+ }
+ }
+ return(-1);
+ }
+ }
+ }
+ }
+
+ // returns the actual bitrate since last call. returns -1 if no
+ // additional data to offer since last call (or at beginning of stream)
+ public int bitrate_instant(){
+ int _link=(seekable?current_link:0);
+ if(samptrack==0)return(-1);
+ int ret=(int)(bittrack/samptrack*vi[_link].rate+.5);
+ bittrack=0.f;
+ samptrack=0.f;
+ return(ret);
+ }
+
+ public int serialnumber(int i){
+ if(i>=links)return(-1);
+ if(!seekable && i>=0)return(serialnumber(-1));
+ if(i<0){
+ return(current_serialno);
+ }
+ else{
+ return(serialnos[i]);
+ }
+ }
+
+ // returns: total raw (compressed) length of content if i==-1
+ // raw (compressed) length of that logical bitstream for i==0 to n
+ // -1 if the stream is not seekable (we can't know the length)
+
+ public long raw_total(int i){
+ if(!seekable || i>=links)return(-1);
+ if(i<0){
+ long acc=0; // bug?
+ for(int j=0;j<links;j++){
+ acc+=raw_total(j);
+ }
+ return(acc);
+ }
+ else{
+ return(offsets[i+1]-offsets[i]);
+ }
+ }
+
+ // returns: total PCM length (samples) of content if i==-1
+ // PCM length (samples) of that logical bitstream for i==0 to n
+ // -1 if the stream is not seekable (we can't know the length)
+ public long pcm_total(int i){
+ if(!seekable || i>=links)return(-1);
+ if(i<0){
+ long acc=0;
+ for(int j=0;j<links;j++){
+ acc+=pcm_total(j);
+ }
+ return(acc);
+ }
+ else{
+ return(pcmlengths[i]);
+ }
+ }
+
+ // returns: total seconds of content if i==-1
+ // seconds in that logical bitstream for i==0 to n
+ // -1 if the stream is not seekable (we can't know the length)
+ public float time_total(int i){
+ if(!seekable || i>=links)return(-1);
+ if(i<0){
+ float acc=0;
+ for(int j=0;j<links;j++){
+ acc+=time_total(j);
+ }
+ return(acc);
+ }
+ else{
+ return((float)(pcmlengths[i])/vi[i].rate);
+ }
+ }
+
+ // seek to an offset relative to the *compressed* data. This also
+ // immediately sucks in and decodes pages to update the PCM cursor. It
+ // will cross a logical bitstream boundary, but only if it can't get
+ // any packets out of the tail of the bitstream we seek to (so no
+ // surprises).
+ //
+ // returns zero on success, nonzero on failure
+
+ public int raw_seek(int pos){
+ if(!seekable)return(-1); // don't dump machine if we can't seek
+ if(pos<0 || pos>offsets[links]){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+
+ // clear out decoding machine state
+ pcm_offset=-1;
+ decode_clear();
+
+ // seek
+ seek_helper(pos);
+
+ // we need to make sure the pcm_offset is set. We use the
+ // _fetch_packet helper to process one packet with readp set, then
+ // call it until it returns '0' with readp not set (the last packet
+ // from a page has the 'granulepos' field set, and that's how the
+ // helper updates the offset
+
+ switch(process_packet(1)){
+ case 0:
+ // oh, eof. There are no packets remaining. Set the pcm offset to
+ // the end of file
+ pcm_offset=pcm_total(-1);
+ return(0);
+ case -1:
+ // error! missing data or invalid bitstream structure
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ default:
+ // all OK
+ break;
+ }
+ while(true){
+ switch(process_packet(0)){
+ case 0:
+ // the offset is set. If it's a bogus bitstream with no offset
+ // information, it's not but that's not our fault. We still run
+ // gracefully, we're just missing the offset
+ return(0);
+ case -1:
+ // error! missing data or invalid bitstream structure
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ default:
+ // continue processing packets
+ break;
+ }
+ }
+
+ // seek_error:
+ // dump the machine so we're in a known state
+ //pcm_offset=-1;
+ //decode_clear();
+ //return -1;
+ }
+
+ // seek to a sample offset relative to the decompressed pcm stream
+ // returns zero on success, nonzero on failure
+
+ public int pcm_seek(long pos){
+ int link=-1;
+ long total=pcm_total(-1);
+
+ if(!seekable)return(-1); // don't dump machine if we can't seek
+ if(pos<0 || pos>total){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+
+ // which bitstream section does this pcm offset occur in?
+ for(link=links-1;link>=0;link--){
+ total-=pcmlengths[link];
+ if(pos>=total)break;
+ }
+
+ // search within the logical bitstream for the page with the highest
+ // pcm_pos preceeding (or equal to) pos. There is a danger here;
+ // missing pages or incorrect frame number information in the
+ // bitstream could make our task impossible. Account for that (it
+ // would be an error condition)
+ {
+ long target=pos-total;
+ long end=offsets[link+1];
+ long begin=offsets[link];
+ int best=(int)begin;
+
+ Page og=new Page();
+ while(begin<end){
+ long bisect;
+ int ret;
+
+ if(end-begin<CHUNKSIZE){
+ bisect=begin;
+ }
+ else{
+ bisect=(end+begin)/2;
+ }
+
+ seek_helper(bisect);
+ ret=get_next_page(og,end-bisect);
+
+ if(ret==-1){
+ end=bisect;
+ }
+ else{
+ long granulepos=og.granulepos();
+ if(granulepos<target){
+ best=ret; // raw offset of packet with granulepos
+ begin=offset; // raw offset of next packet
+ }
+ else{
+ end=bisect;
+ }
+ }
+ }
+ // found our page. seek to it (call raw_seek).
+ if(raw_seek(best)!=0){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+ }
+
+ // verify result
+ if(pcm_offset>=pos){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+ if(pos>pcm_total(-1)){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+
+ // discard samples until we reach the desired position. Crossing a
+ // logical bitstream boundary with abandon is OK.
+ while(pcm_offset<pos){
+ float[][] pcm;
+ int target=(int)(pos-pcm_offset);
+ float[][][] _pcm=new float[1][][];
+ int[] _index=new int[getInfo(-1).channels];
+ int samples=vd.synthesis_pcmout(_pcm, _index);
+ pcm=_pcm[0];
+
+ if(samples>target)samples=target;
+ vd.synthesis_read(samples);
+ pcm_offset+=samples;
+
+ if(samples<target)
+ if(process_packet(1)==0){
+ pcm_offset=pcm_total(-1); // eof
+ }
+ }
+ return 0;
+
+ // seek_error:
+ // dump machine so we're in a known state
+ //pcm_offset=-1;
+ //decode_clear();
+ //return -1;
+ }
+
+ // seek to a playback time relative to the decompressed pcm stream
+ // returns zero on success, nonzero on failure
+ int time_seek(float seconds){
+ // translate time to PCM position and call pcm_seek
+
+ int link=-1;
+ long pcm_total=pcm_total(-1);
+ float time_total=time_total(-1);
+
+ if(!seekable)return(-1); // don't dump machine if we can't seek
+ if(seconds<0 || seconds>time_total){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+
+ // which bitstream section does this time offset occur in?
+ for(link=links-1;link>=0;link--){
+ pcm_total-=pcmlengths[link];
+ time_total-=time_total(link);
+ if(seconds>=time_total)break;
+ }
+
+ // enough information to convert time offset to pcm offset
+ {
+ long target=(long)(pcm_total+(seconds-time_total)*vi[link].rate);
+ return(pcm_seek(target));
+ }
+
+ //seek_error:
+ // dump machine so we're in a known state
+ //pcm_offset=-1;
+ //decode_clear();
+ //return -1;
+ }
+
+ // tell the current stream offset cursor. Note that seek followed by
+ // tell will likely not give the set offset due to caching
+ public long raw_tell(){
+ return(offset);
+ }
+
+ // return PCM offset (sample) of next PCM sample to be read
+ public long pcm_tell(){
+ return(pcm_offset);
+ }
+
+ // return time offset (seconds) of next PCM sample to be read
+ public float time_tell(){
+ // translate time to PCM position and call pcm_seek
+
+ int link=-1;
+ long pcm_total=0;
+ float time_total=0.f;
+
+ if(seekable){
+ pcm_total=pcm_total(-1);
+ time_total=time_total(-1);
+
+ // which bitstream section does this time offset occur in?
+ for(link=links-1;link>=0;link--){
+ pcm_total-=pcmlengths[link];
+ time_total-=time_total(link);
+ if(pcm_offset>=pcm_total)break;
+ }
+ }
+
+ return((float)time_total+(float)(pcm_offset-pcm_total)/vi[link].rate);
+ }
+
+ // link: -1) return the vorbis_info struct for the bitstream section
+ // currently being decoded
+ // 0-n) to request information for a specific bitstream section
+ //
+ // In the case of a non-seekable bitstream, any call returns the
+ // current bitstream. NULL in the case that the machine is not
+ // initialized
+
+ public Info getInfo(int link){
+ if(seekable){
+ if(link<0){
+ if(decode_ready){
+ return vi[current_link];
+ }
+ else{
+ return null;
+ }
+ }
+ else{
+ if(link>=links){
+ return null;
+ }
+ else{
+ return vi[link];
+ }
+ }
+ }
+ else{
+ if(decode_ready){
+ return vi[0];
+ }
+ else{
+ return null;
+ }
+ }
+ }
+
+ public Comment getComment(int link){
+ if(seekable){
+ if(link<0){
+ if(decode_ready){ return vc[current_link]; }
+ else{ return null; }
+ }
+ else{
+ if(link>=links){ return null;}
+ else{ return vc[link]; }
+ }
+ }
+ else{
+ if(decode_ready){ return vc[0]; }
+ else{ return null; }
+ }
+ }
+
+ int host_is_big_endian() {
+ return 1;
+// short pattern = 0xbabe;
+// unsigned char *bytewise = (unsigned char *)&pattern;
+// if (bytewise[0] == 0xba) return 1;
+// assert(bytewise[0] == 0xbe);
+// return 0;
+ }
+
+ // up to this point, everything could more or less hide the multiple
+ // logical bitstream nature of chaining from the toplevel application
+ // if the toplevel application didn't particularly care. However, at
+ // the point that we actually read audio back, the multiple-section
+ // nature must surface: Multiple bitstream sections do not necessarily
+ // have to have the same number of channels or sampling rate.
+ //
+ // read returns the sequential logical bitstream number currently
+ // being decoded along with the PCM data in order that the toplevel
+ // application can take action on channel/sample rate changes. This
+ // number will be incremented even for streamed (non-seekable) streams
+ // (for seekable streams, it represents the actual logical bitstream
+ // index within the physical bitstream. Note that the accessor
+ // functions above are aware of this dichotomy).
+ //
+ // input values: buffer) a buffer to hold packed PCM data for return
+ // length) the byte length requested to be placed into buffer
+ // bigendianp) should the data be packed LSB first (0) or
+ // MSB first (1)
+ // word) word size for output. currently 1 (byte) or
+ // 2 (16 bit short)
+ //
+ // return values: -1) error/hole in data
+ // 0) EOF
+ // n) number of bytes of PCM actually returned. The
+ // below works on a packet-by-packet basis, so the
+ // return length is not related to the 'length' passed
+ // in, just guaranteed to fit.
+ //
+ // *section) set to the logical bitstream number
+
+ int read(byte[] buffer,int length,
+ int bigendianp, int word, int sgned, int[] bitstream){
+ int host_endian = host_is_big_endian();
+ int index=0;
+
+ while(true){
+ if(decode_ready){
+ float[][] pcm;
+ float[][][] _pcm=new float[1][][];
+ int[] _index=new int[getInfo(-1).channels];
+ int samples=vd.synthesis_pcmout(_pcm, _index);
+ pcm=_pcm[0];
+ if(samples!=0){
+ // yay! proceed to pack data into the byte buffer
+ int channels=getInfo(-1).channels;
+ int bytespersample=word * channels;
+ if(samples>length/bytespersample)samples=length/bytespersample;
+
+ // a tight loop to pack each size
+ {
+ int val;
+ if(word==1){
+ int off=(sgned!=0?0:128);
+ for(int j=0;j<samples;j++){
+ for(int i=0;i<channels;i++){
+ val=(int)(pcm[i][_index[i]+j]*128. + 0.5);
+ if(val>127)val=127;
+ else if(val<-128)val=-128;
+ buffer[index++]=(byte)(val+off);
+ }
+ }
+ }
+ else{
+ int off=(sgned!=0?0:32768);
+
+ if(host_endian==bigendianp){
+ if(sgned!=0){
+ for(int i=0;i<channels;i++) { // It's faster in this order
+ int src=_index[i];
+ int dest=i;
+ for(int j=0;j<samples;j++) {
+ val=(int)(pcm[i][src+j]*32768. + 0.5);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ buffer[dest]=(byte)(val>>>8);
+ buffer[dest+1]=(byte)(val);
+ dest+=channels*2;
+ }
+ }
+ }
+ else{
+ for(int i=0;i<channels;i++) {
+ float[] src=pcm[i];
+ int dest=i;
+ for(int j=0;j<samples;j++) {
+ val=(int)(src[j]*32768. + 0.5);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ buffer[dest]=(byte)((val+off)>>>8);
+ buffer[dest+1]=(byte)(val+off);
+ dest+=channels*2;
+ }
+ }
+ }
+ }
+ else if(bigendianp!=0){
+ for(int j=0;j<samples;j++){
+ for(int i=0;i<channels;i++){
+ val=(int)(pcm[i][j]*32768. + 0.5);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ val+=off;
+ buffer[index++]=(byte)(val>>>8);
+ buffer[index++]=(byte)val;
+ }
+ }
+ }
+ else{
+ //int val;
+ for(int j=0;j<samples;j++){
+ for(int i=0;i<channels;i++){
+ val=(int)(pcm[i][j]*32768. + 0.5);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ val+=off;
+ buffer[index++]=(byte)val;
+ buffer[index++]=(byte)(val>>>8);
+ }
+ }
+ }
+ }
+ }
+
+ vd.synthesis_read(samples);
+ pcm_offset+=samples;
+ if(bitstream!=null)bitstream[0]=current_link;
+ return(samples*bytespersample);
+ }
+ }
+
+ // suck in another packet
+ switch(process_packet(1)){
+ case 0:
+ return(0);
+ case -1:
+ return -1;
+ default:
+ break;
+ }
+ }
+ }
+
+ public Info[] getInfo(){return vi;}
+ public Comment[] getComment(){return vc;}
+
+/*
+ public static void main(String[] arg){
+ try{
+ VorbisFile foo=new VorbisFile(arg[0]);
+ int links=foo.streams();
+ System.out.println("links="+links);
+ Comment[] comment=foo.getComment();
+ Info[] info=foo.getInfo();
+ for(int i=0; i<links; i++){
+ System.out.println(info[i]);
+ System.out.println(comment[i]);
+ }
+ System.out.println("raw_total: "+foo.raw_total(-1));
+ System.out.println("pcm_total: "+foo.pcm_total(-1));
+ System.out.println("time_total: "+foo.time_total(-1));
+ }
+ catch(Exception e){
+ System.err.println(e);
+ }
+ }
+*/
+
+ public void close() throws java.io.IOException {
+ datasource.close();
+ }
+
+ class SeekableInputStream extends InputStream {
+ java.io.RandomAccessFile raf=null;
+ final String mode="r";
+ private SeekableInputStream(){
+ }
+ SeekableInputStream(String file) throws java.io.IOException{
+ raf=new java.io.RandomAccessFile(file, mode);
+ }
+ public int read() throws java.io.IOException{
+ return raf.read();
+ }
+ public int read(byte[] buf) throws java.io.IOException{
+ return raf.read(buf);
+ }
+ public int read(byte[] buf , int s, int len) throws java.io.IOException{
+ return raf.read(buf, s, len);
+ }
+ public long skip(long n) throws java.io.IOException{
+ return (long)(raf.skipBytes((int)n));
+ }
+ public long getLength() throws java.io.IOException{
+ return raf.length();
+ }
+ public long tell() throws java.io.IOException{
+ return raf.getFilePointer();
+ }
+ public int available() throws java.io.IOException{
+ return (raf.length()==raf.getFilePointer())? 0 : 1;
+ }
+ public void close() throws java.io.IOException{
+ raf.close();
+ }
+ public synchronized void mark(int m){
+ }
+ public synchronized void reset() throws java.io.IOException{
+ }
+ public boolean markSupported(){
+ return false;
+ }
+ public void seek(long pos) throws java.io.IOException{
+ raf.seek(pos);
+ }
+ }
+
+}
diff --git a/songdbj/com/jcraft/jorbis/VorbisFile.java.new b/songdbj/com/jcraft/jorbis/VorbisFile.java.new
new file mode 100644
index 0000000000..1f822b0991
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/VorbisFile.java.new
@@ -0,0 +1,1240 @@
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * 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 com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+import java.io.InputStream;
+
+public class VorbisFile{
+ static final int CHUNKSIZE=4096;
+ static final int SEEK_SET=0;
+
+ InputStream datasource;
+ boolean seekable=false;
+ long offset;
+ long end;
+
+ SyncState oy=new SyncState();
+
+ int links;
+ Comment[] vc;
+ Info[] vi;
+
+ long[] offsets;
+ long[] dataoffsets;
+ int[] serialnos;
+ long[] pcmlengths;
+
+
+
+ // Decoding working state local storage
+ long pcm_offset;
+ boolean decode_ready=false;
+ int current_serialno;
+ int current_link;
+
+ float bittrack;
+ float samptrack;
+
+ StreamState os=new StreamState(); // take physical pages, weld into a logical
+ // stream of packets
+ DspState vd=new DspState(); // central working state for
+ // the packet->PCM decoder
+ Block vb=new Block(vd); // local working space for packet->PCM decode
+
+ //ov_callbacks callbacks;
+
+ public VorbisFile(String file) throws JOrbisException {
+ super();
+ InputStream is=null;
+ try{ is=new java.io.BufferedInputStream(new java.io.FileInputStream(file));}
+ catch(Exception e){
+ throw new JOrbisException("VorbisFile: "+e.toString());
+ }
+ int ret=open(is, null, 0);
+ if(ret==-1){
+ throw new JOrbisException("VorbisFile: open return -1");
+ }
+ }
+
+ public VorbisFile(InputStream is, byte[] initial, int ibytes)
+ throws JOrbisException {
+ super();
+ int ret=open(is, initial, ibytes);
+ if(ret==-1){
+ }
+ }
+
+ private int get_data(){
+ int index=oy.buffer(CHUNKSIZE);
+ byte[] buffer=oy.data;
+// int bytes=callbacks.read_func(buffer, index, 1, CHUNKSIZE, datasource);
+ int bytes=0;
+ try{
+ bytes=datasource.read(buffer, index, CHUNKSIZE);
+ }
+ catch(Exception e){System.err.println(e);}
+ oy.wrote(bytes);
+ return bytes;
+ }
+
+ private void seek_helper(int offst){
+ //callbacks.seek_func(datasource, offst, SEEK_SET);
+ fseek64_wrap(datasource, offst, SEEK_SET);
+ this.offset=offst;
+ oy.reset();
+ }
+
+ private int get_next_page(Page page, int boundary){
+ if(boundary>0) boundary+=offset;
+ while(true){
+ int more;
+ if(boundary>0 && offset>=boundary)return -1;
+ more=oy.pageseek(page);
+ if(more<0){offset-=more;}
+ else{
+ if(more==0){
+ if(boundary==0)return -1;
+ if(get_data()<=0)return -1;
+ }
+ else{
+ int ret=(int)offset; //!!!
+ offset+=more;
+ return ret;
+ }
+ }
+ }
+ }
+
+ private int get_prev_page(Page page){
+ int begin=(int)offset; //!!!
+ int ret;
+ int offst=-1;
+ while(offst==-1){
+ begin-=CHUNKSIZE;
+ seek_helper(begin);
+ while(offset<begin+CHUNKSIZE){
+ ret=get_next_page(page, begin+CHUNKSIZE-((int)offset));
+ if(ret==-1){ break; }
+ else{ offst=ret; }
+ }
+ }
+ seek_helper((int)offset); //!!!
+ ret=get_next_page(page, CHUNKSIZE);
+ if(ret==-1){
+ System.err.println("Missed page fencepost at end of logical bitstream Exiting");
+ System.exit(1);
+ }
+ return offst;
+ }
+
+ void bisect_forward_serialno(int begin, int searched, int end, int currentno, int m){
+ int endsearched=end;
+ int next=end;
+ Page page=new Page();
+ int ret;
+ while(searched<endsearched){
+ int bisect;
+ if(endsearched-searched<CHUNKSIZE){
+ bisect=searched;
+ }
+ else{
+ bisect=(searched+endsearched)/2;
+ }
+
+ seek_helper(bisect);
+ ret=get_next_page(page, -1);
+ if(ret<0 || page.serialno()!=currentno){
+ endsearched=bisect;
+ if(ret>=0)next=ret;
+ }
+ else{
+ searched=ret+page.header_len+page.body_len;
+ }
+ }
+ seek_helper(next);
+ ret=get_next_page(page, -1);
+
+ if(searched>=end || ret==-1){
+ links=m+1;
+ offsets=new long[m+2];
+ offsets[m+1]=searched;
+ }
+ else{
+ bisect_forward_serialno(next, (int)offset, end, page.serialno(), m+1);
+ }
+ offsets[m]=begin;
+ }
+
+ // uses the local ogg_stream storage in vf; this is important for
+ // non-streaming input sources
+ int fetch_headers(Info vi, Comment vc, int[] serialno){
+ //System.err.println("fetch_headers");
+ Page og=new Page();
+ Packet op=new Packet();
+ int ret;
+
+ ret=get_next_page(og, CHUNKSIZE);
+ if(ret==-1){
+ System.err.println("Did not find initial header for bitstream.");
+ return -1;
+ }
+
+ if(serialno!=null)serialno[0]=og.serialno();
+
+ os.init(og.serialno());
+
+ // extract the initial header from the first page and verify that the
+ // Ogg bitstream is in fact Vorbis data
+
+ vi.init();
+ vc.init();
+
+ int i=0;
+ while(i<3){
+ os.pagein(og);
+ while(i<3){
+ int result=os.packetout(op);
+ if(result==0)break;
+ if(result==-1){
+ System.err.println("Corrupt header in logical bitstream.");
+ //goto bail_header;
+ vi.clear();
+ vc.clear();
+ os.clear();
+ return -1;
+ }
+ if(vi.synthesis_headerin(vc, op)!=0){
+ System.err.println("Illegal header in logical bitstream.");
+ //goto bail_header;
+ vi.clear();
+ vc.clear();
+ os.clear();
+ return -1;
+ }
+ i++;
+ }
+ if(i<3)
+ if(get_next_page(og, 1)<0){
+ System.err.println("Missing header in logical bitstream.");
+ //goto bail_header;
+ vi.clear();
+ vc.clear();
+ os.clear();
+ return -1;
+ }
+ }
+ return 0;
+
+// bail_header:
+// vorbis_info_clear(vi);
+// vorbis_comment_clear(vc);
+// ogg_stream_clear(&vf->os);
+// return -1;
+ }
+
+ // last step of the OggVorbis_File initialization; get all the
+ // vorbis_info structs and PCM positions. Only called by the seekable
+ // initialization (local stream storage is hacked slightly; pay
+ // attention to how that's done)
+ void prefetch_all_headers(Info first_i,Comment first_c, int dataoffset){
+ Page og=new Page();
+ int ret;
+
+ vi=new Info[links];
+ vc=new Comment[links];
+ dataoffsets=new long[links];
+ pcmlengths=new long[links];
+ serialnos=new int[links];
+
+ for(int i=0;i<links;i++){
+ if(first_i!=null && first_c!=null && i==0){
+ // we already grabbed the initial header earlier. This just
+ // saves the waste of grabbing it again
+ // !!!!!!!!!!!!!
+ vi[i]=first_i;
+ //memcpy(vf->vi+i,first_i,sizeof(vorbis_info));
+ vc[i]=first_c;
+ //memcpy(vf->vc+i,first_c,sizeof(vorbis_comment));
+ dataoffsets[i]=dataoffset;
+ }
+ else{
+ // seek to the location of the initial header
+ seek_helper((int)offsets[i]); //!!!
+ if(fetch_headers(vi[i], vc[i], null)==-1){
+ System.err.println("Error opening logical bitstream #"+(i+1)+"\n");
+ dataoffsets[i]=-1;
+ }
+ else{
+ dataoffsets[i]=offset;
+ os.clear();
+ }
+ }
+
+ // get the serial number and PCM length of this link. To do this,
+ // get the last page of the stream
+ {
+ int end=(int)offsets[i+1]; //!!!
+ seek_helper(end);
+
+ while(true){
+ ret=get_prev_page(og);
+ if(ret==-1){
+ // this should not be possible
+ System.err.println("Could not find last page of logical "+
+ "bitstream #"+(i)+"\n");
+ vi[i].clear();
+ vc[i].clear();
+ break;
+ }
+ if(og.granulepos()!=-1){
+ serialnos[i]=og.serialno();
+ pcmlengths[i]=og.granulepos();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ int make_decode_ready(){
+ if(decode_ready)System.exit(1);
+ vd.synthesis_init(vi[0]);
+ vb.init(vd);
+ decode_ready=true;
+ return(0);
+ }
+
+ int open_seekable(){
+ Info initial_i=new Info();
+ Comment initial_c=new Comment();
+ int serialno,end;
+ int ret;
+ int dataoffset;
+ Page og=new Page();
+System.out.println("open_seekable");
+ // is this even vorbis...?
+ int[] foo=new int[1];
+ ret=fetch_headers(initial_i, initial_c, foo);
+ serialno=foo[0];
+ dataoffset=(int)offset; //!!
+ os.clear();
+ if(ret==-1)return(-1);
+
+ // we can seek, so set out learning all about this file
+ seekable=true;
+ //(callbacks.seek_func)(datasource, 0, SEEK_END);
+ fseek64_wrap(datasource, (int)offset, SEEK_SET);
+ //offset=end=(callbacks.tell_func)(datasource);
+ end=(int)offset;
+
+ // We get the offset for the last page of the physical bitstream.
+ // Most OggVorbis files will contain a single logical bitstream
+ end=get_prev_page(og);
+
+ // moer than one logical bitstream?
+ if(og.serialno()!=serialno){
+ // Chained bitstream. Bisect-search each logical bitstream
+ // section. Do so based on serial number only
+ bisect_forward_serialno(0,0,end+1,serialno,0);
+ }
+ else{
+ // Only one logical bitstream
+ bisect_forward_serialno(0,end,end+1,serialno,0);
+ }
+ prefetch_all_headers(initial_i, initial_c, dataoffset);
+
+System.out.println("?");
+ return(raw_seek(0));
+ }
+
+ int open_nonseekable(){
+ //System.err.println("open_nonseekable");
+ // we cannot seek. Set up a 'single' (current) logical bitstream entry
+ links=1;
+ vi=new Info[links]; vi[0]=new Info(); // ??
+ vc=new Comment[links]; vc[0]=new Comment(); // ?? bug?
+
+ // Try to fetch the headers, maintaining all the storage
+ int[]foo=new int[1];
+ if(fetch_headers(vi[0], vc[0], foo)==-1)return(-1);
+ current_serialno=foo[0];
+ make_decode_ready();
+ return 0;
+ }
+
+ // clear out the current logical bitstream decoder
+ void decode_clear(){
+ os.clear();
+ vd.clear();
+ vb.clear();
+ decode_ready=false;
+ bittrack=0.f;
+ samptrack=0.f;
+ }
+
+ // fetch and process a packet. Handles the case where we're at a
+ // bitstream boundary and dumps the decoding machine. If the decoding
+ // machine is unloaded, it loads it. It also keeps pcm_offset up to
+ // date (seek and read both use this. seek uses a special hack with
+ // readp).
+ //
+ // return: -1) hole in the data (lost packet)
+ // 0) need more date (only if readp==0)/eof
+ // 1) got a packet
+
+ int process_packet(int readp){
+System.out.println("porcess_packet:"+ readp+" , decode_ready="+decode_ready);
+ Page og=new Page();
+
+ // handle one packet. Try to fetch it from current stream state
+ // extract packets from page
+ while(true){
+ // process a packet if we can. If the machine isn't loaded,
+ // neither is a page
+ if(decode_ready){
+ Packet op=new Packet();
+ int result=os.packetout(op);
+ long granulepos;
+ // if(result==-1)return(-1); // hole in the data. For now, swallow
+ // and go. We'll need to add a real
+ // error code in a bit.
+ if(result>0){
+ // got a packet. process it
+ granulepos=op.granulepos;
+ if(vb.synthesis(op)==0){ // lazy check for lazy
+ // header handling. The
+ // header packets aren't
+ // audio, so if/when we
+ // submit them,
+ // vorbis_synthesis will
+ // reject them
+ // suck in the synthesis data and track bitrate
+ {
+ int oldsamples=vd.synthesis_pcmout(null, null);
+ vd.synthesis_blockin(vb);
+ samptrack+=vd.synthesis_pcmout(null, null)-oldsamples;
+ bittrack+=op.bytes*8;
+ }
+
+ // update the pcm offset.
+ if(granulepos!=-1 && op.e_o_s==0){
+ int link=(seekable?current_link:0);
+ int samples;
+ // this packet has a pcm_offset on it (the last packet
+ // completed on a page carries the offset) After processing
+ // (above), we know the pcm position of the *last* sample
+ // ready to be returned. Find the offset of the *first*
+ //
+ // As an aside, this trick is inaccurate if we begin
+ // reading anew right at the last page; the end-of-stream
+ // granulepos declares the last frame in the stream, and the
+ // last packet of the last page may be a partial frame.
+ // So, we need a previous granulepos from an in-sequence page
+ // to have a reference point. Thus the !op.e_o_s clause above
+
+ samples=vd.synthesis_pcmout(null, null);
+ granulepos-=samples;
+ for(int i=0;i<link;i++){
+ granulepos+=pcmlengths[i];
+ }
+ pcm_offset=granulepos;
+ }
+ return(1);
+ }
+ }
+ }
+
+ if(readp==0)return(0);
+ if(get_next_page(og,-1)<0)return(0); // eof. leave unitialized
+
+ // bitrate tracking; add the header's bytes here, the body bytes
+ // are done by packet above
+ bittrack+=og.header_len*8;
+
+ // has our decoding just traversed a bitstream boundary?
+ if(decode_ready){
+ if(current_serialno!=og.serialno()){
+ decode_clear();
+ }
+ }
+
+ // Do we need to load a new machine before submitting the page?
+ // This is different in the seekable and non-seekable cases.
+ //
+ // In the seekable case, we already have all the header
+ // information loaded and cached; we just initialize the machine
+ // with it and continue on our merry way.
+ //
+ // In the non-seekable (streaming) case, we'll only be at a
+ // boundary if we just left the previous logical bitstream and
+ // we're now nominally at the header of the next bitstream
+
+ if(!decode_ready){
+ int i;
+ if(seekable){
+ current_serialno=og.serialno();
+
+ // match the serialno to bitstream section. We use this rather than
+ // offset positions to avoid problems near logical bitstream
+ // boundaries
+ for(i=0;i<links;i++){
+ if(serialnos[i]==current_serialno)break;
+ }
+ if(i==links)return(-1); // sign of a bogus stream. error out,
+ // leave machine uninitialized
+ current_link=i;
+
+ os.init(current_serialno);
+ os.reset();
+
+ }
+ else{
+ // we're streaming
+ // fetch the three header packets, build the info struct
+ int foo[]=new int[1];
+ fetch_headers(vi[0], vc[0], foo);
+ current_serialno=foo[0];
+ current_link++;
+ i=0;
+ }
+ make_decode_ready();
+ }
+ os.pagein(og);
+ }
+ }
+
+ //The helpers are over; it's all toplevel interface from here on out
+ // clear out the OggVorbis_File struct
+ int clear(){
+ vb.clear();
+ vd.clear();
+ os.clear();
+
+ if(vi!=null && links!=0){
+ for(int i=0;i<links;i++){
+ vi[i].clear();
+ vc[i].clear();
+ }
+ vi=null;
+ vc=null;
+ }
+ if(dataoffsets!=null)dataoffsets=null;
+ if(pcmlengths!=null)pcmlengths=null;
+ if(serialnos!=null)serialnos=null;
+ if(offsets!=null)offsets=null;
+ oy.clear();
+ //if(datasource!=null)(vf->callbacks.close_func)(vf->datasource);
+ //memset(vf,0,sizeof(OggVorbis_File));
+ return(0);
+ }
+
+ static int fseek64_wrap(InputStream fis,
+ //int64_t off,
+ int off,
+ int whence){
+
+ if(!fis.markSupported()){ return -1; }
+ try{
+ try{if(whence==0){ fis.reset(); }}
+ catch(Exception ee){System.out.println(ee);}
+ fis.skip(off);
+ }
+ catch(Exception e){ System.out.println(e);
+ //return -1;
+ }
+ return 0;
+ }
+
+ // inspects the OggVorbis file and finds/documents all the logical
+ // bitstreams contained in it. Tries to be tolerant of logical
+ // bitstream sections that are truncated/woogie.
+ //
+ // return: -1) error
+ // 0) OK
+
+ int open(InputStream is, byte[] initial, int ibytes){
+ return open_callbacks(is, initial, ibytes//, callbacks
+ );
+ }
+
+ int open_callbacks(InputStream is, byte[] initial,
+ int ibytes//, callbacks callbacks
+ ){
+// int offset=callbacks.seek_func(f,0,SEEK_CUR);
+ int _offset=fseek64_wrap(is, (int)offset, SEEK_SET);
+ int ret;
+ // memset(vf,0,sizeof(OggVorbis_File));
+ datasource=is;
+ //callbacks = _callbacks;
+
+ // init the framing state
+ oy.init();
+
+ // perhaps some data was previously read into a buffer for testing
+ // against other stream types. Allow initialization from this
+ // previously read data (as we may be reading from a non-seekable
+ // stream)
+ if(initial!=null){
+ int index=oy.buffer(ibytes);
+ System.arraycopy(initial, 0, oy.data, index, ibytes);
+ oy.wrote(ibytes);
+ }
+
+System.out.println("open_callbacks="+_offset);
+ // can we seek? Stevens suggests the seek test was portable
+ if(_offset!=-1){ ret=open_seekable(); }
+ else{ ret=open_nonseekable(); }
+
+System.out.println("ret="+ret);
+
+ if(ret!=0){
+ datasource=null;
+ clear();
+ }
+
+ return(ret);
+ }
+
+ // How many logical bitstreams in this physical bitstream?
+ public int streams(){
+ return links;
+ }
+
+ // Is the FILE * associated with vf seekable?
+ public boolean seekable(){
+ return seekable;
+ }
+
+ // returns the bitrate for a given logical bitstream or the entire
+ // physical bitstream. If the file is open for random access, it will
+ // find the *actual* average bitrate. If the file is streaming, it
+ // returns the nominal bitrate (if set) else the average of the
+ // upper/lower bounds (if set) else -1 (unset).
+ //
+ // If you want the actual bitrate field settings, get them from the
+ // vorbis_info structs
+
+ public int bitrate(int i){
+ if(i>=links)return(-1);
+ if(!seekable && i!=0)return(bitrate(0));
+ if(i<0){
+ long bits=0;
+ for(int j=0;j<links;j++){
+ bits+=(offsets[j+1]-dataoffsets[j])*8;
+ }
+ return((int)Math.rint(bits/time_total(-1)));
+ }
+ else{
+ if(seekable){
+ // return the actual bitrate
+ return((int)Math.rint((offsets[i+1]-dataoffsets[i])*8/time_total(i)));
+ }
+ else{
+ // return nominal if set
+ if(vi[i].bitrate_nominal>0){
+ return vi[i].bitrate_nominal;
+ }
+ else{
+ if(vi[i].bitrate_upper>0){
+ if(vi[i].bitrate_lower>0){
+ return (vi[i].bitrate_upper+vi[i].bitrate_lower)/2;
+ }else{
+ return vi[i].bitrate_upper;
+ }
+ }
+ return(-1);
+ }
+ }
+ }
+ }
+
+ // returns the actual bitrate since last call. returns -1 if no
+ // additional data to offer since last call (or at beginning of stream)
+ public int bitrate_instant(){
+ int _link=(seekable?current_link:0);
+ if(samptrack==0)return(-1);
+ int ret=(int)(bittrack/samptrack*vi[_link].rate+.5);
+ bittrack=0.f;
+ samptrack=0.f;
+ return(ret);
+ }
+
+ public int serialnumber(int i){
+ if(i>=links)return(-1);
+ if(!seekable && i>=0)return(serialnumber(-1));
+ if(i<0){
+ return(current_serialno);
+ }
+ else{
+ return(serialnos[i]);
+ }
+ }
+
+ // returns: total raw (compressed) length of content if i==-1
+ // raw (compressed) length of that logical bitstream for i==0 to n
+ // -1 if the stream is not seekable (we can't know the length)
+
+ public long raw_total(int i){
+System.out.println("raw_total: "+seekable);
+ if(!seekable || i>=links)return(-1);
+ if(i<0){
+ long acc=0; // bug?
+ for(int j=0;j<links;j++){
+ acc+=raw_total(j);
+ }
+ return(acc);
+ }
+ else{
+ return(offsets[i+1]-offsets[i]);
+ }
+ }
+
+ // returns: total PCM length (samples) of content if i==-1
+ // PCM length (samples) of that logical bitstream for i==0 to n
+ // -1 if the stream is not seekable (we can't know the length)
+ public long pcm_total(int i){
+ if(!seekable || i>=links)return(-1);
+ if(i<0){
+ long acc=0;
+ for(int j=0;j<links;j++){
+ acc+=pcm_total(j);
+ }
+ return(acc);
+ }
+ else{
+ return(pcmlengths[i]);
+ }
+ }
+
+ // returns: total seconds of content if i==-1
+ // seconds in that logical bitstream for i==0 to n
+ // -1 if the stream is not seekable (we can't know the length)
+ public float time_total(int i){
+ if(!seekable || i>=links)return(-1);
+ if(i<0){
+ float acc=0;
+ for(int j=0;j<links;j++){
+ acc+=time_total(j);
+ }
+ return(acc);
+ }
+ else{
+ return((float)(pcmlengths[i])/vi[i].rate);
+ }
+ }
+
+ // seek to an offset relative to the *compressed* data. This also
+ // immediately sucks in and decodes pages to update the PCM cursor. It
+ // will cross a logical bitstream boundary, but only if it can't get
+ // any packets out of the tail of the bitstream we seek to (so no
+ // surprises).
+ //
+ // returns zero on success, nonzero on failure
+
+ public int raw_seek(int pos){
+System.out.println("raw_seek: "+pos);
+ if(!seekable)return(-1); // don't dump machine if we can't seek
+ if(pos<0 || pos>offsets[links]){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+System.out.println("#1");
+ // clear out decoding machine state
+ pcm_offset=-1;
+System.out.println("#2");
+ decode_clear();
+System.out.println("#3");
+ // seek
+ seek_helper(pos);
+
+ // we need to make sure the pcm_offset is set. We use the
+ // _fetch_packet helper to process one packet with readp set, then
+ // call it until it returns '0' with readp not set (the last packet
+ // from a page has the 'granulepos' field set, and that's how the
+ // helper updates the offset
+System.out.println("#4");
+ switch(process_packet(1)){
+ case 0:
+System.out.println("?0");
+ // oh, eof. There are no packets remaining. Set the pcm offset to
+ // the end of file
+ pcm_offset=pcm_total(-1);
+ return(0);
+ case -1:
+System.out.println("?-1");
+ // error! missing data or invalid bitstream structure
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ default:
+System.out.println("?break");
+ // all OK
+ break;
+ }
+System.out.println("pcm_offset="+pcm_offset);
+ while(true){
+ switch(process_packet(0)){
+ case 0:
+ // the offset is set. If it's a bogus bitstream with no offset
+ // information, it's not but that's not our fault. We still run
+ // gracefully, we're just missing the offset
+ return(0);
+ case -1:
+ // error! missing data or invalid bitstream structure
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ default:
+ // continue processing packets
+ break;
+ }
+ }
+
+ // seek_error:
+ // dump the machine so we're in a known state
+ //pcm_offset=-1;
+ //decode_clear();
+ //return -1;
+ }
+
+ // seek to a sample offset relative to the decompressed pcm stream
+ // returns zero on success, nonzero on failure
+
+ public int pcm_seek(long pos){
+ int link=-1;
+ long total=pcm_total(-1);
+
+ if(!seekable)return(-1); // don't dump machine if we can't seek
+ if(pos<0 || pos>total){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+
+ // which bitstream section does this pcm offset occur in?
+ for(link=links-1;link>=0;link--){
+ total-=pcmlengths[link];
+ if(pos>=total)break;
+ }
+
+ // search within the logical bitstream for the page with the highest
+ // pcm_pos preceeding (or equal to) pos. There is a danger here;
+ // missing pages or incorrect frame number information in the
+ // bitstream could make our task impossible. Account for that (it
+ // would be an error condition)
+ {
+ long target=pos-total;
+ int end=(int)offsets[link+1];
+ int begin=(int)offsets[link];
+ int best=begin;
+
+ Page og=new Page();
+ while(begin<end){
+ int bisect;
+ int ret;
+
+ if(end-begin<CHUNKSIZE){
+ bisect=begin;
+ }
+ else{
+ bisect=(end+begin)/2;
+ }
+
+ seek_helper(bisect);
+ ret=get_next_page(og,end-bisect);
+
+ if(ret==-1){
+ end=bisect;
+ }
+ else{
+ long granulepos=og.granulepos();
+ if(granulepos<target){
+ best=ret; // raw offset of packet with granulepos
+ begin=(int)offset; // raw offset of next packet
+ }
+ else{
+ end=bisect;
+ }
+ }
+ }
+ // found our page. seek to it (call raw_seek).
+ if(raw_seek(best)!=0){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+ }
+
+ // verify result
+ if(pcm_offset>=pos){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+ if(pos>pcm_total(-1)){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+
+ // discard samples until we reach the desired position. Crossing a
+ // logical bitstream boundary with abandon is OK.
+ while(pcm_offset<pos){
+ float[][] pcm;
+ int target=(int)(pos-pcm_offset);
+ float[][][] _pcm=new float[1][][];
+ int[] _index=new int[info(-1).channels];
+ int samples=vd.synthesis_pcmout(_pcm, _index);
+ pcm=_pcm[0];
+
+ if(samples>target)samples=target;
+ vd.synthesis_read(samples);
+ pcm_offset+=samples;
+
+ if(samples<target)
+ if(process_packet(1)==0){
+ pcm_offset=pcm_total(-1); // eof
+ }
+ }
+ return 0;
+
+ // seek_error:
+ // dump machine so we're in a known state
+ //pcm_offset=-1;
+ //decode_clear();
+ //return -1;
+ }
+
+ // seek to a playback time relative to the decompressed pcm stream
+ // returns zero on success, nonzero on failure
+ public int time_seek(float seconds){
+ // translate time to PCM position and call pcm_seek
+
+ int link=-1;
+ long pcm_total=pcm_total(-1);
+ float time_total=time_total(-1);
+
+ if(!seekable)return(-1); // don't dump machine if we can't seek
+ if(seconds<0 || seconds>time_total){
+ //goto seek_error;
+ pcm_offset=-1;
+ decode_clear();
+ return -1;
+ }
+
+ // which bitstream section does this time offset occur in?
+ for(link=links-1;link>=0;link--){
+ pcm_total-=pcmlengths[link];
+ time_total-=time_total(link);
+ if(seconds>=time_total)break;
+ }
+
+ // enough information to convert time offset to pcm offset
+ {
+ long target=(long)(pcm_total+(seconds-time_total)*vi[link].rate);
+ return(pcm_seek(target));
+ }
+
+ //seek_error:
+ // dump machine so we're in a known state
+ //pcm_offset=-1;
+ //decode_clear();
+ //return -1;
+ }
+
+ // tell the current stream offset cursor. Note that seek followed by
+ // tell will likely not give the set offset due to caching
+ public long raw_tell(){
+ return(offset);
+ }
+
+ // return PCM offset (sample) of next PCM sample to be read
+ public long pcm_tell(){
+ return(pcm_offset);
+ }
+
+ // return time offset (seconds) of next PCM sample to be read
+ public float time_tell(){
+ // translate time to PCM position and call pcm_seek
+
+ int link=-1;
+ long pcm_total=0;
+ float time_total=0.f;
+
+ if(seekable){
+ pcm_total=pcm_total(-1);
+ time_total=time_total(-1);
+
+ // which bitstream section does this time offset occur in?
+ for(link=links-1;link>=0;link--){
+ pcm_total-=pcmlengths[link];
+ time_total-=time_total(link);
+ if(pcm_offset>=pcm_total)break;
+ }
+ }
+
+ return((float)time_total+(float)(pcm_offset-pcm_total)/vi[link].rate);
+ }
+
+ // link: -1) return the vorbis_info struct for the bitstream section
+ // currently being decoded
+ // 0-n) to request information for a specific bitstream section
+ //
+ // In the case of a non-seekable bitstream, any call returns the
+ // current bitstream. NULL in the case that the machine is not
+ // initialized
+
+ public Info info(int link){
+ if(seekable){
+ if(link<0){
+ if(decode_ready){
+ return vi[current_link];
+ }
+ else{
+ return null;
+ }
+ }
+ else{
+ if(link>=links){
+ return null;
+ }
+ else{
+ return vi[link];
+ }
+ }
+ }
+ else{
+ if(decode_ready){
+ return vi[0];
+ }
+ else{
+ return null;
+ }
+ }
+ }
+
+ public Comment comment(int link){
+ if(seekable){
+ if(link<0){
+ if(decode_ready){ return vc[current_link]; }
+ else{ return null; }
+ }
+ else{
+ if(link>=links){ return null;}
+ else{ return vc[link]; }
+ }
+ }
+ else{
+ if(decode_ready){ return vc[0]; }
+ else{ return null; }
+ }
+ }
+
+ int host_is_big_endian() {
+ return 1;
+// short pattern = 0xbabe;
+// unsigned char *bytewise = (unsigned char *)&pattern;
+// if (bytewise[0] == 0xba) return 1;
+// assert(bytewise[0] == 0xbe);
+// return 0;
+ }
+
+ // up to this point, everything could more or less hide the multiple
+ // logical bitstream nature of chaining from the toplevel application
+ // if the toplevel application didn't particularly care. However, at
+ // the point that we actually read audio back, the multiple-section
+ // nature must surface: Multiple bitstream sections do not necessarily
+ // have to have the same number of channels or sampling rate.
+ //
+ // read returns the sequential logical bitstream number currently
+ // being decoded along with the PCM data in order that the toplevel
+ // application can take action on channel/sample rate changes. This
+ // number will be incremented even for streamed (non-seekable) streams
+ // (for seekable streams, it represents the actual logical bitstream
+ // index within the physical bitstream. Note that the accessor
+ // functions above are aware of this dichotomy).
+ //
+ // input values: buffer) a buffer to hold packed PCM data for return
+ // length) the byte length requested to be placed into buffer
+ // bigendianp) should the data be packed LSB first (0) or
+ // MSB first (1)
+ // word) word size for output. currently 1 (byte) or
+ // 2 (16 bit short)
+ //
+ // return values: -1) error/hole in data
+ // 0) EOF
+ // n) number of bytes of PCM actually returned. The
+ // below works on a packet-by-packet basis, so the
+ // return length is not related to the 'length' passed
+ // in, just guaranteed to fit.
+ //
+ // *section) set to the logical bitstream number
+
+ int read(byte[] buffer,int length,
+ int bigendianp, int word, int sgned, int[] bitstream){
+ int host_endian = host_is_big_endian();
+ int index=0;
+
+ while(true){
+ if(decode_ready){
+ float[][] pcm;
+ float[][][] _pcm=new float[1][][];
+ int[] _index=new int[info(-1).channels];
+ int samples=vd.synthesis_pcmout(_pcm, _index);
+ pcm=_pcm[0];
+ if(samples!=0){
+ // yay! proceed to pack data into the byte buffer
+ int channels=info(-1).channels;
+ int bytespersample=word * channels;
+ if(samples>length/bytespersample)samples=length/bytespersample;
+
+ // a tight loop to pack each size
+ {
+ int val;
+ if(word==1){
+ int off=(sgned!=0?0:128);
+ for(int j=0;j<samples;j++){
+ for(int i=0;i<channels;i++){
+ val=(int)(pcm[i][_index[i]+j]*128. + 0.5);
+ if(val>127)val=127;
+ else if(val<-128)val=-128;
+ buffer[index++]=(byte)(val+off);
+ }
+ }
+ }
+ else{
+ int off=(sgned!=0?0:32768);
+
+ if(host_endian==bigendianp){
+ if(sgned!=0){
+ for(int i=0;i<channels;i++) { // It's faster in this order
+ int src=_index[i];
+ int dest=i;
+ for(int j=0;j<samples;j++) {
+ val=(int)(pcm[i][src+j]*32768. + 0.5);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ buffer[dest]=(byte)(val>>>8);
+ buffer[dest+1]=(byte)(val);
+ dest+=channels*2;
+ }
+ }
+ }
+ else{
+ for(int i=0;i<channels;i++) {
+ float[] src=pcm[i];
+ int dest=i;
+ for(int j=0;j<samples;j++) {
+ val=(int)(src[j]*32768. + 0.5);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ buffer[dest]=(byte)((val+off)>>>8);
+ buffer[dest+1]=(byte)(val+off);
+ dest+=channels*2;
+ }
+ }
+ }
+ }
+ else if(bigendianp!=0){
+ for(int j=0;j<samples;j++){
+ for(int i=0;i<channels;i++){
+ val=(int)(pcm[i][j]*32768. + 0.5);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ val+=off;
+ buffer[index++]=(byte)(val>>>8);
+ buffer[index++]=(byte)val;
+ }
+ }
+ }
+ else{
+ //int val;
+ for(int j=0;j<samples;j++){
+ for(int i=0;i<channels;i++){
+ val=(int)(pcm[i][j]*32768. + 0.5);
+ if(val>32767)val=32767;
+ else if(val<-32768)val=-32768;
+ val+=off;
+ buffer[index++]=(byte)val;
+ buffer[index++]=(byte)(val>>>8);
+ }
+ }
+ }
+ }
+ }
+
+ vd.synthesis_read(samples);
+ pcm_offset+=samples;
+ if(bitstream!=null)bitstream[0]=current_link;
+ return(samples*bytespersample);
+ }
+ }
+
+ // suck in another packet
+ switch(process_packet(1)){
+ case 0:
+ return(0);
+ case -1:
+ return -1;
+ default:
+ break;
+ }
+ }
+ }
+
+ public int getLinks(){return links;}
+ public Info[] getInfo(){return vi;}
+ public Comment[] getComment(){return vc;}
+
+ public static void main(String[] arg){
+ try{
+ VorbisFile foo=new VorbisFile(arg[0]);
+ int links=foo.getLinks();
+ System.out.println("links="+links);
+ Comment[] comment=foo.getComment();
+ Info[] info=foo.getInfo();
+ for(int i=0; i<links; i++){
+ System.out.println(info[i]);
+ System.out.println(comment[i]);
+ }
+ System.out.println("raw_total: "+foo.raw_total(-1));
+ System.out.println("pcm_total: "+foo.pcm_total(-1));
+ System.out.println("time_total: "+foo.time_total(-1));
+ }
+ catch(Exception e){
+ System.err.println(e);
+ }
+ }
+}
diff --git a/songdbj/de/jarnbjo/ogg/BasicStream.java b/songdbj/de/jarnbjo/ogg/BasicStream.java
new file mode 100644
index 0000000000..9939524d6c
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/BasicStream.java
@@ -0,0 +1,121 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.3 2004/09/21 12:09:45 shred
+ * *** empty log message ***
+ *
+ * Revision 1.2 2004/09/21 06:38:45 shred
+ * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ *
+ */
+
+package de.jarnbjo.ogg;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+
+/**
+ * Implementation of the <code>PhysicalOggStream</code> interface for reading
+ * an Ogg stream from a URL. This class performs
+ * no internal caching, and will not read data from the network before
+ * requested to do so. It is intended to be used in non-realtime applications
+ * like file download managers or similar.
+ */
+
+public class BasicStream implements PhysicalOggStream {
+
+ private boolean closed=false;
+ private InputStream sourceStream;
+ private Object drainLock=new Object();
+ private LinkedList pageCache=new LinkedList();
+ private long numberOfSamples=-1;
+ private int position=0;
+
+ private HashMap logicalStreams=new HashMap();
+ private OggPage firstPage;
+
+ public BasicStream(InputStream sourceStream) throws OggFormatException, IOException {
+ firstPage=OggPage.create(sourceStream);
+ position+=firstPage.getTotalLength();
+ LogicalOggStreamImpl los=new LogicalOggStreamImpl(this, firstPage.getStreamSerialNumber());
+ logicalStreams.put(new Integer(firstPage.getStreamSerialNumber()), los);
+ los.checkFormat(firstPage);
+ }
+
+ public Collection getLogicalStreams() {
+ return logicalStreams.values();
+ }
+
+ public boolean isOpen() {
+ return !closed;
+ }
+
+ public void close() throws IOException {
+ closed=true;
+ sourceStream.close();
+ }
+
+ public int getContentLength() {
+ return -1;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ int pageNumber=2;
+
+ public OggPage getOggPage(int index) throws IOException {
+ if(firstPage!=null) {
+ OggPage tmp=firstPage;
+ firstPage=null;
+ return tmp;
+ }
+ else {
+ OggPage page=OggPage.create(sourceStream);
+ position+=page.getTotalLength();
+ return page;
+ }
+ }
+
+ private LogicalOggStream getLogicalStream(int serialNumber) {
+ return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
+ }
+
+ public void setTime(long granulePosition) throws IOException {
+ throw new UnsupportedOperationException("Method not supported by this class");
+ }
+
+ /**
+ * @return always <code>false</code>
+ */
+
+ public boolean isSeekable() {
+ return false;
+ }
+
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/ogg/CachedUrlStream.java b/songdbj/de/jarnbjo/ogg/CachedUrlStream.java
new file mode 100644
index 0000000000..86f792e272
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/CachedUrlStream.java
@@ -0,0 +1,252 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.1 2003/04/10 19:48:22 jarnbjo
+ * no message
+ *
+ *
+ */
+
+package de.jarnbjo.ogg;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * Implementation of the <code>PhysicalOggStream</code> interface for reading
+ * and caching an Ogg stream from a URL. This class reads the data as fast as
+ * possible from the URL, caches it locally either in memory or on disk, and
+ * supports seeking within the available data.
+ */
+
+public class CachedUrlStream implements PhysicalOggStream {
+
+ private boolean closed=false;
+ private URLConnection source;
+ private InputStream sourceStream;
+ private Object drainLock=new Object();
+ private RandomAccessFile drain;
+ private byte[] memoryCache;
+ private ArrayList pageOffsets=new ArrayList();
+ private ArrayList pageLengths=new ArrayList();
+ private long numberOfSamples=-1;
+ private long cacheLength;
+
+ private HashMap logicalStreams=new HashMap();
+
+ private LoaderThread loaderThread;
+
+ /**
+ * Creates an instance of this class, using a memory cache.
+ */
+
+ public CachedUrlStream(URL source) throws OggFormatException, IOException {
+ this(source, null);
+ }
+
+ /**
+ * Creates an instance of this class, using the specified file as cache. The
+ * file is not automatically deleted when this class is disposed.
+ */
+
+ public CachedUrlStream(URL source, RandomAccessFile drain) throws OggFormatException, IOException {
+
+ this.source=source.openConnection();
+
+ if(drain==null) {
+ int contentLength=this.source.getContentLength();
+ if(contentLength==-1) {
+ throw new IOException("The URLConncetion's content length must be set when operating with a in-memory cache.");
+ }
+ memoryCache=new byte[contentLength];
+ }
+
+ this.drain=drain;
+ this.sourceStream=this.source.getInputStream();
+
+ loaderThread=new LoaderThread(sourceStream, drain, memoryCache);
+ new Thread(loaderThread).start();
+
+ while(!loaderThread.isBosDone() || pageOffsets.size()<20) {
+ System.out.print("pageOffsets.size(): "+pageOffsets.size()+"\r");
+ try {
+ Thread.sleep(200);
+ }
+ catch (InterruptedException ex) {
+ }
+ }
+ System.out.println();
+ System.out.println("caching "+pageOffsets.size()+"/20 pages\r");
+ }
+
+ public Collection getLogicalStreams() {
+ return logicalStreams.values();
+ }
+
+ public boolean isOpen() {
+ return !closed;
+ }
+
+ public void close() throws IOException {
+ closed=true;
+ sourceStream.close();
+ }
+
+ public long getCacheLength() {
+ return cacheLength;
+ }
+
+ /*
+ private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
+ return getNextPage(false);
+ }
+
+ private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
+ return OggPage.create(sourceStream, skipData);
+ }
+ */
+
+ public OggPage getOggPage(int index) throws IOException {
+ synchronized(drainLock) {
+ Long offset=(Long)pageOffsets.get(index);
+ Long length=(Long)pageLengths.get(index);
+ if(offset!=null) {
+ if(drain!=null) {
+ drain.seek(offset.longValue());
+ return OggPage.create(drain);
+ }
+ else {
+ byte[] tmpArray=new byte[length.intValue()];
+ System.arraycopy(memoryCache, offset.intValue(), tmpArray, 0, length.intValue());
+ return OggPage.create(tmpArray);
+ }
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ private LogicalOggStream getLogicalStream(int serialNumber) {
+ return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
+ }
+
+ public void setTime(long granulePosition) throws IOException {
+ for(Iterator iter=logicalStreams.values().iterator(); iter.hasNext(); ) {
+ LogicalOggStream los=(LogicalOggStream)iter.next();
+ los.setTime(granulePosition);
+ }
+ }
+
+ public class LoaderThread implements Runnable {
+
+ private InputStream source;
+ private RandomAccessFile drain;
+ private byte[] memoryCache;
+
+ private boolean bosDone=false;
+
+ private int pageNumber;
+
+ public LoaderThread(InputStream source, RandomAccessFile drain, byte[] memoryCache) {
+ this.source=source;
+ this.drain=drain;
+ this.memoryCache=memoryCache;
+ }
+
+ public void run() {
+ try {
+ boolean eos=false;
+ byte[] buffer=new byte[8192];
+ while(!eos) {
+ OggPage op=OggPage.create(source);
+ synchronized (drainLock) {
+ int listSize=pageOffsets.size();
+
+ long pos=
+ listSize>0?
+ ((Long)pageOffsets.get(listSize-1)).longValue()+
+ ((Long)pageLengths.get(listSize-1)).longValue():
+ 0;
+
+ byte[] arr1=op.getHeader();
+ byte[] arr2=op.getSegmentTable();
+ byte[] arr3=op.getData();
+
+ if(drain!=null) {
+ drain.seek(pos);
+ drain.write(arr1);
+ drain.write(arr2);
+ drain.write(arr3);
+ }
+ else {
+ System.arraycopy(arr1, 0, memoryCache, (int)pos, arr1.length);
+ System.arraycopy(arr2, 0, memoryCache, (int)pos+arr1.length, arr2.length);
+ System.arraycopy(arr3, 0, memoryCache, (int)pos+arr1.length+arr2.length, arr3.length);
+ }
+
+ pageOffsets.add(new Long(pos));
+ pageLengths.add(new Long(arr1.length+arr2.length+arr3.length));
+ }
+
+ if(!op.isBos()) {
+ bosDone=true;
+ //System.out.println("bosDone=true;");
+ }
+ if(op.isEos()) {
+ eos=true;
+ }
+
+ LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
+ if(los==null) {
+ los=new LogicalOggStreamImpl(CachedUrlStream.this, op.getStreamSerialNumber());
+ logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
+ los.checkFormat(op);
+ }
+
+ los.addPageNumberMapping(pageNumber);
+ los.addGranulePosition(op.getAbsoluteGranulePosition());
+
+ pageNumber++;
+ cacheLength=op.getAbsoluteGranulePosition();
+ //System.out.println("read page: "+pageNumber);
+ }
+ }
+ catch(EndOfOggStreamException e) {
+ // ok
+ }
+ catch(IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public boolean isBosDone() {
+ return bosDone;
+ }
+ }
+
+ public boolean isSeekable() {
+ return true;
+ }
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/ogg/EndOfOggStreamException.java b/songdbj/de/jarnbjo/ogg/EndOfOggStreamException.java
new file mode 100644
index 0000000000..4a0c3200f4
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/EndOfOggStreamException.java
@@ -0,0 +1,45 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.2 2005/02/09 23:10:47 shred
+ * Serial UID für jarnbjo
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.1 2003/03/03 21:02:20 jarnbjo
+ * no message
+ *
+ */
+
+ package de.jarnbjo.ogg;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown when reaching the end of an Ogg stream
+ */
+
+public class EndOfOggStreamException extends IOException {
+ private static final long serialVersionUID = 3907210438109444408L;
+
+ public EndOfOggStreamException() {
+ }
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/ogg/FileStream.java b/songdbj/de/jarnbjo/ogg/FileStream.java
new file mode 100644
index 0000000000..5a526300bf
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/FileStream.java
@@ -0,0 +1,154 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.1 2003/04/10 19:48:22 jarnbjo
+ * no message
+ *
+ *
+ */
+
+package de.jarnbjo.ogg;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Implementation of the <code>PhysicalOggStream</code> interface for accessing
+ * normal disk files.
+ */
+
+public class FileStream implements PhysicalOggStream {
+
+ private boolean closed=false;
+ private RandomAccessFile source;
+ private long[] pageOffsets;
+ private long numberOfSamples=-1;
+
+ private HashMap logicalStreams=new HashMap();
+
+ /**
+ * Creates access to the specified file through the <code>PhysicalOggStream</code> interface.
+ * The specified source file must have been opened for reading.
+ *
+ * @param source the file to read from
+ *
+ * @throws OggFormatException if the stream format is incorrect
+ * @throws IOException if some other IO error occurs when reading the file
+ */
+
+ public FileStream(RandomAccessFile source) throws OggFormatException, IOException {
+ this.source=source;
+
+ ArrayList po=new ArrayList();
+ int pageNumber=0;
+ try {
+ while(true) {
+ po.add(new Long(this.source.getFilePointer()));
+
+ // skip data if pageNumber>0
+ OggPage op=getNextPage(pageNumber>0);
+ if(op==null) {
+ break;
+ }
+
+ LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
+ if(los==null) {
+ los=new LogicalOggStreamImpl(this, op.getStreamSerialNumber());
+ logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
+ }
+
+ if(pageNumber==0) {
+ los.checkFormat(op);
+ }
+
+ los.addPageNumberMapping(pageNumber);
+ los.addGranulePosition(op.getAbsoluteGranulePosition());
+
+ if(pageNumber>0) {
+ this.source.seek(this.source.getFilePointer()+op.getTotalLength());
+ }
+
+ pageNumber++;
+ }
+ }
+ catch(EndOfOggStreamException e) {
+ // ok
+ }
+ catch(IOException e) {
+ throw e;
+ }
+ //System.out.println("pageNumber: "+pageNumber);
+ this.source.seek(0L);
+ pageOffsets=new long[po.size()];
+ int i=0;
+ Iterator iter=po.iterator();
+ while(iter.hasNext()) {
+ pageOffsets[i++]=((Long)iter.next()).longValue();
+ }
+ }
+
+ public Collection getLogicalStreams() {
+ return logicalStreams.values();
+ }
+
+ public boolean isOpen() {
+ return !closed;
+ }
+
+ public void close() throws IOException {
+ closed=true;
+ source.close();
+ }
+
+ private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
+ return getNextPage(false);
+ }
+
+ private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
+ return OggPage.create(source, skipData);
+ }
+
+ public OggPage getOggPage(int index) throws IOException {
+ source.seek(pageOffsets[index]);
+ return OggPage.create(source);
+ }
+
+ private LogicalOggStream getLogicalStream(int serialNumber) {
+ return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
+ }
+
+ public void setTime(long granulePosition) throws IOException {
+ for(Iterator iter=logicalStreams.values().iterator(); iter.hasNext(); ) {
+ LogicalOggStream los=(LogicalOggStream)iter.next();
+ los.setTime(granulePosition);
+ }
+ }
+
+ /**
+ * @return always <code>true</code>
+ */
+
+ public boolean isSeekable() {
+ return true;
+ }
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/ogg/LogicalOggStream.java b/songdbj/de/jarnbjo/ogg/LogicalOggStream.java
new file mode 100644
index 0000000000..2f97b2a728
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/LogicalOggStream.java
@@ -0,0 +1,151 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.2 2003/04/10 19:48:22 jarnbjo
+ * no message
+ *
+ * Revision 1.1 2003/03/03 21:02:20 jarnbjo
+ * no message
+ *
+ */
+
+package de.jarnbjo.ogg;
+
+import java.io.IOException;
+
+/**
+ * Interface providing access to a logical Ogg stream as part of a
+ * physical Ogg stream.
+ */
+
+
+public interface LogicalOggStream {
+
+ public static final String FORMAT_UNKNOWN = "application/octet-stream";
+
+ public static final String FORMAT_VORBIS = "audio/x-vorbis";
+ public static final String FORMAT_FLAC = "audio/x-flac";
+ public static final String FORMAT_THEORA = "video/x-theora";
+
+ /**
+ * <i>Note:</i> To read from the stream, you must use either
+ * this method or the method <code>getNextOggPacket</code>.
+ * Mixing calls to the two methods will cause data corruption.
+ *
+ * @return the next Ogg page
+ *
+ * @see #getNextOggPacket()
+ *
+ * @throws OggFormatException if the ogg stream is corrupted
+ * @throws IOException if some other IO error occurs
+ */
+
+ public OggPage getNextOggPage() throws OggFormatException, IOException;
+
+ /**
+ * <i>Note:</i> To read from the stream, you must use either
+ * this method or the method <code>getNextOggPage</code>.
+ * Mixing calls to the two methods will cause data corruption.
+ *
+ * @return the next packet as a byte array
+ *
+ * @see #getNextOggPage()
+ *
+ * @throws OggFormatException if the ogg stream is corrupted
+ * @throws IOException if some other IO error occurs
+ */
+
+ public byte[] getNextOggPacket() throws OggFormatException, IOException;
+
+ /**
+ * Checks if this stream is open for reading.
+ *
+ * @return <code>true</code> if this stream is open for reading,
+ * <code>false</code> otherwise
+ */
+
+ public boolean isOpen();
+
+ /**
+ * Closes this stream. After invoking this method, no further access
+ * to the streams data is possible.
+ *
+ * @throws IOException if an IO error occurs
+ */
+
+ public void close() throws IOException;
+
+ /**
+ * Sets the stream's position to the beginning of the stream.
+ * This method does not work if the physical Ogg stream is not
+ * seekable.
+ *
+ * @throws OggFormatException if the ogg stream is corrupted
+ * @throws IOException if some other IO error occurs
+ */
+
+ public void reset() throws OggFormatException, IOException;
+
+ /**
+ * This method does not work if the physical Ogg stream is not
+ * seekable.
+ *
+ * @return the granule position of the last page within
+ * this stream
+ */
+
+ public long getMaximumGranulePosition();
+
+ /**
+ * This method is invoked on all logical streams when
+ * calling the same method on the physical stream. The
+ * same restrictions as mentioned there apply.
+ * This method does not work if the physical Ogg stream is not
+ * seekable.
+ *
+ * @param granulePosition
+ *
+ * @see PhysicalOggStream#setTime(long)
+ *
+ * @throws IOException if an IO error occurs
+ */
+
+ public void setTime(long granulePosition) throws IOException;
+
+ /**
+ * @return the last parsed granule position of this stream
+ */
+
+ public long getTime();
+
+ /**
+ * @return the content type of this stream
+ *
+ * @see #FORMAT_UNKNOWN
+ * @see #FORMAT_VORBIS
+ * @see #FORMAT_FLAC
+ * @see #FORMAT_THEORA
+ */
+
+ public String getFormat();
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/ogg/LogicalOggStreamImpl.java b/songdbj/de/jarnbjo/ogg/LogicalOggStreamImpl.java
new file mode 100644
index 0000000000..1a503e91ca
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/LogicalOggStreamImpl.java
@@ -0,0 +1,213 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.3 2003/03/31 00:23:04 jarnbjo
+ * no message
+ *
+ * Revision 1.2 2003/03/16 01:11:26 jarnbjo
+ * no message
+ *
+ * Revision 1.1 2003/03/03 21:02:20 jarnbjo
+ * no message
+ *
+ */
+
+package de.jarnbjo.ogg;
+
+import java.io.*;
+import java.util.*;
+
+public class LogicalOggStreamImpl implements LogicalOggStream {
+
+ private PhysicalOggStream source;
+ private int serialNumber;
+
+ private ArrayList pageNumberMapping=new ArrayList();
+ private ArrayList granulePositions=new ArrayList();
+
+ private int pageIndex=0;
+ private OggPage currentPage;
+ private int currentSegmentIndex;
+
+ private boolean open=true;
+
+ private String format=FORMAT_UNKNOWN;
+
+ public LogicalOggStreamImpl(PhysicalOggStream source, int serialNumber) {
+ this.source=source;
+ this.serialNumber=serialNumber;
+ }
+
+ public void addPageNumberMapping(int physicalPageNumber) {
+ pageNumberMapping.add(new Integer(physicalPageNumber));
+ }
+
+ public void addGranulePosition(long granulePosition) {
+ granulePositions.add(new Long(granulePosition));
+ }
+
+ public synchronized void reset() throws OggFormatException, IOException {
+ currentPage=null;
+ currentSegmentIndex=0;
+ pageIndex=0;
+ }
+
+ public synchronized OggPage getNextOggPage() throws EndOfOggStreamException, OggFormatException, IOException {
+ if(source.isSeekable()) {
+ currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
+ }
+ else {
+ currentPage=source.getOggPage(-1);
+ }
+ return currentPage;
+ }
+
+ public synchronized byte[] getNextOggPacket() throws EndOfOggStreamException, OggFormatException, IOException {
+ ByteArrayOutputStream res=new ByteArrayOutputStream();
+ int segmentLength=0;
+
+ if(currentPage==null) {
+ currentPage=getNextOggPage();
+ }
+
+ do {
+ if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) {
+ currentSegmentIndex=0;
+
+ if(!currentPage.isEos()) {
+ if(source.isSeekable() && pageNumberMapping.size()<=pageIndex) {
+ while(pageNumberMapping.size()<=pageIndex+10) {
+ try {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException ex) {
+ }
+ }
+ }
+ currentPage=getNextOggPage();
+
+ if(res.size()==0 && currentPage.isContinued()) {
+ boolean done=false;
+ while(!done) {
+ if(currentPage.getSegmentLengths()[currentSegmentIndex++]!=255) {
+ done=true;
+ }
+ if(currentSegmentIndex>currentPage.getSegmentTable().length) {
+ currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
+ }
+ }
+ }
+ }
+ else {
+ throw new EndOfOggStreamException();
+ }
+ }
+ segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex];
+ res.write(currentPage.getData(), currentPage.getSegmentOffsets()[currentSegmentIndex], segmentLength);
+ currentSegmentIndex++;
+ } while(segmentLength==255);
+
+ return res.toByteArray();
+ }
+
+ public boolean isOpen() {
+ return open;
+ }
+
+ public void close() throws IOException {
+ open=false;
+ }
+
+ public long getMaximumGranulePosition() {
+ Long mgp=(Long)granulePositions.get(granulePositions.size()-1);
+ return mgp.longValue();
+ }
+
+ public synchronized long getTime() {
+ return currentPage!=null?currentPage.getAbsoluteGranulePosition():-1;
+ }
+
+ public synchronized void setTime(long granulePosition) throws IOException {
+
+ int page=0;
+ for(page=0; page<granulePositions.size(); page++) {
+ Long gp=(Long)granulePositions.get(page);
+ if(gp.longValue()>granulePosition) {
+ break;
+ }
+ }
+
+ pageIndex=page;
+ currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
+ currentSegmentIndex=0;
+ int segmentLength=0;
+ do {
+ if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) {
+ currentSegmentIndex=0;
+ if(pageIndex>=pageNumberMapping.size()) {
+ throw new EndOfOggStreamException();
+ }
+ currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
+ }
+ segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex];
+ currentSegmentIndex++;
+ } while(segmentLength==255);
+ }
+
+ public void checkFormat(OggPage page) {
+ byte[] data=page.getData();
+
+ if(data.length>=7 &&
+ data[1]==0x76 &&
+ data[2]==0x6f &&
+ data[3]==0x72 &&
+ data[4]==0x62 &&
+ data[5]==0x69 &&
+ data[6]==0x73) {
+
+ format=FORMAT_VORBIS;
+ }
+ else if(data.length>=7 &&
+ data[1]==0x74 &&
+ data[2]==0x68 &&
+ data[3]==0x65 &&
+ data[4]==0x6f &&
+ data[5]==0x72 &&
+ data[6]==0x61) {
+
+ format=FORMAT_THEORA;
+ }
+ else if (data.length==4 &&
+ data[0]==0x66 &&
+ data[1]==0x4c &&
+ data[2]==0x61 &&
+ data[3]==0x43) {
+
+ format=FORMAT_FLAC;
+ }
+ }
+
+ public String getFormat() {
+ return format;
+ }
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/ogg/OggFormatException.java b/songdbj/de/jarnbjo/ogg/OggFormatException.java
new file mode 100644
index 0000000000..a6b2466b92
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/OggFormatException.java
@@ -0,0 +1,50 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.2 2005/02/09 23:10:47 shred
+ * Serial UID für jarnbjo
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.1 2003/03/03 21:02:20 jarnbjo
+ * no message
+ *
+ */
+
+package de.jarnbjo.ogg;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown when trying to read a corrupted Ogg stream.
+ */
+
+public class OggFormatException extends IOException {
+ private static final long serialVersionUID = 3544953238333175349L;
+
+ public OggFormatException() {
+ super();
+ }
+
+ public OggFormatException(String message) {
+ super(message);
+ }
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/ogg/OggPage.java b/songdbj/de/jarnbjo/ogg/OggPage.java
new file mode 100644
index 0000000000..cc965cc7a9
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/OggPage.java
@@ -0,0 +1,431 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.3 2003/04/10 19:48:22 jarnbjo
+ * no message
+ *
+ * Revision 1.2 2003/03/31 00:23:04 jarnbjo
+ * no message
+ *
+ * Revision 1.1 2003/03/03 21:02:20 jarnbjo
+ * no message
+ *
+ */
+
+package de.jarnbjo.ogg;
+
+import java.io.*;
+
+import de.jarnbjo.util.io.*;
+
+/**
+ * <p>An instance of this class represents an ogg page read from an ogg file
+ * or network stream. It has no public constructor, but instances can be
+ * created by the <code>create</code> methods, supplying a JMF stream or
+ * a <code>RandomAccessFile</code>
+ * which is positioned at the beginning of an Ogg page.</p>
+ *
+ * <p>Furtheron, the class provides methods for accessing the raw page data,
+ * as well as data attributes like segmenting information, sequence number,
+ * stream serial number, chechsum and wether this page is the beginning or
+ * end of a logical bitstream (BOS, EOS) and if the page data starts with a
+ * continued packet or a fresh data packet.</p>
+ */
+
+public class OggPage {
+
+ private int version;
+ private boolean continued, bos, eos;
+ private long absoluteGranulePosition;
+ private int streamSerialNumber, pageSequenceNumber, pageCheckSum;
+ private int[] segmentOffsets;
+ private int[] segmentLengths;
+ private int totalLength;
+ private byte[] header, segmentTable, data;
+
+ protected OggPage() {
+ }
+
+ private OggPage(
+ int version,
+ boolean continued,
+ boolean bos,
+ boolean eos,
+ long absoluteGranulePosition,
+ int streamSerialNumber,
+ int pageSequenceNumber,
+ int pageCheckSum,
+ int[] segmentOffsets,
+ int[] segmentLengths,
+ int totalLength,
+ byte[] header,
+ byte[] segmentTable,
+ byte[] data) {
+
+ this.version=version;
+ this.continued=continued;
+ this.bos=bos;
+ this.eos=eos;
+ this.absoluteGranulePosition=absoluteGranulePosition;
+ this.streamSerialNumber=streamSerialNumber;
+ this.pageSequenceNumber=pageSequenceNumber;
+ this.pageCheckSum=pageCheckSum;
+ this.segmentOffsets=segmentOffsets;
+ this.segmentLengths=segmentLengths;
+ this.totalLength=totalLength;
+ this.header=header;
+ this.segmentTable=segmentTable;
+ this.data=data;
+ }
+
+ /**
+ * this method equals to create(RandomAccessFile source, false)
+ *
+ * @see #create(RandomAccessFile, boolean)
+ */
+
+ public static OggPage create(RandomAccessFile source) throws IOException, EndOfOggStreamException, OggFormatException {
+ return create(source, false);
+ }
+
+ /**
+ * This method is called to read data from the current position in the
+ * specified RandomAccessFile and create a new OggPage instance based on the data
+ * read. If the parameter <code>skipData</code> is set to <code>true</code>,
+ * the actual page segments (page data) is skipped and not read into
+ * memory. This mode is useful when scanning through an ogg file to build
+ * a seek table.
+ *
+ * @param source the source from which the ogg page is generated
+ * @param skipData if set to <code>true</code>, the actual page data is not read into memory
+ * @return an ogg page created by reading data from the specified source, starting at the current position
+ * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
+ * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
+ * @throws IOException if some other I/O error is detected when reading from the source
+ *
+ * @see #create(RandomAccessFile)
+ */
+
+ public static OggPage create(RandomAccessFile source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
+ return create((Object)source, skipData);
+ }
+
+ /**
+ * this method equals to create(InputStream source, false)
+ *
+ * @see #create(InputStream, boolean)
+ */
+
+ public static OggPage create(InputStream source) throws IOException, EndOfOggStreamException, OggFormatException {
+ return create(source, false);
+ }
+
+ /**
+ * This method is called to read data from the current position in the
+ * specified InpuStream and create a new OggPage instance based on the data
+ * read. If the parameter <code>skipData</code> is set to <code>true</code>,
+ * the actual page segments (page data) is skipped and not read into
+ * memory. This mode is useful when scanning through an ogg file to build
+ * a seek table.
+ *
+ * @param source the source from which the ogg page is generated
+ * @param skipData if set to <code>true</code>, the actual page data is not read into memory
+ * @return an ogg page created by reading data from the specified source, starting at the current position
+ * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
+ * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
+ * @throws IOException if some other I/O error is detected when reading from the source
+ *
+ * @see #create(InputStream)
+ */
+
+ public static OggPage create(InputStream source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
+ return create((Object)source, skipData);
+ }
+
+ /**
+ * this method equals to create(byte[] source, false)
+ *
+ * @see #create(byte[], boolean)
+ */
+
+ public static OggPage create(byte[] source) throws IOException, EndOfOggStreamException, OggFormatException {
+ return create(source, false);
+ }
+
+ /**
+ * This method is called to
+ * create a new OggPage instance based on the specified byte array.
+ *
+ * @param source the source from which the ogg page is generated
+ * @param skipData if set to <code>true</code>, the actual page data is not read into memory
+ * @return an ogg page created by reading data from the specified source, starting at the current position
+ * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
+ * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
+ * @throws IOException if some other I/O error is detected when reading from the source
+ *
+ * @see #create(byte[])
+ */
+
+ public static OggPage create(byte[] source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
+ return create((Object)source, skipData);
+ }
+
+ private static OggPage create(Object source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
+
+ try {
+ int sourceOffset=27;
+
+ byte[] header=new byte[27];
+ if(source instanceof RandomAccessFile) {
+ RandomAccessFile raf=(RandomAccessFile)source;
+ if(raf.getFilePointer()==raf.length()) {
+ return null;
+ }
+ raf.readFully(header);
+ }
+ else if(source instanceof InputStream) {
+ readFully((InputStream)source, header);
+ }
+ else if(source instanceof byte[]) {
+ System.arraycopy((byte[])source, 0, header, 0, 27);
+ }
+
+ BitInputStream bdSource=new ByteArrayBitInputStream(header);
+
+ int capture=bdSource.getInt(32);
+
+ if(capture!=0x5367674f) {
+ //throw new FormatException("Ogg page does not start with 'OggS' (0x4f676753)");
+
+ /*
+ ** This condition is IMHO an error, but older Ogg files often contain
+ ** pages with a different capture than OggS. I am not sure how to
+ ** manage these pages, but the decoder seems to work properly, if
+ ** the incorrect capture is simply ignored.
+ */
+
+ String cs=Integer.toHexString(capture);
+ while(cs.length()<8) {
+ cs="0"+cs;
+ }
+ cs=cs.substring(6, 8)+cs.substring(4, 6)+cs.substring(2, 4)+cs.substring(0, 2);
+ char c1=(char)(Integer.valueOf(cs.substring(0, 2), 16).intValue());
+ char c2=(char)(Integer.valueOf(cs.substring(2, 4), 16).intValue());
+ char c3=(char)(Integer.valueOf(cs.substring(4, 6), 16).intValue());
+ char c4=(char)(Integer.valueOf(cs.substring(6, 8), 16).intValue());
+ System.out.println("Ogg packet header is 0x"+cs+" ("+c1+c2+c3+c4+"), should be 0x4f676753 (OggS)");
+ }
+
+ int version=bdSource.getInt(8);
+ byte tmp=(byte)bdSource.getInt(8);
+ boolean bf1=(tmp&1)!=0;
+ boolean bos=(tmp&2)!=0;
+ boolean eos=(tmp&4)!=0;
+ long absoluteGranulePosition=bdSource.getLong(64);
+ int streamSerialNumber=bdSource.getInt(32);
+ int pageSequenceNumber=bdSource.getInt(32);
+ int pageCheckSum=bdSource.getInt(32);
+ int pageSegments=bdSource.getInt(8);
+
+ //System.out.println("OggPage: "+streamSerialNumber+" / "+absoluteGranulePosition+" / "+pageSequenceNumber);
+
+ int[] segmentOffsets=new int[pageSegments];
+ int[] segmentLengths=new int[pageSegments];
+ int totalLength=0;
+
+ byte[] segmentTable=new byte[pageSegments];
+ byte[] tmpBuf=new byte[1];
+
+ for(int i=0; i<pageSegments; i++) {
+ int l=0;
+ if(source instanceof RandomAccessFile) {
+ l=((int)((RandomAccessFile)source).readByte()&0xff);
+ }
+ else if(source instanceof InputStream) {
+ l=(int)((InputStream)source).read();
+ }
+ else if(source instanceof byte[]) {
+ l=(int)((byte[])source)[sourceOffset++];
+ l&=255;
+ }
+ segmentTable[i]=(byte)l;
+ segmentLengths[i]=l;
+ segmentOffsets[i]=totalLength;
+ totalLength+=l;
+ }
+
+ byte[] data=null;
+
+ if(!skipData) {
+
+ //System.out.println("createPage: "+absoluteGranulePosition*1000/44100);
+
+ data=new byte[totalLength];
+ //source.read(data, 0, totalLength);
+ if(source instanceof RandomAccessFile) {
+ ((RandomAccessFile)source).readFully(data);
+ }
+ else if(source instanceof InputStream) {
+ readFully((InputStream)source, data);
+ }
+ else if(source instanceof byte[]) {
+ System.arraycopy(source, sourceOffset, data, 0, totalLength);
+ }
+ }
+
+ return new OggPage(version, bf1, bos, eos, absoluteGranulePosition, streamSerialNumber, pageSequenceNumber, pageCheckSum, segmentOffsets, segmentLengths, totalLength, header, segmentTable, data);
+ }
+ catch(EOFException e) {
+ throw new EndOfOggStreamException();
+ }
+ }
+
+ private static void readFully(InputStream source, byte[] buffer) throws IOException {
+ int total=0;
+ while(total<buffer.length) {
+ int read=source.read(buffer, total, buffer.length-total);
+ if(read==-1) {
+ throw new EndOfOggStreamException();
+ }
+ total+=read;
+ }
+ }
+
+ /**
+ * Returns the absolute granule position of the last complete
+ * packet contained in this Ogg page, or -1 if the page contains a single
+ * packet, which is not completed on this page. For pages containing Vorbis
+ * data, this value is the sample index within the Vorbis stream. The Vorbis
+ * stream does not necessarily start with sample index 0.
+ *
+ * @return the absolute granule position of the last packet completed on
+ * this page
+ */
+
+
+ public long getAbsoluteGranulePosition() {
+ return absoluteGranulePosition;
+ }
+
+ /**
+ * Returns the stream serial number of this ogg page.
+ *
+ * @return this page's serial number
+ */
+
+ public int getStreamSerialNumber() {
+ return streamSerialNumber;
+ }
+
+ /**
+ * Return the sequnce number of this ogg page.
+ *
+ * @return this page's sequence number
+ */
+
+ public int getPageSequenceNumber() {
+ return pageSequenceNumber;
+ }
+
+ /**
+ * Return the check sum of this ogg page.
+ *
+ * @return this page's check sum
+ */
+
+ public int getPageCheckSum() {
+ return pageCheckSum;
+ }
+
+ /**
+ * @return the total number of bytes in the page data
+ */
+
+
+ public int getTotalLength() {
+ if(data!=null) {
+ return 27+segmentTable.length+data.length;
+ }
+ else {
+ return totalLength;
+ }
+ }
+
+ /**
+ * @return a ByteBuffer containing the page data
+ */
+
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public byte[] getHeader() {
+ return header;
+ }
+
+ public byte[] getSegmentTable() {
+ return segmentTable;
+ }
+
+ public int[] getSegmentOffsets() {
+ return segmentOffsets;
+ }
+
+ public int[] getSegmentLengths() {
+ return segmentLengths;
+ }
+
+ /**
+ * @return <code>true</code> if this page begins with a continued packet
+ */
+
+ public boolean isContinued() {
+ return continued;
+ }
+
+ /**
+ * @return <code>true</code> if this page begins with a fresh packet
+ */
+
+ public boolean isFresh() {
+ return !continued;
+ }
+
+ /**
+ * @return <code>true</code> if this page is the beginning of a logical stream
+ */
+
+ public boolean isBos() {
+ return bos;
+ }
+
+ /**
+ * @return <code>true</code> if this page is the end of a logical stream
+ */
+
+ public boolean isEos() {
+ return eos;
+ }
+
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/ogg/OnDemandUrlStream.java b/songdbj/de/jarnbjo/ogg/OnDemandUrlStream.java
new file mode 100644
index 0000000000..98159c4e7c
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/OnDemandUrlStream.java
@@ -0,0 +1,127 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.1 2003/04/10 19:48:22 jarnbjo
+ * no message
+ *
+ * Revision 1.1 2003/03/31 00:23:04 jarnbjo
+ * no message
+ *
+ */
+
+package de.jarnbjo.ogg;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * Implementation of the <code>PhysicalOggStream</code> interface for reading
+ * an Ogg stream from a URL. This class performs
+ * no internal caching, and will not read data from the network before
+ * requested to do so. It is intended to be used in non-realtime applications
+ * like file download managers or similar.
+ */
+
+public class OnDemandUrlStream implements PhysicalOggStream {
+
+ private boolean closed=false;
+ private URLConnection source;
+ private InputStream sourceStream;
+ private Object drainLock=new Object();
+ private LinkedList pageCache=new LinkedList();
+ private long numberOfSamples=-1;
+ private int contentLength=0;
+ private int position=0;
+
+ private HashMap logicalStreams=new HashMap();
+ private OggPage firstPage;
+
+ private static final int PAGECACHE_SIZE = 20;
+
+ public OnDemandUrlStream(URL source) throws OggFormatException, IOException {
+ this.source=source.openConnection();
+ this.sourceStream=this.source.getInputStream();
+
+ contentLength=this.source.getContentLength();
+
+ firstPage=OggPage.create(sourceStream);
+ position+=firstPage.getTotalLength();
+ LogicalOggStreamImpl los=new LogicalOggStreamImpl(this, firstPage.getStreamSerialNumber());
+ logicalStreams.put(new Integer(firstPage.getStreamSerialNumber()), los);
+ los.checkFormat(firstPage);
+ }
+
+ public Collection getLogicalStreams() {
+ return logicalStreams.values();
+ }
+
+ public boolean isOpen() {
+ return !closed;
+ }
+
+ public void close() throws IOException {
+ closed=true;
+ sourceStream.close();
+ }
+
+ public int getContentLength() {
+ return contentLength;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ int pageNumber=2;
+
+ public OggPage getOggPage(int index) throws IOException {
+ if(firstPage!=null) {
+ OggPage tmp=firstPage;
+ firstPage=null;
+ return tmp;
+ }
+ else {
+ OggPage page=OggPage.create(sourceStream);
+ position+=page.getTotalLength();
+ return page;
+ }
+ }
+
+ private LogicalOggStream getLogicalStream(int serialNumber) {
+ return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
+ }
+
+ public void setTime(long granulePosition) throws IOException {
+ throw new UnsupportedOperationException("Method not supported by this class");
+ }
+
+ /**
+ * @return always <code>false</code>
+ */
+
+ public boolean isSeekable() {
+ return false;
+ }
+
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/ogg/PhysicalOggStream.java b/songdbj/de/jarnbjo/ogg/PhysicalOggStream.java
new file mode 100644
index 0000000000..5f342a38b7
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/PhysicalOggStream.java
@@ -0,0 +1,124 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.3 2003/04/10 19:48:22 jarnbjo
+ * no message
+ *
+ * Revision 1.2 2003/03/31 00:23:04 jarnbjo
+ * no message
+ *
+ * Revision 1.1 2003/03/03 21:02:20 jarnbjo
+ * no message
+ *
+ */
+
+package de.jarnbjo.ogg;
+
+import java.io.IOException;
+import java.util.Collection;
+
+/**
+ * Interface providing access to a physical Ogg stream. Typically this is
+ * a file.
+ */
+
+public interface PhysicalOggStream {
+
+ /**
+ * Returns a collection of objects implementing <code>LogicalOggStream</code>
+ * for accessing the separate logical streams within this physical Ogg stream.
+ *
+ * @return a collection of objects implementing <code>LogicalOggStream</code>
+ * which are representing the logical streams contained within this
+ * physical stream
+ *
+ * @see LogicalOggStream
+ */
+
+ public Collection getLogicalStreams();
+
+ /**
+ * Return the Ogg page with the absolute index <code>index</code>,
+ * independent from the logical structure of this stream or if the
+ * index parameter is -1, the next Ogg page is returned.
+ * This method should only be used by implementations of <code>LogicalOggStream</code>
+ * to access the raw pages.
+ *
+ * @param index the absolute index starting from 0 at the beginning of
+ * the file or stream or -1 to get the next page in a non-seekable
+ * stream
+ *
+ * @return the Ogg page with the physical absolute index <code>index</code>
+ *
+ * @throws OggFormatException if the ogg stream is corrupted
+ * @throws IOException if some other IO error occurs
+ */
+
+ public OggPage getOggPage(int index) throws OggFormatException, IOException;
+
+ /**
+ * Checks if this stream is open for reading.
+ *
+ * @return <code>true</code> if this stream is open for reading,
+ * <code>false</code> otherwise
+ */
+
+ public boolean isOpen();
+
+ /**
+ * Closes this stream. After invoking this method, no further access
+ * to the streams data is possible.
+ *
+ * @throws IOException
+ */
+
+ public void close() throws IOException;
+
+ /**
+ * Sets this stream's (and its logical stream's) position to the granule
+ * position. The next packet read from any logical stream will be the
+ * first packet beginning on the first page with a granule position higher
+ * than the argument.<br><br>
+ *
+ * At the moment, this method only works correctly for Ogg files with
+ * a single logical Vorbis stream, and due to the different interpretations
+ * of the granule position, depending on mixed content, this method will
+ * never be able to work for mixed streams. Chained and interleaved streams are
+ * also not yet supported. Actually, this method is only a hack to support
+ * seeking from JMF, but may of course be abused otherwise too :)
+ *
+ * @param granulePosition
+ *
+ * @throws OggFormatException if the ogg stream is corrupted
+ * @throws IOException if some other IO error occurs
+ */
+
+ public void setTime(long granulePosition) throws OggFormatException, IOException;
+
+ /**
+ * @return <code>true</code> if the stream is seekable, <code>false</code>
+ * otherwise
+ */
+
+ public boolean isSeekable();
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/ogg/UncachedUrlStream.java b/songdbj/de/jarnbjo/ogg/UncachedUrlStream.java
new file mode 100644
index 0000000000..a07f0ac00e
--- /dev/null
+++ b/songdbj/de/jarnbjo/ogg/UncachedUrlStream.java
@@ -0,0 +1,207 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.1 2003/04/10 19:48:22 jarnbjo
+ * no message
+ *
+ */
+
+package de.jarnbjo.ogg;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * Implementation of the <code>PhysicalOggStream</code> interface for reading
+ * an Ogg stream from a URL. This class performs only the necessary caching
+ * to provide continous playback. Seeking within the stream is not supported.
+ */
+
+public class UncachedUrlStream implements PhysicalOggStream {
+
+ private boolean closed=false;
+ private URLConnection source;
+ private InputStream sourceStream;
+ private Object drainLock=new Object();
+ private LinkedList pageCache=new LinkedList();
+ private long numberOfSamples=-1;
+
+ private HashMap logicalStreams=new HashMap();
+
+ private LoaderThread loaderThread;
+
+ private static final int PAGECACHE_SIZE = 10;
+
+ /** Creates an instance of the <code>PhysicalOggStream</code> interface
+ * suitable for reading an Ogg stream from a URL.
+ */
+
+ public UncachedUrlStream(URL source) throws OggFormatException, IOException {
+
+ this.source=source.openConnection();
+ this.sourceStream=this.source.getInputStream();
+
+ loaderThread=new LoaderThread(sourceStream, pageCache);
+ new Thread(loaderThread).start();
+
+ while(!loaderThread.isBosDone() || pageCache.size()<PAGECACHE_SIZE) {
+ try {
+ Thread.sleep(200);
+ }
+ catch (InterruptedException ex) {
+ }
+ //System.out.print("caching "+pageCache.size()+"/"+PAGECACHE_SIZE+" pages\r");
+ }
+ //System.out.println();
+ }
+
+ public Collection getLogicalStreams() {
+ return logicalStreams.values();
+ }
+
+ public boolean isOpen() {
+ return !closed;
+ }
+
+ public void close() throws IOException {
+ closed=true;
+ sourceStream.close();
+ }
+
+ /*
+ public long getCacheLength() {
+ return cacheLength;
+ }
+ */
+
+ /*
+ private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
+ return getNextPage(false);
+ }
+
+ private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
+ return OggPage.create(sourceStream, skipData);
+ }
+ */
+
+ public OggPage getOggPage(int index) throws IOException {
+ while(pageCache.size()==0) {
+ try {
+ Thread.sleep(100);
+ }
+ catch (InterruptedException ex) {
+ }
+ }
+ synchronized(drainLock) {
+ //OggPage page=(OggPage)pageCache.getFirst();
+ //pageCache.removeFirst();
+ //return page;
+ return (OggPage)pageCache.removeFirst();
+ }
+ }
+
+ private LogicalOggStream getLogicalStream(int serialNumber) {
+ return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
+ }
+
+ public void setTime(long granulePosition) throws IOException {
+ throw new UnsupportedOperationException("Method not supported by this class");
+ }
+
+ public class LoaderThread implements Runnable {
+
+ private InputStream source;
+ private LinkedList pageCache;
+ private RandomAccessFile drain;
+ private byte[] memoryCache;
+
+ private boolean bosDone=false;
+
+ private int pageNumber;
+
+ public LoaderThread(InputStream source, LinkedList pageCache) {
+ this.source=source;
+ this.pageCache=pageCache;
+ }
+
+ public void run() {
+ try {
+ boolean eos=false;
+ byte[] buffer=new byte[8192];
+ while(!eos) {
+ OggPage op=OggPage.create(source);
+ synchronized (drainLock) {
+ pageCache.add(op);
+ }
+
+ if(!op.isBos()) {
+ bosDone=true;
+ }
+ if(op.isEos()) {
+ eos=true;
+ }
+
+ LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
+ if(los==null) {
+ los=new LogicalOggStreamImpl(UncachedUrlStream.this, op.getStreamSerialNumber());
+ logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
+ los.checkFormat(op);
+ }
+
+ //los.addPageNumberMapping(pageNumber);
+ //los.addGranulePosition(op.getAbsoluteGranulePosition());
+
+ pageNumber++;
+
+ while(pageCache.size()>PAGECACHE_SIZE) {
+ try {
+ Thread.sleep(200);
+ }
+ catch (InterruptedException ex) {
+ }
+ }
+ }
+ }
+ catch(EndOfOggStreamException e) {
+ // ok
+ }
+ catch(IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public boolean isBosDone() {
+ return bosDone;
+ }
+ }
+
+ /**
+ * @return always <code>false</code>
+ */
+
+ public boolean isSeekable() {
+ return false;
+ }
+
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/util/audio/FadeableAudioInputStream.java b/songdbj/de/jarnbjo/util/audio/FadeableAudioInputStream.java
new file mode 100644
index 0000000000..4916102d4b
--- /dev/null
+++ b/songdbj/de/jarnbjo/util/audio/FadeableAudioInputStream.java
@@ -0,0 +1,62 @@
+package de.jarnbjo.util.audio;
+
+import java.io.*;
+import javax.sound.sampled.*;
+
+public class FadeableAudioInputStream extends AudioInputStream {
+
+ private AudioInputStream stream;
+ private boolean fading=false;
+ private double phi=0.0;
+
+ public FadeableAudioInputStream(AudioInputStream stream) throws IOException {
+ super(stream, stream.getFormat(), -1L);
+ }
+
+ public void fadeOut() {
+ fading=true;
+ phi=0.0;
+ }
+
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte[] b, int offset, int length) throws IOException {
+ int read=super.read(b, offset, length);
+
+ //System.out.println("read "+read);
+
+ if(fading) {
+ int j=0, l=0, r=0;
+ double gain=0.0;
+
+ for(int i=offset; i<offset+read; i+=4) {
+ j=i;
+ l=((int)b[j++])&0xff;
+ l|=((int)b[j++])<<8;
+ r=((int)b[j++])&0xff;
+ r|=((int)b[j])<<8;
+
+ if(phi<Math.PI/2) {
+ phi+=0.000015;
+ }
+
+ gain=Math.cos(phi);
+ //System.out.println("gain "+gain);
+
+ l=(int)(l*gain);
+ r=(int)(r*gain);
+
+ j=i;
+ b[j++]=(byte)(l&0xff);
+ b[j++]=(byte)((l>>8)&0xff);
+ b[j++]=(byte)(r&0xff);
+ b[j++]=(byte)((r>>8)&0xff);
+ }
+ }
+
+ return read;
+ }
+
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/util/io/BitInputStream.java b/songdbj/de/jarnbjo/util/io/BitInputStream.java
new file mode 100644
index 0000000000..89cadb8380
--- /dev/null
+++ b/songdbj/de/jarnbjo/util/io/BitInputStream.java
@@ -0,0 +1,185 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.5 2003/04/10 19:48:31 jarnbjo
+ * no message
+ *
+ * Revision 1.4 2003/03/16 20:57:06 jarnbjo
+ * no message
+ *
+ * Revision 1.3 2003/03/16 20:56:56 jarnbjo
+ * no message
+ *
+ * Revision 1.2 2003/03/16 01:11:39 jarnbjo
+ * no message
+ *
+ * Revision 1.1 2003/03/03 21:02:20 jarnbjo
+ * no message
+ *
+ */
+
+package de.jarnbjo.util.io;
+
+import java.io.IOException;
+
+/**
+ * An interface with methods allowing bit-wise reading from
+ * an input stream. All methods in this interface are optional
+ * and an implementation not support a method or a specific state
+ * (e.g. endian) will throw an UnspportedOperationException if
+ * such a method is being called. This should be speicified in
+ * the implementation documentation.
+ */
+
+public interface BitInputStream {
+
+ /**
+ * constant for setting this stream's mode to little endian
+ *
+ * @see #setEndian(int)
+ */
+
+ public static final int LITTLE_ENDIAN = 0;
+
+ /**
+ * constant for setting this stream's mode to big endian
+ *
+ * @see #setEndian(int)
+ */
+
+ public static final int BIG_ENDIAN = 1;
+
+ /**
+ * reads one bit (as a boolean) from the input stream
+ *
+ * @return <code>true</code> if the next bit is 1,
+ * <code>false</code> otherwise
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws UnsupportedOperationException if the method is not supported by the implementation
+ */
+
+ public boolean getBit() throws IOException;
+
+ /**
+ * reads <code>bits</code> number of bits from the input
+ * stream
+ *
+ * @return the unsigned integer value read from the stream
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws UnsupportedOperationException if the method is not supported by the implementation
+ */
+
+ public int getInt(int bits) throws IOException;
+
+ /**
+ * reads <code>bits</code> number of bits from the input
+ * stream
+ *
+ * @return the signed integer value read from the stream
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws UnsupportedOperationException if the method is not supported by the implementation
+ */
+
+ public int getSignedInt(int bits) throws IOException;
+
+ /**
+ * reads a huffman codeword based on the <code>root</code>
+ * parameter and returns the decoded value
+ *
+ * @param root the root of the Huffman tree used to decode the codeword
+ * @return the decoded unsigned integer value read from the stream
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws UnsupportedOperationException if the method is not supported by the implementation
+ */
+
+ public int getInt(HuffmanNode root) throws IOException;
+
+ /**
+ * reads an integer encoded as "signed rice" as described in
+ * the FLAC audio format specification
+ *
+ * @param order
+ * @return the decoded integer value read from the stream
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws UnsupportedOperationException if the method is not supported by the implementation
+ */
+
+ public int readSignedRice(int order) throws IOException;
+
+ /**
+ * fills the array from <code>offset</code> with <code>len</code>
+ * integers encoded as "signed rice" as described in
+ * the FLAC audio format specification
+ *
+ * @param order
+ * @param buffer
+ * @param offset
+ * @param len
+ * @return the decoded integer value read from the stream
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws UnsupportedOperationException if the method is not supported by the implementation
+ */
+
+ public void readSignedRice(int order, int[] buffer, int offset, int len) throws IOException;
+
+ /**
+ * reads <code>bits</code> number of bits from the input
+ * stream
+ *
+ * @return the unsigned long value read from the stream
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws UnsupportedOperationException if the method is not supported by the implementation
+ */
+
+ public long getLong(int bits) throws IOException;
+
+ /**
+ * causes the read pointer to be moved to the beginning
+ * of the next byte, remaining bits in the current byte
+ * are discarded
+ *
+ * @throws UnsupportedOperationException if the method is not supported by the implementation
+ */
+
+ public void align();
+
+ /**
+ * changes the endian mode used when reading bit-wise from
+ * the stream, changing the mode mid-stream will cause the
+ * read cursor to move to the beginning of the next byte
+ * (as if calling the <code>allign</code> method
+ *
+ * @see #align()
+ *
+ * @throws UnsupportedOperationException if the method is not supported by the implementation
+ */
+
+ public void setEndian(int endian);
+} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/util/io/ByteArrayBitInputStream.java b/songdbj/de/jarnbjo/util/io/ByteArrayBitInputStream.java
new file mode 100644
index 0000000000..9c84c7daca
--- /dev/null
+++ b/songdbj/de/jarnbjo/util/io/ByteArrayBitInputStream.java
@@ -0,0 +1,352 @@
+/*
+ * $ProjectName$
+ * $ProjectRevision$
+ * -----------------------------------------------------------
+ * $Id$
+ * -----------------------------------------------------------
+ *
+ * $Author$
+ *
+ * Description:
+ *
+ * Copyright 2002-2003 Tor-Einar Jarnbjo
+ * -----------------------------------------------------------
+ *
+ * Change History
+ * -----------------------------------------------------------
+ * $Log$
+ * Revision 1.1 2005/07/11 15:42:36 hcl
+ * Songdb java version, source. only 1.5 compatible
+ *
+ * Revision 1.1.1.1 2004/04/04 22:09:12 shred
+ * First Import
+ *
+ * Revision 1.3 2003/04/10 19:48:31 jarnbjo
+ * no message
+ *
+ * Revision 1.2 2003/03/16 01:11:39 jarnbjo
+ * no message
+ *
+ * Revision 1.1 2003/03/03 21:02:20 jarnbjo
+ * no message
+ *
+ */
+
+package de.jarnbjo.util.io;
+
+import java.io.IOException;
+
+/**
+ * Implementation of the <code>BitInputStream</code> interface,
+ * using a byte array as data source.
+*/
+
+public class ByteArrayBitInputStream implements BitInputStream {
+
+ private byte[] source;
+ private byte currentByte;
+
+ private int endian;
+
+ private int byteIndex=0;
+ private int bitIndex=0;
+
+ public ByteArrayBitInputStream(byte[] source) {
+ this(source, LITTLE_ENDIAN);
+ }
+
+ public ByteArrayBitInputStream(byte[] source, int endian) {
+ this.endian=endian;
+ this.source=source;
+ currentByte=source[0];
+ bitIndex=(endian==LITTLE_ENDIAN)?0:7;
+ }
+
+ public boolean getBit() throws IOException {
+ if(endian==LITTLE_ENDIAN) {
+ if(bitIndex>7) {
+ bitIndex=0;
+ currentByte=source[++byteIndex];
+ }
+ return (currentByte&(1<<(bitIndex++)))!=0;
+ }
+ else {
+ if(bitIndex<0) {
+ bitIndex=7;
+ currentByte=source[++byteIndex];
+ }
+ return (currentByte&(1<<(bitIndex--)))!=0;
+ }
+ }
+
+ public int getInt(int bits) throws IOException {
+ if(bits>32) {
+ throw new IllegalArgumentException("Argument \"bits\" must be <= 32");
+ }
+ int res=0;
+ if(endian==LITTLE_ENDIAN) {
+ for(int i=0; i<bits; i++) {
+ if(getBit()) {
+ res|=(1<<i);
+ }
+ }
+ }
+ else {
+ if(bitIndex<0) {
+ bitIndex=7;
+ currentByte=source[++byteIndex];
+ }
+ if(bits<=bitIndex+1) {
+ int ci=((int)currentByte)&0xff;
+ int offset=1+bitIndex-bits;
+ int mask=((1<<bits)-1)<<offset;
+ res=(ci&mask)>>offset;
+ bitIndex-=bits;
+ }
+ else {
+ res=(((int)currentByte)&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
+ bits-=bitIndex+1;
+ currentByte=source[++byteIndex];
+ while(bits>=8) {
+ bits-=8;
+ res|=(((int)source[byteIndex])&0xff)<<bits;
+ currentByte=source[++byteIndex];
+ }
+ if(bits>0) {
+ int ci=((int)source[byteIndex])&0xff;
+ res|=(ci>>(8-bits))&((1<<bits)-1);
+ bitIndex=7-bits;
+ }
+ else {
+ currentByte=source[--byteIndex];
+ bitIndex=-1;
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public int getSignedInt(int bits) throws IOException {
+ int raw=getInt(bits);
+ if(raw>=1<<(bits-1)) {
+ raw-=1<<bits;
+ }
+ return raw;
+ }
+
+ public int getInt(HuffmanNode root) throws IOException {
+ while(root.value==null) {
+ if(bitIndex>7) {
+ bitIndex=0;
+ currentByte=source[++byteIndex];
+ }
+ root=(currentByte&(1<<(bitIndex++)))!=0?root.o1:root.o0;
+ }
+ return root.value.intValue();
+ }
+
+ public long getLong(int bits) throws IOException {
+ if(bits>64) {
+ throw new IllegalArgumentException("Argument \"bits\" must be <= 64");
+ }
+ long res=0;
+ if(endian==LITTLE_ENDIAN) {
+ for(int i=0; i<bits; i++) {
+ if(getBit()) {
+ res|=(1L<<i);
+ }
+ }
+ }
+ else {
+ for(int i=bits-1; i>=0; i--) {
+ if(getBit()) {
+ res|=(1L<<i);
+ }
+ }
+ }
+ return res;
+ }
+
+ /**
+ * <p>reads an integer encoded as "signed rice" as described in
+ * the FLAC audio format specification</p>
+ *
+ * <p><b>not supported for little endian</b></p>
+ *
+ * @param order
+ * @return the decoded integer value read from the stream
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws UnsupportedOperationException if the method is not supported by the implementation
+ */
+
+ public int readSignedRice(int order) throws IOException {
+
+ int msbs=-1, lsbs=0, res=0;
+
+ if(endian==LITTLE_ENDIAN) {
+ // little endian
+ throw new UnsupportedOperationException("ByteArrayBitInputStream.readSignedRice() is only supported in big endian mode");
+ }
+ else {
+ // big endian
+
+ byte cb=source[byteIndex];
+ do {
+ msbs++;
+ if(bitIndex<0) {
+ bitIndex=7;
+ byteIndex++;
+ cb=source[byteIndex];
+ }
+ } while((cb&(1<<bitIndex--))==0);
+
+ int bits=order;
+
+ if(bitIndex<0) {
+ bitIndex=7;
+ byteIndex++;
+ }
+ if(bits<=bitIndex+1) {
+ int ci=((int)source[byteIndex])&0xff;
+ int offset=1+bitIndex-bits;
+ int mask=((1<<bits)-1)<<offset;
+ lsbs=(ci&mask)>>offset;
+ bitIndex-=bits;
+ }
+ else {
+ lsbs=(((int)source[byteIndex])&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
+ bits-=bitIndex+1;
+ byteIndex++;
+ while(bits>=8) {
+ bits-=8;
+ lsbs|=(((int)source[byteIndex])&0xff)<<bits;
+ byteIndex++;
+ }
+ if(bits>0) {
+ int ci=((int)source[byteIndex])&0xff;
+ lsbs|=(ci>>(8-bits))&((1<<bits)-1);
+ bitIndex=7-bits;
+ }
+ else {
+ byteIndex--;
+ bitIndex=-1;
+ }
+ }
+
+ res=(msbs<<order)|lsbs;
+ }
+
+ return (res&1)==1?-(res>>1)-1:(res>>1);
+ }
+
+ /**
+ * <p>fills the array from <code>offset</code> with <code