summaryrefslogtreecommitdiff
path: root/songdbj
diff options
context:
space:
mode:
Diffstat (limited to 'songdbj')
-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 @@
1import java.util.*;
2import java.io.*;
3
4public class AlbumEntry extends Entry implements Comparable {
5 protected String name;
6 protected ArtistEntry artist;
7 protected Vector songs;
8 protected int songcount;
9
10 public AlbumEntry(String n) {
11 name=n;
12 songs=new Vector();
13 artist=null;
14 songcount=0;
15 }
16
17 protected class SongSorter implements Comparator {
18 public int compare(Object o1, Object o2) {
19 SongEntry s1=(SongEntry)o1;
20 SongEntry s2=(SongEntry)o2;
21 int track1=s1.getTrack(),track2=s2.getTrack();
22 if(track1>track2)
23 return 1;
24 else if(track1<track2)
25 return -1;
26 return s1.getFile().getFile().getName().compareTo(s2.getFile().getFile().getName());
27 }
28 }
29
30 public void addSong(SongEntry e) {
31 songs.add(e);
32 e.setAlbum(this);
33 e.setArtist(artist);
34 songcount++;
35 Collections.sort(songs,new SongSorter());
36 }
37
38 public int size() { return songcount; }
39 public void setArtist(ArtistEntry a) {
40 a.addAlbum(this);
41 if(artist!=null&&artist!=a&&!artist.getName().equals("<various artists>")) {
42 artist.removeAlbum(this);
43 artist=TagDatabase.getInstance().getArtistEntry("<various artists>");
44 }
45 else
46 artist=a;
47 }
48 public ArtistEntry getArtist() { return artist; }
49
50 public int compareTo(Object o) {
51 return String.CASE_INSENSITIVE_ORDER.compare(name,((AlbumEntry)o).getName());
52 }
53
54 public String getName() { return name; }
55 public Collection getSongs() { return songs; }
56 public void write(DataOutputStream w) throws IOException {
57 int x;
58 w.writeBytes(name);
59 for(x=TagDatabase.getInstance().albumlen-name.length();x>0;x--)
60 w.write(0);
61 w.writeInt(artist.getOffset());
62 Iterator i2 = songs.iterator();
63 x=0;
64 while(i2.hasNext()) {
65 Entry e = (Entry) i2.next();
66 w.writeInt(e.getOffset());
67 x++;
68 }
69 for(;x<TagDatabase.getInstance().songarraylen;x++)
70 w.writeInt(0);
71 }
72 public static int entrySize() {
73 TagDatabase td=TagDatabase.getInstance();
74 return td.albumlen+4+td.songarraylen*4;
75 }
76} \ 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 @@
1import java.util.*;
2import java.io.*;
3
4public class ArtistEntry extends Entry implements Comparable {
5 protected String name;
6 protected Vector albums;
7 protected int albumcount;
8
9 public ArtistEntry(String n) {
10 name=n;
11 albums=new Vector();
12 albumcount=0;
13 }
14
15 public void addAlbum(AlbumEntry e) {
16 if(!albums.contains(e)) {
17 albums.add(e);
18 e.setArtist(this);
19 albumcount++;
20 Collections.sort(albums);
21 }
22 }
23
24 public void removeAlbum(AlbumEntry e) {
25 albums.remove(e);
26 albumcount--;
27 }
28
29 public int size() { return albumcount; }
30
31 public int compareTo(Object o) {
32 return String.CASE_INSENSITIVE_ORDER.compare(name,((ArtistEntry)o).getName());
33 }
34
35 public String getName() { return name; }
36 public Collection getAlbums() { return albums; }
37 public void write(DataOutputStream w) throws IOException {
38 int x;
39 w.writeBytes(name);
40 for(x=TagDatabase.getInstance().artistlen-name.length();x>0;x--)
41 w.write(0);
42 Iterator i2 = albums.iterator();
43 x=0;
44 while(i2.hasNext()) {
45 Entry e = (Entry) i2.next();
46 w.writeInt(e.getOffset());
47 x++;
48 }
49 for(;x<TagDatabase.getInstance().albumarraylen;x++)
50 w.writeInt(0);
51 }
52 public static int entrySize() {
53 TagDatabase td=TagDatabase.getInstance();
54 return td.artistlen+4*td.albumarraylen;
55 }
56} \ 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 @@
1import java.io.*;
2
3public abstract class Entry {
4 protected int offset;
5
6 public Entry() {
7 offset=-1;
8 }
9
10 public void setOffset(int pos) { offset=pos; }
11 public int getOffset() { return offset; }
12
13 public abstract void write(DataOutputStream w) throws IOException;
14} \ 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 @@
1import java.io.*;
2
3public class FileEntry extends Entry implements Comparable {
4 protected String filename;
5 protected int hash;
6 protected SongEntry sentry;
7 protected RundbEntry rentry;
8 protected File file;
9
10 public FileEntry(File f) throws FileNotFoundException, IOException {
11 filename=convertPath(f.getAbsolutePath());
12 file=f;
13 sentry=null;
14 rentry=null;
15 }
16
17 public int compareTo(Object o) {
18 return String.CASE_INSENSITIVE_ORDER.compare(filename,((FileEntry)o).getFilename());
19 }
20
21 public String getFilename() { return filename; }
22
23 public File getFile() { return file; }
24
25 protected void calcHash() throws FileNotFoundException, IOException {
26 DataInputStream r = new DataInputStream(new FileInputStream(file));
27 byte[] buf = new byte[32768];
28 if(sentry!=null)
29 r.skip(sentry.getFirstFrameOffset());
30 r.read(buf);
31 hash=CalcCRC32(buf);
32 r.close();
33 }
34
35 public int getHash() { return hash; }
36
37 public static String add(String t) {
38 String add=TagDatabase.getInstance().add;
39 if(add!=null)
40 return add+t;
41 else
42 return t;
43 }
44
45 public static String convertPath(String t) {
46 String temp = add(strip(t)).replace('\\','/');
47 if (temp.charAt(0)!='/')
48 temp="/"+temp;
49 return temp;
50 }
51
52 public static String strip(String t) {
53 return stripPrefix(stripDriveletter(stripPrefix(t)));
54 }
55
56 public static String stripPrefix(String t) {
57 String prefix=TagDatabase.getInstance().strip;
58 if(prefix!=null&&t.toLowerCase().startsWith(prefix.toLowerCase())) {
59 return t.substring(prefix.length());
60 }
61 return t;
62 }
63
64 public static String stripDriveletter(String t) {
65 if(t.indexOf(':')==1) { // second char is ':'
66 return t.substring(2);
67 }
68 return t;
69 }
70
71 public void setSongEntry(SongEntry e) { sentry=e; try { calcHash(); } catch(Exception d) { } }
72 public void setRundbEntry(RundbEntry e) { rentry=e; }
73 public SongEntry getSongEntry() { return sentry; }
74 public RundbEntry getRundbEntry() { return rentry; }
75 public int getSongEntryOffset() {
76 if(sentry!=null)
77 return sentry.getOffset();
78 else
79 return -1;
80 }
81 public int getRundbEntryOffset() {
82/* if(rentry!=null)
83 return rentry.getOffset();
84 else*/
85 return -1;
86 }
87 public void write(DataOutputStream w) throws IOException {
88 String name=getFilename();
89 w.writeBytes(name);
90 for(int x=TagDatabase.getInstance().filelen-name.length();x>0;x--)
91 w.write(0);
92 w.writeInt(hash);
93 w.writeInt(getSongEntryOffset());
94 w.writeInt(getRundbEntryOffset());
95 }
96
97 public static int entrySize() {
98 return TagDatabase.getInstance().filelen+12;
99 }
100
101 static final int crc_table[] =
102 { // CRC32 lookup table for polynomial 0x04C11DB7
103 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
104 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
105 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7,
106 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
107 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3,
108 0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
109 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF,
110 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
111 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB,
112 0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
113 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
114 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
115 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4,
116 0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
117 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08,
118 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
119 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC,
120 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
121 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050,
122 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
123 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
124 0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
125 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1,
126 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
127 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5,
128 0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
129 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9,
130 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
131 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD,
132 0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
133 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
134 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
135 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2,
136 0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
137 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E,
138 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
139 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A,
140 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
141 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676,
142 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
143 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
144 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
145 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
146 };
147
148 public static int CalcCRC32(byte[] buf) {
149 int i;
150 int crc = 0xffffffff;
151 for (i = 0; i < buf.length; i++)
152 crc = (crc << 8) ^ crc_table[(int)((crc >> 24) ^ buf[i]) & 0xFF];
153 return crc;
154 }
155} \ 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 @@
1/*
2 * MpegInfo.
3 *
4 * JavaZOOM : jlgui@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24import java.io.File;
25import java.io.IOException;
26import java.io.InputStream;
27import java.net.URL;
28import java.util.Iterator;
29import java.util.Map;
30import java.util.Vector;
31import java.io.FileInputStream;
32import java.io.BufferedInputStream;
33import javax.sound.sampled.AudioFileFormat;
34import javax.sound.sampled.AudioSystem;
35import javax.sound.sampled.UnsupportedAudioFileException;
36
37import org.tritonus.share.sampled.file.TAudioFileFormat;
38
39/**
40 * This class gives information (audio format and comments) about MPEG file or URL.
41 */
42public class MpegInfo implements TagInfo
43{
44 protected int channels = -1;
45 protected String channelsMode = null;
46 protected String version = null;
47 protected int rate = 0;
48 protected String layer = null;
49 protected String emphasis = null;
50 protected int nominalbitrate = 0;
51 protected long total = 0;
52 protected String vendor = null;
53 protected String location = null;
54 protected long size = 0;
55 protected boolean copyright = false;
56 protected boolean crc = false;
57 protected boolean original = false;
58 protected boolean priv = false;
59 protected boolean vbr = false;
60 protected int track = -1;
61 protected int offset = 0;
62 protected String year = null;
63 protected String genre = null;
64 protected String title = null;
65 protected String artist = null;
66 protected String album = null;
67 protected Vector comments = null;
68
69 /**
70 * Constructor.
71 */
72 public MpegInfo()
73 {
74 super();
75 }
76
77 /**
78 * Load and parse MPEG info from File.
79 * @param input
80 * @throws IOException
81 */
82 public void load(File input) throws IOException, UnsupportedAudioFileException
83 {
84 size = input.length();
85 location = input.getPath();
86 loadInfo(input);
87 }
88
89 /**
90 * Load and parse MPEG info from URL.
91 * @param input
92 * @throws IOException
93 * @throws UnsupportedAudioFileException
94 */
95 public void load(URL input) throws IOException, UnsupportedAudioFileException
96 {
97 location = input.toString();
98 loadInfo(input);
99 }
100
101 /**
102 * Load and parse MPEG info from InputStream.
103 * @param input
104 * @throws IOException
105 * @throws UnsupportedAudioFileException
106 */
107 public void load(InputStream input) throws IOException, UnsupportedAudioFileException
108 {
109 loadInfo(input);
110 }
111
112 /**
113 * Load info from input stream.
114 * @param input
115 * @throws IOException
116 * @throws UnsupportedAudioFileException
117 */
118 protected void loadInfo(InputStream input) throws IOException, UnsupportedAudioFileException
119 {
120 AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
121 loadInfo(aff);
122 }
123
124 /**
125 * Load MP3 info from file.
126 * @param file
127 * @throws IOException
128 * @throws UnsupportedAudioFileException
129 */
130 protected void loadInfo(File file) throws IOException, UnsupportedAudioFileException
131 {
132 InputStream in = new BufferedInputStream(new FileInputStream(file));
133 loadInfo(in);
134 in.close();
135 }
136
137 /**
138 * Load info from AudioFileFormat.
139 * @param aff
140 */
141 protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException
142 {
143 String type = aff.getType().toString();
144 if (!type.equalsIgnoreCase("mp3")) throw new UnsupportedAudioFileException("Not MP3 audio format");
145 if (aff instanceof TAudioFileFormat)
146 {
147 Map props = ((TAudioFileFormat) aff).properties();
148 if (props.containsKey("mp3.channels")) channels = ((Integer)props.get("mp3.channels")).intValue();
149 if (props.containsKey("mp3.frequency.hz")) rate = ((Integer)props.get("mp3.frequency.hz")).intValue();
150 if (props.containsKey("mp3.bitrate.nominal.bps")) nominalbitrate = ((Integer)props.get("mp3.bitrate.nominal.bps")).intValue();
151 if (props.containsKey("mp3.version.layer")) layer = "Layer "+(String)props.get("mp3.version.layer");
152 if (props.containsKey("mp3.version.mpeg"))
153 {
154 version = (String)props.get("mp3.version.mpeg");
155 if (version.equals("1")) version = "MPEG1";
156 else if (version.equals("2")) version = "MPEG2-LSF";
157 else if (version.equals("2.5")) version = "MPEG2.5-LSF";
158 }
159 if (props.containsKey("mp3.mode"))
160 {
161 int mode = ((Integer)props.get("mp3.mode")).intValue();
162 if (mode==0) channelsMode = "Stereo";
163 else if (mode==1) channelsMode = "Joint Stereo";
164 else if (mode==2) channelsMode = "Dual Channel";
165 else if (mode==3) channelsMode = "Single Channel";
166 }
167 if (props.containsKey("mp3.crc")) crc = ((Boolean)props.get("mp3.crc")).booleanValue();
168 if (props.containsKey("mp3.vbr")) vbr = ((Boolean)props.get("mp3.vbr")).booleanValue();
169 if (props.containsKey("mp3.copyright")) copyright = ((Boolean)props.get("mp3.copyright")).booleanValue();
170 if (props.containsKey("mp3.original")) original = ((Boolean)props.get("mp3.original")).booleanValue();
171 emphasis="none";
172
173 if (props.containsKey("title")) title = (String)props.get("title");
174 if (props.containsKey("author")) artist = (String)props.get("author");
175 if (props.containsKey("album")) album = (String)props.get("album");
176 if (props.containsKey("date")) year = (String)props.get("date");
177 if (props.containsKey("duration")) total = (long) Math.round((((Long)props.get("duration")).longValue())/1000000);
178 if (props.containsKey("mp3.id3tag.genre")) genre = (String)props.get("mp3.id3tag.genre");
179
180 if (props.containsKey("mp3.header.pos")) {
181 offset = ((Integer)props.get("mp3.header.pos")).intValue();
182 }
183 else
184 offset = 0;
185 if (props.containsKey("mp3.id3tag.track"))
186 {
187 try
188 {
189 track = Integer.parseInt((String)props.get("mp3.id3tag.track"));
190 }
191 catch (NumberFormatException e1)
192 {
193 // Not a number
194 }
195 }
196 }
197 }
198
199 /**
200 * Load MP3 info from URL.
201 * @param input
202 * @throws IOException
203 * @throws UnsupportedAudioFileException
204 */
205 protected void loadInfo(URL input) throws IOException, UnsupportedAudioFileException
206 {
207 AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
208 loadInfo(aff);
209 loadShoutastInfo(aff);
210 }
211
212 /**
213 * Load Shoutcast info from AudioFileFormat.
214 * @param aff
215 * @throws IOException
216 * @throws UnsupportedAudioFileException
217 */
218 protected void loadShoutastInfo(AudioFileFormat aff) throws IOException, UnsupportedAudioFileException
219 {
220 String type = aff.getType().toString();
221 if (!type.equalsIgnoreCase("mp3")) throw new UnsupportedAudioFileException("Not MP3 audio format");
222 if (aff instanceof TAudioFileFormat)
223 {
224 Map props = ((TAudioFileFormat) aff).properties();
225 // Try shoutcast meta data (if any).
226 Iterator it = props.keySet().iterator();
227 comments = new Vector();
228 while (it.hasNext())
229 {
230 String key = (String) it.next();
231 if (key.startsWith("mp3.shoutcast.metadata."))
232 {
233 String value = (String) props.get(key);
234 key = key.substring(23,key.length());
235 if (key.equalsIgnoreCase("icy-name"))
236 {
237 title = value;
238 }
239 else if (key.equalsIgnoreCase("icy-genre"))
240 {
241 genre = value;
242 }
243 else
244 {
245 comments.add(key+"="+value);
246 }
247 }
248 }
249 }
250 }
251
252 public boolean getVBR()
253 {
254 return vbr;
255 }
256
257 public int getChannels()
258 {
259 return channels;
260 }
261
262 public String getVersion()
263 {
264 return version;
265 }
266
267 public String getEmphasis()
268 {
269 return emphasis;
270 }
271
272 public boolean getCopyright()
273 {
274 return copyright;
275 }
276
277 public boolean getCRC()
278 {
279 return crc;
280 }
281
282 public boolean getOriginal()
283 {
284 return original;
285 }
286
287 public String getLayer()
288 {
289 return layer;
290 }
291
292 public long getSize()
293 {
294 return size;
295 }
296
297 public String getLocation()
298 {
299 return location;
300 }
301
302 /*-- TagInfo Implementation --*/
303
304 public int getSamplingRate()
305 {
306 return rate;
307 }
308
309 public int getBitRate()
310 {
311 return nominalbitrate;
312 }
313
314 public long getPlayTime()
315 {
316 return total;
317 }
318
319 public String getTitle()
320 {
321 return title;
322 }
323
324 public String getArtist()
325 {
326 return artist;
327 }
328
329 public String getAlbum()
330 {
331 return album;
332 }
333
334 public int getTrack()
335 {
336 return track;
337 }
338
339 public String getGenre()
340 {
341 return genre;
342 }
343
344 public Vector getComment()
345 {
346 return comments;
347 }
348
349 public String getYear()
350 {
351 return year;
352 }
353
354 /**
355 * Get channels mode.
356 * @return
357 */
358 public String getChannelsMode()
359 {
360 return channelsMode;
361 }
362
363 public int getFirstFrameOffset() {
364 return offset;
365 }
366
367} \ 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 @@
1/*
2 * OggVorbisInfo.
3 *
4 * JavaZOOM : jlgui@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24import java.io.File;
25import java.io.IOException;
26import java.io.InputStream;
27import java.io.FileInputStream;
28import java.io.BufferedInputStream;
29import java.net.URL;
30import java.util.Map;
31import java.util.Vector;
32
33import javax.sound.sampled.AudioFileFormat;
34import javax.sound.sampled.AudioSystem;
35import javax.sound.sampled.UnsupportedAudioFileException;
36
37import org.tritonus.share.sampled.file.TAudioFileFormat;
38
39/**
40 * This class gives information (audio format and comments) about Ogg Vorbis file or URL.
41 */
42public class OggVorbisInfo implements TagInfo
43{
44 protected int serial = 0;
45 protected int channels = 0;
46 protected int version = 0;
47 protected int rate = 0;
48 protected int minbitrate = 0;
49 protected int maxbitrate = 0;
50 protected int averagebitrate = 0;
51 protected int nominalbitrate = 0;
52 protected long totalms = 0;
53 protected String vendor = "";
54 protected String location = null;
55
56 protected long size = 0;
57 protected int track = -1;
58 protected String year = null;
59 protected String genre = null;
60 protected String title = null;
61 protected String artist = null;
62 protected String album = null;
63 protected Vector comments = new Vector();
64
65
66 /***
67 * Constructor.
68 */
69 public OggVorbisInfo()
70 {
71 super();
72 }
73
74 /**
75 * Load and parse Ogg Vorbis info from File.
76 * @param input
77 * @throws IOException
78 */
79 public void load(File input) throws IOException, UnsupportedAudioFileException
80 {
81 size = input.length();
82 location = input.getPath();
83 loadInfo(input);
84 }
85
86 /**
87 * Load and parse Ogg Vorbis info from URL.
88 * @param input
89 * @throws IOException
90 * @throws UnsupportedAudioFileException
91 */
92 public void load(URL input) throws IOException, UnsupportedAudioFileException
93 {
94 location = input.toString();
95 loadInfo(input);
96 }
97
98 /**
99 * Load and parse Ogg Vorbis info from InputStream.
100 * @param input
101 * @throws IOException
102 * @throws UnsupportedAudioFileException
103 */
104 public void load(InputStream input) throws IOException, UnsupportedAudioFileException
105 {
106 loadInfo(input);
107 }
108
109 /**
110 * Load info from input stream.
111 * @param input
112 * @throws IOException
113 * @throws UnsupportedAudioFileException
114 */
115 protected void loadInfo(InputStream input) throws IOException, UnsupportedAudioFileException
116 {
117 AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
118 loadInfo(aff);
119 }
120
121 /**
122 * Load Ogg Vorbis info from file.
123 * @param file
124 * @throws IOException
125 * @throws UnsupportedAudioFileException
126 */
127 protected void loadInfo(File file) throws IOException, UnsupportedAudioFileException
128 {
129 InputStream in = new BufferedInputStream(new FileInputStream(file));
130 loadInfo(in);
131 in.close();
132 }
133
134 /**
135 * Load Ogg Vorbis info from URL.
136 * @param input
137 * @throws IOException
138 * @throws UnsupportedAudioFileException
139 */
140 protected void loadInfo(URL input) throws IOException, UnsupportedAudioFileException
141 {
142 AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
143 loadInfo(aff);
144 loadExtendedInfo(aff);
145 }
146
147 /**
148 * Load info from AudioFileFormat.
149 * @param aff
150 * @throws UnsupportedAudioFileException
151 */
152 protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException
153 {
154 String type = aff.getType().toString();
155 if (!type.equalsIgnoreCase("ogg")) throw new UnsupportedAudioFileException("Not Ogg Vorbis audio format");
156 if (aff instanceof TAudioFileFormat)
157 {
158 Map props = ((TAudioFileFormat) aff).properties();
159 if (props.containsKey("ogg.channels")) channels = ((Integer)props.get("ogg.channels")).intValue();
160 if (props.containsKey("ogg.frequency.hz")) rate = ((Integer)props.get("ogg.frequency.hz")).intValue();
161 if (props.containsKey("ogg.bitrate.nominal.bps")) nominalbitrate = ((Integer)props.get("ogg.bitrate.nominal.bps")).intValue();
162 averagebitrate = nominalbitrate;
163 if (props.containsKey("ogg.bitrate.max.bps")) maxbitrate = ((Integer)props.get("ogg.bitrate.max.bps")).intValue();
164 if (props.containsKey("ogg.bitrate.min.bps")) minbitrate = ((Integer)props.get("ogg.bitrate.min.bps")).intValue();
165 if (props.containsKey("ogg.version")) version = ((Integer)props.get("ogg.version")).intValue();
166 if (props.containsKey("ogg.serial")) serial = ((Integer)props.get("ogg.serial")).intValue();
167 if (props.containsKey("ogg.comment.encodedby")) vendor = (String)props.get("ogg.comment.encodedby");
168
169 if (props.containsKey("copyright")) comments.add((String)props.get("copyright"));
170 if (props.containsKey("title")) title = (String)props.get("title");
171 if (props.containsKey("author")) artist = (String)props.get("author");
172 if (props.containsKey("album")) album = (String)props.get("album");
173 if (props.containsKey("date")) year = (String)props.get("date");
174 if (props.containsKey("comment")) comments.add((String)props.get("comment"));
175 if (props.containsKey("duration")) totalms = (long) Math.round((((Long)props.get("duration")).longValue())/1000000);
176 if (props.containsKey("ogg.comment.genre")) genre = (String)props.get("ogg.comment.genre");
177 if (props.containsKey("ogg.comment.track"))
178 {
179 try
180 {
181 track = Integer.parseInt((String)props.get("ogg.comment.track"));
182 }
183 catch (NumberFormatException e1)
184 {
185 // Not a number
186 }
187 }
188 if (props.containsKey("ogg.comment.ext.1")) comments.add((String)props.get("ogg.comment.ext.1"));
189 if (props.containsKey("ogg.comment.ext.2")) comments.add((String)props.get("ogg.comment.ext.2"));
190 if (props.containsKey("ogg.comment.ext.3")) comments.add((String)props.get("ogg.comment.ext.3"));
191 }
192 }
193
194 /**
195 * Load extended info from AudioFileFormat.
196 * @param aff
197 * @throws IOException
198 * @throws UnsupportedAudioFileException
199 */
200 protected void loadExtendedInfo(AudioFileFormat aff) throws IOException, UnsupportedAudioFileException
201 {
202 String type = aff.getType().toString();
203 if (!type.equalsIgnoreCase("ogg")) throw new UnsupportedAudioFileException("Not Ogg Vorbis audio format");
204 if (aff instanceof TAudioFileFormat)
205 {
206 Map props = ((TAudioFileFormat) aff).properties();
207 // How to load icecast meta data (if any) ??
208 }
209 }
210
211 public int getSerial()
212 {
213 return serial;
214 }
215
216 public int getChannels()
217 {
218 return channels;
219 }
220
221 public int getVersion()
222 {
223 return version;
224 }
225
226 public int getMinBitrate()
227 {
228 return minbitrate;
229 }
230
231 public int getMaxBitrate()
232 {
233 return maxbitrate;
234 }
235
236 public int getAverageBitrate()
237 {
238 return averagebitrate;
239 }
240
241 public long getSize()
242 {
243 return size;
244 }
245
246 public String getVendor()
247 {
248 return vendor;
249 }
250
251 public String getLocation()
252 {
253 return location;
254 }
255
256 /*-- TagInfo Implementation --*/
257
258 public int getSamplingRate()
259 {
260 return rate;
261 }
262
263 public int getBitRate()
264 {
265 return nominalbitrate;
266 }
267
268 public long getPlayTime()
269 {
270 return totalms;
271 }
272
273 public String getTitle()
274 {
275 return title;
276 }
277
278 public String getArtist()
279 {
280 return artist;
281 }
282
283 public String getAlbum()
284 {
285 return album;
286 }
287
288 public int getTrack()
289 {
290 return track;
291 }
292
293 public String getGenre()
294 {
295 return genre;
296 }
297
298 public Vector getComment()
299 {
300 return comments;
301 }
302
303 public String getYear()
304 {
305 return year;
306 }
307
308 public int getFirstFrameOffset() {
309 return 0;
310 }
311} \ 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 @@
1import java.io.*;
2
3public class RundbEntry extends Entry {
4 protected FileEntry file;
5 protected short rating, voladj;
6 protected int playcount,lastplayed;
7
8 public RundbEntry(FileEntry f) {
9 file=f;
10 rating=0;
11 voladj=0;
12 playcount=0;
13 lastplayed=0;
14 }
15
16 public void write(DataOutputStream w) throws IOException {
17 w.writeInt(file.getOffset());
18 w.writeInt(file.getHash());
19 w.writeShort(rating);
20 w.writeShort(voladj);
21 w.writeInt(playcount);
22 w.writeInt(lastplayed);
23 }
24
25 public static int entrySize() {
26 return 20;
27 }
28} \ 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 @@
1import java.util.*;
2import java.io.*;
3import java.lang.reflect.Array;
4
5/*
6 TreeSet for runtimedatabase with entry hash used in compareto
7 fix commandline interface.
8*/
9
10public class RuntimeDatabase {
11 protected static RuntimeDatabase instance=null;
12 protected TreeMap entries;
13 protected int entrycount;
14 public static final int headersize = 8;
15
16 protected RuntimeDatabase() {
17 entries=new TreeMap();
18 }
19
20 public static RuntimeDatabase getInstance() {
21 if(instance==null)
22 instance=new RuntimeDatabase();
23 return instance;
24 }
25
26 public RundbEntry getEntry(FileEntry file) {
27 Integer key = new Integer(file.getHash());
28 if(!entries.containsKey(key)) {
29 RundbEntry e = new RundbEntry(file);
30 entries.put(key,e);
31 return e;
32 }
33 else
34 return (RundbEntry)entries.get(key);
35 }
36
37 protected void calcOffsets() {
38 Collection values = entries.values();
39 Iterator i;
40 int offset=headersize;
41 i=values.iterator();
42 while(i.hasNext()) {
43 Entry e = (Entry) i.next();
44 e.setOffset(offset);
45 offset+=RundbEntry.entrySize();
46 }
47 entrycount=values.size();
48 }
49
50 public int isDirty() {
51 return 0;
52 }
53
54 protected void writeHeader(DataOutputStream w) throws IOException {
55 w.write('R');
56 w.write('R');
57 w.write('D');
58 w.write(0x1);
59 w.writeInt(entrycount);
60 }
61
62 public void prepareWrite() {
63 System.out.println("Calculating Runtime Database Offsets..");
64 calcOffsets();
65 }
66
67 public void writeDatabase(File f) throws IOException {
68 int x;
69 Iterator i;
70 DataOutputStream w = new DataOutputStream(new FileOutputStream(f));
71 System.out.println("Writing runtime database..");
72 writeHeader(w);
73 i=entries.values().iterator();
74 while(i.hasNext()) {
75 Entry e = (Entry) i.next();
76 e.write(w);
77 }
78 w.flush();
79 w.close();
80 }
81} \ 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 @@
1import java.io.*;
2import java.lang.reflect.Array;
3
4public class SongDB {
5
6 public static final void main(String[] args) {
7 TagDatabase td = TagDatabase.getInstance();
8 File tdfile = new File("rockbox.tagdb");
9 // RuntimeDatabase rd = RuntimeDatabase.getInstance();
10 int i = 0, j;
11 String arg,path = null;
12
13 while (i < args.length) {
14 arg = args[i++];
15 if (arg.equals("--dirisnotalbumname")) {
16 td.dirisalbumname=false;
17 }
18 else if(arg.equals("--dirisalbum")) {
19 td.dirisalbum=true;
20 }
21 else if(arg.equals("--dontshowduplicates")) {
22 td.showduplicates=false;
23 }
24 else if(arg.equals("--strip")) {
25 if (i < args.length)
26 td.strip = args[i++];
27 else {
28 System.err.println("--strip requires a path");
29 System.exit(0);
30 }
31 }
32 else if(arg.equals("--add")) {
33 if (i < args.length)
34 td.add = args[i++];
35 else {
36 System.err.println("--add requires a path");
37 System.exit(0);
38 }
39 }
40 else {
41 if(path!=null) {
42 System.err.println("you can't specify more than one path!");
43 System.exit(0);
44 }
45 path = arg;
46 }
47 }
48 if (i != args.length||path==null) {
49 System.out.println("Usage: SongDB [--showduplicates] [--strip <directory>] [--add <directory>] [--dirisnotalbumname] [--dirisalbum] <directory>");
50 return;
51 }
52 if(tdfile.exists()&&!tdfile.canWrite()) {
53 System.out.println("rockbox.tagdb is not writable.");
54 return;
55 }
56 try {
57 tdfile.createNewFile();
58 }
59 catch(Exception e) {
60 System.out.println("Error while trying to create rockbox.tagdb: "+e.getMessage());
61 return;
62 }
63 td.add(new File(path));
64 try {
65 td.prepareWrite();
66 // rd.prepareWrite();
67 td.writeDatabase(new File("rockbox.tagdb"));
68 // rd.writeDatabase(new File("rockbox.rundb"));
69 }
70 catch(IOException e) {
71 System.out.println(e);
72 }
73 }
74} \ 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 @@
1import java.util.*;
2import java.io.*;
3import javax.sound.sampled.UnsupportedAudioFileException;
4import java.lang.NumberFormatException;
5import net.shredzone.ifish.ltr.LTR;
6
7public class SongEntry extends Entry implements Comparable {
8 protected TagInfo info;
9 protected LTR tag;
10 protected ArtistEntry artist;
11 protected AlbumEntry album;
12 protected FileEntry file;
13
14 public SongEntry(FileEntry f) {
15 file=f;
16 file.setSongEntry(this);
17 readTagInfo();
18 }
19
20 public void setAlbum(AlbumEntry a) { album=a; }
21 public void setArtist(ArtistEntry a) { artist=a; }
22 public AlbumEntry getAlbum() { return album; }
23 public ArtistEntry getArtist() { return artist; }
24 public FileEntry getFile() { return file; }
25
26 public int compareTo(Object o) {
27 return String.CASE_INSENSITIVE_ORDER.compare(getName(),((SongEntry)o).getName());
28 }
29
30 public String getName() {
31 String title=tag.getTitle();
32 if(title==null)
33 title = stripExt(file.getFile().getName());
34 title=title.trim();
35 if(title.equals(""))
36 title = stripExt(file.getFile().getName());
37 return title;
38 }
39
40 public static String stripExt(String t) {
41 return t.substring(0,t.lastIndexOf('.'));
42 }
43
44 public String getAlbumTag() {
45 String album=tag.getAlbum();
46 if(album==null)
47 album = "<no album tag>";
48 album=album.trim();
49 if(album.equals(""))
50 album = "<no album tag>";
51 if(TagDatabase.getInstance().dirisalbumname&&album.equals("<no album tag>")) {
52 album = file.getFile().getParentFile().getName();
53 }
54 return album;
55 }
56
57 public String getArtistTag() {
58 String artist=tag.getArtist();
59 if(artist==null)
60 artist = "<no artist tag>";
61 artist=artist.trim();
62 if(artist.equals(""))
63 artist = "<no artist tag>";
64 return artist;
65 }
66
67 public String getGenreTag() {
68 String genre=tag.getGenre();
69 if(genre==null)
70 genre = "<no genre tag>";
71 genre=genre.trim();
72 if(genre.equals(""))
73 genre = "<no genre tag>";
74 return genre;
75 }
76
77 public int getYear() {
78 try {
79 return Integer.parseInt(tag.getYear());
80 } catch(NumberFormatException e) {
81 return 0;
82 }
83 }
84
85 public int getTrack() {
86 try {
87 return Integer.parseInt(tag.getTrack());
88 } catch(NumberFormatException e) {
89 return 0;
90 }
91 }
92
93 public int getBitRate() { if(info==null) return -1; return info.getBitRate()/1000; }
94
95 public int getPlayTime() { if(info==null) return -1; return (int)info.getPlayTime(); }
96
97 public int getSamplingRate() { if(info==null) return -1; return info.getSamplingRate(); }
98
99 public int getFirstFrameOffset() { if(info==null) return 0; return info.getFirstFrameOffset(); }
100
101 public boolean gotTagInfo() { return tag!=null; }
102
103 protected void readTagInfo() {
104 // Check Mpeg format.
105 try
106 {
107 info = new MpegInfo();
108 info.load(file.getFile());
109 }
110/* catch (IOException ex)
111 {
112 //ex.printStackTrace();
113 System.out.println(ex);
114 info = null;
115 }*/
116 catch (Exception ex)
117 {
118 // Error..
119 info = null;
120 }
121
122 if (info == null)
123 {
124 // Check Ogg Vorbis format.
125 try
126 {
127 info = new OggVorbisInfo();
128 info.load(file.getFile());
129 }
130 /*catch (IOException ex)
131 {
132 //ex.printStackTrace();
133 System.out.println(ex);
134 info = null;
135 }*/
136 catch (Exception ex)
137 {
138 // Not Ogg Vorbis Format
139 //System.out.println("Failed reading tag for "+location.getAbsolutePath()+", tried mp3 and vorbis.");
140 info = null;
141 }
142 }
143 tag = LTR.create(file.getFile());
144 }
145
146 public void write(DataOutputStream w) throws IOException {
147 String name=getName();
148 w.writeBytes(name);
149 for(int x=TagDatabase.getInstance().songlen-name.length();x>0;x--)
150 w.write(0);
151 w.writeInt(artist.getOffset());
152 w.writeInt(album.getOffset());
153 w.writeInt(file.getOffset());
154 w.writeBytes(getGenreTag());
155 for(int x=TagDatabase.getInstance().genrelen-getGenreTag().length();x>0;x--)
156 w.write(0);
157 w.writeShort(getBitRate());
158 w.writeShort(getYear());
159 w.writeInt(getPlayTime());
160 w.writeShort(getTrack());
161 w.writeShort(getSamplingRate());
162 }
163 public static int entrySize() {
164 TagDatabase td=TagDatabase.getInstance();
165 return td.songlen+12+td.genrelen+12;
166 }
167} \ 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 @@
1import java.util.*;
2import java.io.*;
3import java.lang.reflect.Array;
4
5/*
6 TreeSet for runtimedatabase with entry hash used in compareto
7 fix commandline interface.
8*/
9
10public class TagDatabase {
11 protected static TagDatabase instance=null;
12 protected TreeMap songs;
13 protected TreeMap files;
14 protected TreeMap filehashes;
15 protected TreeMap albums;
16 protected TreeMap artists;
17 protected int artiststart,albumstart,songstart,filestart;
18 protected int artistcount,albumcount,songcount,filecount;
19 public int artistlen,albumlen,songlen,genrelen,filelen,songarraylen,albumarraylen;
20 public String strip,add;
21 public boolean haveOldDatabase,dirisalbum,dirisalbumname,showduplicates;
22 protected Vector sortedsongs,sortedfiles,sortedalbums,sortedartists;
23
24 protected TagDatabase() {
25 songs=new TreeMap();
26 files=new TreeMap();
27 filehashes=new TreeMap();
28 albums=new TreeMap();
29 artists=new TreeMap();
30 strip=null;
31 add=null;
32 haveOldDatabase=false;
33 dirisalbum=false;
34 dirisalbumname=true;
35 showduplicates=true;
36 }
37
38 public static TagDatabase getInstance() {
39 if(instance==null)
40 instance=new TagDatabase();
41 return instance;
42 }
43
44 public void removeFileEntry(File file) {
45 String key = file.getAbsolutePath();
46 files.remove(key);
47 }
48
49 public FileEntry getFileEntry(File file) throws FileNotFoundException, IOException {
50 String key = file.getAbsolutePath();
51 if(!files.containsKey(key)) {
52 FileEntry f = new FileEntry(file);
53 files.put(key,f);
54 return f;
55 }
56 else
57 return (FileEntry)files.get(key);
58 }
59
60 public ArtistEntry getArtistEntry(String name) {
61 String key = name.toLowerCase();
62 if(!artists.containsKey(key)) {
63 ArtistEntry a = new ArtistEntry(name);
64 artists.put(key,a);
65 return a;
66 }
67 else
68 return (ArtistEntry)artists.get(key);
69 }
70
71 public String getAlbumKey(String name, String directory) {
72 if(dirisalbum)
73 return directory;
74 else
75 return name.toLowerCase()+"___"+directory;
76 }
77
78 public AlbumEntry getAlbumEntry(String name,String directory) {
79 String key = getAlbumKey(name,directory);
80 if(!albums.containsKey(key)) {
81 AlbumEntry a = new AlbumEntry(name);
82 albums.put(key,a);
83 return a;
84 }
85 else
86 return (AlbumEntry)albums.get(key);
87 }
88
89 public void removeSongEntry(FileEntry file) {
90 String key = file.getFilename();
91 songs.remove(key);
92 file.setSongEntry(null);
93 }
94
95 public SongEntry getSongEntry(FileEntry file) {
96 String key = file.getFilename();
97 if(!songs.containsKey(key)) {
98 SongEntry s = new SongEntry(file);
99 songs.put(key,s);
100 return s;
101 }
102 else
103 return (SongEntry)songs.get(key);
104 }
105
106 private class SongFilter implements FileFilter {
107 public boolean accept(File f) {
108 if(f.isDirectory()) // always accept directories.
109 return true;
110 String name=f.getName();
111 return name.endsWith(".mp3")||name.endsWith(".ogg");
112 }
113 }
114
115 public void add(File f) {
116 if(!f.isDirectory()) {
117 if(f.isFile()) {
118 addSong(f);
119 }
120 }
121 else {
122 File[] files = f.listFiles(new SongFilter());
123 int length=Array.getLength(files);
124 System.out.println(FileEntry.convertPath(f.getAbsolutePath()));
125 for(int i=0;i<length;i++) {
126 add(files[i]);
127 }
128 }
129 }
130
131 protected FileEntry addSong(File f) {
132 FileEntry file = null;
133 try {
134 file = getFileEntry(f);
135 }
136 catch(Exception e) {
137 return null;
138 }
139 SongEntry song = getSongEntry(file);
140 if(!song.gotTagInfo()) {
141 removeSongEntry(file);
142 return null;
143 }
144 ArtistEntry artist = getArtistEntry(song.getArtistTag());
145 AlbumEntry album = getAlbumEntry(song.getAlbumTag(),f.getParent());
146 album.setArtist(artist);
147 album.addSong(song);
148 return file;
149 }
150
151 protected int align(int len) {
152 while((len&3)!=0) len++;
153 return len;
154 }
155
156 protected void calcLimits() {
157 ArtistEntry longartist=null,longalbumarray=null;
158 AlbumEntry longalbum=null, longsongarray=null;
159 SongEntry longsong=null,longgenre=null;
160 FileEntry longfile=null;
161 Iterator i;
162 artistlen=0;
163 albumarraylen=0;
164 i=sortedartists.iterator();
165 while(i.hasNext()) {
166 ArtistEntry artist = (ArtistEntry) i.next();
167 int length=artist.getName().length();
168 int albumcount=artist.size();
169 if(length > artistlen) {
170 artistlen=align(length);
171 longartist=artist;
172 }
173 if(albumcount> albumarraylen) {
174 albumarraylen=albumcount;
175 longalbumarray=artist;
176 }
177 }
178 artistcount=sortedartists.size();
179 if(longartist!=null)
180 System.out.println("Artist with longest name ("+artistlen+") :"+longartist.getName());
181 if(longalbumarray!=null)
182 System.out.println("Artist with most albums ("+albumarraylen+") :"+longalbumarray.getName());
183 albumlen=0;
184 songarraylen=0;
185 i=sortedalbums.iterator();
186 while(i.hasNext()) {
187 AlbumEntry album = (AlbumEntry) i.next();
188 int length=album.getName().length();
189 int songcount=album.size();
190 if(length > albumlen) {
191 albumlen=align(length);
192 longalbum=album;
193 }
194 if(songcount> songarraylen) {
195 songarraylen=songcount;
196 longsongarray=album;
197 }
198 }
199 albumcount=sortedalbums.size();
200 if(longalbum!=null)
201 System.out.println("Album with longest name ("+albumlen+") :"+longalbum.getName());
202 if(longsongarray!=null)
203 System.out.println("Album with most songs ("+songarraylen+") :"+longsongarray.getName());
204 filelen=0;
205 i=sortedfiles.iterator();
206 while(i.hasNext()) {
207 FileEntry file = (FileEntry) i.next();
208 int length=file.getFilename().length();
209 if(length> filelen) {
210 filelen=align(length);
211 longfile=file;
212 }
213 }
214 filecount=sortedfiles.size();
215 if(longfile!=null)
216 System.out.println("File with longest filename ("+filelen+") :"+longfile.getFilename());
217 songlen=0;
218 genrelen=0;
219 i=sortedsongs.iterator();
220 while(i.hasNext()) {
221 SongEntry song = (SongEntry) i.next();
222 int tlength=song.getName().length();
223 int glength=song.getGenreTag().length();
224 if(tlength> songlen) {
225 songlen=align(tlength);
226 longsong=song;
227 }
228 if(glength> genrelen) {
229 genrelen=align(glength);
230 longgenre=song;
231 }
232 }
233 songcount=sortedsongs.size();
234 if(longsong!=null)
235 System.out.println("Song with longest name ("+songlen+") :"+longsong.getName());
236 if(longsong!=null)
237 System.out.println("Song with longest genre ("+genrelen+") :"+longgenre.getGenreTag());
238 System.out.println("Artistcount: "+artistcount);
239 System.out.println("Albumcount : "+albumcount);
240 System.out.println("Songcount : "+songcount);
241 System.out.println("Filecount : "+filecount);
242 artiststart=68;
243 albumstart=artiststart+artistcount*ArtistEntry.entrySize();
244 songstart=albumstart+albumcount*AlbumEntry.entrySize();
245 filestart=songstart+songcount*SongEntry.entrySize();
246 }
247
248 protected void calcOffsets() {
249 Iterator i;
250 int offset=artiststart;
251 i=sortedartists.iterator();
252 while(i.hasNext()) {
253 Entry e = (Entry) i.next();
254 e.setOffset(offset);
255 offset+=ArtistEntry.entrySize();
256 }
257// assert(offset==albumstart);
258 i=sortedalbums.iterator();
259 while(i.hasNext()) {
260 Entry e = (Entry) i.next();
261 e.setOffset(offset);
262 offset+=AlbumEntry.entrySize();
263 }
264// assert(offset==songstart);
265 i=sortedsongs.iterator();
266 while(i.hasNext()) {
267 Entry e = (Entry) i.next();
268 e.setOffset(offset);
269 offset+=SongEntry.entrySize();
270 }
271// assert(offset==filestart);
272 i=sortedfiles.iterator();
273 while(i.hasNext()) {
274 Entry e = (Entry) i.next();
275 e.setOffset(offset);
276 offset+=FileEntry.entrySize();
277 }
278 }
279
280 protected void calcHashes() {
281 Iterator i;
282 i=sortedfiles.iterator();
283 while(i.hasNext()) {
284 FileEntry file = (FileEntry) i.next();
285 Integer key = new Integer(file.getHash());
286 if(!filehashes.containsKey(key))
287 filehashes.put(key,file);
288 else {
289 System.out.println("Duplicate hash:");
290 System.out.println(((FileEntry)filehashes.get(key)).getFilename());
291 System.out.println(file.getFilename());
292 }
293 }
294 }
295
296 protected void writeHeader(DataOutputStream w) throws IOException {
297 w.write('R');
298 w.write('D');
299 w.write('B');
300 w.write(0x3);
301 w.writeInt(artiststart);
302 w.writeInt(albumstart);
303 w.writeInt(songstart);
304 w.writeInt(filestart);
305 w.writeInt(artistcount);
306 w.writeInt(albumcount);
307 w.writeInt(songcount);
308 w.writeInt(filecount);
309 w.writeInt(artistlen);
310 w.writeInt(albumlen);
311 w.writeInt(songlen);
312 w.writeInt(genrelen);
313 w.writeInt(filelen);
314 w.writeInt(songarraylen);
315 w.writeInt(albumarraylen);
316 w.writeInt(RuntimeDatabase.getInstance().isDirty());
317 }
318
319 public void prepareWrite() {
320 System.out.println("Sorting artists..");
321 sortedartists=new Vector();
322 sortedartists.addAll(artists.values());
323 Collections.sort(sortedartists);
324 System.out.println("Sorting albums..");
325 sortedalbums=new Vector();
326 sortedalbums.addAll(albums.values());
327 Collections.sort(sortedalbums);
328 System.out.println("Sorting songs..");
329 sortedsongs=new Vector();
330 sortedsongs.addAll(songs.values());
331 Collections.sort(sortedsongs);
332 System.out.println("Sorting files..");
333 sortedfiles=new Vector();
334 sortedfiles.addAll(files.values());
335 Collections.sort(sortedfiles);
336 System.out.println("Calculating tag database limits..");
337 calcLimits();
338 System.out.println("Calculating tag database offsets..");
339 calcOffsets();
340 if(showduplicates) {
341 System.out.println("Comparing file hashes..");
342 calcHashes();
343 }
344 }
345
346 public void writeDatabase(File f) throws IOException {
347 int x;
348 Iterator i;
349 DataOutputStream w = new DataOutputStream(new FileOutputStream(f));
350 System.out.println("Writing tag database..");
351 writeHeader(w);
352
353 i=sortedartists.iterator();
354 while(i.hasNext()) {
355 Entry e = (Entry) i.next();
356 e.write(w);
357 }
358 i=sortedalbums.iterator();
359 while(i.hasNext()) {
360 Entry e = (Entry) i.next();
361 e.write(w);
362 }
363 i=sortedsongs.iterator();
364 while(i.hasNext()) {
365 Entry e = (Entry) i.next();
366 e.write(w);
367 }
368 i=sortedfiles.iterator();
369 while(i.hasNext()) {
370 Entry e = (Entry) i.next();
371 e.write(w);
372 }
373 // done...
374 w.flush();
375 w.close();
376 }
377} \ 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 @@
1/*
2 * TagInfo.
3 *
4 * JavaZOOM : jlgui@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24import java.io.File;
25import java.io.IOException;
26import java.io.InputStream;
27import java.net.URL;
28import java.util.Vector;
29
30import javax.sound.sampled.UnsupportedAudioFileException;
31
32/**
33 * This interface define needed features for song information.
34 * Adapted from Scott Pennell interface.
35 */
36public interface TagInfo
37{
38
39 public void load(InputStream input) throws IOException, UnsupportedAudioFileException;
40
41 public void load(URL input) throws IOException, UnsupportedAudioFileException;
42
43 public void load(File input) throws IOException, UnsupportedAudioFileException;
44
45 /**
46 * Get Sampling Rate
47 * @return
48 */
49 public int getSamplingRate();
50
51 /**
52 * Get Nominal Bitrate
53 * @return bitrate in bps
54 */
55 public int getBitRate();
56
57 /**
58 * Get channels.
59 * @return channels
60 */
61 public int getChannels();
62
63 /**
64 * Get play time in seconds.
65 * @return
66 */
67 public long getPlayTime();
68
69 /**
70 * Get the title of the song.
71 * @return the title of the song
72 */
73 public String getTitle();
74
75 /**
76 * Get the artist that performed the song
77 * @return the artist that performed the song
78 */
79 public String getArtist();
80
81 /**
82 * Get the name of the album upon which the song resides
83 * @return the album name
84 */
85 public String getAlbum();
86
87 /**
88 * Get the track number of this track on the album
89 * @return the track number
90 */
91 public int getTrack();
92
93 /**
94 * Get the genre string of the music
95 * @return the genre string
96 */
97 public String getGenre();
98
99 /**
100 * Get the year the track was released
101 * @return the year the track was released
102 */
103 public String getYear();
104
105 /**
106 * Get any comments provided about the song
107 * @return the comments
108 */
109 public Vector getComment();
110
111 public int getFirstFrameOffset();
112} \ 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 @@
1javac -d classes -cp . -source 1.5 -target 1.5 `find -name '*.java'`
2jar 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 @@
1Manifest-Version: 1.0
2Created-By: Apache Ant 1.5.1
3Main-Class: SongDB
4
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 @@
1# for the javalayer mp3 decoder
2javazoom.spi.mpeg.sampled.file.MpegAudioFileReader
3# for the vorbis decoder
4javazoom.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 @@
1# for the javalayer mp3 decoder
2javazoom.spi.mpeg.sampled.convert.MpegFormatConversionProvider
3org.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 @@
1/* -*-mode:java; c-basic-offset:2; -*- */
2/* JOrbis
3 * Copyright (C) 2000 ymnk, JCraft,Inc.
4 *
5 * Written by: 2000 ymnk<ymnk@jcraft.com>
6 *
7 * Many thanks to
8 * Monty <monty@xiph.org> and
9 * The XIPHOPHORUS Company http://www.xiph.org/ .
10 * JOrbis has been based on their awesome works, Vorbis codec.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public License
14 * as published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27package com.jcraft.jogg;
28
29public class Buffer{
30 private static final int BUFFER_INCREMENT=256;
31
32 private static final int[] mask={
33 0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
34 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
35 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,
36 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
37 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff,
38 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
39 0x3fffffff,0x7fffffff,0xffffffff
40 };
41
42 int ptr=0;
43 byte[] buffer=null;
44 int endbit=0;
45 int endbyte=0;
46 int storage=0;
47
48 public void writeinit(){
49 buffer=new byte[BUFFER_INCREMENT];
50 ptr=0;
51 buffer[0]=(byte)'\0';
52 storage=BUFFER_INCREMENT;
53 }
54
55 public void write(byte[] s){
56 for(int i=0; i<s.length; i++){
57 if(s[i]==0)break;
58 write(s[i],8);
59 }
60 }
61
62 public void read(byte[] s, int bytes){
63 int i=0;
64 while(bytes--!=0){
65 s[i++]=(byte)(read(8));
66 }
67 }
68
69 void reset(){
70 ptr=0;
71 buffer[0]=(byte)'\0';
72 endbit=endbyte=0;
73 }
74
75 public void writeclear(){
76 buffer=null;
77 }
78
79 public void readinit(byte[] buf, int bytes){
80 readinit(buf, 0, bytes);
81 }
82
83 public void readinit(byte[] buf, int start, int bytes){
84//System.err.println("readinit: start="+start+", bytes="+bytes);
85//for(int i=0;i<bytes; i++){
86//System.err.println(i+": "+Integer.toHexString(buf[i+start]));
87//}
88 ptr=start;
89 buffer=buf;
90 endbit=endbyte=0;
91 storage=bytes;
92 }
93
94 public void write(int value, int bits){
95//System.err.println("write: "+Integer.toHexString(value)+", bits="+bits+" ptr="+ptr+", storage="+storage+", endbyte="+endbyte);
96 if(endbyte+4>=storage){
97 byte[] foo=new byte[storage+BUFFER_INCREMENT];
98 System.arraycopy(buffer, 0, foo, 0, storage);
99 buffer=foo;
100 storage+=BUFFER_INCREMENT;
101 }
102
103 value&=mask[bits];
104 bits+=endbit;
105 buffer[ptr]|=(byte)(value<<endbit);
106
107 if(bits>=8){
108 buffer[ptr+1]=(byte)(value>>>(8-endbit));
109 if(bits>=16){
110 buffer[ptr+2]=(byte)(value>>>(16-endbit));
111 if(bits>=24){
112 buffer[ptr+3]=(byte)(value>>>(24-endbit));
113 if(bits>=32){
114 if(endbit>0)
115 buffer[ptr+4]=(byte)(value>>>(32-endbit));
116 else
117 buffer[ptr+4]=0;
118 }
119 }
120 }
121 }
122
123 endbyte+=bits/8;
124 ptr+=bits/8;
125 endbit=bits&7;
126 }
127
128 public int look(int bits){
129 int ret;
130 int m=mask[bits];
131
132 bits+=endbit;
133
134//System.err.println("look ptr:"+ptr+", bits="+bits+", endbit="+endbit+", storage="+storage);
135
136 if(endbyte+4>=storage){
137 if(endbyte+(bits-1)/8>=storage)return(-1);
138 }
139
140 ret=((buffer[ptr])&0xff)>>>endbit;
141// ret=((byte)(buffer[ptr]))>>>endbit;
142 if(bits>8){
143 ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
144// ret|=((byte)(buffer[ptr+1]))<<(8-endbit);
145 if(bits>16){
146 ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
147// ret|=((byte)(buffer[ptr+2]))<<(16-endbit);
148 if(bits>24){
149 ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
150//System.err.print("ret="+Integer.toHexString(ret)+", ((byte)(buffer[ptr+3]))="+Integer.toHexString(((buffer[ptr+3])&0xff)));
151// ret|=((byte)(buffer[ptr+3]))<<(24-endbit);
152//System.err.println(" ->ret="+Integer.toHexString(ret));
153 if(bits>32 && endbit!=0){
154 ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
155// ret|=((byte)(buffer[ptr+4]))<<(32-endbit);
156 }
157 }
158 }
159 }
160 return(m&ret);
161 }
162
163 public int look1(){
164 if(endbyte>=storage)return(-1);
165 return((buffer[ptr]>>endbit)&1);
166 }
167
168 public void adv(int bits){
169 bits+=endbit;
170 ptr+=bits/8;
171 endbyte+=bits/8;
172 endbit=bits&7;
173 }
174
175 public void adv1(){
176 ++endbit;
177 if(endbit>7){
178 endbit=0;
179 ptr++;
180 endbyte++;
181 }
182 }
183
184 public int read(int bits){
185//System.err.println(this+" read: bits="+bits+", storage="+storage+", endbyte="+endbyte);
186//System.err.println(this+" read: bits="+bits+", storage="+storage+", endbyte="+endbyte+
187// ", ptr="+ptr+", endbit="+endbit+", buf[ptr]="+buffer[ptr]);
188
189 int ret;
190 int m=mask[bits];
191
192 bits+=endbit;
193
194 if(endbyte+4>=storage){
195 ret=-1;
196 if(endbyte+(bits-1)/8>=storage){
197 ptr+=bits/8;
198 endbyte+=bits/8;
199 endbit=bits&7;
200 return(ret);
201 }
202 }
203
204/*
205 ret=(byte)(buffer[ptr]>>>endbit);
206 if(bits>8){
207 ret|=(buffer[ptr+1]<<(8-endbit));
208 if(bits>16){
209 ret|=(buffer[ptr+2]<<(16-endbit));
210 if(bits>24){
211 ret|=(buffer[ptr+3]<<(24-endbit));
212 if(bits>32 && endbit>0){
213 ret|=(buffer[ptr+4]<<(32-endbit));
214 }
215 }
216 }
217 }
218*/
219 ret=((buffer[ptr])&0xff)>>>endbit;
220 if(bits>8){
221 ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
222// ret|=((byte)(buffer[ptr+1]))<<(8-endbit);
223 if(bits>16){
224 ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
225// ret|=((byte)(buffer[ptr+2]))<<(16-endbit);
226 if(bits>24){
227 ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
228// ret|=((byte)(buffer[ptr+3]))<<(24-endbit);
229 if(bits>32 && endbit!=0){
230 ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
231// ret|=((byte)(buffer[ptr+4]))<<(32-endbit);
232 }
233 }
234 }
235 }
236
237 ret&=m;
238
239 ptr+=bits/8;
240// ptr=bits/8;
241 endbyte+=bits/8;
242// endbyte=bits/8;
243 endbit=bits&7;
244 return(ret);
245 }
246
247 public int readB(int bits){
248 //System.err.println(this+" read: bits="+bits+", storage="+storage+", endbyte="+endbyte+
249 // ", ptr="+ptr+", endbit="+endbit+", buf[ptr]="+buffer[ptr]);
250 int ret;
251 int m=32-bits;
252
253 bits+=endbit;
254
255 if(endbyte+4>=storage){
256 /* not the main path */
257 ret=-1;
258 if(endbyte*8+bits>storage*8) {
259 ptr+=bits/8;
260 endbyte+=bits/8;
261 endbit=bits&7;
262 return(ret);
263 }
264 }
265
266 ret=(buffer[ptr]&0xff)<<(24+endbit);
267 if(bits>8){
268 ret|=(buffer[ptr+1]&0xff)<<(16+endbit);
269 if(bits>16){
270 ret|=(buffer[ptr+2]&0xff)<<(8+endbit);
271 if(bits>24){
272 ret|=(buffer[ptr+3]&0xff)<<(endbit);
273 if(bits>32 && (endbit != 0))
274 ret|=(buffer[ptr+4]&0xff)>>(8-endbit);
275 }
276 }
277 }
278 ret=(ret>>>(m>>1))>>>((m+1)>>1);
279
280 ptr+=bits/8;
281 endbyte+=bits/8;
282 endbit=bits&7;
283 return(ret);
284 }
285
286 public int read1(){
287 int ret;
288 if(endbyte>=storage){
289 ret=-1;
290 endbit++;
291 if(endbit>7){
292 endbit=0;
293 ptr++;
294 endbyte++;
295 }
296 return(ret);
297 }
298
299 ret=(buffer[ptr]>>endbit)&1;
300
301 endbit++;
302 if(endbit>7){
303 endbit=0;
304 ptr++;
305 endbyte++;
306 }
307 return(ret);
308 }
309
310 public int bytes(){
311 return(endbyte+(endbit+7)/8);
312 }
313
314 public int bits(){
315 return(endbyte*8+endbit);
316 }
317
318 public byte[] buffer(){
319 return(buffer);
320 }
321
322 public static int ilog(int v){
323 int ret=0;
324 while(v>0){
325 ret++;
326 v>>>=1;
327 }
328 return(ret);
329 }
330
331 public static void report(String in){
332 System.err.println(in);
333 System.exit(1);
334 }
335
336 /*
337 static void cliptest(int[] b, int vals, int bits, int[] comp, int compsize){
338 int bytes;
339 byte[] buffer;
340
341 o.reset();
342 for(int i=0;i<vals;i++){
343 o.write(b[i],((bits!=0)?bits:ilog(b[i])));
344 }
345 buffer=o.buffer();
346 bytes=o.bytes();
347System.err.println("cliptest: bytes="+bytes);
348 if(bytes!=compsize)report("wrong number of bytes!\n");
349 for(int i=0;i<bytes;i++){
350 if(buffer[i]!=(byte)comp[i]){
351 for(int j=0;j<bytes;j++){
352 System.err.println(j+": "+Integer.toHexString(buffer[j])+" "+
353 Integer.toHexString(comp[j]));
354 }
355 report("wrote incorrect value!\n");
356 }
357 }
358System.err.println("bits: "+bits);
359 r.readinit(buffer,bytes);
360 for(int i=0;i<vals;i++){
361 int tbit=(bits!=0)?bits:ilog(b[i]);
362System.err.println(Integer.toHexString(b[i])+" tbit: "+tbit);
363 if(r.look(tbit)==-1){
364 report("out of data!\n");
365 }
366 if(r.look(tbit)!=(b[i]&mask[tbit])){
367 report(i+" looked at incorrect value! "+Integer.toHexString(r.look(tbit))+", "+Integer.toHexString(b[i]&mask[tbit])+":"+b[i]+" bit="+tbit);
368 }
369 if(tbit==1){
370 if(r.look1()!=(b[i]&mask[tbit])){
371 report("looked at single bit incorrect value!\n");
372 }
373 }
374 if(tbit==1){
375 if(r.read1()!=(b[i]&mask[tbit])){
376 report("read incorrect single bit value!\n");
377 }
378 }
379 else{
380 if(r.read(tbit)!=(b[i]&mask[tbit])){
381 report("read incorrect value!\n");
382 }
383 }
384 }
385 if(r.bytes()!=bytes){
386 report("leftover bytes after read!\n");
387 }
388 }
389
390 static int[] testbuffer1=
391 {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
392 567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
393 static int test1size=43;
394
395 static int[] testbuffer2=
396 {216531625,1237861823,56732452,131,3212421,12325343,34547562,12313212,
397 1233432,534,5,346435231,14436467,7869299,76326614,167548585,
398 85525151,0,12321,1,349528352};
399 static int test2size=21;
400
401 static int[] large=
402 {2136531625,2137861823,56732452,131,3212421,12325343,34547562,12313212,
403 1233432,534,5,2146435231,14436467,7869299,76326614,167548585,
404 85525151,0,12321,1,2146528352};
405
406 static int[] testbuffer3=
407 {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,
408 0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1};
409 static int test3size=56;
410
411 static int onesize=33;
412 static int[] one={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40,
413 34,242,223,136,35,222,211,86,171,50,225,135,214,75,172,
414 223,4};
415
416 static int twosize=6;
417 static int[] two={61,255,255,251,231,29};
418
419 static int threesize=54;
420 static int[] three={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254,
421 142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83,
422 58,135,196,61,55,129,183,54,101,100,170,37,127,126,10,
423 100,52,4,14,18,86,77,1};
424
425 static int foursize=38;
426 static int[] four={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72,
427 132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169,
428 28,2,133,0,1};
429
430 static int fivesize=45;
431 static int[] five={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62,
432 241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169,
433 84,75,159,2,1,0,132,192,8,0,0,18,22};
434
435 static int sixsize=7;
436 static int[] six={17,177,170,242,169,19,148};
437
438 static Buffer o=new Buffer();
439 static Buffer r=new Buffer();
440
441 public static void main(String[] arg){
442 byte[] buffer;
443 int bytes;
444// o=new Buffer();
445// r=new Buffer();
446
447 o.writeinit();
448
449 System.err.print("\nSmall preclipped packing: ");
450 cliptest(testbuffer1,test1size,0,one,onesize);
451 System.err.print("ok.");
452
453 System.err.print("\nNull bit call: ");
454 cliptest(testbuffer3,test3size,0,two,twosize);
455 System.err.print("ok.");
456
457 System.err.print("\nLarge preclipped packing: ");
458 cliptest(testbuffer2,test2size,0,three,threesize);
459 System.err.print("ok.");
460
461 System.err.print("\n32 bit preclipped packing: ");
462 o.reset();
463 for(int i=0;i<test2size;i++)
464 o.write(large[i],32);
465 buffer=o.buffer();
466 bytes=o.bytes();
467
468
469 r.readinit(buffer,bytes);
470 for(int i=0;i<test2size;i++){
471 if(r.look(32)==-1){
472 report("out of data. failed!");
473 }
474 if(r.look(32)!=large[i]){
475 System.err.print(r.look(32)+" != "+large[i]+" ("+
476 Integer.toHexString(r.look(32))+"!="+
477 Integer.toHexString(large[i])+")");
478 report("read incorrect value!\n");
479 }
480 r.adv(32);
481 }
482 if(r.bytes()!=bytes)report("leftover bytes after read!\n");
483 System.err.print("ok.");
484
485 System.err.print("\nSmall unclipped packing: ");
486 cliptest(testbuffer1,test1size,7,four,foursize);
487 System.err.print("ok.");
488
489 System.err.print("\nLarge unclipped packing: ");
490 cliptest(testbuffer2,test2size,17,five,fivesize);
491 System.err.print("ok.");
492
493 System.err.print("\nSingle bit unclicpped packing: ");
494 cliptest(testbuffer3,test3size,1,six,sixsize);
495 System.err.print("ok.");
496
497 System.err.print("\nTesting read past end: ");
498 r.readinit("\0\0\0\0\0\0\0\0".getBytes(),8);
499 for(int i=0;i<64;i++){
500 if(r.read(1)!=0){
501 System.err.print("failed; got -1 prematurely.\n");
502 System.exit(1);
503 }
504 }
505
506 if(r.look(1)!=-1 ||
507 r.read(1)!=-1){
508 System.err.print("failed; read past end without -1.\n");
509 System.exit(1);
510 }
511
512 r.readinit("\0\0\0\0\0\0\0\0".getBytes(),8);
513 if(r.read(30)!=0 || r.read(16)!=0){
514 System.err.print("failed 2; got -1 prematurely.\n");
515 System.exit(1);
516 }
517
518 if(r.look(18)!=0 ||
519 r.look(18)!=0){
520 System.err.print("failed 3; got -1 prematurely.\n");
521 System.exit(1);
522 }
523 if(r.look(19)!=-1 ||
524 r.look(19)!=-1){
525 System.err.print("failed; read past end without -1.\n");
526 System.exit(1);
527 }
528 if(r.look(32)!=-1 ||
529 r.look(32)!=-1){
530 System.err.print("failed; read past end without -1.\n");
531 System.exit(1);
532 }
533 System.err.print("ok.\n\n");
534 }
535 */
536}
537
538
539
540
541
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jogg;
27
28public class Packet{
29 public byte[] packet_base;
30 public int packet;
31 public int bytes;
32 public int b_o_s;
33 public int e_o_s;
34
35 public long granulepos;
36
37 public long packetno; // sequence number for decode; the framing
38 // knows where there's a hole in the data,
39 // but we need coupling so that the codec
40 // (which is in a seperate abstraction
41 // layer) also knows about the gap
42
43 /*
44 // TEST
45 static int sequence=0;
46 static int lastno=0;
47 void checkpacket(int len, int no, int pos){
48 if(bytes!=len){
49 System.err.println("incorrect packet length!");
50 System.exit(1);
51 }
52 if(granulepos!=pos){
53 System.err.println("incorrect packet position!");
54 System.exit(1);
55 }
56
57 // packet number just follows sequence/gap; adjust the input number
58 // for that
59 if(no==0){
60 sequence=0;
61 }
62 else{
63 sequence++;
64 if(no>lastno+1)
65 sequence++;
66 }
67 lastno=no;
68 if(packetno!=sequence){
69 System.err.println("incorrect packet sequence "+packetno+" != "+sequence);
70 System.exit(1);
71 }
72
73 // Test data
74 for(int j=0;j<bytes;j++){
75 if((packet_base[packet+j]&0xff)!=((j+no)&0xff)){
76 System.err.println("body data mismatch at pos "+ j+": "+(packet_base[packet+j]&0xff)+"!="+((j+no)&0xff)+"!\n");
77 System.exit(1);
78 }
79 }
80 }
81 */
82}
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 @@
1/* -*-mode:java; c-basic-offset:2; -*- */
2/* JOrbis
3 * Copyright (C) 2000 ymnk, JCraft,Inc.
4 *
5 * Written by: 2000 ymnk<ymnk@jcraft.com>
6 *
7 * Many thanks to
8 * Monty <monty@xiph.org> and
9 * The XIPHOPHORUS Company http://www.xiph.org/ .
10 * JOrbis has been based on their awesome works, Vorbis codec.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public License
14 * as published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27package com.jcraft.jogg;
28
29public class Page{
30 private static int[] crc_lookup=new int[256];
31 static {
32 for(int i=0; i<crc_lookup.length; i++){
33 crc_lookup[i]=crc_entry(i);
34 }
35 }
36
37 private static int crc_entry(int index){
38 int r=index<<24;
39 for(int i=0; i<8; i++){
40 if((r& 0x80000000)!=0){
41 r=(r << 1)^0x04c11db7; /* The same as the ethernet generator
42 polynomial, although we use an
43 unreflected alg and an init/final
44 of 0, not 0xffffffff */
45 }
46 else{
47 r<<=1;
48 }
49 }
50 return(r&0xffffffff);
51 }
52
53 public byte[] header_base;
54 public int header;
55 public int header_len;
56 public byte[] body_base;
57 public int body;
58 public int body_len;
59
60 int version(){
61 return header_base[header+4]&0xff;
62 }
63 int continued(){
64 return (header_base[header+5]&0x01);
65 }
66 public int bos(){
67 return (header_base[header+5]&0x02);
68 }
69 public int eos(){
70 return (header_base[header+5]&0x04);
71 }
72 public long granulepos(){
73 long foo=header_base[header+13]&0xff;
74 foo=(foo<<8)|(header_base[header+12]&0xff);
75 foo=(foo<<8)|(header_base[header+11]&0xff);
76 foo=(foo<<8)|(header_base[header+10]&0xff);
77 foo=(foo<<8)|(header_base[header+9]&0xff);
78 foo=(foo<<8)|(header_base[header+8]&0xff);
79 foo=(foo<<8)|(header_base[header+7]&0xff);
80 foo=(foo<<8)|(header_base[header+6]&0xff);
81 return(foo);
82 }
83 public int serialno(){
84 return (header_base[header+14]&0xff)|
85 ((header_base[header+15]&0xff)<<8)|
86 ((header_base[header+16]&0xff)<<16)|
87 ((header_base[header+17]&0xff)<<24);
88 }
89 int pageno(){
90 return (header_base[header+18]&0xff)|
91 ((header_base[header+19]&0xff)<<8)|
92 ((header_base[header+20]&0xff)<<16)|
93 ((header_base[header+21]&0xff)<<24);
94 }
95
96 void checksum(){
97 int crc_reg=0;
98
99// for(int i=0;i<header_len;i++){
100// System.err.println("chksum: "+Integer.toHexString(header_base[header+i]&0xff));
101// }
102
103 for(int i=0;i<header_len;i++){
104 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg>>>24)&0xff)^(header_base[header+i]&0xff)];
105 }
106 for(int i=0;i<body_len;i++){
107 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg>>>24)&0xff)^(body_base[body+i]&0xff)];
108 }
109 header_base[header+22]=(byte)crc_reg/*&0xff*/;
110 header_base[header+23]=(byte)(crc_reg>>>8)/*&0xff*/;
111 header_base[header+24]=(byte)(crc_reg>>>16)/*&0xff*/;
112 header_base[header+25]=(byte)(crc_reg>>>24)/*&0xff*/;
113 }
114 public Page copy(){
115 return copy(new Page());
116 }
117 public Page copy(Page p){
118 byte[] tmp=new byte[header_len];
119 System.arraycopy(header_base, header, tmp, 0, header_len);
120 p.header_len=header_len;
121 p.header_base=tmp;
122 p.header=0;
123 tmp=new byte[body_len];
124 System.arraycopy(body_base, body, tmp, 0, body_len);
125 p.body_len=body_len;
126 p.body_base=tmp;
127 p.body=0;
128 return p;
129 }
130 /*
131 // TEST
132 static StreamState os_en, os_de;
133 static SyncState oy;
134 void check_page(byte[] data_base, int data, int[] _header){
135 // Test data
136 for(int j=0;j<body_len;j++)
137 if(body_base[body+j]!=data_base[data+j]){
138 System.err.println("body data mismatch at pos "+j+": "+data_base[data+j]+"!="+body_base[body+j]+"!\n");
139 System.exit(1);
140 }
141
142 // Test header
143 for(int j=0;j<header_len;j++){
144 if((header_base[header+j]&0xff)!=_header[j]){
145 System.err.println("header content mismatch at pos "+j);
146 for(int jj=0;jj<_header[26]+27;jj++)
147 System.err.print(" ("+jj+")"+Integer.toHexString(_header[jj])+":"+Integer.toHexString(header_base[header+jj]));
148 System.err.println("");
149 System.exit(1);
150 }
151 }
152 if(header_len!=_header[26]+27){
153 System.err.print("header length incorrect! ("+header_len+"!="+(_header[26]+27)+")");
154 System.exit(1);
155 }
156 }
157
158 void print_header(){
159 System.err.println("\nHEADER:");
160 System.err.println(" capture: "+
161 (header_base[header+0]&0xff)+" "+
162 (header_base[header+1]&0xff)+" "+
163 (header_base[header+2]&0xff)+" "+
164 (header_base[header+3]&0xff)+" "+
165 " version: "+(header_base[header+4]&0xff)+" flags: "+
166 (header_base[header+5]&0xff));
167 System.err.println(" pcmpos: "+
168 (((header_base[header+9]&0xff)<<24)|
169 ((header_base[header+8]&0xff)<<16)|
170 ((header_base[header+7]&0xff)<<8)|
171 ((header_base[header+6]&0xff)))+
172 " serialno: "+
173 (((header_base[header+17]&0xff)<<24)|
174 ((header_base[header+16]&0xff)<<16)|
175 ((header_base[header+15]&0xff)<<8)|
176 ((header_base[header+14]&0xff)))+
177 " pageno: "+
178 (((header_base[header+21]&0xff)<<24)|
179 ((header_base[header+20]&0xff)<<16)|
180 ((header_base[header+19]&0xff)<<8)|
181 ((header_base[header+18]&0xff))));
182
183 System.err.println(" checksum: "+
184 (header_base[header+22]&0xff)+":"+
185 (header_base[header+23]&0xff)+":"+
186 (header_base[header+24]&0xff)+":"+
187 (header_base[header+25]&0xff)+"\n segments: "+
188 (header_base[header+26]&0xff)+" (");
189 for(int j=27;j<header_len;j++){
190 System.err.println((header_base[header+j]&0xff)+" ");
191 }
192 System.err.println(")\n");
193 }
194
195 void copy_page(){
196 byte[] tmp=new byte[header_len];
197 System.arraycopy(header_base, header, tmp, 0, header_len);
198 header_base=tmp;
199 header=0;
200 tmp=new byte[body_len];
201 System.arraycopy(body_base, body, tmp, 0, body_len);
202 body_base=tmp;
203 body=0;
204 }
205
206 static void test_pack(int[] pl, int[][] headers){
207 byte[] data=new byte[1024*1024]; // for scripted test cases only
208 int inptr=0;
209 int outptr=0;
210 int deptr=0;
211 int depacket=0;
212 int pcm_pos=7;
213 int packets,pageno=0,pageout=0;
214 int eosflag=0;
215 int bosflag=0;
216
217 os_en.reset();
218 os_de.reset();
219 oy.reset();
220
221 for(packets=0;;packets++){
222 if(pl[packets]==-1)break;
223 }
224
225 for(int i=0;i<packets;i++){
226 // construct a test packet
227 Packet op=new Packet();
228 int len=pl[i];
229 op.packet_base=data;
230 op.packet=inptr;
231 op.bytes=len;
232 op.e_o_s=(pl[i+1]<0?1:0);
233 op.granulepos=pcm_pos;
234
235 pcm_pos+=1024;
236
237 for(int j=0;j<len;j++){
238 data[inptr++]=(byte)(i+j);
239 }
240
241 // submit the test packet
242 os_en.packetin(op);
243
244 // retrieve any finished pages
245 {
246 Page og=new Page();
247
248 while(os_en.pageout(og)!=0){
249 // We have a page. Check it carefully
250 //System.err.print(pageno+", ");
251 if(headers[pageno]==null){
252 System.err.println("coded too many pages!");
253 System.exit(1);
254 }
255 og.check_page(data, outptr, headers[pageno]);
256
257 outptr+=og.body_len;
258 pageno++;
259
260//System.err.println("1# pageno="+pageno+", pageout="+pageout);
261
262 // have a complete page; submit it to sync/decode
263
264 {
265 Page og_de=new Page();
266 Packet op_de=new Packet();
267 int index=oy.buffer(og.header_len+og.body_len);
268 byte[] buf=oy.data;
269 System.arraycopy(og.header_base, og.header, buf, index, og.header_len);
270 System.arraycopy(og.body_base, og.body, buf, index+og.header_len, og.body_len);
271 oy.wrote(og.header_len+og.body_len);
272
273//System.err.println("2# pageno="+pageno+", pageout="+pageout);
274
275 while(oy.pageout(og_de)>0){
276 // got a page. Happy happy. Verify that it's good.
277
278 og_de.check_page(data, deptr, headers[pageout]);
279 deptr+=og_de.body_len;
280 pageout++;
281
282 // submit it to deconstitution
283 os_de.pagein(og_de);
284
285 // packets out?
286 while(os_de.packetout(op_de)>0){
287
288 // verify the packet!
289 // check data
290 boolean check=false;
291 for(int ii=0; ii<op_de.bytes; ii++){
292 if(data[depacket+ii]!=op_de.packet_base[op_de.packet+ii]){
293 check=true;
294 break;
295 }
296 }
297 if(check){
298 System.err.println("packet data mismatch in decode! pos="+
299 depacket);
300 System.exit(1);
301 }
302
303 // check bos flag
304 if(bosflag==0 && op_de.b_o_s==0){
305 System.err.println("b_o_s flag not set on packet!");
306 System.exit(1);
307 }
308 if(bosflag!=0 && op_de.b_o_s!=0){
309 System.err.println("b_o_s flag incorrectly set on packet!");
310 System.exit(1);
311 }
312
313 bosflag=1;
314 depacket+=op_de.bytes;
315
316 // check eos flag
317 if(eosflag!=0){
318 System.err.println("Multiple decoded packets with eos flag!");
319 System.exit(1);
320 }
321
322 if(op_de.e_o_s!=0)eosflag=1;
323
324 // check pcmpos flag
325 if(op_de.granulepos!=-1){
326 System.err.print(" pcm:"+op_de.granulepos+" ");
327 }
328 }
329 }
330 }
331 }
332 }
333 }
334 //free(data);
335 if(headers[pageno]!=null){
336 System.err.println("did not write last page!");
337 System.exit(1);
338 }
339 if(headers[pageout]!=null){
340 System.err.println("did not decode last page!");
341 System.exit(1);
342 }
343 if(inptr!=outptr){
344 System.err.println("encoded page data incomplete!");
345 System.exit(1);
346 }
347 if(inptr!=deptr){
348 System.err.println("decoded page data incomplete!");
349 System.exit(1);
350 }
351 if(inptr!=depacket){
352 System.err.println("decoded packet data incomplete!");
353 System.exit(1);
354 }
355 if(eosflag==0){
356 System.err.println("Never got a packet with EOS set!");
357 }
358 System.err.println("ok.");
359 }
360
361 static void error(){
362 System.err.println("error!");
363 System.exit(1);
364 }
365 public static void main(String[] arg){
366
367 os_en=new StreamState(0x04030201);
368 os_de=new StreamState(0x04030201);
369
370 oy=new SyncState();
371
372 // Exercise each code path in the framing code. Also verify that
373 // the checksums are working.
374
375 {
376 // 17 only
377 int[] packets={17, -1};
378 int[] head1={0x4f,0x67,0x67,0x53,0,0x06,
379 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
380 0x01,0x02,0x03,0x04,0,0,0,0,
381 0x15,0xed,0xec,0x91,
382 1,
383 17};
384 int[][] headret={head1, null};
385
386 System.err.print("testing single page encoding... ");
387 test_pack(packets,headret);
388 }
389
390 {
391 // 17, 254, 255, 256, 500, 510, 600 byte, pad
392 int[] packets={17, 254, 255, 256, 500, 510, 600, -1};
393 int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
394 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
395 0x01,0x02,0x03,0x04,0,0,0,0,
396 0x59,0x10,0x6c,0x2c,
397 1,
398 17};
399 int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
400 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
401 0x01,0x02,0x03,0x04,1,0,0,0,
402 0x89,0x33,0x85,0xce,
403 13,
404 254,255,0,255,1,255,245,255,255,0,
405 255,255,90};
406 int[][] headret={head1,head2,null};
407
408 System.err.print("testing basic page encoding... ");
409 test_pack(packets,headret);
410 }
411
412 {
413 // nil packets; beginning,middle,end
414 int[] packets={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
415
416 int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
417 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
418 0x01,0x02,0x03,0x04,0,0,0,0,
419 0xff,0x7b,0x23,0x17,
420 1,
421 0};
422 int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
423 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
424 0x01,0x02,0x03,0x04,1,0,0,0,
425 0x5c,0x3f,0x66,0xcb,
426 17,
427 17,254,255,0,0,255,1,0,255,245,255,255,0,
428 255,255,90,0};
429 int[][] headret={head1,head2,null};
430
431 System.err.print("testing basic nil packets... ");
432 test_pack(packets,headret);
433 }
434
435 {
436 // large initial packet
437 int[] packets={4345,259,255,-1};
438
439 int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
440 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
441 0x01,0x02,0x03,0x04,0,0,0,0,
442 0x01,0x27,0x31,0xaa,
443 18,
444 255,255,255,255,255,255,255,255,
445 255,255,255,255,255,255,255,255,255,10};
446
447 int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
448 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
449 0x01,0x02,0x03,0x04,1,0,0,0,
450 0x7f,0x4e,0x8a,0xd2,
451 4,
452 255,4,255,0};
453 int[][] headret={head1,head2,null};
454
455 System.err.print("testing initial-packet lacing > 4k... ");
456 test_pack(packets,headret);
457 }
458
459 {
460 // continuing packet test
461 int[] packets={0,4345,259,255,-1};
462
463 int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
464 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
465 0x01,0x02,0x03,0x04,0,0,0,0,
466 0xff,0x7b,0x23,0x17,
467 1,
468 0};
469
470 int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
471 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
472 0x01,0x02,0x03,0x04,1,0,0,0,
473 0x34,0x24,0xd5,0x29,
474 17,
475 255,255,255,255,255,255,255,255,
476 255,255,255,255,255,255,255,255,255};
477
478 int[] head3={0x4f,0x67,0x67,0x53,0,0x05,
479 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
480 0x01,0x02,0x03,0x04,2,0,0,0,
481 0xc8,0xc3,0xcb,0xed,
482 5,
483 10,255,4,255,0};
484 int[][] headret={head1,head2,head3,null};
485
486 System.err.print("testing single packet page span... ");
487 test_pack(packets,headret);
488 }
489
490 // page with the 255 segment limit
491 {
492
493 int[] packets={0,10,10,10,10,10,10,10,10,
494 10,10,10,10,10,10,10,10,
495 10,10,10,10,10,10,10,10,
496 10,10,10,10,10,10,10,10,
497 10,10,10,10,10,10,10,10,
498 10,10,10,10,10,10,10,10,
499 10,10,10,10,10,10,10,10,
500 10,10,10,10,10,10,10,10,
501 10,10,10,10,10,10,10,10,
502 10,10,10,10,10,10,10,10,
503 10,10,10,10,10,10,10,10,
504 10,10,10,10,10,10,10,10,
505 10,10,10,10,10,10,10,10,
506 10,10,10,10,10,10,10,10,
507 10,10,10,10,10,10,10,10,
508 10,10,10,10,10,10,10,10,
509 10,10,10,10,10,10,10,10,
510 10,10,10,10,10,10,10,10,
511 10,10,10,10,10,10,10,10,
512 10,10,10,10,10,10,10,10,
513 10,10,10,10,10,10,10,10,
514 10,10,10,10,10,10,10,10,
515 10,10,10,10,10,10,10,10,
516 10,10,10,10,10,10,10,10,
517 10,10,10,10,10,10,10,10,
518 10,10,10,10,10,10,10,10,
519 10,10,10,10,10,10,10,10,
520 10,10,10,10,10,10,10,10,
521 10,10,10,10,10,10,10,10,
522 10,10,10,10,10,10,10,10,
523 10,10,10,10,10,10,10,10,
524 10,10,10,10,10,10,10,50,-1};
525
526 int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
527 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
528 0x01,0x02,0x03,0x04,0,0,0,0,
529 0xff,0x7b,0x23,0x17,
530 1,
531 0};
532
533 int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
534 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
535 0x01,0x02,0x03,0x04,1,0,0,0,
536 0xed,0x2a,0x2e,0xa7,
537 255,
538 10,10,10,10,10,10,10,10,
539 10,10,10,10,10,10,10,10,
540 10,10,10,10,10,10,10,10,
541 10,10,10,10,10,10,10,10,
542 10,10,10,10,10,10,10,10,
543 10,10,10,10,10,10,10,10,
544 10,10,10,10,10,10,10,10,
545 10,10,10,10,10,10,10,10,
546 10,10,10,10,10,10,10,10,
547 10,10,10,10,10,10,10,10,
548 10,10,10,10,10,10,10,10,
549 10,10,10,10,10,10,10,10,
550 10,10,10,10,10,10,10,10,
551 10,10,10,10,10,10,10,10,
552 10,10,10,10,10,10,10,10,
553 10,10,10,10,10,10,10,10,
554 10,10,10,10,10,10,10,10,
555 10,10,10,10,10,10,10,10,
556 10,10,10,10,10,10,10,10,
557 10,10,10,10,10,10,10,10,
558 10,10,10,10,10,10,10,10,
559 10,10,10,10,10,10,10,10,
560 10,10,10,10,10,10,10,10,
561 10,10,10,10,10,10,10,10,
562 10,10,10,10,10,10,10,10,
563 10,10,10,10,10,10,10,10,
564 10,10,10,10,10,10,10,10,
565 10,10,10,10,10,10,10,10,
566 10,10,10,10,10,10,10,10,
567 10,10,10,10,10,10,10,10,
568 10,10,10,10,10,10,10,10,
569 10,10,10,10,10,10,10};
570
571 int[] head3={0x4f,0x67,0x67,0x53,0,0x04,
572 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
573 0x01,0x02,0x03,0x04,2,0,0,0,
574 0x6c,0x3b,0x82,0x3d,
575 1,
576 50};
577 int[][] headret={head1,head2,head3,null};
578
579 System.err.print("testing max packet segments... ");
580 test_pack(packets,headret);
581 }
582
583 {
584 // packet that overspans over an entire page
585
586 int[] packets={0,100,9000,259,255,-1};
587
588 int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
589 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
590 0x01,0x02,0x03,0x04,0,0,0,0,
591 0xff,0x7b,0x23,0x17,
592 1,
593 0};
594
595 int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
596 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
597 0x01,0x02,0x03,0x04,1,0,0,0,
598 0x3c,0xd9,0x4d,0x3f,
599 17,
600 100,255,255,255,255,255,255,255,255,
601 255,255,255,255,255,255,255,255};
602
603 int[] head3={0x4f,0x67,0x67,0x53,0,0x01,
604 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
605 0x01,0x02,0x03,0x04,2,0,0,0,
606 0xbd,0xd5,0xb5,0x8b,
607 17,
608 255,255,255,255,255,255,255,255,
609 255,255,255,255,255,255,255,255,255};
610
611 int[] head4={0x4f,0x67,0x67,0x53,0,0x05,
612 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
613 0x01,0x02,0x03,0x04,3,0,0,0,
614 0xef,0xdd,0x88,0xde,
615 7,
616 255,255,75,255,4,255,0};
617 int[][] headret={head1,head2,head3,head4,null};
618
619 System.err.print("testing very large packets... ");
620 test_pack(packets,headret);
621 }
622
623 {
624 // term only page. why not?
625
626 int[] packets={0,100,4080,-1};
627
628 int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
629 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
630 0x01,0x02,0x03,0x04,0,0,0,0,
631 0xff,0x7b,0x23,0x17,
632 1,
633 0};
634
635 int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
636 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
637 0x01,0x02,0x03,0x04,1,0,0,0,
638 0x3c,0xd9,0x4d,0x3f,
639 17,
640 100,255,255,255,255,255,255,255,255,
641 255,255,255,255,255,255,255,255};
642
643 int[] head3={0x4f,0x67,0x67,0x53,0,0x05,
644 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
645 0x01,0x02,0x03,0x04,2,0,0,0,
646 0xd4,0xe0,0x60,0xe5,
647 1,0};
648
649 int[][] headret={head1,head2,head3,null};
650
651 System.err.print("testing zero data page (1 nil packet)... ");
652 test_pack(packets,headret);
653 }
654
655 {
656 // build a bunch of pages for testing
657 byte[] data=new byte[1024*1024];
658 int[] pl={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
659 int inptr=0;
660 Page[] og=new Page[5];
661 for(int i=0; i<5; i++){
662 og[i]=new Page();
663 }
664
665 os_en.reset();
666
667 for(int i=0;pl[i]!=-1;i++){
668 Packet op=new Packet();
669 int len=pl[i];
670
671 op.packet_base=data;
672 op.packet=inptr;
673 op.bytes=len;
674 op.e_o_s=(pl[i+1]<0?1:0);
675 op.granulepos=(i+1)*1000;
676
677 for(int j=0;j<len;j++)data[inptr++]=(byte)(i+j);
678 os_en.packetin(op);
679 }
680
681// free(data);
682
683 // retrieve finished pages
684 for(int i=0;i<5;i++){
685 if(os_en.pageout(og[i])==0){
686 System.err.print("Too few pages output building sync tests!\n");
687 System.exit(1);
688 }
689 og[i].copy_page();
690 }
691
692 // Test lost pages on pagein/packetout: no rollback
693 {
694 Page temp=new Page();
695 Packet test=new Packet();
696
697 System.err.print("Testing loss of pages... ");
698
699 oy.reset();
700 os_de.reset();
701 for(int i=0;i<5;i++){
702 int index=oy.buffer(og[i].header_len);
703 System.arraycopy(og[i].header_base, og[i].header,
704 oy.data, index, og[i].header_len);
705 oy.wrote(og[i].header_len);
706 index=oy.buffer(og[i].body_len);
707 System.arraycopy(og[i].body_base, og[i].body,
708 oy.data, index, og[i].body_len);
709 oy.wrote(og[i].body_len);
710 }
711
712 oy.pageout(temp);
713 os_de.pagein(temp);
714 oy.pageout(temp);
715 os_de.pagein(temp);
716 oy.pageout(temp);
717
718 // skip
719 oy.pageout(temp);
720 os_de.pagein(temp);
721
722 // do we get the expected results/packets?
723
724 if(os_de.packetout(test)!=1)error();
725 test.checkpacket(0,0,0);
726 if(os_de.packetout(test)!=1)error();
727 test.checkpacket(100,1,-1);
728 if(os_de.packetout(test)!=1)error();
729 test.checkpacket(4079,2,3000);
730 if(os_de.packetout(test)!=-1){
731 System.err.println("Error: loss of page did not return error");
732 System.exit(1);
733 }
734 if(os_de.packetout(test)!=1)error();
735 test.checkpacket(76,5,-1);
736 if(os_de.packetout(test)!=1)error();
737 test.checkpacket(34,6,-1);
738 System.err.println("ok.");
739 }
740
741 // Test lost pages on pagein/packetout: rollback with continuation
742 {
743 Page temp=new Page();
744 Packet test=new Packet();
745
746 System.err.print("Testing loss of pages (rollback required)... ");
747
748 oy.reset();
749 os_de.reset();
750 for(int i=0;i<5;i++){
751 int index=oy.buffer(og[i].header_len);
752 System.arraycopy(og[i].header_base, og[i].header,
753 oy.data, index, og[i].header_len);
754 oy.wrote(og[i].header_len);
755 index=oy.buffer(og[i].body_len);
756 System.arraycopy(og[i].body_base, og[i].body,
757 oy.data, index, og[i].body_len);
758 oy.wrote(og[i].body_len);
759 }
760
761 oy.pageout(temp);
762 os_de.pagein(temp);
763 oy.pageout(temp);
764 os_de.pagein(temp);
765 oy.pageout(temp);
766 os_de.pagein(temp);
767 oy.pageout(temp);
768 // skip
769 oy.pageout(temp);
770 os_de.pagein(temp);
771
772 // do we get the expected results/packets?
773
774 if(os_de.packetout(test)!=1)error();
775 test.checkpacket(0,0,0);
776 if(os_de.packetout(test)!=1)error();
777 test.checkpacket(100,1,-1);
778 if(os_de.packetout(test)!=1)error();
779 test.checkpacket(4079,2,3000);
780 if(os_de.packetout(test)!=1)error();
781 test.checkpacket(2956,3,4000);
782 if(os_de.packetout(test)!=-1){
783 System.err.println("Error: loss of page did not return error");
784 System.exit(1);
785 }
786 if(os_de.packetout(test)!=1)error();
787 test.checkpacket(300,13,14000);
788 System.err.println("ok.");
789 }
790
791 // the rest only test sync
792 {
793 Page og_de=new Page();
794 // Test fractional page inputs: incomplete capture
795 System.err.print("Testing sync on partial inputs... ");
796 oy.reset();
797 int index=oy.buffer(og[1].header_len);
798 System.arraycopy(og[1].header_base, og[1].header,
799 oy.data, index, 3);
800 oy.wrote(3);
801 if(oy.pageout(og_de)>0)error();
802
803 // Test fractional page inputs: incomplete fixed header
804 index=oy.buffer(og[1].header_len);
805 System.arraycopy(og[1].header_base, og[1].header+3,
806 oy.data, index, 20);
807
808 oy.wrote(20);
809 if(oy.pageout(og_de)>0)error();
810
811 // Test fractional page inputs: incomplete header
812 index=oy.buffer(og[1].header_len);
813 System.arraycopy(og[1].header_base, og[1].header+23,
814 oy.data, index, 5);
815 oy.wrote(5);
816 if(oy.pageout(og_de)>0)error();
817
818 // Test fractional page inputs: incomplete body
819 index=oy.buffer(og[1].header_len);
820 System.arraycopy(og[1].header_base, og[1].header+28,
821 oy.data, index, og[1].header_len-28);
822 oy.wrote(og[1].header_len-28);
823 if(oy.pageout(og_de)>0)error();
824
825 index=oy.buffer(og[1].body_len);
826 System.arraycopy(og[1].body_base, og[1].body,
827 oy.data, index, 1000);
828 oy.wrote(1000);
829 if(oy.pageout(og_de)>0)error();
830
831 index=oy.buffer(og[1].body_len);
832 System.arraycopy(og[1].body_base, og[1].body+1000,
833 oy.data, index, og[1].body_len-1000);
834 oy.wrote(og[1].body_len-1000);
835 if(oy.pageout(og_de)<=0)error();
836 System.err.println("ok.");
837 }
838
839 // Test fractional page inputs: page + incomplete capture
840 {
841 Page og_de=new Page();
842 System.err.print("Testing sync on 1+partial inputs... ");
843 oy.reset();
844
845 int index=oy.buffer(og[1].header_len);
846 System.arraycopy(og[1].header_base, og[1].header,
847 oy.data, index, og[1].header_len);
848 oy.wrote(og[1].header_len);
849
850 index=oy.buffer(og[1].body_len);
851 System.arraycopy(og[1].body_base, og[1].body,
852 oy.data, index, og[1].body_len);
853 oy.wrote(og[1].body_len);
854
855 index=oy.buffer(og[1].header_len);
856 System.arraycopy(og[1].header_base, og[1].header,
857 oy.data, index, 20);
858 oy.wrote(20);
859 if(oy.pageout(og_de)<=0)error();
860 if(oy.pageout(og_de)>0)error();
861
862 index=oy.buffer(og[1].header_len);
863 System.arraycopy(og[1].header_base, og[1].header+20,
864 oy.data, index, og[1].header_len-20);
865 oy.wrote(og[1].header_len-20);
866 index=oy.buffer(og[1].body_len);
867 System.arraycopy(og[1].body_base, og[1].body,
868 oy.data, index, og[1].body_len);
869
870 oy.wrote(og[1].body_len);
871 if(oy.pageout(og_de)<=0)error();
872
873 System.err.println("ok.");
874 }
875
876// // // // // // // // //
877 // Test recapture: garbage + page
878 {
879 Page og_de=new Page();
880 System.err.print("Testing search for capture... ");
881 oy.reset();
882
883 // 'garbage'
884 int index=oy.buffer(og[1].body_len);
885 System.arraycopy(og[1].body_base, og[1].body,
886 oy.data, index, og[1].body_len);
887 oy.wrote(og[1].body_len);
888
889 index=oy.buffer(og[1].header_len);
890 System.arraycopy(og[1].header_base, og[1].header,
891 oy.data, index, og[1].header_len);
892 oy.wrote(og[1].header_len);
893
894 index=oy.buffer(og[1].body_len);
895 System.arraycopy(og[1].body_base, og[1].body,
896 oy.data, index, og[1].body_len);
897 oy.wrote(og[1].body_len);
898
899 index=oy.buffer(og[2].header_len);
900 System.arraycopy(og[2].header_base, og[2].header,
901 oy.data, index, 20);
902
903 oy.wrote(20);
904 if(oy.pageout(og_de)>0)error();
905 if(oy.pageout(og_de)<=0)error();
906 if(oy.pageout(og_de)>0)error();
907
908 index=oy.buffer(og[2].header_len);
909 System.arraycopy(og[2].header_base, og[2].header+20,
910 oy.data, index, og[2].header_len-20);
911 oy.wrote(og[2].header_len-20);
912 index=oy.buffer(og[2].body_len);
913 System.arraycopy(og[2].body_base, og[2].body,
914 oy.data, index, og[2].body_len);
915 oy.wrote(og[2].body_len);
916 if(oy.pageout(og_de)<=0)error();
917
918 System.err.println("ok.");
919 }
920
921 // Test recapture: page + garbage + page
922 {
923 Page og_de=new Page();
924 System.err.print("Testing recapture... ");
925 oy.reset();
926
927 int index=oy.buffer(og[1].header_len);
928 System.arraycopy(og[1].header_base, og[1].header,
929 oy.data, index, og[1].header_len);
930 oy.wrote(og[1].header_len);
931
932 index=oy.buffer(og[1].body_len);
933 System.arraycopy(og[1].body_base, og[1].body,
934 oy.data, index, og[1].body_len);
935 oy.wrote(og[1].body_len);
936
937 index=oy.buffer(og[2].header_len);
938 System.arraycopy(og[2].header_base, og[2].header,
939 oy.data, index, og[2].header_len);
940 oy.wrote(og[2].header_len);
941
942 index=oy.buffer(og[2].header_len);
943 System.arraycopy(og[2].header_base, og[2].header,
944 oy.data, index, og[2].header_len);
945 oy.wrote(og[2].header_len);
946
947 if(oy.pageout(og_de)<=0)error();
948
949 index=oy.buffer(og[2].body_len);
950 System.arraycopy(og[2].body_base, og[2].body,
951 oy.data, index, og[2].body_len-5);
952 oy.wrote(og[2].body_len-5);
953
954 index=oy.buffer(og[3].header_len);
955 System.arraycopy(og[3].header_base, og[3].header,
956 oy.data, index, og[3].header_len);
957 oy.wrote(og[3].header_len);
958
959 index=oy.buffer(og[3].body_len);
960 System.arraycopy(og[3].body_base, og[3].body,
961 oy.data, index, og[3].body_len);
962 oy.wrote(og[3].body_len);
963
964 if(oy.pageout(og_de)>0)error();
965 if(oy.pageout(og_de)<=0)error();
966
967 System.err.println("ok.");
968 }
969 }
970 //return(0);
971 }
972 */
973}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jogg;
27
28public class StreamState{
29 byte[] body_data; /* bytes from packet bodies */
30 int body_storage; /* storage elements allocated */
31 int body_fill; /* elements stored; fill mark */
32private int body_returned; /* elements of fill returned */
33
34
35 int[] lacing_vals; /* The values that will go to the segment table */
36 long[] granule_vals; /* pcm_pos values for headers. Not compact
37 this way, but it is simple coupled to the
38 lacing fifo */
39 int lacing_storage;
40 int lacing_fill;
41 int lacing_packet;
42 int lacing_returned;
43
44 byte[] header=new byte[282]; /* working space for header encode */
45 int header_fill;
46
47 public int e_o_s; /* set when we have buffered the last packet in the
48 logical bitstream */
49 int b_o_s; /* set after we've written the initial page
50 of a logical bitstream */
51 int serialno;
52 int pageno;
53 long packetno; /* sequence number for decode; the framing
54 knows where there's a hole in the data,
55 but we need coupling so that the codec
56 (which is in a seperate abstraction
57 layer) also knows about the gap */
58 long granulepos;
59
60 public StreamState(){
61 init();
62 }
63
64 StreamState(int serialno){
65 this();
66 init(serialno);
67 }
68 void init(){
69 body_storage=16*1024;
70 body_data=new byte[body_storage];
71 lacing_storage=1024;
72 lacing_vals=new int[lacing_storage];
73 granule_vals=new long[lacing_storage];
74 }
75 public void init(int serialno){
76 if(body_data==null){ init(); }
77 else{
78 for(int i=0; i<body_data.length; i++) body_data[i]=0;
79 for(int i=0; i<lacing_vals.length; i++) lacing_vals[i]=0;
80 for(int i=0; i<granule_vals.length; i++) granule_vals[i]=0;
81 }
82 this.serialno=serialno;
83 }
84 public void clear(){
85 body_data=null;
86 lacing_vals=null;
87 granule_vals=null;
88 //memset(os,0,sizeof(ogg_stream_state));
89 }
90 void destroy(){
91 clear();
92 }
93 void body_expand(int needed){
94 if(body_storage<=body_fill+needed){
95 body_storage+=(needed+1024);
96 byte[] foo=new byte[body_storage];
97 System.arraycopy(body_data, 0, foo, 0, body_data.length);
98 body_data=foo;
99//System.out.println("expand: body_fill="+body_fill+", body_storage="+body_data.length);
100 }
101 }
102 void lacing_expand(int needed){
103 if(lacing_storage<=lacing_fill+needed){
104 lacing_storage+=(needed+32);
105 int[] foo=new int[lacing_storage];
106 System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length);
107 lacing_vals=foo;
108
109 long[] bar=new long[lacing_storage];
110 System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
111 granule_vals=bar;
112 }
113 }
114
115 /* submit data to the internal buffer of the framing engine */
116 public int packetin(Packet op){
117 int lacing_val=op.bytes/255+1;
118
119 if(body_returned!=0){
120 /* advance packet data according to the body_returned pointer. We
121 had to keep it around to return a pointer into the buffer last
122 call */
123
124 body_fill-=body_returned;
125 if(body_fill!=0){
126// memmove(os->body_data,os->body_data+os->body_returned,
127// os->body_fill*sizeof(char));
128 System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
129 }
130 body_returned=0;
131 }
132
133 /* make sure we have the buffer storage */
134 body_expand(op.bytes);
135 lacing_expand(lacing_val);
136
137 /* Copy in the submitted packet. Yes, the copy is a waste; this is
138 the liability of overly clean abstraction for the time being. It
139 will actually be fairly easy to eliminate the extra copy in the
140 future */
141
142 System.arraycopy(op.packet_base, op.packet, body_data, body_fill, op.bytes);
143 body_fill+=op.bytes;
144//System.out.println("add: "+body_fill);
145
146 /* Store lacing vals for this packet */
147 int j;
148 for(j=0;j<lacing_val-1;j++){
149 lacing_vals[lacing_fill+j]=255;
150 granule_vals[lacing_fill+j]=granulepos;
151 }
152 lacing_vals[lacing_fill+j]=(op.bytes)%255;
153 granulepos=granule_vals[lacing_fill+j]=op.granulepos;
154
155 /* flag the first segment as the beginning of the packet */
156 lacing_vals[lacing_fill]|= 0x100;
157
158 lacing_fill+=lacing_val;
159
160 /* for the sake of completeness */
161 packetno++;
162
163 if(op.e_o_s!=0)e_o_s=1;
164 return(0);
165 }
166
167 public int packetout(Packet op){
168
169 /* The last part of decode. We have the stream broken into packet
170 segments. Now we need to group them into packets (or return the
171 out of sync markers) */
172
173 int ptr=lacing_returned;
174
175 if(lacing_packet<=ptr){
176 return(0);
177 }
178
179 if((lacing_vals[ptr]&0x400)!=0){
180 /* We lost sync here; let the app know */
181 lacing_returned++;
182
183 /* we need to tell the codec there's a gap; it might need to
184 handle previous packet dependencies. */
185 packetno++;
186 return(-1);
187 }
188
189 /* Gather the whole packet. We'll have no holes or a partial packet */
190 {
191 int size=lacing_vals[ptr]&0xff;
192 int bytes=0;
193
194 op.packet_base=body_data;
195 op.packet=body_returned;
196 op.e_o_s=lacing_vals[ptr]&0x200; /* last packet of the stream? */
197 op.b_o_s=lacing_vals[ptr]&0x100; /* first packet of the stream? */
198 bytes+=size;
199
200 while(size==255){
201 int val=lacing_vals[++ptr];
202 size=val&0xff;
203 if((val&0x200)!=0)op.e_o_s=0x200;
204 bytes+=size;
205 }
206
207 op.packetno=packetno;
208 op.granulepos=granule_vals[ptr];
209 op.bytes=bytes;
210
211//System.out.println(this+" # body_returned="+body_returned);
212 body_returned+=bytes;
213//System.out.println(this+"## body_returned="+body_returned);
214
215 lacing_returned=ptr+1;
216 }
217 packetno++;
218 return(1);
219 }
220
221
222 // add the incoming page to the stream state; we decompose the page
223 // into packet segments here as well.
224
225 public int pagein(Page og){
226 byte[] header_base=og.header_base;
227 int header=og.header;
228 byte[] body_base=og.body_base;
229 int body=og.body;
230 int bodysize=og.body_len;
231 int segptr=0;
232
233 int version=og.version();
234 int continued=og.continued();
235 int bos=og.bos();
236 int eos=og.eos();
237 long granulepos=og.granulepos();
238 int _serialno=og.serialno();
239 int _pageno=og.pageno();
240 int segments=header_base[header+26]&0xff;
241
242 // clean up 'returned data'
243 {
244 int lr=lacing_returned;
245 int br=body_returned;
246
247 // body data
248
249//System.out.println("br="+br+", body_fill="+body_fill);
250
251 if(br!=0){
252 body_fill-=br;
253 if(body_fill!=0){
254 System.arraycopy(body_data, br, body_data, 0, body_fill);
255 }
256 body_returned=0;
257 }
258
259//System.out.println("?? br="+br+", body_fill="+body_fill+" body_returned="+body_returned);
260
261 if(lr!=0){
262 // segment table
263 if((lacing_fill-lr)!=0){
264 System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill-lr);
265 System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill-lr);
266 }
267 lacing_fill-=lr;
268 lacing_packet-=lr;
269 lacing_returned=0;
270 }
271 }
272
273 // check the serial number
274 if(_serialno!=serialno)return(-1);
275 if(version>0)return(-1);
276
277 lacing_expand(segments+1);
278
279 // are we in sequence?
280 if(_pageno!=pageno){
281 int i;
282
283 // unroll previous partial packet (if any)
284 for(i=lacing_packet;i<lacing_fill;i++){
285 body_fill-=lacing_vals[i]&0xff;
286//System.out.println("??");
287 }
288 lacing_fill=lacing_packet;
289
290 // make a note of dropped data in segment table
291 if(pageno!=-1){
292 lacing_vals[lacing_fill++]=0x400;
293 lacing_packet++;
294 }
295
296 // are we a 'continued packet' page? If so, we'll need to skip
297 // some segments
298 if(continued!=0){
299 bos=0;
300 for(;segptr<segments;segptr++){
301 int val=(header_base[header+27+segptr]&0xff);
302 body+=val;
303 bodysize-=val;
304 if(val<255){
305 segptr++;
306 break;
307 }
308 }
309 }
310 }
311
312//System.out.println("bodysize="+bodysize);
313
314 if(bodysize!=0){
315 body_expand(bodysize);
316 System.arraycopy(body_base, body, body_data, body_fill, bodysize);
317 body_fill+=bodysize;
318 }
319
320//System.out.println("bodyfill="+body_fill);
321
322 {
323 int saved=-1;
324 while(segptr<segments){
325 int val=(header_base[header+27+segptr]&0xff);
326 lacing_vals[lacing_fill]=val;
327 granule_vals[lacing_fill]=-1;
328
329 if(bos!=0){
330 lacing_vals[lacing_fill]|=0x100;
331 bos=0;
332 }
333
334 if(val<255)saved=lacing_fill;
335
336 lacing_fill++;
337 segptr++;
338
339 if(val<255)lacing_packet=lacing_fill;
340 }
341
342 /* set the granulepos on the last pcmval of the last full packet */
343 if(saved!=-1){
344 granule_vals[saved]=granulepos;
345 }
346 }
347
348 if(eos!=0){
349 e_o_s=1;
350 if(lacing_fill>0)
351 lacing_vals[lacing_fill-1]|=0x200;
352 }
353
354 pageno=_pageno+1;
355 return(0);
356 }
357
358
359/* This will flush remaining packets into a page (returning nonzero),
360 even if there is not enough data to trigger a flush normally
361 (undersized page). If there are no packets or partial packets to
362 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
363 try to flush a normal sized page like ogg_stream_pageout; a call to
364 ogg_stream_flush does not gurantee that all packets have flushed.
365 Only a return value of 0 from ogg_stream_flush indicates all packet
366 data is flushed into pages.
367
368 ogg_stream_page will flush the last page in a stream even if it's
369 undersized; you almost certainly want to use ogg_stream_pageout
370 (and *not* ogg_stream_flush) unless you need to flush an undersized
371 page in the middle of a stream for some reason. */
372
373 public int flush(Page og){
374
375//System.out.println(this+" ---body_returned: "+body_returned);
376
377 int i;
378 int vals=0;
379 int maxvals=(lacing_fill>255?255:lacing_fill);
380 int bytes=0;
381 int acc=0;
382 long granule_pos=granule_vals[0];
383
384 if(maxvals==0)return(0);
385
386 /* construct a page */
387 /* decide how many segments to include */
388
389 /* If this is the initial header case, the first page must only include
390 the initial header packet */
391 if(b_o_s==0){ /* 'initial header page' case */
392 granule_pos=0;
393 for(vals=0;vals<maxvals;vals++){
394 if((lacing_vals[vals]&0x0ff)<255){
395 vals++;
396 break;
397 }
398 }
399 }
400 else{
401 for(vals=0;vals<maxvals;vals++){
402 if(acc>4096)break;
403 acc+=(lacing_vals[vals]&0x0ff);
404 granule_pos=granule_vals[vals];
405 }
406 }
407
408 /* construct the header in temp storage */
409 System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
410
411 /* stream structure version */
412 header[4]=0x00;
413
414 /* continued packet flag? */
415 header[5]=0x00;
416 if((lacing_vals[0]&0x100)==0)header[5]|=0x01;
417 /* first page flag? */
418 if(b_o_s==0) header[5]|=0x02;
419 /* last page flag? */
420 if(e_o_s!=0 && lacing_fill==vals) header[5]|=0x04;
421 b_o_s=1;
422
423 /* 64 bits of PCM position */
424 for(i=6;i<14;i++){
425 header[i]=(byte)granule_pos;
426 granule_pos>>>=8;
427 }
428
429 /* 32 bits of stream serial number */
430 {
431 int _serialno=serialno;
432 for(i=14;i<18;i++){
433 header[i]=(byte)_serialno;
434 _serialno>>>=8;
435 }
436 }
437
438 /* 32 bits of page counter (we have both counter and page header
439 because this val can roll over) */
440 if(pageno==-1)pageno=0; /* because someone called
441 stream_reset; this would be a
442 strange thing to do in an
443 encode stream, but it has
444 plausible uses */
445 {
446 int _pageno=pageno++;
447 for(i=18;i<22;i++){
448 header[i]=(byte)_pageno;
449 _pageno>>>=8;
450 }
451 }
452
453 /* zero for computation; filled in later */
454 header[22]=0;
455 header[23]=0;
456 header[24]=0;
457 header[25]=0;
458
459 /* segment table */
460 header[26]=(byte)vals;
461 for(i=0;i<vals;i++){
462 header[i+27]=(byte)lacing_vals[i];
463 bytes+=(header[i+27]&0xff);
464 }
465
466 /* set pointers in the ogg_page struct */
467 og.header_base=header;
468 og.header=0;
469 og.header_len=header_fill=vals+27;
470 og.body_base=body_data;
471 og.body=body_returned;
472 og.body_len=bytes;
473
474 /* advance the lacing data and set the body_returned pointer */
475
476//System.out.println("###body_returned: "+body_returned);
477
478 lacing_fill-=vals;
479 System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill*4);
480 System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill*8);
481 body_returned+=bytes;
482
483//System.out.println("####body_returned: "+body_returned);
484
485 /* calculate the checksum */
486
487 og.checksum();
488
489 /* done */
490 return(1);
491 }
492
493
494/* This constructs pages from buffered packet segments. The pointers
495returned are to static buffers; do not free. The returned buffers are
496good only until the next call (using the same ogg_stream_state) */
497 public int pageout(Page og){
498// if(body_returned!=0){
499// /* advance packet data according to the body_returned pointer. We
500// had to keep it around to return a pointer into the buffer last
501// call */
502//
503// body_fill-=body_returned;
504// if(body_fill!=0){ // overlap?
505// System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
506// }
507// body_returned=0;
508// }
509//
510//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);
511//
512// if((e_o_s!=0&&lacing_fill!=0) || /* 'were done, now flush' case */
513// body_fill > 4096 || /* 'page nominal size' case */
514// lacing_fill>=255 || /* 'segment table full' case */
515// (lacing_fill!=0&&b_o_s==0)){ /* 'initial header page' case */
516// int vals=0,bytes=0;
517// int maxvals=(lacing_fill>255?255:lacing_fill);
518// long acc=0;
519// long pcm_pos=granule_vals[0];
520//
521// /* construct a page */
522// /* decide how many segments to include */
523//
524// /* If this is the initial header case, the first page must only include
525// the initial header packet */
526// if(b_o_s==0){ /* 'initial header page' case */
527// pcm_pos=0;
528// for(vals=0;vals<maxvals;vals++){
529// if((lacing_vals[vals]&0x0ff)<255){
530// vals++;
531// break;
532// }
533// }
534// }
535// else{
536// for(vals=0;vals<maxvals;vals++){
537// if(acc>4096)break;
538// acc+=lacing_vals[vals]&0x0ff;
539// pcm_pos=granule_vals[vals];
540// }
541// }
542//
543// /* construct the header in temp storage */
544// System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
545//
546// /* stream structure version */
547// header[4]=0x00;
548//
549// /* continued packet flag? */
550// header[5]=0x00;
551// if((lacing_vals[0]&0x100)==0)header[5]|=0x01;
552// /* first page flag? */
553// if(b_o_s==0)header[5]|=0x02;
554// /* last page flag? */
555// if(e_o_s!=0 && lacing_fill==vals)header[5]|=0x04;
556// b_o_s=1;
557//
558// /* 64 bits of PCM position */
559// for(int i=6;i<14;i++){
560// header[i]=(byte)pcm_pos;
561// pcm_pos>>>=8;
562// }
563//
564// /* 32 bits of stream serial number */
565// {
566// int serialn=serialno;
567// for(int i=14;i<18;i++){
568// header[i]=(byte)serialn;
569// serialn>>>=8;
570// }
571// }
572//
573//
574///* 32 bits of page counter (we have both counter and page header
575// because this val can roll over) */
576// if(pageno==-1)pageno=0; /* because someone called
577// stream_reset; this would be a
578// strange thing to do in an
579// encode stream, but it has
580// plausible uses */
581// {
582// int pagen=pageno++;
583// for(int i=18;i<22;i++){
584// header[i]=(byte)pagen;
585// pagen>>>=8;
586// }
587// }
588//
589// /* zero for computation; filled in later */
590// header[22]=0;
591// header[23]=0;
592// header[24]=0;
593// header[25]=0;
594//
595// /* segment table */
596// header[26]=(byte)vals;
597// for(int i=0;i<vals;i++){
598// header[i+27]=(byte)lacing_vals[i];
599// bytes+=header[i+27]&0xff;
600//// bytes+=header[i+27]=(lacing_vals[i]&0xff);
601// }
602//
603// /* advance the lacing data and set the body_returned pointer */
604//
605// lacing_fill-=vals;
606// System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill);
607// System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill);
608// body_returned=bytes;
609//
610// /* set pointers in the ogg_page struct */
611// og.header_base=header;
612// og.header=0;
613// og.header_len=header_fill=vals+27;
614//
615// og.body_base=body_data;
616// og.body=0;
617// og.body_len=bytes;
618//
619// /* calculate the checksum */
620//
621// og.checksum();
622// return(1);
623// }
624// /* not enough data to construct a page and not end of stream */
625// return(0);
626//System.out.println("pageout: "+body_returned);
627 if((e_o_s!=0&&lacing_fill!=0) || /* 'were done, now flush' case */
628 body_fill-body_returned> 4096 || /* 'page nominal size' case */
629 lacing_fill>=255 || /* 'segment table full' case */
630 (lacing_fill!=0&&b_o_s==0)){ /* 'initial header page' case */
631 return flush(og);
632 }
633 return 0;
634 }
635
636 public int eof(){
637 return e_o_s;
638 }
639
640 public int reset(){
641 body_fill=0;
642 body_returned=0;
643
644 lacing_fill=0;
645 lacing_packet=0;
646 lacing_returned=0;
647
648 header_fill=0;
649
650 e_o_s=0;
651 b_o_s=0;
652 pageno=-1;
653 packetno=0;
654 granulepos=0;
655 return(0);
656 }
657}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jogg;
27
28// DECODING PRIMITIVES: packet streaming layer
29
30// This has two layers to place more of the multi-serialno and paging
31// control in the application's hands. First, we expose a data buffer
32// using ogg_decode_buffer(). The app either copies into the
33// buffer, or passes it directly to read(), etc. We then call
34// ogg_decode_wrote() to tell how many bytes we just added.
35//
36// Pages are returned (pointers into the buffer in ogg_sync_state)
37// by ogg_decode_stream(). The page is then submitted to
38// ogg_decode_page() along with the appropriate
39// ogg_stream_state* (ie, matching serialno). We then get raw
40// packets out calling ogg_stream_packet() with a
41// ogg_stream_state. See the 'frame-prog.txt' docs for details and
42// example code.
43
44public class SyncState{
45
46 public byte[] data;
47 int storage;
48 int fill;
49 int returned;
50
51 int unsynced;
52 int headerbytes;
53 int bodybytes;
54
55 public int clear(){
56 data=null;
57 return(0);
58 }
59
60// !!!!!!!!!!!!
61// byte[] buffer(int size){
62 public int buffer(int size){
63 // first, clear out any space that has been previously returned
64 if(returned!=0){
65 fill-=returned;
66 if(fill>0){
67 System.arraycopy(data, returned, data, 0, fill);
68 }
69 returned=0;
70 }
71
72 if(size>storage-fill){
73 // We need to extend the internal buffer
74 int newsize=size+fill+4096; // an extra page to be nice
75 if(data!=null){
76 byte[] foo=new byte[newsize];
77 System.arraycopy(data, 0, foo, 0, data.length);
78 data=foo;
79 }
80 else{
81 data=new byte[newsize];
82 }
83 storage=newsize;
84 }
85
86 // expose a segment at least as large as requested at the fill mark
87// return((char *)oy->data+oy->fill);
88// return(data);
89 return(fill);
90 }
91
92 public int wrote(int bytes){
93 if(fill+bytes>storage)return(-1);
94 fill+=bytes;
95 return(0);
96 }
97
98// sync the stream. This is meant to be useful for finding page
99// boundaries.
100//
101// return values for this:
102// -n) skipped n bytes
103// 0) page not ready; more data (no bytes skipped)
104// n) page synced at current location; page length n bytes
105 private Page pageseek=new Page();
106 private byte[] chksum=new byte[4];
107 public int pageseek(Page og){
108 int page=returned;
109 int next;
110 int bytes=fill-returned;
111
112 if(headerbytes==0){
113 int _headerbytes,i;
114 if(bytes<27)return(0); // not enough for a header
115
116 /* verify capture pattern */
117//!!!!!!!!!!!
118 if(data[page]!='O' ||
119 data[page+1]!='g' ||
120 data[page+2]!='g' ||
121 data[page+3]!='S'){
122 headerbytes=0;
123 bodybytes=0;
124
125 // search for possible capture
126 next=0;
127 for(int ii=0; ii<bytes-1; ii++){
128 if(data[page+1+ii]=='O'){next=page+1+ii; break;}
129 }
130 //next=memchr(page+1,'O',bytes-1);
131 if(next==0) next=fill;
132
133 returned=next;
134 return(-(next-page));
135 }
136 _headerbytes=(data[page+26]&0xff)+27;
137 if(bytes<_headerbytes)return(0); // not enough for header + seg table
138
139 // count up body length in the segment table
140
141 for(i=0;i<(data[page+26]&0xff);i++){
142 bodybytes+=(data[page+27+i]&0xff);
143 }
144 headerbytes=_headerbytes;
145 }
146
147 if(bodybytes+headerbytes>bytes)return(0);
148
149 // The whole test page is buffered. Verify the checksum
150 synchronized(chksum){
151 // Grab the checksum bytes, set the header field to zero
152
153 System.arraycopy(data, page+22, chksum, 0, 4);
154 data[page+22]=0;
155 data[page+23]=0;
156 data[page+24]=0;
157 data[page+25]=0;
158
159 // set up a temp page struct and recompute the checksum
160 Page log=pageseek;
161 log.header_base=data;
162 log.header=page;
163 log.header_len=headerbytes;
164
165 log.body_base=data;
166 log.body=page+headerbytes;
167 log.body_len=bodybytes;
168 log.checksum();
169
170 // Compare
171 if(chksum[0]!=data[page+22] ||
172 chksum[1]!=data[page+23] ||
173 chksum[2]!=data[page+24] ||
174 chksum[3]!=data[page+25]){
175 // D'oh. Mismatch! Corrupt page (or miscapture and not a page at all)
176 // replace the computed checksum with the one actually read in
177 System.arraycopy(chksum, 0, data, page+22, 4);
178 // Bad checksum. Lose sync */
179
180 headerbytes=0;
181 bodybytes=0;
182 // search for possible capture
183 next=0;
184 for(int ii=0; ii<bytes-1; ii++){
185 if(data[page+1+ii]=='O'){next=page+1+ii; break;}
186 }
187 //next=memchr(page+1,'O',bytes-1);
188 if(next==0) next=fill;
189 returned=next;
190 return(-(next-page));
191 }
192 }
193
194 // yes, have a whole page all ready to go
195 {
196 page=returned;
197
198 if(og!=null){
199 og.header_base=data;
200 og.header=page;
201 og.header_len=headerbytes;
202 og.body_base=data;
203 og.body=page+headerbytes;
204 og.body_len=bodybytes;
205 }
206
207 unsynced=0;
208 returned+=(bytes=headerbytes+bodybytes);
209 headerbytes=0;
210 bodybytes=0;
211 return(bytes);
212 }
213// headerbytes=0;
214// bodybytes=0;
215// next=0;
216// for(int ii=0; ii<bytes-1; ii++){
217// if(data[page+1+ii]=='O'){next=page+1+ii;}
218// }
219// //next=memchr(page+1,'O',bytes-1);
220// if(next==0) next=fill;
221// returned=next;
222// return(-(next-page));
223 }
224
225
226// sync the stream and get a page. Keep trying until we find a page.
227// Supress 'sync errors' after reporting the first.
228//
229// return values:
230// -1) recapture (hole in data)
231// 0) need more data
232// 1) page returned
233//
234// Returns pointers into buffered data; invalidated by next call to
235// _stream, _clear, _init, or _buffer
236
237 public int pageout(Page og){
238 // all we need to do is verify a page at the head of the stream
239 // buffer. If it doesn't verify, we look for the next potential
240 // frame
241
242 while(true){
243 int ret=pageseek(og);
244 if(ret>0){
245 // have a page
246 return(1);
247 }
248 if(ret==0){
249 // need more data
250 return(0);
251 }
252
253 // head did not start a synced page... skipped some bytes
254 if(unsynced==0){
255 unsynced=1;
256 return(-1);
257 }
258 // loop. keep looking
259 }
260 }
261
262// clear things to an initial state. Good to call, eg, before seeking
263 public int reset(){
264 fill=0;
265 returned=0;
266 unsynced=0;
267 headerbytes=0;
268 bodybytes=0;
269 return(0);
270 }
271 public void init(){}
272
273 public int getDataOffset(){ return returned; }
274 public int getBufferOffset(){ return fill; }
275}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28class AllocChain{
29 Object ptr;
30 AllocChain next;
31};
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30public class Block{
31 ///necessary stream state for linking to the framing abstraction
32 float[][] pcm=new float[0][]; // this is a pointer into local storage
33 Buffer opb=new Buffer();
34
35 int lW;
36 int W;
37 int nW;
38 int pcmend;
39 int mode;
40
41 int eofflag;
42 long granulepos;
43 long sequence;
44 DspState vd; // For read-only access of configuration
45
46 // local storage to avoid remallocing; it's up to the mapping to
47 // structure it
48//byte[] localstore;
49//int localtop;
50//int localalloc;
51//int totaluse;
52//AllocChain reap;
53
54 // bitmetrics for the frame
55 int glue_bits;
56 int time_bits;
57 int floor_bits;
58 int res_bits;
59
60 public Block(DspState vd){
61 this.vd=vd;
62// localalloc=0;
63// localstore=null;
64 if(vd.analysisp!=0){
65 opb.writeinit();
66 }
67 }
68
69 public void init(DspState vd){
70 this.vd=vd;
71 }
72
73// int alloc(int bytes){
74// bytes=(bytes+(8-1))&(~(8-1));
75// if(bytes+localtop>localalloc){
76// if(localstore!=null){
77// AllocChain link=new AllocChain();
78// totaluse+=localtop;
79// link.next=reap;
80// link.ptr=localstore;
81// reap=link;
82// }
83// // highly conservative
84// localalloc=bytes;
85// localstore=new byte[localalloc];
86// localtop=0;
87// }
88// {
89// int foo=localtop;
90// //void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
91// localtop+=bytes;
92// return foo;
93// }
94// }
95
96 // reap the chain, pull the ripcord
97// void ripcord(){
98// // reap the chain
99// while(reap!=null){
100// AllocChain next=reap.next;
101// //free(reap->ptr);
102// reap.ptr=null;
103// //memset(reap,0,sizeof(struct alloc_chain));
104// //free(reap);
105// reap=next;
106// }
107// // consolidate storage
108// if(totaluse!=0){
109// //vb->localstore=realloc(vb->localstore,vb->totaluse+vb->localalloc);
110// byte[] foo=new byte[totaluse+localalloc];
111// System.arraycopy(localstore, 0, foo, 0, localstore.length);
112// localstore=foo;
113// localalloc+=totaluse;
114// totaluse=0;
115// }
116// // pull the ripcord
117// localtop=0;
118// reap=null;
119// }
120
121 public int clear(){
122 if(vd!=null){
123 if(vd.analysisp!=0){
124 opb.writeclear();
125 }
126 }
127 //ripcord();
128 //if(localstore!=null)
129 // localstore=null;
130 //memset(vb,0,sizeof(vorbis_block));
131 return(0);
132 }
133
134 public int synthesis(Packet op){
135 Info vi=vd.vi;
136
137 // first things first. Make sure decode is ready
138 // ripcord();
139 opb.readinit(op.packet_base, op.packet, op.bytes);
140
141 // Check the packet type
142 if(opb.read(1)!=0){
143 // Oops. This is not an audio data packet
144 return(-1);
145 }
146
147 // read our mode and pre/post windowsize
148 int _mode=opb.read(vd.modebits);
149 if(_mode==-1)return(-1);
150
151 mode=_mode;
152 W=vi.mode_param[mode].blockflag;
153 if(W!=0){
154 lW=opb.read(1);
155 nW=opb.read(1);
156 if(nW==-1) return(-1);
157 }
158 else{
159 lW=0;
160 nW=0;
161 }
162
163 // more setup
164 granulepos=op.granulepos;
165 sequence=op.packetno-3; // first block is third packet
166 eofflag=op.e_o_s;
167
168 // alloc pcm passback storage
169 pcmend=vi.blocksizes[W];
170 //pcm=alloc(vi.channels);
171 if(pcm.length<vi.channels){
172 pcm=new float[vi.channels][];
173 }
174 for(int i=0;i<vi.channels;i++){
175 if(pcm[i]==null || pcm[i].length<pcmend){
176 pcm[i]=new float[pcmend];
177 //pcm[i]=alloc(pcmend);
178 }
179 else{
180 for(int j=0;j<pcmend;j++){ pcm[i][j]=0; }
181 }
182 }
183
184 // unpack_header enforces range checking
185 int type=vi.map_type[vi.mode_param[mode].mapping];
186 return(FuncMapping.mapping_P[type].inverse(this, vd.mode[mode]));
187 }
188}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28class ChainingExample{
29 public static void main(String[] arg){
30 VorbisFile ov=null;
31
32 try{
33 ov=new VorbisFile(System.in, null, -1);
34 }
35 catch(Exception e){
36 System.err.println(e);
37 return;
38 }
39
40 if(ov.seekable()){
41 System.out.println("Input bitstream contained "+ov.streams()+" logical bitstream section(s).");
42 System.out.println("Total bitstream playing time: "+ov.time_total(-1)+" seconds\n");
43 }
44 else{
45 System.out.println("Standard input was not seekable.");
46 System.out.println("First logical bitstream information:\n");
47 }
48
49 for(int i=0;i<ov.streams();i++){
50 Info vi=ov.getInfo(i);
51 System.out.println("\tlogical bitstream section "+(i+1)+" information:");
52 System.out.println("\t\t"+vi.rate+"Hz "+vi.channels+" channels bitrate "+
53 (ov.bitrate(i)/1000)+"kbps serial number="+ov.serialnumber(i));
54 System.out.print("\t\tcompressed length: "+ov.raw_total(i)+" bytes ");
55 System.out.println(" play time: "+ov.time_total(i)+"s");
56 Comment vc=ov.getComment(i);
57 System.out.println(vc);
58 }
59 //clear(&ov);
60 }
61}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30class CodeBook{
31 int dim; // codebook dimensions (elements per vector)
32 int entries; // codebook entries
33 StaticCodeBook c=new StaticCodeBook();
34
35 float[] valuelist; // list of dim*entries actual entry values
36 int[] codelist; // list of bitstream codewords for each entry
37 DecodeAux decode_tree;
38
39 // returns the number of bits
40 int encode(int a, Buffer b){
41 b.write(codelist[a], c.lengthlist[a]);
42 return(c.lengthlist[a]);
43 }
44
45 // One the encode side, our vector writers are each designed for a
46 // specific purpose, and the encoder is not flexible without modification:
47 //
48 // The LSP vector coder uses a single stage nearest-match with no
49 // interleave, so no step and no error return. This is specced by floor0
50 // and doesn't change.
51 //
52 // Residue0 encoding interleaves, uses multiple stages, and each stage
53 // peels of a specific amount of resolution from a lattice (thus we want
54 // to match by threshhold, not nearest match). Residue doesn't *have* to
55 // be encoded that way, but to change it, one will need to add more
56 // infrastructure on the encode side (decode side is specced and simpler)
57
58 // floor0 LSP (single stage, non interleaved, nearest match)
59 // returns entry number and *modifies a* to the quantization value
60 int errorv(float[] a){
61 int best=best(a,1);
62 for(int k=0;k<dim;k++){
63 a[k]=valuelist[best*dim+k];
64 }
65 return(best);
66 }
67
68 // returns the number of bits and *modifies a* to the quantization value
69 int encodev(int best, float[] a, Buffer b){
70 for(int k=0;k<dim;k++){
71 a[k]=valuelist[best*dim+k];
72 }
73 return(encode(best,b));
74 }
75
76 // res0 (multistage, interleave, lattice)
77 // returns the number of bits and *modifies a* to the remainder value
78 int encodevs(float[] a, Buffer b, int step,int addmul){
79 int best=besterror(a,step,addmul);
80 return(encode(best,b));
81 }
82
83 private int[] t=new int[15]; // decodevs_add is synchronized for re-using t.
84 synchronized int decodevs_add(float[]a, int offset, Buffer b, int n){
85 int step=n/dim;
86 int entry;
87 int i,j,o;
88
89 if(t.length<step){
90 t=new int[step];
91 }
92
93 for(i = 0; i < step; i++){
94 entry=decode(b);
95 if(entry==-1)return(-1);
96 t[i]=entry*dim;
97 }
98 for(i=0,o=0;i<dim;i++,o+=step){
99 for(j=0;j<step;j++){
100 a[offset+o+j]+=valuelist[t[j]+i];
101 }
102 }
103
104 return(0);
105 }
106
107 int decodev_add(float[]a, int offset, Buffer b,int n){
108 int i,j,entry;
109 int t;
110
111 if(dim>8){
112 for(i=0;i<n;){
113 entry = decode(b);
114 if(entry==-1)return(-1);
115 t=entry*dim;
116 for(j=0;j<dim;){
117 a[offset+(i++)]+=valuelist[t+(j++)];
118 }
119 }
120 }
121 else{
122 for(i=0;i<n;){
123 entry=decode(b);
124 if(entry==-1)return(-1);
125 t=entry*dim;
126 j=0;
127 switch(dim){
128 case 8:
129 a[offset+(i++)]+=valuelist[t+(j++)];
130 case 7:
131 a[offset+(i++)]+=valuelist[t+(j++)];
132 case 6:
133 a[offset+(i++)]+=valuelist[t+(j++)];
134 case 5:
135 a[offset+(i++)]+=valuelist[t+(j++)];
136 case 4:
137 a[offset+(i++)]+=valuelist[t+(j++)];
138 case 3:
139 a[offset+(i++)]+=valuelist[t+(j++)];
140 case 2:
141 a[offset+(i++)]+=valuelist[t+(j++)];
142 case 1:
143 a[offset+(i++)]+=valuelist[t+(j++)];
144 case 0:
145 break;
146 }
147 }
148 }
149 return(0);
150 }
151
152 int decodev_set(float[] a,int offset, Buffer b, int n){
153 int i,j,entry;
154 int t;
155
156 for(i=0;i<n;){
157 entry = decode(b);
158 if(entry==-1)return(-1);
159 t=entry*dim;
160 for(j=0;j<dim;){
161 a[offset+i++]=valuelist[t+(j++)];
162 }
163 }
164 return(0);
165 }
166
167 int decodevv_add(float[][] a, int offset,int ch, Buffer b,int n){
168 int i,j,k,entry;
169 int chptr=0;
170 //System.out.println("decodevv_add: a="+a+",b="+b+",valuelist="+valuelist);
171
172 for(i=offset/ch;i<(offset+n)/ch;){
173 entry = decode(b);
174 if(entry==-1)return(-1);
175
176 int t = entry*dim;
177 for(j=0;j<dim;j++){
178 a[chptr++][i]+=valuelist[t+j];
179 if(chptr==ch){
180 chptr=0;
181 i++;
182 }
183 }
184 }
185 return(0);
186 }
187
188
189 // Decode side is specced and easier, because we don't need to find
190 // matches using different criteria; we simply read and map. There are
191 // two things we need to do 'depending':
192 //
193 // We may need to support interleave. We don't really, but it's
194 // convenient to do it here rather than rebuild the vector later.
195 //
196 // Cascades may be additive or multiplicitive; this is not inherent in
197 // the codebook, but set in the code using the codebook. Like
198 // interleaving, it's easiest to do it here.
199 // stage==0 -> declarative (set the value)
200 // stage==1 -> additive
201 // stage==2 -> multiplicitive
202
203 // returns the entry number or -1 on eof
204 int decode(Buffer b){
205 int ptr=0;
206 DecodeAux t=decode_tree;
207 int lok=b.look(t.tabn);
208 //System.err.println(this+" "+t+" lok="+lok+", tabn="+t.tabn);
209
210 if(lok>=0){
211 ptr=t.tab[lok];
212 b.adv(t.tabl[lok]);
213 if(ptr<=0){
214 return -ptr;
215 }
216 }
217 do{
218 switch(b.read1()){
219 case 0:
220 ptr=t.ptr0[ptr];
221 break;
222 case 1:
223 ptr=t.ptr1[ptr];
224 break;
225 case -1:
226 default:
227 return(-1);
228 }
229 }
230 while(ptr>0);
231 return(-ptr);
232 }
233
234 // returns the entry number or -1 on eof
235 int decodevs(float[] a, int index, Buffer b, int step,int addmul){
236 int entry=decode(b);
237 if(entry==-1)return(-1);
238 switch(addmul){
239 case -1:
240 for(int i=0,o=0;i<dim;i++,o+=step)
241 a[index+o]=valuelist[entry*dim+i];
242 break;
243 case 0:
244 for(int i=0,o=0;i<dim;i++,o+=step)
245 a[index+o]+=valuelist[entry*dim+i];
246 break;
247 case 1:
248 for(int i=0,o=0;i<dim;i++,o+=step)
249 a[index+o]*=valuelist[entry*dim+i];
250 break;
251 default:
252 //System.err.println("CodeBook.decodeves: addmul="+addmul);
253 }
254 return(entry);
255 }
256
257 int best(float[] a, int step){
258 EncodeAuxNearestMatch nt=c.nearest_tree;
259 EncodeAuxThreshMatch tt=c.thresh_tree;
260 int ptr=0;
261
262 // we assume for now that a thresh tree is the only other possibility
263 if(tt!=null){
264 int index=0;
265 // find the quant val of each scalar
266 for(int k=0,o=step*(dim-1);k<dim;k++,o-=step){
267 int i;
268 // linear search the quant list for now; it's small and although
269 // with > 8 entries, it would be faster to bisect, this would be
270 // a misplaced optimization for now
271 for(i=0;i<tt.threshvals-1;i++){
272 if(a[o]<tt.quantthresh[i]){
273 break;
274 }
275 }
276 index=(index*tt.quantvals)+tt.quantmap[i];
277 }
278 // regular lattices are easy :-)
279 if(c.lengthlist[index]>0){
280 // is this unused? If so, we'll
281 // use a decision tree after all
282 // and fall through
283 return(index);
284 }
285 }
286 if(nt!=null){
287 // optimized using the decision tree
288 while(true){
289 float c=0.f;
290 int p=nt.p[ptr];
291 int q=nt.q[ptr];
292 for(int k=0,o=0;k<dim;k++,o+=step){
293 c+=(valuelist[p+k]-valuelist[q+k])*
294 (a[o]-(valuelist[p+k]+valuelist[q+k])*.5);
295 }
296 if(c>0.){ // in A
297 ptr= -nt.ptr0[ptr];
298 }
299 else{ // in B
300 ptr= -nt.ptr1[ptr];
301 }
302 if(ptr<=0)break;
303 }
304 return(-ptr);
305 }
306
307 // brute force it!
308 {
309 int besti=-1;
310 float best=0.f;
311 int e=0;
312 for(int i=0;i<entries;i++){
313 if(c.lengthlist[i]>0){
314 float _this=dist(dim, valuelist, e, a, step);
315 if(besti==-1 || _this<best){
316 best=_this;
317 besti=i;
318 }
319 }
320 e+=dim;
321 }
322 return(besti);
323 }
324 }
325
326 // returns the entry number and *modifies a* to the remainder value
327 int besterror(float[] a, int step, int addmul){
328 int best=best(a,step);
329 switch(addmul){
330 case 0:
331 for(int i=0,o=0;i<dim;i++,o+=step)
332 a[o]-=valuelist[best*dim+i];
333 break;
334 case 1:
335 for(int i=0,o=0;i<dim;i++,o+=step){
336 float val=valuelist[best*dim+i];
337 if(val==0){
338 a[o]=0;
339 }else{
340 a[o]/=val;
341 }
342 }
343 break;
344 }
345 return(best);
346 }
347
348 void clear(){
349 // static book is not cleared; we're likely called on the lookup and
350 // the static codebook belongs to the info struct
351 //if(decode_tree!=null){
352 // free(b->decode_tree->ptr0);
353 // free(b->decode_tree->ptr1);
354 // memset(b->decode_tree,0,sizeof(decode_aux));
355 // free(b->decode_tree);
356 //}
357 //if(valuelist!=null)free(b->valuelist);
358 //if(codelist!=null)free(b->codelist);
359 //memset(b,0,sizeof(codebook));
360 }
361
362 private static float dist(int el, float[] ref, int index, float[] b, int step){
363 float acc=(float)0.;
364 for(int i=0; i<el; i++){
365 float val=(ref[index+i]-b[i*step]);
366 acc+=val*val;
367 }
368 return(acc);
369 }
370
371/*
372 int init_encode(StaticCodeBook s){
373 //memset(c,0,sizeof(codebook));
374 c=s;
375 entries=s.entries;
376 dim=s.dim;
377 codelist=make_words(s.lengthlist, s.entries);
378 valuelist=s.unquantize();
379 return(0);
380 }
381*/
382
383 int init_decode(StaticCodeBook s){
384 //memset(c,0,sizeof(codebook));
385 c=s;
386 entries=s.entries;
387 dim=s.dim;
388 valuelist=s.unquantize();
389
390 decode_tree=make_decode_tree();
391 if(decode_tree==null){
392 //goto err_out;
393 clear();
394 return(-1);
395 }
396 return(0);
397// err_out:
398// vorbis_book_clear(c);
399// return(-1);
400 }
401
402 // given a list of word lengths, generate a list of codewords. Works
403 // for length ordered or unordered, always assigns the lowest valued
404 // codewords first. Extended to handle unused entries (length 0)
405 static int[] make_words(int[] l, int n){
406 int[] marker=new int[33];
407 int[] r=new int[n];
408 //memset(marker,0,sizeof(marker));
409
410 for(int i=0;i<n;i++){
411 int length=l[i];
412 if(length>0){
413 int entry=marker[length];
414
415 // when we claim a node for an entry, we also claim the nodes
416 // below it (pruning off the imagined tree that may have dangled
417 // from it) as well as blocking the use of any nodes directly
418 // above for leaves
419
420 // update ourself
421 if(length<32 && (entry>>>length)!=0){
422 // error condition; the lengths must specify an overpopulated tree
423 //free(r);
424 return(null);
425 }
426 r[i]=entry;
427
428 // Look to see if the next shorter marker points to the node
429 // above. if so, update it and repeat.
430 {
431 for(int j=length;j>0;j--){
432 if((marker[j]&1)!=0){
433 // have to jump branches
434 if(j==1)marker[1]++;
435 else marker[j]=marker[j-1]<<1;
436 break; // invariant says next upper marker would already
437 // have been moved if it was on the same path
438 }
439 marker[j]++;
440 }
441 }
442
443 // prune the tree; the implicit invariant says all the longer
444 // markers were dangling from our just-taken node. Dangle them
445 // from our *new* node.
446 for(int j=length+1;j<33;j++){
447 if((marker[j]>>>1) == entry){
448 entry=marker[j];
449 marker[j]=marker[j-1]<<1;
450 }
451 else{
452 break;
453 }
454 }
455 }
456 }
457
458 // bitreverse the words because our bitwise packer/unpacker is LSb
459 // endian
460 for(int i=0;i<n;i++){
461 int temp=0;
462 for(int j=0;j<l[i];j++){
463 temp<<=1;
464 temp|=(r[i]>>>j)&1;
465 }
466 r[i]=temp;
467 }
468
469 return(r);
470 }
471
472 // build the decode helper tree from the codewords
473 DecodeAux make_decode_tree(){
474 int top=0;
475 DecodeAux t=new DecodeAux();
476 int[] ptr0=t.ptr0=new int[entries*2];
477 int[] ptr1=t.ptr1=new int[entries*2];
478 int[] codelist=make_words(c.lengthlist, c.entries);
479
480 if(codelist==null)return(null);
481 t.aux=entries*2;
482
483 for(int i=0;i<entries;i++){
484 if(c.lengthlist[i]>0){
485 int ptr=0;
486 int j;
487 for(j=0;j<c.lengthlist[i]-1;j++){
488 int bit=(codelist[i]>>>j)&1;
489 if(bit==0){
490 if(ptr0[ptr]==0){
491 ptr0[ptr]=++top;
492 }
493 ptr=ptr0[ptr];
494 }
495 else{
496 if(ptr1[ptr]==0){
497 ptr1[ptr]= ++top;
498 }
499 ptr=ptr1[ptr];
500 }
501 }
502
503 if(((codelist[i]>>>j)&1)==0){ ptr0[ptr]=-i; }
504 else{ ptr1[ptr]=-i; }
505
506 }
507 }
508 //free(codelist);
509
510 t.tabn = ilog(entries)-4;
511
512 if(t.tabn<5)t.tabn=5;
513 int n = 1<<t.tabn;
514 t.tab = new int[n];
515 t.tabl = new int[n];
516 for(int i = 0; i < n; i++){
517 int p = 0;
518 int j=0;
519 for(j = 0; j < t.tabn && (p > 0 || j == 0); j++){
520 if ((i&(1<<j))!=0){
521 p = ptr1[p];
522 }
523 else{
524 p = ptr0[p];
525 }
526 }
527 t.tab[i]=p; // -code
528 t.tabl[i]=j; // length
529 }
530
531 return(t);
532 }
533
534 private static int ilog(int v){
535 int ret=0;
536 while(v!=0){
537 ret++;
538 v>>>=1;
539 }
540 return(ret);
541 }
542
543/*
544 // TEST
545 // Simple enough; pack a few candidate codebooks, unpack them. Code a
546 // number of vectors through (keeping track of the quantized values),
547 // and decode using the unpacked book. quantized version of in should
548 // exactly equal out
549
550 //#include "vorbis/book/lsp20_0.vqh"
551 //#include "vorbis/book/lsp32_0.vqh"
552 //#include "vorbis/book/res0_1a.vqh"
553 static final int TESTSIZE=40;
554
555 static float[] test1={
556 0.105939,
557 0.215373,
558 0.429117,
559 0.587974,
560
561 0.181173,
562 0.296583,
563 0.515707,
564 0.715261,
565
566 0.162327,
567 0.263834,
568 0.342876,
569 0.406025,
570
571 0.103571,
572 0.223561,
573 0.368513,
574 0.540313,
575
576 0.136672,
577 0.395882,
578 0.587183,
579 0.652476,
580
581 0.114338,
582 0.417300,
583 0.525486,
584 0.698679,
585
586 0.147492,
587 0.324481,
588 0.643089,
589 0.757582,
590
591 0.139556,
592 0.215795,
593 0.324559,
594 0.399387,
595
596 0.120236,
597 0.267420,
598 0.446940,
599 0.608760,
600
601 0.115587,
602 0.287234,
603 0.571081,
604 0.708603,
605 };
606
607 static float[] test2={
608 0.088654,
609 0.165742,
610 0.279013,
611 0.395894,
612
613 0.110812,
614 0.218422,
615 0.283423,
616 0.371719,
617
618 0.136985,
619 0.186066,
620 0.309814,
621 0.381521,
622
623 0.123925,
624 0.211707,
625 0.314771,
626 0.433026,
627
628 0.088619,
629 0.192276,
630 0.277568,
631 0.343509,
632
633 0.068400,
634 0.132901,
635 0.223999,
636 0.302538,
637
638 0.202159,
639 0.306131,
640 0.360362,
641 0.416066,
642
643 0.072591,
644 0.178019,
645 0.304315,
646 0.376516,
647
648 0.094336,
649 0.188401,
650 0.325119,
651 0.390264,
652
653 0.091636,
654 0.223099,
655 0.282899,
656 0.375124,
657 };
658
659 static float[] test3={
660 0,1,-2,3,4,-5,6,7,8,9,
661 8,-2,7,-1,4,6,8,3,1,-9,
662 10,11,12,13,14,15,26,17,18,19,
663 30,-25,-30,-1,-5,-32,4,3,-2,0};
664
665// static_codebook *testlist[]={&_vq_book_lsp20_0,
666// &_vq_book_lsp32_0,
667// &_vq_book_res0_1a,NULL};
668 static[][] float testvec={test1,test2,test3};
669
670 static void main(String[] arg){
671 Buffer write=new Buffer();
672 Buffer read=new Buffer();
673 int ptr=0;
674 write.writeinit();
675
676 System.err.println("Testing codebook abstraction...:");
677
678 while(testlist[ptr]!=null){
679 CodeBook c=new CodeBook();
680 StaticCodeBook s=new StaticCodeBook();;
681 float *qv=alloca(sizeof(float)*TESTSIZE);
682 float *iv=alloca(sizeof(float)*TESTSIZE);
683 memcpy(qv,testvec[ptr],sizeof(float)*TESTSIZE);
684 memset(iv,0,sizeof(float)*TESTSIZE);
685
686 System.err.print("\tpacking/coding "+ptr+"... ");
687
688 // pack the codebook, write the testvector
689 write.reset();
690 vorbis_book_init_encode(&c,testlist[ptr]); // get it into memory
691 // we can write
692 vorbis_staticbook_pack(testlist[ptr],&write);
693 System.err.print("Codebook size "+write.bytes()+" bytes... ");
694 for(int i=0;i<TESTSIZE;i+=c.dim){
695 vorbis_book_encodev(&c,qv+i,&write);
696 }
697 c.clear();
698
699 System.err.print("OK.\n");
700 System.err.print("\tunpacking/decoding "+ptr+"... ");
701
702 // transfer the write data to a read buffer and unpack/read
703 _oggpack_readinit(&read,_oggpack_buffer(&write),_oggpack_bytes(&write));
704 if(s.unpack(read)){
705 System.err.print("Error unpacking codebook.\n");
706 System.exit(1);
707 }
708 if(vorbis_book_init_decode(&c,&s)){
709 System.err.print("Error initializing codebook.\n");
710 System.exit(1);
711 }
712 for(int i=0;i<TESTSIZE;i+=c.dim){
713 if(vorbis_book_decodevs(&c,iv+i,&read,1,-1)==-1){
714 System.err.print("Error reading codebook test data (EOP).\n");
715 System.exit(1);
716 }
717 }
718 for(int i=0;i<TESTSIZE;i++){
719 if(fabs(qv[i]-iv[i])>.000001){
720 System.err.print("read ("+iv[i]+") != written ("+qv[i]+") at position ("+i+")\n");
721 System.exit(1);
722 }
723 }
724
725 System.err.print("OK\n");
726 ptr++;
727 }
728 // The above is the trivial stuff;
729 // now try unquantizing a log scale codebook
730 }
731*/
732}
733
734class DecodeAux{
735 int[] tab;
736 int[] tabl;
737 int tabn;
738
739 int[] ptr0;
740 int[] ptr1;
741 int aux; // number of tree entries
742}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30// the comments are not part of vorbis_info so that vorbis_info can be
31// static storage
32public class Comment{
33 private static byte[] _vorbis="vorbis".getBytes();
34
35 private static final int OV_EFAULT=-129;
36 private static final int OV_EIMPL=-130;
37
38 // unlimited user comment fields. libvorbis writes 'libvorbis'
39 // whatever vendor is set to in encode
40 public byte[][] user_comments;
41 public int[] comment_lengths;
42 public int comments;
43 public byte[] vendor;
44
45 public void init(){
46 user_comments=null;
47 comments=0;
48 vendor=null;
49 }
50
51 public void add(String comment){
52 add(comment.getBytes());
53 }
54
55 private void add(byte[] comment){
56 byte[][] foo=new byte[comments+2][];
57 if(user_comments!=null){
58 System.arraycopy(user_comments, 0, foo, 0, comments);
59 }
60 user_comments=foo;
61
62 int[] goo=new int[comments+2];
63 if(comment_lengths!=null){
64 System.arraycopy(comment_lengths, 0, goo, 0, comments);
65 }
66 comment_lengths=goo;
67
68 byte[] bar=new byte[comment.length+1];
69 System.arraycopy(comment, 0, bar, 0, comment.length);
70 user_comments[comments]=bar;
71 comment_lengths[comments]=comment.length;
72 comments++;
73 user_comments[comments]=null;
74 }
75
76 public void add_tag(String tag, String contents){
77 if(contents==null) contents="";
78 add(tag+"="+contents);
79 }
80
81/*
82 private void add_tag(byte[] tag, byte[] contents){
83 byte[] foo=new byte[tag.length+contents.length+1];
84 int j=0;
85 for(int i=0; i<tag.length; i++){foo[j++]=tag[i];}
86 foo[j++]=(byte)'='; j++;
87 for(int i=0; i<contents.length; i++){foo[j++]=tag[i];}
88 add(foo);
89 }
90*/
91
92 // This is more or less the same as strncasecmp - but that doesn't exist
93 // * everywhere, and this is a fairly trivial function, so we include it
94 static boolean tagcompare(byte[] s1, byte[] s2, int n){
95 int c=0;
96 byte u1, u2;
97 while(c < n){
98 u1=s1[c]; u2=s2[c];
99 if('Z'>=u1 && u1>='A')u1=(byte)(u1-'A'+'a');
100 if('Z'>=u2 && u2>='A')u2=(byte)(u2-'A'+'a');
101 if(u1!=u2){ return false; }
102 c++;
103 }
104 return true;
105 }
106
107 public String query(String tag){
108 return query(tag, 0);
109 }
110
111 public String query(String tag, int count){
112 int foo=query(tag.getBytes(), count);
113 if(foo==-1)return null;
114 byte[] comment=user_comments[foo];
115 for(int i=0; i<comment_lengths[foo]; i++){
116 if(comment[i]=='='){
117 return new String(comment, i+1, comment_lengths[foo]-(i+1));
118 }
119 }
120 return null;
121 }
122
123 private int query(byte[] tag, int count){
124 int i=0;
125 int found = 0;
126 int fulltaglen = tag.length + 1;
127 byte[] fulltag = new byte[fulltaglen];
128 System.arraycopy(tag, 0, fulltag, 0, tag.length);
129 fulltag[tag.length]=(byte)'=';
130
131 for(i=0;i<comments;i++){
132 if(tagcompare(user_comments[i], fulltag, fulltaglen)){
133 if(count==found){
134 // We return a pointer to the data, not a copy
135 //return user_comments[i] + taglen + 1;
136 return i;
137 }
138 else{ found++; }
139 }
140 }
141 return -1;
142 }
143
144 int unpack(Buffer opb){
145 int vendorlen=opb.read(32);
146 if(vendorlen<0){
147 //goto err_out;
148 clear();
149 return(-1);
150 }
151 vendor=new byte[vendorlen+1];
152 opb.read(vendor,vendorlen);
153 comments=opb.read(32);
154 if(comments<0){
155 //goto err_out;
156 clear();
157 return(-1);
158 }
159 user_comments=new byte[comments+1][];
160 comment_lengths=new int[comments+1];
161
162 for(int i=0;i<comments;i++){
163 int len=opb.read(32);
164 if(len<0){
165 //goto err_out;
166 clear();
167 return(-1);
168 }
169 comment_lengths[i]=len;
170 user_comments[i]=new byte[len+1];
171 opb.read(user_comments[i], len);
172 }
173 if(opb.read(1)!=1){
174 //goto err_out; // EOP check
175 clear();
176 return(-1);
177
178 }
179 return(0);
180// err_out:
181// comment_clear(vc);
182// return(-1);
183 }
184
185 int pack(Buffer opb){
186 byte[] temp="Xiphophorus libVorbis I 20000508".getBytes();
187
188 // preamble
189 opb.write(0x03,8);
190 opb.write(_vorbis);
191
192 // vendor
193 opb.write(temp.length,32);
194 opb.write(temp);
195
196 // comments
197
198 opb.write(comments,32);
199 if(comments!=0){
200 for(int i=0;i<comments;i++){
201 if(user_comments[i]!=null){
202 opb.write(comment_lengths[i],32);
203 opb.write(user_comments[i]);
204 }
205 else{
206 opb.write(0,32);
207 }
208 }
209 }
210 opb.write(1,1);
211 return(0);
212 }
213
214 public int header_out(Packet op){
215 Buffer opb=new Buffer();
216 opb.writeinit();
217
218 if(pack(opb)!=0) return OV_EIMPL;
219
220 op.packet_base = new byte[opb.bytes()];
221 op.packet=0;
222 op.bytes=opb.bytes();
223 System.arraycopy(opb.buffer(), 0, op.packet_base, 0, op.bytes);
224 op.b_o_s=0;
225 op.e_o_s=0;
226 op.granulepos=0;
227 return 0;
228 }
229
230 void clear(){
231 for(int i=0;i<comments;i++)
232 user_comments[i]=null;
233 user_comments=null;
234 vendor=null;
235 }
236
237 public String getVendor(){
238 return new String(vendor, 0, vendor.length-1);
239 }
240 public String getComment(int i){
241 if(comments<=i)return null;
242 return new String(user_comments[i], 0, user_comments[i].length-1);
243 }
244 public String toString(){
245 String foo="Vendor: "+new String(vendor, 0, vendor.length-1);
246 for(int i=0; i<comments; i++){
247 foo=foo+"\nComment: "+new String(user_comments[i], 0, user_comments[i].length-1);
248 }
249 foo=foo+"\n";
250 return foo;
251 }
252}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30// Takes a vorbis bitstream from stdin and writes raw stereo PCM to
31// stdout. Decodes simple and chained OggVorbis files from beginning
32// to end. Vorbisfile.a is somewhat more complex than the code below.
33
34class DecodeExample{
35 static int convsize=4096*2;
36 static byte[] convbuffer=new byte[convsize]; // take 8k out of the data segment, not the stack
37
38 public static void main(String[] arg){
39 java.io.InputStream input=System.in;
40 if(arg.length>0){
41 try{
42 input=new java.io.FileInputStream(arg[0]);
43 }
44 catch(Exception e){
45 System.err.println(e);
46 }
47 }
48
49 SyncState oy=new SyncState(); // sync and verify incoming physical bitstream
50 StreamState os=new StreamState(); // take physical pages, weld into a logical stream of packets
51 Page og=new Page(); // one Ogg bitstream page. Vorbis packets are inside
52 Packet op=new Packet(); // one raw packet of data for decode
53
54 Info vi=new Info(); // struct that stores all the static vorbis bitstream settings
55 Comment vc=new Comment(); // struct that stores all the bitstream user comments
56 DspState vd=new DspState(); // central working state for the packet->PCM decoder
57 Block vb=new Block(vd); // local working space for packet->PCM decode
58
59 byte[] buffer;
60 int bytes=0;
61
62 // Decode setup
63
64 oy.init(); // Now we can read pages
65
66 while(true){ // we repeat if the bitstream is chained
67 int eos=0;
68
69 // grab some data at the head of the stream. We want the first page
70 // (which is guaranteed to be small and only contain the Vorbis
71 // stream initial header) We need the first page to get the stream
72 // serialno.
73
74 // submit a 4k block to libvorbis' Ogg layer
75 int index=oy.buffer(4096);
76 buffer=oy.data;
77 try{
78 bytes=input.read(buffer, index, 4096);
79 }
80 catch(Exception e){
81 System.err.println(e);
82 System.exit(-1);
83 }
84 oy.wrote(bytes);
85
86 // Get the first page.
87 if(oy.pageout(og)!=1){
88 // have we simply run out of data? If so, we're done.
89 if(bytes<4096)break;
90
91 // error case. Must not be Vorbis data
92 System.err.println("Input does not appear to be an Ogg bitstream.");
93 System.exit(1);
94 }
95
96 // Get the serial number and set up the rest of decode.
97 // serialno first; use it to set up a logical stream
98 os.init(og.serialno());
99
100 // extract the initial header from the first page and verify that the
101 // Ogg bitstream is in fact Vorbis data
102
103 // I handle the initial header first instead of just having the code
104 // read all three Vorbis headers at once because reading the initial
105 // header is an easy way to identify a Vorbis bitstream and it's
106 // useful to see that functionality seperated out.
107
108 vi.init();
109 vc.init();
110 if(os.pagein(og)<0){
111 // error; stream version mismatch perhaps
112 System.err.println("Error reading first page of Ogg bitstream data.");
113 System.exit(1);
114 }
115
116 if(os.packetout(op)!=1){
117 // no page? must not be vorbis
118 System.err.println("Error reading initial header packet.");
119 System.exit(1);
120 }
121
122 if(vi.synthesis_headerin(vc,op)<0){
123 // error case; not a vorbis header
124 System.err.println("This Ogg bitstream does not contain Vorbis audio data.");
125 System.exit(1);
126 }
127
128 // At this point, we're sure we're Vorbis. We've set up the logical
129 // (Ogg) bitstream decoder. Get the comment and codebook headers and
130 // set up the Vorbis decoder
131
132 // The next two packets in order are the comment and codebook headers.
133 // They're likely large and may span multiple pages. Thus we reead
134 // and submit data until we get our two pacakets, watching that no
135 // pages are missing. If a page is missing, error out; losing a
136 // header page is the only place where missing data is fatal. */
137
138 int i=0;
139 while(i<2){
140 while(i<2){
141
142 int result=oy.pageout(og);
143 if(result==0) break; // Need more data
144 // Don't complain about missing or corrupt data yet. We'll
145 // catch it at the packet output phase
146
147 if(result==1){
148 os.pagein(og); // we can ignore any errors here
149 // as they'll also become apparent
150 // at packetout
151 while(i<2){
152 result=os.packetout(op);
153 if(result==0)break;
154 if(result==-1){
155 // Uh oh; data at some point was corrupted or missing!
156 // We can't tolerate that in a header. Die.
157 System.err.println("Corrupt secondary header. Exiting.");
158 System.exit(1);
159 }
160 vi.synthesis_headerin(vc,op);
161 i++;
162 }
163 }
164 }
165 // no harm in not checking before adding more
166 index=oy.buffer(4096);
167 buffer=oy.data;
168 try{
169 bytes=input.read(buffer, index, 4096);
170 }
171 catch(Exception e){
172 System.err.println(e);
173 System.exit(1);
174 }
175 if(bytes==0 && i<2){
176 System.err.println("End of file before finding all Vorbis headers!");
177 System.exit(1);
178 }
179 oy.wrote(bytes);
180 }
181
182 // Throw the comments plus a few lines about the bitstream we're
183 // decoding
184 {
185 byte[][] ptr=vc.user_comments;
186 for(int j=0; j<ptr.length;j++){
187 if(ptr[j]==null) break;
188 System.err.println(new String(ptr[j], 0, ptr[j].length-1));
189 }
190 System.err.println("\nBitstream is "+vi.channels+" channel, "+vi.rate+"Hz");
191 System.err.println("Encoded by: "+new String(vc.vendor, 0, vc.vendor.length-1)+"\n");
192 }
193
194 convsize=4096/vi.channels;
195
196 // OK, got and parsed all three headers. Initialize the Vorbis
197 // packet->PCM decoder.
198 vd.synthesis_init(vi); // central decode state
199 vb.init(vd); // local state for most of the decode
200 // so multiple block decodes can
201 // proceed in parallel. We could init
202 // multiple vorbis_block structures
203 // for vd here
204
205 float[][][] _pcm=new float[1][][];
206 int[] _index=new int[vi.channels];
207 // The rest is just a straight decode loop until end of stream
208 while(eos==0){
209 while(eos==0){
210
211 int result=oy.pageout(og);
212 if(result==0)break; // need more data
213 if(result==-1){ // missing or corrupt data at this page position
214 System.err.println("Corrupt or missing data in bitstream; continuing...");
215 }
216 else{
217 os.pagein(og); // can safely ignore errors at
218 // this point
219 while(true){
220 result=os.packetout(op);
221
222 if(result==0)break; // need more data
223 if(result==-1){ // missing or corrupt data at this page position
224 // no reason to complain; already complained above
225 }
226 else{
227 // we have a packet. Decode it
228 int samples;
229 if(vb.synthesis(op)==0){ // test for success!
230 vd.synthesis_blockin(vb);
231 }
232
233 // **pcm is a multichannel float vector. In stereo, for
234 // example, pcm[0] is left, and pcm[1] is right. samples is
235 // the size of each channel. Convert the float values
236 // (-1.<=range<=1.) to whatever PCM format and write it out
237
238 while((samples=vd.synthesis_pcmout(_pcm, _index))>0){
239 float[][] pcm=_pcm[0];
240 boolean clipflag=false;
241 int bout=(samples<convsize?samples:convsize);
242
243 // convert floats to 16 bit signed ints (host order) and
244 // interleave
245 for(i=0;i<vi.channels;i++){
246 int ptr=i*2;
247 //int ptr=i;
248 int mono=_index[i];
249 for(int j=0;j<bout;j++){
250 int val=(int)(pcm[i][mono+j]*32767.);
251// short val=(short)(pcm[i][mono+j]*32767.);
252// int val=(int)Math.round(pcm[i][mono+j]*32767.);
253 // might as well guard against clipping
254 if(val>32767){
255 val=32767;
256 clipflag=true;
257 }
258 if(val<-32768){
259 val=-32768;
260 clipflag=true;
261 }
262 if(val<0) val=val|0x8000;
263 convbuffer[ptr]=(byte)(val);
264 convbuffer[ptr+1]=(byte)(val>>>8);
265 ptr+=2*(vi.channels);
266 }
267 }
268
269 //if(clipflag)
270 // System.err.println("Clipping in frame "+vd.sequence);
271
272 System.out.write(convbuffer, 0, 2*vi.channels*bout);
273
274 vd.synthesis_read(bout); // tell libvorbis how
275 // many samples we
276 // actually consumed
277 }
278 }
279 }
280 if(og.eos()!=0)eos=1;
281 }
282 }
283 if(eos==0){
284 index=oy.buffer(4096);
285 buffer=oy.data;
286 try{
287 bytes=input.read(buffer,index,4096);
288 }
289 catch(Exception e){
290 System.err.println(e);
291 System.exit(1);
292 }
293 oy.wrote(bytes);
294 if(bytes==0)eos=1;
295 }
296 }
297
298 // clean up this logical bitstream; before exit we see if we're
299 // followed by another [chained]
300
301 os.clear();
302
303 // ogg_page and ogg_packet structs always point to storage in
304 // libvorbis. They're never freed or manipulated directly
305
306 vb.clear();
307 vd.clear();
308 vi.clear(); // must be called last
309 }
310
311 // OK, clean up the framer
312 oy.clear();
313 System.err.println("Done.");
314 }
315}
316
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28class Drft{
29 int n;
30 float[] trigcache;
31 int[] splitcache;
32
33 void backward(float[] data){
34 //System.err.println("Drft.backward");
35 if(n==1)return;
36 drftb1(n,data,trigcache,trigcache,n,splitcache);
37 }
38
39 void init(int n){
40 //System.err.println("Drft.init");
41 this.n=n;
42 trigcache=new float[3*n];
43 splitcache=new int[32];
44 fdrffti(n, trigcache, splitcache);
45 }
46
47 void clear(){
48 //System.err.println("Drft.clear");
49 if(trigcache!=null)trigcache=null;
50 if(splitcache!=null)splitcache=null;
51// memset(l,0,sizeof(drft_lookup));
52 }
53
54 static int[] ntryh = { 4,2,3,5 };
55 static float tpi = 6.28318530717958647692528676655900577f;
56 static float hsqt2 = .70710678118654752440084436210485f;
57 static float taui = .86602540378443864676372317075293618f;
58 static float taur = -.5f;
59 static float sqrt2 = 1.4142135623730950488016887242097f;
60
61 static void drfti1(int n, float[] wa, int index, int[] ifac){
62 float arg,argh,argld,fi;
63 int ntry=0,i,j=-1;
64 int k1, l1, l2, ib;
65 int ld, ii, ip, is, nq, nr;
66 int ido, ipm, nfm1;
67 int nl=n;
68 int nf=0;
69
70 int state=101;
71
72 loop: while(true){
73 switch(state){
74 case 101:
75 j++;
76 if (j < 4)
77 ntry=ntryh[j];
78 else
79 ntry+=2;
80 case 104:
81 nq=nl/ntry;
82 nr=nl-ntry*nq;
83 if(nr!=0){
84 state=101;
85 break;
86 }
87 nf++;
88 ifac[nf+1]=ntry;
89 nl=nq;
90 if(ntry!=2){
91 state=107;
92 break;
93 }
94 if(nf==1){
95 state=107;
96 break;
97 }
98
99 for(i=1;i<nf;i++){
100 ib=nf-i+1;
101 ifac[ib+1]=ifac[ib];
102 }
103 ifac[2] = 2;
104 case 107:
105 if(nl!=1){
106 state=104;
107 break;
108 }
109 ifac[0]=n;
110 ifac[1]=nf;
111 argh=tpi/n;
112 is=0;
113 nfm1=nf-1;
114 l1=1;
115
116 if(nfm1==0)return;
117
118 for (k1=0;k1<nfm1;k1++){
119 ip=ifac[k1+2];
120 ld=0;
121 l2=l1*ip;
122 ido=n/l2;
123 ipm=ip-1;
124
125 for (j=0;j<ipm;j++){
126 ld+=l1;
127 i=is;
128 argld=(float)ld*argh;
129 fi=0.f;
130 for (ii=2;ii<ido;ii+=2){
131 fi+=1.f;
132 arg=fi*argld;
133 wa[index+i++]=(float)Math.cos(arg);
134 wa[index+i++]=(float)Math.sin(arg);
135 }
136 is+=ido;
137 }
138 l1=l2;
139 }
140 break loop;
141 }
142 }
143 }
144
145 static void fdrffti(int n, float[] wsave, int[] ifac){
146//System.err.println("fdrffti: n="+n);
147 if(n == 1) return;
148 drfti1(n, wsave, n, ifac);
149 }
150
151 static void dradf2(int ido,int l1,float[] cc, float[] ch, float[] wa1, int index){
152 int i,k;
153 float ti2,tr2;
154 int t0,t1,t2,t3,t4,t5,t6;
155
156 t1=0;
157 t0=(t2=l1*ido);
158 t3=ido<<1;
159 for(k=0;k<l1;k++){
160 ch[t1<<1]=cc[t1]+cc[t2];
161 ch[(t1<<1)+t3-1]=cc[t1]-cc[t2];
162 t1+=ido;
163 t2+=ido;
164 }
165
166 if(ido<2)return;
167
168 if(ido!=2){
169 t1=0;
170 t2=t0;
171 for(k=0;k<l1;k++){
172 t3=t2;
173 t4=(t1<<1)+(ido<<1);
174 t5=t1;
175 t6=t1+t1;
176 for(i=2;i<ido;i+=2){
177 t3+=2;
178 t4-=2;
179 t5+=2;
180 t6+=2;
181 tr2=wa1[index+i-2]*cc[t3-1]+wa1[index+i-1]*cc[t3];
182 ti2=wa1[index+i-2]*cc[t3]-wa1[index+i-1]*cc[t3-1];
183 ch[t6]=cc[t5]+ti2;
184 ch[t4]=ti2-cc[t5];
185 ch[t6-1]=cc[t5-1]+tr2;
186 ch[t4-1]=cc[t5-1]-tr2;
187 }
188 t1+=ido;
189 t2+=ido;
190 }
191 if(ido%2==1)return;
192 }
193
194 t3=(t2=(t1=ido)-1);
195 t2+=t0;
196 for(k=0;k<l1;k++){
197 ch[t1]=-cc[t2];
198 ch[t1-1]=cc[t3];
199 t1+=ido<<1;
200 t2+=ido;
201 t3+=ido;
202 }
203 }
204
205 static void dradf4(int ido,int l1,float[] cc, float[] ch,
206 float[] wa1, int index1,
207 float[] wa2, int index2,
208 float[] wa3, int index3){
209 int i,k,t0,t1,t2,t3,t4,t5,t6;
210 float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
211 t0=l1*ido;
212
213 t1=t0;
214 t4=t1<<1;
215 t2=t1+(t1<<1);
216 t3=0;
217
218 for(k=0;k<l1;k++){
219 tr1=cc[t1]+cc[t2];
220 tr2=cc[t3]+cc[t4];
221
222 ch[t5=t3<<2]=tr1+tr2;
223 ch[(ido<<2)+t5-1]=tr2-tr1;
224 ch[(t5+=(ido<<1))-1]=cc[t3]-cc[t4];
225 ch[t5]=cc[t2]-cc[t1];
226
227 t1+=ido;
228 t2+=ido;
229 t3+=ido;
230 t4+=ido;
231 }
232 if(ido<2)return;
233
234 if(ido!=2){
235 t1=0;
236 for(k=0;k<l1;k++){
237 t2=t1;
238 t4=t1<<2;
239 t5=(t6=ido<<1)+t4;
240 for(i=2;i<ido;i+=2){
241 t3=(t2+=2);
242 t4+=2;
243 t5-=2;
244
245 t3+=t0;
246 cr2=wa1[index1+i-2]*cc[t3-1]+wa1[index1+i-1]*cc[t3];
247 ci2=wa1[index1+i-2]*cc[t3]-wa1[index1+i-1]*cc[t3-1];
248 t3+=t0;
249 cr3=wa2[index2+i-2]*cc[t3-1]+wa2[index2+i-1]*cc[t3];
250 ci3=wa2[index2+i-2]*cc[t3]-wa2[index2+i-1]*cc[t3-1];
251 t3+=t0;
252 cr4=wa3[index3+i-2]*cc[t3-1]+wa3[index3+i-1]*cc[t3];
253 ci4=wa3[index3+i-2]*cc[t3]-wa3[index3+i-1]*cc[t3-1];
254
255 tr1=cr2+cr4;
256 tr4=cr4-cr2;
257 ti1=ci2+ci4;
258 ti4=ci2-ci4;
259
260 ti2=cc[t2]+ci3;
261 ti3=cc[t2]-ci3;
262 tr2=cc[t2-1]+cr3;
263 tr3=cc[t2-1]-cr3;
264
265 ch[t4-1]=tr1+tr2;
266 ch[t4]=ti1+ti2;
267
268 ch[t5-1]=tr3-ti4;
269 ch[t5]=tr4-ti3;
270
271 ch[t4+t6-1]=ti4+tr3;
272 ch[t4+t6]=tr4+ti3;
273
274 ch[t5+t6-1]=tr2-tr1;
275 ch[t5+t6]=ti1-ti2;
276 }
277 t1+=ido;
278 }
279 if((ido&1)!=0)return;
280 }
281
282 t2=(t1=t0+ido-1)+(t0<<1);
283 t3=ido<<2;
284 t4=ido;
285 t5=ido<<1;
286 t6=ido;
287
288 for(k=0;k<l1;k++){
289 ti1=-hsqt2*(cc[t1]+cc[t2]);
290 tr1=hsqt2*(cc[t1]-cc[t2]);
291
292 ch[t4-1]=tr1+cc[t6-1];
293 ch[t4+t5-1]=cc[t6-1]-tr1;
294
295 ch[t4]=ti1-cc[t1+t0];
296 ch[t4+t5]=ti1+cc[t1+t0];
297
298 t1+=ido;
299 t2+=ido;
300 t4+=t3;
301 t6+=ido;
302 }
303 }
304
305 static void dradfg(int ido,int ip,int l1,int idl1,float[] cc,float[] c1,
306 float[] c2, float[] ch, float[] ch2, float[] wa, int index){
307 int idij,ipph,i,j,k,l,ic,ik,is;
308 int t0,t1,t2=0,t3,t4,t5,t6,t7,t8,t9,t10;
309 float dc2,ai1,ai2,ar1,ar2,ds2;
310 int nbd;
311 float dcp=0,arg,dsp=0,ar1h,ar2h;
312 int idp2,ipp2;
313
314 arg=tpi/(float)ip;
315 dcp=(float)Math.cos(arg);
316 dsp=(float)Math.sin(arg);
317 ipph=(ip+1)>>1;
318 ipp2=ip;
319 idp2=ido;
320 nbd=(ido-1)>>1;
321 t0=l1*ido;
322 t10=ip*ido;
323
324 int state=100;
325 loop: while(true){
326 switch(state){
327 case 101:
328 if(ido==1){
329 state=119;
330 break;
331 }
332 for(ik=0;ik<idl1;ik++)ch2[ik]=c2[ik];
333
334 t1=0;
335 for(j=1;j<ip;j++){
336 t1+=t0;
337 t2=t1;
338 for(k=0;k<l1;k++){
339 ch[t2]=c1[t2];
340 t2+=ido;
341 }
342 }
343
344 is=-ido;
345 t1=0;
346 if(nbd>l1){
347 for(j=1;j<ip;j++){
348 t1+=t0;
349 is+=ido;
350 t2= -ido+t1;
351 for(k=0;k<l1;k++){
352 idij=is-1;
353 t2+=ido;
354 t3=t2;
355 for(i=2;i<ido;i+=2){
356 idij+=2;
357 t3+=2;
358 ch[t3-1]=wa[index+idij-1]*c1[t3-1]+wa[index+idij]*c1[t3];
359 ch[t3]=wa[index+idij-1]*c1[t3]-wa[index+idij]*c1[t3-1];
360 }
361 }
362 }
363 }
364 else{
365
366 for(j=1;j<ip;j++){
367 is+=ido;
368 idij=is-1;
369 t1+=t0;
370 t2=t1;
371 for(i=2;i<ido;i+=2){
372 idij+=2;
373 t2+=2;
374 t3=t2;
375 for(k=0;k<l1;k++){
376 ch[t3-1]=wa[index+idij-1]*c1[t3-1]+wa[index+idij]*c1[t3];
377 ch[t3]=wa[index+idij-1]*c1[t3]-wa[index+idij]*c1[t3-1];
378 t3+=ido;
379 }
380 }
381 }
382 }
383
384 t1=0;
385 t2=ipp2*t0;
386 if(nbd<l1){
387 for(j=1;j<ipph;j++){
388 t1+=t0;
389 t2-=t0;
390 t3=t1;
391 t4=t2;
392 for(i=2;i<ido;i+=2){
393 t3+=2;
394 t4+=2;
395 t5=t3-ido;
396 t6=t4-ido;
397 for(k=0;k<l1;k++){
398 t5+=ido;
399 t6+=ido;
400 c1[t5-1]=ch[t5-1]+ch[t6-1];
401 c1[t6-1]=ch[t5]-ch[t6];
402 c1[t5]=ch[t5]+ch[t6];
403 c1[t6]=ch[t6-1]-ch[t5-1];
404 }
405 }
406 }
407 }
408 else{
409 for(j=1;j<ipph;j++){
410 t1+=t0;
411 t2-=t0;
412 t3=t1;
413 t4=t2;
414 for(k=0;k<l1;k++){
415 t5=t3;
416 t6=t4;
417 for(i=2;i<ido;i+=2){
418 t5+=2;
419 t6+=2;
420 c1[t5-1]=ch[t5-1]+ch[t6-1];
421 c1[t6-1]=ch[t5]-ch[t6];
422 c1[t5]=ch[t5]+ch[t6];
423 c1[t6]=ch[t6-1]-ch[t5-1];
424 }
425 t3+=ido;
426 t4+=ido;
427 }
428 }
429 }
430 case 119:
431 for(ik=0;ik<idl1;ik++)c2[ik]=ch2[ik];
432
433 t1=0;
434 t2=ipp2*idl1;
435 for(j=1;j<ipph;j++){
436 t1+=t0;
437 t2-=t0;
438 t3=t1-ido;
439 t4=t2-ido;
440 for(k=0;k<l1;k++){
441 t3+=ido;
442 t4+=ido;
443 c1[t3]=ch[t3]+ch[t4];
444 c1[t4]=ch[t4]-ch[t3];
445 }
446 }
447
448 ar1=1.f;
449 ai1=0.f;
450 t1=0;
451 t2=ipp2*idl1;
452 t3=(ip-1)*idl1;
453 for(l=1;l<ipph;l++){
454 t1+=idl1;
455 t2-=idl1;
456 ar1h=dcp*ar1-dsp*ai1;
457 ai1=dcp*ai1+dsp*ar1;
458 ar1=ar1h;
459 t4=t1;
460 t5=t2;
461 t6=t3;
462 t7=idl1;
463
464 for(ik=0;ik<idl1;ik++){
465 ch2[t4++]=c2[ik]+ar1*c2[t7++];
466 ch2[t5++]=ai1*c2[t6++];
467 }
468
469 dc2=ar1;
470 ds2=ai1;
471 ar2=ar1;
472 ai2=ai1;
473
474 t4=idl1;
475 t5=(ipp2-1)*idl1;
476 for(j=2;j<ipph;j++){
477 t4+=idl1;
478 t5-=idl1;
479
480 ar2h=dc2*ar2-ds2*ai2;
481 ai2=dc2*ai2+ds2*ar2;
482 ar2=ar2h;
483
484 t6=t1;
485 t7=t2;
486 t8=t4;
487 t9=t5;
488 for(ik=0;ik<idl1;ik++){
489 ch2[t6++]+=ar2*c2[t8++];
490 ch2[t7++]+=ai2*c2[t9++];
491 }
492 }
493 }
494 t1=0;
495 for(j=1;j<ipph;j++){
496 t1+=idl1;
497 t2=t1;
498 for(ik=0;ik<idl1;ik++)ch2[ik]+=c2[t2++];
499 }
500
501 if(ido<l1){
502 state=132;
503 break;
504 }
505
506 t1=0;
507 t2=0;
508 for(k=0;k<l1;k++){
509 t3=t1;
510 t4=t2;
511 for(i=0;i<ido;i++)cc[t4++]=ch[t3++];
512 t1+=ido;
513 t2+=t10;
514 }
515 state=135;
516 break;
517
518 case 132:
519 for(i=0;i<ido;i++){
520 t1=i;
521 t2=i;
522 for(k=0;k<l1;k++){
523 cc[t2]=ch[t1];
524 t1+=ido;
525 t2+=t10;
526 }
527 }
528 case 135:
529 t1=0;
530 t2=ido<<1;
531 t3=0;
532 t4=ipp2*t0;
533 for(j=1;j<ipph;j++){
534 t1+=t2;
535 t3+=t0;
536 t4-=t0;
537
538 t5=t1;
539 t6=t3;
540 t7=t4;
541
542 for(k=0;k<l1;k++){
543 cc[t5-1]=ch[t6];
544 cc[t5]=ch[t7];
545 t5+=t10;
546 t6+=ido;
547 t7+=ido;
548 }
549 }
550
551 if(ido==1)return;
552 if(nbd<l1){
553 state=141;
554 break;
555 }
556
557 t1=-ido;
558 t3=0;
559 t4=0;
560 t5=ipp2*t0;
561 for(j=1;j<ipph;j++){
562 t1+=t2;
563 t3+=t2;
564 t4+=t0;
565 t5-=t0;
566 t6=t1;
567 t7=t3;
568 t8=t4;
569 t9=t5;
570 for(k=0;k<l1;k++){
571 for(i=2;i<ido;i+=2){
572 ic=idp2-i;
573 cc[i+t7-1]=ch[i+t8-1]+ch[i+t9-1];
574 cc[ic+t6-1]=ch[i+t8-1]-ch[i+t9-1];
575 cc[i+t7]=ch[i+t8]+ch[i+t9];
576 cc[ic+t6]=ch[i+t9]-ch[i+t8];
577 }
578 t6+=t10;
579 t7+=t10;
580 t8+=ido;
581 t9+=ido;
582 }
583 }
584 return;
585 case 141:
586 t1=-ido;
587 t3=0;
588 t4=0;
589 t5=ipp2*t0;
590 for(j=1;j<ipph;j++){
591 t1+=t2;
592 t3+=t2;
593 t4+=t0;
594 t5-=t0;
595 for(i=2;i<ido;i+=2){
596 t6=idp2+t1-i;
597 t7=i+t3;
598 t8=i+t4;
599 t9=i+t5;
600 for(k=0;k<l1;k++){
601 cc[t7-1]=ch[t8-1]+ch[t9-1];
602 cc[t6-1]=ch[t8-1]-ch[t9-1];
603 cc[t7]=ch[t8]+ch[t9];
604 cc[t6]=ch[t9]-ch[t8];
605 t6+=t10;
606 t7+=t10;
607 t8+=ido;
608 t9+=ido;
609 }
610 }
611 }
612 break loop;
613 }
614 }
615 }
616
617 static void drftf1(int n,float[] c, float[] ch, float[] wa, int[] ifac){
618 int i,k1,l1,l2;
619 int na,kh,nf;
620 int ip,iw,ido,idl1,ix2,ix3;
621
622 nf=ifac[1];
623 na=1;
624 l2=n;
625 iw=n;
626
627 for(k1=0;k1<nf;k1++){
628 kh=nf-k1;
629 ip=ifac[kh+1];
630 l1=l2/ip;
631 ido=n/l2;
632 idl1=ido*l1;
633 iw-=(ip-1)*ido;
634 na=1-na;
635
636 int state=100;
637 loop: while(true){
638 switch(state){
639 case 100:
640 if(ip!=4){
641 state=102;
642 break;
643 }
644
645 ix2=iw+ido;
646 ix3=ix2+ido;
647 if(na!=0)
648 dradf4(ido,l1,ch,c,wa,iw-1,wa,ix2-1,wa,ix3-1);
649 else
650 dradf4(ido,l1,c,ch,wa,iw-1,wa,ix2-1,wa,ix3-1);
651 state=110;
652 break;
653 case 102:
654 if(ip!=2){
655 state=104;
656 break;
657 }
658 if(na!=0){
659 state=103;
660 break;
661 }
662 dradf2(ido,l1,c,ch,wa, iw-1);
663 state=110;
664 break;
665 case 103:
666 dradf2(ido,l1,ch,c,wa, iw-1);
667 case 104:
668 if(ido==1)na=1-na;
669 if(na!=0){
670 state=109;
671 break;
672 }
673 dradfg(ido,ip,l1,idl1,c,c,c,ch,ch,wa,iw-1);
674 na=1;
675 state=110;
676 break;
677 case 109:
678 dradfg(ido,ip,l1,idl1,ch,ch,ch,c,c,wa,iw-1);
679 na=0;
680 case 110:
681 l2=l1;
682 break loop;
683 }
684 }
685 }
686 if(na==1)return;
687 for(i=0;i<n;i++)c[i]=ch[i];
688 }
689
690 static void dradb2(int ido,int l1,float[] cc,float[] ch,float[] wa1, int index){
691 int i,k,t0,t1,t2,t3,t4,t5,t6;
692 float ti2,tr2;
693
694 t0=l1*ido;
695
696 t1=0;
697 t2=0;
698 t3=(ido<<1)-1;
699 for(k=0;k<l1;k++){
700 ch[t1]=cc[t2]+cc[t3+t2];
701 ch[t1+t0]=cc[t2]-cc[t3+t2];
702 t2=(t1+=ido)<<1;
703 }
704
705 if(ido<2)return;
706 if(ido!=2){
707 t1=0;
708 t2=0;
709 for(k=0;k<l1;k++){
710 t3=t1;
711 t5=(t4=t2)+(ido<<1);
712 t6=t0+t1;
713 for(i=2;i<ido;i+=2){
714 t3+=2;
715 t4+=2;
716 t5-=2;
717 t6+=2;
718 ch[t3-1]=cc[t4-1]+cc[t5-1];
719 tr2=cc[t4-1]-cc[t5-1];
720 ch[t3]=cc[t4]-cc[t5];
721 ti2=cc[t4]+cc[t5];
722 ch[t6-1]=wa1[index+i-2]*tr2-wa1[index+i-1]*ti2;
723 ch[t6]=wa1[index+i-2]*ti2+wa1[index+i-1]*tr2;
724 }
725 t2=(t1+=ido)<<1;
726 }
727 if((ido%2)==1)return;
728 }
729
730 t1=ido-1;
731 t2=ido-1;
732 for(k=0;k<l1;k++){
733 ch[t1]=cc[t2]+cc[t2];
734 ch[t1+t0]=-(cc[t2+1]+cc[t2+1]);
735 t1+=ido;
736 t2+=ido<<1;
737 }
738 }
739
740 static void dradb3(int ido,int l1,float[] cc,float[] ch,
741 float[] wa1, int index1,
742 float[] wa2, int index2){
743 int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10;
744 float ci2,ci3,di2,di3,cr2,cr3,dr2,dr3,ti2,tr2;
745 t0=l1*ido;
746
747 t1=0;
748 t2=t0<<1;
749 t3=ido<<1;
750 t4=ido+(ido<<1);
751 t5=0;
752 for(k=0;k<l1;k++){
753 tr2=cc[t3-1]+cc[t3-1];
754 cr2=cc[t5]+(taur*tr2);
755 ch[t1]=cc[t5]+tr2;
756 ci3=taui*(cc[t3]+cc[t3]);
757 ch[t1+t0]=cr2-ci3;
758 ch[t1+t2]=cr2+ci3;
759 t1+=ido;
760 t3+=t4;
761 t5+=t4;
762 }
763
764 if(ido==1)return;
765
766 t1=0;
767 t3=ido<<1;
768 for(k=0;k<l1;k++){
769 t7=t1+(t1<<1);
770 t6=(t5=t7+t3);
771 t8=t1;
772 t10=(t9=t1+t0)+t0;
773
774 for(i=2;i<ido;i+=2){
775 t5+=2;
776 t6-=2;
777 t7+=2;
778 t8+=2;
779 t9+=2;
780 t10+=2;
781 tr2=cc[t5-1]+cc[t6-1];
782 cr2=cc[t7-1]+(taur*tr2);
783 ch[t8-1]=cc[t7-1]+tr2;
784 ti2=cc[t5]-cc[t6];
785 ci2=cc[t7]+(taur*ti2);
786 ch[t8]=cc[t7]+ti2;
787 cr3=taui*(cc[t5-1]-cc[t6-1]);
788 ci3=taui*(cc[t5]+cc[t6]);
789 dr2=cr2-ci3;
790 dr3=cr2+ci3;
791 di2=ci2+cr3;
792 di3=ci2-cr3;
793 ch[t9-1]=wa1[index1+i-2]*dr2-wa1[index1+i-1]*di2;
794 ch[t9]=wa1[index1+i-2]*di2+wa1[index1+i-1]*dr2;
795 ch[t10-1]=wa2[index2+i-2]*dr3-wa2[index2+i-1]*di3;
796 ch[t10]=wa2[index2+i-2]*di3+wa2[index2+i-1]*dr3;
797 }
798 t1+=ido;
799 }
800 }
801
802 static void dradb4(int ido,int l1,float[] cc,float[] ch,
803 float[] wa1, int index1,
804 float[] wa2, int index2,
805 float[] wa3, int index3){
806 int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8;
807 float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
808 t0=l1*ido;
809
810 t1=0;
811 t2=ido<<2;
812 t3=0;
813 t6=ido<<1;
814 for(k=0;k<l1;k++){
815 t4=t3+t6;
816 t5=t1;
817 tr3=cc[t4-1]+cc[t4-1];
818 tr4=cc[t4]+cc[t4];
819 tr1=cc[t3]-cc[(t4+=t6)-1];
820 tr2=cc[t3]+cc[t4-1];
821 ch[t5]=tr2+tr3;
822 ch[t5+=t0]=tr1-tr4;
823 ch[t5+=t0]=tr2-tr3;
824 ch[t5+=t0]=tr1+tr4;
825 t1+=ido;
826 t3+=t2;
827 }
828
829 if(ido<2)return;
830 if(ido!=2){
831 t1=0;
832 for(k=0;k<l1;k++){
833 t5=(t4=(t3=(t2=t1<<2)+t6))+t6;
834 t7=t1;
835 for(i=2;i<ido;i+=2){
836 t2+=2;
837 t3+=2;
838 t4-=2;
839 t5-=2;
840 t7+=2;
841 ti1=cc[t2]+cc[t5];
842 ti2=cc[t2]-cc[t5];
843 ti3=cc[t3]-cc[t4];
844 tr4=cc[t3]+cc[t4];
845 tr1=cc[t2-1]-cc[t5-1];
846 tr2=cc[t2-1]+cc[t5-1];
847 ti4=cc[t3-1]-cc[t4-1];
848 tr3=cc[t3-1]+cc[t4-1];
849 ch[t7-1]=tr2+tr3;
850 cr3=tr2-tr3;
851 ch[t7]=ti2+ti3;
852 ci3=ti2-ti3;
853 cr2=tr1-tr4;
854 cr4=tr1+tr4;
855 ci2=ti1+ti4;
856 ci4=ti1-ti4;
857
858 ch[(t8=t7+t0)-1]=wa1[index1+i-2]*cr2-wa1[index1+i-1]*ci2;
859 ch[t8]=wa1[index1+i-2]*ci2+wa1[index1+i-1]*cr2;
860 ch[(t8+=t0)-1]=wa2[index2+i-2]*cr3-wa2[index2+i-1]*ci3;
861 ch[t8]=wa2[index2+i-2]*ci3+wa2[index2+i-1]*cr3;
862 ch[(t8+=t0)-1]=wa3[index3+i-2]*cr4-wa3[index3+i-1]*ci4;
863 ch[t8]=wa3[index3+i-2]*ci4+wa3[index3+i-1]*cr4;
864 }
865 t1+=ido;
866 }
867 if(ido%2 == 1)return;
868 }
869
870 t1=ido;
871 t2=ido<<2;
872 t3=ido-1;
873 t4=ido+(ido<<1);
874 for(k=0;k<l1;k++){
875 t5=t3;
876 ti1=cc[t1]+cc[t4];
877 ti2=cc[t4]-cc[t1];
878 tr1=cc[t1-1]-cc[t4-1];
879 tr2=cc[t1-1]+cc[t4-1];
880 ch[t5]=tr2+tr2;
881 ch[t5+=t0]=sqrt2*(tr1-ti1);
882 ch[t5+=t0]=ti2+ti2;
883 ch[t5+=t0]=-sqrt2*(tr1+ti1);
884
885 t3+=ido;
886 t1+=t2;
887 t4+=t2;
888 }
889 }
890
891 static void dradbg(int ido,int ip,int l1,int idl1,float[] cc,float[] c1,
892 float[] c2,float[] ch,float[] ch2,float[] wa, int index ){
893
894 int idij,ipph=0,i,j,k,l,ik,is,t0=0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10=0,
895 t11,t12;
896 float dc2,ai1,ai2,ar1,ar2,ds2;
897 int nbd=0;
898 float dcp=0,arg,dsp=0,ar1h,ar2h;
899 int ipp2=0;
900
901 int state=100;
902
903 loop: while(true){
904 switch(state){
905 case 100:
906 t10=ip*ido;
907 t0=l1*ido;
908 arg=tpi/(float)ip;
909 dcp=(float)Math.cos(arg);
910 dsp=(float)Math.sin(arg);
911 nbd=(ido-1)>>>1;
912 ipp2=ip;
913 ipph=(ip+1)>>>1;
914 if(ido<l1){
915 state=103;
916 break;
917 }
918 t1=0;
919 t2=0;
920 for(k=0;k<l1;k++){
921 t3=t1;
922 t4=t2;
923 for(i=0;i<ido;i++){
924 ch[t3]=cc[t4];
925 t3++;
926 t4++;
927 }
928 t1+=ido;
929 t2+=t10;
930 }
931 state=106;
932 break;
933 case 103:
934 t1=0;
935 for(i=0;i<ido;i++){
936 t2=t1;
937 t3=t1;
938 for(k=0;k<l1;k++){
939 ch[t2]=cc[t3];
940 t2+=ido;
941 t3+=t10;
942 }
943 t1++;
944 }
945 case 106:
946 t1=0;
947 t2=ipp2*t0;
948 t7=(t5=ido<<1);
949 for(j=1;j<ipph;j++){
950 t1+=t0;
951 t2-=t0;
952 t3=t1;
953 t4=t2;
954 t6=t5;
955 for(k=0;k<l1;k++){
956 ch[t3]=cc[t6-1]+cc[t6-1];
957 ch[t4]=cc[t6]+cc[t6];
958 t3+=ido;
959 t4+=ido;
960 t6+=t10;
961 }
962 t5+=t7;
963 }
964 if (ido == 1){
965 state=116;
966 break;
967 }
968 if(nbd<l1){
969 state=112;
970 break;
971 }
972
973 t1=0;
974 t2=ipp2*t0;
975 t7=0;
976 for(j=1;j<ipph;j++){
977 t1+=t0;
978 t2-=t0;
979 t3=t1;
980 t4=t2;
981
982 t7+=(ido<<1);
983 t8=t7;
984 for(k=0;k<l1;k++){
985 t5=t3;
986 t6=t4;
987 t9=t8;
988 t11=t8;
989 for(i=2;i<ido;i+=2){
990 t5+=2;
991 t6+=2;
992 t9+=2;
993 t11-=2;
994 ch[t5-1]=cc[t9-1]+cc[t11-1];
995 ch[t6-1]=cc[t9-1]-cc[t11-1];
996 ch[t5]=cc[t9]-cc[t11];
997 ch[t6]=cc[t9]+cc[t11];
998 }
999 t3+=ido;
1000 t4+=ido;
1001 t8+=t10;
1002 }
1003 }
1004 state=116;
1005 break;
1006 case 112:
1007 t1=0;
1008 t2=ipp2*t0;
1009 t7=0;
1010 for(j=1;j<ipph;j++){
1011 t1+=t0;
1012 t2-=t0;
1013 t3=t1;
1014 t4=t2;
1015 t7+=(ido<<1);
1016 t8=t7;
1017 t9=t7;
1018 for(i=2;i<ido;i+=2){
1019 t3+=2;
1020 t4+=2;
1021 t8+=2;
1022 t9-=2;
1023 t5=t3;
1024 t6=t4;
1025 t11=t8;
1026 t12=t9;
1027 for(k=0;k<l1;k++){
1028 ch[t5-1]=cc[t11-1]+cc[t12-1];
1029 ch[t6-1]=cc[t11-1]-cc[t12-1];
1030 ch[t5]=cc[t11]-cc[t12];
1031 ch[t6]=cc[t11]+cc[t12];
1032 t5+=ido;
1033 t6+=ido;
1034 t11+=t10;
1035 t12+=t10;
1036 }
1037 }
1038 }
1039 case 116:
1040 ar1=1.f;
1041 ai1=0.f;
1042 t1=0;
1043 t9=(t2=ipp2*idl1);
1044 t3=(ip-1)*idl1;
1045 for(l=1;l<ipph;l++){
1046 t1+=idl1;
1047 t2-=idl1;
1048
1049 ar1h=dcp*ar1-dsp*ai1;
1050 ai1=dcp*ai1+dsp*ar1;
1051 ar1=ar1h;
1052 t4=t1;
1053 t5=t2;
1054 t6=0;
1055 t7=idl1;
1056 t8=t3;
1057 for(ik=0;ik<idl1;ik++){
1058 c2[t4++]=ch2[t6++]+ar1*ch2[t7++];
1059 c2[t5++]=ai1*ch2[t8++];
1060 }
1061 dc2=ar1;
1062 ds2=ai1;
1063 ar2=ar1;
1064 ai2=ai1;
1065
1066 t6=idl1;
1067 t7=t9-idl1;
1068 for(j=2;j<ipph;j++){
1069 t6+=idl1;
1070 t7-=idl1;
1071 ar2h=dc2*ar2-ds2*ai2;
1072 ai2=dc2*ai2+ds2*ar2;
1073 ar2=ar2h;
1074 t4=t1;
1075 t5=t2;
1076 t11=t6;
1077 t12=t7;
1078 for(ik=0;ik<idl1;ik++){
1079 c2[t4++]+=ar2*ch2[t11++];
1080 c2[t5++]+=ai2*ch2[t12++];
1081 }
1082 }
1083 }
1084
1085 t1=0;
1086 for(j=1;j<ipph;j++){
1087 t1+=idl1;
1088 t2=t1;
1089 for(ik=0;ik<idl1;ik++)ch2[ik]+=ch2[t2++];
1090 }
1091
1092 t1=0;
1093 t2=ipp2*t0;
1094 for(j=1;j<ipph;j++){
1095 t1+=t0;
1096 t2-=t0;
1097 t3=t1;
1098 t4=t2;
1099 for(k=0;k<l1;k++){
1100 ch[t3]=c1[t3]-c1[t4];
1101 ch[t4]=c1[t3]+c1[t4];
1102 t3+=ido;
1103 t4+=ido;
1104 }
1105 }
1106
1107 if(ido==1){
1108 state=132;
1109 break;
1110 }
1111 if(nbd<l1){
1112 state=128;
1113 break;
1114 }
1115
1116 t1=0;
1117 t2=ipp2*t0;
1118 for(j=1;j<ipph;j++){
1119 t1+=t0;
1120 t2-=t0;
1121 t3=t1;
1122 t4=t2;
1123 for(k=0;k<l1;k++){
1124 t5=t3;
1125 t6=t4;
1126 for(i=2;i<ido;i+=2){
1127 t5+=2;
1128 t6+=2;
1129 ch[t5-1]=c1[t5-1]-c1[t6];
1130 ch[t6-1]=c1[t5-1]+c1[t6];
1131 ch[t5]=c1[t5]+c1[t6-1];
1132 ch[t6]=c1[t5]-c1[t6-1];
1133 }
1134 t3+=ido;
1135 t4+=ido;
1136 }
1137 }
1138 state=132;
1139 break;
1140 case 128:
1141 t1=0;
1142 t2=ipp2*t0;
1143 for(j=1;j<ipph;j++){
1144 t1+=t0;
1145 t2-=t0;
1146 t3=t1;
1147 t4=t2;
1148 for(i=2;i<ido;i+=2){
1149 t3+=2;
1150 t4+=2;
1151 t5=t3;
1152 t6=t4;
1153 for(k=0;k<l1;k++){
1154 ch[t5-1]=c1[t5-1]-c1[t6];
1155 ch[t6-1]=c1[t5-1]+c1[t6];
1156 ch[t5]=c1[t5]+c1[t6-1];
1157 ch[t6]=c1[t5]-c1[t6-1];
1158 t5+=ido;
1159 t6+=ido;
1160 }
1161 }
1162 }
1163 case 132:
1164 if(ido==1)return;
1165
1166 for(ik=0;ik<idl1;ik++)c2[ik]=ch2[ik];
1167
1168 t1=0;
1169 for(j=1;j<ip;j++){
1170 t2=(t1+=t0);
1171 for(k=0;k<l1;k++){
1172 c1[t2]=ch[t2];
1173 t2+=ido;
1174 }
1175 }
1176
1177 if(nbd>l1){
1178 state=139;
1179 break;
1180 }
1181
1182 is= -ido-1;
1183 t1=0;
1184 for(j=1;j<ip;j++){
1185 is+=ido;
1186 t1+=t0;
1187 idij=is;
1188 t2=t1;
1189 for(i=2;i<ido;i+=2){
1190 t2+=2;
1191 idij+=2;
1192 t3=t2;
1193 for(k=0;k<l1;k++){
1194 c1[t3-1]=wa[index+idij-1]*ch[t3-1]-wa[index+idij]*ch[t3];
1195 c1[t3]=wa[index+idij-1]*ch[t3]+wa[index+idij]*ch[t3-1];
1196 t3+=ido;
1197 }
1198 }
1199 }
1200 return;
1201
1202 case 139:
1203 is= -ido-1;
1204 t1=0;
1205 for(j=1;j<ip;j++){
1206 is+=ido;
1207 t1+=t0;
1208 t2=t1;
1209 for(k=0;k<l1;k++){
1210 idij=is;
1211 t3=t2;
1212 for(i=2;i<ido;i+=2){
1213 idij+=2;
1214 t3+=2;
1215 c1[t3-1]=wa[index+idij-1]*ch[t3-1]-wa[index+idij]*ch[t3];
1216 c1[t3]=wa[index+idij-1]*ch[t3]+wa[index+idij]*ch[t3-1];
1217 }
1218 t2+=ido;
1219 }
1220 }
1221 break loop;
1222 }
1223 }
1224 }
1225
1226 static void drftb1(int n, float[] c, float[] ch, float[] wa, int index, int[] ifac){
1227 int i,k1,l1,l2=0;
1228 int na;
1229 int nf,ip=0,iw,ix2,ix3,ido=0,idl1=0;
1230
1231 nf=ifac[1];
1232 na=0;
1233 l1=1;
1234 iw=1;
1235
1236 for(k1=0;k1<nf;k1++){
1237 int state=100;
1238 loop: while(true){
1239 switch(state){
1240 case 100:
1241 ip=ifac[k1 + 2];
1242 l2=ip*l1;
1243 ido=n/l2;
1244 idl1=ido*l1;
1245 if(ip!=4){
1246 state=103;
1247 break;
1248 }
1249 ix2=iw+ido;
1250 ix3=ix2+ido;
1251
1252 if(na!=0)
1253 dradb4(ido,l1,ch,c,wa,index+iw-1,wa,index+ix2-1,wa,index+ix3-1);
1254 else
1255 dradb4(ido,l1,c,ch,wa,index+iw-1,wa,index+ix2-1,wa,index+ix3-1);
1256 na=1-na;
1257 state=115;
1258 break;
1259 case 103:
1260 if(ip!=2){
1261 state=106;
1262 break;
1263 }
1264
1265 if(na!=0)
1266 dradb2(ido,l1,ch,c,wa,index+iw-1);
1267 else
1268 dradb2(ido,l1,c,ch,wa,index+iw-1);
1269 na=1-na;
1270 state=115;
1271 break;
1272
1273 case 106:
1274 if(ip!=3){
1275 state=109;
1276 break;
1277 }
1278
1279 ix2=iw+ido;
1280 if(na!=0)
1281 dradb3(ido,l1,ch,c,wa,index+iw-1,wa,index+ix2-1);
1282 else
1283 dradb3(ido,l1,c,ch,wa,index+iw-1,wa,index+ix2-1);
1284 na=1-na;
1285 state=115;
1286 break;
1287 case 109:
1288 // The radix five case can be translated later.....
1289 // if(ip!=5)goto L112;
1290 //
1291 //ix2=iw+ido;
1292 //ix3=ix2+ido;
1293 //ix4=ix3+ido;
1294 //if(na!=0)
1295 // dradb5(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1,wa+ix4-1);
1296 //else
1297 // dradb5(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1,wa+ix4-1);
1298 //na=1-na;
1299 //state=115;
1300 //break;
1301 if(na!=0)
1302 dradbg(ido,ip,l1,idl1,ch,ch,ch,c,c,wa,index+iw-1);
1303 else
1304 dradbg(ido,ip,l1,idl1,c,c,c,ch,ch,wa,index+iw-1);
1305 if(ido==1)na=1-na;
1306
1307 case 115:
1308 l1=l2;
1309 iw+=(ip-1)*ido;
1310 break loop;
1311 }
1312 }
1313 }
1314 if(na==0)return;
1315 for(i=0;i<n;i++)c[i]=ch[i];
1316 }
1317}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28public class DspState{
29 static final float M_PI=3.1415926539f;
30 static final int VI_TRANSFORMB=1;
31 static final int VI_WINDOWB=1;
32
33 int analysisp;
34 Info vi;
35 int modebits;
36
37 float[][] pcm;
38 //float[][] pcmret;
39 int pcm_storage;
40 int pcm_current;
41 int pcm_returned;
42
43 float[] multipliers;
44 int envelope_storage;
45 int envelope_current;
46
47 int eofflag;
48
49 int lW;
50 int W;
51 int nW;
52 int centerW;
53
54 long granulepos;
55 long sequence;
56
57 long glue_bits;
58 long time_bits;
59 long floor_bits;
60 long res_bits;
61
62 // local lookup storage
63//!! Envelope ve=new Envelope(); // envelope
64//float **window[2][2][2]; // block, leadin, leadout, type
65 float[][][][][] window; // block, leadin, leadout, type
66 //vorbis_look_transform **transform[2]; // block, type
67 Object[][] transform;
68 CodeBook[] fullbooks;
69 // backend lookups are tied to the mode, not the backend or naked mapping
70 Object[] mode;
71
72 // local storage, only used on the encoding side. This way the
73 // application does not need to worry about freeing some packets'
74 // memory and not others'; packet storage is always tracked.
75 // Cleared next call to a _dsp_ function
76 byte[] header;
77 byte[] header1;
78 byte[] header2;
79
80 public DspState(){
81 transform=new Object[2][];
82 window=new float[2][][][][];
83 window[0]=new float[2][][][];
84 window[0][0]=new float[2][][];
85 window[0][1]=new float[2][][];
86 window[0][0][0]=new float[2][];
87 window[0][0][1]=new float[2][];
88 window[0][1][0]=new float[2][];
89 window[0][1][1]=new float[2][];
90 window[1]=new float[2][][][];
91 window[1][0]=new float[2][][];
92 window[1][1]=new float[2][][];
93 window[1][0][0]=new float[2][];
94 window[1][0][1]=new float[2][];
95 window[1][1][0]=new float[2][];
96 window[1][1][1]=new float[2][];
97 }
98
99 private static int ilog2(int v){
100 int ret=0;
101 while(v>1){
102 ret++;
103 v>>>=1;
104 }
105 return(ret);
106 }
107
108 static float[] window(int type, int window, int left, int right){
109 float[] ret=new float[window];
110 switch(type){
111 case 0:
112 // The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*2pi)
113 {
114 int leftbegin=window/4-left/2;
115 int rightbegin=window-window/4-right/2;
116
117 for(int i=0;i<left;i++){
118 float x=(float)((i+.5)/left*M_PI/2.);
119 x=(float)Math.sin(x);
120 x*=x;
121 x*=M_PI/2.;
122 x=(float)Math.sin(x);
123 ret[i+leftbegin]=x;
124 }
125
126 for(int i=leftbegin+left;i<rightbegin;i++){
127 ret[i]=1.f;
128 }
129
130 for(int i=0;i<right;i++){
131 float x=(float)((right-i-.5)/right*M_PI/2.);
132 x=(float)Math.sin(x);
133 x*=x;
134 x*=M_PI/2.;
135 x=(float)Math.sin(x);
136 ret[i+rightbegin]=x;
137 }
138 }
139 break;
140 default:
141 //free(ret);
142 return(null);
143 }
144 return(ret);
145 }
146
147 // Analysis side code, but directly related to blocking. Thus it's
148 // here and not in analysis.c (which is for analysis transforms only).
149 // The init is here because some of it is shared
150
151 int init(Info vi, boolean encp){
152//System.err.println("DspState.init: vi="+vi+", encp="+encp);
153 //memset(v,0,sizeof(vorbis_dsp_state));
154 this.vi=vi;
155 modebits=ilog2(vi.modes);
156
157 transform[0]=new Object[VI_TRANSFORMB];
158 transform[1]=new Object[VI_TRANSFORMB];
159
160 // MDCT is tranform 0
161
162 transform[0][0]=new Mdct();
163 transform[1][0]=new Mdct();
164 ((Mdct)transform[0][0]).init(vi.blocksizes[0]);
165 ((Mdct)transform[1][0]).init(vi.blocksizes[1]);
166
167 window[0][0][0]=new float[VI_WINDOWB][];
168 window[0][0][1]=window[0][0][0];
169 window[0][1][0]=window[0][0][0];
170 window[0][1][1]=window[0][0][0];
171 window[1][0][0]=new float[VI_WINDOWB][];
172 window[1][0][1]=new float[VI_WINDOWB][];
173 window[1][1][0]=new float[VI_WINDOWB][];
174 window[1][1][1]=new float[VI_WINDOWB][];
175
176 for(int i=0;i<VI_WINDOWB;i++){
177 window[0][0][0][i]=
178 window(i,vi.blocksizes[0],vi.blocksizes[0]/2,vi.blocksizes[0]/2);
179 window[1][0][0][i]=
180 window(i,vi.blocksizes[1],vi.blocksizes[0]/2,vi.blocksizes[0]/2);
181 window[1][0][1][i]=
182 window(i,vi.blocksizes[1],vi.blocksizes[0]/2,vi.blocksizes[1]/2);
183 window[1][1][0][i]=
184 window(i,vi.blocksizes[1],vi.blocksizes[1]/2,vi.blocksizes[0]/2);
185 window[1][1][1][i]=
186 window(i,vi.blocksizes[1],vi.blocksizes[1]/2,vi.blocksizes[1]/2);
187 }
188
189// if(encp){ // encode/decode differ here
190// // finish the codebooks
191// fullbooks=new CodeBook[vi.books];
192// for(int i=0;i<vi.books;i++){
193// fullbooks[i]=new CodeBook();
194// fullbooks[i].init_encode(vi.book_param[i]);
195// }
196// analysisp=1;
197// }
198// else{
199 // finish the codebooks
200 fullbooks=new CodeBook[vi.books];
201 for(int i=0;i<vi.books;i++){
202 fullbooks[i]=new CodeBook();
203 fullbooks[i].init_decode(vi.book_param[i]);
204 }
205// }
206
207 // initialize the storage vectors to a decent size greater than the
208 // minimum
209
210 pcm_storage=8192; // we'll assume later that we have
211 // a minimum of twice the blocksize of
212 // accumulated samples in analysis
213 pcm=new float[vi.channels][];
214 //pcmret=new float[vi.channels][];
215 {
216 for(int i=0;i<vi.channels;i++){
217 pcm[i]=new float[pcm_storage];
218 }
219 }
220
221 // all 1 (large block) or 0 (small block)
222 // explicitly set for the sake of clarity
223 lW=0; // previous window size
224 W=0; // current window size
225
226 // all vector indexes; multiples of samples_per_envelope_step
227 centerW=vi.blocksizes[1]/2;
228
229 pcm_current=centerW;
230
231 // initialize all the mapping/backend lookups
232 mode=new Object[vi.modes];
233 for(int i=0;i<vi.modes;i++){
234 int mapnum=vi.mode_param[i].mapping;
235 int maptype=vi.map_type[mapnum];
236 mode[i]=FuncMapping.mapping_P[maptype].look(this,vi.mode_param[i],
237 vi.map_param[mapnum]);
238 }
239 return(0);
240 }
241
242 public int synthesis_init(Info vi){
243 init(vi, false);
244 // Adjust centerW to allow an easier mechanism for determining output
245 pcm_returned=centerW;
246 centerW-= vi.blocksizes[W]/4+vi.blocksizes[lW]/4;
247 granulepos=-1;
248 sequence=-1;
249 return(0);
250 }
251
252 DspState(Info vi){
253 this();
254 init(vi, false);
255 // Adjust centerW to allow an easier mechanism for determining output
256 pcm_returned=centerW;
257 centerW-= vi.blocksizes[W]/4+vi.blocksizes[lW]/4;
258 granulepos=-1;
259 sequence=-1;
260 }
261
262 // Unike in analysis, the window is only partially applied for each
263 // block. The time domain envelope is not yet handled at the point of
264 // calling (as it relies on the previous block).
265
266 public int synthesis_blockin(Block vb){
267 // Shift out any PCM/multipliers that we returned previously
268 // centerW is currently the center of the last block added
269 if(centerW>vi.blocksizes[1]/2 && pcm_returned>8192){
270 // don't shift too much; we need to have a minimum PCM buffer of
271 // 1/2 long block
272
273 int shiftPCM=centerW-vi.blocksizes[1]/2;
274 shiftPCM=(pcm_returned<shiftPCM?pcm_returned:shiftPCM);
275
276 pcm_current-=shiftPCM;
277 centerW-=shiftPCM;
278 pcm_returned-=shiftPCM;
279 if(shiftPCM!=0){
280 for(int i=0;i<vi.channels;i++){
281 System.arraycopy(pcm[i], shiftPCM, pcm[i], 0, pcm_current);
282 }
283 }
284 }
285
286 lW=W;
287 W=vb.W;
288 nW=-1;
289
290 glue_bits+=vb.glue_bits;
291 time_bits+=vb.time_bits;
292 floor_bits+=vb.floor_bits;
293 res_bits+=vb.res_bits;
294
295 if(sequence+1 != vb.sequence)granulepos=-1; // out of sequence; lose count
296
297 sequence=vb.sequence;
298
299 {
300 int sizeW=vi.blocksizes[W];
301 int _centerW=centerW+vi.blocksizes[lW]/4+sizeW/4;
302 int beginW=_centerW-sizeW/2;
303 int endW=beginW+sizeW;
304 int beginSl=0;
305 int endSl=0;
306
307 // Do we have enough PCM/mult storage for the block?
308 if(endW>pcm_storage){
309 // expand the storage
310 pcm_storage=endW+vi.blocksizes[1];
311 for(int i=0;i<vi.channels;i++){
312 float[] foo=new float[pcm_storage];
313 System.arraycopy(pcm[i], 0, foo, 0, pcm[i].length);
314 pcm[i]=foo;
315 }
316 }
317
318 // overlap/add PCM
319 switch(W){
320 case 0:
321 beginSl=0;
322 endSl=vi.blocksizes[0]/2;
323 break;
324 case 1:
325 beginSl=vi.blocksizes[1]/4-vi.blocksizes[lW]/4;
326 endSl=beginSl+vi.blocksizes[lW]/2;
327 break;
328 }
329
330 for(int j=0;j<vi.channels;j++){
331 int _pcm=beginW;
332 // the overlap/add section
333 int i=0;
334 for(i=beginSl;i<endSl;i++){
335 pcm[j][_pcm+i]+=vb.pcm[j][i];
336 }
337 // the remaining section
338 for(;i<sizeW;i++){
339 pcm[j][_pcm+i]=vb.pcm[j][i];
340 }
341 }
342
343 // track the frame number... This is for convenience, but also
344 // making sure our last packet doesn't end with added padding. If
345 // the last packet is partial, the number of samples we'll have to
346 // return will be past the vb->granulepos.
347 //
348 // This is not foolproof! It will be confused if we begin
349 // decoding at the last page after a seek or hole. In that case,
350 // we don't have a starting point to judge where the last frame
351 // is. For this reason, vorbisfile will always try to make sure
352 // it reads the last two marked pages in proper sequence
353
354 if(granulepos==-1){
355 granulepos=vb.granulepos;
356 }
357 else{
358 granulepos+=(_centerW-centerW);
359 if(vb.granulepos!=-1 && granulepos!=vb.granulepos){
360 if(granulepos>vb.granulepos && vb.eofflag!=0){
361 // partial last frame. Strip the padding off
362 _centerW-=(granulepos-vb.granulepos);
363 }// else{ Shouldn't happen *unless* the bitstream is out of
364 // spec. Either way, believe the bitstream }
365 granulepos=vb.granulepos;
366 }
367 }
368
369 // Update, cleanup
370
371 centerW=_centerW;
372 pcm_current=endW;
373 if(vb.eofflag!=0)eofflag=1;
374 }
375 return(0);
376 }
377
378 // pcm==NULL indicates we just want the pending samples, no more
379 public int synthesis_pcmout(float[][][] _pcm, int[] index){
380 if(pcm_returned<centerW){
381 if(_pcm!=null){
382 for(int i=0;i<vi.channels;i++){
383// pcmret[i]=pcm[i]+v.pcm_returned;
384//!!!!!!!!
385 index[i]=pcm_returned;
386 }
387 _pcm[0]=pcm;
388 }
389 return(centerW-pcm_returned);
390 }
391 return(0);
392 }
393
394 public int synthesis_read(int bytes){
395 if(bytes!=0 && pcm_returned+bytes>centerW)return(-1);
396 pcm_returned+=bytes;
397 return(0);
398 }
399
400 public void clear(){
401/*
402 if(window[0][0][0]!=0){
403 for(i=0;i<VI_WINDOWB;i++)
404 if(v->window[0][0][0][i])free(v->window[0][0][0][i]);
405 free(v->window[0][0][0]);
406
407 for(j=0;j<2;j++)
408 for(k=0;k<2;k++){
409 for(i=0;i<VI_WINDOWB;i++)
410 if(v->window[1][j][k][i])free(v->window[1][j][k][i]);
411 free(v->window[1][j][k]);
412 }
413 }
414
415 if(v->pcm){
416 for(i=0;i<vi->channels;i++)
417 if(v->pcm[i])free(v->pcm[i]);
418 free(v->pcm);
419 if(v->pcmret)free(v->pcmret);
420 }
421 if(v->multipliers)free(v->multipliers);
422
423 _ve_envelope_clear(&v->ve);
424 if(v->transform[0]){
425 mdct_clear(v->transform[0][0]);
426 free(v->transform[0][0]);
427 free(v->transform[0]);
428 }
429 if(v->transform[1]){
430 mdct_clear(v->transform[1][0]);
431 free(v->transform[1][0]);
432 free(v->transform[1]);
433 }
434
435 // free mode lookups; these are actually vorbis_look_mapping structs
436 if(vi){
437 for(i=0;i<vi->modes;i++){
438 int mapnum=vi->mode_param[i]->mapping;
439 int maptype=vi->map_type[mapnum];
440 _mapping_P[maptype]->free_look(v->mode[i]);
441 }
442 // free codebooks
443 for(i=0;i<vi->books;i++)
444 vorbis_book_clear(v->fullbooks+i);
445 }
446
447 if(v->mode)free(v->mode);
448 if(v->fullbooks)free(v->fullbooks);
449
450 // free header, header1, header2
451 if(v->header)free(v->header);
452 if(v->header1)free(v->header1);
453 if(v->header2)free(v->header2);
454
455 memset(v,0,sizeof(vorbis_dsp_state));
456 }
457*/
458}
459}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28class EncodeAuxNearestMatch{
29 int[] ptr0;
30 int[] ptr1;
31
32 int[] p; // decision points (each is an entry)
33 int[] q; // decision points (each is an entry)
34 int aux; // number of tree entries
35 int alloc;
36}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28class EncodeAuxThreshMatch{
29 float[] quantthresh;
30 int[] quantmap;
31 int quantvals;
32 int threshvals;
33}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30class Floor0 extends FuncFloor{
31
32 void pack(Object i, Buffer opb){
33 InfoFloor0 info=(InfoFloor0)i;
34 opb.write(info.order,8);
35 opb.write(info.rate,16);
36 opb.write(info.barkmap,16);
37 opb.write(info.ampbits,6);
38 opb.write(info.ampdB,8);
39 opb.write(info.numbooks-1,4);
40 for(int j=0;j<info.numbooks;j++)
41 opb.write(info.books[j],8);
42 }
43
44 Object unpack(Info vi , Buffer opb){
45 InfoFloor0 info=new InfoFloor0();
46 info.order=opb.read(8);
47 info.rate=opb.read(16);
48 info.barkmap=opb.read(16);
49 info.ampbits=opb.read(6);
50 info.ampdB=opb.read(8);
51 info.numbooks=opb.read(4)+1;
52
53 if((info.order<1)||
54 (info.rate<1)||
55 (info.barkmap<1)||
56 (info.numbooks<1)){
57 //free_info(info);
58 return(null);
59 }
60
61 for(int j=0;j<info.numbooks;j++){
62 info.books[j]=opb.read(8);
63 if(info.books[j]<0 || info.books[j]>=vi.books){
64 //free_info(info);
65 return(null);
66 }
67 }
68 return(info);
69// err_out:
70// free_info(info);
71// return(NULL);
72 }
73 Object look(DspState vd, InfoMode mi, Object i){
74 float scale;
75 Info vi=vd.vi;
76 InfoFloor0 info=(InfoFloor0)i;
77 LookFloor0 look=new LookFloor0();
78 look.m=info.order;
79 look.n=vi.blocksizes[mi.blockflag]/2;
80 look.ln=info.barkmap;
81 look.vi=info;
82 look.lpclook.init(look.ln,look.m);
83
84 // we choose a scaling constant so that:
85 // floor(bark(rate/2-1)*C)=mapped-1
86 // floor(bark(rate/2)*C)=mapped
87 scale=look.ln/toBARK((float)(info.rate/2.));
88
89 // the mapping from a linear scale to a smaller bark scale is
90 // straightforward. We do *not* make sure that the linear mapping
91 // does not skip bark-scale bins; the decoder simply skips them and
92 // the encoder may do what it wishes in filling them. They're
93 // necessary in some mapping combinations to keep the scale spacing
94 // accurate
95 look.linearmap=new int[look.n];
96 for(int j=0;j<look.n;j++){
97 int val=(int)Math.floor(toBARK((float)((info.rate/2.)/look.n*j))
98 *scale); // bark numbers represent band edges
99 if(val>=look.ln)val=look.ln; // guard against the approximation
100 look.linearmap[j]=val;
101 }
102 return look;
103 }
104
105 static float toBARK(float f){
106 return (float)(13.1*Math.atan(.00074*(f))+2.24*Math.atan((f)*(f)*1.85e-8)+1e-4*(f));
107 }
108
109 Object state(Object i){
110 EchstateFloor0 state=new EchstateFloor0();
111 InfoFloor0 info=(InfoFloor0)i;
112
113 // a safe size if usually too big (dim==1)
114 state.codewords=new int[info.order];
115 state.curve=new float[info.barkmap];
116 state.frameno=-1;
117 return(state);
118 }
119 void free_info(Object i){}
120 void free_look(Object i){}
121 void free_state(Object vs){}
122 int forward(Block vb, Object i, float[] in, float[] out, Object vs){return 0;}
123
124 float[] lsp=null;
125 int inverse(Block vb, Object i, float[] out){
126 //System.err.println("Floor0.inverse "+i.getClass()+"]");
127 LookFloor0 look=(LookFloor0)i;
128 InfoFloor0 info=look.vi;
129 int ampraw=vb.opb.read(info.ampbits);
130 if(ampraw>0){ // also handles the -1 out of data case
131 int maxval=(1<<info.ampbits)-1;
132 float amp=(float)ampraw/maxval*info.ampdB;
133 int booknum=vb.opb.read(ilog(info.numbooks));
134
135 if(booknum!=-1 && booknum<info.numbooks){
136
137 synchronized(this){
138 if(lsp==null||lsp.length<look.m){
139 lsp=new float[look.m];
140 }
141 else{
142 for(int j=0; j<look.m; j++)lsp[j]=0.f;
143 }
144
145 CodeBook b=vb.vd.fullbooks[info.books[booknum]];
146 float last=0.f;
147
148 //memset(out,0,sizeof(float)*look->m);
149 for(int j=0; j<look.m; j++)out[j]=0.0f;
150
151 for(int j=0;j<look.m;j+=b.dim){
152 if(b.decodevs(lsp, j, vb.opb, 1, -1)==-1){
153 //goto eop;
154 // memset(out,0,sizeof(float)*look->n);
155 for(int k=0; k<look.n; k++)out[k]=0.0f;
156 return(0);
157 }
158 }
159 for(int j=0;j<look.m;){
160 for(int k=0;k<b.dim;k++,j++)lsp[j]+=last;
161 last=lsp[j-1];
162 }
163 // take the coefficients back to a spectral envelope curve
164 /*
165 lsp_to_lpc(out,out,look.m);
166 lpc_to_curve(out,out,amp,look,"",0);
167 for(int j=0;j<look.n;j++){
168 out[j]=fromdB(out[j]-info.ampdB);
169 }
170 */
171 Lsp.lsp_to_curve(out,look.linearmap,look.n,look.ln,
172 lsp,look.m,amp,info.ampdB);
173
174 return(1);
175 }
176 }
177 }
178// eop:
179// memset(out,0,sizeof(float)*look->n);
180 return(0);
181 }
182
183 Object inverse1(Block vb, Object i, Object memo){
184 //System.err.println("Floor0.inverse "+i.getClass()+"]");
185 LookFloor0 look=(LookFloor0)i;
186 InfoFloor0 info=look.vi;
187 float[] lsp=null;
188 if(memo instanceof float[]){
189 lsp=(float[])memo;
190 }
191
192 int ampraw=vb.opb.read(info.ampbits);
193 if(ampraw>0){ // also handles the -1 out of data case
194 int maxval=(1<<info.ampbits)-1;
195 float amp=(float)ampraw/maxval*info.ampdB;
196 int booknum=vb.opb.read(ilog(info.numbooks));
197
198 if(booknum!=-1 && booknum<info.numbooks){
199 CodeBook b=vb.vd.fullbooks[info.books[booknum]];
200 float last=0.f;
201
202 if(lsp==null||lsp.length<look.m+1){
203 lsp=new float[look.m+1];
204 }
205 else{
206 for(int j=0; j<lsp.length; j++)lsp[j]=0.f;
207 }
208
209 for(int j=0;j<look.m;j+=b.dim){
210 if(b.decodev_set(lsp, j, vb.opb, b.dim)==-1){
211 //goto eop;
212 return(null);
213 }
214 }
215
216 for(int j=0;j<look.m;){
217 for(int k=0;k<b.dim;k++,j++)lsp[j]+=last;
218 last=lsp[j-1];
219 }
220 lsp[look.m]=amp;
221 return(lsp);
222 }
223 }
224// eop:
225 return(null);
226 }
227
228 int inverse2(Block vb, Object i, Object memo, float[] out){
229 //System.err.println("Floor0.inverse "+i.getClass()+"]");
230 LookFloor0 look=(LookFloor0)i;
231 InfoFloor0 info=look.vi;
232
233 if(memo!=null){
234 float[] lsp=(float[])memo;
235 float amp=lsp[look.m];
236
237 Lsp.lsp_to_curve(out,look.linearmap,look.n,look.ln,
238 lsp,look.m,amp,info.ampdB);
239 return(1);
240 }
241// eop:
242// memset(out,0,sizeof(float)*look->n);
243 for(int j=0; j<look.n; j++){
244 out[j]=0.f;
245 }
246 return(0);
247 }
248
249 static float fromdB(float x){
250 return (float)(Math.exp((x)*.11512925));
251 }
252 private static int ilog(int v){
253 int ret=0;
254 while(v!=0){
255 ret++;
256 v>>>=1;
257 }
258 return(ret);
259 }
260
261 static void lsp_to_lpc(float[] lsp, float[] lpc, int m){
262 int i,j,m2=m/2;
263 float[] O=new float[m2];
264 float[] E=new float[m2];
265 float A;
266 float[] Ae=new float[m2+1];
267 float[] Ao=new float[m2+1];
268 float B;
269 float[] Be=new float[m2];
270 float[] Bo=new float[m2];
271 float temp;
272
273 // even/odd roots setup
274 for(i=0;i<m2;i++){
275 O[i]=(float)(-2.*Math.cos(lsp[i*2]));
276 E[i]=(float)(-2.*Math.cos(lsp[i*2+1]));
277 }
278
279 // set up impulse response
280 for(j=0;j<m2;j++){
281 Ae[j]=0.f;
282 Ao[j]=1.f;
283 Be[j]=0.f;
284 Bo[j]=1.f;
285 }
286 Ao[j]=1.f;
287 Ae[j]=1.f;
288
289 // run impulse response
290 for(i=1;i<m+1;i++){
291 A=B=0.f;
292 for(j=0;j<m2;j++){
293 temp=O[j]*Ao[j]+Ae[j];
294 Ae[j]=Ao[j];
295 Ao[j]=A;
296 A+=temp;
297
298 temp=E[j]*Bo[j]+Be[j];
299 Be[j]=Bo[j];
300 Bo[j]=B;
301 B+=temp;
302 }
303 lpc[i-1]=(A+Ao[j]+B-Ae[j])/2;
304 Ao[j]=A;
305 Ae[j]=B;
306 }
307 }
308
309 static void lpc_to_curve(float[] curve, float[] lpc,float amp,
310 LookFloor0 l, String name, int frameno){
311 // l->m+1 must be less than l->ln, but guard in case we get a bad stream
312 float[] lcurve=new float[Math.max(l.ln*2,l.m*2+2)];
313
314 if(amp==0){
315 //memset(curve,0,sizeof(float)*l->n);
316 for(int j=0; j<l.n; j++)curve[j]=0.0f;
317 return;
318 }
319 l.lpclook.lpc_to_curve(lcurve,lpc,amp);
320
321 for(int i=0;i<l.n;i++)curve[i]=lcurve[l.linearmap[i]];
322 }
323}
324
325class InfoFloor0{
326 int order;
327 int rate;
328 int barkmap;
329
330 int ampbits;
331 int ampdB;
332
333 int numbooks; // <= 16
334 int[] books=new int[16];
335}
336
337class LookFloor0{
338 int n;
339 int ln;
340 int m;
341 int[] linearmap;
342
343 InfoFloor0 vi;
344 Lpc lpclook=new Lpc();
345}
346
347class EchstateFloor0{
348 int[] codewords;
349 float[] curve;
350 long frameno;
351 long codes;
352}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30class Floor1 extends FuncFloor{
31 static final int floor1_rangedb=140;
32 static final int VIF_POSIT=63;
33
34 void pack(Object i, Buffer opb){
35 InfoFloor1 info=(InfoFloor1)i;
36
37 int count=0;
38 int rangebits;
39 int maxposit=info.postlist[1];
40 int maxclass=-1;
41
42 /* save out partitions */
43 opb.write(info.partitions,5); /* only 0 to 31 legal */
44 for(int j=0;j<info.partitions;j++){
45 opb.write(info.partitionclass[j],4); /* only 0 to 15 legal */
46 if(maxclass<info.partitionclass[j])
47 maxclass=info.partitionclass[j];
48 }
49
50 /* save out partition classes */
51 for(int j=0;j<maxclass+1;j++){
52 opb.write(info.class_dim[j]-1,3); /* 1 to 8 */
53 opb.write(info.class_subs[j],2); /* 0 to 3 */
54 if(info.class_subs[j]!=0){
55 opb.write(info.class_book[j],8);
56 }
57 for(int k=0;k<(1<<info.class_subs[j]);k++){
58 opb.write(info.class_subbook[j][k]+1,8);
59 }
60 }
61
62 /* save out the post list */
63 opb.write(info.mult-1,2); /* only 1,2,3,4 legal now */
64 opb.write(ilog2(maxposit),4);
65 rangebits=ilog2(maxposit);
66
67 for(int j=0,k=0;j<info.partitions;j++){
68 count+=info.class_dim[info.partitionclass[j]];
69 for(;k<count;k++){
70 opb.write(info.postlist[k+2],rangebits);
71 }
72 }
73 }
74
75 Object unpack(Info vi , Buffer opb){
76 int count=0,maxclass=-1,rangebits;
77 InfoFloor1 info=new InfoFloor1();
78
79 /* read partitions */
80 info.partitions=opb.read(5); /* only 0 to 31 legal */
81 for(int j=0;j<info.partitions;j++){
82 info.partitionclass[j]=opb.read(4); /* only 0 to 15 legal */
83 if(maxclass<info.partitionclass[j])
84 maxclass=info.partitionclass[j];
85 }
86
87 /* read partition classes */
88 for(int j=0;j<maxclass+1;j++){
89 info.class_dim[j]=opb.read(3)+1; /* 1 to 8 */
90 info.class_subs[j]=opb.read(2); /* 0,1,2,3 bits */
91 if(info.class_subs[j]<0){
92 //goto err_out;
93 info.free();
94 return(null);
95 }
96 if(info.class_subs[j]!=0){
97 info.class_book[j]=opb.read(8);
98 }
99 if(info.class_book[j]<0 || info.class_book[j]>=vi.books){
100 //goto err_out;
101 info.free();
102 return(null);
103 }
104 for(int k=0;k<(1<<info.class_subs[j]);k++){
105 info.class_subbook[j][k]=opb.read(8)-1;
106 if(info.class_subbook[j][k]<-1 || info.class_subbook[j][k]>=vi.books){
107 //goto err_out;
108 info.free();
109 return(null);
110 }
111 }
112 }
113
114 /* read the post list */
115 info.mult=opb.read(2)+1; /* only 1,2,3,4 legal now */
116 rangebits=opb.read(4);
117
118 for(int j=0,k=0;j<info.partitions;j++){
119 count+=info.class_dim[info.partitionclass[j]];
120 for(;k<count;k++){
121 int t=info.postlist[k+2]=opb.read(rangebits);
122 if(t<0 || t>=(1<<rangebits)){
123 //goto err_out;
124 info.free();
125 return(null);
126 }
127 }
128 }
129 info.postlist[0]=0;
130 info.postlist[1]=1<<rangebits;
131
132 return(info);
133// err_out:
134// info.free();
135// return(null);
136 }
137
138 Object look(DspState vd, InfoMode mi, Object i){
139 int _n=0;
140
141 int[] sortpointer=new int[VIF_POSIT+2];
142
143// Info vi=vd.vi;
144
145 InfoFloor1 info=(InfoFloor1)i;
146 LookFloor1 look=new LookFloor1();
147 look.vi=info;
148 look.n=info.postlist[1];
149
150 /* we drop each position value in-between already decoded values,
151 and use linear interpolation to predict each new value past the
152 edges. The positions are read in the order of the position
153 list... we precompute the bounding positions in the lookup. Of
154 course, the neighbors can change (if a position is declined), but
155 this is an initial mapping */
156
157 for(int j=0;j<info.partitions;j++){
158 _n+=info.class_dim[info.partitionclass[j]];
159 }
160 _n+=2;
161 look.posts=_n;
162
163 /* also store a sorted position index */
164 for(int j=0;j<_n;j++){
165 sortpointer[j]=j;
166 }
167// qsort(sortpointer,n,sizeof(int),icomp); // !!
168
169 int foo;
170 for(int j=0; j<_n-1; j++){
171 for(int k=j; k<_n; k++){
172 if(info.postlist[sortpointer[j]]>info.postlist[sortpointer[k]]){
173 foo=sortpointer[k];
174 sortpointer[k]=sortpointer[j];
175 sortpointer[j]=foo;
176 }
177 }
178 }
179
180 /* points from sort order back to range number */
181 for(int j=0;j<_n;j++){
182 look.forward_index[j]=sortpointer[j];
183 }
184 /* points from range order to sorted position */
185 for(int j=0;j<_n;j++){
186 look.reverse_index[look.forward_index[j]]=j;
187 }
188 /* we actually need the post values too */
189 for(int j=0;j<_n;j++){
190 look.sorted_index[j]=info.postlist[look.forward_index[j]];
191 }
192
193
194 /* quantize values to multiplier spec */
195 switch(info.mult){
196 case 1: /* 1024 -> 256 */
197 look.quant_q=256;
198 break;
199 case 2: /* 1024 -> 128 */
200 look.quant_q=128;
201 break;
202 case 3: /* 1024 -> 86 */
203 look.quant_q=86;
204 break;
205 case 4: /* 1024 -> 64 */
206 look.quant_q=64;
207 break;
208 default:
209 look.quant_q=-1;
210 }
211
212 /* discover our neighbors for decode where we don't use fit flags
213 (that would push the neighbors outward) */
214 for(int j=0;j<_n-2;j++){
215 int lo=0;
216 int hi=1;
217 int lx=0;
218 int hx=look.n;
219 int currentx=info.postlist[j+2];
220 for(int k=0;k<j+2;k++){
221 int x=info.postlist[k];
222 if(x>lx && x<currentx){
223 lo=k;
224 lx=x;
225 }
226 if(x<hx && x>currentx){
227 hi=k;
228 hx=x;
229 }
230 }
231 look.loneighbor[j]=lo;
232 look.hineighbor[j]=hi;
233 }
234
235 return look;
236 }
237
238 void free_info(Object i){}
239 void free_look(Object i){}
240 void free_state(Object vs){}
241
242 int forward(Block vb, Object i, float[] in, float[] out, Object vs){return 0;}
243
244 Object inverse1(Block vb, Object ii, Object memo){
245 //System.err.println("Floor1.inverse "+i.getClass()+"]");
246 LookFloor1 look=(LookFloor1)ii;
247 InfoFloor1 info=look.vi;
248 CodeBook[] books=vb.vd.fullbooks;
249
250 /* unpack wrapped/predicted values from stream */
251 if(vb.opb.read(1)==1){
252 int[] fit_value=null;
253 if(memo instanceof int[]){
254 fit_value=(int[])memo;
255 }
256 if(fit_value==null || fit_value.length<look.posts){
257 fit_value=new int[look.posts];
258 }
259 else{
260 for(int i=0; i<fit_value.length; i++) fit_value[i]=0;
261 }
262
263 fit_value[0]=vb.opb.read(ilog(look.quant_q-1));
264 fit_value[1]=vb.opb.read(ilog(look.quant_q-1));
265
266 /* partition by partition */
267 for(int i=0,j=2;i<info.partitions;i++){
268 int clss=info.partitionclass[i];
269 int cdim=info.class_dim[clss];
270 int csubbits=info.class_subs[clss];
271 int csub=1<<csubbits;
272 int cval=0;
273
274 /* decode the partition's first stage cascade value */
275 if(csubbits!=0){
276 cval=books[info.class_book[clss]].decode(vb.opb);
277
278 if(cval==-1){
279 //goto eop;
280 return(null);
281 }
282 }
283
284 for(int k=0;k<cdim;k++){
285 int book=info.class_subbook[clss][cval&(csub-1)];
286 cval>>>=csubbits;
287 if(book>=0){
288 if((fit_value[j+k]=books[book].decode(vb.opb))==-1){
289 //goto eop;
290 return(null);
291 }
292 }
293 else{
294 fit_value[j+k]=0;
295 }
296 }
297 j+=cdim;
298 }
299
300 /* unwrap positive values and reconsitute via linear interpolation */
301 for(int i=2;i<look.posts;i++){
302 int predicted=render_point(info.postlist[look.loneighbor[i-2]],
303 info.postlist[look.hineighbor[i-2]],
304 fit_value[look.loneighbor[i-2]],
305 fit_value[look.hineighbor[i-2]],
306 info.postlist[i]);
307 int hiroom=look.quant_q-predicted;
308 int loroom=predicted;
309 int room=(hiroom<loroom?hiroom:loroom)<<1;
310 int val=fit_value[i];
311
312 if(val!=0){
313 if(val>=room){
314 if(hiroom>loroom){
315 val = val-loroom;
316 }
317 else{
318 val = -1-(val-hiroom);
319 }
320 }
321 else{
322 if((val&1)!=0){
323 val= -((val+1)>>>1);
324 }
325 else{
326 val>>=1;
327 }
328 }
329
330 fit_value[i]=val+predicted;
331 fit_value[look.loneighbor[i-2]]&=0x7fff;
332 fit_value[look.hineighbor[i-2]]&=0x7fff;
333 }
334 else{
335 fit_value[i]=predicted|0x8000;
336 }
337 }
338 return(fit_value);
339 }
340
341// eop:
342// return(NULL);
343 return(null);
344 }
345
346 private static int render_point(int x0,int x1,int y0,int y1,int x){
347 y0&=0x7fff; /* mask off flag */
348 y1&=0x7fff;
349
350 {
351 int dy=y1-y0;
352 int adx=x1-x0;
353 int ady=Math.abs(dy);
354 int err=ady*(x-x0);
355
356 int off=(int)(err/adx);
357 if(dy<0)return(y0-off);
358 return(y0+off);
359 }
360 }
361
362 int inverse2(Block vb, Object i, Object memo, float[] out){
363 LookFloor1 look=(LookFloor1)i;
364 InfoFloor1 info=look.vi;
365 int n=vb.vd.vi.blocksizes[vb.mode]/2;
366
367 if(memo!=null){
368 /* render the lines */
369 int[] fit_value=(int[] )memo;
370 int hx=0;
371 int lx=0;
372 int ly=fit_value[0]*info.mult;
373 for(int j=1;j<look.posts;j++){
374 int current=look.forward_index[j];
375 int hy=fit_value[current]&0x7fff;
376 if(hy==fit_value[current]){
377 hy*=info.mult;
378 hx=info.postlist[current];
379
380 render_line(lx,hx,ly,hy,out);
381
382 lx=hx;
383 ly=hy;
384 }
385 }
386 for(int j=hx;j<n;j++){
387 out[j]*=out[j-1]; /* be certain */
388 }
389 return(1);
390 }
391 for(int j=0; j<n; j++){
392 out[j]=0.f;
393 }
394 return(0);
395 }
396
397
398 private static float[] FLOOR_fromdB_LOOKUP={
399 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F,
400 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F,
401 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F,
402 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F,
403 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F,
404 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F,
405 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F,
406 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F,
407 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F,
408 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F,
409 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F,
410 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F,
411 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F,
412 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F,
413 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F,
414 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F,
415 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F,
416 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F,
417 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F,
418 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F,
419 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F,
420 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F,
421 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F,
422 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F,
423 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F,
424 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F,
425 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F,
426 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F,
427 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F,
428 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F,
429 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F,
430 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F,
431 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F,
432 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F,
433 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F,
434 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F,
435 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F,
436 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F,
437 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F,
438 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F,
439 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F,
440 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F,
441 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F,
442 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F,
443 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F,
444 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F,
445 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F,
446 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F,
447 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F,
448 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F,
449 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F,
450 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F,
451 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F,
452 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F,
453 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F,
454 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F,
455 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F,
456 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F,
457 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F,
458 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F,
459 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F,
460 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F,
461 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F,
462 0.82788260F, 0.88168307F, 0.9389798F, 1.F
463 };
464
465 private static void render_line(int x0, int x1,int y0,int y1,float[] d){
466 int dy=y1-y0;
467 int adx=x1-x0;
468 int ady=Math.abs(dy);
469 int base=dy/adx;
470 int sy=(dy<0?base-1:base+1);
471 int x=x0;
472 int y=y0;
473 int err=0;
474
475 ady-=Math.abs(base*adx);
476
477 d[x]*=FLOOR_fromdB_LOOKUP[y];
478 while(++x<x1){
479 err=err+ady;
480 if(err>=adx){
481 err-=adx;
482 y+=sy;
483 }
484 else{
485 y+=base;
486 }
487 d[x]*=FLOOR_fromdB_LOOKUP[y];
488 }
489 }
490
491 static int ilog(int v){
492 int ret=0;
493 while(v!=0){
494 ret++;
495 v>>>=1;
496 }
497 return(ret);
498 }
499
500 private static int ilog2(int v){
501 int ret=0;
502 while(v>1){
503 ret++;
504 v>>>=1;
505 }
506 return(ret);
507 }
508}
509
510class InfoFloor1{
511 static final int VIF_POSIT=63;
512 static final int VIF_CLASS=16;
513 static final int VIF_PARTS=31;
514
515 int partitions; /* 0 to 31 */
516 int[] partitionclass=new int[VIF_PARTS]; /* 0 to 15 */
517
518 int[] class_dim=new int[VIF_CLASS]; /* 1 to 8 */
519 int[] class_subs=new int[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */
520 int[] class_book=new int[VIF_CLASS]; /* subs ^ dim entries */
521 int[][] class_subbook=new int[VIF_CLASS][]; /* [VIF_CLASS][subs] */
522
523
524 int mult; /* 1 2 3 or 4 */
525 int[] postlist=new int[VIF_POSIT+2]; /* first two implicit */
526
527
528 /* encode side analysis parameters */
529 float maxover;
530 float maxunder;
531 float maxerr;
532
533 int twofitminsize;
534 int twofitminused;
535 int twofitweight;
536 float twofitatten;
537 int unusedminsize;
538 int unusedmin_n;
539
540 int n;
541
542 InfoFloor1(){
543 for(int i=0; i<class_subbook.length; i++){
544 class_subbook[i]=new int[8];
545 }
546 }
547
548 void free(){
549 partitionclass=null;
550 class_dim=null;
551 class_subs=null;
552 class_book=null;
553 class_subbook=null;
554 postlist=null;
555 }
556
557 Object copy_info(){
558 InfoFloor1 info=this;
559 InfoFloor1 ret=new InfoFloor1();
560
561 ret.partitions=info.partitions;
562 System.arraycopy(info.partitionclass, 0, ret.partitionclass, 0, VIF_PARTS);
563 System.arraycopy(info.class_dim, 0, ret.class_dim, 0, VIF_CLASS);
564 System.arraycopy(info.class_subs, 0, ret.class_subs, 0, VIF_CLASS);
565 System.arraycopy(info.class_book, 0, ret.class_book, 0, VIF_CLASS);
566
567 for(int j=0; j<VIF_CLASS; j++){
568 System.arraycopy(info.class_subbook[j], 0,
569 ret.class_subbook[j], 0, 8);
570 }
571
572 ret.mult=info.mult;
573 System.arraycopy(info.postlist, 0, ret.postlist, 0, VIF_POSIT+2);
574
575 ret.maxover=info.maxover;
576 ret.maxunder=info.maxunder;
577 ret.maxerr=info.maxerr;
578
579 ret.twofitminsize=info.twofitminsize;
580 ret.twofitminused=info.twofitminused;
581 ret.twofitweight=info.twofitweight;
582 ret.twofitatten=info.twofitatten;
583 ret.unusedminsize=info.unusedminsize;
584 ret.unusedmin_n=info.unusedmin_n;
585
586 ret.n=info.n;
587
588 return(ret);
589 }
590
591}
592
593class LookFloor1{
594 static final int VIF_POSIT=63;
595
596 int[] sorted_index=new int[VIF_POSIT+2];
597 int[] forward_index=new int[VIF_POSIT+2];
598 int[] reverse_index=new int[VIF_POSIT+2];
599 int[] hineighbor=new int[VIF_POSIT];
600 int[] loneighbor=new int[VIF_POSIT];
601 int posts;
602
603 int n;
604 int quant_q;
605 InfoFloor1 vi;
606
607 int phrasebits;
608 int postbits;
609 int frames;
610
611 void free(){
612
613/*
614 System.out.println("floor 1 bit usage "+
615 (float)(phrasebits/frames)
616 +":"+
617 (float)(postbits/frames)
618 +"("+
619 (float)((postbits+phrasebits)/frames)
620 +" total)"
621
622*/
623
624 sorted_index=null;
625 forward_index=null;
626 reverse_index=null;
627 hineighbor=null;
628 loneighbor=null;
629 }
630}
631
632class Lsfit_acc{
633 long x0;
634 long x1;
635
636 long xa;
637 long ya;
638 long x2a;
639 long y2a;
640 long xya;
641 long n;
642 long an;
643 long un;
644 long edgey0;
645 long edgey1;
646}
647
648class EchstateFloor1{
649 int[] codewords;
650 float[] curve;
651 long frameno;
652 long codes;
653}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30abstract class FuncFloor{
31// public static FuncFloor[] floor_P={new Floor0()};
32 public static FuncFloor[] floor_P={new Floor0(),new Floor1()};
33
34 abstract void pack(Object i, Buffer opb);
35 abstract Object unpack(Info vi, Buffer opb);
36 abstract Object look(DspState vd, InfoMode mi, Object i);
37// abstract Object state(Object i);
38 abstract void free_info(Object i);
39 abstract void free_look(Object i);
40 abstract void free_state(Object vs);
41 abstract int forward(Block vb, Object i, float[] in, float[] out, Object vs);
42// abstract int inverse(Block vb, Object i, float[] out);
43 abstract Object inverse1(Block vb, Object i, Object memo);
44 abstract int inverse2(Block vb, Object i, Object memo, float[] out);
45}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30abstract class FuncMapping{
31 public static FuncMapping[] mapping_P={new Mapping0()};
32
33 abstract void pack(Info info , Object imap, Buffer buffer);
34 abstract Object unpack(Info info , Buffer buffer);
35 abstract Object look(DspState vd, InfoMode vm, Object m);
36 abstract void free_info(Object imap);
37 abstract void free_look(Object imap);
38// abstract int forward(Block vd, Object lm);
39 abstract int inverse(Block vd, Object lm);
40}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30abstract class FuncResidue{
31 public static FuncResidue[] residue_P={new Residue0(),
32 new Residue1(),
33 new Residue2()};
34
35 abstract void pack(Object vr, Buffer opb);
36 abstract Object unpack(Info vi, Buffer opb);
37 abstract Object look(DspState vd, InfoMode vm, Object vr);
38 abstract void free_info(Object i);
39 abstract void free_look(Object i);
40 abstract int forward(Block vb,Object vl, float[][] in, int ch);
41// abstract int inverse(Block vb, Object vl, float[][] in, int ch);
42abstract int inverse(Block vb, Object vl, float[][] in, int[] nonzero,int ch);
43}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30abstract class FuncTime{
31 public static FuncTime[] time_P={new Time0()};
32
33 abstract void pack(Object i, Buffer opb);
34 abstract Object unpack(Info vi , Buffer opb);
35 abstract Object look(DspState vd, InfoMode vm, Object i);
36 abstract void free_info(Object i);
37 abstract void free_look(Object i);
38 abstract int forward(Block vb, Object i);
39 abstract int inverse(Block vb, Object i, float[] in, float[] out);
40}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30public class Info{
31 private static final int OV_EBADPACKET=-136;
32 private static final int OV_ENOTAUDIO=-135;
33
34 private static byte[] _vorbis="vorbis".getBytes();
35 private static final int VI_TIMEB=1;
36// private static final int VI_FLOORB=1;
37 private static final int VI_FLOORB=2;
38// private static final int VI_RESB=1;
39 private static final int VI_RESB=3;
40 private static final int VI_MAPB=1;
41 private static final int VI_WINDOWB=1;
42
43 public int version;
44 public int channels;
45 public int rate;
46
47 // The below bitrate declarations are *hints*.
48 // Combinations of the three values carry the following implications:
49 //
50 // all three set to the same value:
51 // implies a fixed rate bitstream
52 // only nominal set:
53 // implies a VBR stream that averages the nominal bitrate. No hard
54 // upper/lower limit
55 // upper and or lower set:
56 // implies a VBR bitstream that obeys the bitrate limits. nominal
57 // may also be set to give a nominal rate.
58 // none set:
59 // the coder does not care to speculate.
60
61 int bitrate_upper;
62 int bitrate_nominal;
63 int bitrate_lower;
64
65 // Vorbis supports only short and long blocks, but allows the
66 // encoder to choose the sizes
67
68 int[] blocksizes=new int[2];
69
70 // modes are the primary means of supporting on-the-fly different
71 // blocksizes, different channel mappings (LR or mid-side),
72 // different residue backends, etc. Each mode consists of a
73 // blocksize flag and a mapping (along with the mapping setup
74
75 int modes;
76 int maps;
77 int times;
78 int floors;
79 int residues;
80 int books;
81 int psys; // encode only
82
83 InfoMode[] mode_param=null;
84
85 int[] map_type=null;
86 Object[] map_param=null;
87
88 int[] time_type=null;
89 Object[] time_param=null;
90
91 int[] floor_type=null;
92 Object[] floor_param=null;
93
94 int[] residue_type=null;
95 Object[] residue_param=null;
96
97 StaticCodeBook[] book_param=null;
98
99 PsyInfo[] psy_param=new PsyInfo[64]; // encode only
100
101 // for block long/sort tuning; encode only
102 int envelopesa;
103 float preecho_thresh;
104 float preecho_clamp;
105
106 // used by synthesis, which has a full, alloced vi
107 public void init(){
108 rate=0;
109 //memset(vi,0,sizeof(vorbis_info));
110 }
111
112 public void clear(){
113 for(int i=0;i<modes;i++){ mode_param[i]=null; }
114 mode_param=null;
115
116 for(int i=0;i<maps;i++){ // unpack does the range checking
117 FuncMapping.mapping_P[map_type[i]].free_info(map_param[i]);
118 }
119 map_param=null;
120
121 for(int i=0;i<times;i++){ // unpack does the range checking
122 FuncTime.time_P[time_type[i]].free_info(time_param[i]);
123 }
124 time_param=null;
125
126 for(int i=0;i<floors;i++){ // unpack does the range checking
127 FuncFloor.floor_P[floor_type[i]].free_info(floor_param[i]);
128 }
129 floor_param=null;
130
131 for(int i=0;i<residues;i++){ // unpack does the range checking
132 FuncResidue.residue_P[residue_type[i]].free_info(residue_param[i]);
133 }
134 residue_param=null;
135
136 // the static codebooks *are* freed if you call info_clear, because
137 // decode side does alloc a 'static' codebook. Calling clear on the
138 // full codebook does not clear the static codebook (that's our
139 // responsibility)
140 for(int i=0;i<books;i++){
141 // just in case the decoder pre-cleared to save space
142 if(book_param[i]!=null){
143 book_param[i].clear();
144 book_param[i]=null;
145 }
146 }
147 //if(vi->book_param)free(vi->book_param);
148 book_param=null;
149
150 for(int i=0;i<psys;i++){
151 psy_param[i].free();
152 }
153 //if(vi->psy_param)free(vi->psy_param);
154 //memset(vi,0,sizeof(vorbis_info));
155 }
156
157 // Header packing/unpacking
158 int unpack_info(Buffer opb){
159 version=opb.read(32);
160 if(version!=0)return(-1);
161
162 channels=opb.read(8);
163 rate=opb.read(32);
164
165 bitrate_upper=opb.read(32);
166 bitrate_nominal=opb.read(32);
167 bitrate_lower=opb.read(32);
168
169 blocksizes[0]=1<<opb.read(4);
170 blocksizes[1]=1<<opb.read(4);
171
172 if((rate<1) ||
173 (channels<1)||
174 (blocksizes[0]<8)||
175 (blocksizes[1]<blocksizes[0]) ||
176 (opb.read(1)!=1)){
177 //goto err_out; // EOP check
178 clear();
179 return(-1);
180 }
181 return(0);
182 // err_out:
183 // vorbis_info_clear(vi);
184 // return(-1);
185 }
186
187 // all of the real encoding details are here. The modes, books,
188 // everything
189 int unpack_books(Buffer opb){
190
191 //d* codebooks
192 books=opb.read(8)+1;
193
194 if(book_param==null || book_param.length!=books)
195 book_param=new StaticCodeBook[books];
196 for(int i=0;i<books;i++){
197 book_param[i]=new StaticCodeBook();
198 if(book_param[i].unpack(opb)!=0){
199 //goto err_out;
200 clear();
201 return(-1);
202 }
203 }
204
205 // time backend settings
206 times=opb.read(6)+1;
207 if(time_type==null || time_type.length!=times) time_type=new int[times];
208 if(time_param==null || time_param.length!=times)
209 time_param=new Object[times];
210 for(int i=0;i<times;i++){
211 time_type[i]=opb.read(16);
212 if(time_type[i]<0 || time_type[i]>=VI_TIMEB){
213 //goto err_out;
214 clear();
215 return(-1);
216 }
217 time_param[i]=FuncTime.time_P[time_type[i]].unpack(this, opb);
218 if(time_param[i]==null){
219 //goto err_out;
220 clear();
221 return(-1);
222 }
223 }
224
225 // floor backend settings
226 floors=opb.read(6)+1;
227 if(floor_type==null || floor_type.length!=floors)
228 floor_type=new int[floors];
229 if(floor_param==null || floor_param.length!=floors)
230 floor_param=new Object[floors];
231
232 for(int i=0;i<floors;i++){
233 floor_type[i]=opb.read(16);
234 if(floor_type[i]<0 || floor_type[i]>=VI_FLOORB){
235 //goto err_out;
236 clear();
237 return(-1);
238 }
239
240 floor_param[i]=FuncFloor.floor_P[floor_type[i]].unpack(this,opb);
241 if(floor_param[i]==null){
242 //goto err_out;
243 clear();
244 return(-1);
245 }
246 }
247
248 // residue backend settings
249 residues=opb.read(6)+1;
250
251 if(residue_type==null || residue_type.length!=residues)
252 residue_type=new int[residues];
253
254 if(residue_param==null || residue_param.length!=residues)
255 residue_param=new Object[residues];
256
257 for(int i=0;i<residues;i++){
258 residue_type[i]=opb.read(16);
259 if(residue_type[i]<0 || residue_type[i]>=VI_RESB){
260// goto err_out;
261 clear();
262 return(-1);
263 }
264 residue_param[i]=FuncResidue.residue_P[residue_type[i]].unpack(this,opb);
265 if(residue_param[i]==null){
266// goto err_out;
267 clear();
268 return(-1);
269 }
270 }
271
272 // map backend settings
273 maps=opb.read(6)+1;
274 if(map_type==null || map_type.length!=maps) map_type=new int[maps];
275 if(map_param==null || map_param.length!=maps) map_param=new Object[maps];
276 for(int i=0;i<maps;i++){
277 map_type[i]=opb.read(16);
278 if(map_type[i]<0 || map_type[i]>=VI_MAPB){
279// goto err_out;
280 clear();
281 return(-1);
282 }
283 map_param[i]=FuncMapping.mapping_P[map_type[i]].unpack(this,opb);
284 if(map_param[i]==null){
285// goto err_out;
286 clear();
287 return(-1);
288 }
289 }
290
291 // mode settings
292 modes=opb.read(6)+1;
293 if(mode_param==null || mode_param.length!=modes)
294 mode_param=new InfoMode[modes];
295 for(int i=0;i<modes;i++){
296 mode_param[i]=new InfoMode();
297 mode_param[i].blockflag=opb.read(1);
298 mode_param[i].windowtype=opb.read(16);
299 mode_param[i].transformtype=opb.read(16);
300 mode_param[i].mapping=opb.read(8);
301
302 if((mode_param[i].windowtype>=VI_WINDOWB)||
303 (mode_param[i].transformtype>=VI_WINDOWB)||
304 (mode_param[i].mapping>=maps)){
305// goto err_out;
306 clear();
307 return(-1);
308 }
309 }
310
311 if(opb.read(1)!=1){
312 //goto err_out; // top level EOP check
313 clear();
314 return(-1);
315 }
316
317 return(0);
318// err_out:
319// vorbis_info_clear(vi);
320// return(-1);
321 }
322
323 // The Vorbis header is in three packets; the initial small packet in
324 // the first page that identifies basic parameters, a second packet
325 // with bitstream comments and a third packet that holds the
326 // codebook.
327
328 public int synthesis_headerin(Comment vc, Packet op){
329 Buffer opb=new Buffer();
330
331 if(op!=null){
332 opb.readinit(op.packet_base, op.packet, op.bytes);
333
334 // Which of the three types of header is this?
335 // Also verify header-ness, vorbis
336 {
337 byte[] buffer=new byte[6];
338 int packtype=opb.read(8);
339 //memset(buffer,0,6);
340 opb.read(buffer,6);
341 if(buffer[0]!='v' || buffer[1]!='o' || buffer[2]!='r' ||
342 buffer[3]!='b' || buffer[4]!='i' || buffer[5]!='s'){
343 // not a vorbis header
344 return(-1);
345 }
346 switch(packtype){
347 case 0x01: // least significant *bit* is read first
348 if(op.b_o_s==0){
349 // Not the initial packet
350 return(-1);
351 }
352 if(rate!=0){
353 // previously initialized info header
354 return(-1);
355 }
356 return(unpack_info(opb));
357 case 0x03: // least significant *bit* is read first
358 if(rate==0){
359 // um... we didn't get the initial header
360 return(-1);
361 }
362 return(vc.unpack(opb));
363 case 0x05: // least significant *bit* is read first
364 if(rate==0 || vc.vendor==null){
365 // um... we didn;t get the initial header or comments yet
366 return(-1);
367 }
368 return(unpack_books(opb));
369 default:
370 // Not a valid vorbis header type
371 //return(-1);
372 break;
373 }
374 }
375 }
376 return(-1);
377 }
378
379 // pack side
380 int pack_info(Buffer opb){
381 // preamble
382 opb.write(0x01,8);
383 opb.write(_vorbis);
384
385 // basic information about the stream
386 opb.write(0x00,32);
387 opb.write(channels,8);
388 opb.write(rate,32);
389
390 opb.write(bitrate_upper,32);
391 opb.write(bitrate_nominal,32);
392 opb.write(bitrate_lower,32);
393
394 opb.write(ilog2(blocksizes[0]),4);
395 opb.write(ilog2(blocksizes[1]),4);
396 opb.write(1,1);
397 return(0);
398 }
399
400 int pack_books(Buffer opb){
401 opb.write(0x05,8);
402 opb.write(_vorbis);
403
404 // books
405 opb.write(books-1,8);
406 for(int i=0;i<books;i++){
407 if(book_param[i].pack(opb)!=0){
408 //goto err_out;
409 return(-1);
410 }
411 }
412
413 // times
414 opb.write(times-1,6);
415 for(int i=0;i<times;i++){
416 opb.write(time_type[i],16);
417 FuncTime.time_P[time_type[i]].pack(this.time_param[i],opb);
418 }
419
420 // floors
421 opb.write(floors-1,6);
422 for(int i=0;i<floors;i++){
423 opb.write(floor_type[i],16);
424 FuncFloor.floor_P[floor_type[i]].pack(floor_param[i],opb);
425 }
426
427 // residues
428 opb.write(residues-1,6);
429 for(int i=0;i<residues;i++){
430 opb.write(residue_type[i],16);
431 FuncResidue.residue_P[residue_type[i]].pack(residue_param[i],opb);
432 }
433
434 // maps
435 opb.write(maps-1,6);
436 for(int i=0;i<maps;i++){
437 opb.write(map_type[i],16);
438 FuncMapping.mapping_P[map_type[i]].pack(this,map_param[i],opb);
439 }
440
441 // modes
442 opb.write(modes-1,6);
443 for(int i=0;i<modes;i++){
444 opb.write(mode_param[i].blockflag,1);
445 opb.write(mode_param[i].windowtype,16);
446 opb.write(mode_param[i].transformtype,16);
447 opb.write(mode_param[i].mapping,8);
448 }
449 opb.write(1,1);
450 return(0);
451 //err_out:
452 //return(-1);
453 }
454
455// static void v_writestring(Buffer o, byte[] s){
456// int i=0;
457// while(s[i]!=0){
458// o.write(s[i++],8);
459// }
460// }
461
462// static void v_readstring(Buffer o, byte[] buf, int bytes){
463// int i=0
464// while(bytes--!=0){
465// buf[i++]=o.read(8);
466// }
467// }
468
469// private Buffer opb_blocksize=new Buffer();
470 public int blocksize(Packet op){
471 //codec_setup_info *ci=vi->codec_setup;
472 Buffer opb=new Buffer();
473// synchronized(opb_blocksize){
474 int mode;
475
476 opb.readinit(op.packet_base, op.packet, op.bytes);
477
478 /* Check the packet type */
479 if(opb.read(1)!=0){
480 /* Oops. This is not an audio data packet */
481 return(OV_ENOTAUDIO);
482 }
483 {
484 int modebits=0;
485 int v=modes;
486 while(v>1){
487 modebits++;
488 v>>>=1;
489 }
490
491 /* read our mode and pre/post windowsize */
492 mode=opb.read(modebits);
493 }
494 if(mode==-1)return(OV_EBADPACKET);
495 return(blocksizes[mode_param[mode].blockflag]);
496// }
497 }
498
499 private static int ilog2(int v){
500 int ret=0;
501 while(v>1){
502 ret++;
503 v>>>=1;
504 }
505 return(ret);
506 }
507
508 public String toString(){
509 return "version:"+new Integer(version)+
510 ", channels:"+new Integer(channels)+
511 ", rate:"+new Integer(rate)+
512 ", bitrate:"+new Integer(bitrate_upper)+","+
513 new Integer(bitrate_nominal)+","+
514 new Integer(bitrate_lower);
515 }
516}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28class InfoMode{
29 int blockflag;
30 int windowtype;
31 int transformtype;
32 int mapping;
33}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28public class JOrbisException extends Exception {
29 public JOrbisException () {
30 super();
31 }
32 public JOrbisException (String s) {
33 super ("JOrbis: "+s);
34 }
35}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28class Lookup{
29 static final int COS_LOOKUP_SZ=128;
30 static final float[] COS_LOOKUP={
31 +1.0000000000000f,+0.9996988186962f,+0.9987954562052f,+0.9972904566787f,
32 +0.9951847266722f,+0.9924795345987f,+0.9891765099648f,+0.9852776423889f,
33 +0.9807852804032f,+0.9757021300385f,+0.9700312531945f,+0.9637760657954f,
34 +0.9569403357322f,+0.9495281805930f,+0.9415440651830f,+0.9329927988347f,
35 +0.9238795325113f,+0.9142097557035f,+0.9039892931234f,+0.8932243011955f,
36 +0.8819212643484f,+0.8700869911087f,+0.8577286100003f,+0.8448535652497f,
37 +0.8314696123025f,+0.8175848131516f,+0.8032075314806f,+0.7883464276266f,
38 +0.7730104533627f,+0.7572088465065f,+0.7409511253550f,+0.7242470829515f,
39 +0.7071067811865f,+0.6895405447371f,+0.6715589548470f,+0.6531728429538f,
40 +0.6343932841636f,+0.6152315905806f,+0.5956993044924f,+0.5758081914178f,
41 +0.5555702330196f,+0.5349976198871f,+0.5141027441932f,+0.4928981922298f,
42 +0.4713967368260f,+0.4496113296546f,+0.4275550934303f,+0.4052413140050f,
43 +0.3826834323651f,+0.3598950365350f,+0.3368898533922f,+0.3136817403989f,
44 +0.2902846772545f,+0.2667127574749f,+0.2429801799033f,+0.2191012401569f,
45 +0.1950903220161f,+0.1709618887603f,+0.1467304744554f,+0.1224106751992f,
46 +0.0980171403296f,+0.0735645635997f,+0.0490676743274f,+0.0245412285229f,
47 +0.0000000000000f,-0.0245412285229f,-0.0490676743274f,-0.0735645635997f,
48 -0.0980171403296f,-0.1224106751992f,-0.1467304744554f,-0.1709618887603f,
49 -0.1950903220161f,-0.2191012401569f,-0.2429801799033f,-0.2667127574749f,
50 -0.2902846772545f,-0.3136817403989f,-0.3368898533922f,-0.3598950365350f,
51 -0.3826834323651f,-0.4052413140050f,-0.4275550934303f,-0.4496113296546f,
52 -0.4713967368260f,-0.4928981922298f,-0.5141027441932f,-0.5349976198871f,
53 -0.5555702330196f,-0.5758081914178f,-0.5956993044924f,-0.6152315905806f,
54 -0.6343932841636f,-0.6531728429538f,-0.6715589548470f,-0.6895405447371f,
55 -0.7071067811865f,-0.7242470829515f,-0.7409511253550f,-0.7572088465065f,
56 -0.7730104533627f,-0.7883464276266f,-0.8032075314806f,-0.8175848131516f,
57 -0.8314696123025f,-0.8448535652497f,-0.8577286100003f,-0.8700869911087f,
58 -0.8819212643484f,-0.8932243011955f,-0.9039892931234f,-0.9142097557035f,
59 -0.9238795325113f,-0.9329927988347f,-0.9415440651830f,-0.9495281805930f,
60 -0.9569403357322f,-0.9637760657954f,-0.9700312531945f,-0.9757021300385f,
61 -0.9807852804032f,-0.9852776423889f,-0.9891765099648f,-0.9924795345987f,
62 -0.9951847266722f,-0.9972904566787f,-0.9987954562052f,-0.9996988186962f,
63 -1.0000000000000f,
64 };
65 /* interpolated lookup based cos function, domain 0 to PI only */
66 static float coslook(float a){
67 double d=a*(.31830989*(float)COS_LOOKUP_SZ);
68 int i=(int)d;
69 return COS_LOOKUP[i]+ ((float)(d-i))*(COS_LOOKUP[i+1]-COS_LOOKUP[i]);
70 }
71
72 static final int INVSQ_LOOKUP_SZ=32;
73 static final float[] INVSQ_LOOKUP={
74 1.414213562373f,1.392621247646f,1.371988681140f,1.352246807566f,
75 1.333333333333f,1.315191898443f,1.297771369046f,1.281025230441f,
76 1.264911064067f,1.249390095109f,1.234426799697f,1.219988562661f,
77 1.206045378311f,1.192569588000f,1.179535649239f,1.166919931983f,
78 1.154700538379f,1.142857142857f,1.131370849898f,1.120224067222f,
79 1.109400392450f,1.098884511590f,1.088662107904f,1.078719779941f,
80 1.069044967650f,1.059625885652f,1.050451462878f,1.041511287847f,
81 1.032795558989f,1.024295039463f,1.016001016002f,1.007905261358f,
82 1.000000000000f,
83 };
84 /* interpolated 1./sqrt(p) where .5 <= p < 1. */
85 static float invsqlook(float a){
86// System.out.println(a);
87 double d=a*(2.f*(float)INVSQ_LOOKUP_SZ)-(float)INVSQ_LOOKUP_SZ;
88 int i=(int)d;
89 return INVSQ_LOOKUP[i]+ ((float)(d-i))*(INVSQ_LOOKUP[i+1]-INVSQ_LOOKUP[i]);
90 }
91
92 static final int INVSQ2EXP_LOOKUP_MIN=-32;
93 static final int INVSQ2EXP_LOOKUP_MAX=32;
94 static final float[] INVSQ2EXP_LOOKUP={
95 65536.f, 46340.95001f, 32768.f, 23170.47501f,
96 16384.f, 11585.2375f, 8192.f, 5792.618751f,
97 4096.f, 2896.309376f, 2048.f, 1448.154688f,
98 1024.f, 724.0773439f, 512.f, 362.038672f,
99 256.f, 181.019336f, 128.f, 90.50966799f,
100 64.f, 45.254834f, 32.f, 22.627417f,
101 16.f, 11.3137085f, 8.f, 5.656854249f,
102 4.f, 2.828427125f, 2.f, 1.414213562f,
103 1.f, 0.7071067812f, 0.5f, 0.3535533906f,
104 0.25f, 0.1767766953f, 0.125f, 0.08838834765f,
105 0.0625f, 0.04419417382f, 0.03125f, 0.02209708691f,
106 0.015625f, 0.01104854346f, 0.0078125f, 0.005524271728f,
107 0.00390625f, 0.002762135864f, 0.001953125f, 0.001381067932f,
108 0.0009765625f, 0.000690533966f, 0.00048828125f, 0.000345266983f,
109 0.000244140625f,0.0001726334915f,0.0001220703125f,8.631674575e-05f,
110 6.103515625e-05f,4.315837288e-05f,3.051757812e-05f,2.157918644e-05f,
111 1.525878906e-05f,
112 };
113 /* interpolated 1./sqrt(p) where .5 <= p < 1. */
114 static float invsq2explook(int a){
115 return INVSQ2EXP_LOOKUP[a-INVSQ2EXP_LOOKUP_MIN];
116 }
117
118 static final int FROMdB_LOOKUP_SZ=35;
119 static final int FROMdB2_LOOKUP_SZ=32;
120 static final int FROMdB_SHIFT=5;
121 static final int FROMdB2_SHIFT=3;
122 static final int FROMdB2_MASK=31;
123 static final float[] FROMdB_LOOKUP={
124 1.f, 0.6309573445f, 0.3981071706f, 0.2511886432f,
125 0.1584893192f, 0.1f, 0.06309573445f, 0.03981071706f,
126 0.02511886432f, 0.01584893192f, 0.01f, 0.006309573445f,
127 0.003981071706f, 0.002511886432f, 0.001584893192f, 0.001f,
128 0.0006309573445f,0.0003981071706f,0.0002511886432f,0.0001584893192f,
129 0.0001f,6.309573445e-05f,3.981071706e-05f,2.511886432e-05f,
130 1.584893192e-05f, 1e-05f,6.309573445e-06f,3.981071706e-06f,
131 2.511886432e-06f,1.584893192e-06f, 1e-06f,6.309573445e-07f,
132 3.981071706e-07f,2.511886432e-07f,1.584893192e-07f,
133 };
134 static final float[] FROMdB2_LOOKUP={
135 0.9928302478f, 0.9786445908f, 0.9646616199f, 0.9508784391f,
136 0.9372921937f, 0.92390007f, 0.9106992942f, 0.8976871324f,
137 0.8848608897f, 0.8722179097f, 0.8597555737f, 0.8474713009f,
138 0.835362547f, 0.8234268041f, 0.8116616003f, 0.8000644989f,
139 0.7886330981f, 0.7773650302f, 0.7662579617f, 0.755309592f,
140 0.7445176537f, 0.7338799116f, 0.7233941627f, 0.7130582353f,
141 0.7028699885f, 0.6928273125f, 0.6829281272f, 0.6731703824f,
142 0.6635520573f, 0.6540711597f, 0.6447257262f, 0.6355138211f,
143 };
144 /* interpolated lookup based fromdB function, domain -140dB to 0dB only */
145 static float fromdBlook(float a){
146 int i=(int)(a*((float)(-(1<<FROMdB2_SHIFT))));
147 return (i<0)?1.f:
148 ((i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT))?0.f:
149 FROMdB_LOOKUP[i>>>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]);
150 }
151
152}
153
154
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28class Lpc{
29 // en/decode lookups
30 Drft fft=new Drft();;
31
32 int ln;
33 int m;
34
35 // Autocorrelation LPC coeff generation algorithm invented by
36 // N. Levinson in 1947, modified by J. Durbin in 1959.
37
38 // Input : n elements of time doamin data
39 // Output: m lpc coefficients, excitation energy
40
41 static float lpc_from_data(float[] data, float[] lpc,int n,int m){
42 float[] aut=new float[m+1];
43 float error;
44 int i,j;
45
46 // autocorrelation, p+1 lag coefficients
47
48 j=m+1;
49 while(j--!=0){
50 float d=0;
51 for(i=j;i<n;i++)d+=data[i]*data[i-j];
52 aut[j]=d;
53 }
54
55 // Generate lpc coefficients from autocorr values
56
57 error=aut[0];
58 /*
59 if(error==0){
60 for(int k=0; k<m; k++) lpc[k]=0.0f;
61 return 0;
62 }
63 */
64
65 for(i=0;i<m;i++){
66 float r=-aut[i+1];
67
68 if(error==0){
69 for(int k=0; k<m; k++) lpc[k]=0.0f;
70 return 0;
71 }
72
73 // Sum up this iteration's reflection coefficient; note that in
74 // Vorbis we don't save it. If anyone wants to recycle this code
75 // and needs reflection coefficients, save the results of 'r' from
76 // each iteration.
77
78 for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];
79 r/=error;
80
81 // Update LPC coefficients and total error
82
83 lpc[i]=r;
84 for(j=0;j<i/2;j++){
85 float tmp=lpc[j];
86 lpc[j]+=r*lpc[i-1-j];
87 lpc[i-1-j]+=r*tmp;
88 }
89 if(i%2!=0)lpc[j]+=lpc[j]*r;
90
91 error*=1.0-r*r;
92 }
93
94 // we need the error value to know how big an impulse to hit the
95 // filter with later
96
97 return error;
98 }
99
100 // Input : n element envelope spectral curve
101 // Output: m lpc coefficients, excitation energy
102
103 float lpc_from_curve(float[] curve, float[] lpc){
104 int n=ln;
105 float[] work=new float[n+n];
106 float fscale=(float)(.5/n);
107 int i,j;
108
109 // input is a real curve. make it complex-real
110 // This mixes phase, but the LPC generation doesn't care.
111 for(i=0;i<n;i++){
112 work[i*2]=curve[i]*fscale;
113 work[i*2+1]=0;
114 }
115 work[n*2-1]=curve[n-1]*fscale;
116
117 n*=2;
118 fft.backward(work);
119
120 // The autocorrelation will not be circular. Shift, else we lose
121 // most of the power in the edges.
122
123 for(i=0,j=n/2;i<n/2;){
124 float temp=work[i];
125 work[i++]=work[j];
126 work[j++]=temp;
127 }
128
129 return(lpc_from_data(work,lpc,n,m));
130 }
131
132 void init(int mapped, int m){
133 //memset(l,0,sizeof(lpc_lookup));
134
135 ln=mapped;
136 this.m=m;
137
138 // we cheat decoding the LPC spectrum via FFTs
139 fft.init(mapped*2);
140 }
141
142 void clear(){
143 fft.clear();
144 }
145
146 static float FAST_HYPOT(float a, float b){
147 return (float)Math.sqrt((a)*(a) + (b)*(b));
148 }
149
150 // One can do this the long way by generating the transfer function in
151 // the time domain and taking the forward FFT of the result. The
152 // results from direct calculation are cleaner and faster.
153 //
154 // This version does a linear curve generation and then later
155 // interpolates the log curve from the linear curve.
156
157 void lpc_to_curve(float[] curve, float[] lpc, float amp){
158
159 //memset(curve,0,sizeof(float)*l->ln*2);
160 for(int i=0; i<ln*2; i++)curve[i]=0.0f;
161
162 if(amp==0)return;
163
164 for(int i=0;i<m;i++){
165 curve[i*2+1]=lpc[i]/(4*amp);
166 curve[i*2+2]=-lpc[i]/(4*amp);
167 }
168
169 fft.backward(curve); // reappropriated ;-)
170
171 {
172 int l2=ln*2;
173 float unit=(float)(1./amp);
174 curve[0]=(float)(1./(curve[0]*2+unit));
175 for(int i=1;i<ln;i++){
176 float real=(curve[i]+curve[l2-i]);
177 float imag=(curve[i]-curve[l2-i]);
178
179 float a = real + unit;
180 curve[i] = (float)(1.0 / FAST_HYPOT(a, imag));
181 }
182 }
183 }
184
185/*
186 // subtract or add an lpc filter to data. Vorbis doesn't actually use this.
187
188 static void lpc_residue(float[] coeff, float[] prime,int m,
189 float[] data, int n){
190
191 // in: coeff[0...m-1] LPC coefficients
192 // prime[0...m-1] initial values
193 // data[0...n-1] data samples
194 // out: data[0...n-1] residuals from LPC prediction
195
196 float[] work=new float[m+n];
197 float y;
198
199 if(prime==null){
200 for(int i=0;i<m;i++){
201 work[i]=0;
202 }
203 }
204 else{
205 for(int i=0;i<m;i++){
206 work[i]=prime[i];
207 }
208 }
209
210 for(int i=0;i<n;i++){
211 y=0;
212 for(int j=0;j<m;j++){
213 y-=work[i+j]*coeff[m-j-1];
214 }
215 work[i+m]=data[i];
216 data[i]-=y;
217 }
218 }
219
220 static void lpc_predict(float[] coeff, float[] prime,int m,
221 float[] data, int n){
222
223 // in: coeff[0...m-1] LPC coefficients
224 // prime[0...m-1] initial values (allocated size of n+m-1)
225 // data[0...n-1] residuals from LPC prediction
226 // out: data[0...n-1] data samples
227
228 int o,p;
229 float y;
230 float[] work=new float[m+n];
231
232 if(prime==null){
233 for(int i=0;i<m;i++){
234 work[i]=0.f;
235 }
236 }
237 else{
238 for(int i=0;i<m;i++){
239 work[i]=prime[i];
240 }
241 }
242
243 for(int i=0;i<n;i++){
244 y=data[i];
245 o=i;
246 p=m;
247 for(int j=0;j<m;j++){
248 y-=work[o++]*coeff[--p];
249 }
250 data[i]=work[o]=y;
251 }
252 }
253*/
254}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28/*
29 function: LSP (also called LSF) conversion routines
30
31 The LSP generation code is taken (with minimal modification) from
32 "On the Computation of the LSP Frequencies" by Joseph Rothweiler
33 <rothwlr@altavista.net>, available at:
34
35 http://www2.xtdl.com/~rothwlr/lsfpaper/lsfpage.html
36 ********************************************************************/
37
38class Lsp{
39
40 static final float M_PI=(float)(3.1415926539);
41
42 static void lsp_to_curve(float[] curve,
43 int[] map, int n, int ln,
44 float[] lsp, int m,
45 float amp, float ampoffset){
46 int i;
47 float wdel=M_PI/ln;
48 for(i=0;i<m;i++)lsp[i]=Lookup.coslook(lsp[i]);
49 int m2=(m/2)*2;
50
51 i=0;
52 while(i<n){
53 int k=map[i];
54 float p=.7071067812f;
55 float q=.7071067812f;
56 float w=Lookup.coslook(wdel*k);
57 int ftmp=0;
58 int c=m>>>1;
59
60 for(int j=0;j<m2;j+=2){
61 q*=lsp[j]-w;
62 p*=lsp[j+1]-w;
63 }
64
65 if((m&1)!=0){
66 /* odd order filter; slightly assymetric */
67 /* the last coefficient */
68 q*=lsp[m-1]-w;
69 q*=q;
70 p*=p*(1.f-w*w);
71 }
72 else{
73 /* even order filter; still symmetric */
74 q*=q*(1.f+w);
75 p*=p*(1.f-w);
76 }
77
78 // q=frexp(p+q,&qexp);
79 q=p+q;
80 int hx=Float.floatToIntBits(q);
81 int ix=0x7fffffff&hx;
82 int qexp=0;
83
84 if(ix>=0x7f800000||(ix==0)){
85 // 0,inf,nan
86 }
87 else{
88 if(ix<0x00800000){ // subnormal
89 q*=3.3554432000e+07; // 0x4c000000
90 hx=Float.floatToIntBits(q);
91 ix=0x7fffffff&hx;
92 qexp=-25;
93 }
94 qexp += ((ix>>>23)-126);
95 hx=(hx&0x807fffff)|0x3f000000;
96 q=Float.intBitsToFloat(hx);
97 }
98
99 q=Lookup.fromdBlook(amp*
100 Lookup.invsqlook(q)*
101 Lookup.invsq2explook(qexp+m)-ampoffset);
102
103 do{curve[i++]*=q;}
104// do{curve[i++]=q;}
105 while(i<n&&map[i]==k);
106
107 }
108 }
109}
110
111
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30class Mapping0 extends FuncMapping{
31 static int seq=0;
32 void free_info(Object imap){};
33 void free_look(Object imap){
34/*
35 LookMapping0 l=(LookMapping0)imap;
36 InfoMapping0 info=l.map;
37 if(l!=null){
38 for(int i=0;i<l.map.submaps;i++){
39 l.time_func[i].free_look(l.time_look[i]);
40 l.floor_func[i].free_look(l.floor_look[i]);
41 l.residue_func[i].free_look(l.residue_look[i]);
42 if(l.psy_look!=null)l.psy_look[i].clear();
43 }
44 }
45
46 if(l.floor_state!=null){
47 for(int i=0;i<l.ch;i++)
48 l.floor_func[info.chmuxlist[i]].free_state(l.floor_state[i]);
49 //free(l.floor_state);
50 }
51
52 if(l.decay!=null){
53 for(int i=0;i<l.ch;i++){
54 //if(l.decay[i])free(l->decay[i]);
55 l.decay[i]=null;
56 }
57 //free(l->decay);
58 l.decay=null;
59 }
60 //free(l->time_func);
61 //free(l->floor_func);
62 //free(l->residue_func);
63 //free(l->time_look);
64 //free(l->floor_look);
65 //free(l->residue_look);
66 //f(l->psy_look)free(l->psy_look);
67 l.time_func=null;
68 l.floor_func=null;
69 l.residue_func=null;
70 l.time_look=null;
71 l.floor_look=null;
72 l.residue_look=null;
73 //memset(l,0,sizeof(vorbis_look_mapping0));
74 //free(l);
75*/
76 }
77
78 Object look(DspState vd, InfoMode vm, Object m){
79//System.err.println("Mapping0.look");
80 Info vi=vd.vi;
81 LookMapping0 look=new LookMapping0();
82 InfoMapping0 info=look.map=(InfoMapping0)m;
83 look.mode=vm;
84
85 look.time_look=new Object[info.submaps];
86 look.floor_look=new Object[info.submaps];
87 look.residue_look=new Object[info.submaps];
88
89/*
90 if(vd.analysisp!=0){
91 look.floor_state=new Object[vi.channels];
92 }
93 if(vi.psys!=0){
94 look.psy_look=new PsyLook[info.submaps];
95 for(int i=0; i<info.submaps; i++){ look.psy_look[i]=new PsyLook(); }
96 }
97*/
98
99 look.time_func=new FuncTime[info.submaps];
100 look.floor_func=new FuncFloor[info.submaps];
101 look.residue_func=new FuncResidue[info.submaps];
102
103 for(int i=0;i<info.submaps;i++){
104 int timenum=info.timesubmap[i];
105 int floornum=info.floorsubmap[i];
106 int resnum=info.residuesubmap[i];
107
108 look.time_func[i]=FuncTime.time_P[vi.time_type[timenum]];
109 look.time_look[i]=look.time_func[i].look(vd,vm,vi.time_param[timenum]);
110 look.floor_func[i]=FuncFloor.floor_P[vi.floor_type[floornum]];
111 look.floor_look[i]=look.floor_func[i].
112 look(vd,vm,vi.floor_param[floornum]);
113 look.residue_func[i]=FuncResidue.residue_P[vi.residue_type[resnum]];
114 look.residue_look[i]=look.residue_func[i].
115 look(vd,vm,vi.residue_param[resnum]);
116
117/*
118 if(vi.psys!=0 && vd.analysisp!=0){
119 int psynum=info.psysubmap[i];
120 look.psy_look[i].init(vi.psy_param[psynum],
121 vi.blocksizes[vm.blockflag]/2,vi.rate);
122 }
123*/
124 }
125
126 if(vi.psys!=0 && vd.analysisp!=0){
127 /*
128 if(info->psy[0] != info->psy[1]){
129
130 int psynum=info->psy[0];
131 look->psy_look[0]=_ogg_calloc(1,sizeof(vorbis_look_psy));
132 _vp_psy_init(look->psy_look[0],ci->psy_param[psynum],
133 ci->psy_g_param,
134 ci->blocksizes[vm->blockflag]/2,vi->rate);
135
136 psynum=info->psy[1];
137 look->psy_look[1]=_ogg_calloc(1,sizeof(vorbis_look_psy));
138 _vp_psy_init(look->psy_look[1],ci->psy_param[psynum],
139 ci->psy_g_param,
140 ci->blocksizes[vm->blockflag]/2,vi->rate);
141 }else{
142
143 int psynum=info->psy[0];
144 look->psy_look[0]=_ogg_calloc(1,sizeof(vorbis_look_psy));
145 look->psy_look[1]=look->psy_look[0];
146 _vp_psy_init(look->psy_look[0],ci->psy_param[psynum],
147 ci->psy_g_param,
148 ci->blocksizes[vm->blockflag]/2,vi->rate);
149
150 }
151 */
152 }
153
154 look.ch=vi.channels;
155// if(vd->analysisp)drft_init(&look->fft_look,ci->blocksizes[vm->blockflag]);
156
157 return(look);
158//return null;
159 }
160
161 void pack(Info vi, Object imap, Buffer opb){
162 InfoMapping0 info=(InfoMapping0)imap;
163
164 /* another 'we meant to do it this way' hack... up to beta 4, we
165 packed 4 binary zeros here to signify one submapping in use. We
166 now redefine that to mean four bitflags that indicate use of
167 deeper features; bit0:submappings, bit1:coupling,
168 bit2,3:reserved. This is backward compatable with all actual uses
169 of the beta code. */
170
171 if(info.submaps>1){
172 opb.write(1,1);
173 opb.write(info.submaps-1,4);
174 }
175 else{
176 opb.write(0,1);
177 }
178
179 if(info.coupling_steps>0){
180 opb.write(1,1);
181 opb.write(info.coupling_steps-1,8);
182 for(int i=0;i<info.coupling_steps;i++){
183 opb.write(info.coupling_mag[i],ilog2(vi.channels));
184 opb.write(info.coupling_ang[i],ilog2(vi.channels));
185 }
186 }
187 else{
188 opb.write(0,1);
189 }
190
191 opb.write(0,2); /* 2,3:reserved */
192
193 /* we don't write the channel submappings if we only have one... */
194 if(info.submaps>1){
195 for(int i=0;i<vi.channels;i++)
196 opb.write(info.chmuxlist[i],4);
197 }
198 for(int i=0;i<info.submaps;i++){
199 opb.write(info.timesubmap[i],8);
200 opb.write(info.floorsubmap[i],8);
201 opb.write(info.residuesubmap[i],8);
202 }
203 }
204
205 // also responsible for range checking
206 Object unpack(Info vi, Buffer opb){
207 InfoMapping0 info=new InfoMapping0();
208
209 // !!!!
210 if(opb.read(1)!=0){
211 info.submaps=opb.read(4)+1;
212 }
213 else{
214 info.submaps=1;
215 }
216
217 if(opb.read(1)!=0){
218 info.coupling_steps=opb.read(8)+1;
219
220 for(int i=0;i<info.coupling_steps;i++){
221 int testM=info.coupling_mag[i]=opb.read(ilog2(vi.channels));
222 int testA=info.coupling_ang[i]=opb.read(ilog2(vi.channels));
223
224 if(testM<0 ||
225 testA<0 ||
226 testM==testA ||
227 testM>=vi.channels ||
228 testA>=vi.channels){
229 //goto err_out;
230 info.free();
231 return(null);
232 }
233 }
234 }
235
236 if(opb.read(2)>0){ /* 2,3:reserved */
237 //goto err_out;
238 info.free();
239 return(null);
240 }
241
242 if(info.submaps>1){
243 for(int i=0;i<vi.channels;i++){
244 info.chmuxlist[i]=opb.read(4);
245 if(info.chmuxlist[i]>=info.submaps){
246 //goto err_out;
247 info.free();
248 return(null);
249 }
250 }
251 }
252
253 for(int i=0;i<info.submaps;i++){
254 info.timesubmap[i]=opb.read(8);
255 if(info.timesubmap[i]>=vi.times){
256 //goto err_out;
257 info.free();
258 return(null);
259 }
260 info.floorsubmap[i]=opb.read(8);
261 if(info.floorsubmap[i]>=vi.floors){
262 //goto err_out;
263 info.free();
264 return(null);
265 }
266 info.residuesubmap[i]=opb.read(8);
267 if(info.residuesubmap[i]>=vi.residues){
268 //goto err_out;
269 info.free();
270 return(null);
271 }
272 }
273 return info;
274 //err_out:
275 //free_info(info);
276 //return(NULL);
277 }
278
279/*
280 // no time mapping implementation for now
281 static int seq=0;
282 int forward(Block vb, Object l){
283 DspState vd=vb.vd;
284 Info vi=vd.vi;
285 LookMapping0 look=(LookMapping0)l;
286 InfoMapping0 info=look.map;
287 InfoMode mode=look.mode;
288 int n=vb.pcmend;
289 float[] window=vd.window[vb.W][vb.lW][vb.nW][mode.windowtype];
290
291 float[][] pcmbundle=new float[vi.channles][];
292 int[] nonzero=new int[vi.channels];
293
294 // time domain pre-window: NONE IMPLEMENTED
295
296 // window the PCM data: takes PCM vector, vb; modifies PCM vector
297
298 for(int i=0;i<vi.channels;i++){
299 float[] pcm=vb.pcm[i];
300 for(int j=0;j<n;j++)
301 pcm[j]*=window[j];
302 }
303
304 // time-domain post-window: NONE IMPLEMENTED
305
306 // transform the PCM data; takes PCM vector, vb; modifies PCM vector
307 // only MDCT right now....
308 for(int i=0;i<vi.channels;i++){
309 float[] pcm=vb.pcm[i];
310 mdct_forward(vd.transform[vb.W][0],pcm,pcm);
311 }
312
313 {
314 float[] floor=_vorbis_block_alloc(vb,n*sizeof(float)/2);
315
316 for(int i=0;i<vi.channels;i++){
317 float[] pcm=vb.pcm[i];
318 float[] decay=look.decay[i];
319 int submap=info.chmuxlist[i];
320
321 // if some other mode/mapping was called last frame, our decay
322 // accumulator is out of date. Clear it.
323 //if(look.lastframe+1 != vb->sequence)
324 // memset(decay,0,n*sizeof(float)/2);
325
326 // perform psychoacoustics; do masking
327 _vp_compute_mask(look.psy_look[submap],pcm,floor,decay);
328
329 _analysis_output("mdct",seq,pcm,n/2,0,1);
330 _analysis_output("lmdct",seq,pcm,n/2,0,0);
331 _analysis_output("prefloor",seq,floor,n/2,0,1);
332
333 // perform floor encoding
334 nonzero[i]=look.floor_func[submap].
335 forward(vb,look.floor_look[submap],floor,floor,look.floor_state[i]);
336
337 _analysis_output("floor",seq,floor,n/2,0,1);
338
339 // apply the floor, do optional noise levelling
340 _vp_apply_floor(look->psy_look+submap,pcm,floor);
341
342 _analysis_output("res",seq++,pcm,n/2,0,0);
343 }
344
345 // perform residue encoding with residue mapping; this is
346 // multiplexed. All the channels belonging to one submap are
347 // encoded (values interleaved), then the next submap, etc
348
349 for(int i=0;i<info.submaps;i++){
350 int ch_in_bundle=0;
351 for(int j=0;j<vi.channels;j++){
352 if(info.chmuxlist[j]==i && nonzero[j]==1){
353 pcmbundle[ch_in_bundle++]=vb.pcm[j];
354 }
355 }
356 look.residue_func[i].forward(vb,look.residue_look[i], pcmbundle,ch_in_bundle);
357 }
358 }
359 look.lastframe=vb.sequence;
360 return(0);
361 }
362*/
363
364 float[][] pcmbundle=null;
365 int[] zerobundle=null;
366 int[] nonzero=null;
367 Object[] floormemo=null;
368
369 synchronized int inverse(Block vb, Object l){
370 //System.err.println("Mapping0.inverse");
371 DspState vd=vb.vd;
372 Info vi=vd.vi;
373 LookMapping0 look=(LookMapping0)l;
374 InfoMapping0 info=look.map;
375 InfoMode mode=look.mode;
376 int n=vb.pcmend=vi.blocksizes[vb.W];
377
378 float[] window=vd.window[vb.W][vb.lW][vb.nW][mode.windowtype];
379 // float[][] pcmbundle=new float[vi.channels][];
380 // int[] nonzero=new int[vi.channels];
381 if(pcmbundle==null || pcmbundle.length<vi.channels){
382 pcmbundle=new float[vi.channels][];
383 nonzero=new int[vi.channels];
384 zerobundle=new int[vi.channels];
385 floormemo=new Object[vi.channels];
386 }
387
388 // time domain information decode (note that applying the
389 // information would have to happen later; we'll probably add a
390 // function entry to the harness for that later
391 // NOT IMPLEMENTED
392
393 // recover the spectral envelope; store it in the PCM vector for now
394 for(int i=0;i<vi.channels;i++){
395 float[] pcm=vb.pcm[i];
396 int submap=info.chmuxlist[i];
397
398 floormemo[i]=look.floor_func[submap].inverse1(vb,look.
399 floor_look[submap],
400 floormemo[i]
401 );
402 if(floormemo[i]!=null){ nonzero[i]=1; }
403 else{ nonzero[i]=0; }
404 for(int j=0; j<n/2; j++){
405 pcm[j]=0;
406 }
407
408 //_analysis_output("ifloor",seq+i,pcm,n/2,0,1);
409 }
410
411 for(int i=0; i<info.coupling_steps; i++){
412 if(nonzero[info.coupling_mag[i]]!=0 ||
413 nonzero[info.coupling_ang[i]]!=0){
414 nonzero[info.coupling_mag[i]]=1;
415 nonzero[info.coupling_ang[i]]=1;
416 }
417 }
418
419 // recover the residue, apply directly to the spectral envelope
420
421 for(int i=0;i<info.submaps;i++){
422 int ch_in_bundle=0;
423 for(int j=0;j<vi.channels;j++){
424 if(info.chmuxlist[j]==i){
425 if(nonzero[j]!=0){
426 zerobundle[ch_in_bundle]=1;
427 }
428 else{
429 zerobundle[ch_in_bundle]=0;
430 }
431 pcmbundle[ch_in_bundle++]=vb.pcm[j];
432 }
433 }
434
435 look.residue_func[i].inverse(vb,look.residue_look[i],
436 pcmbundle,zerobundle,ch_in_bundle);
437 }
438
439
440 for(int i=info.coupling_steps-1;i>=0;i--){
441 float[] pcmM=vb.pcm[info.coupling_mag[i]];
442 float[] pcmA=vb.pcm[info.coupling_ang[i]];
443
444 for(int j=0;j<n/2;j++){
445 float mag=pcmM[j];
446 float ang=pcmA[j];
447
448 if(mag>0){
449 if(ang>0){
450 pcmM[j]=mag;
451 pcmA[j]=mag-ang;
452 }
453 else{
454 pcmA[j]=mag;
455 pcmM[j]=mag+ang;
456 }
457 }
458 else{
459 if(ang>0){
460 pcmM[j]=mag;
461 pcmA[j]=mag+ang;
462 }
463 else{
464 pcmA[j]=mag;
465 pcmM[j]=mag-ang;
466 }
467 }
468 }
469 }
470
471// /* compute and apply spectral envelope */
472
473 for(int i=0;i<vi.channels;i++){
474 float[] pcm=vb.pcm[i];
475 int submap=info.chmuxlist[i];
476 look.floor_func[submap].inverse2(vb,look.floor_look[submap],floormemo[i],pcm);
477 }
478
479 // transform the PCM data; takes PCM vector, vb; modifies PCM vector
480 // only MDCT right now....
481
482 for(int i=0;i<vi.channels;i++){
483 float[] pcm=vb.pcm[i];
484 //_analysis_output("out",seq+i,pcm,n/2,0,0);
485 ((Mdct)vd.transform[vb.W][0]).backward(pcm,pcm);
486 }
487
488 // now apply the decoded pre-window time information
489 // NOT IMPLEMENTED
490
491 // window the data
492 for(int i=0;i<vi.channels;i++){
493 float[] pcm=vb.pcm[i];
494 if(nonzero[i]!=0){
495 for(int j=0;j<n;j++){
496 pcm[j]*=window[j];
497 }
498 }
499 else{
500 for(int j=0;j<n;j++){
501 pcm[j]=0.f;
502 }
503 }
504 //_analysis_output("final",seq++,pcm,n,0,0);
505 }
506
507 // now apply the decoded post-window time information
508 // NOT IMPLEMENTED
509 // all done!
510 return(0);
511 }
512
513
514 private static int ilog2(int v){
515 int ret=0;
516 while(v>1){
517 ret++;
518 v>>>=1;
519 }
520 return(ret);
521 }
522}
523
524class InfoMapping0{
525 int submaps; // <= 16
526 int[] chmuxlist=new int[256]; // up to 256 channels in a Vorbis stream
527
528 int[] timesubmap=new int[16]; // [mux]
529 int[] floorsubmap=new int[16]; // [mux] submap to floors
530 int[] residuesubmap=new int[16];// [mux] submap to residue
531 int[] psysubmap=new int[16]; // [mux]; encode only
532
533 int coupling_steps;
534 int[] coupling_mag=new int[256];
535 int[] coupling_ang=new int[256];
536
537 void free(){
538 chmuxlist=null;
539 timesubmap=null;
540 floorsubmap=null;
541 residuesubmap=null;
542 psysubmap=null;
543
544 coupling_mag=null;
545 coupling_ang=null;
546 }
547}
548
549class LookMapping0{
550 InfoMode mode;
551 InfoMapping0 map;
552 Object[] time_look;
553 Object[] floor_look;
554 Object[] floor_state;
555 Object[] residue_look;
556 PsyLook[] psy_look;
557
558 FuncTime[] time_func;
559 FuncFloor[] floor_func;
560 FuncResidue[] residue_func;
561
562 int ch;
563 float[][] decay;
564 int lastframe; // if a different mode is called, we need to
565 // invalidate decay and floor state
566}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28class Mdct{
29
30 static private final float cPI3_8=0.38268343236508977175f;
31 static private final float cPI2_8=0.70710678118654752441f;
32 static private final float cPI1_8=0.92387953251128675613f;
33
34 int n;
35 int log2n;
36
37 float[] trig;
38 int[] bitrev;
39
40 float scale;
41
42 void init(int n){
43 bitrev=new int[n/4];
44 trig=new float[n+n/4];
45
46 int n2=n>>>1;
47 log2n=(int)Math.rint(Math.log(n)/Math.log(2));
48 this.n=n;
49
50
51 int AE=0;
52 int AO=1;
53 int BE=AE+n/2;
54 int BO=BE+1;
55 int CE=BE+n/2;
56 int CO=CE+1;
57 // trig lookups...
58 for(int i=0;i<n/4;i++){
59 trig[AE+i*2]=(float)Math.cos((Math.PI/n)*(4*i));
60 trig[AO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i));
61 trig[BE+i*2]=(float)Math.cos((Math.PI/(2*n))*(2*i+1));
62 trig[BO+i*2]=(float)Math.sin((Math.PI/(2*n))*(2*i+1));
63 }
64 for(int i=0;i<n/8;i++){
65 trig[CE+i*2]=(float)Math.cos((Math.PI/n)*(4*i+2));
66 trig[CO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i+2));
67 }
68
69 {
70 int mask=(1<<(log2n-1))-1;
71 int msb=1<<(log2n-2);
72 for(int i=0;i<n/8;i++){
73 int acc=0;
74 for(int j=0;msb>>>j!=0;j++)
75 if(((msb>>>j)&i)!=0)acc|=1<<j;
76 bitrev[i*2]=((~acc)&mask);
77// bitrev[i*2]=((~acc)&mask)-1;
78 bitrev[i*2+1]=acc;
79 }
80 }
81 scale=4.f/n;
82 }
83
84 void clear(){
85 }
86
87 void forward(float[] in, float[] out){
88 }
89
90 float[] _x=new float[1024];
91 float[] _w=new float[1024];
92
93 synchronized void backward(float[] in, float[] out){
94 if(_x.length<n/2){_x=new float[n/2];}
95 if(_w.length<n/2){_w=new float[n/2];}
96 float[] x=_x;
97 float[] w=_w;
98 int n2=n>>>1;
99 int n4=n>>>2;
100 int n8=n>>>3;
101
102 // rotate + step 1
103 {
104 int inO=1;
105 int xO=0;
106 int A=n2;
107
108 int i;
109 for(i=0;i<n8;i++){
110 A-=2;
111 x[xO++]=-in[inO+2]*trig[A+1] - in[inO]*trig[A];
112 x[xO++]= in[inO]*trig[A+1] - in[inO+2]*trig[A];
113 inO+=4;
114 }
115
116 inO=n2-4;
117
118 for(i=0;i<n8;i++){
119 A-=2;
120 x[xO++]=in[inO]*trig[A+1] + in[inO+2]*trig[A];
121 x[xO++]=in[inO]*trig[A] - in[inO+2]*trig[A+1];
122 inO-=4;
123 }
124 }
125
126 float[] xxx=mdct_kernel(x,w,n,n2,n4,n8);
127 int xx=0;
128
129 // step 8
130
131 {
132 int B=n2;
133 int o1=n4,o2=o1-1;
134 int o3=n4+n2,o4=o3-1;
135
136 for(int i=0;i<n4;i++){
137 float temp1= (xxx[xx] * trig[B+1] - xxx[xx+1] * trig[B]);
138 float temp2=-(xxx[xx] * trig[B] + xxx[xx+1] * trig[B+1]);
139
140 out[o1]=-temp1;
141 out[o2]= temp1;
142 out[o3]= temp2;
143 out[o4]= temp2;
144
145 o1++;
146 o2--;
147 o3++;
148 o4--;
149 xx+=2;
150 B+=2;
151 }
152 }
153 }
154 private float[] mdct_kernel(float[] x, float[] w,
155 int n, int n2, int n4, int n8){
156 // step 2
157
158 int xA=n4;
159 int xB=0;
160 int w2=n4;
161 int A=n2;
162
163 for(int i=0;i<n4;){
164 float x0=x[xA] - x[xB];
165 float x1;
166 w[w2+i]=x[xA++]+x[xB++];
167
168 x1=x[xA]-x[xB];
169 A-=4;
170
171 w[i++]= x0 * trig[A] + x1 * trig[A+1];
172 w[i]= x1 * trig[A] - x0 * trig[A+1];
173
174 w[w2+i]=x[xA++]+x[xB++];
175 i++;
176 }
177
178 // step 3
179
180 {
181 for(int i=0;i<log2n-3;i++){
182 int k0=n>>>(i+2);
183 int k1=1<<(i+3);
184 int wbase=n2-2;
185
186 A=0;
187 float[] temp;
188
189 for(int r=0;r<(k0>>>2);r++){
190 int w1=wbase;
191 w2=w1-(k0>>1);
192 float AEv= trig[A],wA;
193 float AOv= trig[A+1],wB;
194 wbase-=2;
195
196 k0++;
197 for(int s=0;s<(2<<i);s++){
198 wB =w[w1] -w[w2];
199 x[w1] =w[w1] +w[w2];
200
201 wA =w[++w1] -w[++w2];
202 x[w1] =w[w1] +w[w2];
203
204 x[w2] =wA*AEv - wB*AOv;
205 x[w2-1]=wB*AEv + wA*AOv;
206
207 w1-=k0;
208 w2-=k0;
209 }
210 k0--;
211 A+=k1;
212 }
213
214 temp=w;
215 w=x;
216 x=temp;
217 }
218 }
219
220 // step 4, 5, 6, 7
221 {
222 int C=n;
223 int bit=0;
224 int x1=0;
225 int x2=n2-1;
226
227 for(int i=0;i<n8;i++){
228 int t1=bitrev[bit++];
229 int t2=bitrev[bit++];
230
231 float wA=w[t1]-w[t2+1];
232 float wB=w[t1-1]+w[t2];
233 float wC=w[t1]+w[t2+1];
234 float wD=w[t1-1]-w[t2];
235
236 float wACE=wA* trig[C];
237 float wBCE=wB* trig[C++];
238 float wACO=wA* trig[C];
239 float wBCO=wB* trig[C++];
240
241 x[x1++]=( wC+wACO+wBCE)*.5f;
242 x[x2--]=(-wD+wBCO-wACE)*.5f;
243 x[x1++]=( wD+wBCO-wACE)*.5f;
244 x[x2--]=( wC-wACO-wBCE)*.5f;
245 }
246 }
247 return(x);
248 }
249}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28// psychoacoustic setup
29class PsyInfo{
30 int athp;
31 int decayp;
32 int smoothp;
33 int noisefitp;
34 int noisefit_subblock;
35 float noisefit_threshdB;
36
37 float ath_att;
38
39 int tonemaskp;
40 float[] toneatt_125Hz=new float[5];
41 float[] toneatt_250Hz=new float[5];
42 float[] toneatt_500Hz=new float[5];
43 float[] toneatt_1000Hz=new float[5];
44 float[] toneatt_2000Hz=new float[5];
45 float[] toneatt_4000Hz=new float[5];
46 float[] toneatt_8000Hz=new float[5];
47
48 int peakattp;
49 float[] peakatt_125Hz=new float[5];
50 float[] peakatt_250Hz=new float[5];
51 float[] peakatt_500Hz=new float[5];
52 float[] peakatt_1000Hz=new float[5];
53 float[] peakatt_2000Hz=new float[5];
54 float[] peakatt_4000Hz=new float[5];
55 float[] peakatt_8000Hz=new float[5];
56
57 int noisemaskp;
58 float[] noiseatt_125Hz=new float[5];
59 float[] noiseatt_250Hz=new float[5];
60 float[] noiseatt_500Hz=new float[5];
61 float[] noiseatt_1000Hz=new float[5];
62 float[] noiseatt_2000Hz=new float[5];
63 float[] noiseatt_4000Hz=new float[5];
64 float[] noiseatt_8000Hz=new float[5];
65
66 float max_curve_dB;
67
68 float attack_coeff;
69 float decay_coeff;
70
71 void free(){}
72}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28class PsyLook {
29 int n;
30 PsyInfo vi;
31
32 float[][][] tonecurves;
33 float[][] peakatt;
34 float[][][] noisecurves;
35
36 float[] ath;
37 int[] octave;
38
39 void init(PsyInfo vi, int n, int rate){
40 /*
41 float rate2=rate/2.;
42 //memset(p,0,sizeof(vorbis_look_psy));
43 ath=new float[n];
44 octave=new int[n];
45 this.vi=vi;
46 this.n=n;
47
48 // set up the lookups for a given blocksize and sample rate
49 // Vorbis max sample rate is limited by 26 Bark (54kHz)
50 set_curve(ATH_Bark_dB, ath,n,rate);
51 for(int i=0;i<n;i++)
52 ath[i]=fromdB(ath[i]+vi.ath_att);
53
54 for(int i=0;i<n;i++){
55 int oc=rint(toOC((i+.5)*rate2/n)*2.);
56 if(oc<0)oc=0;
57 if(oc>12)oc=12;
58 octave[i]=oc;
59 }
60
61 tonecurves=malloc(13*sizeof(float **));
62 noisecurves=malloc(13*sizeof(float **));
63 peakatt=malloc(7*sizeof(float *));
64 for(int i=0;i<13;i++){
65 tonecurves[i]=malloc(9*sizeof(float *));
66 noisecurves[i]=malloc(9*sizeof(float *));
67 }
68 for(i=0;i<7;i++)
69 peakatt[i]=malloc(5*sizeof(float));
70
71 for(i=0;i<13;i++){
72 for(j=0;j<9;j++){
73 tonecurves[i][j]=malloc(EHMER_MAX*sizeof(float));
74 noisecurves[i][j]=malloc(EHMER_MAX*sizeof(float));
75 }
76 }
77
78 // OK, yeah, this was a silly way to do it
79 memcpy(tonecurves[0][2],tone_125_80dB_SL,sizeof(float)*EHMER_MAX);
80 memcpy(tonecurves[0][4],tone_125_80dB_SL,sizeof(float)*EHMER_MAX);
81 memcpy(tonecurves[0][6],tone_125_80dB_SL,sizeof(float)*EHMER_MAX);
82 memcpy(tonecurves[0][8],tone_125_100dB_SL,sizeof(float)*EHMER_MAX);
83
84 memcpy(tonecurves[2][2],tone_250_40dB_SL,sizeof(float)*EHMER_MAX);
85 memcpy(tonecurves[2][4],tone_250_60dB_SL,sizeof(float)*EHMER_MAX);
86 memcpy(tonecurves[2][6],tone_250_80dB_SL,sizeof(float)*EHMER_MAX);
87 memcpy(tonecurves[2][8],tone_250_80dB_SL,sizeof(float)*EHMER_MAX);
88
89 memcpy(tonecurves[4][2],tone_500_40dB_SL,sizeof(float)*EHMER_MAX);
90 memcpy(tonecurves[4][4],tone_500_60dB_SL,sizeof(float)*EHMER_MAX);
91 memcpy(tonecurves[4][6],tone_500_80dB_SL,sizeof(float)*EHMER_MAX);
92 memcpy(tonecurves[4][8],tone_500_100dB_SL,sizeof(float)*EHMER_MAX);
93
94 memcpy(tonecurves[6][2],tone_1000_40dB_SL,sizeof(float)*EHMER_MAX);
95 memcpy(tonecurves[6][4],tone_1000_60dB_SL,sizeof(float)*EHMER_MAX);
96 memcpy(tonecurves[6][6],tone_1000_80dB_SL,sizeof(float)*EHMER_MAX);
97 memcpy(tonecurves[6][8],tone_1000_100dB_SL,sizeof(float)*EHMER_MAX);
98
99 memcpy(tonecurves[8][2],tone_2000_40dB_SL,sizeof(float)*EHMER_MAX);
100 memcpy(tonecurves[8][4],tone_2000_60dB_SL,sizeof(float)*EHMER_MAX);
101 memcpy(tonecurves[8][6],tone_2000_80dB_SL,sizeof(float)*EHMER_MAX);
102 memcpy(tonecurves[8][8],tone_2000_100dB_SL,sizeof(float)*EHMER_MAX);
103
104 memcpy(tonecurves[10][2],tone_4000_40dB_SL,sizeof(float)*EHMER_MAX);
105 memcpy(tonecurves[10][4],tone_4000_60dB_SL,sizeof(float)*EHMER_MAX);
106 memcpy(tonecurves[10][6],tone_4000_80dB_SL,sizeof(float)*EHMER_MAX);
107 memcpy(tonecurves[10][8],tone_4000_100dB_SL,sizeof(float)*EHMER_MAX);
108
109 memcpy(tonecurves[12][2],tone_4000_40dB_SL,sizeof(float)*EHMER_MAX);
110 memcpy(tonecurves[12][4],tone_4000_60dB_SL,sizeof(float)*EHMER_MAX);
111 memcpy(tonecurves[12][6],tone_8000_80dB_SL,sizeof(float)*EHMER_MAX);
112 memcpy(tonecurves[12][8],tone_8000_100dB_SL,sizeof(float)*EHMER_MAX);
113
114
115 memcpy(noisecurves[0][2],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
116 memcpy(noisecurves[0][4],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
117 memcpy(noisecurves[0][6],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
118 memcpy(noisecurves[0][8],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
119
120 memcpy(noisecurves[2][2],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
121 memcpy(noisecurves[2][4],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
122 memcpy(noisecurves[2][6],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
123 memcpy(noisecurves[2][8],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
124
125 memcpy(noisecurves[4][2],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
126 memcpy(noisecurves[4][4],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
127 memcpy(noisecurves[4][6],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
128 memcpy(noisecurves[4][8],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
129
130 memcpy(noisecurves[6][2],noise_1000_60dB_SL,sizeof(float)*EHMER_MAX);
131 memcpy(noisecurves[6][4],noise_1000_60dB_SL,sizeof(float)*EHMER_MAX);
132 memcpy(noisecurves[6][6],noise_1000_80dB_SL,sizeof(float)*EHMER_MAX);
133 memcpy(noisecurves[6][8],noise_1000_80dB_SL,sizeof(float)*EHMER_MAX);
134
135 memcpy(noisecurves[8][2],noise_2000_60dB_SL,sizeof(float)*EHMER_MAX);
136 memcpy(noisecurves[8][4],noise_2000_60dB_SL,sizeof(float)*EHMER_MAX);
137 memcpy(noisecurves[8][6],noise_2000_80dB_SL,sizeof(float)*EHMER_MAX);
138 memcpy(noisecurves[8][8],noise_2000_80dB_SL,sizeof(float)*EHMER_MAX);
139
140 memcpy(noisecurves[10][2],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
141 memcpy(noisecurves[10][4],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
142 memcpy(noisecurves[10][6],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
143 memcpy(noisecurves[10][8],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
144
145 memcpy(noisecurves[12][2],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
146 memcpy(noisecurves[12][4],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
147 memcpy(noisecurves[12][6],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
148 memcpy(noisecurves[12][8],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
149
150 setup_curve(tonecurves[0],0,vi.toneatt_125Hz);
151 setup_curve(tonecurves[2],2,vi.toneatt_250Hz);
152 setup_curve(tonecurves[4],4,vi.toneatt_500Hz);
153 setup_curve(tonecurves[6],6,vi.toneatt_1000Hz);
154 setup_curve(tonecurves[8],8,vi.toneatt_2000Hz);
155 setup_curve(tonecurves[10],10,vi.toneatt_4000Hz);
156 setup_curve(tonecurves[12],12,vi.toneatt_8000Hz);
157
158 setup_curve(noisecurves[0],0,vi.noiseatt_125Hz);
159 setup_curve(noisecurves[2],2,vi.noiseatt_250Hz);
160 setup_curve(noisecurves[4],4,vi.noiseatt_500Hz);
161 setup_curve(noisecurves[6],6,vi.noiseatt_1000Hz);
162 setup_curve(noisecurves[8],8,vi.noiseatt_2000Hz);
163 setup_curve(noisecurves[10],10,vi.noiseatt_4000Hz);
164 setup_curve(noisecurves[12],12,vi.noiseatt_8000Hz);
165
166 for(i=1;i<13;i+=2){
167 for(j=0;j<9;j++){
168 interp_curve_dB(tonecurves[i][j],
169 tonecurves[i-1][j],
170 tonecurves[i+1][j],.5);
171 interp_curve_dB(noisecurves[i][j],
172 noisecurves[i-1][j],
173 noisecurves[i+1][j],.5);
174 }
175 }
176 for(i=0;i<5;i++){
177 peakatt[0][i]=fromdB(vi.peakatt_125Hz[i]);
178 peakatt[1][i]=fromdB(vi.peakatt_250Hz[i]);
179 peakatt[2][i]=fromdB(vi.peakatt_500Hz[i]);
180 peakatt[3][i]=fromdB(vi.peakatt_1000Hz[i]);
181 peakatt[4][i]=fromdB(vi.peakatt_2000Hz[i]);
182 peakatt[5][i]=fromdB(vi.peakatt_4000Hz[i]);
183 peakatt[6][i]=fromdB(vi.peakatt_8000Hz[i]);
184 }
185 */
186 }
187}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30class Residue0 extends FuncResidue{
31 void pack(Object vr, Buffer opb){
32 InfoResidue0 info=(InfoResidue0)vr;
33 int acc=0;
34 opb.write(info.begin,24);
35 opb.write(info.end,24);
36
37 opb.write(info.grouping-1,24); /* residue vectors to group and
38 code with a partitioned book */
39 opb.write(info.partitions-1,6); /* possible partition choices */
40 opb.write(info.groupbook,8); /* group huffman book */
41
42 /* secondstages is a bitmask; as encoding progresses pass by pass, a
43 bitmask of one indicates this partition class has bits to write
44 this pass */
45 for(int j=0;j<info.partitions;j++){
46 if(ilog(info.secondstages[j])>3){
47 /* yes, this is a minor hack due to not thinking ahead */
48 opb.write(info.secondstages[j],3);
49 opb.write(1,1);
50 opb.write(info.secondstages[j]>>>3,5);
51 }
52 else{
53 opb.write(info.secondstages[j],4); /* trailing zero */
54 }
55 acc+=icount(info.secondstages[j]);
56 }
57 for(int j=0;j<acc;j++){
58 opb.write(info.booklist[j],8);
59 }
60 }
61
62 Object unpack(Info vi, Buffer opb){
63 int acc=0;
64 InfoResidue0 info=new InfoResidue0();
65
66 info.begin=opb.read(24);
67 info.end=opb.read(24);
68 info.grouping=opb.read(24)+1;
69 info.partitions=opb.read(6)+1;
70 info.groupbook=opb.read(8);
71
72 for(int j=0;j<info.partitions;j++){
73 int cascade=opb.read(3);
74 if(opb.read(1)!=0){
75 cascade|=(opb.read(5)<<3);
76 }
77 info.secondstages[j]=cascade;
78 acc+=icount(cascade);
79 }
80
81 for(int j=0;j<acc;j++){
82 info.booklist[j]=opb.read(8);
83// if(info.booklist[j]==255)info.booklist[j]=-1;
84 }
85
86 if(info.groupbook>=vi.books){
87 free_info(info);
88 return(null);
89 }
90
91 for(int j=0;j<acc;j++){
92 if(info.booklist[j]>=vi.books){
93 free_info(info);
94 return(null);
95 }
96 }
97 return(info);
98// errout:
99// free_info(info);
100// return(NULL);
101 }
102
103 Object look(DspState vd, InfoMode vm, Object vr){
104 InfoResidue0 info=(InfoResidue0)vr;
105 LookResidue0 look=new LookResidue0();
106 int acc=0;
107 int dim;
108 int maxstage=0;
109 look.info=info;
110 look.map=vm.mapping;
111
112 look.parts=info.partitions;
113 look.fullbooks=vd.fullbooks;
114 look.phrasebook=vd.fullbooks[info.groupbook];
115
116 dim=look.phrasebook.dim;
117
118 look.partbooks=new int[look.parts][];
119
120 for(int j=0;j<look.parts;j++){
121 int stages=ilog(info.secondstages[j]);
122 if(stages!=0){
123 if(stages>maxstage)maxstage=stages;
124 look.partbooks[j]=new int[stages];
125 for(int k=0; k<stages; k++){
126 if((info.secondstages[j]&(1<<k))!=0){
127 look.partbooks[j][k]=info.booklist[acc++];
128 }
129 }
130 }
131 }
132
133 look.partvals=(int)Math.rint(Math.pow(look.parts,dim));
134 look.stages=maxstage;
135 look.decodemap=new int[look.partvals][];
136 for(int j=0;j<look.partvals;j++){
137 int val=j;
138 int mult=look.partvals/look.parts;
139 look.decodemap[j]=new int[dim];
140
141 for(int k=0;k<dim;k++){
142 int deco=val/mult;
143 val-=deco*mult;
144 mult/=look.parts;
145 look.decodemap[j][k]=deco;
146 }
147 }
148 return(look);
149 }
150 void free_info(Object i){}
151 void free_look(Object i){}
152 int forward(Block vb,Object vl, float[][] in, int ch){
153 System.err.println("Residue0.forward: not implemented");
154 return 0;
155 }
156
157 static int[][][] partword=new int[2][][]; // _01inverse is synchronized for
158 // re-using partword
159 synchronized static int _01inverse(Block vb, Object vl,
160 float[][] in,int ch,int decodepart){
161 int i,j,k,l,s;
162 LookResidue0 look=(LookResidue0 )vl;
163 InfoResidue0 info=look.info;
164
165 // move all this setup out later
166 int samples_per_partition=info.grouping;
167 int partitions_per_word=look.phrasebook.dim;
168 int n=info.end-info.begin;
169
170 int partvals=n/samples_per_partition;
171 int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
172
173 if(partword.length<ch){
174 partword=new int[ch][][];
175 for(j=0;j<ch;j++){
176 partword[j]=new int[partwords][];
177 }
178 }
179 else{
180 for(j=0;j<ch;j++){
181 if(partword[j]==null || partword[j].length<partwords)
182 partword[j]=new int[partwords][];
183 }
184 }
185
186 for(s=0;s<look.stages;s++){
187 // each loop decodes on partition codeword containing
188 // partitions_pre_word partitions
189 for(i=0,l=0;i<partvals;l++){
190 if(s==0){
191 // fetch the partition word for each channel
192 for(j=0;j<ch;j++){
193 int temp=look.phrasebook.decode(vb.opb);
194 if(temp==-1){
195 //goto eopbreak;
196 return(0);
197 }
198 partword[j][l]=look.decodemap[temp];
199 if(partword[j][l]==null){
200// goto errout;
201 return(0);
202 }
203 }
204 }
205
206 // now we decode residual values for the partitions
207 for(k=0;k<partitions_per_word && i<partvals;k++,i++)
208 for(j=0;j<ch;j++){
209 int offset=info.begin+i*samples_per_partition;
210 if((info.secondstages[partword[j][l][k]]&(1<<s))!=0){
211 CodeBook stagebook=look.fullbooks[look.partbooks[partword[j][l][k]][s]];
212// CodeBook stagebook=look.partbooks[partword[j][l][k]][s];
213 if(stagebook!=null){
214 if(decodepart==0){
215 if(stagebook.decodevs_add(in[j],offset,vb.opb,samples_per_partition)==-1){
216 // goto errout;
217 return(0);
218 }
219 }
220 else if(decodepart==1){
221 if(stagebook.decodev_add(in[j], offset, vb.opb,samples_per_partition)==-1){
222 // goto errout;
223 return(0);
224 }
225 }
226 }
227 }
228 }
229 }
230 }
231// errout:
232// eopbreak:
233 return(0);
234 }
235
236 static int _2inverse(Block vb, Object vl, float[][] in, int ch){
237 int i,j,k,l,s;
238 LookResidue0 look=(LookResidue0 )vl;
239 InfoResidue0 info=look.info;
240
241 // move all this setup out later
242 int samples_per_partition=info.grouping;
243 int partitions_per_word=look.phrasebook.dim;
244 int n=info.end-info.begin;
245
246 int partvals=n/samples_per_partition;
247 int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
248
249 int[][] partword=new int[partwords][];
250 for(s=0;s<look.stages;s++){
251 for(i=0,l=0;i<partvals;l++){
252 if(s==0){
253 // fetch the partition word for each channel
254 int temp=look.phrasebook.decode(vb.opb);
255 if(temp==-1){
256 // goto eopbreak;
257 return(0);
258 }
259 partword[l]=look.decodemap[temp];
260 if(partword[l]==null){
261 // goto errout;
262 return(0);
263 }
264 }
265
266 // now we decode residual values for the partitions
267 for(k=0;k<partitions_per_word && i<partvals;k++,i++){
268 int offset=info.begin+i*samples_per_partition;
269 if((info.secondstages[partword[l][k]]&(1<<s))!=0){
270 CodeBook stagebook=look.fullbooks[look.partbooks[partword[l][k]][s]];
271 if(stagebook!=null){
272 if(stagebook.decodevv_add(in, offset, ch, vb.opb,samples_per_partition)==-1){
273 // goto errout;
274 return(0);
275 }
276 }
277 }
278 }
279 }
280 }
281// errout:
282// eopbreak:
283 return(0);
284 }
285
286 int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
287 //System.err.println("Residue0.inverse");
288 int used=0;
289 for(int i=0;i<ch;i++){
290 if(nonzero[i]!=0){
291 in[used++]=in[i];
292 }
293 }
294 if(used!=0)
295 return(_01inverse(vb,vl,in,used,0));
296 else
297 return(0);
298 }
299
300/*
301 int inverse(Block vb, Object vl, float[][] in, int ch){
302//System.err.println("Residue0.inverse");
303 int i,j,k,l,transend=vb.pcmend/2;
304 LookResidue0 look=(LookResidue0 )vl;
305 InfoResidue0 info=look.info;
306
307 // move all this setup out later
308 int samples_per_partition=info.grouping;
309 int partitions_per_word=look.phrasebook.dim;
310 int n=info.end-info.begin;
311
312 int partvals=n/samples_per_partition;
313 int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
314 int[][] partword=new int[ch][];
315 float[] work=new float[samples_per_partition];
316 partvals=partwords*partitions_per_word;
317
318 // make sure we're zeroed up to the start
319 for(j=0;j<ch;j++){
320 for(k=0; k<info.begin; k++)in[j][k]=0.0f;
321 }
322
323 for(i=info.begin,l=0;i<info.end;){
324 // fetch the partition word for each channel
325 for(j=0;j<ch;j++){
326 int temp=look.phrasebook.decode(vb.opb);
327 if(temp==-1){
328 //goto eopbreak;
329 if(i<transend){
330 for(j=0;j<ch;j++){
331 for(k=0;k<transend-i;k++)in[j][i+k]=0.0f;
332 }
333 }
334 return(0);
335 }
336 partword[j]=look.decodemap[temp];
337 if(partword[j]==null){
338 //goto errout;
339 for(j=0;j<ch;j++){
340 for(k=0;k<transend;k++)in[j][k]=0.0f;
341 }
342 return(0);
343 }
344 }
345
346 // now we decode interleaved residual values for the partitions
347 for(k=0;k<partitions_per_word;k++,l++,i+=samples_per_partition){
348 for(j=0;j<ch;j++){
349 int part=partword[j][k];
350 if(decodepart(vb.opb,work, in[j], i,samples_per_partition,
351 info.secondstages[part],
352 look.partbooks[part])==-1){
353 //goto eopbreak;
354 if(i<transend){
355 for(j=0;j<ch;j++){
356 for(k=0;k<transend-i;k++)in[j][i+k]=0.0f;
357 }
358 }
359 return(0);
360 }
361 }
362 }
363 }
364
365// eopbreak:
366 if(i<transend){
367 for(j=0;j<ch;j++){
368 for(k=0;k<transend-i;k++)in[j][i+k]=0.0f;
369 }
370 }
371 return(0);
372
373// errout:
374// for(j=0;j<ch;j++)
375// for(k=0;k<transend;k++)in[j][k]=0.0f;
376// return(0);
377 }
378 int decodepart(Buffer opb, float[] work, float[] vec, int veci,
379 int n, int stages, CodeBook[] books){
380 int i,j;
381 for(i=0;i<n;i++)work[i]=0.0f;
382
383 for(j=0;j<stages;j++){
384 int dim=books[j].dim;
385 int step=n/dim;
386 for(i=0;i<step;i++){
387 if(books[j].decodevs(work, i, opb, step, 0)==-1){
388 return(-1);
389 }
390 }
391 }
392 for(i=0;i<n;i++){
393 vec[veci+i]*=work[i];
394 }
395 return(0);
396 }
397*/
398
399 private static int ilog(int v){
400 int ret=0;
401 while(v!=0){
402 ret++;
403 v>>>=1;
404 }
405 return(ret);
406 }
407 private static int icount(int v){
408 int ret=0;
409 while(v!=0){
410 ret+=(v&1);
411 v>>>=1;
412 }
413 return(ret);
414 }
415}
416
417class LookResidue0 {
418 InfoResidue0 info;
419 int map;
420
421 int parts;
422 int stages;
423 CodeBook[] fullbooks;
424 CodeBook phrasebook;
425 int[][] partbooks;
426// CodeBook[][] partbooks;
427
428 int partvals;
429 int[][] decodemap;
430
431 int postbits;
432 int phrasebits;
433// int[][] frames;
434 int frames;
435}
436
437class InfoResidue0{
438 // block-partitioned VQ coded straight residue
439 int begin;
440 int end;
441
442 // first stage (lossless partitioning)
443 int grouping; // group n vectors per partition
444 int partitions; // possible codebooks for a partition
445 int groupbook; // huffbook for partitioning
446 int[] secondstages=new int[64]; // expanded out to pointers in lookup
447 int[] booklist=new int[256]; // list of second stage books
448
449 // encode-only heuristic settings
450 float[] entmax=new float[64]; // book entropy threshholds
451 float[] ampmax=new float[64]; // book amp threshholds
452 int[] subgrp=new int[64]; // book heuristic subgroup size
453 int[] blimit=new int[64]; // subgroup position limits
454}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30class Residue1 extends Residue0{
31 int forward(Block vb,Object vl, float[][] in, int ch){
32 System.err.println("Residue0.forward: not implemented");
33 return 0;
34 }
35
36 int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
37//System.err.println("Residue0.inverse");
38 int used=0;
39 for(int i=0; i<ch; i++){
40 if(nonzero[i]!=0){
41 in[used++]=in[i];
42 }
43 }
44 if(used!=0){
45 return(_01inverse(vb,vl,in,used,1));
46 }
47 else{
48 return 0;
49 }
50 }
51}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30class Residue2 extends Residue0{
31 int forward(Block vb,Object vl, float[][] in, int ch){
32 System.err.println("Residue0.forward: not implemented");
33 return 0;
34 }
35
36 int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
37//System.err.println("Residue0.inverse");
38 int i=0;
39 for(i=0;i<ch;i++)if(nonzero[i]!=0)break;
40 if(i==ch)return(0); /* no nonzero vectors */
41
42 return(_2inverse(vb,vl,in, ch));
43 }
44}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30class StaticCodeBook{
31 int dim; // codebook dimensions (elements per vector)
32 int entries; // codebook entries
33 int[] lengthlist; // codeword lengths in bits
34
35 // mapping
36 int maptype; // 0=none
37 // 1=implicitly populated values from map column
38 // 2=listed arbitrary values
39
40 // The below does a linear, single monotonic sequence mapping.
41 int q_min; // packed 32 bit float; quant value 0 maps to minval
42 int q_delta; // packed 32 bit float; val 1 - val 0 == delta
43 int q_quant; // bits: 0 < quant <= 16
44 int q_sequencep; // bitflag
45
46 // additional information for log (dB) mapping; the linear mapping
47 // is assumed to actually be values in dB. encodebias is used to
48 // assign an error weight to 0 dB. We have two additional flags:
49 // zeroflag indicates if entry zero is to represent -Inf dB; negflag
50 // indicates if we're to represent negative linear values in a
51 // mirror of the positive mapping.
52
53 int[] quantlist; // map == 1: (int)(entries/dim) element column map
54 // map == 2: list of dim*entries quantized entry vals
55
56 // encode helpers
57 EncodeAuxNearestMatch nearest_tree;
58 EncodeAuxThreshMatch thresh_tree;
59
60 StaticCodeBook(){}
61 StaticCodeBook(int dim, int entries, int[] lengthlist,
62 int maptype, int q_min, int q_delta,
63 int q_quant, int q_sequencep, int[] quantlist,
64 //EncodeAuxNearestmatch nearest_tree,
65 Object nearest_tree,
66 // EncodeAuxThreshmatch thresh_tree,
67 Object thresh_tree
68 ){
69 this();
70 this.dim=dim; this.entries=entries; this.lengthlist=lengthlist;
71 this.maptype=maptype; this.q_min=q_min; this.q_delta=q_delta;
72 this.q_quant=q_quant; this.q_sequencep=q_sequencep;
73 this.quantlist=quantlist;
74 }
75
76 int pack(Buffer opb){
77 int i;
78 boolean ordered=false;
79
80 opb.write(0x564342,24);
81 opb.write(dim, 16);
82 opb.write(entries, 24);
83
84 // pack the codewords. There are two packings; length ordered and
85 // length random. Decide between the two now.
86
87 for(i=1;i<entries;i++){
88 if(lengthlist[i]<lengthlist[i-1])break;
89 }
90 if(i==entries)ordered=true;
91
92 if(ordered){
93 // length ordered. We only need to say how many codewords of
94 // each length. The actual codewords are generated
95 // deterministically
96
97 int count=0;
98 opb.write(1,1); // ordered
99 opb.write(lengthlist[0]-1,5); // 1 to 32
100
101 for(i=1;i<entries;i++){
102 int _this=lengthlist[i];
103 int _last=lengthlist[i-1];
104 if(_this>_last){
105 for(int j=_last;j<_this;j++){
106 opb.write(i-count,ilog(entries-count));
107 count=i;
108 }
109 }
110 }
111 opb.write(i-count,ilog(entries-count));
112 }
113 else{
114 // length random. Again, we don't code the codeword itself, just
115 // the length. This time, though, we have to encode each length
116 opb.write(0,1); // unordered
117
118 // algortihmic mapping has use for 'unused entries', which we tag
119 // here. The algorithmic mapping happens as usual, but the unused
120 // entry has no codeword.
121 for(i=0;i<entries;i++){
122 if(lengthlist[i]==0)break;
123 }
124
125 if(i==entries){
126 opb.write(0,1); // no unused entries
127 for(i=0;i<entries;i++){
128 opb.write(lengthlist[i]-1,5);
129 }
130 }
131 else{
132 opb.write(1,1); // we have unused entries; thus we tag
133 for(i=0;i<entries;i++){
134 if(lengthlist[i]==0){
135 opb.write(0,1);
136 }
137 else{
138 opb.write(1,1);
139 opb.write(lengthlist[i]-1,5);
140 }
141 }
142 }
143 }
144
145 // is the entry number the desired return value, or do we have a
146 // mapping? If we have a mapping, what type?
147 opb.write(maptype,4);
148 switch(maptype){
149 case 0:
150 // no mapping
151 break;
152 case 1:
153 case 2:
154 // implicitly populated value mapping
155 // explicitly populated value mapping
156 if(quantlist==null){
157 // no quantlist? error
158 return(-1);
159 }
160
161 // values that define the dequantization
162 opb.write(q_min,32);
163 opb.write(q_delta,32);
164 opb.write(q_quant-1,4);
165 opb.write(q_sequencep,1);
166
167 {
168 int quantvals=0;
169 switch(maptype){
170 case 1:
171 // a single column of (c->entries/c->dim) quantized values for
172 // building a full value list algorithmically (square lattice)
173 quantvals=maptype1_quantvals();
174 break;
175 case 2:
176 // every value (c->entries*c->dim total) specified explicitly
177 quantvals=entries*dim;
178 break;
179 }
180
181 // quantized values
182 for(i=0;i<quantvals;i++){
183 opb.write(Math.abs(quantlist[i]),q_quant);
184 }
185 }
186 break;
187 default:
188 // error case; we don't have any other map types now
189 return(-1);
190 }
191 return(0);
192 }
193/*
194*/
195
196 // unpacks a codebook from the packet buffer into the codebook struct,
197 // readies the codebook auxiliary structures for decode
198 int unpack(Buffer opb){
199 int i;
200 //memset(s,0,sizeof(static_codebook));
201
202 // make sure alignment is correct
203 if(opb.read(24)!=0x564342){
204// goto _eofout;
205 clear();
206 return(-1);
207 }
208
209 // first the basic parameters
210 dim=opb.read(16);
211 entries=opb.read(24);
212 if(entries==-1){
213// goto _eofout;
214 clear();
215 return(-1);
216 }
217
218 // codeword ordering.... length ordered or unordered?
219 switch(opb.read(1)){
220 case 0:
221 // unordered
222 lengthlist=new int[entries];
223
224 // allocated but unused entries?
225 if(opb.read(1)!=0){
226 // yes, unused entries
227
228 for(i=0;i<entries;i++){
229 if(opb.read(1)!=0){
230 int num=opb.read(5);
231 if(num==-1){
232// goto _eofout;
233 clear();
234 return(-1);
235 }
236 lengthlist[i]=num+1;
237 }
238 else{
239 lengthlist[i]=0;
240 }
241 }
242 }
243 else{
244 // all entries used; no tagging
245 for(i=0;i<entries;i++){
246 int num=opb.read(5);
247 if(num==-1){
248// goto _eofout;
249 clear();
250 return(-1);
251 }
252 lengthlist[i]=num+1;
253 }
254 }
255 break;
256 case 1:
257 // ordered
258 {
259 int length=opb.read(5)+1;
260 lengthlist=new int[entries];
261
262 for(i=0;i<entries;){
263 int num=opb.read(ilog(entries-i));
264 if(num==-1){
265// goto _eofout;
266 clear();
267 return(-1);
268 }
269 for(int j=0;j<num;j++,i++){
270 lengthlist[i]=length;
271 }
272 length++;
273 }
274 }
275 break;
276 default:
277 // EOF
278 return(-1);
279 }
280
281 // Do we have a mapping to unpack?
282 switch((maptype=opb.read(4))){
283 case 0:
284 // no mapping
285 break;
286 case 1:
287 case 2:
288 // implicitly populated value mapping
289 // explicitly populated value mapping
290 q_min=opb.read(32);
291 q_delta=opb.read(32);
292 q_quant=opb.read(4)+1;
293 q_sequencep=opb.read(1);
294
295 {
296 int quantvals=0;
297 switch(maptype){
298 case 1:
299 quantvals=maptype1_quantvals();
300 break;
301 case 2:
302 quantvals=entries*dim;
303 break;
304 }
305
306 // quantized values
307 quantlist=new int[quantvals];
308 for(i=0;i<quantvals;i++){
309 quantlist[i]=opb.read(q_quant);
310 }
311 if(quantlist[quantvals-1]==-1){
312// goto _eofout;
313 clear();
314 return(-1);
315 }
316 }
317 break;
318 default:
319// goto _eofout;
320 clear();
321 return(-1);
322 }
323 // all set
324 return(0);
325// _errout:
326// _eofout:
327// vorbis_staticbook_clear(s);
328// return(-1);
329 }
330
331 // there might be a straightforward one-line way to do the below
332 // that's portable and totally safe against roundoff, but I haven't
333 // thought of it. Therefore, we opt on the side of caution
334 private int maptype1_quantvals(){
335 int vals=(int)(Math.floor(Math.pow(entries,1./dim)));
336
337 // the above *should* be reliable, but we'll not assume that FP is
338 // ever reliable when bitstream sync is at stake; verify via integer
339 // means that vals really is the greatest value of dim for which
340 // vals^b->bim <= b->entries
341 // treat the above as an initial guess
342 while(true){
343 int acc=1;
344 int acc1=1;
345 for(int i=0;i<dim;i++){
346 acc*=vals;
347 acc1*=vals+1;
348 }
349 if(acc<=entries && acc1>entries){ return(vals); }
350 else{
351 if(acc>entries){ vals--; }
352 else{ vals++; }
353 }
354 }
355 }
356
357 void clear(){
358// if(quantlist!=null)free(b->quantlist);
359// if(lengthlist!=null)free(b->lengthlist);
360// if(nearest_tree!=null){
361// free(b->nearest_tree->ptr0);
362// free(b->nearest_tree->ptr1);
363// free(b->nearest_tree->p);
364// free(b->nearest_tree->q);
365// memset(b->nearest_tree,0,sizeof(encode_aux_nearestmatch));
366// free(b->nearest_tree);
367// }
368// if(thresh_tree!=null){
369// free(b->thresh_tree->quantthresh);
370// free(b->thresh_tree->quantmap);
371// memset(b->thresh_tree,0,sizeof(encode_aux_threshmatch));
372// free(b->thresh_tree);
373// }
374// memset(b,0,sizeof(static_codebook));
375 }
376
377 // unpack the quantized list of values for encode/decode
378 // we need to deal with two map types: in map type 1, the values are
379 // generated algorithmically (each column of the vector counts through
380 // the values in the quant vector). in map type 2, all the values came
381 // in in an explicit list. Both value lists must be unpacked
382 float[] unquantize(){
383
384 if(maptype==1 || maptype==2){
385 int quantvals;
386 float mindel=float32_unpack(q_min);
387 float delta=float32_unpack(q_delta);
388 float[] r=new float[entries*dim];
389
390 //System.err.println("q_min="+q_min+", mindel="+mindel);
391
392 // maptype 1 and 2 both use a quantized value vector, but
393 // different sizes
394 switch(maptype){
395 case 1:
396 // most of the time, entries%dimensions == 0, but we need to be
397 // well defined. We define that the possible vales at each
398 // scalar is values == entries/dim. If entries%dim != 0, we'll
399 // have 'too few' values (values*dim<entries), which means that
400 // we'll have 'left over' entries; left over entries use zeroed
401 // values (and are wasted). So don't generate codebooks like that
402 quantvals=maptype1_quantvals();
403 for(int j=0;j<entries;j++){
404 float last=0.f;
405 int indexdiv=1;
406 for(int k=0;k<dim;k++){
407 int index=(j/indexdiv)%quantvals;
408 float val=quantlist[index];
409 val=Math.abs(val)*delta+mindel+last;
410 if(q_sequencep!=0)last=val;
411 r[j*dim+k]=val;
412 indexdiv*=quantvals;
413 }
414 }
415 break;
416 case 2:
417 for(int j=0;j<entries;j++){
418 float last=0.f;
419 for(int k=0;k<dim;k++){
420 float val=quantlist[j*dim+k];
421//if((j*dim+k)==0){System.err.println(" | 0 -> "+val+" | ");}
422 val=Math.abs(val)*delta+mindel+last;
423 if(q_sequencep!=0)last=val;
424 r[j*dim+k]=val;
425//if((j*dim+k)==0){System.err.println(" $ r[0] -> "+r[0]+" | ");}
426 }
427 }
428//System.err.println("\nr[0]="+r[0]);
429 }
430 return(r);
431 }
432 return(null);
433 }
434
435 private static int ilog(int v){
436 int ret=0;
437 while(v!=0){
438 ret++;
439 v>>>=1;
440 }
441 return(ret);
442 }
443
444 // 32 bit float (not IEEE; nonnormalized mantissa +
445 // biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm
446 // Why not IEEE? It's just not that important here.
447
448 static final int VQ_FEXP=10;
449 static final int VQ_FMAN=21;
450 static final int VQ_FEXP_BIAS=768; // bias toward values smaller than 1.
451
452 // doesn't currently guard under/overflow
453 static long float32_pack(float val){
454 int sign=0;
455 int exp;
456 int mant;
457 if(val<0){
458 sign=0x80000000;
459 val= -val;
460 }
461 exp=(int)Math.floor(Math.log(val)/Math.log(2));
462 mant=(int)Math.rint(Math.pow(val,(VQ_FMAN-1)-exp));
463 exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN;
464 return(sign|exp|mant);
465 }
466
467 static float float32_unpack(int val){
468 float mant=val&0x1fffff;
469 float sign=val&0x80000000;
470 float exp =(val&0x7fe00000)>>>VQ_FMAN;
471//System.err.println("mant="+mant+", sign="+sign+", exp="+exp);
472 //if(sign!=0.0)mant= -mant;
473 if((val&0x80000000)!=0)mant= -mant;
474//System.err.println("mant="+mant);
475 return(ldexp(mant,((int)exp)-(VQ_FMAN-1)-VQ_FEXP_BIAS));
476 }
477
478 static float ldexp(float foo, int e){
479 return (float)(foo*Math.pow(2, e));
480 }
481
482/*
483 // TEST
484 // Unit tests of the dequantizer; this stuff will be OK
485 // cross-platform, I simply want to be sure that special mapping cases
486 // actually work properly; a bug could go unnoticed for a while
487
488 // cases:
489 //
490 // no mapping
491 // full, explicit mapping
492 // algorithmic mapping
493 //
494 // nonsequential
495 // sequential
496
497 static int[] full_quantlist1={0,1,2,3, 4,5,6,7, 8,3,6,1};
498 static int[] partial_quantlist1={0,7,2};
499
500 // no mapping
501 static StaticCodeBook test1=new StaticCodeBook(4,16,null,
502 0,0,0,0,0,
503 null,null,null);
504 static float[] test1_result=null;
505
506 // linear, full mapping, nonsequential
507 static StaticCodeBook test2=new StaticCodeBook(4,3,null,
508 2,-533200896,1611661312,4,0,
509 full_quantlist1, null, null);
510 static float[] test2_result={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2};
511
512 // linear, full mapping, sequential
513 static StaticCodeBook test3=new StaticCodeBook(4,3,null,
514 2, -533200896,1611661312,4,1,
515 full_quantlist1,null, null);
516 static float[] test3_result={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6};
517
518 // linear, algorithmic mapping, nonsequential
519 static StaticCodeBook test4=new StaticCodeBook(3,27,null,
520 1,-533200896,1611661312,4,0,
521 partial_quantlist1,null,null);
522 static float[] test4_result={-3,-3,-3, 4,-3,-3, -1,-3,-3,
523 -3, 4,-3, 4, 4,-3, -1, 4,-3,
524 -3,-1,-3, 4,-1,-3, -1,-1,-3,
525 -3,-3, 4, 4,-3, 4, -1,-3, 4,
526 -3, 4, 4, 4, 4, 4, -1, 4, 4,
527 -3,-1, 4, 4,-1, 4, -1,-1, 4,
528 -3,-3,-1, 4,-3,-1, -1,-3,-1,
529 -3, 4,-1, 4, 4,-1, -1, 4,-1,
530 -3,-1,-1, 4,-1,-1, -1,-1,-1};
531
532 // linear, algorithmic mapping, sequential
533 static StaticCodeBook test5=new StaticCodeBook(3,27,null,
534 1,-533200896,1611661312,4,1,
535 partial_quantlist1,null,null);
536 static float[] test5_result={-3,-6,-9, 4, 1,-2, -1,-4,-7,
537 -3, 1,-2, 4, 8, 5, -1, 3, 0,
538 -3,-4,-7, 4, 3, 0, -1,-2,-5,
539 -3,-6,-2, 4, 1, 5, -1,-4, 0,
540 -3, 1, 5, 4, 8,12, -1, 3, 7,
541 -3,-4, 0, 4, 3, 7, -1,-2, 2,
542 -3,-6,-7, 4, 1, 0, -1,-4,-5,
543 -3, 1, 0, 4, 8, 7, -1, 3, 2,
544 -3,-4,-5, 4, 3, 2, -1,-2,-3};
545
546 void run_test(float[] comp){
547 float[] out=unquantize();
548 if(comp!=null){
549 if(out==null){
550 System.err.println("_book_unquantize incorrectly returned NULL");
551 System.exit(1);
552 }
553 for(int i=0;i<entries*dim;i++){
554 if(Math.abs(out[i]-comp[i])>.0001){
555 System.err.println("disagreement in unquantized and reference data:\nposition "+i+": "+out[i]+" != "+comp[i]);
556 System.exit(1);
557 }
558 }
559 }
560 else{
561 if(out!=null){
562 System.err.println("_book_unquantize returned a value array:\n correct result should have been NULL");
563 System.exit(1);
564 }
565 }
566 }
567
568 public static void main(String[] arg){
569 // run the nine dequant tests, and compare to the hand-rolled results
570 System.err.print("Dequant test 1... ");
571 test1.run_test(test1_result);
572 System.err.print("OK\nDequant test 2... ");
573 test2.run_test(test2_result);
574 System.err.print("OK\nDequant test 3... ");
575 test3.run_test(test3_result);
576 System.err.print("OK\nDequant test 4... ");
577 test4.run_test(test4_result);
578 System.err.print("OK\nDequant test 5... ");
579 test5.run_test(test5_result);
580 System.err.print("OK\n\n");
581 }
582*/
583}
584
585
586
587
588
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30class Time0 extends FuncTime{
31 void pack(Object i, Buffer opb){}
32 Object unpack(Info vi , Buffer opb){return "";}
33 Object look(DspState vd, InfoMode mi, Object i){return "";}
34 void free_info(Object i){}
35 void free_look(Object i){}
36 int forward(Block vb, Object i){return 0;}
37 int inverse(Block vb, Object i, float[] in, float[] out){return 0;}
38}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29
30import java.io.InputStream;
31import java.io.IOException;
32
33public class VorbisFile{
34 static final int CHUNKSIZE=8500;
35 static final int SEEK_SET=0;
36 static final int SEEK_CUR=1;
37 static final int SEEK_END=2;
38
39 static final int OV_FALSE=-1;
40 static final int OV_EOF=-2;
41 static final int OV_HOLE=-3;
42
43 static final int OV_EREAD=-128;
44 static final int OV_EFAULT=-129;
45 static final int OV_EIMPL=-130;
46 static final int OV_EINVAL=-131;
47 static final int OV_ENOTVORBIS=-132;
48 static final int OV_EBADHEADER=-133;
49 static final int OV_EVERSION=-134;
50 static final int OV_ENOTAUDIO=-135;
51 static final int OV_EBADPACKET=-136;
52 static final int OV_EBADLINK=-137;
53 static final int OV_ENOSEEK=-138;
54
55 InputStream datasource;
56 boolean seekable=false;
57 long offset;
58 long end;
59
60 SyncState oy=new SyncState();
61
62 int links;
63 long[] offsets;
64 long[] dataoffsets;
65 int[] serialnos;
66 long[] pcmlengths;
67 Info[] vi;
68 Comment[] vc;
69
70 // Decoding working state local storage
71 long pcm_offset;
72 boolean decode_ready=false;
73 int current_serialno;
74 int current_link;
75
76 float bittrack;
77 float samptrack;
78
79 StreamState os=new StreamState(); // take physical pages, weld into a logical
80 // stream of packets
81 DspState vd=new DspState(); // central working state for
82 // the packet->PCM decoder
83 Block vb=new Block(vd); // local working space for packet->PCM decode
84
85 //ov_callbacks callbacks;
86
87 public VorbisFile(String file) throws JOrbisException {
88 super();
89 InputStream is=null;
90 try{
91 is=new SeekableInputStream(file);
92 int ret=open(is, null, 0);
93 if(ret==-1){
94 throw new JOrbisException("VorbisFile: open return -1");
95 }
96 }
97 catch(Exception e){
98 throw new JOrbisException("VorbisFile: "+e.toString());
99 }
100 finally{
101 if(is != null){
102 try {
103 is.close();
104 }
105 catch (IOException e) {
106 e.printStackTrace();
107 }
108 }
109 }
110 }
111
112 public VorbisFile(InputStream is, byte[] initial, int ibytes)
113 throws JOrbisException {
114 super();
115 int ret=open(is, initial, ibytes);
116 if(ret==-1){
117 }
118 }
119
120 private int get_data(){
121 int index=oy.buffer(CHUNKSIZE);
122 byte[] buffer=oy.data;
123// int bytes=callbacks.read_func(buffer, index, 1, CHUNKSIZE, datasource);
124 int bytes=0;
125 try{
126 bytes=datasource.read(buffer, index, CHUNKSIZE);
127 }
128 catch(Exception e){
129 //System.err.println(e);
130 return OV_EREAD;
131 }
132 oy.wrote(bytes);
133 if(bytes==-1){
134// System.out.println("bytes="+bytes);
135 bytes=0;
136 }
137 return bytes;
138 }
139
140 private void seek_helper(long offst){
141 //callbacks.seek_func(datasource, offst, SEEK_SET);
142 fseek(datasource, offst, SEEK_SET);
143 this.offset=offst;
144 oy.reset();
145 }
146
147 private int get_next_page(Page page, long boundary){
148 if(boundary>0) boundary+=offset;
149 while(true){
150 int more;
151 if(boundary>0 && offset>=boundary)return OV_FALSE;
152 more=oy.pageseek(page);
153 if(more<0){offset-=more;}
154 else{
155 if(more==0){
156 if(boundary==0)return OV_FALSE;
157// if(get_data()<=0)return -1;
158 int ret=get_data();
159 if(ret==0) return OV_EOF;
160 if(ret<0) return OV_EREAD;
161 }
162 else{
163 int ret=(int)offset; //!!!
164 offset+=more;
165 return ret;
166 }
167 }
168 }
169 }
170
171 private int get_prev_page(Page page) throws JOrbisException {
172 long begin=offset; //!!!
173 int ret;
174 int offst=-1;
175 while(offst==-1){
176 begin-=CHUNKSIZE;
177 if(begin<0)
178 begin=0;
179 seek_helper(begin);
180 while(offset<begin+CHUNKSIZE){
181 ret=get_next_page(page, begin+CHUNKSIZE-offset);
182 if(ret==OV_EREAD){ return OV_EREAD; }
183 if(ret<0){
184 if(offst == -1)
185 throw new JOrbisException();
186 break;
187 }
188 else{ offst=ret; }
189 }
190 }
191 seek_helper(offst); //!!!
192 ret=get_next_page(page, CHUNKSIZE);
193 if(ret<0){
194 //System.err.println("Missed page fencepost at end of logical bitstream Exiting");
195 //System.exit(1);
196 return OV_EFAULT;
197 }
198 return offst;
199 }
200
201 int bisect_forward_serialno(long begin, long searched, long end, int currentno, int m){
202 long endsearched=end;
203 long next=end;
204 Page page=new Page();
205 int ret;
206
207 while(searched<endsearched){
208 long bisect;
209 if(endsearched-searched<CHUNKSIZE){
210 bisect=searched;
211 }
212 else{
213 bisect=(searched+endsearched)/2;
214 }
215
216 seek_helper(bisect);
217 ret=get_next_page(page, -1);
218 if(ret==OV_EREAD) return OV_EREAD;
219 if(ret<0 || page.serialno()!=currentno){
220 endsearched=bisect;
221 if(ret>=0)next=ret;
222 }
223 else{
224 searched=ret+page.header_len+page.body_len;
225 }
226 }
227 seek_helper(next);
228 ret=get_next_page(page, -1);
229 if(ret==OV_EREAD) return OV_EREAD;
230
231 if(searched>=end || ret==-1){
232 links=m+1;
233 offsets=new long[m+2];
234 offsets[m+1]=searched;
235 }
236 else{
237 ret=bisect_forward_serialno(next, offset, end, page.serialno(), m+1);
238 if(ret==OV_EREAD)return OV_EREAD;
239 }
240 offsets[m]=begin;
241 return 0;
242 }
243
244 // uses the local ogg_stream storage in vf; this is important for
245 // non-streaming input sources
246 int fetch_headers(Info vi, Comment vc, int[] serialno, Page og_ptr){
247 //System.err.println("fetch_headers");
248 Page og=new Page();
249 Packet op=new Packet();
250 int ret;
251
252 if(og_ptr==null){
253 ret=get_next_page(og, CHUNKSIZE);
254 if(ret==OV_EREAD)return OV_EREAD;
255 if(ret<0) return OV_ENOTVORBIS;
256 og_ptr=og;
257 }
258
259 if(serialno!=null)serialno[0]=og_ptr.serialno();
260
261 os.init(og_ptr.serialno());
262
263 // extract the initial header from the first page and verify that the
264 // Ogg bitstream is in fact Vorbis data
265
266 vi.init();
267 vc.init();
268
269 int i=0;
270 while(i<3){
271 os.pagein(og_ptr);
272 while(i<3){
273 int result=os.packetout(op);
274 if(result==0)break;
275 if(result==-1){
276 //System.err.println("Corrupt header in logical bitstream.");
277 //goto bail_header;
278 vi.clear();
279 vc.clear();
280 os.clear();
281 return -1;
282 }
283 if(vi.synthesis_headerin(vc, op)!=0){
284 //System.err.println("Illegal header in logical bitstream.");
285 //goto bail_header;
286 vi.clear();
287 vc.clear();
288 os.clear();
289 return -1;
290 }
291 i++;
292 }
293 if(i<3)
294 if(get_next_page(og_ptr, 1)<0){
295 //System.err.println("Missing header in logical bitstream.");
296 //goto bail_header;
297 vi.clear();
298 vc.clear();
299 os.clear();
300 return -1;
301 }
302 }
303 return 0;
304
305// bail_header:
306// vorbis_info_clear(vi);
307// vorbis_comment_clear(vc);
308// ogg_stream_clear(&vf->os);
309// return -1;
310 }
311
312 // last step of the OggVorbis_File initialization; get all the
313 // vorbis_info structs and PCM positions. Only called by the seekable
314 // initialization (local stream storage is hacked slightly; pay
315 // attention to how that's done)
316 void prefetch_all_headers(Info first_i,Comment first_c,
317 int dataoffset) throws JOrbisException {
318 Page og=new Page();
319 int ret;
320
321 vi=new Info[links];
322 vc=new Comment[links];
323 dataoffsets=new long[links];
324 pcmlengths=new long[links];
325 serialnos=new int[links];
326
327 for(int i=0;i<links;i++){
328 if(first_i!=null && first_c!=null && i==0){
329 // we already grabbed the initial header earlier. This just
330 // saves the waste of grabbing it again
331 // !!!!!!!!!!!!!
332 vi[i]=first_i;
333 //memcpy(vf->vi+i,first_i,sizeof(vorbis_info));
334 vc[i]=first_c;
335 //memcpy(vf->vc+i,first_c,sizeof(vorbis_comment));
336 dataoffsets[i]=dataoffset;
337 }
338 else{
339 // seek to the location of the initial header
340 seek_helper(offsets[i]); //!!!
341 vi[i]=new Info();
342 vc[i]=new Comment();
343 if(fetch_headers(vi[i], vc[i], null, null)==-1){
344 //System.err.println("Error opening logical bitstream #"+(i+1)+"\n");
345 dataoffsets[i]=-1;
346 }
347 else{
348 dataoffsets[i]=offset;
349 os.clear();
350 }
351 }
352
353 // get the serial number and PCM length of this link. To do this,
354 // get the last page of the stream
355 {
356 long end=offsets[i+1]; //!!!
357 seek_helper(end);
358
359 while(true){
360 ret=get_prev_page(og);
361 if(ret==-1){
362 // this should not be possible
363 //System.err.println("Could not find last page of logical "+
364 // "bitstream #"+(i)+"\n");
365 vi[i].clear();
366 vc[i].clear();
367 break;
368 }
369 if(og.granulepos()!=-1){
370 serialnos[i]=og.serialno();
371 pcmlengths[i]=og.granulepos();
372 break;
373 }
374 }
375 }
376 }
377 }
378
379 int make_decode_ready(){
380 if(decode_ready)System.exit(1);
381 vd.synthesis_init(vi[0]);
382 vb.init(vd);
383 decode_ready=true;
384 return(0);
385 }
386
387 int open_seekable() throws JOrbisException {
388 Info initial_i=new Info();
389 Comment initial_c=new Comment();
390 int serialno;
391 long end;
392 int ret;
393 int dataoffset;
394 Page og=new Page();
395 // is this even vorbis...?
396 int[] foo=new int[1];
397 ret=fetch_headers(initial_i, initial_c, foo, null);
398 serialno=foo[0];
399 dataoffset=(int)offset; //!!
400 os.clear();
401 if(ret==-1)return(-1);
402 // we can seek, so set out learning all about this file
403 seekable=true;
404 //(callbacks.seek_func)(datasource, 0, SEEK_END);
405 fseek(datasource, 0, SEEK_END);
406 //offset=end=(callbacks.tell_func)(datasource);
407 offset=ftell(datasource);
408 end=offset;
409 // We get the offset for the last page of the physical bitstream.
410 // Most OggVorbis files will contain a single logical bitstream
411 end=get_prev_page(og);
412 // moer than one logical bitstream?
413 if(og.serialno()!=serialno){
414 // Chained bitstream. Bisect-search each logical bitstream
415 // section. Do so based on serial number only
416 if(bisect_forward_serialno(0,0,end+1,serialno,0)<0){
417 clear();
418 return OV_EREAD;
419 }
420 }
421 else{
422 // Only one logical bitstream
423 if(bisect_forward_serialno(0,end,end+1,serialno,0)<0){
424 clear();
425 return OV_EREAD;
426 }
427 }
428 prefetch_all_headers(initial_i, initial_c, dataoffset);
429 return(raw_seek(0));
430 }
431
432 int open_nonseekable(){
433 //System.err.println("open_nonseekable");
434 // we cannot seek. Set up a 'single' (current) logical bitstream entry
435 links=1;
436 vi=new Info[links]; vi[0]=new Info(); // ??
437 vc=new Comment[links]; vc[0]=new Comment(); // ?? bug?
438
439 // Try to fetch the headers, maintaining all the storage
440 int[]foo=new int[1];
441 if(fetch_headers(vi[0], vc[0], foo, null)==-1)return(-1);
442 current_serialno=foo[0];
443 make_decode_ready();
444 return 0;
445 }
446
447 // clear out the current logical bitstream decoder
448 void decode_clear(){
449 os.clear();
450 vd.clear();
451 vb.clear();
452 decode_ready=false;
453 bittrack=0.f;
454 samptrack=0.f;
455 }
456
457 // fetch and process a packet. Handles the case where we're at a
458 // bitstream boundary and dumps the decoding machine. If the decoding
459 // machine is unloaded, it loads it. It also keeps pcm_offset up to
460 // date (seek and read both use this. seek uses a special hack with
461 // readp).
462 //
463 // return: -1) hole in the data (lost packet)
464 // 0) need more date (only if readp==0)/eof
465 // 1) got a packet
466
467 int process_packet(int readp){
468 Page og=new Page();
469
470 // handle one packet. Try to fetch it from current stream state
471 // extract packets from page
472 while(true){
473 // process a packet if we can. If the machine isn't loaded,
474 // neither is a page
475 if(decode_ready){
476 Packet op=new Packet();
477 int result=os.packetout(op);
478 long granulepos;
479 // if(result==-1)return(-1); // hole in the data. For now, swallow
480 // and go. We'll need to add a real
481 // error code in a bit.
482 if(result>0){
483 // got a packet. process it
484 granulepos=op.granulepos;
485 if(vb.synthesis(op)==0){ // lazy check for lazy
486 // header handling. The
487 // header packets aren't
488 // audio, so if/when we
489 // submit them,
490 // vorbis_synthesis will
491 // reject them
492 // suck in the synthesis data and track bitrate
493 {
494 int oldsamples=vd.synthesis_pcmout(null, null);
495 vd.synthesis_blockin(vb);
496 samptrack+=vd.synthesis_pcmout(null, null)-oldsamples;
497 bittrack+=op.bytes*8;
498 }
499
500 // update the pcm offset.
501 if(granulepos!=-1 && op.e_o_s==0){
502 int link=(seekable?current_link:0);
503 int samples;
504 // this packet has a pcm_offset on it (the last packet
505 // completed on a page carries the offset) After processing
506 // (above), we know the pcm position of the *last* sample
507 // ready to be returned. Find the offset of the *first*
508 //
509 // As an aside, this trick is inaccurate if we begin
510 // reading anew right at the last page; the end-of-stream
511 // granulepos declares the last frame in the stream, and the
512 // last packet of the last page may be a partial frame.
513 // So, we need a previous granulepos from an in-sequence page
514 // to have a reference point. Thus the !op.e_o_s clause above
515
516 samples=vd.synthesis_pcmout(null, null);
517 granulepos-=samples;
518 for(int i=0;i<link;i++){
519 granulepos+=pcmlengths[i];
520 }
521 pcm_offset=granulepos;
522 }
523 return(1);
524 }
525 }
526 }
527
528 if(readp==0)return(0);
529 if(get_next_page(og,-1)<0)return(0); // eof. leave unitialized
530
531 // bitrate tracking; add the header's bytes here, the body bytes
532 // are done by packet above
533 bittrack+=og.header_len*8;
534
535 // has our decoding just traversed a bitstream boundary?
536 if(decode_ready){
537 if(current_serialno!=og.serialno()){
538 decode_clear();
539 }
540 }
541
542 // Do we need to load a new machine before submitting the page?
543 // This is different in the seekable and non-seekable cases.
544 //
545 // In the seekable case, we already have all the header
546 // information loaded and cached; we just initialize the machine
547 // with it and continue on our merry way.
548 //
549 // In the non-seekable (streaming) case, we'll only be at a
550 // boundary if we just left the previous logical bitstream and
551 // we're now nominally at the header of the next bitstream
552
553 if(!decode_ready){
554 int i;
555 if(seekable){
556 current_serialno=og.serialno();
557
558 // match the serialno to bitstream section. We use this rather than
559 // offset positions to avoid problems near logical bitstream
560 // boundaries
561 for(i=0;i<links;i++){
562 if(serialnos[i]==current_serialno)break;
563 }
564 if(i==links)return(-1); // sign of a bogus stream. error out,
565 // leave machine uninitialized
566 current_link=i;
567
568 os.init(current_serialno);
569 os.reset();
570
571 }
572 else{
573 // we're streaming
574 // fetch the three header packets, build the info struct
575 int foo[]=new int[1];
576 int ret=fetch_headers(vi[0], vc[0], foo, og);
577 current_serialno=foo[0];
578 if(ret!=0)return ret;
579 current_link++;
580 i=0;
581 }
582 make_decode_ready();
583 }
584 os.pagein(og);
585 }
586 }
587
588 //The helpers are over; it's all toplevel interface from here on out
589 // clear out the OggVorbis_File struct
590 int clear(){
591 vb.clear();
592 vd.clear();
593 os.clear();
594
595 if(vi!=null && links!=0){
596 for(int i=0;i<links;i++){
597 vi[i].clear();
598 vc[i].clear();
599 }
600 vi=null;
601 vc=null;
602 }
603 if(dataoffsets!=null)dataoffsets=null;
604 if(pcmlengths!=null)pcmlengths=null;
605 if(serialnos!=null)serialnos=null;
606 if(offsets!=null)offsets=null;
607 oy.clear();
608 //if(datasource!=null)(vf->callbacks.close_func)(vf->datasource);
609 //memset(vf,0,sizeof(OggVorbis_File));
610 return(0);
611 }
612
613 static int fseek(InputStream fis,
614 //int64_t off,
615 long off,
616 int whence){
617 if(fis instanceof SeekableInputStream){
618 SeekableInputStream sis=(SeekableInputStream)fis;
619 try{
620 if(whence==SEEK_SET){
621 sis.seek(off);
622 }
623 else if(whence==SEEK_END){
624 sis.seek(sis.getLength()-off);
625 }
626 else{
627 //System.out.println("seek: "+whence+" is not supported");
628 }
629 }
630 catch(Exception e){
631 }
632 return 0;
633 }
634 try{
635 if(whence==0){ fis.reset(); }
636 fis.skip(off);
637 }
638 catch(Exception e){return -1;}
639 return 0;
640 }
641
642 static long ftell(InputStream fis){
643 try{
644 if(fis instanceof SeekableInputStream){
645 SeekableInputStream sis=(SeekableInputStream)fis;
646 return (sis.tell());
647 }
648 }
649 catch(Exception e){
650 }
651 return 0;
652 }
653
654 // inspects the OggVorbis file and finds/documents all the logical
655 // bitstreams contained in it. Tries to be tolerant of logical
656 // bitstream sections that are truncated/woogie.
657 //
658 // return: -1) error
659 // 0) OK
660
661 int open(InputStream is, byte[] initial, int ibytes) throws JOrbisException {
662 //callbacks callbacks = {
663 // (size_t (*)(void *, size_t, size_t, void *)) fread,
664 // (int (*)(void *, int64_t, int)) _fseek,
665 // (int (*)(void *)) fclose,
666 // (long (*)(void *)) ftell
667 // };
668 return open_callbacks(is, initial, ibytes//, callbacks
669 );
670 }
671
672 int open_callbacks(InputStream is, byte[] initial,
673 int ibytes//, callbacks callbacks
674 ) throws JOrbisException {
675 int ret;
676 datasource=is;
677 //callbacks = _callbacks;
678 // init the framing state
679 oy.init();
680
681 // perhaps some data was previously read into a buffer for testing
682 // against other stream types. Allow initialization from this
683 // previously read data (as we may be reading from a non-seekable
684 // stream)
685 if(initial!=null){
686 int index=oy.buffer(ibytes);
687 System.arraycopy(initial, 0, oy.data, index, ibytes);
688 oy.wrote(ibytes);
689 }
690 // can we seek? Stevens suggests the seek test was portable
691 if(is instanceof SeekableInputStream){ ret=open_seekable(); }
692 else{ ret=open_nonseekable(); }
693 if(ret!=0){
694 datasource=null;
695 clear();
696 }
697 return ret;
698 }
699
700 // How many logical bitstreams in this physical bitstream?
701 public int streams(){
702 return links;
703 }
704
705 // Is the FILE * associated with vf seekable?
706 public boolean seekable(){
707 return seekable;
708 }
709
710 // returns the bitrate for a given logical bitstream or the entire
711 // physical bitstream. If the file is open for random access, it will
712 // find the *actual* average bitrate. If the file is streaming, it
713 // returns the nominal bitrate (if set) else the average of the
714 // upper/lower bounds (if set) else -1 (unset).
715 //
716 // If you want the actual bitrate field settings, get them from the
717 // vorbis_info structs
718
719 public int bitrate(int i){
720 if(i>=links)return(-1);
721 if(!seekable && i!=0)return(bitrate(0));
722 if(i<0){
723 long bits=0;
724 for(int j=0;j<links;j++){
725 bits+=(offsets[j+1]-dataoffsets[j])*8;
726 }
727 return((int)Math.rint(bits/time_total(-1)));
728 }
729 else{
730 if(seekable){
731 // return the actual bitrate
732 return((int)Math.rint((offsets[i+1]-dataoffsets[i])*8/time_total(i)));
733 }
734 else{
735 // return nominal if set
736 if(vi[i].bitrate_nominal>0){
737 return vi[i].bitrate_nominal;
738 }
739 else{
740 if(vi[i].bitrate_upper>0){
741 if(vi[i].bitrate_lower>0){
742 return (vi[i].bitrate_upper+vi[i].bitrate_lower)/2;
743 }else{
744 return vi[i].bitrate_upper;
745 }
746 }
747 return(-1);
748 }
749 }
750 }
751 }
752
753 // returns the actual bitrate since last call. returns -1 if no
754 // additional data to offer since last call (or at beginning of stream)
755 public int bitrate_instant(){
756 int _link=(seekable?current_link:0);
757 if(samptrack==0)return(-1);
758 int ret=(int)(bittrack/samptrack*vi[_link].rate+.5);
759 bittrack=0.f;
760 samptrack=0.f;
761 return(ret);
762 }
763
764 public int serialnumber(int i){
765 if(i>=links)return(-1);
766 if(!seekable && i>=0)return(serialnumber(-1));
767 if(i<0){
768 return(current_serialno);
769 }
770 else{
771 return(serialnos[i]);
772 }
773 }
774
775 // returns: total raw (compressed) length of content if i==-1
776 // raw (compressed) length of that logical bitstream for i==0 to n
777 // -1 if the stream is not seekable (we can't know the length)
778
779 public long raw_total(int i){
780 if(!seekable || i>=links)return(-1);
781 if(i<0){
782 long acc=0; // bug?
783 for(int j=0;j<links;j++){
784 acc+=raw_total(j);
785 }
786 return(acc);
787 }
788 else{
789 return(offsets[i+1]-offsets[i]);
790 }
791 }
792
793 // returns: total PCM length (samples) of content if i==-1
794 // PCM length (samples) of that logical bitstream for i==0 to n
795 // -1 if the stream is not seekable (we can't know the length)
796 public long pcm_total(int i){
797 if(!seekable || i>=links)return(-1);
798 if(i<0){
799 long acc=0;
800 for(int j=0;j<links;j++){
801 acc+=pcm_total(j);
802 }
803 return(acc);
804 }
805 else{
806 return(pcmlengths[i]);
807 }
808 }
809
810 // returns: total seconds of content if i==-1
811 // seconds in that logical bitstream for i==0 to n
812 // -1 if the stream is not seekable (we can't know the length)
813 public float time_total(int i){
814 if(!seekable || i>=links)return(-1);
815 if(i<0){
816 float acc=0;
817 for(int j=0;j<links;j++){
818 acc+=time_total(j);
819 }
820 return(acc);
821 }
822 else{
823 return((float)(pcmlengths[i])/vi[i].rate);
824 }
825 }
826
827 // seek to an offset relative to the *compressed* data. This also
828 // immediately sucks in and decodes pages to update the PCM cursor. It
829 // will cross a logical bitstream boundary, but only if it can't get
830 // any packets out of the tail of the bitstream we seek to (so no
831 // surprises).
832 //
833 // returns zero on success, nonzero on failure
834
835 public int raw_seek(int pos){
836 if(!seekable)return(-1); // don't dump machine if we can't seek
837 if(pos<0 || pos>offsets[links]){
838 //goto seek_error;
839 pcm_offset=-1;
840 decode_clear();
841 return -1;
842 }
843
844 // clear out decoding machine state
845 pcm_offset=-1;
846 decode_clear();
847
848 // seek
849 seek_helper(pos);
850
851 // we need to make sure the pcm_offset is set. We use the
852 // _fetch_packet helper to process one packet with readp set, then
853 // call it until it returns '0' with readp not set (the last packet
854 // from a page has the 'granulepos' field set, and that's how the
855 // helper updates the offset
856
857 switch(process_packet(1)){
858 case 0:
859 // oh, eof. There are no packets remaining. Set the pcm offset to
860 // the end of file
861 pcm_offset=pcm_total(-1);
862 return(0);
863 case -1:
864 // error! missing data or invalid bitstream structure
865 //goto seek_error;
866 pcm_offset=-1;
867 decode_clear();
868 return -1;
869 default:
870 // all OK
871 break;
872 }
873 while(true){
874 switch(process_packet(0)){
875 case 0:
876 // the offset is set. If it's a bogus bitstream with no offset
877 // information, it's not but that's not our fault. We still run
878 // gracefully, we're just missing the offset
879 return(0);
880 case -1:
881 // error! missing data or invalid bitstream structure
882 //goto seek_error;
883 pcm_offset=-1;
884 decode_clear();
885 return -1;
886 default:
887 // continue processing packets
888 break;
889 }
890 }
891
892 // seek_error:
893 // dump the machine so we're in a known state
894 //pcm_offset=-1;
895 //decode_clear();
896 //return -1;
897 }
898
899 // seek to a sample offset relative to the decompressed pcm stream
900 // returns zero on success, nonzero on failure
901
902 public int pcm_seek(long pos){
903 int link=-1;
904 long total=pcm_total(-1);
905
906 if(!seekable)return(-1); // don't dump machine if we can't seek
907 if(pos<0 || pos>total){
908 //goto seek_error;
909 pcm_offset=-1;
910 decode_clear();
911 return -1;
912 }
913
914 // which bitstream section does this pcm offset occur in?
915 for(link=links-1;link>=0;link--){
916 total-=pcmlengths[link];
917 if(pos>=total)break;
918 }
919
920 // search within the logical bitstream for the page with the highest
921 // pcm_pos preceeding (or equal to) pos. There is a danger here;
922 // missing pages or incorrect frame number information in the
923 // bitstream could make our task impossible. Account for that (it
924 // would be an error condition)
925 {
926 long target=pos-total;
927 long end=offsets[link+1];
928 long begin=offsets[link];
929 int best=(int)begin;
930
931 Page og=new Page();
932 while(begin<end){
933 long bisect;
934 int ret;
935
936 if(end-begin<CHUNKSIZE){
937 bisect=begin;
938 }
939 else{
940 bisect=(end+begin)/2;
941 }
942
943 seek_helper(bisect);
944 ret=get_next_page(og,end-bisect);
945
946 if(ret==-1){
947 end=bisect;
948 }
949 else{
950 long granulepos=og.granulepos();
951 if(granulepos<target){
952 best=ret; // raw offset of packet with granulepos
953 begin=offset; // raw offset of next packet
954 }
955 else{
956 end=bisect;
957 }
958 }
959 }
960 // found our page. seek to it (call raw_seek).
961 if(raw_seek(best)!=0){
962 //goto seek_error;
963 pcm_offset=-1;
964 decode_clear();
965 return -1;
966 }
967 }
968
969 // verify result
970 if(pcm_offset>=pos){
971 //goto seek_error;
972 pcm_offset=-1;
973 decode_clear();
974 return -1;
975 }
976 if(pos>pcm_total(-1)){
977 //goto seek_error;
978 pcm_offset=-1;
979 decode_clear();
980 return -1;
981 }
982
983 // discard samples until we reach the desired position. Crossing a
984 // logical bitstream boundary with abandon is OK.
985 while(pcm_offset<pos){
986 float[][] pcm;
987 int target=(int)(pos-pcm_offset);
988 float[][][] _pcm=new float[1][][];
989 int[] _index=new int[getInfo(-1).channels];
990 int samples=vd.synthesis_pcmout(_pcm, _index);
991 pcm=_pcm[0];
992
993 if(samples>target)samples=target;
994 vd.synthesis_read(samples);
995 pcm_offset+=samples;
996
997 if(samples<target)
998 if(process_packet(1)==0){
999 pcm_offset=pcm_total(-1); // eof
1000 }
1001 }
1002 return 0;
1003
1004 // seek_error:
1005 // dump machine so we're in a known state
1006 //pcm_offset=-1;
1007 //decode_clear();
1008 //return -1;
1009 }
1010
1011 // seek to a playback time relative to the decompressed pcm stream
1012 // returns zero on success, nonzero on failure
1013 int time_seek(float seconds){
1014 // translate time to PCM position and call pcm_seek
1015
1016 int link=-1;
1017 long pcm_total=pcm_total(-1);
1018 float time_total=time_total(-1);
1019
1020 if(!seekable)return(-1); // don't dump machine if we can't seek
1021 if(seconds<0 || seconds>time_total){
1022 //goto seek_error;
1023 pcm_offset=-1;
1024 decode_clear();
1025 return -1;
1026 }
1027
1028 // which bitstream section does this time offset occur in?
1029 for(link=links-1;link>=0;link--){
1030 pcm_total-=pcmlengths[link];
1031 time_total-=time_total(link);
1032 if(seconds>=time_total)break;
1033 }
1034
1035 // enough information to convert time offset to pcm offset
1036 {
1037 long target=(long)(pcm_total+(seconds-time_total)*vi[link].rate);
1038 return(pcm_seek(target));
1039 }
1040
1041 //seek_error:
1042 // dump machine so we're in a known state
1043 //pcm_offset=-1;
1044 //decode_clear();
1045 //return -1;
1046 }
1047
1048 // tell the current stream offset cursor. Note that seek followed by
1049 // tell will likely not give the set offset due to caching
1050 public long raw_tell(){
1051 return(offset);
1052 }
1053
1054 // return PCM offset (sample) of next PCM sample to be read
1055 public long pcm_tell(){
1056 return(pcm_offset);
1057 }
1058
1059 // return time offset (seconds) of next PCM sample to be read
1060 public float time_tell(){
1061 // translate time to PCM position and call pcm_seek
1062
1063 int link=-1;
1064 long pcm_total=0;
1065 float time_total=0.f;
1066
1067 if(seekable){
1068 pcm_total=pcm_total(-1);
1069 time_total=time_total(-1);
1070
1071 // which bitstream section does this time offset occur in?
1072 for(link=links-1;link>=0;link--){
1073 pcm_total-=pcmlengths[link];
1074 time_total-=time_total(link);
1075 if(pcm_offset>=pcm_total)break;
1076 }
1077 }
1078
1079 return((float)time_total+(float)(pcm_offset-pcm_total)/vi[link].rate);
1080 }
1081
1082 // link: -1) return the vorbis_info struct for the bitstream section
1083 // currently being decoded
1084 // 0-n) to request information for a specific bitstream section
1085 //
1086 // In the case of a non-seekable bitstream, any call returns the
1087 // current bitstream. NULL in the case that the machine is not
1088 // initialized
1089
1090 public Info getInfo(int link){
1091 if(seekable){
1092 if(link<0){
1093 if(decode_ready){
1094 return vi[current_link];
1095 }
1096 else{
1097 return null;
1098 }
1099 }
1100 else{
1101 if(link>=links){
1102 return null;
1103 }
1104 else{
1105 return vi[link];
1106 }
1107 }
1108 }
1109 else{
1110 if(decode_ready){
1111 return vi[0];
1112 }
1113 else{
1114 return null;
1115 }
1116 }
1117 }
1118
1119 public Comment getComment(int link){
1120 if(seekable){
1121 if(link<0){
1122 if(decode_ready){ return vc[current_link]; }
1123 else{ return null; }
1124 }
1125 else{
1126 if(link>=links){ return null;}
1127 else{ return vc[link]; }
1128 }
1129 }
1130 else{
1131 if(decode_ready){ return vc[0]; }
1132 else{ return null; }
1133 }
1134 }
1135
1136 int host_is_big_endian() {
1137 return 1;
1138// short pattern = 0xbabe;
1139// unsigned char *bytewise = (unsigned char *)&pattern;
1140// if (bytewise[0] == 0xba) return 1;
1141// assert(bytewise[0] == 0xbe);
1142// return 0;
1143 }
1144
1145 // up to this point, everything could more or less hide the multiple
1146 // logical bitstream nature of chaining from the toplevel application
1147 // if the toplevel application didn't particularly care. However, at
1148 // the point that we actually read audio back, the multiple-section
1149 // nature must surface: Multiple bitstream sections do not necessarily
1150 // have to have the same number of channels or sampling rate.
1151 //
1152 // read returns the sequential logical bitstream number currently
1153 // being decoded along with the PCM data in order that the toplevel
1154 // application can take action on channel/sample rate changes. This
1155 // number will be incremented even for streamed (non-seekable) streams
1156 // (for seekable streams, it represents the actual logical bitstream
1157 // index within the physical bitstream. Note that the accessor
1158 // functions above are aware of this dichotomy).
1159 //
1160 // input values: buffer) a buffer to hold packed PCM data for return
1161 // length) the byte length requested to be placed into buffer
1162 // bigendianp) should the data be packed LSB first (0) or
1163 // MSB first (1)
1164 // word) word size for output. currently 1 (byte) or
1165 // 2 (16 bit short)
1166 //
1167 // return values: -1) error/hole in data
1168 // 0) EOF
1169 // n) number of bytes of PCM actually returned. The
1170 // below works on a packet-by-packet basis, so the
1171 // return length is not related to the 'length' passed
1172 // in, just guaranteed to fit.
1173 //
1174 // *section) set to the logical bitstream number
1175
1176 int read(byte[] buffer,int length,
1177 int bigendianp, int word, int sgned, int[] bitstream){
1178 int host_endian = host_is_big_endian();
1179 int index=0;
1180
1181 while(true){
1182 if(decode_ready){
1183 float[][] pcm;
1184 float[][][] _pcm=new float[1][][];
1185 int[] _index=new int[getInfo(-1).channels];
1186 int samples=vd.synthesis_pcmout(_pcm, _index);
1187 pcm=_pcm[0];
1188 if(samples!=0){
1189 // yay! proceed to pack data into the byte buffer
1190 int channels=getInfo(-1).channels;
1191 int bytespersample=word * channels;
1192 if(samples>length/bytespersample)samples=length/bytespersample;
1193
1194 // a tight loop to pack each size
1195 {
1196 int val;
1197 if(word==1){
1198 int off=(sgned!=0?0:128);
1199 for(int j=0;j<samples;j++){
1200 for(int i=0;i<channels;i++){
1201 val=(int)(pcm[i][_index[i]+j]*128. + 0.5);
1202 if(val>127)val=127;
1203 else if(val<-128)val=-128;
1204 buffer[index++]=(byte)(val+off);
1205 }
1206 }
1207 }
1208 else{
1209 int off=(sgned!=0?0:32768);
1210
1211 if(host_endian==bigendianp){
1212 if(sgned!=0){
1213 for(int i=0;i<channels;i++) { // It's faster in this order
1214 int src=_index[i];
1215 int dest=i;
1216 for(int j=0;j<samples;j++) {
1217 val=(int)(pcm[i][src+j]*32768. + 0.5);
1218 if(val>32767)val=32767;
1219 else if(val<-32768)val=-32768;
1220 buffer[dest]=(byte)(val>>>8);
1221 buffer[dest+1]=(byte)(val);
1222 dest+=channels*2;
1223 }
1224 }
1225 }
1226 else{
1227 for(int i=0;i<channels;i++) {
1228 float[] src=pcm[i];
1229 int dest=i;
1230 for(int j=0;j<samples;j++) {
1231 val=(int)(src[j]*32768. + 0.5);
1232 if(val>32767)val=32767;
1233 else if(val<-32768)val=-32768;
1234 buffer[dest]=(byte)((val+off)>>>8);
1235 buffer[dest+1]=(byte)(val+off);
1236 dest+=channels*2;
1237 }
1238 }
1239 }
1240 }
1241 else if(bigendianp!=0){
1242 for(int j=0;j<samples;j++){
1243 for(int i=0;i<channels;i++){
1244 val=(int)(pcm[i][j]*32768. + 0.5);
1245 if(val>32767)val=32767;
1246 else if(val<-32768)val=-32768;
1247 val+=off;
1248 buffer[index++]=(byte)(val>>>8);
1249 buffer[index++]=(byte)val;
1250 }
1251 }
1252 }
1253 else{
1254 //int val;
1255 for(int j=0;j<samples;j++){
1256 for(int i=0;i<channels;i++){
1257 val=(int)(pcm[i][j]*32768. + 0.5);
1258 if(val>32767)val=32767;
1259 else if(val<-32768)val=-32768;
1260 val+=off;
1261 buffer[index++]=(byte)val;
1262 buffer[index++]=(byte)(val>>>8);
1263 }
1264 }
1265 }
1266 }
1267 }
1268
1269 vd.synthesis_read(samples);
1270 pcm_offset+=samples;
1271 if(bitstream!=null)bitstream[0]=current_link;
1272 return(samples*bytespersample);
1273 }
1274 }
1275
1276 // suck in another packet
1277 switch(process_packet(1)){
1278 case 0:
1279 return(0);
1280 case -1:
1281 return -1;
1282 default:
1283 break;
1284 }
1285 }
1286 }
1287
1288 public Info[] getInfo(){return vi;}
1289 public Comment[] getComment(){return vc;}
1290
1291/*
1292 public static void main(String[] arg){
1293 try{
1294 VorbisFile foo=new VorbisFile(arg[0]);
1295 int links=foo.streams();
1296 System.out.println("links="+links);
1297 Comment[] comment=foo.getComment();
1298 Info[] info=foo.getInfo();
1299 for(int i=0; i<links; i++){
1300 System.out.println(info[i]);
1301 System.out.println(comment[i]);
1302 }
1303 System.out.println("raw_total: "+foo.raw_total(-1));
1304 System.out.println("pcm_total: "+foo.pcm_total(-1));
1305 System.out.println("time_total: "+foo.time_total(-1));
1306 }
1307 catch(Exception e){
1308 System.err.println(e);
1309 }
1310 }
1311*/
1312
1313 public void close() throws java.io.IOException {
1314 datasource.close();
1315 }
1316
1317 class SeekableInputStream extends InputStream {
1318 java.io.RandomAccessFile raf=null;
1319 final String mode="r";
1320 private SeekableInputStream(){
1321 }
1322 SeekableInputStream(String file) throws java.io.IOException{
1323 raf=new java.io.RandomAccessFile(file, mode);
1324 }
1325 public int read() throws java.io.IOException{
1326 return raf.read();
1327 }
1328 public int read(byte[] buf) throws java.io.IOException{
1329 return raf.read(buf);
1330 }
1331 public int read(byte[] buf , int s, int len) throws java.io.IOException{
1332 return raf.read(buf, s, len);
1333 }
1334 public long skip(long n) throws java.io.IOException{
1335 return (long)(raf.skipBytes((int)n));
1336 }
1337 public long getLength() throws java.io.IOException{
1338 return raf.length();
1339 }
1340 public long tell() throws java.io.IOException{
1341 return raf.getFilePointer();
1342 }
1343 public int available() throws java.io.IOException{
1344 return (raf.length()==raf.getFilePointer())? 0 : 1;
1345 }
1346 public void close() throws java.io.IOException{
1347 raf.close();
1348 }
1349 public synchronized void mark(int m){
1350 }
1351 public synchronized void reset() throws java.io.IOException{
1352 }
1353 public boolean markSupported(){
1354 return false;
1355 }
1356 public void seek(long pos) throws java.io.IOException{
1357 raf.seek(pos);
1358 }
1359 }
1360
1361}
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 @@
1/* JOrbis
2 * Copyright (C) 2000 ymnk, JCraft,Inc.
3 *
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
5 *
6 * Many thanks to
7 * Monty <monty@xiph.org> and
8 * The XIPHOPHORUS Company http://www.xiph.org/ .
9 * JOrbis has been based on their awesome works, Vorbis codec.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29import java.io.InputStream;
30
31public class VorbisFile{
32 static final int CHUNKSIZE=4096;
33 static final int SEEK_SET=0;
34
35 InputStream datasource;
36 boolean seekable=false;
37 long offset;
38 long end;
39
40 SyncState oy=new SyncState();
41
42 int links;
43 Comment[] vc;
44 Info[] vi;
45
46 long[] offsets;
47 long[] dataoffsets;
48 int[] serialnos;
49 long[] pcmlengths;
50
51
52
53 // Decoding working state local storage
54 long pcm_offset;
55 boolean decode_ready=false;
56 int current_serialno;
57 int current_link;
58
59 float bittrack;
60 float samptrack;
61
62 StreamState os=new StreamState(); // take physical pages, weld into a logical
63 // stream of packets
64 DspState vd=new DspState(); // central working state for
65 // the packet->PCM decoder
66 Block vb=new Block(vd); // local working space for packet->PCM decode
67
68 //ov_callbacks callbacks;
69
70 public VorbisFile(String file) throws JOrbisException {
71 super();
72 InputStream is=null;
73 try{ is=new java.io.BufferedInputStream(new java.io.FileInputStream(file));}
74 catch(Exception e){
75 throw new JOrbisException("VorbisFile: "+e.toString());
76 }
77 int ret=open(is, null, 0);
78 if(ret==-1){
79 throw new JOrbisException("VorbisFile: open return -1");
80 }
81 }
82
83 public VorbisFile(InputStream is, byte[] initial, int ibytes)
84 throws JOrbisException {
85 super();
86 int ret=open(is, initial, ibytes);
87 if(ret==-1){
88 }
89 }
90
91 private int get_data(){
92 int index=oy.buffer(CHUNKSIZE);
93 byte[] buffer=oy.data;
94// int bytes=callbacks.read_func(buffer, index, 1, CHUNKSIZE, datasource);
95 int bytes=0;
96 try{
97 bytes=datasource.read(buffer, index, CHUNKSIZE);
98 }
99 catch(Exception e){System.err.println(e);}
100 oy.wrote(bytes);
101 return bytes;
102 }
103
104 private void seek_helper(int offst){
105 //callbacks.seek_func(datasource, offst, SEEK_SET);
106 fseek64_wrap(datasource, offst, SEEK_SET);
107 this.offset=offst;
108 oy.reset();
109 }
110
111 private int get_next_page(Page page, int boundary){
112 if(boundary>0) boundary+=offset;
113 while(true){
114 int more;
115 if(boundary>0 && offset>=boundary)return -1;
116 more=oy.pageseek(page);
117 if(more<0){offset-=more;}
118 else{
119 if(more==0){
120 if(boundary==0)return -1;
121 if(get_data()<=0)return -1;
122 }
123 else{
124 int ret=(int)offset; //!!!
125 offset+=more;
126 return ret;
127 }
128 }
129 }
130 }
131
132 private int get_prev_page(Page page){
133 int begin=(int)offset; //!!!
134 int ret;
135 int offst=-1;
136 while(offst==-1){
137 begin-=CHUNKSIZE;
138 seek_helper(begin);
139 while(offset<begin+CHUNKSIZE){
140 ret=get_next_page(page, begin+CHUNKSIZE-((int)offset));
141 if(ret==-1){ break; }
142 else{ offst=ret; }
143 }
144 }
145 seek_helper((int)offset); //!!!
146 ret=get_next_page(page, CHUNKSIZE);
147 if(ret==-1){
148 System.err.println("Missed page fencepost at end of logical bitstream Exiting");
149 System.exit(1);
150 }
151 return offst;
152 }
153
154 void bisect_forward_serialno(int begin, int searched, int end, int currentno, int m){
155 int endsearched=end;
156 int next=end;
157 Page page=new Page();
158 int ret;
159 while(searched<endsearched){
160 int bisect;
161 if(endsearched-searched<CHUNKSIZE){
162 bisect=searched;
163 }
164 else{
165 bisect=(searched+endsearched)/2;
166 }
167
168 seek_helper(bisect);
169 ret=get_next_page(page, -1);
170 if(ret<0 || page.serialno()!=currentno){
171 endsearched=bisect;
172 if(ret>=0)next=ret;
173 }
174 else{
175 searched=ret+page.header_len+page.body_len;
176 }
177 }
178 seek_helper(next);
179 ret=get_next_page(page, -1);
180
181 if(searched>=end || ret==-1){
182 links=m+1;
183 offsets=new long[m+2];
184 offsets[m+1]=searched;
185 }
186 else{
187 bisect_forward_serialno(next, (int)offset, end, page.serialno(), m+1);
188 }
189 offsets[m]=begin;
190 }
191
192 // uses the local ogg_stream storage in vf; this is important for
193 // non-streaming input sources
194 int fetch_headers(Info vi, Comment vc, int[] serialno){
195 //System.err.println("fetch_headers");
196 Page og=new Page();
197 Packet op=new Packet();
198 int ret;
199
200 ret=get_next_page(og, CHUNKSIZE);
201 if(ret==-1){
202 System.err.println("Did not find initial header for bitstream.");
203 return -1;
204 }
205
206 if(serialno!=null)serialno[0]=og.serialno();
207
208 os.init(og.serialno());
209
210 // extract the initial header from the first page and verify that the
211 // Ogg bitstream is in fact Vorbis data
212
213 vi.init();
214 vc.init();
215
216 int i=0;
217 while(i<3){
218 os.pagein(og);
219 while(i<3){
220 int result=os.packetout(op);
221 if(result==0)break;
222 if(result==-1){
223 System.err.println("Corrupt header in logical bitstream.");
224 //goto bail_header;
225 vi.clear();
226 vc.clear();
227 os.clear();
228 return -1;
229 }
230 if(vi.synthesis_headerin(vc, op)!=0){
231 System.err.println("Illegal header in logical bitstream.");
232 //goto bail_header;
233 vi.clear();
234 vc.clear();
235 os.clear();
236 return -1;
237 }
238 i++;
239 }
240 if(i<3)
241 if(get_next_page(og, 1)<0){
242 System.err.println("Missing header in logical bitstream.");
243 //goto bail_header;
244 vi.clear();
245 vc.clear();
246 os.clear();
247 return -1;
248 }
249 }
250 return 0;
251
252// bail_header:
253// vorbis_info_clear(vi);
254// vorbis_comment_clear(vc);
255// ogg_stream_clear(&vf->os);
256// return -1;
257 }
258
259 // last step of the OggVorbis_File initialization; get all the
260 // vorbis_info structs and PCM positions. Only called by the seekable
261 // initialization (local stream storage is hacked slightly; pay
262 // attention to how that's done)
263 void prefetch_all_headers(Info first_i,Comment first_c, int dataoffset){
264 Page og=new Page();
265 int ret;
266
267 vi=new Info[links];
268 vc=new Comment[links];
269 dataoffsets=new long[links];
270 pcmlengths=new long[links];
271 serialnos=new int[links];
272
273 for(int i=0;i<links;i++){
274 if(first_i!=null && first_c!=null && i==0){
275 // we already grabbed the initial header earlier. This just
276 // saves the waste of grabbing it again
277 // !!!!!!!!!!!!!
278 vi[i]=first_i;
279 //memcpy(vf->vi+i,first_i,sizeof(vorbis_info));
280 vc[i]=first_c;
281 //memcpy(vf->vc+i,first_c,sizeof(vorbis_comment));
282 dataoffsets[i]=dataoffset;
283 }
284 else{
285 // seek to the location of the initial header
286 seek_helper((int)offsets[i]); //!!!
287 if(fetch_headers(vi[i], vc[i], null)==-1){
288 System.err.println("Error opening logical bitstream #"+(i+1)+"\n");
289 dataoffsets[i]=-1;
290 }
291 else{
292 dataoffsets[i]=offset;
293 os.clear();
294 }
295 }
296
297 // get the serial number and PCM length of this link. To do this,
298 // get the last page of the stream
299 {
300 int end=(int)offsets[i+1]; //!!!
301 seek_helper(end);
302
303 while(true){
304 ret=get_prev_page(og);
305 if(ret==-1){
306 // this should not be possible
307 System.err.println("Could not find last page of logical "+
308 "bitstream #"+(i)+"\n");
309 vi[i].clear();
310 vc[i].clear();
311 break;
312 }
313 if(og.granulepos()!=-1){
314 serialnos[i]=og.serialno();
315 pcmlengths[i]=og.granulepos();
316 break;
317 }
318 }
319 }
320 }
321 }
322
323 int make_decode_ready(){
324 if(decode_ready)System.exit(1);
325 vd.synthesis_init(vi[0]);
326 vb.init(vd);
327 decode_ready=true;
328 return(0);
329 }
330
331 int open_seekable(){
332 Info initial_i=new Info();
333 Comment initial_c=new Comment();
334 int serialno,end;
335 int ret;
336 int dataoffset;
337 Page og=new Page();
338System.out.println("open_seekable");
339 // is this even vorbis...?
340 int[] foo=new int[1];
341 ret=fetch_headers(initial_i, initial_c, foo);
342 serialno=foo[0];
343 dataoffset=(int)offset; //!!
344 os.clear();
345 if(ret==-1)return(-1);
346
347 // we can seek, so set out learning all about this file
348 seekable=true;
349 //(callbacks.seek_func)(datasource, 0, SEEK_END);
350 fseek64_wrap(datasource, (int)offset, SEEK_SET);
351 //offset=end=(callbacks.tell_func)(datasource);
352 end=(int)offset;
353
354 // We get the offset for the last page of the physical bitstream.
355 // Most OggVorbis files will contain a single logical bitstream
356 end=get_prev_page(og);
357
358 // moer than one logical bitstream?
359 if(og.serialno()!=serialno){
360 // Chained bitstream. Bisect-search each logical bitstream
361 // section. Do so based on serial number only
362 bisect_forward_serialno(0,0,end+1,serialno,0);
363 }
364 else{
365 // Only one logical bitstream
366 bisect_forward_serialno(0,end,end+1,serialno,0);
367 }
368 prefetch_all_headers(initial_i, initial_c, dataoffset);
369
370System.out.println("?");
371 return(raw_seek(0));
372 }
373
374 int open_nonseekable(){
375 //System.err.println("open_nonseekable");
376 // we cannot seek. Set up a 'single' (current) logical bitstream entry
377 links=1;
378 vi=new Info[links]; vi[0]=new Info(); // ??
379 vc=new Comment[links]; vc[0]=new Comment(); // ?? bug?
380
381 // Try to fetch the headers, maintaining all the storage
382 int[]foo=new int[1];
383 if(fetch_headers(vi[0], vc[0], foo)==-1)return(-1);
384 current_serialno=foo[0];
385 make_decode_ready();
386 return 0;
387 }
388
389 // clear out the current logical bitstream decoder
390 void decode_clear(){
391 os.clear();
392 vd.clear();
393 vb.clear();
394 decode_ready=false;
395 bittrack=0.f;
396 samptrack=0.f;
397 }
398
399 // fetch and process a packet. Handles the case where we're at a
400 // bitstream boundary and dumps the decoding machine. If the decoding
401 // machine is unloaded, it loads it. It also keeps pcm_offset up to
402 // date (seek and read both use this. seek uses a special hack with
403 // readp).
404 //
405 // return: -1) hole in the data (lost packet)
406 // 0) need more date (only if readp==0)/eof
407 // 1) got a packet
408
409 int process_packet(int readp){
410System.out.println("porcess_packet:"+ readp+" , decode_ready="+decode_ready);
411 Page og=new Page();
412
413 // handle one packet. Try to fetch it from current stream state
414 // extract packets from page
415 while(true){
416 // process a packet if we can. If the machine isn't loaded,
417 // neither is a page
418 if(decode_ready){
419 Packet op=new Packet();
420 int result=os.packetout(op);
421 long granulepos;
422 // if(result==-1)return(-1); // hole in the data. For now, swallow
423 // and go. We'll need to add a real
424 // error code in a bit.
425 if(result>0){
426 // got a packet. process it
427 granulepos=op.granulepos;
428 if(vb.synthesis(op)==0){ // lazy check for lazy
429 // header handling. The
430 // header packets aren't
431 // audio, so if/when we
432 // submit them,
433 // vorbis_synthesis will
434 // reject them
435 // suck in the synthesis data and track bitrate
436 {
437 int oldsamples=vd.synthesis_pcmout(null, null);
438 vd.synthesis_blockin(vb);
439 samptrack+=vd.synthesis_pcmout(null, null)-oldsamples;
440 bittrack+=op.bytes*8;
441 }
442
443 // update the pcm offset.
444 if(granulepos!=-1 && op.e_o_s==0){
445 int link=(seekable?current_link:0);
446 int samples;
447 // this packet has a pcm_offset on it (the last packet
448 // completed on a page carries the offset) After processing
449 // (above), we know the pcm position of the *last* sample
450 // ready to be returned. Find the offset of the *first*
451 //
452 // As an aside, this trick is inaccurate if we begin
453 // reading anew right at the last page; the end-of-stream
454 // granulepos declares the last frame in the stream, and the
455 // last packet of the last page may be a partial frame.
456 // So, we need a previous granulepos from an in-sequence page
457 // to have a reference point. Thus the !op.e_o_s clause above
458
459 samples=vd.synthesis_pcmout(null, null);
460 granulepos-=samples;
461 for(int i=0;i<link;i++){
462 granulepos+=pcmlengths[i];
463 }
464 pcm_offset=granulepos;
465 }
466 return(1);
467 }
468 }
469 }
470
471 if(readp==0)return(0);
472 if(get_next_page(og,-1)<0)return(0); // eof. leave unitialized
473
474 // bitrate tracking; add the header's bytes here, the body bytes
475 // are done by packet above
476 bittrack+=og.header_len*8;
477
478 // has our decoding just traversed a bitstream boundary?
479 if(decode_ready){
480 if(current_serialno!=og.serialno()){
481 decode_clear();
482 }
483 }
484
485 // Do we need to load a new machine before submitting the page?
486 // This is different in the seekable and non-seekable cases.
487 //
488 // In the seekable case, we already have all the header
489 // information loaded and cached; we just initialize the machine
490 // with it and continue on our merry way.
491 //
492 // In the non-seekable (streaming) case, we'll only be at a
493 // boundary if we just left the previous logical bitstream and
494 // we're now nominally at the header of the next bitstream
495
496 if(!decode_ready){
497 int i;
498 if(seekable){
499 current_serialno=og.serialno();
500
501 // match the serialno to bitstream section. We use this rather than
502 // offset positions to avoid problems near logical bitstream
503 // boundaries
504 for(i=0;i<links;i++){
505 if(serialnos[i]==current_serialno)break;
506 }
507 if(i==links)return(-1); // sign of a bogus stream. error out,
508 // leave machine uninitialized
509 current_link=i;
510
511 os.init(current_serialno);
512 os.reset();
513
514 }
515 else{
516 // we're streaming
517 // fetch the three header packets, build the info struct
518 int foo[]=new int[1];
519 fetch_headers(vi[0], vc[0], foo);
520 current_serialno=foo[0];
521 current_link++;
522 i=0;
523 }
524 make_decode_ready();
525 }
526 os.pagein(og);
527 }
528 }
529
530 //The helpers are over; it's all toplevel interface from here on out
531 // clear out the OggVorbis_File struct
532 int clear(){
533 vb.clear();
534 vd.clear();
535 os.clear();
536
537 if(vi!=null && links!=0){
538 for(int i=0;i<links;i++){
539 vi[i].clear();
540 vc[i].clear();
541 }
542 vi=null;
543 vc=null;
544 }
545 if(dataoffsets!=null)dataoffsets=null;
546 if(pcmlengths!=null)pcmlengths=null;
547 if(serialnos!=null)serialnos=null;
548 if(offsets!=null)offsets=null;
549 oy.clear();
550 //if(datasource!=null)(vf->callbacks.close_func)(vf->datasource);
551 //memset(vf,0,sizeof(OggVorbis_File));
552 return(0);
553 }
554
555 static int fseek64_wrap(InputStream fis,
556 //int64_t off,
557 int off,
558 int whence){
559
560 if(!fis.markSupported()){ return -1; }
561 try{
562 try{if(whence==0){ fis.reset(); }}
563 catch(Exception ee){System.out.println(ee);}
564 fis.skip(off);
565 }
566 catch(Exception e){ System.out.println(e);
567 //return -1;
568 }
569 return 0;
570 }
571
572 // inspects the OggVorbis file and finds/documents all the logical
573 // bitstreams contained in it. Tries to be tolerant of logical
574 // bitstream sections that are truncated/woogie.
575 //
576 // return: -1) error
577 // 0) OK
578
579 int open(InputStream is, byte[] initial, int ibytes){
580 return open_callbacks(is, initial, ibytes//, callbacks
581 );
582 }
583
584 int open_callbacks(InputStream is, byte[] initial,
585 int ibytes//, callbacks callbacks
586 ){
587// int offset=callbacks.seek_func(f,0,SEEK_CUR);
588 int _offset=fseek64_wrap(is, (int)offset, SEEK_SET);
589 int ret;
590 // memset(vf,0,sizeof(OggVorbis_File));
591 datasource=is;
592 //callbacks = _callbacks;
593
594 // init the framing state
595 oy.init();
596
597 // perhaps some data was previously read into a buffer for testing
598 // against other stream types. Allow initialization from this
599 // previously read data (as we may be reading from a non-seekable
600 // stream)
601 if(initial!=null){
602 int index=oy.buffer(ibytes);
603 System.arraycopy(initial, 0, oy.data, index, ibytes);
604 oy.wrote(ibytes);
605 }
606
607System.out.println("open_callbacks="+_offset);
608 // can we seek? Stevens suggests the seek test was portable
609 if(_offset!=-1){ ret=open_seekable(); }
610 else{ ret=open_nonseekable(); }
611
612System.out.println("ret="+ret);
613
614 if(ret!=0){
615 datasource=null;
616 clear();
617 }
618
619 return(ret);
620 }
621
622 // How many logical bitstreams in this physical bitstream?
623 public int streams(){
624 return links;
625 }
626
627 // Is the FILE * associated with vf seekable?
628 public boolean seekable(){
629 return seekable;
630 }
631
632 // returns the bitrate for a given logical bitstream or the entire
633 // physical bitstream. If the file is open for random access, it will
634 // find the *actual* average bitrate. If the file is streaming, it
635 // returns the nominal bitrate (if set) else the average of the
636 // upper/lower bounds (if set) else -1 (unset).
637 //
638 // If you want the actual bitrate field settings, get them from the
639 // vorbis_info structs
640
641 public int bitrate(int i){
642 if(i>=links)return(-1);
643 if(!seekable && i!=0)return(bitrate(0));
644 if(i<0){
645 long bits=0;
646 for(int j=0;j<links;j++){
647 bits+=(offsets[j+1]-dataoffsets[j])*8;
648 }
649 return((int)Math.rint(bits/time_total(-1)));
650 }
651 else{
652 if(seekable){
653 // return the actual bitrate
654 return((int)Math.rint((offsets[i+1]-dataoffsets[i])*8/time_total(i)));
655 }
656 else{
657 // return nominal if set
658 if(vi[i].bitrate_nominal>0){
659 return vi[i].bitrate_nominal;
660 }
661 else{
662 if(vi[i].bitrate_upper>0){
663 if(vi[i].bitrate_lower>0){
664 return (vi[i].bitrate_upper+vi[i].bitrate_lower)/2;
665 }else{
666 return vi[i].bitrate_upper;
667 }
668 }
669 return(-1);
670 }
671 }
672 }
673 }
674
675 // returns the actual bitrate since last call. returns -1 if no
676 // additional data to offer since last call (or at beginning of stream)
677 public int bitrate_instant(){
678 int _link=(seekable?current_link:0);
679 if(samptrack==0)return(-1);
680 int ret=(int)(bittrack/samptrack*vi[_link].rate+.5);
681 bittrack=0.f;
682 samptrack=0.f;
683 return(ret);
684 }
685
686 public int serialnumber(int i){
687 if(i>=links)return(-1);
688 if(!seekable && i>=0)return(serialnumber(-1));
689 if(i<0){
690 return(current_serialno);
691 }
692 else{
693 return(serialnos[i]);
694 }
695 }
696
697 // returns: total raw (compressed) length of content if i==-1
698 // raw (compressed) length of that logical bitstream for i==0 to n
699 // -1 if the stream is not seekable (we can't know the length)
700
701 public long raw_total(int i){
702System.out.println("raw_total: "+seekable);
703 if(!seekable || i>=links)return(-1);
704 if(i<0){
705 long acc=0; // bug?
706 for(int j=0;j<links;j++){
707 acc+=raw_total(j);
708 }
709 return(acc);
710 }
711 else{
712 return(offsets[i+1]-offsets[i]);
713 }
714 }
715
716 // returns: total PCM length (samples) of content if i==-1
717 // PCM length (samples) of that logical bitstream for i==0 to n
718 // -1 if the stream is not seekable (we can't know the length)
719 public long pcm_total(int i){
720 if(!seekable || i>=links)return(-1);
721 if(i<0){
722 long acc=0;
723 for(int j=0;j<links;j++){
724 acc+=pcm_total(j);
725 }
726 return(acc);
727 }
728 else{
729 return(pcmlengths[i]);
730 }
731 }
732
733 // returns: total seconds of content if i==-1
734 // seconds in that logical bitstream for i==0 to n
735 // -1 if the stream is not seekable (we can't know the length)
736 public float time_total(int i){
737 if(!seekable || i>=links)return(-1);
738 if(i<0){
739 float acc=0;
740 for(int j=0;j<links;j++){
741 acc+=time_total(j);
742 }
743 return(acc);
744 }
745 else{
746 return((float)(pcmlengths[i])/vi[i].rate);
747 }
748 }
749
750 // seek to an offset relative to the *compressed* data. This also
751 // immediately sucks in and decodes pages to update the PCM cursor. It
752 // will cross a logical bitstream boundary, but only if it can't get
753 // any packets out of the tail of the bitstream we seek to (so no
754 // surprises).
755 //
756 // returns zero on success, nonzero on failure
757
758 public int raw_seek(int pos){
759System.out.println("raw_seek: "+pos);
760 if(!seekable)return(-1); // don't dump machine if we can't seek
761 if(pos<0 || pos>offsets[links]){
762 //goto seek_error;
763 pcm_offset=-1;
764 decode_clear();
765 return -1;
766 }
767System.out.println("#1");
768 // clear out decoding machine state
769 pcm_offset=-1;
770System.out.println("#2");
771 decode_clear();
772System.out.println("#3");
773 // seek
774 seek_helper(pos);
775
776 // we need to make sure the pcm_offset is set. We use the
777 // _fetch_packet helper to process one packet with readp set, then
778 // call it until it returns '0' with readp not set (the last packet
779 // from a page has the 'granulepos' field set, and that's how the
780 // helper updates the offset
781System.out.println("#4");
782 switch(process_packet(1)){
783 case 0:
784System.out.println("?0");
785 // oh, eof. There are no packets remaining. Set the pcm offset to
786 // the end of file
787 pcm_offset=pcm_total(-1);
788 return(0);
789 case -1:
790System.out.println("?-1");
791 // error! missing data or invalid bitstream structure
792 //goto seek_error;
793 pcm_offset=-1;
794 decode_clear();
795 return -1;
796 default:
797System.out.println("?break");
798 // all OK
799 break;
800 }
801System.out.println("pcm_offset="+pcm_offset);
802 while(true){
803 switch(process_packet(0)){
804 case 0:
805 // the offset is set. If it's a bogus bitstream with no offset
806 // information, it's not but that's not our fault. We still run
807 // gracefully, we're just missing the offset
808 return(0);
809 case -1:
810 // error! missing data or invalid bitstream structure
811 //goto seek_error;
812 pcm_offset=-1;
813 decode_clear();
814 return -1;
815 default:
816 // continue processing packets
817 break;
818 }
819 }
820
821 // seek_error:
822 // dump the machine so we're in a known state
823 //pcm_offset=-1;
824 //decode_clear();
825 //return -1;
826 }
827
828 // seek to a sample offset relative to the decompressed pcm stream
829 // returns zero on success, nonzero on failure
830
831 public int pcm_seek(long pos){
832 int link=-1;
833 long total=pcm_total(-1);
834
835 if(!seekable)return(-1); // don't dump machine if we can't seek
836 if(pos<0 || pos>total){
837 //goto seek_error;
838 pcm_offset=-1;
839 decode_clear();
840 return -1;
841 }
842
843 // which bitstream section does this pcm offset occur in?
844 for(link=links-1;link>=0;link--){
845 total-=pcmlengths[link];
846 if(pos>=total)break;
847 }
848
849 // search within the logical bitstream for the page with the highest
850 // pcm_pos preceeding (or equal to) pos. There is a danger here;
851 // missing pages or incorrect frame number information in the
852 // bitstream could make our task impossible. Account for that (it
853 // would be an error condition)
854 {
855 long target=pos-total;
856 int end=(int)offsets[link+1];
857 int begin=(int)offsets[link];
858 int best=begin;
859
860 Page og=new Page();
861 while(begin<end){
862 int bisect;
863 int ret;
864
865 if(end-begin<CHUNKSIZE){
866 bisect=begin;
867 }
868 else{
869 bisect=(end+begin)/2;
870 }
871
872 seek_helper(bisect);
873 ret=get_next_page(og,end-bisect);
874
875 if(ret==-1){
876 end=bisect;
877 }
878 else{
879 long granulepos=og.granulepos();
880 if(granulepos<target){
881 best=ret; // raw offset of packet with granulepos
882 begin=(int)offset; // raw offset of next packet
883 }
884 else{
885 end=bisect;
886 }
887 }
888 }
889 // found our page. seek to it (call raw_seek).
890 if(raw_seek(best)!=0){
891 //goto seek_error;
892 pcm_offset=-1;
893 decode_clear();
894 return -1;
895 }
896 }
897
898 // verify result
899 if(pcm_offset>=pos){
900 //goto seek_error;
901 pcm_offset=-1;
902 decode_clear();
903 return -1;
904 }
905 if(pos>pcm_total(-1)){
906 //goto seek_error;
907 pcm_offset=-1;
908 decode_clear();
909 return -1;
910 }
911
912 // discard samples until we reach the desired position. Crossing a
913 // logical bitstream boundary with abandon is OK.
914 while(pcm_offset<pos){
915 float[][] pcm;
916 int target=(int)(pos-pcm_offset);
917 float[][][] _pcm=new float[1][][];
918 int[] _index=new int[info(-1).channels];
919 int samples=vd.synthesis_pcmout(_pcm, _index);
920 pcm=_pcm[0];
921
922 if(samples>target)samples=target;
923 vd.synthesis_read(samples);
924 pcm_offset+=samples;
925
926 if(samples<target)
927 if(process_packet(1)==0){
928 pcm_offset=pcm_total(-1); // eof
929 }
930 }
931 return 0;
932
933 // seek_error:
934 // dump machine so we're in a known state
935 //pcm_offset=-1;
936 //decode_clear();
937 //return -1;
938 }
939
940 // seek to a playback time relative to the decompressed pcm stream
941 // returns zero on success, nonzero on failure
942 public int time_seek(float seconds){
943 // translate time to PCM position and call pcm_seek
944
945 int link=-1;
946 long pcm_total=pcm_total(-1);
947 float time_total=time_total(-1);
948
949 if(!seekable)return(-1); // don't dump machine if we can't seek
950 if(seconds<0 || seconds>time_total){
951 //goto seek_error;
952 pcm_offset=-1;
953 decode_clear();
954 return -1;
955 }
956
957 // which bitstream section does this time offset occur in?
958 for(link=links-1;link>=0;link--){
959 pcm_total-=pcmlengths[link];
960 time_total-=time_total(link);
961 if(seconds>=time_total)break;
962 }
963
964 // enough information to convert time offset to pcm offset
965 {
966 long target=(long)(pcm_total+(seconds-time_total)*vi[link].rate);
967 return(pcm_seek(target));
968 }
969
970 //seek_error:
971 // dump machine so we're in a known state
972 //pcm_offset=-1;
973 //decode_clear();
974 //return -1;
975 }
976
977 // tell the current stream offset cursor. Note that seek followed by
978 // tell will likely not give the set offset due to caching
979 public long raw_tell(){
980 return(offset);
981 }
982
983 // return PCM offset (sample) of next PCM sample to be read
984 public long pcm_tell(){
985 return(pcm_offset);
986 }
987
988 // return time offset (seconds) of next PCM sample to be read
989 public float time_tell(){
990 // translate time to PCM position and call pcm_seek
991
992 int link=-1;
993 long pcm_total=0;
994 float time_total=0.f;
995
996 if(seekable){
997 pcm_total=pcm_total(-1);
998 time_total=time_total(-1);
999
1000 // which bitstream section does this time offset occur in?
1001 for(link=links-1;link>=0;link--){
1002 pcm_total-=pcmlengths[link];
1003 time_total-=time_total(link);
1004 if(pcm_offset>=pcm_total)break;
1005 }
1006 }
1007
1008 return((float)time_total+(float)(pcm_offset-pcm_total)/vi[link].rate);
1009 }
1010
1011 // link: -1) return the vorbis_info struct for the bitstream section
1012 // currently being decoded
1013 // 0-n) to request information for a specific bitstream section
1014 //
1015 // In the case of a non-seekable bitstream, any call returns the
1016 // current bitstream. NULL in the case that the machine is not
1017 // initialized
1018
1019 public Info info(int link){
1020 if(seekable){
1021 if(link<0){
1022 if(decode_ready){
1023 return vi[current_link];
1024 }
1025 else{
1026 return null;
1027 }
1028 }
1029 else{
1030 if(link>=links){
1031 return null;
1032 }
1033 else{
1034 return vi[link];
1035 }
1036 }
1037 }
1038 else{
1039 if(decode_ready){
1040 return vi[0];
1041 }
1042 else{
1043 return null;
1044 }
1045 }
1046 }
1047
1048 public Comment comment(int link){
1049 if(seekable){
1050 if(link<0){
1051 if(decode_ready){ return vc[current_link]; }
1052 else{ return null; }
1053 }
1054 else{
1055 if(link>=links){ return null;}
1056 else{ return vc[link]; }
1057 }
1058 }
1059 else{
1060 if(decode_ready){ return vc[0]; }
1061 else{ return null; }
1062 }
1063 }
1064
1065 int host_is_big_endian() {
1066 return 1;
1067// short pattern = 0xbabe;
1068// unsigned char *bytewise = (unsigned char *)&pattern;
1069// if (bytewise[0] == 0xba) return 1;
1070// assert(bytewise[0] == 0xbe);
1071// return 0;
1072 }
1073
1074 // up to this point, everything could more or less hide the multiple
1075 // logical bitstream nature of chaining from the toplevel application
1076 // if the toplevel application didn't particularly care. However, at
1077 // the point that we actually read audio back, the multiple-section
1078 // nature must surface: Multiple bitstream sections do not necessarily
1079 // have to have the same number of channels or sampling rate.
1080 //
1081 // read returns the sequential logical bitstream number currently
1082 // being decoded along with the PCM data in order that the toplevel
1083 // application can take action on channel/sample rate changes. This
1084 // number will be incremented even for streamed (non-seekable) streams
1085 // (for seekable streams, it represents the actual logical bitstream
1086 // index within the physical bitstream. Note that the accessor
1087 // functions above are aware of this dichotomy).
1088 //
1089 // input values: buffer) a buffer to hold packed PCM data for return
1090 // length) the byte length requested to be placed into buffer
1091 // bigendianp) should the data be packed LSB first (0) or
1092 // MSB first (1)
1093 // word) word size for output. currently 1 (byte) or
1094 // 2 (16 bit short)
1095 //
1096 // return values: -1) error/hole in data
1097 // 0) EOF
1098 // n) number of bytes of PCM actually returned. The
1099 // below works on a packet-by-packet basis, so the
1100 // return length is not related to the 'length' passed
1101 // in, just guaranteed to fit.
1102 //
1103 // *section) set to the logical bitstream number
1104
1105 int read(byte[] buffer,int length,
1106 int bigendianp, int word, int sgned, int[] bitstream){
1107 int host_endian = host_is_big_endian();
1108 int index=0;
1109
1110 while(true){
1111 if(decode_ready){
1112 float[][] pcm;
1113 float[][][] _pcm=new float[1][][];
1114 int[] _index=new int[info(-1).channels];
1115 int samples=vd.synthesis_pcmout(_pcm, _index);
1116 pcm=_pcm[0];
1117 if(samples!=0){
1118 // yay! proceed to pack data into the byte buffer
1119 int channels=info(-1).channels;
1120 int bytespersample=word * channels;
1121 if(samples>length/bytespersample)samples=length/bytespersample;
1122
1123 // a tight loop to pack each size
1124 {
1125 int val;
1126 if(word==1){
1127 int off=(sgned!=0?0:128);
1128 for(int j=0;j<samples;j++){
1129 for(int i=0;i<channels;i++){
1130 val=(int)(pcm[i][_index[i]+j]*128. + 0.5);
1131 if(val>127)val=127;
1132 else if(val<-128)val=-128;
1133 buffer[index++]=(byte)(val+off);
1134 }
1135 }
1136 }
1137 else{
1138 int off=(sgned!=0?0:32768);
1139
1140 if(host_endian==bigendianp){
1141 if(sgned!=0){
1142 for(int i=0;i<channels;i++) { // It's faster in this order
1143 int src=_index[i];
1144 int dest=i;
1145 for(int j=0;j<samples;j++) {
1146 val=(int)(pcm[i][src+j]*32768. + 0.5);
1147 if(val>32767)val=32767;
1148 else if(val<-32768)val=-32768;
1149 buffer[dest]=(byte)(val>>>8);
1150 buffer[dest+1]=(byte)(val);
1151 dest+=channels*2;
1152 }
1153 }
1154 }
1155 else{
1156 for(int i=0;i<channels;i++) {
1157 float[] src=pcm[i];
1158 int dest=i;
1159 for(int j=0;j<samples;j++) {
1160 val=(int)(src[j]*32768. + 0.5);
1161 if(val>32767)val=32767;
1162 else if(val<-32768)val=-32768;
1163 buffer[dest]=(byte)((val+off)>>>8);
1164 buffer[dest+1]=(byte)(val+off);
1165 dest+=channels*2;
1166 }
1167 }
1168 }
1169 }
1170 else if(bigendianp!=0){
1171 for(int j=0;j<samples;j++){
1172 for(int i=0;i<channels;i++){
1173 val=(int)(pcm[i][j]*32768. + 0.5);
1174 if(val>32767)val=32767;
1175 else if(val<-32768)val=-32768;
1176 val+=off;
1177 buffer[index++]=(byte)(val>>>8);
1178 buffer[index++]=(byte)val;
1179 }
1180 }
1181 }
1182 else{
1183 //int val;
1184 for(int j=0;j<samples;j++){
1185 for(int i=0;i<channels;i++){
1186 val=(int)(pcm[i][j]*32768. + 0.5);
1187 if(val>32767)val=32767;
1188 else if(val<-32768)val=-32768;
1189 val+=off;
1190 buffer[index++]=(byte)val;
1191 buffer[index++]=(byte)(val>>>8);
1192 }
1193 }
1194 }
1195 }
1196 }
1197
1198 vd.synthesis_read(samples);
1199 pcm_offset+=samples;
1200 if(bitstream!=null)bitstream[0]=current_link;
1201 return(samples*bytespersample);
1202 }
1203 }
1204
1205 // suck in another packet
1206 switch(process_packet(1)){
1207 case 0:
1208 return(0);
1209 case -1:
1210 return -1;
1211 default:
1212 break;
1213 }
1214 }
1215 }
1216
1217 public int getLinks(){return links;}
1218 public Info[] getInfo(){return vi;}
1219 public Comment[] getComment(){return vc;}
1220
1221 public static void main(String[] arg){
1222 try{
1223 VorbisFile foo=new VorbisFile(arg[0]);
1224 int links=foo.getLinks();
1225 System.out.println("links="+links);
1226 Comment[] comment=foo.getComment();
1227 Info[] info=foo.getInfo();
1228 for(int i=0; i<links; i++){
1229 System.out.println(info[i]);
1230 System.out.println(comment[i]);
1231 }
1232 System.out.println("raw_total: "+foo.raw_total(-1));
1233 System.out.println("pcm_total: "+foo.pcm_total(-1));
1234 System.out.println("time_total: "+foo.time_total(-1));
1235 }
1236 catch(Exception e){
1237 System.err.println(e);
1238 }
1239 }
1240}
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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.3 2004/09/21 12:09:45 shred
22 * *** empty log message ***
23 *
24 * Revision 1.2 2004/09/21 06:38:45 shred
25 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
26 *
27 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
28 * First Import
29 *
30 *
31 */
32
33package de.jarnbjo.ogg;
34
35import java.io.IOException;
36import java.io.InputStream;
37import java.util.Collection;
38import java.util.HashMap;
39import java.util.LinkedList;
40
41/**
42 * Implementation of the <code>PhysicalOggStream</code> interface for reading
43 * an Ogg stream from a URL. This class performs
44 * no internal caching, and will not read data from the network before
45 * requested to do so. It is intended to be used in non-realtime applications
46 * like file download managers or similar.
47 */
48
49public class BasicStream implements PhysicalOggStream {
50
51 private boolean closed=false;
52 private InputStream sourceStream;
53 private Object drainLock=new Object();
54 private LinkedList pageCache=new LinkedList();
55 private long numberOfSamples=-1;
56 private int position=0;
57
58 private HashMap logicalStreams=new HashMap();
59 private OggPage firstPage;
60
61 public BasicStream(InputStream sourceStream) throws OggFormatException, IOException {
62 firstPage=OggPage.create(sourceStream);
63 position+=firstPage.getTotalLength();
64 LogicalOggStreamImpl los=new LogicalOggStreamImpl(this, firstPage.getStreamSerialNumber());
65 logicalStreams.put(new Integer(firstPage.getStreamSerialNumber()), los);
66 los.checkFormat(firstPage);
67 }
68
69 public Collection getLogicalStreams() {
70 return logicalStreams.values();
71 }
72
73 public boolean isOpen() {
74 return !closed;
75 }
76
77 public void close() throws IOException {
78 closed=true;
79 sourceStream.close();
80 }
81
82 public int getContentLength() {
83 return -1;
84 }
85
86 public int getPosition() {
87 return position;
88 }
89
90 int pageNumber=2;
91
92 public OggPage getOggPage(int index) throws IOException {
93 if(firstPage!=null) {
94 OggPage tmp=firstPage;
95 firstPage=null;
96 return tmp;
97 }
98 else {
99 OggPage page=OggPage.create(sourceStream);
100 position+=page.getTotalLength();
101 return page;
102 }
103 }
104
105 private LogicalOggStream getLogicalStream(int serialNumber) {
106 return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
107 }
108
109 public void setTime(long granulePosition) throws IOException {
110 throw new UnsupportedOperationException("Method not supported by this class");
111 }
112
113 /**
114 * @return always <code>false</code>
115 */
116
117 public boolean isSeekable() {
118 return false;
119 }
120
121} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.1 2003/04/10 19:48:22 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.ogg;
31
32import java.io.*;
33import java.net.*;
34import java.util.*;
35
36/**
37 * Implementation of the <code>PhysicalOggStream</code> interface for reading
38 * and caching an Ogg stream from a URL. This class reads the data as fast as
39 * possible from the URL, caches it locally either in memory or on disk, and
40 * supports seeking within the available data.
41 */
42
43public class CachedUrlStream implements PhysicalOggStream {
44
45 private boolean closed=false;
46 private URLConnection source;
47 private InputStream sourceStream;
48 private Object drainLock=new Object();
49 private RandomAccessFile drain;
50 private byte[] memoryCache;
51 private ArrayList pageOffsets=new ArrayList();
52 private ArrayList pageLengths=new ArrayList();
53 private long numberOfSamples=-1;
54 private long cacheLength;
55
56 private HashMap logicalStreams=new HashMap();
57
58 private LoaderThread loaderThread;
59
60 /**
61 * Creates an instance of this class, using a memory cache.
62 */
63
64 public CachedUrlStream(URL source) throws OggFormatException, IOException {
65 this(source, null);
66 }
67
68 /**
69 * Creates an instance of this class, using the specified file as cache. The
70 * file is not automatically deleted when this class is disposed.
71 */
72
73 public CachedUrlStream(URL source, RandomAccessFile drain) throws OggFormatException, IOException {
74
75 this.source=source.openConnection();
76
77 if(drain==null) {
78 int contentLength=this.source.getContentLength();
79 if(contentLength==-1) {
80 throw new IOException("The URLConncetion's content length must be set when operating with a in-memory cache.");
81 }
82 memoryCache=new byte[contentLength];
83 }
84
85 this.drain=drain;
86 this.sourceStream=this.source.getInputStream();
87
88 loaderThread=new LoaderThread(sourceStream, drain, memoryCache);
89 new Thread(loaderThread).start();
90
91 while(!loaderThread.isBosDone() || pageOffsets.size()<20) {
92 System.out.print("pageOffsets.size(): "+pageOffsets.size()+"\r");
93 try {
94 Thread.sleep(200);
95 }
96 catch (InterruptedException ex) {
97 }
98 }
99 System.out.println();
100 System.out.println("caching "+pageOffsets.size()+"/20 pages\r");
101 }
102
103 public Collection getLogicalStreams() {
104 return logicalStreams.values();
105 }
106
107 public boolean isOpen() {
108 return !closed;
109 }
110
111 public void close() throws IOException {
112 closed=true;
113 sourceStream.close();
114 }
115
116 public long getCacheLength() {
117 return cacheLength;
118 }
119
120 /*
121 private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
122 return getNextPage(false);
123 }
124
125 private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
126 return OggPage.create(sourceStream, skipData);
127 }
128 */
129
130 public OggPage getOggPage(int index) throws IOException {
131 synchronized(drainLock) {
132 Long offset=(Long)pageOffsets.get(index);
133 Long length=(Long)pageLengths.get(index);
134 if(offset!=null) {
135 if(drain!=null) {
136 drain.seek(offset.longValue());
137 return OggPage.create(drain);
138 }
139 else {
140 byte[] tmpArray=new byte[length.intValue()];
141 System.arraycopy(memoryCache, offset.intValue(), tmpArray, 0, length.intValue());
142 return OggPage.create(tmpArray);
143 }
144 }
145 else {
146 return null;
147 }
148 }
149 }
150
151 private LogicalOggStream getLogicalStream(int serialNumber) {
152 return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
153 }
154
155 public void setTime(long granulePosition) throws IOException {
156 for(Iterator iter=logicalStreams.values().iterator(); iter.hasNext(); ) {
157 LogicalOggStream los=(LogicalOggStream)iter.next();
158 los.setTime(granulePosition);
159 }
160 }
161
162 public class LoaderThread implements Runnable {
163
164 private InputStream source;
165 private RandomAccessFile drain;
166 private byte[] memoryCache;
167
168 private boolean bosDone=false;
169
170 private int pageNumber;
171
172 public LoaderThread(InputStream source, RandomAccessFile drain, byte[] memoryCache) {
173 this.source=source;
174 this.drain=drain;
175 this.memoryCache=memoryCache;
176 }
177
178 public void run() {
179 try {
180 boolean eos=false;
181 byte[] buffer=new byte[8192];
182 while(!eos) {
183 OggPage op=OggPage.create(source);
184 synchronized (drainLock) {
185 int listSize=pageOffsets.size();
186
187 long pos=
188 listSize>0?
189 ((Long)pageOffsets.get(listSize-1)).longValue()+
190 ((Long)pageLengths.get(listSize-1)).longValue():
191 0;
192
193 byte[] arr1=op.getHeader();
194 byte[] arr2=op.getSegmentTable();
195 byte[] arr3=op.getData();
196
197 if(drain!=null) {
198 drain.seek(pos);
199 drain.write(arr1);
200 drain.write(arr2);
201 drain.write(arr3);
202 }
203 else {
204 System.arraycopy(arr1, 0, memoryCache, (int)pos, arr1.length);
205 System.arraycopy(arr2, 0, memoryCache, (int)pos+arr1.length, arr2.length);
206 System.arraycopy(arr3, 0, memoryCache, (int)pos+arr1.length+arr2.length, arr3.length);
207 }
208
209 pageOffsets.add(new Long(pos));
210 pageLengths.add(new Long(arr1.length+arr2.length+arr3.length));
211 }
212
213 if(!op.isBos()) {
214 bosDone=true;
215 //System.out.println("bosDone=true;");
216 }
217 if(op.isEos()) {
218 eos=true;
219 }
220
221 LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
222 if(los==null) {
223 los=new LogicalOggStreamImpl(CachedUrlStream.this, op.getStreamSerialNumber());
224 logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
225 los.checkFormat(op);
226 }
227
228 los.addPageNumberMapping(pageNumber);
229 los.addGranulePosition(op.getAbsoluteGranulePosition());
230
231 pageNumber++;
232 cacheLength=op.getAbsoluteGranulePosition();
233 //System.out.println("read page: "+pageNumber);
234 }
235 }
236 catch(EndOfOggStreamException e) {
237 // ok
238 }
239 catch(IOException e) {
240 e.printStackTrace();
241 }
242 }
243
244 public boolean isBosDone() {
245 return bosDone;
246 }
247 }
248
249 public boolean isSeekable() {
250 return true;
251 }
252} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2005/02/09 23:10:47 shred
22 * Serial UID für jarnbjo
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.1 2003/03/03 21:02:20 jarnbjo
28 * no message
29 *
30 */
31
32 package de.jarnbjo.ogg;
33
34import java.io.IOException;
35
36/**
37 * Exception thrown when reaching the end of an Ogg stream
38 */
39
40public class EndOfOggStreamException extends IOException {
41 private static final long serialVersionUID = 3907210438109444408L;
42
43 public EndOfOggStreamException() {
44 }
45} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.1 2003/04/10 19:48:22 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.ogg;
31
32import java.io.*;
33import java.util.*;
34
35/**
36 * Implementation of the <code>PhysicalOggStream</code> interface for accessing
37 * normal disk files.
38 */
39
40public class FileStream implements PhysicalOggStream {
41
42 private boolean closed=false;
43 private RandomAccessFile source;
44 private long[] pageOffsets;
45 private long numberOfSamples=-1;
46
47 private HashMap logicalStreams=new HashMap();
48
49 /**
50 * Creates access to the specified file through the <code>PhysicalOggStream</code> interface.
51 * The specified source file must have been opened for reading.
52 *
53 * @param source the file to read from
54 *
55 * @throws OggFormatException if the stream format is incorrect
56 * @throws IOException if some other IO error occurs when reading the file
57 */
58
59 public FileStream(RandomAccessFile source) throws OggFormatException, IOException {
60 this.source=source;
61
62 ArrayList po=new ArrayList();
63 int pageNumber=0;
64 try {
65 while(true) {
66 po.add(new Long(this.source.getFilePointer()));
67
68 // skip data if pageNumber>0
69 OggPage op=getNextPage(pageNumber>0);
70 if(op==null) {
71 break;
72 }
73
74 LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
75 if(los==null) {
76 los=new LogicalOggStreamImpl(this, op.getStreamSerialNumber());
77 logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
78 }
79
80 if(pageNumber==0) {
81 los.checkFormat(op);
82 }
83
84 los.addPageNumberMapping(pageNumber);
85 los.addGranulePosition(op.getAbsoluteGranulePosition());
86
87 if(pageNumber>0) {
88 this.source.seek(this.source.getFilePointer()+op.getTotalLength());
89 }
90
91 pageNumber++;
92 }
93 }
94 catch(EndOfOggStreamException e) {
95 // ok
96 }
97 catch(IOException e) {
98 throw e;
99 }
100 //System.out.println("pageNumber: "+pageNumber);
101 this.source.seek(0L);
102 pageOffsets=new long[po.size()];
103 int i=0;
104 Iterator iter=po.iterator();
105 while(iter.hasNext()) {
106 pageOffsets[i++]=((Long)iter.next()).longValue();
107 }
108 }
109
110 public Collection getLogicalStreams() {
111 return logicalStreams.values();
112 }
113
114 public boolean isOpen() {
115 return !closed;
116 }
117
118 public void close() throws IOException {
119 closed=true;
120 source.close();
121 }
122
123 private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
124 return getNextPage(false);
125 }
126
127 private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
128 return OggPage.create(source, skipData);
129 }
130
131 public OggPage getOggPage(int index) throws IOException {
132 source.seek(pageOffsets[index]);
133 return OggPage.create(source);
134 }
135
136 private LogicalOggStream getLogicalStream(int serialNumber) {
137 return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
138 }
139
140 public void setTime(long granulePosition) throws IOException {
141 for(Iterator iter=logicalStreams.values().iterator(); iter.hasNext(); ) {
142 LogicalOggStream los=(LogicalOggStream)iter.next();
143 los.setTime(granulePosition);
144 }
145 }
146
147 /**
148 * @return always <code>true</code>
149 */
150
151 public boolean isSeekable() {
152 return true;
153 }
154} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/04/10 19:48:22 jarnbjo
25 * no message
26 *
27 * Revision 1.1 2003/03/03 21:02:20 jarnbjo
28 * no message
29 *
30 */
31
32package de.jarnbjo.ogg;
33
34import java.io.IOException;
35
36/**
37 * Interface providing access to a logical Ogg stream as part of a
38 * physical Ogg stream.
39 */
40
41
42public interface LogicalOggStream {
43
44 public static final String FORMAT_UNKNOWN = "application/octet-stream";
45
46 public static final String FORMAT_VORBIS = "audio/x-vorbis";
47 public static final String FORMAT_FLAC = "audio/x-flac";
48 public static final String FORMAT_THEORA = "video/x-theora";
49
50 /**
51 * <i>Note:</i> To read from the stream, you must use either
52 * this method or the method <code>getNextOggPacket</code>.
53 * Mixing calls to the two methods will cause data corruption.
54 *
55 * @return the next Ogg page
56 *
57 * @see #getNextOggPacket()
58 *
59 * @throws OggFormatException if the ogg stream is corrupted
60 * @throws IOException if some other IO error occurs
61 */
62
63 public OggPage getNextOggPage() throws OggFormatException, IOException;
64
65 /**
66 * <i>Note:</i> To read from the stream, you must use either
67 * this method or the method <code>getNextOggPage</code>.
68 * Mixing calls to the two methods will cause data corruption.
69 *
70 * @return the next packet as a byte array
71 *
72 * @see #getNextOggPage()
73 *
74 * @throws OggFormatException if the ogg stream is corrupted
75 * @throws IOException if some other IO error occurs
76 */
77
78 public byte[] getNextOggPacket() throws OggFormatException, IOException;
79
80 /**
81 * Checks if this stream is open for reading.
82 *
83 * @return <code>true</code> if this stream is open for reading,
84 * <code>false</code> otherwise
85 */
86
87 public boolean isOpen();
88
89 /**
90 * Closes this stream. After invoking this method, no further access
91 * to the streams data is possible.
92 *
93 * @throws IOException if an IO error occurs
94 */
95
96 public void close() throws IOException;
97
98 /**
99 * Sets the stream's position to the beginning of the stream.
100 * This method does not work if the physical Ogg stream is not
101 * seekable.
102 *
103 * @throws OggFormatException if the ogg stream is corrupted
104 * @throws IOException if some other IO error occurs
105 */
106
107 public void reset() throws OggFormatException, IOException;
108
109 /**
110 * This method does not work if the physical Ogg stream is not
111 * seekable.
112 *
113 * @return the granule position of the last page within
114 * this stream
115 */
116
117 public long getMaximumGranulePosition();
118
119 /**
120 * This method is invoked on all logical streams when
121 * calling the same method on the physical stream. The
122 * same restrictions as mentioned there apply.
123 * This method does not work if the physical Ogg stream is not
124 * seekable.
125 *
126 * @param granulePosition
127 *
128 * @see PhysicalOggStream#setTime(long)
129 *
130 * @throws IOException if an IO error occurs
131 */
132
133 public void setTime(long granulePosition) throws IOException;
134
135 /**
136 * @return the last parsed granule position of this stream
137 */
138
139 public long getTime();
140
141 /**
142 * @return the content type of this stream
143 *
144 * @see #FORMAT_UNKNOWN
145 * @see #FORMAT_VORBIS
146 * @see #FORMAT_FLAC
147 * @see #FORMAT_THEORA
148 */
149
150 public String getFormat();
151} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/03/31 00:23:04 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/16 01:11:26 jarnbjo
28 * no message
29 *
30 * Revision 1.1 2003/03/03 21:02:20 jarnbjo
31 * no message
32 *
33 */
34
35package de.jarnbjo.ogg;
36
37import java.io.*;
38import java.util.*;
39
40public class LogicalOggStreamImpl implements LogicalOggStream {
41
42 private PhysicalOggStream source;
43 private int serialNumber;
44
45 private ArrayList pageNumberMapping=new ArrayList();
46 private ArrayList granulePositions=new ArrayList();
47
48 private int pageIndex=0;
49 private OggPage currentPage;
50 private int currentSegmentIndex;
51
52 private boolean open=true;
53
54 private String format=FORMAT_UNKNOWN;
55
56 public LogicalOggStreamImpl(PhysicalOggStream source, int serialNumber) {
57 this.source=source;
58 this.serialNumber=serialNumber;
59 }
60
61 public void addPageNumberMapping(int physicalPageNumber) {
62 pageNumberMapping.add(new Integer(physicalPageNumber));
63 }
64
65 public void addGranulePosition(long granulePosition) {
66 granulePositions.add(new Long(granulePosition));
67 }
68
69 public synchronized void reset() throws OggFormatException, IOException {
70 currentPage=null;
71 currentSegmentIndex=0;
72 pageIndex=0;
73 }
74
75 public synchronized OggPage getNextOggPage() throws EndOfOggStreamException, OggFormatException, IOException {
76 if(source.isSeekable()) {
77 currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
78 }
79 else {
80 currentPage=source.getOggPage(-1);
81 }
82 return currentPage;
83 }
84
85 public synchronized byte[] getNextOggPacket() throws EndOfOggStreamException, OggFormatException, IOException {
86 ByteArrayOutputStream res=new ByteArrayOutputStream();
87 int segmentLength=0;
88
89 if(currentPage==null) {
90 currentPage=getNextOggPage();
91 }
92
93 do {
94 if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) {
95 currentSegmentIndex=0;
96
97 if(!currentPage.isEos()) {
98 if(source.isSeekable() && pageNumberMapping.size()<=pageIndex) {
99 while(pageNumberMapping.size()<=pageIndex+10) {
100 try {
101 Thread.sleep(1000);
102 }
103 catch (InterruptedException ex) {
104 }
105 }
106 }
107 currentPage=getNextOggPage();
108
109 if(res.size()==0 && currentPage.isContinued()) {
110 boolean done=false;
111 while(!done) {
112 if(currentPage.getSegmentLengths()[currentSegmentIndex++]!=255) {
113 done=true;
114 }
115 if(currentSegmentIndex>currentPage.getSegmentTable().length) {
116 currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
117 }
118 }
119 }
120 }
121 else {
122 throw new EndOfOggStreamException();
123 }
124 }
125 segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex];
126 res.write(currentPage.getData(), currentPage.getSegmentOffsets()[currentSegmentIndex], segmentLength);
127 currentSegmentIndex++;
128 } while(segmentLength==255);
129
130 return res.toByteArray();
131 }
132
133 public boolean isOpen() {
134 return open;
135 }
136
137 public void close() throws IOException {
138 open=false;
139 }
140
141 public long getMaximumGranulePosition() {
142 Long mgp=(Long)granulePositions.get(granulePositions.size()-1);
143 return mgp.longValue();
144 }
145
146 public synchronized long getTime() {
147 return currentPage!=null?currentPage.getAbsoluteGranulePosition():-1;
148 }
149
150 public synchronized void setTime(long granulePosition) throws IOException {
151
152 int page=0;
153 for(page=0; page<granulePositions.size(); page++) {
154 Long gp=(Long)granulePositions.get(page);
155 if(gp.longValue()>granulePosition) {
156 break;
157 }
158 }
159
160 pageIndex=page;
161 currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
162 currentSegmentIndex=0;
163 int segmentLength=0;
164 do {
165 if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) {
166 currentSegmentIndex=0;
167 if(pageIndex>=pageNumberMapping.size()) {
168 throw new EndOfOggStreamException();
169 }
170 currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
171 }
172 segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex];
173 currentSegmentIndex++;
174 } while(segmentLength==255);
175 }
176
177 public void checkFormat(OggPage page) {
178 byte[] data=page.getData();
179
180 if(data.length>=7 &&
181 data[1]==0x76 &&
182 data[2]==0x6f &&
183 data[3]==0x72 &&
184 data[4]==0x62 &&
185 data[5]==0x69 &&
186 data[6]==0x73) {
187
188 format=FORMAT_VORBIS;
189 }
190 else if(data.length>=7 &&
191 data[1]==0x74 &&
192 data[2]==0x68 &&
193 data[3]==0x65 &&
194 data[4]==0x6f &&
195 data[5]==0x72 &&
196 data[6]==0x61) {
197
198 format=FORMAT_THEORA;
199 }
200 else if (data.length==4 &&
201 data[0]==0x66 &&
202 data[1]==0x4c &&
203 data[2]==0x61 &&
204 data[3]==0x43) {
205
206 format=FORMAT_FLAC;
207 }
208 }
209
210 public String getFormat() {
211 return format;
212 }
213} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2005/02/09 23:10:47 shred
22 * Serial UID für jarnbjo
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.1 2003/03/03 21:02:20 jarnbjo
28 * no message
29 *
30 */
31
32package de.jarnbjo.ogg;
33
34import java.io.IOException;
35
36/**
37 * Exception thrown when trying to read a corrupted Ogg stream.
38 */
39
40public class OggFormatException extends IOException {
41 private static final long serialVersionUID = 3544953238333175349L;
42
43 public OggFormatException() {
44 super();
45 }
46
47 public OggFormatException(String message) {
48 super(message);
49 }
50} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/04/10 19:48:22 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/31 00:23:04 jarnbjo
28 * no message
29 *
30 * Revision 1.1 2003/03/03 21:02:20 jarnbjo
31 * no message
32 *
33 */
34
35package de.jarnbjo.ogg;
36
37import java.io.*;
38
39import de.jarnbjo.util.io.*;
40
41/**
42 * <p>An instance of this class represents an ogg page read from an ogg file
43 * or network stream. It has no public constructor, but instances can be
44 * created by the <code>create</code> methods, supplying a JMF stream or
45 * a <code>RandomAccessFile</code>
46 * which is positioned at the beginning of an Ogg page.</p>
47 *
48 * <p>Furtheron, the class provides methods for accessing the raw page data,
49 * as well as data attributes like segmenting information, sequence number,
50 * stream serial number, chechsum and wether this page is the beginning or
51 * end of a logical bitstream (BOS, EOS) and if the page data starts with a
52 * continued packet or a fresh data packet.</p>
53 */
54
55public class OggPage {
56
57 private int version;
58 private boolean continued, bos, eos;
59 private long absoluteGranulePosition;
60 private int streamSerialNumber, pageSequenceNumber, pageCheckSum;
61 private int[] segmentOffsets;
62 private int[] segmentLengths;
63 private int totalLength;
64 private byte[] header, segmentTable, data;
65
66 protected OggPage() {
67 }
68
69 private OggPage(
70 int version,
71 boolean continued,
72 boolean bos,
73 boolean eos,
74 long absoluteGranulePosition,
75 int streamSerialNumber,
76 int pageSequenceNumber,
77 int pageCheckSum,
78 int[] segmentOffsets,
79 int[] segmentLengths,
80 int totalLength,
81 byte[] header,
82 byte[] segmentTable,
83 byte[] data) {
84
85 this.version=version;
86 this.continued=continued;
87 this.bos=bos;
88 this.eos=eos;
89 this.absoluteGranulePosition=absoluteGranulePosition;
90 this.streamSerialNumber=streamSerialNumber;
91 this.pageSequenceNumber=pageSequenceNumber;
92 this.pageCheckSum=pageCheckSum;
93 this.segmentOffsets=segmentOffsets;
94 this.segmentLengths=segmentLengths;
95 this.totalLength=totalLength;
96 this.header=header;
97 this.segmentTable=segmentTable;
98 this.data=data;
99 }
100
101 /**
102 * this method equals to create(RandomAccessFile source, false)
103 *
104 * @see #create(RandomAccessFile, boolean)
105 */
106
107 public static OggPage create(RandomAccessFile source) throws IOException, EndOfOggStreamException, OggFormatException {
108 return create(source, false);
109 }
110
111 /**
112 * This method is called to read data from the current position in the
113 * specified RandomAccessFile and create a new OggPage instance based on the data
114 * read. If the parameter <code>skipData</code> is set to <code>true</code>,
115 * the actual page segments (page data) is skipped and not read into
116 * memory. This mode is useful when scanning through an ogg file to build
117 * a seek table.
118 *
119 * @param source the source from which the ogg page is generated
120 * @param skipData if set to <code>true</code>, the actual page data is not read into memory
121 * @return an ogg page created by reading data from the specified source, starting at the current position
122 * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
123 * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
124 * @throws IOException if some other I/O error is detected when reading from the source
125 *
126 * @see #create(RandomAccessFile)
127 */
128
129 public static OggPage create(RandomAccessFile source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
130 return create((Object)source, skipData);
131 }
132
133 /**
134 * this method equals to create(InputStream source, false)
135 *
136 * @see #create(InputStream, boolean)
137 */
138
139 public static OggPage create(InputStream source) throws IOException, EndOfOggStreamException, OggFormatException {
140 return create(source, false);
141 }
142
143 /**
144 * This method is called to read data from the current position in the
145 * specified InpuStream and create a new OggPage instance based on the data
146 * read. If the parameter <code>skipData</code> is set to <code>true</code>,
147 * the actual page segments (page data) is skipped and not read into
148 * memory. This mode is useful when scanning through an ogg file to build
149 * a seek table.
150 *
151 * @param source the source from which the ogg page is generated
152 * @param skipData if set to <code>true</code>, the actual page data is not read into memory
153 * @return an ogg page created by reading data from the specified source, starting at the current position
154 * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
155 * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
156 * @throws IOException if some other I/O error is detected when reading from the source
157 *
158 * @see #create(InputStream)
159 */
160
161 public static OggPage create(InputStream source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
162 return create((Object)source, skipData);
163 }
164
165 /**
166 * this method equals to create(byte[] source, false)
167 *
168 * @see #create(byte[], boolean)
169 */
170
171 public static OggPage create(byte[] source) throws IOException, EndOfOggStreamException, OggFormatException {
172 return create(source, false);
173 }
174
175 /**
176 * This method is called to
177 * create a new OggPage instance based on the specified byte array.
178 *
179 * @param source the source from which the ogg page is generated
180 * @param skipData if set to <code>true</code>, the actual page data is not read into memory
181 * @return an ogg page created by reading data from the specified source, starting at the current position
182 * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
183 * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
184 * @throws IOException if some other I/O error is detected when reading from the source
185 *
186 * @see #create(byte[])
187 */
188
189 public static OggPage create(byte[] source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
190 return create((Object)source, skipData);
191 }
192
193 private static OggPage create(Object source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
194
195 try {
196 int sourceOffset=27;
197
198 byte[] header=new byte[27];
199 if(source instanceof RandomAccessFile) {
200 RandomAccessFile raf=(RandomAccessFile)source;
201 if(raf.getFilePointer()==raf.length()) {
202 return null;
203 }
204 raf.readFully(header);
205 }
206 else if(source instanceof InputStream) {
207 readFully((InputStream)source, header);
208 }
209 else if(source instanceof byte[]) {
210 System.arraycopy((byte[])source, 0, header, 0, 27);
211 }
212
213 BitInputStream bdSource=new ByteArrayBitInputStream(header);
214
215 int capture=bdSource.getInt(32);
216
217 if(capture!=0x5367674f) {
218 //throw new FormatException("Ogg page does not start with 'OggS' (0x4f676753)");
219
220 /*
221 ** This condition is IMHO an error, but older Ogg files often contain
222 ** pages with a different capture than OggS. I am not sure how to
223 ** manage these pages, but the decoder seems to work properly, if
224 ** the incorrect capture is simply ignored.
225 */
226
227 String cs=Integer.toHexString(capture);
228 while(cs.length()<8) {
229 cs="0"+cs;
230 }
231 cs=cs.substring(6, 8)+cs.substring(4, 6)+cs.substring(2, 4)+cs.substring(0, 2);
232 char c1=(char)(Integer.valueOf(cs.substring(0, 2), 16).intValue());
233 char c2=(char)(Integer.valueOf(cs.substring(2, 4), 16).intValue());
234 char c3=(char)(Integer.valueOf(cs.substring(4, 6), 16).intValue());
235 char c4=(char)(Integer.valueOf(cs.substring(6, 8), 16).intValue());
236 System.out.println("Ogg packet header is 0x"+cs+" ("+c1+c2+c3+c4+"), should be 0x4f676753 (OggS)");
237 }
238
239 int version=bdSource.getInt(8);
240 byte tmp=(byte)bdSource.getInt(8);
241 boolean bf1=(tmp&1)!=0;
242 boolean bos=(tmp&2)!=0;
243 boolean eos=(tmp&4)!=0;
244 long absoluteGranulePosition=bdSource.getLong(64);
245 int streamSerialNumber=bdSource.getInt(32);
246 int pageSequenceNumber=bdSource.getInt(32);
247 int pageCheckSum=bdSource.getInt(32);
248 int pageSegments=bdSource.getInt(8);
249
250 //System.out.println("OggPage: "+streamSerialNumber+" / "+absoluteGranulePosition+" / "+pageSequenceNumber);
251
252 int[] segmentOffsets=new int[pageSegments];
253 int[] segmentLengths=new int[pageSegments];
254 int totalLength=0;
255
256 byte[] segmentTable=new byte[pageSegments];
257 byte[] tmpBuf=new byte[1];
258
259 for(int i=0; i<pageSegments; i++) {
260 int l=0;
261 if(source instanceof RandomAccessFile) {
262 l=((int)((RandomAccessFile)source).readByte()&0xff);
263 }
264 else if(source instanceof InputStream) {
265 l=(int)((InputStream)source).read();
266 }
267 else if(source instanceof byte[]) {
268 l=(int)((byte[])source)[sourceOffset++];
269 l&=255;
270 }
271 segmentTable[i]=(byte)l;
272 segmentLengths[i]=l;
273 segmentOffsets[i]=totalLength;
274 totalLength+=l;
275 }
276
277 byte[] data=null;
278
279 if(!skipData) {
280
281 //System.out.println("createPage: "+absoluteGranulePosition*1000/44100);
282
283 data=new byte[totalLength];
284 //source.read(data, 0, totalLength);
285 if(source instanceof RandomAccessFile) {
286 ((RandomAccessFile)source).readFully(data);
287 }
288 else if(source instanceof InputStream) {
289 readFully((InputStream)source, data);
290 }
291 else if(source instanceof byte[]) {
292 System.arraycopy(source, sourceOffset, data, 0, totalLength);
293 }
294 }
295
296 return new OggPage(version, bf1, bos, eos, absoluteGranulePosition, streamSerialNumber, pageSequenceNumber, pageCheckSum, segmentOffsets, segmentLengths, totalLength, header, segmentTable, data);
297 }
298 catch(EOFException e) {
299 throw new EndOfOggStreamException();
300 }
301 }
302
303 private static void readFully(InputStream source, byte[] buffer) throws IOException {
304 int total=0;
305 while(total<buffer.length) {
306 int read=source.read(buffer, total, buffer.length-total);
307 if(read==-1) {
308 throw new EndOfOggStreamException();
309 }
310 total+=read;
311 }
312 }
313
314 /**
315 * Returns the absolute granule position of the last complete
316 * packet contained in this Ogg page, or -1 if the page contains a single
317 * packet, which is not completed on this page. For pages containing Vorbis
318 * data, this value is the sample index within the Vorbis stream. The Vorbis
319 * stream does not necessarily start with sample index 0.
320 *
321 * @return the absolute granule position of the last packet completed on
322 * this page
323 */
324
325
326 public long getAbsoluteGranulePosition() {
327 return absoluteGranulePosition;
328 }
329
330 /**
331 * Returns the stream serial number of this ogg page.
332 *
333 * @return this page's serial number
334 */
335
336 public int getStreamSerialNumber() {
337 return streamSerialNumber;
338 }
339
340 /**
341 * Return the sequnce number of this ogg page.
342 *
343 * @return this page's sequence number
344 */
345
346 public int getPageSequenceNumber() {
347 return pageSequenceNumber;
348 }
349
350 /**
351 * Return the check sum of this ogg page.
352 *
353 * @return this page's check sum
354 */
355
356 public int getPageCheckSum() {
357 return pageCheckSum;
358 }
359
360 /**
361 * @return the total number of bytes in the page data
362 */
363
364
365 public int getTotalLength() {
366 if(data!=null) {
367 return 27+segmentTable.length+data.length;
368 }
369 else {
370 return totalLength;
371 }
372 }
373
374 /**
375 * @return a ByteBuffer containing the page data
376 */
377
378
379 public byte[] getData() {
380 return data;
381 }
382
383 public byte[] getHeader() {
384 return header;
385 }
386
387 public byte[] getSegmentTable() {
388 return segmentTable;
389 }
390
391 public int[] getSegmentOffsets() {
392 return segmentOffsets;
393 }
394
395 public int[] getSegmentLengths() {
396 return segmentLengths;
397 }
398
399 /**
400 * @return <code>true</code> if this page begins with a continued packet
401 */
402
403 public boolean isContinued() {
404 return continued;
405 }
406
407 /**
408 * @return <code>true</code> if this page begins with a fresh packet
409 */
410
411 public boolean isFresh() {
412 return !continued;
413 }
414
415 /**
416 * @return <code>true</code> if this page is the beginning of a logical stream
417 */
418
419 public boolean isBos() {
420 return bos;
421 }
422
423 /**
424 * @return <code>true</code> if this page is the end of a logical stream
425 */
426
427 public boolean isEos() {
428 return eos;
429 }
430
431} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.1 2003/04/10 19:48:22 jarnbjo
25 * no message
26 *
27 * Revision 1.1 2003/03/31 00:23:04 jarnbjo
28 * no message
29 *
30 */
31
32package de.jarnbjo.ogg;
33
34import java.io.*;
35import java.net.*;
36import java.util.*;
37
38/**
39 * Implementation of the <code>PhysicalOggStream</code> interface for reading
40 * an Ogg stream from a URL. This class performs
41 * no internal caching, and will not read data from the network before
42 * requested to do so. It is intended to be used in non-realtime applications
43 * like file download managers or similar.
44 */
45
46public class OnDemandUrlStream implements PhysicalOggStream {
47
48 private boolean closed=false;
49 private URLConnection source;
50 private InputStream sourceStream;
51 private Object drainLock=new Object();
52 private LinkedList pageCache=new LinkedList();
53 private long numberOfSamples=-1;
54 private int contentLength=0;
55 private int position=0;
56
57 private HashMap logicalStreams=new HashMap();
58 private OggPage firstPage;
59
60 private static final int PAGECACHE_SIZE = 20;
61
62 public OnDemandUrlStream(URL source) throws OggFormatException, IOException {
63 this.source=source.openConnection();
64 this.sourceStream=this.source.getInputStream();
65
66 contentLength=this.source.getContentLength();
67
68 firstPage=OggPage.create(sourceStream);
69 position+=firstPage.getTotalLength();
70 LogicalOggStreamImpl los=new LogicalOggStreamImpl(this, firstPage.getStreamSerialNumber());
71 logicalStreams.put(new Integer(firstPage.getStreamSerialNumber()), los);
72 los.checkFormat(firstPage);
73 }
74
75 public Collection getLogicalStreams() {
76 return logicalStreams.values();
77 }
78
79 public boolean isOpen() {
80 return !closed;
81 }
82
83 public void close() throws IOException {
84 closed=true;
85 sourceStream.close();
86 }
87
88 public int getContentLength() {
89 return contentLength;
90 }
91
92 public int getPosition() {
93 return position;
94 }
95
96 int pageNumber=2;
97
98 public OggPage getOggPage(int index) throws IOException {
99 if(firstPage!=null) {
100 OggPage tmp=firstPage;
101 firstPage=null;
102 return tmp;
103 }
104 else {
105 OggPage page=OggPage.create(sourceStream);
106 position+=page.getTotalLength();
107 return page;
108 }
109 }
110
111 private LogicalOggStream getLogicalStream(int serialNumber) {
112 return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
113 }
114
115 public void setTime(long granulePosition) throws IOException {
116 throw new UnsupportedOperationException("Method not supported by this class");
117 }
118
119 /**
120 * @return always <code>false</code>
121 */
122
123 public boolean isSeekable() {
124 return false;
125 }
126
127} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/04/10 19:48:22 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/31 00:23:04 jarnbjo
28 * no message
29 *
30 * Revision 1.1 2003/03/03 21:02:20 jarnbjo
31 * no message
32 *
33 */
34
35package de.jarnbjo.ogg;
36
37import java.io.IOException;
38import java.util.Collection;
39
40/**
41 * Interface providing access to a physical Ogg stream. Typically this is
42 * a file.
43 */
44
45public interface PhysicalOggStream {
46
47 /**
48 * Returns a collection of objects implementing <code>LogicalOggStream</code>
49 * for accessing the separate logical streams within this physical Ogg stream.
50 *
51 * @return a collection of objects implementing <code>LogicalOggStream</code>
52 * which are representing the logical streams contained within this
53 * physical stream
54 *
55 * @see LogicalOggStream
56 */
57
58 public Collection getLogicalStreams();
59
60 /**
61 * Return the Ogg page with the absolute index <code>index</code>,
62 * independent from the logical structure of this stream or if the
63 * index parameter is -1, the next Ogg page is returned.
64 * This method should only be used by implementations of <code>LogicalOggStream</code>
65 * to access the raw pages.
66 *
67 * @param index the absolute index starting from 0 at the beginning of
68 * the file or stream or -1 to get the next page in a non-seekable
69 * stream
70 *
71 * @return the Ogg page with the physical absolute index <code>index</code>
72 *
73 * @throws OggFormatException if the ogg stream is corrupted
74 * @throws IOException if some other IO error occurs
75 */
76
77 public OggPage getOggPage(int index) throws OggFormatException, IOException;
78
79 /**
80 * Checks if this stream is open for reading.
81 *
82 * @return <code>true</code> if this stream is open for reading,
83 * <code>false</code> otherwise
84 */
85
86 public boolean isOpen();
87
88 /**
89 * Closes this stream. After invoking this method, no further access
90 * to the streams data is possible.
91 *
92 * @throws IOException
93 */
94
95 public void close() throws IOException;
96
97 /**
98 * Sets this stream's (and its logical stream's) position to the granule
99 * position. The next packet read from any logical stream will be the
100 * first packet beginning on the first page with a granule position higher
101 * than the argument.<br><br>
102 *
103 * At the moment, this method only works correctly for Ogg files with
104 * a single logical Vorbis stream, and due to the different interpretations
105 * of the granule position, depending on mixed content, this method will
106 * never be able to work for mixed streams. Chained and interleaved streams are
107 * also not yet supported. Actually, this method is only a hack to support
108 * seeking from JMF, but may of course be abused otherwise too :)
109 *
110 * @param granulePosition
111 *
112 * @throws OggFormatException if the ogg stream is corrupted
113 * @throws IOException if some other IO error occurs
114 */
115
116 public void setTime(long granulePosition) throws OggFormatException, IOException;
117
118 /**
119 * @return <code>true</code> if the stream is seekable, <code>false</code>
120 * otherwise
121 */
122
123 public boolean isSeekable();
124} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.1 2003/04/10 19:48:22 jarnbjo
25 * no message
26 *
27 */
28
29package de.jarnbjo.ogg;
30
31import java.io.*;
32import java.net.*;
33import java.util.*;
34
35/**
36 * Implementation of the <code>PhysicalOggStream</code> interface for reading
37 * an Ogg stream from a URL. This class performs only the necessary caching
38 * to provide continous playback. Seeking within the stream is not supported.
39 */
40
41public class UncachedUrlStream implements PhysicalOggStream {
42
43 private boolean closed=false;
44 private URLConnection source;
45 private InputStream sourceStream;
46 private Object drainLock=new Object();
47 private LinkedList pageCache=new LinkedList();
48 private long numberOfSamples=-1;
49
50 private HashMap logicalStreams=new HashMap();
51
52 private LoaderThread loaderThread;
53
54 private static final int PAGECACHE_SIZE = 10;
55
56 /** Creates an instance of the <code>PhysicalOggStream</code> interface
57 * suitable for reading an Ogg stream from a URL.
58 */
59
60 public UncachedUrlStream(URL source) throws OggFormatException, IOException {
61
62 this.source=source.openConnection();
63 this.sourceStream=this.source.getInputStream();
64
65 loaderThread=new LoaderThread(sourceStream, pageCache);
66 new Thread(loaderThread).start();
67
68 while(!loaderThread.isBosDone() || pageCache.size()<PAGECACHE_SIZE) {
69 try {
70 Thread.sleep(200);
71 }
72 catch (InterruptedException ex) {
73 }
74 //System.out.print("caching "+pageCache.size()+"/"+PAGECACHE_SIZE+" pages\r");
75 }
76 //System.out.println();
77 }
78
79 public Collection getLogicalStreams() {
80 return logicalStreams.values();
81 }
82
83 public boolean isOpen() {
84 return !closed;
85 }
86
87 public void close() throws IOException {
88 closed=true;
89 sourceStream.close();
90 }
91
92 /*
93 public long getCacheLength() {
94 return cacheLength;
95 }
96 */
97
98 /*
99 private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
100 return getNextPage(false);
101 }
102
103 private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
104 return OggPage.create(sourceStream, skipData);
105 }
106 */
107
108 public OggPage getOggPage(int index) throws IOException {
109 while(pageCache.size()==0) {
110 try {
111 Thread.sleep(100);
112 }
113 catch (InterruptedException ex) {
114 }
115 }
116 synchronized(drainLock) {
117 //OggPage page=(OggPage)pageCache.getFirst();
118 //pageCache.removeFirst();
119 //return page;
120 return (OggPage)pageCache.removeFirst();
121 }
122 }
123
124 private LogicalOggStream getLogicalStream(int serialNumber) {
125 return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
126 }
127
128 public void setTime(long granulePosition) throws IOException {
129 throw new UnsupportedOperationException("Method not supported by this class");
130 }
131
132 public class LoaderThread implements Runnable {
133
134 private InputStream source;
135 private LinkedList pageCache;
136 private RandomAccessFile drain;
137 private byte[] memoryCache;
138
139 private boolean bosDone=false;
140
141 private int pageNumber;
142
143 public LoaderThread(InputStream source, LinkedList pageCache) {
144 this.source=source;
145 this.pageCache=pageCache;
146 }
147
148 public void run() {
149 try {
150 boolean eos=false;
151 byte[] buffer=new byte[8192];
152 while(!eos) {
153 OggPage op=OggPage.create(source);
154 synchronized (drainLock) {
155 pageCache.add(op);
156 }
157
158 if(!op.isBos()) {
159 bosDone=true;
160 }
161 if(op.isEos()) {
162 eos=true;
163 }
164
165 LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
166 if(los==null) {
167 los=new LogicalOggStreamImpl(UncachedUrlStream.this, op.getStreamSerialNumber());
168 logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
169 los.checkFormat(op);
170 }
171
172 //los.addPageNumberMapping(pageNumber);
173 //los.addGranulePosition(op.getAbsoluteGranulePosition());
174
175 pageNumber++;
176
177 while(pageCache.size()>PAGECACHE_SIZE) {
178 try {
179 Thread.sleep(200);
180 }
181 catch (InterruptedException ex) {
182 }
183 }
184 }
185 }
186 catch(EndOfOggStreamException e) {
187 // ok
188 }
189 catch(IOException e) {
190 e.printStackTrace();
191 }
192 }
193
194 public boolean isBosDone() {
195 return bosDone;
196 }
197 }
198
199 /**
200 * @return always <code>false</code>
201 */
202
203 public boolean isSeekable() {
204 return false;
205 }
206
207} \ 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 @@
1package de.jarnbjo.util.audio;
2
3import java.io.*;
4import javax.sound.sampled.*;
5
6public class FadeableAudioInputStream extends AudioInputStream {
7
8 private AudioInputStream stream;
9 private boolean fading=false;
10 private double phi=0.0;
11
12 public FadeableAudioInputStream(AudioInputStream stream) throws IOException {
13 super(stream, stream.getFormat(), -1L);
14 }
15
16 public void fadeOut() {
17 fading=true;
18 phi=0.0;
19 }
20
21 public int read(byte[] b) throws IOException {
22 return read(b, 0, b.length);
23 }
24
25 public int read(byte[] b, int offset, int length) throws IOException {
26 int read=super.read(b, offset, length);
27
28 //System.out.println("read "+read);
29
30 if(fading) {
31 int j=0, l=0, r=0;
32 double gain=0.0;
33
34 for(int i=offset; i<offset+read; i+=4) {
35 j=i;
36 l=((int)b[j++])&0xff;
37 l|=((int)b[j++])<<8;
38 r=((int)b[j++])&0xff;
39 r|=((int)b[j])<<8;
40
41 if(phi<Math.PI/2) {
42 phi+=0.000015;
43 }
44
45 gain=Math.cos(phi);
46 //System.out.println("gain "+gain);
47
48 l=(int)(l*gain);
49 r=(int)(r*gain);
50
51 j=i;
52 b[j++]=(byte)(l&0xff);
53 b[j++]=(byte)((l>>8)&0xff);
54 b[j++]=(byte)(r&0xff);
55 b[j++]=(byte)((r>>8)&0xff);
56 }
57 }
58
59 return read;
60 }
61
62} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.5 2003/04/10 19:48:31 jarnbjo
25 * no message
26 *
27 * Revision 1.4 2003/03/16 20:57:06 jarnbjo
28 * no message
29 *
30 * Revision 1.3 2003/03/16 20:56:56 jarnbjo
31 * no message
32 *
33 * Revision 1.2 2003/03/16 01:11:39 jarnbjo
34 * no message
35 *
36 * Revision 1.1 2003/03/03 21:02:20 jarnbjo
37 * no message
38 *
39 */
40
41package de.jarnbjo.util.io;
42
43import java.io.IOException;
44
45/**
46 * An interface with methods allowing bit-wise reading from
47 * an input stream. All methods in this interface are optional
48 * and an implementation not support a method or a specific state
49 * (e.g. endian) will throw an UnspportedOperationException if
50 * such a method is being called. This should be speicified in
51 * the implementation documentation.
52 */
53
54public interface BitInputStream {
55
56 /**
57 * constant for setting this stream's mode to little endian
58 *
59 * @see #setEndian(int)
60 */
61
62 public static final int LITTLE_ENDIAN = 0;
63
64 /**
65 * constant for setting this stream's mode to big endian
66 *
67 * @see #setEndian(int)
68 */
69
70 public static final int BIG_ENDIAN = 1;
71
72 /**
73 * reads one bit (as a boolean) from the input stream
74 *
75 * @return <code>true</code> if the next bit is 1,
76 * <code>false</code> otherwise
77 *
78 * @throws IOException if an I/O error occurs
79 * @throws UnsupportedOperationException if the method is not supported by the implementation
80 */
81
82 public boolean getBit() throws IOException;
83
84 /**
85 * reads <code>bits</code> number of bits from the input
86 * stream
87 *
88 * @return the unsigned integer value read from the stream
89 *
90 * @throws IOException if an I/O error occurs
91 * @throws UnsupportedOperationException if the method is not supported by the implementation
92 */
93
94 public int getInt(int bits) throws IOException;
95
96 /**
97 * reads <code>bits</code> number of bits from the input
98 * stream
99 *
100 * @return the signed integer value read from the stream
101 *
102 * @throws IOException if an I/O error occurs
103 * @throws UnsupportedOperationException if the method is not supported by the implementation
104 */
105
106 public int getSignedInt(int bits) throws IOException;
107
108 /**
109 * reads a huffman codeword based on the <code>root</code>
110 * parameter and returns the decoded value
111 *
112 * @param root the root of the Huffman tree used to decode the codeword
113 * @return the decoded unsigned integer value read from the stream
114 *
115 * @throws IOException if an I/O error occurs
116 * @throws UnsupportedOperationException if the method is not supported by the implementation
117 */
118
119 public int getInt(HuffmanNode root) throws IOException;
120
121 /**
122 * reads an integer encoded as "signed rice" as described in
123 * the FLAC audio format specification
124 *
125 * @param order
126 * @return the decoded integer value read from the stream
127 *
128 * @throws IOException if an I/O error occurs
129 * @throws UnsupportedOperationException if the method is not supported by the implementation
130 */
131
132 public int readSignedRice(int order) throws IOException;
133
134 /**
135 * fills the array from <code>offset</code> with <code>len</code>
136 * integers encoded as "signed rice" as described in
137 * the FLAC audio format specification
138 *
139 * @param order
140 * @param buffer
141 * @param offset
142 * @param len
143 * @return the decoded integer value read from the stream
144 *
145 * @throws IOException if an I/O error occurs
146 * @throws UnsupportedOperationException if the method is not supported by the implementation
147 */
148
149 public void readSignedRice(int order, int[] buffer, int offset, int len) throws IOException;
150
151 /**
152 * reads <code>bits</code> number of bits from the input
153 * stream
154 *
155 * @return the unsigned long value read from the stream
156 *
157 * @throws IOException if an I/O error occurs
158 * @throws UnsupportedOperationException if the method is not supported by the implementation
159 */
160
161 public long getLong(int bits) throws IOException;
162
163 /**
164 * causes the read pointer to be moved to the beginning
165 * of the next byte, remaining bits in the current byte
166 * are discarded
167 *
168 * @throws UnsupportedOperationException if the method is not supported by the implementation
169 */
170
171 public void align();
172
173 /**
174 * changes the endian mode used when reading bit-wise from
175 * the stream, changing the mode mid-stream will cause the
176 * read cursor to move to the beginning of the next byte
177 * (as if calling the <code>allign</code> method
178 *
179 * @see #align()
180 *
181 * @throws UnsupportedOperationException if the method is not supported by the implementation
182 */
183
184 public void setEndian(int endian);
185} \ 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 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/04/10 19:48:31 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/16 01:11:39 jarnbjo
28 * no message
29 *
30 * Revision 1.1 2003/03/03 21:02:20 jarnbjo
31 * no message
32 *
33 */
34
35package de.jarnbjo.util.io;
36
37import java.io.IOException;
38
39/**
40 * Implementation of the <code>BitInputStream</code> interface,
41 * using a byte array as data source.
42*/
43
44public class ByteArrayBitInputStream implements BitInputStream {
45
46 private byte[] source;
47 private byte currentByte;
48
49 private int endian;
50
51 private int byteIndex=0;
52 private int bitIndex=0;
53
54 public ByteArrayBitInputStream(byte[] source) {
55 this(source, LITTLE_ENDIAN);
56 }
57
58 public ByteArrayBitInputStream(byte[] source, int endian) {
59 this.endian=endian;
60 this.source=source;
61 currentByte=source[0];
62 bitIndex=(endian==LITTLE_ENDIAN)?0:7;
63 }
64
65 public boolean getBit() throws IOException {
66 if(endian==LITTLE_ENDIAN) {
67 if(bitIndex>7) {
68 bitIndex=0;
69 currentByte=source[++byteIndex];
70 }
71 return (currentByte&(1<<(bitIndex++)))!=0;
72 }
73 else {
74 if(bitIndex<0) {
75 bitIndex=7;
76 currentByte=source[++byteIndex];
77 }
78 return (currentByte&(1<<(bitIndex--)))!=0;
79 }
80 }
81
82 public int getInt(int bits) throws IOException {
83 if(bits>32) {
84 throw new IllegalArgumentException("Argument \"bits\" must be <= 32");
85 }
86 int res=0;
87 if(endian==LITTLE_ENDIAN) {
88 for(int i=0; i<bits; i++) {
89 if(getBit()) {
90 res|=(1<<i);
91 }
92 }
93 }
94 else {
95 if(bitIndex<0) {
96 bitIndex=7;
97 currentByte=source[++byteIndex];
98 }
99 if(bits<=bitIndex+1) {
100 int ci=((int)currentByte)&0xff;
101 int offset=1+bitIndex-bits;
102 int mask=((1<<bits)-1)<<offset;
103 res=(ci&mask)>>offset;
104 bitIndex-=bits;
105 }
106 else {
107 res=(((int)currentByte)&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
108 bits-=bitIndex+1;
109 currentByte=source[++byteIndex];
110 while(bits>=8) {
111 bits-=8;
112 res|=(((int)source[byteIndex])&0xff)<<bits;
113 currentByte=source[++byteIndex];
114 }
115 if(bits>0) {
116 int ci=((int)source[byteIndex])&0xff;
117 res|=(ci>>(8-bits))&((1<<bits)-1);
118 bitIndex=7-bits;
119 }
120 else {
121 currentByte=source[--byteIndex];
122 bitIndex=-1;
123 }
124 }
125 }
126
127 return res;
128 }
129
130 public int getSignedInt(int bits) throws IOException {
131 int raw=getInt(bits);
132 if(raw>=1<<(bits-1)) {
133 raw-=1<<bits;
134 }
135 return raw;
136 }
137
138 public int getInt(HuffmanNode root) throws IOException {
139 while(root.value==null) {
140 if(bitIndex>7) {
141 bitIndex=0;
142 currentByte=source[++byteIndex];
143 }
144 root=(currentByte&(1<<(bitIndex++)))!=0?root.o1:root.o0;
145 }
146 return root.value.intValue();
147 }
148
149 public long getLong(int bits) throws IOException {
150 if(bits>64) {
151 throw new IllegalArgumentException("Argument \"bits\" must be <= 64");
152 }
153 long res=0;
154 if(endian==LITTLE_ENDIAN) {
155 for(int i=0; i<bits; i++) {
156 if(getBit()) {
157 res|=(1L<<i);
158 }
159 }
160 }
161 else {
162 for(int i=bits-1; i>=0; i--) {
163 if(getBit()) {
164 res|=(1L<<i);
165 }
166 }
167 }
168 return res;
169 }
170
171 /**
172 * <p>reads an integer encoded as "signed rice" as described in
173 * the FLAC audio format specification</p>
174 *
175 * <p><b>not supported for little endian</b></p>
176 *
177 * @param order
178 * @return the decoded integer value read from the stream
179 *
180 * @throws IOException if an I/O error occurs
181 * @throws UnsupportedOperationException if the method is not supported by the implementation
182 */
183
184 public int readSignedRice(int order) throws IOException {
185
186 int msbs=-1, lsbs=0, res=0;
187
188 if(endian==LITTLE_ENDIAN) {
189 // little endian
190 throw new UnsupportedOperationException("ByteArrayBitInputStream.readSignedRice() is only supported in big endian mode");
191 }
192 else {
193 // big endian
194
195 byte cb=source[byteIndex];
196 do {
197 msbs++;
198 if(bitIndex<0) {
199 bitIndex=7;
200 byteIndex++;
201 cb=source[byteIndex];
202 }
203 } while((cb&(1<<bitIndex--))==0);
204
205 int bits=order;
206
207 if(bitIndex<0) {
208 bitIndex=7;
209 byteIndex++;
210 }
211 if(bits<=bitIndex+1) {
212 int ci=((int)source[byteIndex])&0xff;
213 int offset=1+bitIndex-bits;
214 int mask=((1<<bits)-1)<<offset;
215 lsbs=(ci&mask)>>offset;
216 bitIndex-=bits;
217 }
218 else {
219 lsbs=(((int)source[byteIndex])&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
220 bits-=bitIndex+1;
221 byteIndex++;
222 while(bits>=8) {
223 bits-=8;
224 lsbs|=(((int)source[byteIndex])&0xff)<<bits;
225 byteIndex++;
226 }
227 if(bits>0) {
228 int ci=((int)source[byteIndex])&0xff;
229 lsbs|=(ci>>(8-bits))&((1<<bits)-1);
230 bitIndex=7-bits;
231 }
232 else {
233 byteIndex--;
234 bitIndex=-1;
235 }
236 }
237
238 res=(msbs<<order)|lsbs;
239 }
240
241 return (res&1)==1?-(res>>1)-1:(res>>1);
242 }
243
244 /**
245 * <p>fills the array from <code>offset</code> with <code>len</code>
246 * integers encoded as "signed rice" as described in
247 * the FLAC audio format specification</p>
248 *
249 * <p><b>not supported for little endian</b></p>
250 *
251 * @param order
252 * @param buffer
253 * @param offset
254 * @param len
255 * @return the decoded integer value read from the stream
256 *
257 * @throws IOException if an I/O error occurs
258 * @throws UnsupportedOperationException if the method is not supported by the implementation
259 */
260
261 public void readSignedRice(int order, int[] buffer, int off, int len) throws IOException {
262
263 if(endian==LITTLE_ENDIAN) {
264 // little endian
265 throw new UnsupportedOperationException("ByteArrayBitInputStream.readSignedRice() is only supported in big endian mode");
266 }
267 else {
268 // big endian
269 for(int i=off; i<off+len; i++) {
270
271 int msbs=-1, lsbs=0;
272
273 byte cb=source[byteIndex];
274 do {
275 msbs++;
276 if(bitIndex<0) {
277 bitIndex=7;
278 byteIndex++;
279 cb=source[byteIndex];
280 }
281 } while((cb&(1<<bitIndex--))==0);
282
283 int bits=order;
284
285 if(bitIndex<0) {
286 bitIndex=7;
287 byteIndex++;
288 }
289 if(bits<=bitIndex+1) {
290 int ci=((int)source[byteIndex])&0xff;
291 int offset=1+bitIndex-bits;
292 int mask=((1<<bits)-1)<<offset;
293 lsbs=(ci&mask)>>offset;
294 bitIndex-=bits;
295 }
296 else {
297 lsbs=(((int)source[byteIndex])&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
298 bits-=bitIndex+1;
299 byteIndex++;
300 while(bits>=8) {
301 bits-=8;
302 lsbs|=(((int)source[byteIndex])&0xff)<<bits;
303 byteIndex++;
304 }
305 if(bits>0) {
306 int ci=((int)source[byteIndex])&0xff;
307 lsbs|=(ci>>(8-bits))&((1<<bits)-1);
308 bitIndex=7-bits;
309 }
310 else {
311 byteIndex--;
312 bitIndex=-1;
313 }
314 }
315
316 int res=(msbs<<order)|lsbs;
317 buffer[i]=(res&1)==1?-(res>>1)-1:(res>>1);
318 }
319 }
320 }
321
322 public void align() {
323 if(endian==BIG_ENDIAN && bitIndex>=0) {
324 bitIndex=7;
325 byteIndex++;
326 }
327 else if(endian==LITTLE_ENDIAN && bitIndex<=7) {
328 bitIndex=0;
329 byteIndex++;
330 }
331 }
332
333 public void setEndian(int endian) {
334 if(this.endian==BIG_ENDIAN && endian==LITTLE_ENDIAN) {
335 bitIndex=0;
336 byteIndex++;
337 }
338 else if(this.endian==LITTLE_ENDIAN && endian==BIG_ENDIAN) {
339 bitIndex=7;
340 byteIndex++;
341 }
342 this.endian=endian;
343 }
344
345 /**
346 * @return the byte array used as a source for this instance
347 */
348
349 public byte[] getSource() {
350 return source;
351 }
352} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/util/io/HuffmanNode.java b/songdbj/de/jarnbjo/util/io/HuffmanNode.java
new file mode 100644
index 0000000000..88600a4ddd
--- /dev/null
+++ b/songdbj/de/jarnbjo/util/io/HuffmanNode.java
@@ -0,0 +1,144 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/04/10 19:48:31 jarnbjo
25 * no message
26 *
27 */
28
29package de.jarnbjo.util.io;
30
31import java.io.IOException;
32import de.jarnbjo.util.io.BitInputStream;
33
34/**
35 * Representation of a node in a Huffman tree, used to read
36 * Huffman compressed codewords from e.g. a Vorbis stream.
37 */
38
39final public class HuffmanNode {
40
41 private HuffmanNode parent;
42 private int depth=0;
43 protected HuffmanNode o0, o1;
44 protected Integer value;
45 private boolean full=false;
46
47 /**
48 * creates a new Huffman tree root node
49 */
50
51 public HuffmanNode() {
52 this(null);
53 }
54
55 protected HuffmanNode(HuffmanNode parent) {
56 this.parent=parent;
57 if(parent!=null) {
58 depth=parent.getDepth()+1;
59 }
60 }
61
62 protected HuffmanNode(HuffmanNode parent, int value) {
63 this(parent);
64 this.value=new Integer(value);
65 full=true;
66 }
67
68 protected int read(BitInputStream bis) throws IOException {
69 HuffmanNode iter=this;
70 while(iter.value==null) {
71 iter=bis.getBit()?iter.o1:iter.o0;
72 }
73 return iter.value.intValue();
74 }
75
76 protected HuffmanNode get0() {
77 return o0==null?set0(new HuffmanNode(this)):o0;
78 }
79
80 protected HuffmanNode get1() {
81 return o1==null?set1(new HuffmanNode(this)):o1;
82 }
83
84 protected Integer getValue() {
85 return value;
86 }
87
88 private HuffmanNode getParent() {
89 return parent;
90 }
91
92 protected int getDepth() {
93 return depth;
94 }
95
96 private boolean isFull() {
97 return full?true:(full=o0!=null&&o0.isFull()&&o1!=null&&o1.isFull());
98 }
99
100 private HuffmanNode set0(HuffmanNode value) {
101 return o0=value;
102 }
103
104 private HuffmanNode set1(HuffmanNode value) {
105 return o1=value;
106 }
107
108 private void setValue(Integer value) {
109 full=true;
110 this.value=value;
111 }
112
113 /**
114 * creates a new tree node at the first free location at the given
115 * depth, and assigns the value to it
116 *
117 * @param depth the tree depth of the new node (codeword length in bits)
118 * @param value the node's new value
119 */
120
121 public boolean setNewValue(int depth, int value) {
122 if(isFull()) {
123 return false;
124 }
125 if(depth==1) {
126 if(o0==null) {
127 set0(new HuffmanNode(this, value));
128 return true;
129 }
130 else if(o1==null) {
131 set1(new HuffmanNode(this, value));
132 return true;
133 }
134 else {
135 return false;
136 }
137 }
138 else {
139 return get0().setNewValue(depth-1, value)?
140 true:
141 get1().setNewValue(depth-1, value);
142 }
143 }
144}
diff --git a/songdbj/de/jarnbjo/vorbis/AudioPacket.java b/songdbj/de/jarnbjo/vorbis/AudioPacket.java
new file mode 100644
index 0000000000..90a54073c1
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/AudioPacket.java
@@ -0,0 +1,328 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37import de.jarnbjo.util.io.BitInputStream;
38
39class AudioPacket {
40
41 private int modeNumber;
42 private Mode mode;
43 private Mapping mapping;
44 private int n; // block size
45 private boolean blockFlag, previousWindowFlag, nextWindowFlag;
46
47 private int windowCenter, leftWindowStart, leftWindowEnd, leftN, rightWindowStart, rightWindowEnd, rightN;
48 private float[] window;
49 private float[][] pcm;
50 private int[][] pcmInt;
51
52 private Floor[] channelFloors;
53 private boolean[] noResidues;
54
55 private final static float[][] windows=new float[8][];
56
57 protected AudioPacket(final VorbisStream vorbis, final BitInputStream source) throws VorbisFormatException, IOException {
58
59 final SetupHeader sHeader=vorbis.getSetupHeader();
60 final IdentificationHeader iHeader=vorbis.getIdentificationHeader();
61 final Mode[] modes=sHeader.getModes();
62 final Mapping[] mappings=sHeader.getMappings();
63 final Residue[] residues=sHeader.getResidues();
64 final int channels=iHeader.getChannels();
65
66 if(source.getInt(1)!=0) {
67 throw new VorbisFormatException("Packet type mismatch when trying to create an audio packet.");
68 }
69
70 modeNumber=source.getInt(Util.ilog(modes.length-1));
71
72 try {
73 mode=modes[modeNumber];
74 }
75 catch(ArrayIndexOutOfBoundsException e) {
76 throw new VorbisFormatException("Reference to invalid mode in audio packet.");
77 }
78
79 mapping=mappings[mode.getMapping()];
80
81 final int[] magnitudes=mapping.getMagnitudes();
82 final int[] angles=mapping.getAngles();
83
84 blockFlag=mode.getBlockFlag();
85
86 final int blockSize0=iHeader.getBlockSize0();
87 final int blockSize1=iHeader.getBlockSize1();
88
89 n=blockFlag?blockSize1:blockSize0;
90
91 if(blockFlag) {
92 previousWindowFlag=source.getBit();
93 nextWindowFlag=source.getBit();
94 }
95
96 windowCenter=n/2;
97
98 if(blockFlag && !previousWindowFlag) {
99 leftWindowStart=n/4-blockSize0/4;
100 leftWindowEnd=n/4+blockSize0/4;
101 leftN=blockSize0/2;
102 }
103 else {
104 leftWindowStart=0;
105 leftWindowEnd=n/2;
106 leftN=windowCenter;
107 }
108
109 if(blockFlag && !nextWindowFlag) {
110 rightWindowStart=n*3/4-blockSize0/4;
111 rightWindowEnd=n*3/4+blockSize0/4;
112 rightN=blockSize0/2;
113 }
114 else {
115 rightWindowStart=windowCenter;
116 rightWindowEnd=n;
117 rightN=n/2;
118 }
119
120 window=getComputedWindow();//new double[n];
121
122 channelFloors=new Floor[channels];
123 noResidues=new boolean[channels];
124
125 pcm=new float[channels][n];
126 pcmInt=new int[channels][n];
127
128 boolean allFloorsEmpty=true;
129
130 for(int i=0; i<channels; i++) {
131 int submapNumber=mapping.getMux()[i];
132 int floorNumber=mapping.getSubmapFloors()[submapNumber];
133 Floor decodedFloor=sHeader.getFloors()[floorNumber].decodeFloor(vorbis, source);
134 channelFloors[i]=decodedFloor;
135 noResidues[i]=decodedFloor==null;
136 if(decodedFloor!=null) {
137 allFloorsEmpty=false;
138 }
139 }
140
141 if(allFloorsEmpty) {
142 return;
143 }
144
145 for(int i=0; i<magnitudes.length; i++) {
146 if(!noResidues[magnitudes[i]] ||
147 !noResidues[angles[i]]) {
148
149 noResidues[magnitudes[i]]=false;
150 noResidues[angles[i]]=false;
151 }
152 }
153
154 Residue[] decodedResidues=new Residue[mapping.getSubmaps()];
155
156 for(int i=0; i<mapping.getSubmaps(); i++) {
157 int ch=0;
158 boolean[] doNotDecodeFlags=new boolean[channels];
159 for(int j=0; j<channels; j++) {
160 if(mapping.getMux()[j]==i) {
161 doNotDecodeFlags[ch++]=noResidues[j];
162 }
163 }
164 int residueNumber=mapping.getSubmapResidues()[i];
165 Residue residue=residues[residueNumber];
166
167 residue.decodeResidue(vorbis, source, mode, ch, doNotDecodeFlags, pcm);
168 }
169
170
171 for(int i=mapping.getCouplingSteps()-1; i>=0; i--) {
172 double newA=0, newM=0;
173 final float[] magnitudeVector=pcm[magnitudes[i]];
174 final float[] angleVector=pcm[angles[i]];
175 for(int j=0; j<magnitudeVector.length; j++) {
176 float a=angleVector[j];
177 float m=magnitudeVector[j];
178 if(a>0) {
179 //magnitudeVector[j]=m;
180 angleVector[j]=m>0?m-a:m+a;
181 }
182 else {
183 magnitudeVector[j]=m>0?m+a:m-a;
184 angleVector[j]=m;
185 }
186 }
187 }
188
189 for(int i=0; i<channels; i++) {
190 if(channelFloors[i]!=null) {
191 channelFloors[i].computeFloor(pcm[i]);
192 }
193 }
194
195 // perform an inverse mdct to all channels
196
197 for(int i=0; i<channels; i++) {
198 MdctFloat mdct=blockFlag?iHeader.getMdct1():iHeader.getMdct0();
199 mdct.imdct(pcm[i], window, pcmInt[i]);
200 }
201
202 }
203
204 private float[] getComputedWindow() {
205 int ix=(blockFlag?4:0)+(previousWindowFlag?2:0)+(nextWindowFlag?1:0);
206 float[] w=windows[ix];
207 if(w==null) {
208 w=new float[n];
209
210 for(int i=0;i<leftN;i++){
211 float x=(float)((i+.5)/leftN*Math.PI/2.);
212 x=(float)Math.sin(x);
213 x*=x;
214 x*=(float)Math.PI/2.;
215 x=(float)Math.sin(x);
216 w[i+leftWindowStart]=x;
217 }
218
219 for(int i=leftWindowEnd; i<rightWindowStart; w[i++]=1.0f);
220
221 for(int i=0;i<rightN;i++){
222 float x=(float)((rightN-i-.5)/rightN*Math.PI/2.);
223 x=(float)Math.sin(x);
224 x*=x;
225 x*=(float)Math.PI/2.;
226 x=(float)Math.sin(x);
227 w[i+rightWindowStart]=x;
228 }
229
230 windows[ix]=w;
231 }
232 return w;
233 }
234
235 protected int getNumberOfSamples() {
236 return rightWindowStart-leftWindowStart;
237 }
238
239 protected int getPcm(final AudioPacket previousPacket, final int[][] buffer) {
240 int channels=pcm.length;
241 int val;
242
243 // copy left window flank and mix with right window flank from
244 // the previous audio packet
245 for(int i=0; i<channels; i++) {
246 int j1=0, j2=previousPacket.rightWindowStart;
247 final int[] ppcm=previousPacket.pcmInt[i];
248 final int[] tpcm=pcmInt[i];
249 final int[] target=buffer[i];
250
251 for(int j=leftWindowStart; j<leftWindowEnd; j++) {
252 val=ppcm[j2++]+tpcm[j];
253 if(val>32767) val=32767;
254 if(val<-32768) val=-32768;
255 target[j1++]=val;
256 }
257 }
258
259 // use System.arraycopy to copy the middle part (if any)
260 // of the window
261 if(leftWindowEnd+1<rightWindowStart) {
262 for(int i=0; i<channels; i++) {
263 System.arraycopy(pcmInt[i], leftWindowEnd, buffer[i], leftWindowEnd-leftWindowStart, rightWindowStart-leftWindowEnd);
264 }
265 }
266
267 return rightWindowStart-leftWindowStart;
268 }
269
270 protected void getPcm(final AudioPacket previousPacket, final byte[] buffer) {
271 int channels=pcm.length;
272 int val;
273
274 // copy left window flank and mix with right window flank from
275 // the previous audio packet
276 for(int i=0; i<channels; i++) {
277 int ix=0, j2=previousPacket.rightWindowStart;
278 final int[] ppcm=previousPacket.pcmInt[i];
279 final int[] tpcm=pcmInt[i];
280 for(int j=leftWindowStart; j<leftWindowEnd; j++) {
281 val=ppcm[j2++]+tpcm[j];
282 if(val>32767) val=32767;
283 if(val<-32768) val=-32768;
284 buffer[ix+(i*2)+1]=(byte)(val&0xff);
285 buffer[ix+(i*2)]=(byte)((val>>8)&0xff);
286 ix+=channels*2;
287 }
288
289 ix=(leftWindowEnd-leftWindowStart)*channels*2;
290 for(int j=leftWindowEnd; j<rightWindowStart; j++) {
291 val=tpcm[j];
292 if(val>32767) val=32767;
293 if(val<-32768) val=-32768;
294 buffer[ix+(i*2)+1]=(byte)(val&0xff);
295 buffer[ix+(i*2)]=(byte)((val>>8)&0xff);
296 ix+=channels*2;
297 }
298 }
299 }
300
301 protected float[] getWindow() {
302 return window;
303 }
304
305 protected int getLeftWindowStart() {
306 return leftWindowStart;
307 }
308
309 protected int getLeftWindowEnd() {
310 return leftWindowEnd;
311 }
312
313 protected int getRightWindowStart() {
314 return rightWindowStart;
315 }
316
317 protected int getRightWindowEnd() {
318 return rightWindowEnd;
319 }
320
321 public int[][] getPcm() {
322 return pcmInt;
323 }
324
325 public float[][] getFreqencyDomain() {
326 return pcm;
327 }
328}
diff --git a/songdbj/de/jarnbjo/vorbis/CodeBook.java b/songdbj/de/jarnbjo/vorbis/CodeBook.java
new file mode 100644
index 0000000000..c865b120ca
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/CodeBook.java
@@ -0,0 +1,275 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.3 2003/04/10 19:49:04 jarnbjo
28 * no message
29 *
30 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
31 * no message
32 *
33 *
34 */
35
36package de.jarnbjo.vorbis;
37
38import java.io.IOException;
39import java.util.Arrays;
40
41import de.jarnbjo.util.io.BitInputStream;
42import de.jarnbjo.util.io.HuffmanNode;
43
44class CodeBook {
45
46 private HuffmanNode huffmanRoot;
47 private int dimensions, entries;
48
49 private int[] entryLengths;
50 private float[][] valueVector;
51
52 protected CodeBook(BitInputStream source) throws VorbisFormatException, IOException {
53
54 // check sync
55 if(source.getInt(24)!=0x564342) {
56 throw new VorbisFormatException("The code book sync pattern is not correct.");
57 }
58
59 dimensions=source.getInt(16);
60 entries=source.getInt(24);
61
62 entryLengths=new int[entries];
63
64 boolean ordered=source.getBit();
65
66 if(ordered) {
67 int cl=source.getInt(5)+1;
68 for(int i=0; i<entryLengths.length; ) {
69 int num=source.getInt(Util.ilog(entryLengths.length-i));
70 if(i+num>entryLengths.length) {
71 throw new VorbisFormatException("The codebook entry length list is longer than the actual number of entry lengths.");
72 }
73 Arrays.fill(entryLengths, i, i+num, cl);
74 cl++;
75 i+=num;
76 }
77 }
78 else {
79 // !ordered
80 boolean sparse=source.getBit();
81
82 if(sparse) {
83 for(int i=0; i<entryLengths.length; i++) {
84 if(source.getBit()) {
85 entryLengths[i]=source.getInt(5)+1;
86 }
87 else {
88 entryLengths[i]=-1;
89 }
90 }
91 }
92 else {
93 // !sparse
94 for(int i=0; i<entryLengths.length; i++) {
95 entryLengths[i]=source.getInt(5)+1;
96 }
97 }
98 }
99
100 if (!createHuffmanTree(entryLengths)) {
101 throw new VorbisFormatException("An exception was thrown when building the codebook Huffman tree.");
102 }
103
104 int codeBookLookupType=source.getInt(4);
105
106 switch(codeBookLookupType) {
107 case 0:
108 // codebook has no scalar vectors to be calculated
109 break;
110 case 1:
111 case 2:
112 float codeBookMinimumValue=Util.float32unpack(source.getInt(32));
113 float codeBookDeltaValue=Util.float32unpack(source.getInt(32));
114
115 int codeBookValueBits=source.getInt(4)+1;
116 boolean codeBookSequenceP=source.getBit();
117
118 int codeBookLookupValues=0;
119
120 if(codeBookLookupType==1) {
121 codeBookLookupValues=Util.lookup1Values(entries, dimensions);
122 }
123 else {
124 codeBookLookupValues=entries*dimensions;
125 }
126
127 int codeBookMultiplicands[]=new int[codeBookLookupValues];
128
129 for(int i=0; i<codeBookMultiplicands.length; i++) {
130 codeBookMultiplicands[i]=source.getInt(codeBookValueBits);
131 }
132
133 valueVector=new float[entries][dimensions];
134
135 if(codeBookLookupType==1) {
136 for(int i=0; i<entries; i++) {
137 float last=0;
138 int indexDivisor=1;
139 for(int j=0; j<dimensions; j++) {
140 int multiplicandOffset=
141 (i/indexDivisor)%codeBookLookupValues;
142 valueVector[i][j]=
143 codeBookMultiplicands[multiplicandOffset]*codeBookDeltaValue+codeBookMinimumValue+last;
144 if(codeBookSequenceP) {
145 last=valueVector[i][j];
146 }
147 indexDivisor*=codeBookLookupValues;
148 }
149 }
150 }
151 else {
152 throw new UnsupportedOperationException();
153 /** @todo implement */
154 }
155 break;
156 default:
157 throw new VorbisFormatException("Unsupported codebook lookup type: "+codeBookLookupType);
158 }
159 }
160
161 private static long totalTime=0;
162
163 private boolean createHuffmanTree(int[] entryLengths) {
164 huffmanRoot=new HuffmanNode();
165 for(int i=0; i<entryLengths.length; i++) {
166 int el=entryLengths[i];
167 if(el>0) {
168 if(!huffmanRoot.setNewValue(el, i)) {
169 return false;
170 }
171 }
172 }
173 return true;
174 }
175
176 protected int getDimensions() {
177 return dimensions;
178 }
179
180 protected int getEntries() {
181 return entries;
182 }
183
184 protected HuffmanNode getHuffmanRoot() {
185 return huffmanRoot;
186 }
187
188 //public float[] readVQ(ReadableBitChannel source) throws IOException {
189 // return valueVector[readInt(source)];
190 //}
191
192 protected int readInt(final BitInputStream source) throws IOException {
193 return source.getInt(huffmanRoot);
194 /*
195 HuffmanNode node;
196 for(node=huffmanRoot; node.value==null; node=source.getBit()?node.o1:node.o0);
197 return node.value.intValue();
198 */
199 }
200
201 protected void readVvAdd(float[][] a, BitInputStream source, int offset, int length)
202 throws VorbisFormatException, IOException {
203
204 int i,j;//k;//entry;
205 int chptr=0;
206 int ch=a.length;
207
208 if(ch==0) {
209 return;
210 }
211
212 int lim=(offset+length)/ch;
213
214 for(i=offset/ch;i<lim;){
215 final float[] ve=valueVector[source.getInt(huffmanRoot)];
216 for(j=0;j<dimensions;j++){
217 a[chptr++][i]+=ve[j];
218 if(chptr==ch){
219 chptr=0;
220 i++;
221 }
222 }
223 }
224 }
225
226 /*
227 public void readVAdd(double[] a, ReadableBitChannel source, int offset, int length)
228 throws FormatException, IOException {
229
230 int i,j,entry;
231 int t;
232
233 if(dimensions>8){
234 for(i=0;i<length;){
235 entry = readInt(source);
236 //if(entry==-1)return(-1);
237 //t=entry*dimensions;
238 for(j=0;j<dimensions;){
239 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
240 }
241 }
242 }
243 else{
244 for(i=0;i<length;){
245 entry=readInt(source);
246 //if(entry==-1)return(-1);
247 //t=entry*dim;
248 j=0;
249 switch(dimensions){
250 case 8:
251 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
252 case 7:
253 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
254 case 6:
255 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
256 case 5:
257 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
258 case 4:
259 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
260 case 3:
261 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
262 case 2:
263 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
264 case 1:
265 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
266 case 0:
267 break;
268 }
269 }
270 }
271 }
272 */
273
274
275} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/CommentHeader.java b/songdbj/de/jarnbjo/vorbis/CommentHeader.java
new file mode 100644
index 0000000000..dd00ebca38
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/CommentHeader.java
@@ -0,0 +1,244 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.*;
33
34import java.util.*;
35
36import de.jarnbjo.util.io.BitInputStream;
37
38/**
39 */
40
41public class CommentHeader {
42
43 public static final String TITLE = "TITLE";
44 public static final String ARTIST = "ARTIST";
45 public static final String ALBUM = "ALBUM";
46 public static final String TRACKNUMBER = "TRACKNUMBER";
47 public static final String VERSION = "VERSION";
48 public static final String PERFORMER = "PERFORMER";
49 public static final String COPYRIGHT = "COPYRIGHT";
50 public static final String LICENSE = "LICENSE";
51 public static final String ORGANIZATION = "ORGANIZATION";
52 public static final String DESCRIPTION = "DESCRIPTION";
53 public static final String GENRE = "GENRE";
54 public static final String DATE = "DATE";
55 public static final String LOCATION = "LOCATION";
56 public static final String CONTACT = "CONTACT";
57 public static final String ISRC = "ISRC";
58
59 private String vendor;
60 private HashMap comments=new HashMap();
61 private boolean framingBit;
62
63 private static final long HEADER = 0x736962726f76L; // 'vorbis'
64
65 public CommentHeader(BitInputStream source) throws VorbisFormatException, IOException {
66 if(source.getLong(48)!=HEADER) {
67 throw new VorbisFormatException("The identification header has an illegal leading.");
68 }
69
70 vendor=getString(source);
71
72 int ucLength=source.getInt(32);
73
74 for(int i=0; i<ucLength; i++) {
75 String comment=getString(source);
76 int ix=comment.indexOf('=');
77 String key=comment.substring(0, ix);
78 String value=comment.substring(ix+1);
79 //comments.put(key, value);
80 addComment(key, value);
81 }
82
83 framingBit=source.getInt(8)!=0;
84 }
85
86 private void addComment(String key, String value) {
87 key = key.toUpperCase(); // Comment keys are case insensitive
88 ArrayList al=(ArrayList)comments.get(key);
89 if(al==null) {
90 al=new ArrayList();
91 comments.put(key, al);
92 }
93 al.add(value);
94 }
95
96 public String getVendor() {
97 return vendor;
98 }
99
100 public String getComment(String key) {
101 ArrayList al=(ArrayList)comments.get(key);
102 return al==null?(String)null:(String)al.get(0);
103 }
104
105 public String[] getComments(String key) {
106 ArrayList al=(ArrayList)comments.get(key);
107 return al==null?new String[0]:(String[])al.toArray(new String[al.size()]);
108 }
109
110 public String getTitle() {
111 return getComment(TITLE);
112 }
113
114 public String[] getTitles() {
115 return getComments(TITLE);
116 }
117
118 public String getVersion() {
119 return getComment(VERSION);
120 }
121
122 public String[] getVersions() {
123 return getComments(VERSION);
124 }
125
126 public String getAlbum() {
127 return getComment(ALBUM);
128 }
129
130 public String[] getAlbums() {
131 return getComments(ALBUM);
132 }
133
134 public String getTrackNumber() {
135 return getComment(TRACKNUMBER);
136 }
137
138 public String[] getTrackNumbers() {
139 return getComments(TRACKNUMBER);
140 }
141
142 public String getArtist() {
143 return getComment(ARTIST);
144 }
145
146 public String[] getArtists() {
147 return getComments(ARTIST);
148 }
149
150 public String getPerformer() {
151 return getComment(PERFORMER);
152 }
153
154 public String[] getPerformers() {
155 return getComments(PERFORMER);
156 }
157
158 public String getCopyright() {
159 return getComment(COPYRIGHT);
160 }
161
162 public String[] getCopyrights() {
163 return getComments(COPYRIGHT);
164 }
165
166 public String getLicense() {
167 return getComment(LICENSE);
168 }
169
170 public String[] getLicenses() {
171 return getComments(LICENSE);
172 }
173
174 public String getOrganization() {
175 return getComment(ORGANIZATION);
176 }
177
178 public String[] getOrganizations() {
179 return getComments(ORGANIZATION);
180 }
181
182 public String getDescription() {
183 return getComment(DESCRIPTION);
184 }
185
186 public String[] getDescriptions() {
187 return getComments(DESCRIPTION);
188 }
189
190 public String getGenre() {
191 return getComment(GENRE);
192 }
193
194 public String[] getGenres() {
195 return getComments(GENRE);
196 }
197
198 public String getDate() {
199 return getComment(DATE);
200 }
201
202 public String[] getDates() {
203 return getComments(DATE);
204 }
205
206 public String getLocation() {
207 return getComment(LOCATION);
208 }
209
210 public String[] getLocations() {
211 return getComments(LOCATION);
212 }
213
214 public String getContact() {
215 return getComment(CONTACT);
216 }
217
218 public String[] getContacts() {
219 return getComments(CONTACT);
220 }
221
222 public String getIsrc() {
223 return getComment(ISRC);
224 }
225
226 public String[] getIsrcs() {
227 return getComments(ISRC);
228 }
229
230
231 private String getString(BitInputStream source) throws IOException, VorbisFormatException {
232
233 int length=source.getInt(32);
234
235 byte[] strArray=new byte[length];
236
237 for(int i=0; i<length; i++) {
238 strArray[i]=(byte)source.getInt(8);
239 }
240
241 return new String(strArray, "UTF-8");
242 }
243
244} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Floor.java b/songdbj/de/jarnbjo/vorbis/Floor.java
new file mode 100644
index 0000000000..5be2798dfb
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Floor.java
@@ -0,0 +1,124 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/04/10 19:49:04 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37import de.jarnbjo.util.io.BitInputStream;
38
39
40public abstract class Floor {
41
42 public final static float[] DB_STATIC_TABLE={
43 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f,
44 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f,
45 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.128753e-07f,
46 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f,
47 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f,
48 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f,
49 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f,
50 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f,
51 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f,
52 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f,
53 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f,
54 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f,
55 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f,
56 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f,
57 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f,
58 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f,
59 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f,
60 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f,
61 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f,
62 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f,
63 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f,
64 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f,
65 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f,
66 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f,
67 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f,
68 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f,
69 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f,
70 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f,
71 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f,
72 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f,
73 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f,
74 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f,
75 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f,
76 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f,
77 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f,
78 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f,
79 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f,
80 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f,
81 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f,
82 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f,
83 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f,
84 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f,
85 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f,
86 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f,
87 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f,
88 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f,
89 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f,
90 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f,
91 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f,
92 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f,
93 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f,
94 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f,
95 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f,
96 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f,
97 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f,
98 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f,
99 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f,
100 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f,
101 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f,
102 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f,
103 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f,
104 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f,
105 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f,
106 0.82788260f, 0.88168307f, 0.9389798f, 1.0f};
107
108 static Floor createInstance(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
109
110 int type=source.getInt(16);
111 switch(type) {
112 case 0:
113 return new Floor0(source, header);
114 case 1:
115 return new Floor1(source, header);
116 default:
117 throw new VorbisFormatException("Floor type "+type+" is not supported.");
118 }
119 }
120
121 abstract int getType();
122 abstract Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException;
123 abstract void computeFloor(float[] vector);
124} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Floor0.java b/songdbj/de/jarnbjo/vorbis/Floor0.java
new file mode 100644
index 0000000000..4e94b27b73
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Floor0.java
@@ -0,0 +1,74 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.IOException;
33
34import de.jarnbjo.util.io.BitInputStream;
35
36class Floor0 extends Floor {
37
38 private int order, rate, barkMapSize, amplitudeBits, amplitudeOffset;
39 private int bookList[];
40
41 protected Floor0(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
42
43 order=source.getInt(8);
44 rate=source.getInt(16);
45 barkMapSize=source.getInt(16);
46 amplitudeBits=source.getInt(6);
47 amplitudeOffset=source.getInt(8);
48
49 int bookCount=source.getInt(4)+1;
50 bookList=new int[bookCount];
51
52 for(int i=0; i<bookList.length; i++) {
53 bookList[i]=source.getInt(8);
54 if(bookList[i]>header.getCodeBooks().length) {
55 throw new VorbisFormatException("A floor0_book_list entry is higher than the code book count.");
56 }
57 }
58 }
59
60 protected int getType() {
61 return 0;
62 }
63
64 protected Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
65 /** @todo implement */
66 throw new UnsupportedOperationException();
67 }
68
69 protected void computeFloor(float[] vector) {
70 /** @todo implement */
71 throw new UnsupportedOperationException();
72 }
73
74} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Floor1.java b/songdbj/de/jarnbjo/vorbis/Floor1.java
new file mode 100644
index 0000000000..69a118b44e
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Floor1.java
@@ -0,0 +1,324 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$multip
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.IOException;
33import java.util.*;
34
35import de.jarnbjo.util.io.BitInputStream;
36
37
38class Floor1 extends Floor implements Cloneable {
39
40 private int[] partitionClassList;
41 private int maximumClass, multiplier, rangeBits;
42 private int[] classDimensions;
43 private int[] classSubclasses;
44 private int[] classMasterbooks;
45 private int[][] subclassBooks;
46 private int[] xList;
47 private int[] yList;
48 private int[] lowNeighbours, highNeighbours;
49 //private boolean[] step2Flags;
50
51 private static final int[] RANGES = {256, 128, 86, 64};
52
53 private Floor1() {
54 }
55
56 protected Floor1(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
57
58 maximumClass=-1;
59 int partitions=source.getInt(5);
60 partitionClassList=new int[partitions];
61
62 for(int i=0; i<partitionClassList.length; i++) {
63 partitionClassList[i]=source.getInt(4);
64 if(partitionClassList[i]>maximumClass) {
65 maximumClass=partitionClassList[i];
66 }
67 }
68
69
70 classDimensions=new int[maximumClass+1];
71 classSubclasses=new int[maximumClass+1];
72 classMasterbooks=new int[maximumClass+1];
73 subclassBooks=new int[maximumClass+1][];
74
75 int xListLength=2;
76
77 for(int i=0; i<=maximumClass; i++) {
78 classDimensions[i]=source.getInt(3)+1;
79 xListLength+=classDimensions[i];
80 classSubclasses[i]=source.getInt(2);
81
82 if(classDimensions[i] > header.getCodeBooks().length ||
83 classSubclasses[i] > header.getCodeBooks().length) {
84 throw new VorbisFormatException("There is a class dimension or class subclasses entry higher than the number of codebooks in the setup header.");
85 }
86 if(classSubclasses[i]!=0) {
87 classMasterbooks[i]=source.getInt(8);
88 }
89 subclassBooks[i]=new int[1<<classSubclasses[i]];
90 for(int j=0; j<subclassBooks[i].length; j++) {
91 subclassBooks[i][j]=source.getInt(8)-1;
92 }
93 }
94
95 multiplier=source.getInt(2)+1;
96 rangeBits=source.getInt(4);
97
98 //System.out.println("multiplier: "+multiplier);
99 //System.out.println("rangeBits: "+rangeBits);
100
101 //System.out.println("xListLength: "+xListLength);
102
103 int floorValues=0;
104
105 ArrayList alXList=new ArrayList();
106
107 alXList.add(new Integer(0));
108 alXList.add(new Integer(1<<rangeBits));
109
110 //System.out.println("partitions: "+partitions);
111 //System.out.println("classDimensions.length: "+classDimensions.length);
112
113 for(int i=0; i<partitions; i++) {
114 for(int j=0; j<classDimensions[partitionClassList[i]]; j++) {
115 alXList.add(new Integer(source.getInt(rangeBits)));
116 }
117 }
118
119 xList=new int[alXList.size()];
120 lowNeighbours=new int[xList.length];
121 highNeighbours=new int[xList.length];
122
123 Iterator iter=alXList.iterator();
124 for(int i=0; i<xList.length; i++) {
125 xList[i]=((Integer)iter.next()).intValue();
126 }
127
128 for(int i=0; i<xList.length; i++) {
129 lowNeighbours[i]=Util.lowNeighbour(xList, i);
130 highNeighbours[i]=Util.highNeighbour(xList, i);
131 }
132 }
133
134 protected int getType() {
135 return 1;
136 }
137
138 protected Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
139
140 //System.out.println("decodeFloor");
141 if(!source.getBit()) {
142 //System.out.println("null");
143 return null;
144 }
145
146 Floor1 clone=(Floor1)clone();
147
148 clone.yList=new int[xList.length];
149
150 int range=RANGES[multiplier-1];
151
152 clone.yList[0]=source.getInt(Util.ilog(range-1));
153 clone.yList[1]=source.getInt(Util.ilog(range-1));
154
155 int offset=2;
156
157 for(int i=0; i<partitionClassList.length; i++) {
158 int cls=partitionClassList[i];
159 int cdim=classDimensions[cls];
160 int cbits=classSubclasses[cls];
161 int csub=(1<<cbits)-1;
162 int cval=0;
163 if(cbits>0) {
164 cval=source.getInt(vorbis.getSetupHeader().getCodeBooks()[classMasterbooks[cls]].getHuffmanRoot());
165 //cval=vorbis.getSetupHeader().getCodeBooks()[classMasterbooks[cls]].readInt(source);
166 //System.out.println("cval: "+cval);
167 }
168 //System.out.println("0: "+cls+" "+cdim+" "+cbits+" "+csub+" "+cval);
169 for(int j=0; j<cdim; j++) {
170 //System.out.println("a: "+cls+" "+cval+" "+csub);
171 int book=subclassBooks[cls][cval&csub];
172 cval>>>=cbits;
173 if(book>=0) {
174 clone.yList[j+offset]=source.getInt(vorbis.getSetupHeader().getCodeBooks()[book].getHuffmanRoot());
175 //clone.yList[j+offset]=vorbis.getSetupHeader().getCodeBooks()[book].readInt(source);
176 //System.out.println("b: "+(j+offset)+" "+book+" "+clone.yList[j+offset]);
177 //System.out.println("");
178 }
179 else {
180 clone.yList[j+offset]=0;
181 }
182 }
183 offset+=cdim;
184 }
185
186 //System.out.println("");
187 //for(int i=0; i<clone.xList.length; i++) {
188 // System.out.println(i+" = "+clone.xList[i]);
189 //}
190
191 //System.out.println("");
192 //for(int i=0; i<clone.yList.length; i++) {
193 // System.out.println(i+" = "+clone.yList[i]);
194 //}
195
196 //System.out.println("offset: "+offset);
197 //System.out.println("yList.length: "+clone.yList.length);
198
199 //System.exit(0);
200
201 return clone;
202 }
203
204 protected void computeFloor(final float[] vector) {
205
206 int n=vector.length;
207 final int values=xList.length;
208 final boolean[] step2Flags=new boolean[values];
209
210 final int range=RANGES[multiplier-1];
211
212 for(int i=2; i<values; i++) {
213 final int lowNeighbourOffset=lowNeighbours[i];//Util.lowNeighbour(xList, i);
214 final int highNeighbourOffset=highNeighbours[i];//Util.highNeighbour(xList, i);
215 final int predicted=Util.renderPoint(
216 xList[lowNeighbourOffset], xList[highNeighbourOffset],
217 yList[lowNeighbourOffset], yList[highNeighbourOffset],
218 xList[i]);
219 final int val=yList[i];
220 final int highRoom=range-predicted;
221 final int lowRoom=predicted;
222 final int room=highRoom<lowRoom?highRoom*2:lowRoom*2;
223 if(val!=0) {
224 step2Flags[lowNeighbourOffset]=true;
225 step2Flags[highNeighbourOffset]=true;
226 step2Flags[i]=true;
227 if(val>=room) {
228 yList[i]=highRoom>lowRoom?
229 val-lowRoom+predicted:
230 -val+highRoom+predicted-1;
231 }
232 else {
233 yList[i]=(val&1)==1?
234 predicted-((val+1)>>1):
235 predicted+(val>>1);
236 }
237 }
238 else {
239 step2Flags[i]=false;
240 yList[i]=predicted;
241 }
242 }
243
244 final int[] xList2=new int[values];
245
246 System.arraycopy(xList, 0, xList2, 0, values);
247 sort(xList2, yList, step2Flags);
248
249 int hx=0, hy=0, lx=0, ly=yList[0]*multiplier;
250
251 float[] vector2=new float[vector.length];
252 float[] vector3=new float[vector.length];
253 Arrays.fill(vector2, 1.0f);
254 System.arraycopy(vector, 0, vector3, 0, vector.length);
255
256 for(int i=1; i<values; i++) {
257 if(step2Flags[i]) {
258 hy=yList[i]*multiplier;
259 hx=xList2[i];
260 Util.renderLine(lx, ly, hx, hy, vector);
261 Util.renderLine(lx, ly, hx, hy, vector2);
262 lx=hx;
263 ly=hy;
264 }
265 }
266
267 final float r=DB_STATIC_TABLE[hy];
268 for(; hx<n/2; vector[hx++]=r);
269 }
270
271 public Object clone() {
272 Floor1 clone=new Floor1();
273 clone.classDimensions=classDimensions;
274 clone.classMasterbooks=classMasterbooks;
275 clone.classSubclasses=classSubclasses;
276 clone.maximumClass=maximumClass;
277 clone.multiplier=multiplier;
278 clone.partitionClassList=partitionClassList;
279 clone.rangeBits=rangeBits;
280 clone.subclassBooks=subclassBooks;
281 clone.xList=xList;
282 clone.yList=yList;
283 clone.lowNeighbours=lowNeighbours;
284 clone.highNeighbours=highNeighbours;
285 return clone;
286 }
287
288 private final static void sort(int x[], int y[], boolean b[]) {
289 int off=0;
290 int len=x.length;
291 int lim=len+off;
292 int itmp;
293 boolean btmp;
294 // Insertion sort on smallest arrays
295 for (int i=off; i<lim; i++) {
296 for (int j=i; j>off && x[j-1]>x[j]; j--) {
297 itmp=x[j];
298 x[j]=x[j-1];
299 x[j-1]=itmp;
300 itmp=y[j];
301 y[j]=y[j-1];
302 y[j-1]=itmp;
303 btmp=b[j];
304 b[j]=b[j-1];
305 b[j-1]=btmp;
306 //swap(x, j, j-1);
307 //swap(y, j, j-1);
308 //swap(b, j, j-1);
309 }
310 }
311 }
312
313 private final static void swap(int x[], int a, int b) {
314 int t = x[a];
315 x[a] = x[b];
316 x[b] = t;
317 }
318
319 private final static void swap(boolean x[], int a, int b) {
320 boolean t = x[a];
321 x[a] = x[b];
322 x[b] = t;
323 }
324} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/IdentificationHeader.java b/songdbj/de/jarnbjo/vorbis/IdentificationHeader.java
new file mode 100644
index 0000000000..1e18163385
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/IdentificationHeader.java
@@ -0,0 +1,120 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.3 2003/03/31 00:20:16 jarnbjo
28 * no message
29 *
30 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
31 * no message
32 *
33 *
34 */
35
36package de.jarnbjo.vorbis;
37
38import java.io.IOException;
39
40import de.jarnbjo.util.io.BitInputStream;
41
42/**
43 */
44
45public class IdentificationHeader {
46
47 private int version, channels, sampleRate, bitrateMaximum, bitrateNominal, bitrateMinimum, blockSize0, blockSize1;
48 private boolean framingFlag;
49 private MdctFloat[] mdct=new MdctFloat[2];
50 //private MdctLong[] mdctInt=new MdctLong[2];
51
52 private static final long HEADER = 0x736962726f76L; // 'vorbis'
53
54 public IdentificationHeader(BitInputStream source) throws VorbisFormatException, IOException {
55 //equalizer=new Equalizer();
56 //equalizer.pack();
57 //equalizer.show();
58
59 long leading=source.getLong(48);
60 if(leading!=HEADER) {
61 throw new VorbisFormatException("The identification header has an illegal leading.");
62 }
63 version=source.getInt(32);
64 channels=source.getInt(8);
65 sampleRate=source.getInt(32);
66 bitrateMaximum=source.getInt(32);
67 bitrateNominal=source.getInt(32);
68 bitrateMinimum=source.getInt(32);
69 int bs=source.getInt(8);
70 blockSize0=1<<(bs&0xf);
71 blockSize1=1<<(bs>>4);
72
73 mdct[0]=new MdctFloat(blockSize0);
74 mdct[1]=new MdctFloat(blockSize1);
75 //mdctInt[0]=new MdctLong(blockSize0);
76 //mdctInt[1]=new MdctLong(blockSize1);
77
78 framingFlag=source.getInt(8)!=0;
79 }
80
81 public int getSampleRate() {
82 return sampleRate;
83 }
84
85 public int getMaximumBitrate() {
86 return bitrateMaximum;
87 }
88
89 public int getNominalBitrate() {
90 return bitrateNominal;
91 }
92
93 public int getMinimumBitrate() {
94 return bitrateMinimum;
95 }
96
97 public int getChannels() {
98 return channels;
99 }
100
101 public int getBlockSize0() {
102 return blockSize0;
103 }
104
105 public int getBlockSize1() {
106 return blockSize1;
107 }
108
109 protected MdctFloat getMdct0() {
110 return mdct[0];
111 }
112
113 protected MdctFloat getMdct1() {
114 return mdct[1];
115 }
116
117 public int getVersion() {
118 return version;
119 }
120} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Mapping.java b/songdbj/de/jarnbjo/vorbis/Mapping.java
new file mode 100644
index 0000000000..24a2eaa19a
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Mapping.java
@@ -0,0 +1,59 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.IOException;
33
34import de.jarnbjo.util.io.BitInputStream;
35
36abstract class Mapping {
37
38 protected static Mapping createInstance(VorbisStream vorbis, BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
39
40 int type=source.getInt(16);
41 switch(type) {
42 case 0:
43 //System.out.println("mapping type 0");
44 return new Mapping0(vorbis, source, header);
45 default:
46 throw new VorbisFormatException("Mapping type "+type+" is not supported.");
47 }
48 }
49
50 protected abstract int getType();
51 protected abstract int[] getAngles();
52 protected abstract int[] getMagnitudes() ;
53 protected abstract int[] getMux();
54 protected abstract int[] getSubmapFloors();
55 protected abstract int[] getSubmapResidues();
56 protected abstract int getCouplingSteps();
57 protected abstract int getSubmaps();
58
59} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Mapping0.java b/songdbj/de/jarnbjo/vorbis/Mapping0.java
new file mode 100644
index 0000000000..e8fde4686f
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Mapping0.java
@@ -0,0 +1,146 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.IOException;
33
34import de.jarnbjo.util.io.BitInputStream;
35
36class Mapping0 extends Mapping {
37
38 private int[] magnitudes, angles, mux, submapFloors, submapResidues;
39
40 protected Mapping0(VorbisStream vorbis, BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
41
42 int submaps=1;
43
44 if(source.getBit()) {
45 submaps=source.getInt(4)+1;
46 }
47
48 //System.out.println("submaps: "+submaps);
49
50 int channels=vorbis.getIdentificationHeader().getChannels();
51 int ilogChannels=Util.ilog(channels-1);
52
53 //System.out.println("ilogChannels: "+ilogChannels);
54
55 if(source.getBit()) {
56 int couplingSteps=source.getInt(8)+1;
57 magnitudes=new int[couplingSteps];
58 angles=new int[couplingSteps];
59
60 for(int i=0; i<couplingSteps; i++) {
61 magnitudes[i]=source.getInt(ilogChannels);
62 angles[i]=source.getInt(ilogChannels);
63 if(magnitudes[i]==angles[i] || magnitudes[i]>=channels || angles[i]>=channels) {
64 System.err.println(magnitudes[i]);
65 System.err.println(angles[i]);
66 throw new VorbisFormatException("The channel magnitude and/or angle mismatch.");
67 }
68 }
69 }
70 else {
71 magnitudes=new int[0];
72 angles=new int[0];
73 }
74
75 if(source.getInt(2)!=0) {
76 throw new VorbisFormatException("A reserved mapping field has an invalid value.");
77 }
78
79 mux=new int[channels];
80 if(submaps>1) {
81 for(int i=0; i<channels; i++) {
82 mux[i]=source.getInt(4);
83 if(mux[i]>submaps) {
84 throw new VorbisFormatException("A mapping mux value is higher than the number of submaps");
85 }
86 }
87 }
88 else {
89 for(int i=0; i<channels; i++) {
90 mux[i]=0;
91 }
92 }
93
94 submapFloors=new int[submaps];
95 submapResidues=new int[submaps];
96
97 int floorCount=header.getFloors().length;
98 int residueCount=header.getResidues().length;
99
100 for(int i=0; i<submaps; i++) {
101 source.getInt(8); // discard time placeholder
102 submapFloors[i]=source.getInt(8);
103 submapResidues[i]=source.getInt(8);
104
105 if(submapFloors[i]>floorCount) {
106 throw new VorbisFormatException("A mapping floor value is higher than the number of floors.");
107 }
108
109 if(submapResidues[i]>residueCount) {
110 throw new VorbisFormatException("A mapping residue value is higher than the number of residues.");
111 }
112 }
113 }
114
115 protected int getType() {
116 return 0;
117 }
118
119 protected int[] getAngles() {
120 return angles;
121 }
122
123 protected int[] getMagnitudes() {
124 return magnitudes;
125 }
126
127 protected int[] getMux() {
128 return mux;
129 }
130
131 protected int[] getSubmapFloors() {
132 return submapFloors;
133 }
134
135 protected int[] getSubmapResidues() {
136 return submapResidues;
137 }
138
139 protected int getCouplingSteps() {
140 return angles.length;
141 }
142
143 protected int getSubmaps() {
144 return submapFloors.length;
145 }
146} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/MdctFloat.java b/songdbj/de/jarnbjo/vorbis/MdctFloat.java
new file mode 100644
index 0000000000..4f354b259b
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/MdctFloat.java
@@ -0,0 +1,321 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 12:09:45 shred
22 * *** empty log message ***
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.3 2003/04/10 19:49:04 jarnbjo
28 * no message
29 *
30 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
31 * no message
32 *
33 *
34 */
35
36package de.jarnbjo.vorbis;
37
38class MdctFloat {
39 static private final float cPI3_8=0.38268343236508977175f;
40 static private final float cPI2_8=0.70710678118654752441f;
41 static private final float cPI1_8=0.92387953251128675613f;
42
43 private int n;
44 private int log2n;
45
46 private float[] trig;
47 private int[] bitrev;
48
49 private float[] equalizer;
50
51 private float scale;
52
53 private int itmp1, itmp2, itmp3, itmp4, itmp5, itmp6, itmp7, itmp8, itmp9;
54 private float dtmp1, dtmp2, dtmp3, dtmp4, dtmp5, dtmp6, dtmp7, dtmp8, dtmp9;
55
56 protected MdctFloat(int n) {
57 bitrev=new int[n/4];
58 trig=new float[n+n/4];
59
60 int n2=n>>>1;
61 log2n=(int)Math.rint(Math.log(n)/Math.log(2));
62 this.n=n;
63
64 int AE=0;
65 int AO=1;
66 int BE=AE+n/2;
67 int BO=BE+1;
68 int CE=BE+n/2;
69 int CO=CE+1;
70 // trig lookups...
71 for(int i=0;i<n/4;i++){
72 trig[AE+i*2]=(float)Math.cos((Math.PI/n)*(4*i));
73 trig[AO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i));
74 trig[BE+i*2]=(float)Math.cos((Math.PI/(2*n))*(2*i+1));
75 trig[BO+i*2]=(float)Math.sin((Math.PI/(2*n))*(2*i+1));
76 }
77 for(int i=0;i<n/8;i++){
78 trig[CE+i*2]=(float)Math.cos((Math.PI/n)*(4*i+2));
79 trig[CO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i+2));
80 }
81
82 {
83 int mask=(1<<(log2n-1))-1;
84 int msb=1<<(log2n-2);
85 for(int i=0;i<n/8;i++){
86 int acc=0;
87 for(int j=0;msb>>>j!=0;j++)
88 if(((msb>>>j)&i)!=0)acc|=1<<j;
89 bitrev[i*2]=((~acc)&mask);
90// bitrev[i*2]=((~acc)&mask)-1;
91 bitrev[i*2+1]=acc;
92 }
93 }
94 scale=4.f/n;
95 }
96
97 //void clear(){
98 //}
99
100 //void forward(float[] in, float[] out){
101 //}
102
103 private float[] _x=new float[1024];
104 private float[] _w=new float[1024];
105
106 protected void setEqualizer(float[] equalizer) {
107 this.equalizer=equalizer;
108 }
109
110 protected float[] getEqualizer() {
111 return equalizer;
112 }
113
114 protected synchronized void imdct(final float[] frq, final float[] window, final int[] pcm) {//, float[] out){
115
116 float[] in=frq;//, out=buf;
117 if(_x.length<n/2){_x=new float[n/2];}
118 if(_w.length<n/2){_w=new float[n/2];}
119 final float[] x=_x;
120 final float[] w=_w;
121 int n2=n>>1;
122 int n4=n>>2;
123 int n8=n>>3;
124
125 if(equalizer!=null) {
126 for(int i=0; i<n; i++) {
127 frq[i]*=equalizer[i];
128 }
129 }
130
131 // rotate + step 1
132 {
133 int inO=-1;
134 int xO=0;
135 int A=n2;
136
137 int i;
138 for(i=0;i<n8;i++) {
139 dtmp1=in[inO+=2];
140 dtmp2=in[inO+=2];
141 dtmp3=trig[--A];
142 dtmp4=trig[--A];
143 x[xO++]=-dtmp2*dtmp3 - dtmp1*dtmp4;
144 x[xO++]= dtmp1*dtmp3 - dtmp2*dtmp4;
145 //A-=2;
146 //x[xO++]=-in[inO+2]*trig[A+1] - in[inO]*trig[A];
147 //x[xO++]= in[inO]*trig[A+1] - in[inO+2]*trig[A];
148 //inO+=4;
149 }
150
151 inO=n2;//-4;
152
153 for(i=0;i<n8;i++) {
154 dtmp1=in[inO-=2];
155 dtmp2=in[inO-=2];
156 dtmp3=trig[--A];
157 dtmp4=trig[--A];
158 x[xO++]=dtmp2*dtmp3 + dtmp1*dtmp4;
159 x[xO++]=dtmp2*dtmp4 - dtmp1*dtmp3;
160 //A-=2;
161 //x[xO++]=in[inO]*trig[A+1] + in[inO+2]*trig[A];
162 //x[xO++]=in[inO]*trig[A] - in[inO+2]*trig[A+1];
163 //inO-=4;
164 }
165 }
166
167 float[] xxx=kernel(x,w,n,n2,n4,n8);
168 int xx=0;
169
170 // step 8
171
172 {
173 int B=n2;
174 int o1=n4,o2=o1-1;
175 int o3=n4+n2,o4=o3-1;
176
177 for(int i=0;i<n4;i++){
178 dtmp1=xxx[xx++];
179 dtmp2=xxx[xx++];
180 dtmp3=trig[B++];
181 dtmp4=trig[B++];
182
183 float temp1= (dtmp1* dtmp4 - dtmp2 * dtmp3);
184 float temp2=-(dtmp1 * dtmp3 + dtmp2 * dtmp4);
185
186 /*
187 float temp1= (xxx[xx] * trig[B+1] - xxx[xx+1] * trig[B]);//*32767.0f;
188 float temp2=-(xxx[xx] * trig[B] + xxx[xx+1] * trig[B+1]);//*32767.0f;
189 */
190
191 //if(temp1>32767.0f) temp1=32767.0f;
192 //if(temp1<-32768.0f) temp1=-32768.0f;
193 //if(temp2>32767.0f) temp2=32767.0f;
194 //if(temp2<-32768.0f) temp2=-32768.0f;
195
196 pcm[o1]=(int)(-temp1*window[o1]);
197 pcm[o2]=(int)( temp1*window[o2]);
198 pcm[o3]=(int)( temp2*window[o3]);
199 pcm[o4]=(int)( temp2*window[o4]);
200
201 o1++;
202 o2--;
203 o3++;
204 o4--;
205 //xx+=2;
206 //B+=2;
207 }
208 }
209 }
210
211 private float[] kernel(float[] x, float[] w,
212 int n, int n2, int n4, int n8){
213 // step 2
214
215 int xA=n4;
216 int xB=0;
217 int w2=n4;
218 int A=n2;
219
220 for(int i=0;i<n4;){
221 float x0=x[xA] - x[xB];
222 float x1;
223 w[w2+i]=x[xA++]+x[xB++];
224
225 x1=x[xA]-x[xB];
226 A-=4;
227
228 w[i++]= x0 * trig[A] + x1 * trig[A+1];
229 w[i]= x1 * trig[A] - x0 * trig[A+1];
230
231 w[w2+i]=x[xA++]+x[xB++];
232 i++;
233 }
234
235 // step 3
236
237 {
238 for(int i=0;i<log2n-3;i++){
239 int k0=n>>>(i+2);
240 int k1=1<<(i+3);
241 int wbase=n2-2;
242
243 A=0;
244 float[] temp;
245
246 for(int r=0;r<(k0>>>2);r++){
247 int w1=wbase;
248 w2=w1-(k0>>1);
249 float AEv= trig[A],wA;
250 float AOv= trig[A+1],wB;
251 wbase-=2;
252
253 k0++;
254 for(int s=0;s<(2<<i);s++){
255 dtmp1=w[w1];
256 dtmp2=w[w2];
257 wB=dtmp1-dtmp2;
258 x[w1]=dtmp1+dtmp2;
259 dtmp1=w[++w1];
260 dtmp2=w[++w2];
261 wA=dtmp1-dtmp2;
262 x[w1]=dtmp1+dtmp2;
263 x[w2] =wA*AEv - wB*AOv;
264 x[w2-1]=wB*AEv + wA*AOv;
265
266 /*
267 wB =w[w1] -w[w2];
268 x[w1] =w[w1] +w[w2];
269
270 wA =w[++w1] -w[++w2];
271 x[w1] =w[w1] +w[w2];
272
273 x[w2] =wA*AEv - wB*AOv;
274 x[w2-1]=wB*AEv + wA*AOv;
275 */
276
277 w1-=k0;
278 w2-=k0;
279 }
280 k0--;
281 A+=k1;
282 }
283
284 temp=w;
285 w=x;
286 x=temp;
287 }
288 }
289
290 // step 4, 5, 6, 7
291 {
292 int C=n;
293 int bit=0;
294 int x1=0;
295 int x2=n2-1;
296
297 for(int i=0;i<n8;i++) {
298 int t1=bitrev[bit++];
299 int t2=bitrev[bit++];
300
301 float wA=w[t1]-w[t2+1];
302 float wB=w[t1-1]+w[t2];
303 float wC=w[t1]+w[t2+1];
304 float wD=w[t1-1]-w[t2];
305
306 float wACE=wA* trig[C];
307 float wBCE=wB* trig[C++];
308 float wACO=wA* trig[C];
309 float wBCO=wB* trig[C++];
310
311 x[x1++]=( wC+wACO+wBCE)*16383.0f;
312 x[x2--]=(-wD+wBCO-wACE)*16383.0f;
313 x[x1++]=( wD+wBCO-wACE)*16383.0f;
314 x[x2--]=( wC-wACO-wBCE)*16383.0f;
315 }
316 }
317 return x;
318 }
319
320}
321
diff --git a/songdbj/de/jarnbjo/vorbis/Mode.java b/songdbj/de/jarnbjo/vorbis/Mode.java
new file mode 100644
index 0000000000..ab88944a25
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Mode.java
@@ -0,0 +1,75 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.*;
33
34import de.jarnbjo.util.io.*;
35
36class Mode {
37
38 private boolean blockFlag;
39 private int windowType, transformType, mapping;
40
41 protected Mode(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
42 blockFlag=source.getBit();
43 windowType=source.getInt(16);
44 transformType=source.getInt(16);
45 mapping=source.getInt(8);
46
47 if(windowType!=0) {
48 throw new VorbisFormatException("Window type = "+windowType+", != 0");
49 }
50
51 if(transformType!=0) {
52 throw new VorbisFormatException("Transform type = "+transformType+", != 0");
53 }
54
55 if(mapping>header.getMappings().length) {
56 throw new VorbisFormatException("Mode mapping number is higher than total number of mappings.");
57 }
58 }
59
60 protected boolean getBlockFlag() {
61 return blockFlag;
62 }
63
64 protected int getWindowType() {
65 return windowType;
66 }
67
68 protected int getTransformType() {
69 return transformType;
70 }
71
72 protected int getMapping() {
73 return mapping;
74 }
75} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Residue.java b/songdbj/de/jarnbjo/vorbis/Residue.java
new file mode 100644
index 0000000000..78c28fa5ed
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Residue.java
@@ -0,0 +1,260 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/04/04 08:33:02 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36import java.util.HashMap;
37
38import de.jarnbjo.util.io.*;
39
40
41abstract class Residue {
42
43 protected int begin, end;
44 protected int partitionSize; // grouping
45 protected int classifications; // partitions
46 protected int classBook; // groupbook
47 protected int[] cascade; // secondstages
48 protected int[][] books;
49 protected HashMap looks=new HashMap();
50
51 protected Residue() {
52 }
53
54 protected Residue(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
55 begin=source.getInt(24);
56 end=source.getInt(24);
57 partitionSize=source.getInt(24)+1;
58 classifications=source.getInt(6)+1;
59 classBook=source.getInt(8);
60
61 cascade=new int[classifications];
62
63 int acc=0;
64
65 for(int i=0; i<classifications; i++) {
66 int highBits=0, lowBits=0;
67 lowBits=source.getInt(3);
68 if(source.getBit()) {
69 highBits=source.getInt(5);
70 }
71 cascade[i]=(highBits<<3)|lowBits;
72 acc+=Util.icount(cascade[i]);
73 }
74
75 books=new int[classifications][8];
76
77 for(int i=0; i<classifications; i++) {
78 for(int j=0; j<8; j++) {
79 if((cascade[i]&(1<<j))!=0) {
80 books[i][j]=source.getInt(8);
81 if(books[i][j]>header.getCodeBooks().length) {
82 throw new VorbisFormatException("Reference to invalid codebook entry in residue header.");
83 }
84 }
85 }
86 }
87 }
88
89
90 protected static Residue createInstance(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
91
92 int type=source.getInt(16);
93 switch(type) {
94 case 0:
95 //System.out.println("residue type 0");
96 return new Residue0(source, header);
97 case 1:
98 //System.out.println("residue type 1");
99 return new Residue2(source, header);
100 case 2:
101 //System.out.println("residue type 2");
102 return new Residue2(source, header);
103 default:
104 throw new VorbisFormatException("Residue type "+type+" is not supported.");
105 }
106 }
107
108 protected abstract int getType();
109 protected abstract void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException;
110 //public abstract double[][] getDecodedVectors();
111
112 protected int getBegin() {
113 return begin;
114 }
115
116 protected int getEnd() {
117 return end;
118 }
119
120 protected int getPartitionSize() {
121 return partitionSize;
122 }
123
124 protected int getClassifications() {
125 return classifications;
126 }
127
128 protected int getClassBook() {
129 return classBook;
130 }
131
132 protected int[] getCascade() {
133 return cascade;
134 }
135
136 protected int[][] getBooks() {
137 return books;
138 }
139
140 protected final void fill(Residue clone) {
141 clone.begin=begin;
142 clone.books=books;
143 clone.cascade=cascade;
144 clone.classBook=classBook;
145 clone.classifications=classifications;
146 clone.end=end;
147 clone.partitionSize=partitionSize;
148 }
149
150 protected Look getLook(VorbisStream source, Mode key) {
151 //return new Look(source, key);
152 Look look=(Look)looks.get(key);
153 if(look==null) {
154 look=new Look(source, key);
155 looks.put(key, look);
156 }
157 return look;
158 }
159
160
161 class Look {
162 int map;
163 int parts;
164 int stages;
165 CodeBook[] fullbooks;
166 CodeBook phrasebook;
167 int[][] partbooks;
168 int partvals;
169 int[][] decodemap;
170 int postbits;
171 int phrasebits;
172 int frames;
173
174 protected Look (VorbisStream source, Mode mode) {
175 int dim=0, acc=0, maxstage=0;
176
177 map=mode.getMapping();
178 parts=Residue.this.getClassifications();
179 fullbooks=source.getSetupHeader().getCodeBooks();
180 phrasebook=fullbooks[Residue.this.getClassBook()];
181 dim=phrasebook.getDimensions();
182
183 partbooks=new int[parts][];
184
185 for(int j=0;j<parts;j++) {
186 int stages=Util.ilog(Residue.this.getCascade()[j]);
187 if(stages!=0) {
188 if(stages>maxstage) {
189 maxstage=stages;
190 }
191 partbooks[j]=new int[stages];
192 for(int k=0; k<stages; k++){
193 if((Residue.this.getCascade()[j]&(1<<k))!=0){
194 partbooks[j][k]=Residue.this.getBooks()[j][k];
195 }
196 }
197 }
198 }
199
200 partvals=(int)Math.rint(Math.pow(parts, dim));
201 stages=maxstage;
202
203 decodemap=new int[partvals][];
204
205 for(int j=0;j<partvals;j++){
206 int val=j;
207 int mult=partvals/parts;
208 decodemap[j]=new int[dim];
209
210 for(int k=0;k<dim;k++){
211 int deco=val/mult;
212 val-=deco*mult;
213 mult/=parts;
214 decodemap[j][k]=deco;
215 }
216 }
217 }
218
219 protected int[][] getDecodeMap() {
220 return decodemap;
221 }
222
223 protected int getFrames() {
224 return frames;
225 }
226
227 protected int getMap() {
228 return map;
229 }
230
231 protected int[][] getPartBooks() {
232 return partbooks;
233 }
234
235 protected int getParts() {
236 return parts;
237 }
238
239 protected int getPartVals() {
240 return partvals;
241 }
242
243 protected int getPhraseBits() {
244 return phrasebits;
245 }
246
247 protected CodeBook getPhraseBook() {
248 return phrasebook;
249 }
250
251 protected int getPostBits() {
252 return postbits;
253 }
254
255 protected int getStages() {
256 return stages;
257 }
258 }
259
260} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Residue0.java b/songdbj/de/jarnbjo/vorbis/Residue0.java
new file mode 100644
index 0000000000..7dc0dfa765
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Residue0.java
@@ -0,0 +1,53 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37import de.jarnbjo.util.io.BitInputStream;
38
39class Residue0 extends Residue {
40
41 protected Residue0(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
42 super(source, header);
43 }
44
45 protected int getType() {
46 return 0;
47 }
48
49 protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
50 /** @todo implement */
51 throw new UnsupportedOperationException();
52 }
53} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Residue1.java b/songdbj/de/jarnbjo/vorbis/Residue1.java
new file mode 100644
index 0000000000..f31147c072
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Residue1.java
@@ -0,0 +1,55 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37import de.jarnbjo.util.io.BitInputStream;
38
39class Residue1 extends Residue {
40
41 protected Residue1(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
42 super(source, header);
43 }
44
45 protected int getType() {
46 return 1;
47 }
48
49 protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
50 /** @todo implement */
51 throw new UnsupportedOperationException();
52 }
53
54
55} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Residue2.java b/songdbj/de/jarnbjo/vorbis/Residue2.java
new file mode 100644
index 0000000000..666d2cd017
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Residue2.java
@@ -0,0 +1,123 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37import de.jarnbjo.util.io.BitInputStream;
38
39class Residue2 extends Residue {
40
41 private double[][] decodedVectors;
42
43 private Residue2() {
44 }
45
46 protected Residue2(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
47 super(source, header);
48 }
49
50 protected int getType() {
51 return 2;
52 }
53
54 protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
55
56 Look look=getLook(vorbis, mode);
57
58 CodeBook codeBook=vorbis.getSetupHeader().getCodeBooks()[getClassBook()];
59
60 int classvalsPerCodeword=codeBook.getDimensions();
61 int nToRead=getEnd()-getBegin();
62 int partitionsToRead=nToRead/getPartitionSize(); // partvals
63
64 int samplesPerPartition=getPartitionSize();
65 int partitionsPerWord=look.getPhraseBook().getDimensions();
66
67 int partWords=(partitionsToRead+partitionsPerWord-1)/partitionsPerWord;
68
69 int realCh=0;
70 for(int i=0; i<doNotDecodeFlags.length; i++) {
71 if(!doNotDecodeFlags[i]) {
72 realCh++;
73 }
74 }
75
76 float[][] realVectors=new float[realCh][];
77
78 realCh=0;
79 for(int i=0; i<doNotDecodeFlags.length; i++) {
80 if(!doNotDecodeFlags[i]) {
81 realVectors[realCh++]=vectors[i];
82 }
83 }
84
85 int[][] partword=new int[partWords][];
86 for(int s=0;s<look.getStages();s++){
87 for(int i=0,l=0;i<partitionsToRead;l++){
88 if(s==0){
89 //int temp=look.getPhraseBook().readInt(source);
90 int temp=source.getInt(look.getPhraseBook().getHuffmanRoot());
91 if(temp==-1){
92 throw new VorbisFormatException("");
93 }
94 partword[l]=look.getDecodeMap()[temp];
95 if(partword[l]==null){
96 throw new VorbisFormatException("");
97 }
98 }
99
100 for(int k=0;k<partitionsPerWord && i<partitionsToRead;k++,i++){
101 int offset=begin+i*samplesPerPartition;
102 if((cascade[partword[l][k]]&(1<<s))!=0){
103 CodeBook stagebook=vorbis.getSetupHeader().getCodeBooks()[look.getPartBooks()[partword[l][k]][s]];
104 if(stagebook!=null){
105 stagebook.readVvAdd(realVectors, source, offset, samplesPerPartition);
106 }
107 }
108 }
109 }
110 }
111 }
112
113
114 public Object clone() {
115 Residue2 clone=new Residue2();
116 fill(clone);
117 return clone;
118 }
119
120 protected double[][] getDecodedVectors() {
121 return decodedVectors;
122 }
123} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/SetupHeader.java b/songdbj/de/jarnbjo/vorbis/SetupHeader.java
new file mode 100644
index 0000000000..56e400f348
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/SetupHeader.java
@@ -0,0 +1,131 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.*;
33
34import de.jarnbjo.util.io.*;
35
36class SetupHeader {
37
38 private static final long HEADER = 0x736962726f76L; // 'vorbis'
39
40 private CodeBook[] codeBooks;
41 private Floor[] floors;
42 private Residue[] residues;
43 private Mapping[] mappings;
44 private Mode[] modes;
45
46 public SetupHeader(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
47
48 if(source.getLong(48)!=HEADER) {
49 throw new VorbisFormatException("The setup header has an illegal leading.");
50 }
51
52 // read code books
53
54 int codeBookCount=source.getInt(8)+1;
55 codeBooks=new CodeBook[codeBookCount];
56
57 for(int i=0; i<codeBooks.length; i++) {
58 codeBooks[i]=new CodeBook(source);
59 }
60
61 // read the time domain transformations,
62 // these should all be 0
63
64 int timeCount=source.getInt(6)+1;
65 for(int i=0; i<timeCount; i++) {
66 if(source.getInt(16)!=0) {
67 throw new VorbisFormatException("Time domain transformation != 0");
68 }
69 }
70
71 // read floor entries
72
73 int floorCount=source.getInt(6)+1;
74 floors=new Floor[floorCount];
75
76 for(int i=0; i<floorCount; i++) {
77 floors[i]=Floor.createInstance(source, this);
78 }
79
80 // read residue entries
81
82 int residueCount=source.getInt(6)+1;
83 residues=new Residue[residueCount];
84
85 for(int i=0; i<residueCount; i++) {
86 residues[i]=Residue.createInstance(source, this);
87 }
88
89 // read mapping entries
90
91 int mappingCount=source.getInt(6)+1;
92 mappings=new Mapping[mappingCount];
93
94 for(int i=0; i<mappingCount; i++) {
95 mappings[i]=Mapping.createInstance(vorbis, source, this);
96 }
97
98 // read mode entries
99
100 int modeCount=source.getInt(6)+1;
101 modes=new Mode[modeCount];
102
103 for(int i=0; i<modeCount; i++) {
104 modes[i]=new Mode(source, this);
105 }
106
107 if(!source.getBit()) {
108 throw new VorbisFormatException("The setup header framing bit is incorrect.");
109 }
110 }
111
112 public CodeBook[] getCodeBooks() {
113 return codeBooks;
114 }
115
116 public Floor[] getFloors() {
117 return floors;
118 }
119
120 public Residue[] getResidues() {
121 return residues;
122 }
123
124 public Mapping[] getMappings() {
125 return mappings;
126 }
127
128 public Mode[] getModes() {
129 return modes;
130 }
131} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Util.java b/songdbj/de/jarnbjo/vorbis/Util.java
new file mode 100644
index 0000000000..7e31c9495e
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Util.java
@@ -0,0 +1,127 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/04/10 19:49:04 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35final public class Util {
36
37 public static final int ilog(int x) {
38 int res=0;
39 for(; x>0; x>>=1, res++);
40 return res;
41 }
42
43 public static final float float32unpack(int x) {
44 float mantissa=x&0x1fffff;
45 float e=(x&0x7fe00000)>>21;
46 if((x&0x80000000)!=0) {
47 mantissa=-mantissa;
48 }
49 return mantissa*(float)Math.pow(2.0, e-788.0);
50 }
51
52 public static final int lookup1Values(int a, int b) {
53 int res=(int)Math.pow(Math.E, Math.log(a)/b);
54 return intPow(res+1, b)<=a?res+1:res;
55 }
56
57 public static final int intPow(int base, int e) {
58 int res=1;
59 for(; e>0; e--, res*=base);
60 return res;
61 }
62
63 public static final boolean isBitSet(int value, int bit) {
64 return (value&(1<<bit))!=0;
65 }
66
67 public static final int icount(int value) {
68 int res=0;
69 while(value>0) {
70 res+=value&1;
71 value>>=1;
72 }
73 return res;
74 }
75
76 public static final int lowNeighbour(int[] v, int x) {
77 int max=-1, n=0;
78 for(int i=0; i<v.length && i<x; i++) {
79 if(v[i]>max && v[i]<v[x]) {
80 max=v[i];
81 n=i;
82 }
83 }
84 return n;
85 }
86
87 public static final int highNeighbour(int[] v, int x) {
88 int min=Integer.MAX_VALUE, n=0;
89 for(int i=0; i<v.length && i<x; i++) {
90 if(v[i]<min && v[i]>v[x]) {
91 min=v[i];
92 n=i;
93 }
94 }
95 return n;
96 }
97
98 public static final int renderPoint(int x0, int x1, int y0, int y1, int x) {
99 int dy=y1-y0;
100 int ady=dy<0?-dy:dy;
101 int off=(ady*(x-x0))/(x1-x0);
102 return dy<0?y0-off:y0+off;
103 }
104
105 public static final void renderLine(final int x0, final int y0, final int x1, final int y1, final float[] v) {
106 final int dy=y1-y0;
107 final int adx=x1-x0;
108 final int base=dy/adx;
109 final int sy=dy<0?base-1:base+1;
110 int x=x0;
111 int y=y0;
112 int err=0;
113 final int ady=(dy<0?-dy:dy)-(base>0?base*adx:-base*adx);
114
115 v[x]*=Floor.DB_STATIC_TABLE[y];
116 for(x=x0+1; x<x1; x++) {
117 err+=ady;
118 if(err>=adx) {
119 err-=adx;
120 v[x]*=Floor.DB_STATIC_TABLE[y+=sy];
121 }
122 else {
123 v[x]*=Floor.DB_STATIC_TABLE[y+=base];
124 }
125 }
126 }
127} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java b/songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java
new file mode 100644
index 0000000000..b1bc999947
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java
@@ -0,0 +1,217 @@
1package de.jarnbjo.vorbis;
2
3/*
4 * $ProjectName$
5 * $ProjectRevision$
6 * -----------------------------------------------------------
7 * $Id$
8 * -----------------------------------------------------------
9 *
10 * $Author$
11 *
12 * Description:
13 *
14 * Copyright 2002-2003 Tor-Einar Jarnbjo
15 * -----------------------------------------------------------
16 *
17 * Change History
18 * -----------------------------------------------------------
19 * $Log$
20 * Revision 1.1 2005/07/11 15:42:36 hcl
21 * Songdb java version, source. only 1.5 compatible
22 *
23 * Revision 1.2 2004/09/21 06:39:06 shred
24 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
25 *
26 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
27 * First Import
28 *
29 *
30 */
31
32import java.io.File;
33import java.io.IOException;
34import java.io.InputStream;
35import java.io.RandomAccessFile;
36import java.net.URL;
37import java.util.Collection;
38
39import javax.sound.sampled.AudioFileFormat;
40import javax.sound.sampled.AudioFormat;
41import javax.sound.sampled.AudioInputStream;
42import javax.sound.sampled.AudioSystem;
43import javax.sound.sampled.UnsupportedAudioFileException;
44import javax.sound.sampled.spi.AudioFileReader;
45
46import de.jarnbjo.ogg.BasicStream;
47import de.jarnbjo.ogg.EndOfOggStreamException;
48import de.jarnbjo.ogg.FileStream;
49import de.jarnbjo.ogg.LogicalOggStream;
50import de.jarnbjo.ogg.OggFormatException;
51import de.jarnbjo.ogg.PhysicalOggStream;
52import de.jarnbjo.ogg.UncachedUrlStream;
53
54public class VorbisAudioFileReader extends AudioFileReader {
55
56 public VorbisAudioFileReader() {
57 }
58
59 public AudioFileFormat getAudioFileFormat(File file) throws IOException, UnsupportedAudioFileException {
60 try {
61 return getAudioFileFormat(new FileStream(new RandomAccessFile(file, "r")));
62 }
63 catch(OggFormatException e) {
64 throw new UnsupportedAudioFileException(e.getMessage());
65 }
66 }
67
68 public AudioFileFormat getAudioFileFormat(InputStream stream) throws IOException, UnsupportedAudioFileException {
69 try {
70 return getAudioFileFormat(new BasicStream(stream));
71 }
72 catch(OggFormatException e) {
73 throw new UnsupportedAudioFileException(e.getMessage());
74 }
75 }
76
77 public AudioFileFormat getAudioFileFormat(URL url) throws IOException, UnsupportedAudioFileException {
78 try {
79 return getAudioFileFormat(new UncachedUrlStream(url));
80 }
81 catch(OggFormatException e) {
82 throw new UnsupportedAudioFileException(e.getMessage());
83 }
84 }
85
86 private AudioFileFormat getAudioFileFormat(PhysicalOggStream oggStream) throws IOException, UnsupportedAudioFileException {
87 try {
88 Collection streams=oggStream.getLogicalStreams();
89 if(streams.size()!=1) {
90 throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
91 }
92
93 LogicalOggStream los=(LogicalOggStream)streams.iterator().next();
94 if(los.getFormat()!=LogicalOggStream.FORMAT_VORBIS) {
95 throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
96 }
97
98 VorbisStream vs=new VorbisStream(los);
99
100 AudioFormat audioFormat=new AudioFormat(
101 (float)vs.getIdentificationHeader().getSampleRate(),
102 16,
103 vs.getIdentificationHeader().getChannels(),
104 true, true);
105
106 return new AudioFileFormat(VorbisFormatType.getInstance(), audioFormat, AudioSystem.NOT_SPECIFIED);
107 }
108 catch(OggFormatException e) {
109 throw new UnsupportedAudioFileException(e.getMessage());
110 }
111 catch(VorbisFormatException e) {
112 throw new UnsupportedAudioFileException(e.getMessage());
113 }
114 }
115
116
117
118 public AudioInputStream getAudioInputStream(File file) throws IOException, UnsupportedAudioFileException {
119 try {
120 return getAudioInputStream(new FileStream(new RandomAccessFile(file, "r")));
121 }
122 catch(OggFormatException e) {
123 throw new UnsupportedAudioFileException(e.getMessage());
124 }
125 }
126
127 public AudioInputStream getAudioInputStream(InputStream stream) throws IOException, UnsupportedAudioFileException {
128 try {
129 return getAudioInputStream(new BasicStream(stream));
130 }
131 catch(OggFormatException e) {
132 throw new UnsupportedAudioFileException(e.getMessage());
133 }
134 }
135
136 public AudioInputStream getAudioInputStream(URL url) throws IOException, UnsupportedAudioFileException {
137 try {
138 return getAudioInputStream(new UncachedUrlStream(url));
139 }
140 catch(OggFormatException e) {
141 throw new UnsupportedAudioFileException(e.getMessage());
142 }
143 }
144
145 private AudioInputStream getAudioInputStream(PhysicalOggStream oggStream) throws IOException, UnsupportedAudioFileException {
146 try {
147 Collection streams=oggStream.getLogicalStreams();
148 if(streams.size()!=1) {
149 throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
150 }
151
152 LogicalOggStream los=(LogicalOggStream)streams.iterator().next();
153 if(los.getFormat()!=LogicalOggStream.FORMAT_VORBIS) {
154 throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
155 }
156
157 VorbisStream vs=new VorbisStream(los);
158
159 AudioFormat audioFormat=new AudioFormat(
160 (float)vs.getIdentificationHeader().getSampleRate(),
161 16,
162 vs.getIdentificationHeader().getChannels(),
163 true, true);
164
165 return new AudioInputStream(new VorbisInputStream(vs), audioFormat, -1);
166 }
167 catch(OggFormatException e) {
168 throw new UnsupportedAudioFileException(e.getMessage());
169 }
170 catch(VorbisFormatException e) {
171 throw new UnsupportedAudioFileException(e.getMessage());
172 }
173 }
174
175
176 public static class VorbisFormatType extends AudioFileFormat.Type {
177
178 private static final VorbisFormatType instance=new VorbisFormatType();
179
180 private VorbisFormatType() {
181 super("VORBIS", "ogg");
182 }
183
184 public static AudioFileFormat.Type getInstance() {
185 return instance;
186 }
187 }
188
189 public static class VorbisInputStream extends InputStream {
190
191 private VorbisStream source;
192 private byte[] buffer=new byte[8192];
193
194 public VorbisInputStream(VorbisStream source) {
195 this.source=source;
196 }
197
198 public int read() throws IOException {
199 return 0;
200 }
201
202 public int read(byte[] buffer) throws IOException {
203 return read(buffer, 0, buffer.length);
204 }
205
206 public int read(byte[] buffer, int offset, int length) throws IOException {
207 try {
208 return source.readPcm(buffer, offset, length);
209 }
210 catch(EndOfOggStreamException e) {
211 return -1;
212 }
213 }
214 }
215
216
217} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/VorbisFormatException.java b/songdbj/de/jarnbjo/vorbis/VorbisFormatException.java
new file mode 100644
index 0000000000..5214298378
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/VorbisFormatException.java
@@ -0,0 +1,51 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2005/02/09 23:10:47 shred
22 * Serial UID für jarnbjo
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37/**
38 * Exception thrown when trying to read a corrupted Vorbis stream.
39 */
40
41public class VorbisFormatException extends IOException {
42 private static final long serialVersionUID = 3616453405694834743L;
43
44 public VorbisFormatException() {
45 super();
46 }
47
48 public VorbisFormatException(String message) {
49 super(message);
50 }
51} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/VorbisStream.java b/songdbj/de/jarnbjo/vorbis/VorbisStream.java
new file mode 100644
index 0000000000..36659c7106
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/VorbisStream.java
@@ -0,0 +1,247 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.4 2003/04/10 19:49:04 jarnbjo
25 * no message
26 *
27 * Revision 1.3 2003/03/31 00:20:16 jarnbjo
28 * no message
29 *
30 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
31 * no message
32 *
33 *
34 */
35
36package de.jarnbjo.vorbis;
37
38import java.io.*;
39import java.util.*;
40
41import de.jarnbjo.ogg.*;
42import de.jarnbjo.util.io.*;
43
44/**
45 */
46
47public class VorbisStream {
48
49 private LogicalOggStream oggStream;
50 private IdentificationHeader identificationHeader;
51 private CommentHeader commentHeader;
52 private SetupHeader setupHeader;
53
54 private AudioPacket lastAudioPacket, nextAudioPacket;
55 private LinkedList audioPackets=new LinkedList();
56 private byte[] currentPcm;
57 private int currentPcmIndex;
58 private int currentPcmLimit;
59
60 private static final int IDENTIFICATION_HEADER = 1;
61 private static final int COMMENT_HEADER = 3;
62 private static final int SETUP_HEADER = 5;
63
64 private int bitIndex=0;
65 private byte lastByte=(byte)0;
66 private boolean initialized=false;
67
68 private Object streamLock=new Object();
69 private int pageCounter=0;
70
71 private int currentBitRate=0;
72
73 private long currentGranulePosition;
74
75 public static final int BIG_ENDIAN = 0;
76 public static final int LITTLE_ENDIAN = 1;
77
78 public VorbisStream() {
79 }
80
81 public VorbisStream(LogicalOggStream oggStream) throws VorbisFormatException, IOException {
82 this.oggStream=oggStream;
83
84 for(int i=0; i<3; i++) {
85 BitInputStream source=new ByteArrayBitInputStream(oggStream.getNextOggPacket());
86 int headerType=source.getInt(8);
87 switch(headerType) {
88 case IDENTIFICATION_HEADER:
89 identificationHeader=new IdentificationHeader(source);
90 break;
91 case COMMENT_HEADER:
92 commentHeader=new CommentHeader(source);
93 break;
94 case SETUP_HEADER:
95 setupHeader=new SetupHeader(this, source);
96 break;
97 }
98 }
99
100 if(identificationHeader==null) {
101 throw new VorbisFormatException("The file has no identification header.");
102 }
103
104 if(commentHeader==null) {
105 throw new VorbisFormatException("The file has no commentHeader.");
106 }
107
108 if(setupHeader==null) {
109 throw new VorbisFormatException("The file has no setup header.");
110 }
111
112 //currentPcm=new int[identificationHeader.getChannels()][16384];
113 currentPcm=new byte[identificationHeader.getChannels()*identificationHeader.getBlockSize1()*2];
114 //new BufferThread().start();
115 }
116
117 public IdentificationHeader getIdentificationHeader() {
118 return identificationHeader;
119 }
120
121 public CommentHeader getCommentHeader() {
122 return commentHeader;
123 }
124
125 protected SetupHeader getSetupHeader() {
126 return setupHeader;
127 }
128
129 public boolean isOpen() {
130 return oggStream.isOpen();
131 }
132
133 public void close() throws IOException {
134 oggStream.close();
135 }
136
137
138 public int readPcm(byte[] buffer, int offset, int length) throws IOException {
139 synchronized (streamLock) {
140 final int channels=identificationHeader.getChannels();
141
142 if(lastAudioPacket==null) {
143 lastAudioPacket=getNextAudioPacket();
144 }
145 if(currentPcm==null || currentPcmIndex>=currentPcmLimit) {
146 AudioPacket ap=getNextAudioPacket();
147 try {
148 ap.getPcm(lastAudioPacket, currentPcm);
149 currentPcmLimit=ap.getNumberOfSamples()*identificationHeader.getChannels()*2;
150 }
151 catch(ArrayIndexOutOfBoundsException e) {
152 return 0;
153 }
154 currentPcmIndex=0;
155 lastAudioPacket=ap;
156 }
157 int written=0;
158 int i=0;
159 int arrIx=0;
160 for(i=currentPcmIndex; i<currentPcmLimit && arrIx<length; i++) {
161 buffer[offset+arrIx++]=currentPcm[i];
162 written++;
163 }
164 currentPcmIndex=i;
165 return written;
166 }
167 }
168
169
170 private AudioPacket getNextAudioPacket() throws VorbisFormatException, IOException {
171 pageCounter++;
172 byte[] data=oggStream.getNextOggPacket();
173 AudioPacket res=null;
174 while(res==null) {
175 try {
176 res=new AudioPacket(this, new ByteArrayBitInputStream(data));
177 }
178 catch(ArrayIndexOutOfBoundsException e) {
179 // ignore and continue with next packet
180 }
181 }
182 currentGranulePosition+=res.getNumberOfSamples();
183 currentBitRate=data.length*8*identificationHeader.getSampleRate()/res.getNumberOfSamples();
184 return res;
185 }
186
187 public long getCurrentGranulePosition() {
188 return currentGranulePosition;
189 }
190
191 public int getCurrentBitRate() {
192 return currentBitRate;
193 }
194
195 public byte[] processPacket(byte[] packet) throws VorbisFormatException, IOException {
196 if(packet.length==0) {
197 throw new VorbisFormatException("Cannot decode a vorbis packet with length = 0");
198 }
199 if(((int)packet[0]&1)==1) {
200 // header packet
201 BitInputStream source=new ByteArrayBitInputStream(packet);
202 switch(source.getInt(8)) {
203 case IDENTIFICATION_HEADER:
204 identificationHeader=new IdentificationHeader(source);
205 break;
206 case COMMENT_HEADER:
207 commentHeader=new CommentHeader(source);
208 break;
209 case SETUP_HEADER:
210 setupHeader=new SetupHeader(this, source);
211 break;
212 }
213 return null;
214 }
215 else {
216 // audio packet
217 if(identificationHeader==null ||
218 commentHeader==null ||
219 setupHeader==null) {
220
221 throw new VorbisFormatException("Cannot decode audio packet before all three header packets have been decoded.");
222 }
223
224 AudioPacket ap=new AudioPacket(this, new ByteArrayBitInputStream(packet));
225 currentGranulePosition+=ap.getNumberOfSamples();
226
227 if(lastAudioPacket==null) {
228 lastAudioPacket=ap;
229 return null;
230 }
231
232 byte[] res=new byte[identificationHeader.getChannels()*ap.getNumberOfSamples()*2];
233
234 try {
235 ap.getPcm(lastAudioPacket, res);
236 }
237 catch(IndexOutOfBoundsException e) {
238 java.util.Arrays.fill(res, (byte)0);
239 }
240
241 lastAudioPacket=ap;
242
243 return res;
244 }
245 }
246
247} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/AudioFile.java b/songdbj/entagged/audioformats/AudioFile.java
new file mode 100644
index 0000000000..8ff49c0d84
--- /dev/null
+++ b/songdbj/entagged/audioformats/AudioFile.java
@@ -0,0 +1,186 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats;
23
24import entagged.audioformats.exceptions.*;
25import entagged.audioformats.generic.GenericTag;
26
27import java.io.*;
28
29/**
30 * <p>This is the main object manipulated by the user representing an audiofile, its properties and its tag.</p>
31 * <p>The prefered way to obtain an <code>AudioFile</code> is to use the <code>AudioFileIO.read(File)</code> method.</p>
32 * <p>The <code>AudioFile</code> contains every properties associated with the file itself (no meta-data), like the bitrate, the sampling rate, the encoding infos, etc.</p>
33 * <p>To get the meta-data contained in this file you have to get the <code>Tag</code> of this <code>AudioFile</code></p>
34 *
35 *@author Raphael Slinckx
36 *@version $Id$
37 *@since v0.01
38 *@see AudioFileIO
39 *@see Tag
40 */
41public class AudioFile extends File {
42 private static final long serialVersionUID = 3257289136422728502L;
43
44 private EncodingInfo info;
45 private Tag tag;
46
47 /**
48 * <p>These constructors are used by the different readers, users should not use them, but use the <code>AudioFileIO.read(File)</code> method instead !.</p>
49 * <p>Create the AudioFile representing file denoted by pathname s, the encodinginfos and containing the tag</p>
50 *
51 *@param s The pathname of the audiofile
52 *@param info the encoding infos over this file
53 *@param tag the tag contained in this file
54 */
55 public AudioFile(String s, EncodingInfo info, Tag tag) {
56 super(s);
57 this.info = info;
58 this.tag = tag;
59 }
60
61 /**
62 * <p>These constructors are used by the different readers, users should not use them, but use the <code>AudioFileIO.read(File)</code> method instead !.</p>
63 * <p>Create the AudioFile representing file denoted by pathname s, the encodinginfos and containing an empty tag</p>
64 *
65 *@param s The pathname of the audiofile
66 *@param info the encoding infos over this file
67 */
68 public AudioFile(String s, EncodingInfo info) {
69 super(s);
70 this.info = info;
71 this.tag = new GenericTag();
72 }
73
74 /**
75 * <p>These constructors are used by the different readers, users should not use them, but use the <code>AudioFileIO.read(File)</code> method instead !.</p>
76 * <p>Create the AudioFile representing file f, the encodinginfos and containing the tag</p>
77 *
78 *@param f The file of the audiofile
79 *@param info the encoding infos over this file
80 *@param tag the tag contained in this file
81 */
82 public AudioFile(File f, EncodingInfo info, Tag tag) {
83 super(f.getAbsolutePath());
84 this.info = info;
85 this.tag = tag;
86 }
87
88 /**
89 * <p>These constructors are used by the different readers, users should not use them, but use the <code>AudioFileIO.read(File)</code> method instead !.</p>
90 * <p>Create the AudioFile representing file f, the encodinginfos and containing an empty tag</p>
91 *
92 *@param f The file of the audiofile
93 *@param info the encoding infos over this file
94 */
95 public AudioFile(File f, EncodingInfo info) {
96 super(f.getAbsolutePath());
97 this.info = info;
98 this.tag = new GenericTag();
99 }
100
101 /**
102 * <p>Returns the bitrate of this AufioFile in kilobytes per second (KB/s). Example: 192 KB/s</p>
103 *
104 *@return Returns the bitrate of this AufioFile
105 */
106 public int getBitrate() {
107 return info.getBitrate();
108 }
109
110 /**
111 * <p>Returns the number of audio channels contained in this AudioFile, 2 for example means stereo</p>
112 *
113 *@return Returns the number of audio channels contained in this AudioFile
114 */
115 public int getChannelNumber() {
116 return info.getChannelNumber();
117 }
118
119 /**
120 * <p>Returns the encoding type of this AudioFile, this needs to be precisely specified in the future</p>
121 *
122 *@return Returns the encoding type of this AudioFile
123 *@todo This method needs to be fully specified
124 */
125 public String getEncodingType() {
126 return info.getEncodingType();
127 }
128
129 /**
130 * <p>Returns the extra encoding infos of this AudioFile, this needs to be precisely specified in the future</p>
131 *
132 *@return Returns the extra encoding infos of this AudioFile
133 *@todo This method needs to be fully specified
134 */
135 public String getExtraEncodingInfos() {
136 return info.getExtraEncodingInfos();
137 }
138
139 /**
140 * <p>Returns the sampling rate of this AudioFile in Hertz (Hz). Example: 44100 Hz for most of the audio files</p>
141 *
142 *@return Returns the sampling rate of this AudioFile
143 */
144 public int getSamplingRate() {
145 return info.getSamplingRate();
146 }
147
148 /**
149 * <p>Returns the length (duration) in seconds (s) of this AudioFile.Example: 241 seconds</p>
150 *
151 *@return Returns the length (duration) of this AudioFile
152 */
153 public int getLength() {
154 return info.getLength();
155 }
156
157 /**
158 * <p>Returns the tag contained in this AudioFile, the <code>Tag</code> contains any useful meta-data, like artist, album, title, etc.</p>
159 * <p>If the file does not contain any tag, a new empty tag is returned</p>
160 *
161 *@return Returns the tag contained in this AudioFile, or a new one if file hasn't any tag.
162 */
163 public Tag getTag() {
164 return (tag == null) ? new GenericTag() : tag;
165 }
166
167 /*
168 * <p>Checks if this file is a VBR (variable bitrate) or a Constant Bitrate one</p>
169 * <p>True means VBR, false means CBR</p>
170 * <p>This has only meaning with MP3 and MPC files, other formats are always VBR
171 * since it offers a better compression ratio (and lossless compression is by nature VBR</p>
172 */
173 public boolean isVbr() {
174 return info.isVbr();
175 }
176
177 /**
178 * <p>Returns a multi-line string with the file path, the encoding informations, and the tag contents.</p>
179 *
180 *@return A multi-line string with the file path, the encoding informations, and the tag contents.
181 *@todo Maybe this can be changed ?
182 */
183 public String toString() {
184 return "AudioFile "+getAbsolutePath()+" --------\n"+info.toString()+"\n"+ ( (tag == null) ? "" : tag.toString())+"\n-------------------";
185 }
186}
diff --git a/songdbj/entagged/audioformats/EncodingInfo.java b/songdbj/entagged/audioformats/EncodingInfo.java
new file mode 100644
index 0000000000..6f1ff0ff91
--- /dev/null
+++ b/songdbj/entagged/audioformats/EncodingInfo.java
@@ -0,0 +1,116 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats;
23
24import java.util.*;
25
26public class EncodingInfo {
27
28 private Hashtable content;
29
30 public EncodingInfo() {
31 content = new Hashtable(6);
32 content.put("BITRATE", new Integer(-1) );
33 content.put("CHANNB", new Integer(-1) );
34 content.put("TYPE", "");
35 content.put("INFOS", "");
36 content.put("SAMPLING", new Integer(-1) );
37 content.put("LENGTH", new Integer(-1) );
38 content.put("VBR", new Boolean(true) );
39 }
40
41 //Sets the bitrate in KByte/s
42 public void setBitrate( int bitrate ) {
43 content.put("BITRATE", new Integer(bitrate) );
44 }
45 //Sets the number of channels
46 public void setChannelNumber( int chanNb ) {
47 content.put("CHANNB", new Integer(chanNb) );
48 }
49 //Sets the type of the encoding, this is a bit format specific. eg:Layer I/II/II
50 public void setEncodingType( String encodingType ) {
51 content.put("TYPE", encodingType );
52 }
53 //A string contianing anything else that might be interesting
54 public void setExtraEncodingInfos( String infos ) {
55 content.put("INFOS", infos );
56 }
57 //Sets the Sampling rate in Hz
58 public void setSamplingRate( int samplingRate ) {
59 content.put("SAMPLING", new Integer(samplingRate) );
60 }
61 //Sets the length of the song in seconds
62 public void setLength( int length ) {
63 content.put("LENGTH", new Integer(length) );
64 }
65 //Is the song vbr or not ?
66 public void setVbr( boolean b ) {
67 content.put("VBR", new Boolean(b) );
68 }
69
70
71 //returns the bitrate in KByte/s
72 public int getBitrate() {
73 return ((Integer) content.get("BITRATE")).intValue();
74 }
75 //Returns the number of channels
76 public int getChannelNumber() {
77 return ((Integer) content.get("CHANNB")).intValue();
78 }
79 //returns the encoding type.
80 public String getEncodingType() {
81 return (String) content.get("TYPE");
82 }
83 //returns a string with misc. information about the encoding
84 public String getExtraEncodingInfos() {
85 return (String) content.get("INFOS");
86 }
87 //returns the sample rate in Hz
88 public int getSamplingRate() {
89 return ((Integer) content.get("SAMPLING")).intValue();
90 }
91 //Returns the length of the song in seconds
92 public int getLength() {
93 return ((Integer) content.get("LENGTH")).intValue();
94 }
95 //Is the song vbr ?
96 public boolean isVbr() {
97 return ((Boolean) content.get("VBR")).booleanValue();
98 }
99
100 //Pretty prints this encoding info
101 public String toString() {
102 StringBuffer out = new StringBuffer(50);
103 out.append("Encoding infos content:\n");
104 Enumeration en = content.keys();
105 while(en.hasMoreElements()) {
106 Object key = en.nextElement();
107 Object val = content.get(key);
108 out.append("\t");
109 out.append(key);
110 out.append(" : ");
111 out.append(val);
112 out.append("\n");
113 }
114 return out.toString().substring(0,out.length()-1);
115 }
116}
diff --git a/songdbj/entagged/audioformats/Tag.java b/songdbj/entagged/audioformats/Tag.java
new file mode 100644
index 0000000000..c1189ec2e3
--- /dev/null
+++ b/songdbj/entagged/audioformats/Tag.java
@@ -0,0 +1,116 @@
1package entagged.audioformats;
2
3import java.util.Iterator;
4import java.util.List;
5
6import entagged.audioformats.generic.TagField;
7
8public interface Tag {
9 /**
10 * This final field contains all the tags that id3v1 supports. The list has
11 * the same order as the id3v1 genres. To be perfectly compatible (with
12 * id3v1) the genre field should match one of these genre (case ignored).
13 * You can also use this list to present a list of basic (modifiable)
14 * possible choices for the genre field.
15 */
16 public static final String[] DEFAULT_GENRES = { "Blues", "Classic Rock",
17 "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz",
18 "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap",
19 "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
20 "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient",
21 "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical",
22 "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel",
23 "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space",
24 "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic",
25 "Gothic", "Darkwave", "Techno-Industrial", "Electronic",
26 "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
27 "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
28 "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave",
29 "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk",
30 "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll",
31 "Hard Rock", "Folk", "Folk-Rock", "National Folk", "Swing",
32 "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
33 "Avantgarde", "Gothic Rock", "Progressive Rock",
34 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
35 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
36 "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony",
37 "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam",
38 "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad",
39 "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo",
40 "A capella", "Euro-House", "Dance Hall" };
41
42 public void add(TagField field);
43
44 public void addAlbum(String s);
45
46 public void addArtist(String s);
47
48 public void addComment(String s);
49
50 public void addGenre(String s);
51
52 public void addTitle(String s);
53
54 public void addTrack(String s);
55
56 public void addYear(String s);
57
58 public List get(String id);
59
60 public Iterator getFields();
61
62 public List getGenre();
63
64 public List getTitle();
65
66 public List getTrack();
67
68 public List getYear();
69 public List getAlbum();
70
71 public List getArtist();
72
73 public List getComment();
74
75 public String getFirstGenre();
76
77 public String getFirstTitle();
78
79 public String getFirstTrack();
80
81 public String getFirstYear();
82 public String getFirstAlbum();
83
84 public String getFirstArtist();
85
86 public String getFirstComment();
87
88 public boolean hasCommonFields();
89
90 public boolean hasField(String id);
91
92 public boolean isEmpty();
93
94 //public Iterator getCommonFields();
95 //public Iterator getSpecificFields();
96
97 public void merge(Tag tag);
98
99 public void set(TagField field);
100
101 public void setAlbum(String s);
102
103 public void setArtist(String s);
104
105 public void setComment(String s);
106
107 public void setGenre(String s);
108
109 public void setTitle(String s);
110
111 public void setTrack(String s);
112
113 public void setYear(String s);
114
115 public String toString();
116} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/AsfFileReader.java b/songdbj/entagged/audioformats/asf/AsfFileReader.java
new file mode 100644
index 0000000000..d408a9fa56
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/AsfFileReader.java
@@ -0,0 +1,112 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf;
23
24import java.io.IOException;
25import java.io.RandomAccessFile;
26
27import entagged.audioformats.EncodingInfo;
28import entagged.audioformats.Tag;
29import entagged.audioformats.asf.data.AsfHeader;
30import entagged.audioformats.asf.io.AsfHeaderReader;
31import entagged.audioformats.asf.util.TagConverter;
32import entagged.audioformats.exceptions.CannotReadException;
33import entagged.audioformats.generic.AudioFileReader;
34
35/**
36 * This reader can read asf files containing any content (stream type). <br>
37 *
38 * @author Christian Laireiter
39 */
40public class AsfFileReader extends AudioFileReader {
41
42 /**
43 * (overridden)
44 *
45 * @see entagged.audioformats.generic.AudioFileReader#getEncodingInfo(java.io.RandomAccessFile)
46 */
47 protected EncodingInfo getEncodingInfo(RandomAccessFile raf)
48 throws CannotReadException, IOException {
49 raf.seek(0);
50 EncodingInfo info = new EncodingInfo();
51 try {
52 AsfHeader header = AsfHeaderReader.readHeader(raf);
53 if (header == null) {
54 throw new CannotReadException(
55 "Some values must have been "
56 + "incorrect for interpretation as asf with wma content.");
57 }
58 info.setBitrate(header.getAudioStreamChunk().getKbps());
59 info.setChannelNumber((int) header.getAudioStreamChunk()
60 .getChannelCount());
61 info.setEncodingType("ASF (audio): "+header.getAudioStreamChunk()
62 .getCodecDescription());
63 info.setLength(header.getFileHeader().getDurationInSeconds());
64 info.setSamplingRate((int) header.getAudioStreamChunk()
65 .getSamplingRate());
66
67 } catch (Exception e) {
68 if (e instanceof IOException)
69 throw (IOException) e;
70 else if (e instanceof CannotReadException)
71 throw (CannotReadException) e;
72 else {
73 throw new CannotReadException("Failed to read. Cause: "
74 + e.getMessage());
75 }
76 }
77 return info;
78 }
79
80 /**
81 * (overridden)
82 *
83 * @see entagged.audioformats.generic.AudioFileReader#getTag(java.io.RandomAccessFile)
84 */
85 protected Tag getTag(RandomAccessFile raf) throws CannotReadException,
86 IOException {
87 raf.seek(0);
88 Tag tag = null;
89 try {
90 AsfHeader header = AsfHeaderReader.readHeader(raf);
91 if (header == null) {
92 throw new CannotReadException(
93 "Some values must have been "
94 + "incorrect for interpretation as asf with wma content.");
95 }
96
97 tag = TagConverter.createTagOf(header);
98
99 } catch (Exception e) {
100 if (e instanceof IOException)
101 throw (IOException) e;
102 else if (e instanceof CannotReadException)
103 throw (CannotReadException) e;
104 else {
105 throw new CannotReadException("Failed to read. Cause: "
106 + e.getMessage());
107 }
108 }
109 return tag;
110 }
111
112} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/AsfHeader.java b/songdbj/entagged/audioformats/asf/data/AsfHeader.java
new file mode 100644
index 0000000000..3b4feefe87
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/AsfHeader.java
@@ -0,0 +1,279 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.math.BigInteger;
25import java.util.Arrays;
26
27/**
28 * Each asf file starts with a so called header. <br>
29 * This header contains other chunks. Each chunk starts with a 16 byte GUID
30 * followed by the length (in bytes) of the chunk (including GUID). The length
31 * number takes 8 bytes and is unsigned. Finally the chunk's data appears. <br>
32 *
33 * @author Christian Laireiter
34 */
35public class AsfHeader extends Chunk {
36
37 /**
38 * An asf header contains multiple chunks. <br>
39 * The count of those is stored here.
40 */
41 private final long chunkCount;
42
43 /**
44 * The content description of the entire file.
45 */
46 private ContentDescription contentDescription;
47
48 /**
49 * Stores the encoding chunk.
50 */
51 private EncodingChunk encodingChunk;
52
53 /**
54 * Stores the tag header.
55 */
56 private ExtendedContentDescription extendedContentDescription;
57
58 /**
59 * Stores the file header.
60 */
61 private FileHeader fileHeader;
62
63 /**
64 * This array stores all found stream chunks.
65 */
66 private StreamChunk[] streamChunks;
67
68 /**
69 * This field stores all chunks which aren't specified and not represented
70 * by a wrapper. <br>
71 * However during write operations this position and size of those chunks is
72 * useful.
73 */
74 private Chunk[] unspecifiedChunks;
75
76 /**
77 * Creates an instance.
78 *
79 * @param pos
80 * see {@link Chunk#position}
81 * @param chunkLen
82 * see {@link Chunk#chunkLength}
83 * @param chunkCnt
84 */
85 public AsfHeader(long pos, BigInteger chunkLen, long chunkCnt) {
86 super(GUID.GUID_HEADER, pos, chunkLen);
87 this.chunkCount = chunkCnt;
88 this.streamChunks = new StreamChunk[0];
89 this.unspecifiedChunks = new Chunk[0];
90 }
91
92 /**
93 * This method appends a StreamChunk to the header. <br>
94 *
95 * @param toAdd
96 * Chunk to add.
97 */
98 public void addStreamChunk(StreamChunk toAdd) {
99 if (toAdd == null) {
100 throw new IllegalArgumentException("Argument must not be null.");
101 }
102 if (!Arrays.asList(this.streamChunks).contains(toAdd)) {
103 StreamChunk[] tmp = new StreamChunk[this.streamChunks.length + 1];
104 System.arraycopy(this.streamChunks, 0, tmp, 0,
105 this.streamChunks.length);
106 tmp[tmp.length - 1] = toAdd;
107 this.streamChunks = tmp;
108 }
109 }
110
111 /**
112 * This method appends the given chunk to the
113 * {@linkplain #unspecifiedChunks unspecified}list. <br>
114 *
115 * @param toAppend
116 * The chunk whose use is unknown or of no interest.
117 */
118 public void addUnspecifiedChunk(Chunk toAppend) {
119 if (toAppend == null) {
120 throw new IllegalArgumentException("Argument must not be null.");
121 }
122 if (!Arrays.asList(unspecifiedChunks).contains(toAppend)) {
123 Chunk[] tmp = new Chunk[unspecifiedChunks.length + 1];
124 System.arraycopy(unspecifiedChunks, 0, tmp, 0,
125 unspecifiedChunks.length);
126 tmp[tmp.length - 1] = toAppend;
127 unspecifiedChunks = tmp;
128 }
129 }
130
131 /**
132 * This method returns the first audio stream chunk found in the asf file or
133 * stream.
134 *
135 * @return Returns the audioStreamChunk.
136 */
137 public AudioStreamChunk getAudioStreamChunk() {
138 AudioStreamChunk result = null;
139 for (int i = 0; i < getStreamChunkCount() && result == null; i++) {
140 StreamChunk tmp = getStreamChunk(i);
141 if (tmp instanceof AudioStreamChunk) {
142 result = (AudioStreamChunk) tmp;
143 }
144 }
145 return result;
146 }
147
148 /**
149 * @return Returns the chunkCount.
150 */
151 public long getChunkCount() {
152 return chunkCount;
153 }
154
155 /**
156 * @return Returns the contentDescription.
157 */
158 public ContentDescription getContentDescription() {
159 return contentDescription;
160 }
161
162 /**
163 * @return Returns the encodingChunk.
164 */
165 public EncodingChunk getEncodingChunk() {
166 return encodingChunk;
167 }
168
169 /**
170 * @return Returns the tagHeader.
171 */
172 public ExtendedContentDescription getExtendedContentDescription() {
173 return extendedContentDescription;
174 }
175
176 /**
177 * @return Returns the fileHeader.
178 */
179 public FileHeader getFileHeader() {
180 return fileHeader;
181 }
182
183 /**
184 * This method returns the StreamChunk at given index. <br>
185 *
186 * @param index
187 * index of the wanted chunk
188 * @return StreamChunk at given index.
189 */
190 public StreamChunk getStreamChunk(int index) {
191 return this.streamChunks[index];
192 }
193
194 /**
195 * This method returns the amount of StreamChunks in this header. <br>
196 *
197 * @return Number of inserted StreamChunks.
198 */
199 public int getStreamChunkCount() {
200 return this.streamChunks.length;
201 }
202
203 /**
204 * This method returns the unspecified chunk at given position. <br>
205 *
206 * @param index
207 * Index of the wanted chunk
208 * @return The chunk at given index.
209 */
210 public Chunk getUnspecifiedChunk(int index) {
211 return this.unspecifiedChunks[index];
212 }
213
214 /**
215 * This method returns the number of {@link Chunk}objects which where
216 * inserted using {@link #addUnspecifiedChunk(Chunk)}.
217 *
218 * @return Number of unspecified chunks.
219 */
220 public int getUnspecifiedChunkCount() {
221 return this.unspecifiedChunks.length;
222 }
223
224 /**
225 * (overridden)
226 *
227 * @see entagged.audioformats.asf.data.Chunk#prettyPrint()
228 */
229 public String prettyPrint() {
230 StringBuffer result = new StringBuffer(super.prettyPrint());
231 result.insert(0, "\nASF Chunk\n");
232 result.append(" Contains: \"" + getChunkCount() + "\" chunks\n");
233 result.append(getFileHeader());
234 result.append(getExtendedContentDescription());
235 result.append(getEncodingChunk());
236 result.append(getContentDescription());
237 for (int i = 0; i < getStreamChunkCount(); i++) {
238 result.append(getStreamChunk(i));
239 }
240 return result.toString();
241 }
242
243 /**
244 * @param contentDesc
245 * sets the contentDescription. <code>null</code> deletes the
246 * chunk.
247 */
248 public void setContentDescription(ContentDescription contentDesc) {
249 this.contentDescription = contentDesc;
250 }
251
252 /**
253 * @param encChunk
254 * The encodingChunk to set.
255 */
256 public void setEncodingChunk(EncodingChunk encChunk) {
257 if (encChunk == null)
258 throw new IllegalArgumentException("Argument must not be null.");
259 this.encodingChunk = encChunk;
260 }
261
262 /**
263 * @param th
264 * sets the extendedContentDescription. <code>null</code>
265 * delete the chunk.
266 */
267 public void setExtendedContentDescription(ExtendedContentDescription th) {
268 this.extendedContentDescription = th;
269 }
270
271 /**
272 * @param fh
273 */
274 public void setFileHeader(FileHeader fh) {
275 if (fh == null)
276 throw new IllegalArgumentException("Argument must not be null.");
277 this.fileHeader = fh;
278 }
279} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/AudioStreamChunk.java b/songdbj/entagged/audioformats/asf/data/AudioStreamChunk.java
new file mode 100644
index 0000000000..619f0c2a42
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/AudioStreamChunk.java
@@ -0,0 +1,292 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.math.BigInteger;
25
26import entagged.audioformats.asf.util.Utils;
27
28/**
29 * This class represents the streamchunk describing an audio stream. <br>
30 *
31 * @author Christian Laireiter
32 */
33public class AudioStreamChunk extends StreamChunk {
34
35 /**
36 * Stores the hex values of codec identifiers to their descriptions. <br>
37 */
38 public final static String[][] CODEC_DESCRIPTIONS = {
39 { "161", " (Windows Media Audio (ver 7,8,9))" },
40 { "162", " (Windows Media Audio 9 series (Professional))" },
41 { "163", "(Windows Media Audio 9 series (Lossless))" },
42 { "7A21", " (GSM-AMR (CBR))" }, { "7A22", " (GSM-AMR (VBR))" } };
43
44 /**
45 * Stores the average amount of bytes used by audio stream. <br>
46 * This value is a field within type specific data of audio stream. Maybe it
47 * could be used to calculate the kbps.
48 */
49 private long averageBytesPerSec;
50
51 /**
52 * Amount of bits used per sample. <br>
53 */
54 private int bitsPerSample;
55
56 /**
57 * The block alignment of the audio data.
58 */
59 private long blockAlignment;
60
61 /**
62 * Number of channels.
63 */
64 private long channelCount;
65
66 /**
67 * Some data which needs to be interpreted if the codec is handled.
68 */
69 private byte[] codecData;
70
71 /**
72 * The audio compression format code.
73 */
74 private long compressionFormat;
75
76 /**
77 * this field stores the error concealment type.
78 */
79 private GUID errorConcealment;
80
81 /**
82 * Sampling rate of audio stream.
83 */
84 private long samplingRate;
85
86 /**
87 * Creates an instance.
88 *
89 * @param pos
90 * Position of current chunk within asf file or stream.
91 * @param chunkLen
92 * Length of the entire chunk (including guid and size)
93 */
94 public AudioStreamChunk(long pos, BigInteger chunkLen) {
95 super(pos, chunkLen);
96 }
97
98 /**
99 * @return Returns the averageBytesPerSec.
100 */
101 public long getAverageBytesPerSec() {
102 return averageBytesPerSec;
103 }
104
105 /**
106 * @return Returns the bitsPerSample.
107 */
108 public int getBitsPerSample() {
109 return bitsPerSample;
110 }
111
112 /**
113 * @return Returns the blockAlignment.
114 */
115 public long getBlockAlignment() {
116 return blockAlignment;
117 }
118
119 /**
120 * @return Returns the channelCount.
121 */
122 public long getChannelCount() {
123 return channelCount;
124 }
125
126 /**
127 * @return Returns the codecData.
128 */
129 public byte[] getCodecData() {
130 return codecData;
131 }
132
133 /**
134 * This method will take a look at {@link #compressionFormat}and returns a
135 * String with its hex value and if known a textual note on what coded it
136 * represents. <br>
137 *
138 * @return A description for the used codec.
139 */
140 public String getCodecDescription() {
141 StringBuffer result = new StringBuffer(Long
142 .toHexString(getCompressionFormat()));
143 String furtherDesc = " (Unknown)";
144 for (int i = 0; i < CODEC_DESCRIPTIONS.length; i++) {
145 if (CODEC_DESCRIPTIONS[i][0].equalsIgnoreCase(result.toString())) {
146 furtherDesc = CODEC_DESCRIPTIONS[i][1];
147 break;
148 }
149 }
150 if (result.length() % 2 != 0) {
151 result.insert(0, "0x0");
152 } else {
153 result.insert(0, "0x");
154 }
155 result.append(furtherDesc);
156 return result.toString();
157 }
158
159 /**
160 * @return Returns the compressionFormat.
161 */
162 public long getCompressionFormat() {
163 return compressionFormat;
164 }
165
166 /**
167 * @return Returns the errorConcealment.
168 */
169 public GUID getErrorConcealment() {
170 return errorConcealment;
171 }
172
173 /**
174 * This method takes the value of {@link #getAverageBytesPerSec()}and
175 * calculates the kbps out of it, by simply multiplying by 8 and dividing by
176 * 1000. <br>
177 *
178 * @return amount of bits per second in kilo bits.
179 */
180 public int getKbps() {
181 return (int) getAverageBytesPerSec() * 8 / 1000;
182 }
183
184 /**
185 * @return Returns the samplingRate.
186 */
187 public long getSamplingRate() {
188 return samplingRate;
189 }
190
191 /**
192 * This mehtod returns whether the audio stream data is error concealed.
193 * <br>
194 * For now only interleaved concealment is known. <br>
195 *
196 * @return <code>true</code> if error concealment is used.
197 */
198 public boolean isErrorConcealed() {
199 return getErrorConcealment().equals(
200 GUID.GUID_AUDIO_ERROR_CONCEALEMENT_INTERLEAVED);
201 }
202
203 /**
204 * (overridden)
205 *
206 * @see entagged.audioformats.asf.data.StreamChunk#prettyPrint()
207 */
208 public String prettyPrint() {
209 StringBuffer result = new StringBuffer(super.prettyPrint().replaceAll(
210 Utils.LINE_SEPARATOR, Utils.LINE_SEPARATOR + " "));
211 result.insert(0, Utils.LINE_SEPARATOR + "AudioStream");
212 result.append("Audio info:" + Utils.LINE_SEPARATOR);
213 result.append(" Bitrate : " + getKbps() + Utils.LINE_SEPARATOR);
214 result.append(" Channels : " + getChannelCount() + " at "
215 + getSamplingRate() + " Hz" + Utils.LINE_SEPARATOR);
216 result.append(" Bits per Sample: " + getBitsPerSample()
217 + Utils.LINE_SEPARATOR);
218 result.append(" Formatcode: " + getCodecDescription()
219 + Utils.LINE_SEPARATOR);
220 return result.toString();
221 }
222
223 /**
224 * @param avgeBytesPerSec
225 * The averageBytesPerSec to set.
226 */
227 public void setAverageBytesPerSec(long avgeBytesPerSec) {
228 this.averageBytesPerSec = avgeBytesPerSec;
229 }
230
231 /**
232 * Sets the bitsPerSample
233 *
234 * @param bps
235 */
236 public void setBitsPerSample(int bps) {
237 this.bitsPerSample = bps;
238 }
239
240 /**
241 * Sets the blockAlignment.
242 *
243 * @param align
244 */
245 public void setBlockAlignment(long align) {
246 this.blockAlignment = align;
247 }
248
249 /**
250 * @param channels
251 * The channelCount to set.
252 */
253 public void setChannelCount(long channels) {
254 this.channelCount = channels;
255 }
256
257 /**
258 * Sets the codecData
259 *
260 * @param codecSpecificData
261 */
262 public void setCodecData(byte[] codecSpecificData) {
263 this.codecData = codecSpecificData;
264 }
265
266 /**
267 * @param cFormatCode
268 * The compressionFormat to set.
269 */
270 public void setCompressionFormat(long cFormatCode) {
271 this.compressionFormat = cFormatCode;
272 }
273
274 /**
275 * This method sets the error concealment type which is given by two GUIDs.
276 * <br>
277 *
278 * @param errConc
279 * the type of error concealment the audio stream is stored as.
280 */
281 public void setErrorConcealment(GUID errConc) {
282 this.errorConcealment = errConc;
283 }
284
285 /**
286 * @param sampRate
287 * The samplingRate to set.
288 */
289 public void setSamplingRate(long sampRate) {
290 this.samplingRate = sampRate;
291 }
292} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/Chunk.java b/songdbj/entagged/audioformats/asf/data/Chunk.java
new file mode 100644
index 0000000000..b0da2fc853
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/Chunk.java
@@ -0,0 +1,135 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.math.BigInteger;
25
26/**
27 * This class represents a chunk within asf streams. <br>
28 * Each chunk starts with a 16byte guid identifying the type. After that a
29 * number (represented by 8 bytes) follows which shows the size in bytes of the
30 * chunk. Finally there is the data of the chunk.
31 *
32 * @author Christian Laireiter
33 */
34public class Chunk {
35
36 /**
37 * The length of current chunk. <br>
38 */
39 protected final BigInteger chunkLength;
40
41 /**
42 * The guid of represented chunk header.
43 */
44 protected final GUID guid;
45
46 /**
47 * The position of current header object within file or stream.
48 */
49 protected final long position;
50
51 /**
52 * Creates an instance
53 *
54 * @param headerGuid
55 * The GUID of header object.
56 * @param pos
57 * Position of header object within stream or file.
58 * @param chunkLen
59 * Length of current chunk.
60 */
61 public Chunk(GUID headerGuid, long pos, BigInteger chunkLen) {
62 if (headerGuid == null) {
63 throw new IllegalArgumentException(
64 "GUID must not be null nor anything else than "
65 + GUID.GUID_LENGTH + " entries long.");
66 }
67 if (pos < 0) {
68 throw new IllegalArgumentException(
69 "Position of header can't be negative.");
70 }
71 if (chunkLen == null || chunkLen.compareTo(BigInteger.ZERO) < 0) {
72 throw new IllegalArgumentException(
73 "chunkLen must not be null nor negative.");
74 }
75 this.guid = headerGuid;
76 this.position = pos;
77 this.chunkLength = chunkLen;
78 }
79
80 /**
81 * This method returns the End of the current chunk introduced by current
82 * header object.
83 *
84 * @return Position after current chunk.
85 */
86 public long getChunckEnd() {
87 return position + chunkLength.longValue();
88 }
89
90 /**
91 * @return Returns the chunkLength.
92 */
93 public BigInteger getChunkLength() {
94 return chunkLength;
95 }
96
97 /**
98 * @return Returns the guid.
99 */
100 public GUID getGuid() {
101 return guid;
102 }
103
104 /**
105 * @return Returns the position.
106 */
107 public long getPosition() {
108 return position;
109 }
110
111 /**
112 * This method creates a String containing usefull information prepared to
113 * be printed on stdout. <br>
114 * This method is intended to be overwritten by inheriting classes.
115 *
116 * @return Information of current Chunk Object.
117 */
118 public String prettyPrint() {
119 StringBuffer result = new StringBuffer();
120 result.append("GUID: " + GUID.getGuidDescription(guid));
121 result.append("\n Starts at position: " + getPosition() + "\n");
122 result.append(" Last byte at: " + (getChunckEnd() - 1) + "\n\n");
123 return result.toString();
124 }
125
126 /**
127 * (overridden)
128 *
129 * @see java.lang.Object#toString()
130 */
131 public String toString() {
132 return prettyPrint();
133 }
134
135} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/ContentDescription.java b/songdbj/entagged/audioformats/asf/data/ContentDescription.java
new file mode 100644
index 0000000000..6601a2ccdc
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/ContentDescription.java
@@ -0,0 +1,251 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.io.ByteArrayOutputStream;
25import java.math.BigInteger;
26
27import entagged.audioformats.asf.util.Utils;
28
29/**
30 * This class represents the data of a chunk which contains title, author,
31 * copyright, description and the rating of the file. <br>
32 * It is optional whithin asf files. But if exists only once.
33 *
34 * @author Christian Laireiter
35 */
36public class ContentDescription extends Chunk {
37
38 /**
39 * File artist.
40 */
41 private String author = null;
42
43 /**
44 * File copyright.
45 */
46 private String copyRight = null;
47
48 /**
49 * File comment.
50 */
51 private String description = null;
52
53 /**
54 * File rating.
55 */
56 private String rating = null;
57
58 /**
59 * File title.
60 */
61 private String title = null;
62
63 /**
64 * Creates an instance. <br>
65 */
66 public ContentDescription() {
67 this(0, BigInteger.valueOf(0));
68 }
69
70 /**
71 * Creates an instance.
72 *
73 * @param pos
74 * Position of content description within file or stream
75 * @param chunkLen
76 * Length of content description.
77 */
78 public ContentDescription(long pos, BigInteger chunkLen) {
79 super(GUID.GUID_CONTENTDESCRIPTION, pos, chunkLen);
80 }
81
82 /**
83 * @return Returns the author.
84 */
85 public String getAuthor() {
86 if (author == null)
87 return "";
88 return author;
89 }
90
91 /**
92 * This method creates a byte array that could directly be written to an asf
93 * file. <br>
94 *
95 * @return The asf chunk representation of a content description with the
96 * values of the current object.
97 */
98 public byte[] getBytes() {
99 ByteArrayOutputStream result = new ByteArrayOutputStream();
100 try {
101 ByteArrayOutputStream tags = new ByteArrayOutputStream();
102 String[] toWrite = new String[] { getTitle(), getAuthor(),
103 getCopyRight(), getComment(), getRating() };
104 byte[][] stringRepresentations = new byte[toWrite.length][];
105 // Create byte[] of UTF-16LE encodings
106 for (int i = 0; i < toWrite.length; i++) {
107 stringRepresentations[i] = toWrite[i].getBytes("UTF-16LE");
108 }
109 // Write the amount of bytes needed to store the values.
110 for (int i = 0; i < stringRepresentations.length; i++) {
111 tags.write(Utils.getBytes(stringRepresentations[i].length + 2,
112 2));
113 }
114 // Write the values themselves.
115 for (int i = 0; i < toWrite.length; i++) {
116 tags.write(stringRepresentations[i]);
117 // Zero term character.
118 tags.write(Utils.getBytes(0, 2));
119 }
120 // Now tags has got the values. The result just needs
121 // The GUID, length of the chunk and the tags.
122 byte[] tagContent = tags.toByteArray();
123 // The guid of the chunk
124 result.write(GUID.GUID_CONTENTDESCRIPTION.getBytes());
125 /*
126 * The length of the chunk. 16 Bytes guid 8 Bytes the length
127 * tagContent.length bytes.
128 */
129 result.write(Utils.getBytes(tagContent.length + 24, 8));
130 // The tags.
131 result.write(tagContent);
132 } catch (Exception e) {
133 e.printStackTrace();
134 }
135 return result.toByteArray();
136 }
137
138 /**
139 * @return Returns the comment.
140 */
141 public String getComment() {
142 if (description == null)
143 return "";
144 return description;
145 }
146
147 /**
148 * @return Returns the copyRight.
149 */
150 public String getCopyRight() {
151 if (copyRight == null)
152 return "";
153 return copyRight;
154 }
155
156 /**
157 * @return returns the rating.
158 */
159 public String getRating() {
160 if (rating == null)
161 return "";
162 return rating;
163 }
164
165 /**
166 * @return Returns the title.
167 */
168 public String getTitle() {
169 if (title == null)
170 return "";
171 return title;
172 }
173
174 /**
175 * (overridden)
176 *
177 * @see entagged.audioformats.asf.data.Chunk#prettyPrint()
178 */
179 public String prettyPrint() {
180 StringBuffer result = new StringBuffer(super.prettyPrint());
181 result.insert(0, Utils.LINE_SEPARATOR + "Content Description:"
182 + Utils.LINE_SEPARATOR);
183 result.append(" Title : " + getTitle() + Utils.LINE_SEPARATOR);
184 result.append(" Author : " + getAuthor() + Utils.LINE_SEPARATOR);
185 result.append(" Copyright : " + getCopyRight()
186 + Utils.LINE_SEPARATOR);
187 result.append(" Description: " + getComment() + Utils.LINE_SEPARATOR);
188 result.append(" Rating :" + getRating() + Utils.LINE_SEPARATOR);
189 return result.toString();
190 }
191
192 /**
193 * @param fileAuthor
194 * The author to set.
195 * @throws IllegalArgumentException
196 * If "UTF-16LE"-byte-representation would take more than 65535
197 * bytes.
198 */
199 public void setAuthor(String fileAuthor) throws IllegalArgumentException {
200 Utils.checkStringLengthNullSafe(fileAuthor);
201 this.author = fileAuthor;
202 }
203
204 /**
205 * @param tagComment
206 * The comment to set.
207 * @throws IllegalArgumentException
208 * If "UTF-16LE"-byte-representation would take more than 65535
209 * bytes.
210 */
211 public void setComment(String tagComment) throws IllegalArgumentException {
212 Utils.checkStringLengthNullSafe(tagComment);
213 this.description = tagComment;
214 }
215
216 /**
217 * @param cpright
218 * The copyRight to set.
219 * @throws IllegalArgumentException
220 * If "UTF-16LE"-byte-representation would take more than 65535
221 * bytes.
222 */
223 public void setCopyRight(String cpright) throws IllegalArgumentException {
224 Utils.checkStringLengthNullSafe(cpright);
225 this.copyRight = cpright;
226 }
227
228 /**
229 * @param ratingText
230 * The rating to be set.
231 * @throws IllegalArgumentException
232 * If "UTF-16LE"-byte-representation would take more than 65535
233 * bytes.
234 */
235 public void setRating(String ratingText) throws IllegalArgumentException {
236 Utils.checkStringLengthNullSafe(ratingText);
237 this.rating = ratingText;
238 }
239
240 /**
241 * @param songTitle
242 * The title to set.
243 * @throws IllegalArgumentException
244 * If "UTF-16LE"-byte-representation would take more than 65535
245 * bytes.
246 */
247 public void setTitle(String songTitle) throws IllegalArgumentException {
248 Utils.checkStringLengthNullSafe(songTitle);
249 this.title = songTitle;
250 }
251} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/ContentDescriptor.java b/songdbj/entagged/audioformats/asf/data/ContentDescriptor.java
new file mode 100644
index 0000000000..ddacbd841c
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/ContentDescriptor.java
@@ -0,0 +1,517 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.io.ByteArrayOutputStream;
25import java.io.UnsupportedEncodingException;
26import java.util.Arrays;
27import java.util.HashSet;
28
29import entagged.audioformats.asf.util.Utils;
30
31/**
32 * This class is a wrapper for properties within a
33 * {@link entagged.audioformats.asf.data.ExtendedContentDescription}.<br>
34 *
35 * @author Christian Laireiter
36 */
37public final class ContentDescriptor implements Comparable {
38 /**
39 * This field stores all values of the "ID_"-constants.
40 */
41 public final static HashSet COMMON_FIELD_IDS;
42
43 /**
44 * This constant gives the common id (name) for the "album" field in an asf
45 * extended content description.
46 */
47 public final static String ID_ALBUM = "WM/AlbumTitle";
48
49 /**
50 * This constant gives the common id (name) for the "artist" field in an asf
51 * extended content description.
52 */
53 public final static String ID_ARTIST ="WM/AlbumArtist";
54
55 /**
56 * This constant gives the common id (name) for the "genre" field in an asf
57 * extended content description.
58 */
59 public final static String ID_GENRE = "WM/Genre";
60
61 /**
62 * This constant gives the common id (name) for the "genre Id" field in an
63 * asf extended content description.
64 */
65 public final static String ID_GENREID = "WM/GenreID";
66
67 /**
68 * This constant gives the common id (name) for the "track number" field in
69 * an asf extended content description.
70 */
71 public final static String ID_TRACKNUMBER = "WM/TrackNumber";
72
73 /**
74 * This constant gives the common id (name) for the "year" field in an asf
75 * extended content description.
76 */
77 public final static String ID_YEAR = "WM/Year";
78
79 /**
80 * Constant for the content descriptor-type for binary data.
81 */
82 public final static int TYPE_BINARY = 1;
83
84 /**
85 * Constant for the content descriptor-type for booleans.
86 */
87 public final static int TYPE_BOOLEAN = 2;
88
89 /**
90 * Constant for the content descriptor-type for integers (32-bit). <br>
91 */
92 public final static int TYPE_DWORD = 3;
93
94 /**
95 * Constant for the content descriptor-type for integers (64-bit). <br>
96 */
97 public final static int TYPE_QWORD = 4;
98
99 /**
100 * Constant for the content descriptor-type for Strings.
101 */
102 public final static int TYPE_STRING = 0;
103
104 /**
105 * Constant for the content descriptor-type for integers (16-bit). <br>
106 */
107 public final static int TYPE_WORD = 5;
108
109 static {
110 COMMON_FIELD_IDS = new HashSet();
111 COMMON_FIELD_IDS.add(ID_ALBUM);
112 COMMON_FIELD_IDS.add(ID_ARTIST);
113 COMMON_FIELD_IDS.add(ID_GENRE);
114 COMMON_FIELD_IDS.add(ID_GENREID);
115 COMMON_FIELD_IDS.add(ID_TRACKNUMBER);
116 COMMON_FIELD_IDS.add(ID_YEAR);
117 }
118
119 /**
120 * The binary representation of the value.
121 */
122 protected byte[] content = new byte[0];
123
124 /**
125 * This field shows the type of the content descriptor. <br>
126 *
127 * @see #TYPE_BINARY
128 * @see #TYPE_BOOLEAN
129 * @see #TYPE_DWORD
130 * @see #TYPE_QWORD
131 * @see #TYPE_STRING
132 * @see #TYPE_WORD
133 */
134 private int descriptorType;
135
136 /**
137 * The name of the content descriptor.
138 */
139 private final String name;
140
141 /**
142 * Creates an Instance.
143 *
144 * @param propName
145 * Name of the ContentDescriptor.
146 * @param propType
147 * Type of the content descriptor. See {@link #descriptorType}
148 *
149 */
150 public ContentDescriptor(String propName, int propType) {
151 if (propName == null) {
152 throw new IllegalArgumentException("Arguments must not be null.");
153 }
154 Utils.checkStringLengthNullSafe(propName);
155 this.name = propName;
156 this.descriptorType = propType;
157 }
158
159 /**
160 * (overridden)
161 *
162 * @see java.lang.Object#clone()
163 */
164 public Object clone() throws CloneNotSupportedException {
165 return createCopy();
166 }
167
168 /**
169 * (overridden)
170 *
171 * @see java.lang.Comparable#compareTo(java.lang.Object)
172 */
173 public int compareTo(Object o) {
174 int result = 0;
175 if (o instanceof ContentDescriptor) {
176 ContentDescriptor other = (ContentDescriptor) o;
177 result = getName().compareTo(other.getName());
178 }
179 return result;
180 }
181
182 /**
183 * This mehtod creates a copy of the current object. <br>
184 * All data will be copied, too. <br>
185 *
186 * @return A new Contentdescriptor containing the same values as the current
187 * one.
188 */
189 public ContentDescriptor createCopy() {
190 ContentDescriptor result = new ContentDescriptor(getName(), getType());
191 result.content = getRawData();
192 return result;
193 }
194
195 /**
196 * (overridden)
197 *
198 * @see java.lang.Object#equals(java.lang.Object)
199 */
200 public boolean equals(Object obj) {
201 boolean result = false;
202 if (obj instanceof ContentDescriptor) {
203 if (obj == this) {
204 result = true;
205 } else {
206 ContentDescriptor other = (ContentDescriptor) obj;
207 result = other.getName().equals(getName())
208 && other.descriptorType == this.descriptorType
209 && Arrays.equals(this.content, other.content);
210 }
211 }
212 return result;
213 }
214
215 /**
216 * Returns the value of the ContentDescriptor as a Boolean. <br>
217 * If no Conversion is Possible false is returned. <br>
218 * <code>true</code> if first byte of {@link #content}is not zero.
219 *
220 * @return boolean representation of the current value.
221 */
222 public boolean getBoolean() {
223 return content.length > 0 && content[0] != 0;
224 }
225
226 /**
227 * This method will return a byte array, which can directly be written into
228 * an "Extended Content Description"-chunk. <br>
229 *
230 * @return byte[] with the data, that occurs in asf files.
231 */
232 public byte[] getBytes() {
233 ByteArrayOutputStream result = new ByteArrayOutputStream();
234 try {
235 byte[] nameBytes = getName().getBytes("UTF-16LE");
236 // Write the number of bytes the name needs. +2 because of the
237 // Zero term character.
238 result.write(Utils.getBytes(nameBytes.length + 2, 2));
239 // Write the name itself
240 result.write(nameBytes);
241 // Write zero term character
242 result.write(Utils.getBytes(0, 2));
243 // Write the type of the current descriptor
244 result.write(Utils.getBytes(getType(), 2));
245 /*
246 * Now the content.
247 */
248 if (this.getType() == TYPE_STRING) {
249 // String length +2 for zero termination
250 result.write(Utils.getBytes(content.length + 2, 2));
251 // Value
252 result.write(content);
253 // Zero term
254 result.write(Utils.getBytes(0, 2));
255 } else {
256 result.write(Utils.getBytes(content.length, 2));
257 result.write(content);
258 }
259 } catch (Exception e) {
260 e.printStackTrace();
261 }
262 return result.toByteArray();
263 }
264
265 /**
266 * This method returns the name of the content descriptor.
267 *
268 * @return Name.
269 */
270 public String getName() {
271 return this.name;
272 }
273
274 /**
275 * This method returns the value of the content descriptor as an integer.
276 * <br>
277 * Converts the needed amount of byte out of {@link #content}to a number.
278 * <br>
279 * Only possible if {@link #getType()}equals on of the following: <br>
280 * <li>
281 *
282 * @see #TYPE_BOOLEAN</li>
283 * <li>
284 * @see #TYPE_DWORD</li>
285 * <li>
286 * @see #TYPE_QWORD</li>
287 * <li>
288 * @see #TYPE_WORD</li>
289 *
290 * @return integer value.
291 */
292 public long getNumber() {
293 long result = 0;
294 int bytesNeeded = -1;
295 switch (getType()) {
296 case TYPE_BOOLEAN:
297 bytesNeeded = 1;
298 break;
299 case TYPE_DWORD:
300 bytesNeeded = 4;
301 break;
302 case TYPE_QWORD:
303 bytesNeeded = 8;
304 break;
305 case TYPE_WORD:
306 bytesNeeded = 2;
307 break;
308 default:
309 throw new UnsupportedOperationException(
310 "The current type doesn't allow an interpretation as a number.");
311 }
312 if (bytesNeeded > content.length) {
313 throw new IllegalStateException(
314 "The stored data cannot represent the type of current object.");
315 }
316 for (int i = 0; i < bytesNeeded; i++) {
317 result |= (content[i] << (i * 8));
318 }
319 return result;
320 }
321
322 /**
323 * This method returns a copy of the content of the descriptor. <br>
324 *
325 * @return The content in binary representation, as it would be written to
326 * asf file. <br>
327 */
328 public byte[] getRawData() {
329 byte[] copy = new byte[this.content.length];
330 System.arraycopy(copy, 0, this.content, 0, this.content.length);
331 return copy;
332 }
333
334 /**
335 * Returns the value of the ContentDescriptor as a String. <br>
336 *
337 * @return String - Representation Value
338 */
339 public String getString() {
340 String result = "";
341 switch (getType()) {
342 case TYPE_BINARY:
343 result = "binary data";
344 break;
345 case TYPE_BOOLEAN:
346 result = String.valueOf(getBoolean());
347 break;
348 case TYPE_QWORD:
349 case TYPE_DWORD:
350 case TYPE_WORD:
351 result = String.valueOf(getNumber());
352 break;
353 case TYPE_STRING:
354 try {
355 result = new String(content, "UTF-16LE");
356 } catch (Exception e) {
357 e.printStackTrace();
358 }
359 break;
360 default:
361 throw new IllegalStateException("Current type is not known.");
362 }
363 return result;
364 }
365
366 /**
367 * Returns the type of the content descriptor. <br>
368 *
369 * @see #TYPE_BINARY
370 * @see #TYPE_BOOLEAN
371 * @see #TYPE_DWORD
372 * @see #TYPE_QWORD
373 * @see #TYPE_STRING
374 * @see #TYPE_WORD
375 *
376 * @return the value of {@link #descriptorType}
377 */
378 public int getType() {
379 return this.descriptorType;
380 }
381
382 /**
383 * This method checks whether the name of the current field is one of the
384 * commonly specified fields. <br>
385 *
386 * @see #ID_ALBUM
387 * @see #ID_GENRE
388 * @see #ID_GENREID
389 * @see #ID_TRACKNUMBER
390 * @see #ID_YEAR
391 * @return <code>true</code> if a common field.
392 */
393 public boolean isCommon() {
394 return COMMON_FIELD_IDS.contains(this.getName());
395 }
396
397 /**
398 * This method checks if the binary data is empty. <br>
399 * Disregarding the type of the descriptor its content is stored as a byte
400 * array.
401 *
402 * @return <code>true</code> if no value is set.
403 */
404 public boolean isEmpty() {
405 return this.content.length == 0;
406 }
407
408 /**
409 * Sets the Value of the current content descriptor. <br>
410 * Using this method will change {@link #descriptorType}to
411 * {@link #TYPE_BINARY}.<br>
412 *
413 * @param data
414 * Value to set.
415 * @throws IllegalArgumentException
416 * If the byte array is greater that 65535 bytes.
417 */
418 public void setBinaryValue(byte[] data) throws IllegalArgumentException {
419 if (data.length > 65535) {
420 throw new IllegalArgumentException(
421 "Too many bytes. 65535 is maximum.");
422 }
423 this.content = data;
424 this.descriptorType = TYPE_BINARY;
425 }
426
427 /**
428 * Sets the Value of the current content descriptor. <br>
429 * Using this method will change {@link #descriptorType}to
430 * {@link #TYPE_BOOLEAN}.<br>
431 *
432 * @param value
433 * Value to set.
434 */
435 public void setBooleanValue(boolean value) {
436 this.content = new byte[] { value ? (byte) 1 : 0, 0, 0, 0 };
437 this.descriptorType = TYPE_BOOLEAN;
438 }
439
440 /**
441 * Sets the Value of the current content descriptor. <br>
442 * Using this method will change {@link #descriptorType}to
443 * {@link #TYPE_DWORD}.
444 *
445 * @param value
446 * Value to set.
447 */
448 public void setDWordValue(long value) {
449 this.content = Utils.getBytes(value, 4);
450 this.descriptorType = TYPE_DWORD;
451 }
452
453 /**
454 * Sets the Value of the current content descriptor. <br>
455 * Using this method will change {@link #descriptorType}to
456 * {@link #TYPE_QWORD}
457 *
458 * @param value
459 * Value to set.
460 */
461 public void setQWordValue(long value) {
462 this.content = Utils.getBytes(value, 8);
463 this.descriptorType = TYPE_QWORD;
464 }
465
466 /**
467 * Sets the Value of the current content descriptor. <br>
468 * Using this method will change {@link #descriptorType}to
469 * {@link #TYPE_STRING}.
470 *
471 * @param value
472 * Value to set.
473 * @throws IllegalArgumentException
474 * If byte representation would take more than 65535 Bytes.
475 */
476 public void setStringValue(String value) throws IllegalArgumentException {
477 try {
478 byte[] tmp = value.getBytes("UTF-16LE");
479 if (tmp.length > 65535) {
480 throw new IllegalArgumentException(
481 "Byte representation of String in "
482 + "\"UTF-16LE\" is to great. (Maximum is 65535 Bytes)");
483 }
484 this.content = tmp;
485 } catch (UnsupportedEncodingException e) {
486 e.printStackTrace();
487 this.content = new byte[0];
488 }
489 this.descriptorType = TYPE_STRING;
490 }
491
492 /**
493 * Sets the Value of the current content descriptor. <br>
494 * Using this method will change {@link #descriptorType}to
495 * {@link #TYPE_WORD}
496 *
497 * @param value
498 * Value to set.
499 */
500 public void setWordValue(int value) {
501 this.content = Utils.getBytes(value, 2);
502 this.descriptorType = TYPE_WORD;
503 }
504
505 /**
506 * (overridden)
507 *
508 * @see java.lang.Object#toString()
509 */
510 public String toString() {
511 return getName()
512 + " : "
513 + new String[] { "String: ", "Binary: ", "Boolean: ",
514 "DWORD: ", "QWORD:", "WORD:" }[this.descriptorType]
515 + getString();
516 }
517} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/EncodingChunk.java b/songdbj/entagged/audioformats/asf/data/EncodingChunk.java
new file mode 100644
index 0000000000..32c9e75c8d
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/EncodingChunk.java
@@ -0,0 +1,95 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.math.BigInteger;
25import java.util.ArrayList;
26import java.util.Collection;
27import java.util.Iterator;
28
29import entagged.audioformats.asf.util.Utils;
30
31/**
32 * This class was intended to store the data of a chunk which contained the
33 * encoding parameters in textual form. <br>
34 * Since the needed parameters were found in other chunks the implementation of
35 * this class was paused. <br>
36 * TODO complete analysis.
37 *
38 * @author Christian Laireiter
39 */
40public class EncodingChunk extends Chunk {
41
42 /**
43 * The read strings.
44 */
45 private final ArrayList strings;
46
47 /**
48 * Creates an instance.
49 *
50 * @param pos
51 * Position of the chunk within file or stream
52 * @param chunkLen
53 * Length of current chunk.
54 */
55 public EncodingChunk(long pos, BigInteger chunkLen) {
56 super(GUID.GUID_ENCODING, pos, chunkLen);
57 this.strings = new ArrayList();
58 }
59
60 /**
61 * This method appends a String.
62 *
63 * @param toAdd
64 * String to add.
65 */
66 public void addString(String toAdd) {
67 strings.add(toAdd);
68 }
69
70 /**
71 * This method returns a collection of all {@link String}s which were addid
72 * due {@link #addString(String)}.
73 *
74 * @return Inserted Strings.
75 */
76 public Collection getStrings() {
77 return new ArrayList(strings);
78 }
79
80 /**
81 * (overridden)
82 *
83 * @see entagged.audioformats.asf.data.Chunk#prettyPrint()
84 */
85 public String prettyPrint() {
86 StringBuffer result = new StringBuffer(super.prettyPrint());
87 result.insert(0, Utils.LINE_SEPARATOR + "Encoding:"
88 + Utils.LINE_SEPARATOR);
89 Iterator iterator = this.strings.iterator();
90 while (iterator.hasNext()) {
91 result.append(" " + iterator.next() + Utils.LINE_SEPARATOR);
92 }
93 return result.toString();
94 }
95} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/ExtendedContentDescription.java b/songdbj/entagged/audioformats/asf/data/ExtendedContentDescription.java
new file mode 100644
index 0000000000..6d957df8f3
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/ExtendedContentDescription.java
@@ -0,0 +1,299 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.io.ByteArrayOutputStream;
25import java.math.BigInteger;
26import java.util.ArrayList;
27import java.util.Arrays;
28import java.util.Collection;
29import java.util.HashMap;
30import java.util.Iterator;
31
32import entagged.audioformats.Tag;
33import entagged.audioformats.asf.util.Utils;
34
35/**
36 * This structure represents the data of a chunk, wich contains extended content
37 * description. <br>
38 * These properties are simply represented by
39 * {@link entagged.audioformats.asf.data.ContentDescriptor}
40 *
41 * @author Christian Laireiter
42 */
43public class ExtendedContentDescription extends Chunk {
44
45 /**
46 * Contains the properties. <br>
47 */
48 private final ArrayList descriptors;
49
50 /**
51 * This map stores the ids (names) of inserted content descriptors. <br>
52 * If {@link #getDescriptor(String)}is called this field will be filled if
53 * <code>null</code>. Any modification of the contents of this object
54 * will set this field to <code>null</code>.
55 */
56 private HashMap indexMap = null;
57
58 /**
59 * Creates an instance.
60 *
61 */
62 public ExtendedContentDescription() {
63 this(0, BigInteger.valueOf(0));
64 }
65
66 /**
67 * Creates an instance.
68 *
69 * @param pos
70 * Position of header object within file or stream.
71 * @param chunkLen
72 * Length of the represented chunck.
73 */
74 public ExtendedContentDescription(long pos, BigInteger chunkLen) {
75 super(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, pos, chunkLen);
76 this.descriptors = new ArrayList();
77 }
78
79 /**
80 * This method inserts the given ContentDescriptor.
81 *
82 * @param toAdd
83 * ContentDescriptor to insert.
84 */
85 public void addDescriptor(ContentDescriptor toAdd) {
86 assert toAdd != null : "Argument must not be null.";
87 if (getDescriptor(toAdd.getName()) != null) {
88 throw new RuntimeException(toAdd.getName() + " is already present");
89 }
90 this.descriptors.add(toAdd);
91 this.indexMap.put(toAdd.getName(), new Integer(descriptors.size() - 1));
92 }
93
94 /**
95 * This method adds or replaces an existing content descriptor.
96 *
97 * @param descriptor
98 * Descriptor to be added or replaced.
99 */
100 public void addOrReplace(ContentDescriptor descriptor) {
101 assert descriptor != null : "Argument must not be null";
102 if (getDescriptor(descriptor.getName()) != null) {
103 /*
104 * Just remove if exists. Will prevent the indexmap being rebuild.
105 */
106 remove(descriptor.getName());
107 }
108 addDescriptor(descriptor);
109 }
110
111 /**
112 * Returns the album entered in the content descriptor chunk.
113 *
114 * @return Album, <code>""</code> if not defined.
115 */
116 public String getAlbum() {
117 ContentDescriptor result = getDescriptor(ContentDescriptor.ID_ALBUM);
118 if (result == null)
119 return "";
120
121 return result.getString();
122 }
123
124 /**
125 * Returns the "WM/AlbumArtist" entered in the extended content description.
126 *
127 * @return Title, <code>""</code> if not defined.
128 */
129 public String getArtist() {
130 ContentDescriptor result = getDescriptor(ContentDescriptor.ID_ARTIST);
131 if (result == null)
132 return "";
133 return result.getString();
134 }
135
136 /**
137 * This method creates a byte array which can be written to asf files.
138 *
139 * @return asf file representation of the current object.
140 */
141 public byte[] getBytes() {
142 ByteArrayOutputStream result = new ByteArrayOutputStream();
143 try {
144 ByteArrayOutputStream content = new ByteArrayOutputStream();
145 // Write the number of descriptors.
146 content.write(Utils.getBytes(this.descriptors.size(), 2));
147 Iterator it = this.descriptors.iterator();
148 while (it.hasNext()) {
149 ContentDescriptor current = (ContentDescriptor) it.next();
150 content.write(current.getBytes());
151 }
152 byte[] contentBytes = content.toByteArray();
153 // Write the guid
154 result.write(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION.getBytes());
155 // Write the length + 24.
156 result.write(Utils.getBytes(contentBytes.length + 24, 8));
157 // Write the content
158 result.write(contentBytes);
159 } catch (Exception e) {
160 e.printStackTrace();
161 }
162 return result.toByteArray();
163 }
164
165 /**
166 * Returns a previously inserted content descriptor.
167 *
168 * @param name
169 * name of the content descriptor.
170 * @return <code>null</code> if not present.
171 */
172 public ContentDescriptor getDescriptor(String name) {
173 if (this.indexMap == null) {
174 this.indexMap = new HashMap();
175 for (int i = 0; i < descriptors.size(); i++) {
176 ContentDescriptor current = (ContentDescriptor) descriptors
177 .get(i);
178 indexMap.put(current.getName(), new Integer(i));
179 }
180 }
181 Integer pos = (Integer) indexMap.get(name);
182 if (pos != null) {
183 return (ContentDescriptor) descriptors.get(pos.intValue());
184 }
185 return null;
186 }
187
188 /**
189 * @return Returns the descriptorCount.
190 */
191 public long getDescriptorCount() {
192 return descriptors.size();
193 }
194
195 /**
196 * Returns a collection of all {@link ContentDescriptor}objects stored in
197 * this extended content description.
198 *
199 * @return An enumeration of {@link ContentDescriptor}objects.
200 */
201 public Collection getDescriptors() {
202 return new ArrayList(this.descriptors);
203 }
204
205 /**
206 * Returns the Genre entered in the content descriptor chunk.
207 *
208 * @return Genre, <code>""</code> if not defined.
209 */
210 public String getGenre() {
211 String result = null;
212 ContentDescriptor prop = getDescriptor(ContentDescriptor.ID_GENRE);
213 if (prop == null) {
214 prop = getDescriptor(ContentDescriptor.ID_GENREID);
215 if (prop == null)
216 result = "";
217 else {
218 result = prop.getString();
219 if (result.startsWith("(") && result.endsWith(")")) {
220 result = result.substring(1, result.length() - 1);
221 try {
222 int genreNum = Integer.parseInt(result);
223 if (genreNum >= 0
224 && genreNum < Tag.DEFAULT_GENRES.length) {
225 result = Tag.DEFAULT_GENRES[genreNum];
226 }
227 } catch (NumberFormatException e) {
228 // Do nothing
229 }
230 }
231 }
232 } else {
233 result = prop.getString();
234 }
235 return result;
236 }
237
238 /**
239 * Returns the Track entered in the content descriptor chunk.
240 *
241 * @return Track, <code>""</code> if not defined.
242 */
243 public String getTrack() {
244 ContentDescriptor result = getDescriptor(ContentDescriptor.ID_TRACKNUMBER);
245 if (result == null)
246 return "";
247
248 return result.getString();
249 }
250
251 /**
252 * Returns the Year entered in the extended content descripion.
253 *
254 * @return Year, <code>""</code> if not defined.
255 */
256 public String getYear() {
257 ContentDescriptor result = getDescriptor(ContentDescriptor.ID_YEAR);
258 if (result == null)
259 return "";
260
261 return result.getString();
262 }
263
264 /**
265 * This method creates a String containing the tag elements an their values
266 * for printing. <br>
267 *
268 * @return nice string.
269 */
270 public String prettyPrint() {
271 StringBuffer result = new StringBuffer(super.prettyPrint());
272 result.insert(0, "\nExtended Content Description:\n");
273 ContentDescriptor[] list = (ContentDescriptor[]) descriptors
274 .toArray(new ContentDescriptor[descriptors.size()]);
275 Arrays.sort(list);
276 for (int i = 0; i < list.length; i++) {
277 result.append(" ");
278 result.append(list[i]);
279 result.append(Utils.LINE_SEPARATOR);
280 }
281 return result.toString();
282 }
283
284 /**
285 * This method removes the content descriptor with the given name. <br>
286 *
287 * @param id
288 * The id (name) of the descriptor which should be removed.
289 * @return The descriptor which is removed. If not present <code>null</code>.
290 */
291 public ContentDescriptor remove(String id) {
292 ContentDescriptor result = getDescriptor(id);
293 if (result != null) {
294 descriptors.remove(result);
295 }
296 this.indexMap = null;
297 return result;
298 }
299} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/FileHeader.java b/songdbj/entagged/audioformats/asf/data/FileHeader.java
new file mode 100644
index 0000000000..cdafbeb6be
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/FileHeader.java
@@ -0,0 +1,235 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.math.BigInteger;
25import java.util.Date;
26
27import entagged.audioformats.asf.util.Utils;
28
29/**
30 * This class stores the information about the file, which is contained within a
31 * special chunk of asf files.<br>
32 *
33 * @author Christian Laireiter
34 */
35public class FileHeader extends Chunk {
36
37 /**
38 * Duration of the media content in 100ns steps.
39 */
40 private final BigInteger duration;
41
42 /**
43 * The time the file was created.
44 */
45 private final Date fileCreationTime;
46
47 /**
48 * Size of the file or stream.
49 */
50 private BigInteger fileSize;
51
52 /**
53 * Usually contains value of 2.
54 */
55 private final long flags;
56
57 /**
58 * Maximum size of stream packages. <br>
59 * <b>Warning: </b> must be same size as {@link #minPackageSize}. Its not
60 * known how to handle deviating values.
61 */
62 private final long maxPackageSize;
63
64 /**
65 * Minimun size of stream packages. <br>
66 * <b>Warning: </b> must be same size as {@link #maxPackageSize}. Its not
67 * known how to handle deviating values.
68 */
69 private final long minPackageSize;
70
71 /**
72 * Number of stream packages within the File.
73 */
74 private final BigInteger packageCount;
75
76 /**
77 * No Idea of the Meaning, but stored anyway. <br>
78 * Source documentation says it is: "Timestamp of end position"
79 */
80 private final BigInteger timeEndPos;
81
82 /**
83 * Like {@link #timeEndPos}no Idea.
84 */
85 private final BigInteger timeStartPos;
86
87 /**
88 * Size of an uncompressed video frame.
89 */
90 private final long uncompressedFrameSize;
91
92 /**
93 * Creates an instance.
94 *
95 * @param fileHeaderStart
96 * Position in file or stream, where the file header starts.
97 * @param chunckLen
98 * Length of the file header (chunk)
99 * @param size
100 * Size of file or stream
101 * @param fileTime
102 * Time file or stream was created. Time is calculated since 1st
103 * january of 1601 in 100ns steps.
104 * @param pkgCount
105 * Number of stream packages.
106 * @param dur
107 * Duration of media clip in 100ns steps
108 * @param timestampStart
109 * Timestamp of start {@link #timeStartPos}
110 * @param timestampEnd
111 * Timestamp of end {@link #timeEndPos}
112 * @param headerFlags
113 * some stream related flags.
114 * @param minPkgSize
115 * minimun size of packages
116 * @param maxPkgSize
117 * maximum size of packages
118 * @param uncmpVideoFrameSize
119 * Size of an uncompressed Video Frame.
120 */
121 public FileHeader(long fileHeaderStart, BigInteger chunckLen,
122 BigInteger size, BigInteger fileTime, BigInteger pkgCount,
123 BigInteger dur, BigInteger timestampStart, BigInteger timestampEnd,
124 long headerFlags, long minPkgSize, long maxPkgSize,
125 long uncmpVideoFrameSize) {
126 super(GUID.GUID_FILE, fileHeaderStart, chunckLen);
127 this.fileSize = size;
128 this.packageCount = pkgCount;
129 this.duration = dur;
130 this.timeStartPos = timestampStart;
131 this.timeEndPos = timestampEnd;
132 this.flags = headerFlags;
133 this.minPackageSize = minPkgSize;
134 this.maxPackageSize = maxPkgSize;
135 this.uncompressedFrameSize = uncmpVideoFrameSize;
136 this.fileCreationTime = Utils.getDateOf(fileTime).getTime();
137 }
138
139 /**
140 * @return Returns the duration.
141 */
142 public BigInteger getDuration() {
143 return duration;
144 }
145
146 /**
147 * This method converts {@link #getDuration()}from 100ns steps to normal
148 * seconds.
149 *
150 * @return Duration of the media in seconds.
151 */
152 public int getDurationInSeconds() {
153 return duration.divide(new BigInteger("10000000")).intValue();
154 }
155
156 /**
157 * @return Returns the fileCreationTime.
158 */
159 public Date getFileCreationTime() {
160 return fileCreationTime;
161 }
162
163 /**
164 * @return Returns the fileSize.
165 */
166 public BigInteger getFileSize() {
167 return fileSize;
168 }
169
170 /**
171 * @return Returns the flags.
172 */
173 public long getFlags() {
174 return flags;
175 }
176
177 /**
178 * @return Returns the maxPackageSize.
179 */
180 public long getMaxPackageSize() {
181 return maxPackageSize;
182 }
183
184 /**
185 * @return Returns the minPackageSize.
186 */
187 public long getMinPackageSize() {
188 return minPackageSize;
189 }
190
191 /**
192 * @return Returns the packageCount.
193 */
194 public BigInteger getPackageCount() {
195 return packageCount;
196 }
197
198 /**
199 * @return Returns the timeEndPos.
200 */
201 public BigInteger getTimeEndPos() {
202 return timeEndPos;
203 }
204
205 /**
206 * @return Returns the timeStartPos.
207 */
208 public BigInteger getTimeStartPos() {
209 return timeStartPos;
210 }
211
212 /**
213 * @return Returns the uncompressedFrameSize.
214 */
215 public long getUncompressedFrameSize() {
216 return uncompressedFrameSize;
217 }
218
219 /**
220 * (overridden)
221 *
222 * @see entagged.audioformats.asf.data.Chunk#prettyPrint()
223 */
224 public String prettyPrint() {
225 StringBuffer result = new StringBuffer(super.prettyPrint());
226 result.insert(0, "\nFileHeader\n");
227 result.append(" Filesize = " + getFileSize().toString()
228 + " Bytes \n");
229 result.append(" Media duration= "
230 + getDuration().divide(new BigInteger("10000")).toString()
231 + " ms \n");
232 result.append(" Created at = " + getFileCreationTime() + "\n");
233 return result.toString();
234 }
235} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/GUID.java b/songdbj/entagged/audioformats/asf/data/GUID.java
new file mode 100644
index 0000000000..47c0394cd8
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/GUID.java
@@ -0,0 +1,329 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.util.Arrays;
25
26import entagged.audioformats.asf.util.Utils;
27
28/**
29 * This class is used for representation of GUIDs and as a reference list of all
30 * Known GUIDs. <br>
31 *
32 * @author Christian Laireiter
33 */
34public class GUID {
35
36 /**
37 * This constant defines the GUID for stream chunks describing audio
38 * streams, indicating the the audio stream has no error concealment. <br>
39 */
40 public final static GUID GUID_AUDIO_ERROR_CONCEALEMENT_ABSENT = new GUID(
41 new int[] { 0x40, 0xA4, 0xF1, 0x49, 0xCE, 0x4E, 0xD0, 0x11, 0xA3,
42 0xAC, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 },
43 "Audio error concealment absent.");
44
45 /**
46 * This constant defines the GUID for stream chunks describing audio
47 * streams, indicating the the audio stream has interleaved error
48 * concealment. <br>
49 */
50 public final static GUID GUID_AUDIO_ERROR_CONCEALEMENT_INTERLEAVED = new GUID(
51 new int[] { 0x40, 0xA4, 0xF1, 0x49, 0xCE, 0x4E, 0xD0, 0x11, 0xA3,
52 0xAC, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 },
53 "Interleaved audio error concealment.");
54
55 /**
56 * This constant stores the GUID indicating that stream type is audio.
57 */
58 public final static GUID GUID_AUDIOSTREAM = new GUID(new int[] { 0x40,
59 0x9E, 0x69, 0xF8, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80,
60 0x5F, 0x5C, 0x44, 0x2B }, " Audio stream");
61
62 /**
63 * This constant represents the guid for a chunk which contains Title,
64 * author, copyright, description and rating.
65 */
66 public final static GUID GUID_CONTENTDESCRIPTION = new GUID(new int[] {
67 0x33, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00,
68 0xAA, 0x00, 0x62, 0xCE, 0x6C }, "Content Description");
69
70 /**
71 * This constant stores the GUID for Encoding-Info chunks.
72 */
73 public final static GUID GUID_ENCODING = new GUID(new int[] { 0x40, 0x52,
74 0xD1, 0x86, 0x1D, 0x31, 0xD0, 0x11, 0xA3, 0xA4, 0x00, 0xA0, 0xC9,
75 0x03, 0x48, 0xF6 }, "Encoding description");
76
77 /**
78 * This constant defines the GUID for a WMA "Extended Content Description"
79 * chunk. <br>
80 */
81 public final static GUID GUID_EXTENDED_CONTENT_DESCRIPTION = new GUID(
82 new int[] { 0x40, 0xA4, 0xD0, 0xD2, 0x07, 0xE3, 0xD2, 0x11, 0x97,
83 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50 },
84 "Extended Content Description");
85
86 /**
87 * GUID of ASF file header.
88 */
89 public final static GUID GUID_FILE = new GUID(new int[] { 0xA1, 0xDC, 0xAB,
90 0x8C, 0x47, 0xA9, 0xCF, 0x11, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20,
91 0x53, 0x65 }, "File header");
92
93 /**
94 * This constant defines the GUID of a asf header chunk.
95 */
96 public final static GUID GUID_HEADER = new GUID(new int[] { 0x30, 0x26,
97 0xb2, 0x75, 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00,
98 0x62, 0xce, 0x6c }, "Asf header");
99
100 /**
101 * This constant stores the length of GUIDs used with ASF streams. <br>
102 */
103 public final static int GUID_LENGTH = 16;
104
105 /**
106 * This constant stores the GUID indicating a stream object.
107 */
108 public final static GUID GUID_STREAM = new GUID(new int[] { 0x91, 0x07,
109 0xDC, 0xB7, 0xB7, 0xA9, 0xCF, 0x11, 0x8E, 0xE6, 0x00, 0xC0, 0x0C,
110 0x20, 0x53, 0x65 }, "Stream");
111
112 /**
113 * This constant stores a GUID whose functionality is unknown.
114 */
115 public final static GUID GUID_UNKNOWN_1 = new GUID(new int[] { 0xB5, 0x03,
116 0xBF, 0x5F, 0x2E, 0xA9, 0xCF, 0x11, 0x8E, 0xE3, 0x00, 0xC0, 0x0C,
117 0x20, 0x53, 0x65 }, "Unknown 1");
118
119 /**
120 * This constant stores a GUID whose functionality is unknown.
121 */
122 public final static GUID GUID_UNKNOWN_2 = new GUID(new int[] { 0xCE, 0x75,
123 0xF8, 0x7B, 0x8D, 0x46, 0xD1, 0x11, 0x8D, 0x82, 0x00, 0x60, 0x97,
124 0xC9, 0xA2, 0xB2 }, "Unknown 2");
125
126 /**
127 * This constant stores the GUID indicating that stream type is video.
128 */
129 public final static GUID GUID_VIDEOSTREAM = new GUID(new int[] { 0xC0,
130 0xEF, 0x19, 0xBC, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80,
131 0x5F, 0x5C, 0x44, 0x2B }, "Video stream");
132
133 /**
134 * This field stores all knwon GUIDs.
135 */
136 public final static GUID[] KNOWN_GUIDS = new GUID[] {
137 GUID_AUDIO_ERROR_CONCEALEMENT_ABSENT,
138 GUID_AUDIO_ERROR_CONCEALEMENT_INTERLEAVED, GUID_CONTENTDESCRIPTION,
139 GUID_AUDIOSTREAM, GUID_ENCODING, GUID_FILE, GUID_HEADER,
140 GUID_STREAM, GUID_EXTENDED_CONTENT_DESCRIPTION, GUID_VIDEOSTREAM,
141 GUID_UNKNOWN_1, GUID_UNKNOWN_2 };
142
143 /**
144 * This method checks if the given <code>value</code> is matching the GUID
145 * specification of ASF streams. <br>
146 *
147 * @param value
148 * possible GUID.
149 * @return <code>true</code> if <code>value</code> matches the
150 * specification of a GUID.
151 */
152 public static boolean assertGUID(int[] value) {
153 boolean result = false;
154 if (value != null) {
155 if (value.length == GUID.GUID_LENGTH) {
156 result = true;
157 }
158 }
159 return result;
160 }
161
162 /**
163 * This method searches a GUID in {@link #KNOWN_GUIDS}which is equal to the
164 * given <code>guid</code> and returns its description. <br>
165 * This method is useful if a guid was read out of a file and no
166 * identification has been done yet.
167 *
168 * @param guid
169 * guid, which description is needed.
170 * @return description of the guid if found. Else <code>null</code>
171 */
172 public static String getGuidDescription(GUID guid) {
173 String result = null;
174 if (guid == null) {
175 throw new IllegalArgumentException("Argument must not be null.");
176 }
177 for (int i = 0; i < KNOWN_GUIDS.length; i++) {
178 if (KNOWN_GUIDS[i].equals(guid)) {
179 result = KNOWN_GUIDS[i].getDescription();
180 }
181 }
182 return result;
183 }
184
185 /**
186 * Stores an optionally description of the GUID.
187 */
188 private String description = "";
189
190 /**
191 * An isntance of this class stores the value of the wrapped GUID in this
192 * field. <br>
193 */
194 private int[] guid = null;
195
196 /**
197 * Creates an empty instance.
198 *
199 */
200 public GUID() {
201 // Nothing to do
202 }
203
204 /**
205 * Creates an instance and assigns given <code>guid</code>.<br>
206 *
207 * @param value
208 * Guid, which should be assigned.
209 */
210 public GUID(int[] value) {
211 setGUID(value);
212 }
213
214 /**
215 * Creates an instance like {@link #GUID(int[])}and sets the optional
216 * description. <br>
217 *
218 * @param value
219 * Guid, which should be assigned.
220 * @param desc
221 * Description for the guid.
222 */
223 public GUID(int[] value, String desc) {
224 this(value);
225 if (desc == null) {
226 throw new IllegalArgumentException("Argument must not be null.");
227 }
228 this.description = desc;
229 }
230
231 /**
232 * This method compares two objects. If the given Object is a {@link GUID},
233 * the stored GUID values are compared. <br>
234 *
235 * @see java.lang.Object#equals(java.lang.Object)
236 */
237 public boolean equals(Object obj) {
238 boolean result = false;
239 if (obj instanceof GUID) {
240 GUID other = (GUID) obj;
241 result = Arrays.equals(this.getGUID(), other.getGUID());
242 } else {
243 result = super.equals(obj);
244 }
245 return result;
246 }
247
248 /**
249 * This method returns the guid as an array of bytes. <br>
250 *
251 * @see #getGUID()
252 * @return The guid as a byte array.
253 */
254 public byte[] getBytes() {
255 byte[] result = new byte[this.guid.length];
256 for (int i = 0; i < result.length; i++) {
257 result[i] = (byte) (this.guid[i] & 0xFF);
258 }
259 return result;
260 }
261
262 /**
263 * @return Returns the description.
264 */
265 public String getDescription() {
266 return description;
267 }
268
269 /**
270 * This method returns the GUID of this object. <br>
271 *
272 * @return stored GUID.
273 */
274 public int[] getGUID() {
275 int[] copy = new int[this.guid.length];
276 System.arraycopy(this.guid, 0, copy, 0, this.guid.length);
277 return copy;
278 }
279
280 /**
281 * This method checks if the currently stored GUID ({@link #guid}) is
282 * correctly filled. <br>
283 *
284 * @return <code>true</code> if it is.
285 */
286 public boolean isValid() {
287 return assertGUID(getGUID());
288 }
289
290 /**
291 * This method saves a copy of the given <code>value</code> as the
292 * represented value of this object. <br>
293 * The given value is checked with {@link #assertGUID(int[])}.<br>
294 *
295 * @param value
296 * GUID to assign.
297 */
298 private void setGUID(int[] value) {
299 if (assertGUID(value)) {
300 this.guid = new int[GUID_LENGTH];
301 System.arraycopy(value, 0, this.guid, 0, GUID_LENGTH);
302 } else {
303 throw new IllegalArgumentException(
304 "The given guid doesn't match the GUID specification.");
305 }
306 }
307
308 /**
309 * This method gives a hex formatted representation of {@link #getGUID()}
310 *
311 * @see java.lang.Object#toString()
312 */
313 public String toString() {
314 StringBuffer result = new StringBuffer();
315 if (getDescription().trim().length() > 0) {
316 result.append("Description: " + getDescription()
317 + Utils.LINE_SEPARATOR + " ");
318 }
319 for (int i = 0; i < guid.length; i++) {
320 String tmp = Integer.toHexString(guid[i]);
321 if (tmp.length() < 2)
322 tmp = "0" + tmp;
323 if (i > 0)
324 result.append(", ");
325 result.append("0x" + tmp);
326 }
327 return result.toString();
328 }
329} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/StreamChunk.java b/songdbj/entagged/audioformats/asf/data/StreamChunk.java
new file mode 100644
index 0000000000..7aafa37c8a
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/StreamChunk.java
@@ -0,0 +1,173 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.math.BigInteger;
25
26import entagged.audioformats.asf.util.Utils;
27
28/**
29 * This class is the base for all handled stream contents. <br>
30 * A Stream chunk delivers information about a audio or video stream. Because of
31 * this the stream chunk identifies in one field what type of stream it is
32 * describing and so other data is provided. However some information is common
33 * to all stream chunks which are stored in this hierarchy of the class tree.
34 *
35 * @author Christian Laireiter
36 */
37public class StreamChunk extends Chunk {
38
39 /**
40 * If <code>true</code>, the stream data is encrypted.
41 */
42 private boolean contentEncrypted;
43
44 /**
45 * This field stores the number of the current stream. <br>
46 */
47 private int streamNumber;
48
49 /**
50 * @see #typeSpecificDataSize
51 */
52 private long streamSpecificDataSize;
53
54 /**
55 * Something technical. <br>
56 * Format time in 100-ns steps.
57 */
58 private long timeOffset;
59
60 /**
61 * Stores the size of type specific data structure within chunk.
62 */
63 private long typeSpecificDataSize;
64
65 /**
66 * Creates an instance
67 *
68 * @param pos
69 * Position of chunk within file or stream.
70 * @param chunkLen
71 * length of chunk
72 */
73 public StreamChunk(long pos, BigInteger chunkLen) {
74 super(GUID.GUID_AUDIOSTREAM, pos, chunkLen);
75 }
76
77 /**
78 * @return Returns the streamNumber.
79 */
80 public int getStreamNumber() {
81 return streamNumber;
82 }
83
84 /**
85 * @return Returns the streamSpecificDataSize.
86 */
87 public long getStreamSpecificDataSize() {
88 return streamSpecificDataSize;
89 }
90
91 /**
92 * @return Returns the timeOffset.
93 */
94 public long getTimeOffset() {
95 return timeOffset;
96 }
97
98 /**
99 * @return Returns the typeSpecificDataSize.
100 */
101 public long getTypeSpecificDataSize() {
102 return typeSpecificDataSize;
103 }
104
105 /**
106 * @return Returns the contentEncrypted.
107 */
108 public boolean isContentEncrypted() {
109 return contentEncrypted;
110 }
111
112 /**
113 * (overridden)
114 *
115 * @see entagged.audioformats.asf.data.Chunk#prettyPrint()
116 */
117 public String prettyPrint() {
118 StringBuffer result = new StringBuffer(super.prettyPrint());
119 result.insert(0, Utils.LINE_SEPARATOR + "Stream Data:"
120 + Utils.LINE_SEPARATOR);
121 result.append(" Stream number: " + getStreamNumber()
122 + Utils.LINE_SEPARATOR);
123 result.append(" Type specific data size : "
124 + getTypeSpecificDataSize() + Utils.LINE_SEPARATOR);
125 result.append(" Stream specific data size: "
126 + getStreamSpecificDataSize() + Utils.LINE_SEPARATOR);
127 result.append(" Time Offset : " + getTimeOffset()
128 + Utils.LINE_SEPARATOR);
129 result.append(" Content Encryption : " + isContentEncrypted()
130 + Utils.LINE_SEPARATOR);
131 return result.toString();
132 }
133
134 /**
135 * @param cntEnc
136 * The contentEncrypted to set.
137 */
138 public void setContentEncrypted(boolean cntEnc) {
139 this.contentEncrypted = cntEnc;
140 }
141
142 /**
143 * @param streamNum
144 * The streamNumber to set.
145 */
146 public void setStreamNumber(int streamNum) {
147 this.streamNumber = streamNum;
148 }
149
150 /**
151 * @param strSpecDataSize
152 * The streamSpecificDataSize to set.
153 */
154 public void setStreamSpecificDataSize(long strSpecDataSize) {
155 this.streamSpecificDataSize = strSpecDataSize;
156 }
157
158 /**
159 * @param timeOffs
160 * sets the time offset
161 */
162 public void setTimeOffset(long timeOffs) {
163 this.timeOffset = timeOffs;
164 }
165
166 /**
167 * @param typeSpecDataSize
168 * The typeSpecificDataSize to set.
169 */
170 public void setTypeSpecificDataSize(long typeSpecDataSize) {
171 this.typeSpecificDataSize = typeSpecDataSize;
172 }
173} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/VideoStreamChunk.java b/songdbj/entagged/audioformats/asf/data/VideoStreamChunk.java
new file mode 100644
index 0000000000..2b2c0211cd
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/VideoStreamChunk.java
@@ -0,0 +1,98 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data;
23
24import java.math.BigInteger;
25
26import entagged.audioformats.asf.util.Utils;
27
28/**
29 *
30 *
31 * @author Christian Laireiter
32 */
33public class VideoStreamChunk extends StreamChunk {
34
35 private long pictureHeight;
36
37 /**
38 * This field stores the width of the video stream.
39 */
40 private long pictureWidth;
41
42 /**
43 * Creates an instance.
44 *
45 * @param pos
46 * Position of the current chunk in the asf file or stream.
47 * @param chunkLen
48 * Length of the entire chunk (including guid and size)
49 */
50 public VideoStreamChunk(long pos, BigInteger chunkLen) {
51 super(pos, chunkLen);
52 }
53
54 /**
55 * @return Returns the pictureHeight.
56 */
57 public long getPictureHeight() {
58 return pictureHeight;
59 }
60
61 /**
62 * @return Returns the pictureWidth.
63 */
64 public long getPictureWidth() {
65 return pictureWidth;
66 }
67
68 /**
69 * (overridden)
70 *
71 * @see entagged.audioformats.asf.data.StreamChunk#prettyPrint()
72 */
73 public String prettyPrint() {
74 StringBuffer result = new StringBuffer(super.prettyPrint().replaceAll(
75 Utils.LINE_SEPARATOR, Utils.LINE_SEPARATOR + " "));
76 result.insert(0, Utils.LINE_SEPARATOR + "VideoStream");
77 result.append("Video info:" + Utils.LINE_SEPARATOR);
78 result.append(" Width : " + getPictureWidth()
79 + Utils.LINE_SEPARATOR);
80 result.append(" Heigth : " + getPictureHeight()
81 + Utils.LINE_SEPARATOR);
82 return result.toString();
83 }
84
85 /**
86 * @param picHeight
87 */
88 public void setPictureHeight(long picHeight) {
89 this.pictureHeight = picHeight;
90 }
91
92 /**
93 * @param picWidth
94 */
95 public void setPictureWidth(long picWidth) {
96 this.pictureWidth = picWidth;
97 }
98} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/data/wrapper/ContentDescriptorTagField.java b/songdbj/entagged/audioformats/asf/data/wrapper/ContentDescriptorTagField.java
new file mode 100644
index 0000000000..454aeb899f
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/data/wrapper/ContentDescriptorTagField.java
@@ -0,0 +1,130 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.data.wrapper;
23
24import java.io.UnsupportedEncodingException;
25
26import entagged.audioformats.asf.data.ContentDescriptor;
27import entagged.audioformats.generic.TagField;
28
29/**
30 * This class encapsulates a
31 * {@link entagged.audioformats.asf.data.ContentDescriptor}and provides access
32 * to it. <br>
33 * The content descriptor used for construction is copied.
34 *
35 * @author Christian Laireiter (liree)
36 */
37public class ContentDescriptorTagField implements TagField {
38
39 /**
40 * This descriptor is wrapped.
41 */
42 private ContentDescriptor toWrap;
43
44 /**
45 * Creates an instance.
46 *
47 * @param source
48 * The descriptor which should be represented as a
49 * {@link TagField}.
50 */
51 public ContentDescriptorTagField(ContentDescriptor source) {
52 this.toWrap = source.createCopy();
53 }
54
55 /**
56 * (overridden)
57 *
58 * @see entagged.audioformats.generic.TagField#copyContent(entagged.audioformats.generic.TagField)
59 */
60 public void copyContent(TagField field) {
61 throw new UnsupportedOperationException("Not implemented yet.");
62 }
63
64 /**
65 * (overridden)
66 *
67 * @see entagged.audioformats.generic.TagField#getId()
68 */
69 public String getId() {
70 return toWrap.getName();
71 }
72
73 /**
74 * (overridden)
75 *
76 * @see entagged.audioformats.generic.TagField#getRawContent()
77 */
78 public byte[] getRawContent() throws UnsupportedEncodingException {
79 return toWrap.getRawData();
80 }
81
82 /**
83 * (overridden)
84 *
85 * @see entagged.audioformats.generic.TagField#isBinary()
86 */
87 public boolean isBinary() {
88 return toWrap.getType() == ContentDescriptor.TYPE_BINARY;
89 }
90
91 /**
92 * (overridden)
93 *
94 * @see entagged.audioformats.generic.TagField#isBinary(boolean)
95 */
96 public void isBinary(boolean b) {
97 if (!b && isBinary()) {
98 throw new UnsupportedOperationException("No conversion supported.");
99 }
100 toWrap.setBinaryValue(toWrap.getRawData());
101 }
102
103 /**
104 * (overridden)
105 *
106 * @see entagged.audioformats.generic.TagField#isCommon()
107 */
108 public boolean isCommon() {
109 return toWrap.isCommon();
110 }
111
112 /**
113 * (overridden)
114 *
115 * @see entagged.audioformats.generic.TagField#isEmpty()
116 */
117 public boolean isEmpty() {
118 return toWrap.isEmpty();
119 }
120
121 /**
122 * (overridden)
123 *
124 * @see entagged.audioformats.generic.TagField#toString()
125 */
126 public String toString() {
127 return toWrap.getString();
128 }
129
130} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/io/AsfHeaderReader.java b/songdbj/entagged/audioformats/asf/io/AsfHeaderReader.java
new file mode 100644
index 0000000000..5e82fcbb0b
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/io/AsfHeaderReader.java
@@ -0,0 +1,178 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.io;
23
24import java.io.IOException;
25import java.io.RandomAccessFile;
26import java.math.BigInteger;
27import java.util.ArrayList;
28import java.util.Iterator;
29
30import entagged.audioformats.asf.data.AsfHeader;
31import entagged.audioformats.asf.data.ContentDescription;
32import entagged.audioformats.asf.data.Chunk;
33import entagged.audioformats.asf.data.EncodingChunk;
34import entagged.audioformats.asf.data.FileHeader;
35import entagged.audioformats.asf.data.GUID;
36import entagged.audioformats.asf.data.ExtendedContentDescription;
37import entagged.audioformats.asf.data.StreamChunk;
38import entagged.audioformats.asf.util.Utils;
39
40/**
41 * This <i>class </i> reads an Asf header out of an inputstream an creates an
42 * {@link entagged.audioformats.asf.data.AsfHeader}object if successfull. <br>
43 * For now only ASF ver 1.0 is supported, till ver 2.0 seems not to be used
44 * anywhere. <br>
45 * Asf headers contains other chunks. As of this other readers of current
46 * <b>package </b> are called from within.
47 *
48 * @author Christian Laireiter
49 */
50public class AsfHeaderReader {
51
52 /**
53 * This method tries to extract an ASF-header out of the given stream. <br>
54 * If no header could be extracted <code>null</code> is returned. <br>
55 *
56 * @param in
57 * File which contains the ASF header.
58 * @return AsfHeader-Wrapper, or <code>null</code> if no supported Asf
59 * header was found.
60 * @throws IOException
61 * Read errors
62 */
63 public static AsfHeader readHeader(RandomAccessFile in) throws IOException {
64 AsfHeaderReader reader = new AsfHeaderReader();
65 return reader.parseData(in);
66 }
67
68 /**
69 * Protected default constructor. <br>
70 * At the time no special use.
71 *
72 */
73 protected AsfHeaderReader() {
74 // Nothing to do
75 }
76
77 /**
78 * This Method implements the reading of the header block. <br>
79 *
80 * @param in
81 * Stream which contains an Asf header.
82 * @return <code>null</code> if no valid data found, else a Wrapper
83 * containing all supported data.
84 * @throws IOException
85 * Read errors.
86 */
87 private AsfHeader parseData(RandomAccessFile in) throws IOException {
88 AsfHeader result = null;
89 long chunkStart = in.getFilePointer();
90 GUID possibleGuid = Utils.readGUID(in);
91
92 if (GUID.GUID_HEADER.equals(possibleGuid)) {
93 // For Know the filepointer pointed to an ASF header chunk.
94 BigInteger chunkLen = Utils.readBig64(in);
95
96 long chunkCount = Utils.readUINT32(in);
97 // They are of unknown use.
98 in.skipBytes(2);
99
100 /*
101 * Now reading header of chuncks.
102 */
103 ArrayList chunks = new ArrayList();
104 while (chunkLen.compareTo(BigInteger.valueOf(in.getFilePointer())) > 0) {
105 Chunk chunk = ChunkHeaderReader.readChunckHeader(in);
106 chunks.add(chunk);
107 in.seek(chunk.getChunckEnd());
108 }
109
110 /*
111 * Creating the resulting object because streamchunks will be added.
112 */
113 result = new AsfHeader(chunkStart, chunkLen, chunkCount);
114 /*
115 * Now we know all positions and guids of chunks which are contained
116 * whithin asf header. Further we need to identify the type of those
117 * chunks and parse the interesting ones.
118 */
119 FileHeader fileHeader = null;
120 ExtendedContentDescription extendedDescription = null;
121 EncodingChunk encodingChunk = null;
122 StreamChunk streamChunk = null;
123 ContentDescription contentDescription = null;
124
125 Iterator iterator = chunks.iterator();
126 while (iterator.hasNext()) {
127 Chunk currentChunk = (Chunk) iterator.next();
128 if (fileHeader == null
129 && (fileHeader = FileHeaderReader
130 .read(in, currentChunk)) != null) {
131 continue;
132 }
133 if (extendedDescription == null
134 && (extendedDescription = ExtContentDescReader.read(in,
135 currentChunk)) != null) {
136 continue;
137 }
138 if (encodingChunk == null
139 && (encodingChunk = EncodingChunkReader.read(in,
140 currentChunk)) != null) {
141 continue;
142 }
143 if (streamChunk == null
144 && (streamChunk = StreamChunkReader.read(in,
145 currentChunk)) != null) {
146 result.addStreamChunk(streamChunk);
147 streamChunk = null;
148 continue;
149 }
150 if (contentDescription == null
151 && (contentDescription = ContentDescriptionReader.read(
152 in, currentChunk)) != null) {
153 continue;
154 }
155 /*
156 * If none of the above statements executed the "continue", this
157 * chunk couldn't be interpreted. Despite this the chunk is
158 * remembered
159 */
160 result.addUnspecifiedChunk(currentChunk);
161 }
162 /*
163 * Finally store the parsed chunks in the resulting ASFHeader
164 * object.
165 */
166 result.setFileHeader(fileHeader);
167 result.setEncodingChunk(encodingChunk);
168 /*
169 * Warning, extendedDescription and contentDescription maybe null
170 * since they are optional fields.
171 */
172 result.setExtendedContentDescription(extendedDescription);
173 result.setContentDescription(contentDescription);
174 }
175 return result;
176 }
177
178} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/io/ChunkHeaderReader.java b/songdbj/entagged/audioformats/asf/io/ChunkHeaderReader.java
new file mode 100644
index 0000000000..7d7c8d98a1
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/io/ChunkHeaderReader.java
@@ -0,0 +1,57 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.io;
23
24import java.io.IOException;
25import java.io.RandomAccessFile;
26import java.math.BigInteger;
27
28import entagged.audioformats.asf.data.Chunk;
29import entagged.audioformats.asf.data.GUID;
30import entagged.audioformats.asf.util.Utils;
31
32/**
33 * Default reader, Reads GUID and size out of an inputsream and creates a
34 * {@link entagged.audioformats.asf.data.Chunk}object.
35 *
36 * @author Christian Laireiter
37 */
38class ChunkHeaderReader {
39
40 /**
41 * Interprets current data as a header of a chunk.
42 *
43 * @param input
44 * inputdata
45 * @return Chunk.
46 * @throws IOException
47 * Access errors.
48 */
49 public static Chunk readChunckHeader(RandomAccessFile input)
50 throws IOException {
51 long pos = input.getFilePointer();
52 GUID guid = Utils.readGUID(input);
53 BigInteger chunkLength = Utils.readBig64(input);
54 return new Chunk(guid, pos, chunkLength);
55 }
56
57} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/io/ContentDescriptionReader.java b/songdbj/entagged/audioformats/asf/io/ContentDescriptionReader.java
new file mode 100644
index 0000000000..a2b120f7d1
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/io/ContentDescriptionReader.java
@@ -0,0 +1,175 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.io;
23
24import java.io.IOException;
25import java.io.RandomAccessFile;
26import java.math.BigInteger;
27
28import entagged.audioformats.asf.data.ContentDescription;
29import entagged.audioformats.asf.data.Chunk;
30import entagged.audioformats.asf.data.GUID;
31import entagged.audioformats.asf.util.Utils;
32
33/**
34 * Reads and interprets the data of a asf chunk containing title, author... <br>
35 *
36 * @see entagged.audioformats.asf.data.ContentDescription
37 *
38 * @author Christian Laireiter
39 */
40public class ContentDescriptionReader {
41
42 /**
43 * Creates and fills a
44 * {@link entagged.audioformats.asf.data.ContentDescription}from given
45 * file. <br>
46 *
47 * @param raf
48 * Input
49 * @param candidate
50 * Chunk which possibly is a file header.
51 * @return FileHeader if filepointer of <code>raf</code> is at valid
52 * fileheader.
53 * @throws IOException
54 * Read errors.
55 */
56 public static ContentDescription read(RandomAccessFile raf, Chunk candidate)
57 throws IOException {
58 if (raf == null || candidate == null) {
59 throw new IllegalArgumentException("Arguments must not be null.");
60 }
61 if (GUID.GUID_CONTENTDESCRIPTION.equals(candidate.getGuid())) {
62 raf.seek(candidate.getPosition());
63 return new ContentDescriptionReader().parseData(raf);
64 }
65 return null;
66 }
67
68 /**
69 * This method reads a UTF-16 encoded String. <br>
70 * For the use this method the number of bytes used by current string must
71 * be known. <br>
72 * The ASF spec recommends that those strings end with a terminating zero.
73 * However it also says that it is not always the case.
74 *
75 * @param raf
76 * Input source
77 * @param strLen
78 * Number of bytes the String may take.
79 * @return read String.
80 * @throws IOException
81 * read errors.
82 */
83 public static String readFixedSizeUTF16Str(RandomAccessFile raf, int strLen)
84 throws IOException {
85 byte[] strBytes = new byte[strLen];
86 int read = raf.read(strBytes);
87 if (read == strBytes.length) {
88 if (strBytes.length >= 2) {
89 /*
90 * Zero termination is recommended but optional.
91 * So check and if, remove.
92 */
93 if (strBytes[strBytes.length-1] == 0 && strBytes[strBytes.length-2] == 0) {
94 byte[] copy = new byte[strBytes.length-2];
95 System.arraycopy(strBytes, 0, copy, 0, strBytes.length-2);
96 strBytes = copy;
97 }
98 }
99 return new String(strBytes, "UTF-16LE");
100 }
101 throw new IllegalStateException(
102 "Couldn't read the necessary amount of bytes.");
103 }
104
105 /**
106 * Should not be used for now.
107 *
108 */
109 protected ContentDescriptionReader() {
110 // NOTHING toDo
111 }
112
113 /**
114 * Directly behind the GUID and chunkSize of the current chunck comes 5
115 * sizes (16-bit) of string lengths. <br>
116 *
117 * @param raf
118 * input source
119 * @return Number and length of Strings, which are directly behind
120 * filepointer if method exits.
121 * @throws IOException
122 * read errors.
123 */
124 private int[] getStringSizes(RandomAccessFile raf) throws IOException {
125 int[] result = new int[5];
126 for (int i = 0; i < result.length; i++) {
127 result[i] = Utils.readUINT16(raf);
128 }
129 return result;
130 }
131
132 /**
133 * Does the job of {@link #read(RandomAccessFile, Chunk)}
134 *
135 * @param raf
136 * input source
137 * @return Contentdescription
138 * @throws IOException
139 * read errors.
140 */
141 private ContentDescription parseData(RandomAccessFile raf)
142 throws IOException {
143 ContentDescription result = null;
144 long chunkStart = raf.getFilePointer();
145 GUID guid = Utils.readGUID(raf);
146 if (GUID.GUID_CONTENTDESCRIPTION.equals(guid)) {
147 BigInteger chunkLen = Utils.readBig64(raf);
148 result = new ContentDescription(chunkStart, chunkLen);
149 /*
150 * Now comes 16-Bit values representing the length of the Strings
151 * which follows.
152 */
153 int[] stringSizes = getStringSizes(raf);
154 /*
155 * Now we know the String length of each occuring String.
156 */
157 String[] strings = new String[stringSizes.length];
158 for (int i = 0; i < strings.length; i++) {
159 if (stringSizes[i] > 0)
160 strings[i] = readFixedSizeUTF16Str(raf, stringSizes[i]);
161 }
162 if (stringSizes[0] > 0)
163 result.setTitle(strings[0]);
164 if (stringSizes[1] > 0)
165 result.setAuthor(strings[1]);
166 if (stringSizes[2] > 0)
167 result.setCopyRight(strings[2]);
168 if (stringSizes[3] > 0)
169 result.setComment(strings[3]);
170 if (stringSizes[4] > 0)
171 result.setRating(strings[4]);
172 }
173 return result;
174 }
175} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/io/EncodingChunkReader.java b/songdbj/entagged/audioformats/asf/io/EncodingChunkReader.java
new file mode 100644
index 0000000000..41ee9a49db
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/io/EncodingChunkReader.java
@@ -0,0 +1,118 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.io;
23
24import java.io.IOException;
25import java.io.RandomAccessFile;
26import java.math.BigInteger;
27
28import entagged.audioformats.asf.data.Chunk;
29import entagged.audioformats.asf.data.EncodingChunk;
30import entagged.audioformats.asf.data.GUID;
31import entagged.audioformats.asf.util.Utils;
32
33/**
34 * This class reads the chunk containing encoding data <br>
35 * <b>Warning:<b><br>
36 * Implementation is not completed. More analysis of this chunk is needed.
37 *
38 * @author Christian Laireiter
39 */
40public class EncodingChunkReader {
41
42 /**
43 * This reads the current data and interprets it as an encoding chunk. <br>
44 * <b>Warning:<b><br>
45 * Implementation is not completed. More analysis of this chunk is needed.
46 *
47 * @param raf
48 * Input source
49 * @param candidate
50 * Chunk which possibly contains encoding data.
51 * @return Encoding info. <code>null</code> if its not a valid encoding
52 * chunk. <br>
53 * @throws IOException
54 * read errors.
55 */
56 public static EncodingChunk read(RandomAccessFile raf, Chunk candidate)
57 throws IOException {
58 if (raf == null || candidate == null) {
59 throw new IllegalArgumentException("Arguments must not be null.");
60 }
61 if (GUID.GUID_ENCODING.equals(candidate.getGuid())) {
62 raf.seek(candidate.getPosition());
63 return new EncodingChunkReader().parseData(raf);
64 }
65 return null;
66 }
67
68 /**
69 * Should not be used for now.
70 *
71 */
72 protected EncodingChunkReader() {
73 // NOTHING toDo
74 }
75
76 /**
77 * see {@link #read(RandomAccessFile, Chunk)}
78 *
79 * @param raf
80 * input source.
81 * @return Enconding info. <code>null</code> if its not a valid encoding
82 * chunk. <br>
83 * @throws IOException
84 * read errors.
85 */
86 private EncodingChunk parseData(RandomAccessFile raf) throws IOException {
87 EncodingChunk result = null;
88 long chunkStart = raf.getFilePointer();
89 GUID guid = Utils.readGUID(raf);
90 if (GUID.GUID_ENCODING.equals(guid)) {
91 BigInteger chunkLen = Utils.readBig64(raf);
92 result = new EncodingChunk(chunkStart, chunkLen);
93
94 // Can't be interpreted
95 /*
96 * What do I think of this data, well it seems to be another GUID.
97 * Then followed by a UINT16 indicating a length of data following
98 * (by half). My test files just had the length of one and a two
99 * bytes zero.
100 */
101 raf.skipBytes(20);
102
103 /*
104 * Read the number of strings which will follow
105 */
106 int stringCount = Utils.readUINT16(raf);
107
108 /*
109 * Now reading the specified amount of strings.
110 */
111 for (int i = 0; i < stringCount; i++) {
112 result.addString(Utils.readCharacterSizedString(raf));
113 }
114 }
115 return result;
116 }
117
118} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/io/ExtContentDescReader.java b/songdbj/entagged/audioformats/asf/io/ExtContentDescReader.java
new file mode 100644
index 0000000000..0bc57d0c9d
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/io/ExtContentDescReader.java
@@ -0,0 +1,182 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.io;
23
24import java.io.ByteArrayOutputStream;
25import java.io.IOException;
26import java.io.RandomAccessFile;
27import java.math.BigInteger;
28
29import entagged.audioformats.asf.data.Chunk;
30import entagged.audioformats.asf.data.ContentDescriptor;
31import entagged.audioformats.asf.data.ExtendedContentDescription;
32import entagged.audioformats.asf.data.GUID;
33import entagged.audioformats.asf.util.Utils;
34
35/**
36 * Class for reading Tag information out of the extended content description of
37 * an asf file. <br>
38 *
39 * @see entagged.audioformats.asf.data.ExtendedContentDescription
40 *
41 * @author Christian Laireiter
42 */
43public class ExtContentDescReader {
44
45 /**
46 * Reads the current chunk if it is a matching one.
47 *
48 * @param raf
49 * Input source
50 * @param candidate
51 * Chunk which possibly contains additional tags
52 * @return Wrapper for the extended content description
53 * @throws IOException
54 * Read errors
55 */
56 public static ExtendedContentDescription read(RandomAccessFile raf,
57 Chunk candidate) throws IOException {
58 if (raf == null || candidate == null) {
59 throw new IllegalArgumentException("Arguments must not be null.");
60 }
61 if (GUID.GUID_EXTENDED_CONTENT_DESCRIPTION.equals(candidate.getGuid())) {
62 raf.seek(candidate.getPosition());
63 return new ExtContentDescReader().parseData(raf);
64 }
65 return null;
66 }
67
68 /**
69 * Should not be used for now.
70 *
71 */
72 protected ExtContentDescReader() {
73 // NOTHING toDo
74 }
75
76 /**
77 * Does the job of {@link #read(RandomAccessFile, Chunk)}
78 *
79 * @param raf
80 * Input source
81 * @return Wrapper for properties
82 * @throws IOException
83 * read errors.
84 */
85 private ExtendedContentDescription parseData(RandomAccessFile raf)
86 throws IOException {
87 ExtendedContentDescription result = null;
88 long chunkStart = raf.getFilePointer();
89 GUID guid = Utils.readGUID(raf);
90
91 if (GUID.GUID_EXTENDED_CONTENT_DESCRIPTION.equals(guid)) {
92 BigInteger chunkLen = Utils.readBig64(raf);
93
94 // Reading Number of Tags.
95 long descriptorCount = Utils.readUINT16(raf);
96
97 // Create Result object
98 result = new ExtendedContentDescription(chunkStart, chunkLen);
99
100 for (long i = 0; i < descriptorCount; i++) {
101 String tagElement = Utils.readUTF16LEStr(raf);
102 int type = Utils.readUINT16(raf);
103 ContentDescriptor prop = new ContentDescriptor(tagElement, type);
104 switch (type) {
105 case ContentDescriptor.TYPE_STRING:
106 prop.setStringValue(Utils.readUTF16LEStr(raf));
107 break;
108 case ContentDescriptor.TYPE_BINARY:
109 prop.setBinaryValue(readBinaryData(raf));
110 break;
111 case ContentDescriptor.TYPE_BOOLEAN:
112 prop.setBooleanValue(readBoolean(raf));
113 break;
114 case ContentDescriptor.TYPE_DWORD:
115 raf.skipBytes(2);
116 prop.setDWordValue(Utils.readUINT32(raf));
117 break;
118 case ContentDescriptor.TYPE_WORD:
119 raf.skipBytes(2);
120 prop.setWordValue(Utils.readUINT16(raf));
121 break;
122 case ContentDescriptor.TYPE_QWORD:
123 raf.skipBytes(2);
124 prop.setQWordValue(Utils.readUINT64(raf));
125 break;
126 default:
127 // Unknown, hopefully the convention for the size of the
128 // value
129 // is given, so we could read it binary
130 prop.setStringValue("Invalid datatype: "
131 + new String(readBinaryData(raf)));
132 }
133 result.addDescriptor(prop);
134 }
135 }
136 return result;
137 }
138
139 /**
140 * This method read binary Data. <br>
141 *
142 * @param raf
143 * input source.
144 * @return the binary data
145 * @throws IOException
146 * read errors.
147 */
148 private byte[] readBinaryData(RandomAccessFile raf) throws IOException {
149 ByteArrayOutputStream bos = new ByteArrayOutputStream();
150 int size = Utils.readUINT16(raf);
151 for (int i = 0; i < size; i++) {
152 bos.write(raf.read());
153 }
154 return bos.toByteArray();
155 }
156
157 /**
158 * This Method reads a boolean value out of the tag chunk. <br>
159 * A boolean requires 6 bytes. This means we've got 3 16-Bit unsigned
160 * numbers. The first number should always be 4 because the other 2 numbers
161 * needs them. The second number seems to take the values 0 (for
162 * <code>false</code>) and 1 (for <code>true</code>). The third one is
163 * zero, maybe indication the end of the value. <br>
164 *
165 * @param raf
166 * input source
167 * @return boolean representation.
168 * @throws IOException
169 * read errors.
170 */
171 private boolean readBoolean(RandomAccessFile raf) throws IOException {
172 int size = Utils.readUINT16(raf);
173 if (size != 4)
174 throw new IllegalStateException(
175 "Boolean value do require 4 Bytes. (Size value is: " + size
176 + ")");
177 long value = Utils.readUINT32(raf);
178 boolean result = value == 1;
179 return result;
180 }
181
182} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/io/FileHeaderReader.java b/songdbj/entagged/audioformats/asf/io/FileHeaderReader.java
new file mode 100644
index 0000000000..92dcbe746b
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/io/FileHeaderReader.java
@@ -0,0 +1,116 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.io;
23
24import java.io.IOException;
25import java.io.RandomAccessFile;
26import java.math.BigInteger;
27
28import entagged.audioformats.asf.data.Chunk;
29import entagged.audioformats.asf.data.FileHeader;
30import entagged.audioformats.asf.data.GUID;
31import entagged.audioformats.asf.util.Utils;
32
33/**
34 * Reads and interprets the data of the file header. <br>
35 *
36 * @author Christian Laireiter
37 */
38public class FileHeaderReader {
39
40 /**
41 * Creates and fills a {@link FileHeader}from given file. <br>
42 *
43 * @param raf
44 * Input
45 * @param candidate
46 * Chunk which possibly is a file header.
47 * @return FileHeader if filepointer of <code>raf</code> is at valid
48 * fileheader.
49 * @throws IOException
50 * Read errors.
51 */
52 public static FileHeader read(RandomAccessFile raf, Chunk candidate)
53 throws IOException {
54 if (raf == null || candidate == null) {
55 throw new IllegalArgumentException("Arguments must not be null.");
56 }
57 if (GUID.GUID_FILE.equals(candidate.getGuid())) {
58 raf.seek(candidate.getPosition());
59 return new FileHeaderReader().parseData(raf);
60 }
61 return null;
62 }
63
64 /**
65 * Should not be used for now.
66 *
67 */
68 protected FileHeaderReader() {
69 // NOTHING toDo
70 }
71
72 /**
73 * Tries to extract an ASF file header object out of the given input.
74 *
75 * @param raf
76 * @return <code>null</code> if no valid file header object.
77 * @throws IOException
78 */
79 private FileHeader parseData(RandomAccessFile raf) throws IOException {
80 FileHeader result = null;
81 long fileHeaderStart = raf.getFilePointer();
82 GUID guid = Utils.readGUID(raf);
83 if (GUID.GUID_FILE.equals(guid)) {
84 BigInteger chunckLen = Utils.readBig64(raf);
85 // Skip client GUID.
86 raf.skipBytes(16);
87
88 BigInteger fileSize = Utils.readBig64(raf);
89 if (fileSize.intValue() != raf.length()) {
90 System.err
91 .println("Filesize of file doesn't match len of Fileheader. ("
92 + fileSize.toString() + ", file: "+raf.length()+")");
93 }
94 // fileTime in 100 ns since midnight of 1st january 1601 GMT
95 BigInteger fileTime = Utils.readBig64(raf);
96
97 BigInteger packageCount = Utils.readBig64(raf);
98
99 BigInteger timeEndPos = Utils.readBig64(raf);
100 BigInteger duration = Utils.readBig64(raf);
101 BigInteger timeStartPos = Utils.readBig64(raf);
102
103 long flags = Utils.readUINT32(raf);
104
105 long minPkgSize = Utils.readUINT32(raf);
106 long maxPkgSize = Utils.readUINT32(raf);
107 long uncompressedFrameSize = Utils.readUINT32(raf);
108
109 result = new FileHeader(fileHeaderStart, chunckLen, fileSize,
110 fileTime, packageCount, duration, timeStartPos, timeEndPos,
111 flags, minPkgSize, maxPkgSize, uncompressedFrameSize);
112 }
113 return result;
114 }
115
116} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/io/StreamChunkReader.java b/songdbj/entagged/audioformats/asf/io/StreamChunkReader.java
new file mode 100644
index 0000000000..97563ca320
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/io/StreamChunkReader.java
@@ -0,0 +1,187 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.io;
23
24import java.io.IOException;
25import java.io.RandomAccessFile;
26import java.math.BigInteger;
27
28import entagged.audioformats.asf.data.AudioStreamChunk;
29import entagged.audioformats.asf.data.Chunk;
30import entagged.audioformats.asf.data.GUID;
31import entagged.audioformats.asf.data.StreamChunk;
32import entagged.audioformats.asf.data.VideoStreamChunk;
33import entagged.audioformats.asf.util.Utils;
34
35/**
36 * Reads and interprets the data of the audio or video stream information chunk.
37 * <br>
38 *
39 * @author Christian Laireiter
40 */
41public class StreamChunkReader {
42
43 /**
44 * Shouldn't be used for now.
45 *
46 */
47 protected StreamChunkReader() {
48 // Nothin todo
49 }
50
51 /**
52 * Reads audio and video stream information.
53 *
54 * @param raf
55 * input source.
56 * @param candidate
57 * possible audio stream chunk
58 * @return Audio Stream Information. <code>null</code> if its not an audio
59 * stream object.
60 * @throws IOException
61 * read errors
62 */
63 public static StreamChunk read(RandomAccessFile raf, Chunk candidate)
64 throws IOException {
65 if (raf == null || candidate == null) {
66 throw new IllegalArgumentException("Arguments must not be null.");
67 }
68 if (GUID.GUID_STREAM.equals(candidate.getGuid())) {
69 raf.seek(candidate.getPosition());
70 return new StreamChunkReader().parseData(raf);
71 }
72 return null;
73 }
74
75 /**
76 * Reads audio and video stream information.
77 *
78 * @param raf
79 * input source.
80 * @return Audio Stream Information. <code>null</code> if its not an audio
81 * stream object.
82 * @throws IOException
83 * read errors
84 */
85 private StreamChunk parseData(RandomAccessFile raf) throws IOException {
86 StreamChunk result = null;
87 long chunkStart = raf.getFilePointer();
88 GUID guid = Utils.readGUID(raf);
89 if (GUID.GUID_STREAM.equals(guid)) {
90 BigInteger chunkLength = Utils.readBig64(raf);
91 // Now comes GUID indicating whether stream content type is audio or
92 // video
93 GUID streamTypeGUID = Utils.readGUID(raf);
94 if (GUID.GUID_AUDIOSTREAM.equals(streamTypeGUID)
95 || GUID.GUID_VIDEOSTREAM.equals(streamTypeGUID)) {
96
97 // A guid is indicating whether the stream is error
98 // concealed
99 GUID errorConcealment = Utils.readGUID(raf);
100 /*
101 * Read the Time Offset
102 */
103 long timeOffset = Utils.readUINT64(raf);
104
105 long typeSpecificDataSize = Utils.readUINT32(raf);
106 long streamSpecificDataSize = Utils.readUINT32(raf);
107
108 /*
109 * Read a bitfield. (Contains streamnumber, and whether
110 * the stream content is encrypted.)
111 */
112 int mask = Utils.readUINT16(raf);
113 int streamNumber = mask & 127;
114 boolean contentEncrypted = (mask & (1 << 15)) != 0;
115
116 /*
117 * Skip a reserved field
118 */
119 raf.skipBytes(4);
120
121 if (GUID.GUID_AUDIOSTREAM.equals(streamTypeGUID)) {
122 /*
123 * Reading audio specific information
124 */
125 AudioStreamChunk audioStreamChunk = new AudioStreamChunk(
126 chunkStart, chunkLength);
127 result = audioStreamChunk;
128
129 /*
130 * read WAVEFORMATEX and format extension.
131 */
132 long compressionFormat = Utils.readUINT16(raf);
133 long channelCount = Utils.readUINT16(raf);
134 long samplingRate = Utils.readUINT32(raf);
135 long avgBytesPerSec = Utils.readUINT32(raf);
136 long blockAlignment = Utils.readUINT16(raf);
137 int bitsPerSample = Utils.readUINT16(raf);
138 int codecSpecificDataSize = Utils.readUINT16(raf);
139 byte[] codecSpecificData = new byte[codecSpecificDataSize];
140 raf.readFully(codecSpecificData);
141
142 audioStreamChunk.setCompressionFormat(compressionFormat);
143 audioStreamChunk.setChannelCount(channelCount);
144 audioStreamChunk.setSamplingRate(samplingRate);
145 audioStreamChunk.setAverageBytesPerSec(avgBytesPerSec);
146 audioStreamChunk.setErrorConcealment(errorConcealment);
147 audioStreamChunk.setBlockAlignment(blockAlignment);
148 audioStreamChunk.setBitsPerSample (bitsPerSample);
149 audioStreamChunk.setCodecData (codecSpecificData);
150 } else if (GUID.GUID_VIDEOSTREAM.equals(streamTypeGUID)) {
151 /*
152 * Reading video specific information
153 */
154 VideoStreamChunk videoStreamChunk = new VideoStreamChunk(
155 chunkStart, chunkLength);
156 result = videoStreamChunk;
157
158 long pictureWidth = Utils.readUINT32(raf);
159 long pictureHeight = Utils.readUINT32(raf);
160
161 // Skipt unknown field
162 raf.skipBytes(1);
163
164 // long bitMapInfoHeaderSize = Utils.readUINT32(raf);
165 // bitMapInfoHeaderEnd stores now the end of the
166 // bitMapInfoHeader
167 // long bitMapInfoHeaderEnd = raf.getFilePointer()
168 // + bitMapInfoHeaderSize;
169
170 videoStreamChunk.setPictureWidth(pictureWidth);
171 videoStreamChunk.setPictureHeight(pictureHeight);
172 }
173
174 /*
175 * Setting common values for audio and video
176 */
177 result.setStreamNumber(streamNumber);
178 result.setStreamSpecificDataSize(streamSpecificDataSize);
179 result.setTypeSpecificDataSize(typeSpecificDataSize);
180 result.setTimeOffset(timeOffset);
181 result.setContentEncrypted(contentEncrypted);
182 }
183 }
184 return result;
185 }
186
187} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/util/ChunkPositionComparator.java b/songdbj/entagged/audioformats/asf/util/ChunkPositionComparator.java
new file mode 100644
index 0000000000..864b6cb432
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/util/ChunkPositionComparator.java
@@ -0,0 +1,52 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.util;
23
24import java.util.Comparator;
25
26import entagged.audioformats.asf.data.Chunk;
27
28/**
29 * This class is needed for ordering all types of
30 * {@link entagged.audioformats.asf.data.Chunk}s ascending by their Position.
31 * <br>
32 *
33 * @author Christian Laireiter
34 */
35public class ChunkPositionComparator implements Comparator {
36
37 /**
38 * (overridden)
39 *
40 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
41 */
42 public int compare(Object o1, Object o2) {
43 int result = 0;
44 if (o1 instanceof Chunk && o2 instanceof Chunk) {
45 Chunk c1 = (Chunk) o1;
46 Chunk c2 = (Chunk) o2;
47 result = (int) (c1.getPosition() - c2.getPosition());
48 }
49 return result;
50 }
51
52} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/util/TagConverter.java b/songdbj/entagged/audioformats/asf/util/TagConverter.java
new file mode 100644
index 0000000000..eb12d23586
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/util/TagConverter.java
@@ -0,0 +1,234 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.util;
23
24import java.io.UnsupportedEncodingException;
25import java.util.Arrays;
26import java.util.Iterator;
27
28import entagged.audioformats.Tag;
29import entagged.audioformats.asf.data.AsfHeader;
30import entagged.audioformats.asf.data.ContentDescription;
31import entagged.audioformats.asf.data.ContentDescriptor;
32import entagged.audioformats.asf.data.ExtendedContentDescription;
33import entagged.audioformats.asf.data.wrapper.ContentDescriptorTagField;
34import entagged.audioformats.generic.GenericTag;
35import entagged.audioformats.generic.TagField;
36
37/**
38 * This class provides functionality to convert
39 * {@link entagged.audioformats.asf.data.AsfHeader}objects into
40 * {@link entagged.audioformats.Tag}objects (More extract information and
41 * create a {@link entagged.audioformats.generic.GenericTag}).<br>
42 *
43 *
44 * @author Christian Laireiter (liree)
45 */
46public class TagConverter {
47
48 /**
49 * This method assigns those tags of <code>tag</code> which are defined to
50 * be common by entagged. <br>
51 *
52 * @param tag
53 * The tag from which the values are gathered. <br>
54 * Assigned values are: <br>
55 * @see Tag#getAlbum() <br>
56 * @see Tag#getTrack() <br>
57 * @see Tag#getYear() <br>
58 * @see Tag#getGenre() <br>
59 * @param description
60 * The extended content description which should recieve the
61 * values. <br>
62 * <b>Warning: </b> the common values will be replaced.
63 */
64 public static void assignCommonTagValues(Tag tag,
65 ExtendedContentDescription description) {
66 ContentDescriptor tmp = null;
67 if (tag.getFirstAlbum() != null && tag.getFirstAlbum().length() > 0) {
68 tmp = new ContentDescriptor(ContentDescriptor.ID_ALBUM,
69 ContentDescriptor.TYPE_STRING);
70 tmp.setStringValue(tag.getFirstAlbum());
71 description.addOrReplace(tmp);
72 } else {
73 description.remove(ContentDescriptor.ID_ALBUM);
74 }
75 if (tag.getFirstTrack() != null && tag.getFirstTrack().length() > 0) {
76 tmp = new ContentDescriptor(ContentDescriptor.ID_TRACKNUMBER,
77 ContentDescriptor.TYPE_STRING);
78 tmp.setStringValue(tag.getFirstTrack());
79 description.addOrReplace(tmp);
80 } else {
81 description.remove(ContentDescriptor.ID_TRACKNUMBER);
82 }
83 if (tag.getFirstYear() != null && tag.getFirstYear().length() > 0) {
84 tmp = new ContentDescriptor(ContentDescriptor.ID_YEAR,
85 ContentDescriptor.TYPE_STRING);
86 tmp.setStringValue(tag.getFirstYear());
87 description.addOrReplace(tmp);
88 } else {
89 description.remove(ContentDescriptor.ID_YEAR);
90 }
91 if (tag.getFirstGenre() != null && tag.getFirstGenre().length() > 0) {
92 tmp = new ContentDescriptor(ContentDescriptor.ID_GENRE,
93 ContentDescriptor.TYPE_STRING);
94 tmp.setStringValue(tag.getFirstGenre());
95 description.addOrReplace(tmp);
96 int index = Arrays.asList(Tag.DEFAULT_GENRES).indexOf(
97 tag.getFirstGenre());
98 if (index != -1) {
99 tmp = new ContentDescriptor(ContentDescriptor.ID_GENREID,
100 ContentDescriptor.TYPE_STRING);
101 tmp.setStringValue("(" + index + ")");
102 description.addOrReplace(tmp);
103 } else {
104 description.remove(ContentDescriptor.ID_GENREID);
105 }
106 } else {
107 description.remove(ContentDescriptor.ID_GENRE);
108 description.remove(ContentDescriptor.ID_GENREID);
109 }
110 }
111
112 /**
113 * This method will add or replace all values of tag are not defined as
114 * common by entagged.
115 *
116 * @param tag
117 * The tag containing the values.
118 * @param descriptor
119 * the extended content description.
120 */
121 public static void assignOptionalTagValues(Tag tag,
122 ExtendedContentDescription descriptor) {
123 Iterator it = tag.getFields();
124 ContentDescriptor tmp = null;
125 while (it.hasNext()) {
126 try {
127 TagField currentField = (TagField) it.next();
128 if (!currentField.isCommon()) {
129 tmp = new ContentDescriptor(currentField.getId(),
130 ContentDescriptor.TYPE_STRING);
131 if (currentField.isBinary()) {
132 tmp.setBinaryValue(currentField.getRawContent());
133 } else {
134 tmp.setStringValue(currentField.toString());
135 }
136 descriptor.addOrReplace(tmp);
137 }
138 } catch (UnsupportedEncodingException uee) {
139 uee.printStackTrace();
140 }
141 }
142 }
143
144 /**
145 * This method creates a new {@link ContentDescription}object, filled with
146 * the according values of the given <code>tag</code>.<br>
147 * <b>Warning </b>: <br>
148 * Only the first values can be stored in asf files, because the content
149 * description is limited.
150 *
151 * @param tag
152 * The tag from which the values are taken. <br>
153 * @see Tag#getFirstArtist() <br>
154 * @see Tag#getFirstTitle() <br>
155 * @see Tag#getFirstComment() <br>
156 *
157 * @return A new content description object filled with <code>tag</code>.
158 */
159 public static ContentDescription createContentDescription(Tag tag) {
160 ContentDescription result = new ContentDescription();
161 result.setAuthor(tag.getFirstArtist());
162 result.setTitle(tag.getFirstTitle());
163 result.setComment(tag.getFirstComment());
164 return result;
165 }
166
167 /**
168 * This method creates a new {@link ExtendedContentDescription}object
169 * filled with the values of the given <code>tag</code>.<br>
170 * Since extended content description of asf files can store name-value
171 * pairs, nearly each {@link entagged.audioformats.generic.TagField}can be
172 * stored whithin. <br>
173 * One constraint is that the strings must be convertable to "UTF-16LE"
174 * encoding and don't exceed a length of 65533 in binary representation.
175 * <br>
176 *
177 * @param tag
178 * The tag whose values the result will be filled with.
179 * @return A new extended content description object.
180 */
181 public static ExtendedContentDescription createExtendedContentDescription(
182 Tag tag) {
183 ExtendedContentDescription result = new ExtendedContentDescription();
184 assignCommonTagValues(tag, result);
185 return result;
186 }
187
188 /**
189 * This method creates a {@link Tag}and fills it with the contents of the
190 * given {@link AsfHeader}.<br>
191 *
192 * @param source
193 * The asf header which contains the information. <br>
194 * @return A Tag with all its values.
195 */
196 public static Tag createTagOf(AsfHeader source) {
197 GenericTag result = new GenericTag();
198 /*
199 * It is possible that the file contains no content description, since
200 * that some informations aren't available.
201 */
202 if (source.getContentDescription() != null) {
203 result.setArtist(source.getContentDescription().getAuthor());
204 result.setComment(source.getContentDescription().getComment());
205 result.setTitle(source.getContentDescription().getTitle());
206 }
207 /*
208 * It is possible that the file contains no extended content
209 * description. In that case some informations cannot be provided.
210 */
211 if (source.getExtendedContentDescription() != null) {
212 result.setTrack(source.getExtendedContentDescription().getTrack());
213 result.setYear(source.getExtendedContentDescription().getYear());
214 result.setGenre(source.getExtendedContentDescription().getGenre());
215 result.setAlbum(source.getExtendedContentDescription().getAlbum());
216
217 /*
218 * Now any properties, which don't belong to the common section of
219 * entagged.
220 */
221 ExtendedContentDescription extDesc = source
222 .getExtendedContentDescription();
223 Iterator it = extDesc.getDescriptors().iterator();
224 while (it.hasNext()) {
225 ContentDescriptor current = (ContentDescriptor) it.next();
226 // If common, it has been added to the result some lines upward.
227 if (!current.isCommon()) {
228 result.add(new ContentDescriptorTagField(current));
229 }
230 }
231 }
232 return result;
233 }
234} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/asf/util/Utils.java b/songdbj/entagged/audioformats/asf/util/Utils.java
new file mode 100644
index 0000000000..bafe82ea6f
--- /dev/null
+++ b/songdbj/entagged/audioformats/asf/util/Utils.java
@@ -0,0 +1,306 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.asf.util;
23
24import java.io.IOException;
25import java.io.RandomAccessFile;
26import java.io.UnsupportedEncodingException;
27import java.math.BigInteger;
28import java.util.Calendar;
29import java.util.GregorianCalendar;
30
31import entagged.audioformats.asf.data.GUID;
32
33/**
34 * Some static Methods which are used in several Classes. <br>
35 *
36 * @author Christian Laireiter
37 */
38public class Utils {
39
40 /**
41 * Stores the default line seperator of the current underlying system.
42 */
43 public final static String LINE_SEPARATOR = System
44 .getProperty("line.separator");
45
46 /**
47 * Reads chars out of <code>raf</code> until <code>chars</code> is
48 * filled.
49 *
50 * @param chars
51 * to be filled
52 * @param raf
53 * to be read
54 * @throws IOException
55 * read error, or file at end before <code>chars</code> is
56 * filled.
57 */
58 public static void fillChars(char[] chars, RandomAccessFile raf)
59 throws IOException {
60 if (chars == null) {
61 throw new IllegalArgumentException("Argument must not be null.");
62 }
63 for (int i = 0; i < chars.length; i++) {
64 chars[i] = raf.readChar();
65 }
66 }
67
68 /**
69 * This method will create a byte[] at the size of <code>byteCount</code>
70 * and insert the bytes of <code>value</code> (starting from lowset byte)
71 * into it. <br>
72 * You can easily create a Word (16-bit), DWORD (32-bit), QWORD (64 bit) out
73 * of the value, ignoring the original type of value, since java
74 * automatically performs transformations. <br>
75 * <b>Warning: </b> This method works with unsigned numbers only.
76 *
77 * @param value
78 * The value to be written into the result.
79 * @param byteCount
80 * The number of bytes the array has got.
81 * @return A byte[] with the size of <code>byteCount</code> containing the
82 * lower byte values of <code>value</code>.
83 */
84 public static byte[] getBytes(long value, int byteCount) {
85 byte[] result = new byte[byteCount];
86 for (int i = 0; i < result.length; i++) {
87 result[i] = (byte) (value & 0xFF);
88 value >>>= 8;
89 }
90 return result;
91 }
92
93 /**
94 * Since date values in asf files are given in 100 ns steps since first
95 * january of 1601 a little conversion must be done. <br>
96 * This method converts a date given in described manner to a calendar.
97 *
98 * @param fileTime
99 * Time in 100ns since 1 jan 1601
100 * @return Calendar holding the date representation.
101 */
102 public static GregorianCalendar getDateOf(BigInteger fileTime) {
103 GregorianCalendar result = new GregorianCalendar(1601, 0, 1);
104 // lose anything beyond milliseconds, because calendar can't handle
105 // less value
106 fileTime = fileTime.divide(new BigInteger("10000"));
107 BigInteger maxInt = new BigInteger(String.valueOf(Integer.MAX_VALUE));
108 while (fileTime.compareTo(maxInt) > 0) {
109 result.add(Calendar.MILLISECOND, Integer.MAX_VALUE);
110 fileTime = fileTime.subtract(maxInt);
111 }
112 result.add(Calendar.MILLISECOND, fileTime.intValue());
113 return result;
114 }
115
116 /**
117 * This method reads one byte from <code>raf</code> and creates an
118 * unsigned value of it. <br>
119 *
120 * @param raf
121 * The file to read from.
122 * @return next 7 bits as number.
123 * @throws IOException
124 * read errors.
125 */
126 public static int read7Bit(RandomAccessFile raf) throws IOException {
127 int result = raf.read();
128 return result & 127;
129 }
130
131 /**
132 * This method reads 8 bytes, interprets them as an unsigned number and
133 * creates a {@link BigInteger}
134 *
135 * @param raf
136 * Input source
137 * @return 8 bytes unsigned number
138 * @throws IOException
139 * read errors.
140 */
141 public static BigInteger readBig64(RandomAccessFile raf) throws IOException {
142 byte[] bytes = new byte[8];
143 byte[] oa = new byte[8];
144 raf.readFully(bytes);
145 for (int i = 0; i < bytes.length; i++) {
146 oa[7 - i] = bytes[i];
147 }
148 BigInteger result = new BigInteger(oa);
149 return result;
150 }
151
152 /**
153 * This method reads a UTF-16 String, which legth is given on the number of
154 * characters it consits of. <br>
155 * The filepointer of <code>raf</code> must be at the number of
156 * characters. This number contains the terminating zero character (UINT16).
157 *
158 * @param raf
159 * Input source
160 * @return String
161 * @throws IOException
162 * read errors
163 */
164 public static String readCharacterSizedString(RandomAccessFile raf)
165 throws IOException {
166 StringBuffer result = new StringBuffer();
167 int strLen = readUINT16(raf);
168 int character = raf.read();
169 character |= raf.read() << 8;
170 do {
171 if (character != 0) {
172 result.append((char) character);
173 character = raf.read();
174 character |= raf.read() << 8;
175 }
176 } while (character != 0 || (result.length() + 1) > strLen);
177 if (strLen != (result.length() + 1)) {
178 throw new IllegalStateException(
179 "Invalid Data for current interpretation");
180 }
181 return result.toString();
182 }
183
184 /**
185 * This Method reads a GUID (which is a 16 byte long sequence) from the
186 * given <code>raf</code> and creates a wrapper. <br>
187 * <b>Warning </b>: <br>
188 * There is no way of telling if a byte sequence is a guid or not. The next
189 * 16 bytes will be interpreted as a guid, whether it is or not.
190 *
191 * @param raf
192 * Input source.
193 * @return A class wrapping the guid.
194 * @throws IOException
195 * happens when the file ends before guid could be extracted.
196 */
197 public static GUID readGUID(RandomAccessFile raf) throws IOException {
198 if (raf == null) {
199 throw new IllegalArgumentException("Argument must not be null");
200 }
201 int[] binaryGuid = new int[GUID.GUID_LENGTH];
202 for (int i = 0; i < binaryGuid.length; i++) {
203 binaryGuid[i] = raf.read();
204 }
205 return new GUID(binaryGuid);
206 }
207
208 /**
209 * @see #readUINT64(RandomAccessFile)
210 * @param raf
211 * @return number
212 * @throws IOException
213 */
214 public static int readUINT16(RandomAccessFile raf) throws IOException {
215 int result = raf.read();
216 result |= raf.read() << 8;
217 return result;
218 }
219
220 /**
221 * @see #readUINT64(RandomAccessFile)
222 * @param raf
223 * @return number
224 * @throws IOException
225 */
226 public static long readUINT32(RandomAccessFile raf) throws IOException {
227 long result = 0;
228 for (int i = 0; i <= 24; i += 8)
229 result |= raf.read() << i;
230 return result;
231 }
232
233 /**
234 * Reads long as little endian.
235 *
236 * @param raf
237 * Data source
238 * @return long value
239 * @throws IOException
240 * read error, or eof is reached before long is completed
241 */
242 public static long readUINT64(RandomAccessFile raf) throws IOException {
243 long result = 0;
244 for (int i = 0; i <= 56; i += 8)
245 result |= raf.read() << i;
246 return result;
247 }
248
249 /**
250 * This method reads a UTF-16 encoded String, beginning with a 16-bit value
251 * representing the number of bytes needed. The String is terminated with as
252 * 16-bit ZERO. <br>
253 *
254 * @param raf
255 * Input source
256 * @return read String.
257 * @throws IOException
258 * read errors.
259 */
260 public static String readUTF16LEStr(RandomAccessFile raf)
261 throws IOException {
262 int strLen = readUINT16(raf);
263 byte[] buf = new byte[strLen];
264 int read = raf.read(buf);
265 if (read == buf.length) {
266 /*
267 * Check on zero termination
268 */
269 if (buf.length >= 2) {
270 if (buf[buf.length - 1] == 0 && buf[buf.length - 2] == 0) {
271 byte[] copy = new byte[buf.length - 2];
272 System.arraycopy(buf, 0, copy, 0, buf.length - 2);
273 buf = copy;
274 }
275 }
276 return new String(buf, "UTF-16LE");
277 }
278 throw new IllegalStateException(
279 "Invalid Data for current interpretation");
280 }
281
282 /**
283 * This method converts the given string into a byte[] in UTF-16LE encoding
284 * and checks whether the length doesn't exceed 65535 bytes. <br>
285 *
286 * @param value
287 * The string to check.
288 * @throws IllegalArgumentException
289 * If byte representation takes more than 65535 bytes.
290 */
291 public static void checkStringLengthNullSafe(String value)
292 throws IllegalArgumentException {
293 if (value != null) {
294 try {
295 byte[] tmp = value.getBytes("UTF-16LE");
296 if (tmp.length > 65533) {
297 throw new IllegalArgumentException(
298 "\"UTF-16LE\" representation exceeds 65535 bytes."
299 + " (Including zero term character)");
300 }
301 } catch (UnsupportedEncodingException e) {
302 e.printStackTrace();
303 }
304 }
305 }
306} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/exceptions/CannotReadException.java b/songdbj/entagged/audioformats/exceptions/CannotReadException.java
new file mode 100644
index 0000000000..1dc19d4f8e
--- /dev/null
+++ b/songdbj/entagged/audioformats/exceptions/CannotReadException.java
@@ -0,0 +1,33 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.exceptions;
23
24public class CannotReadException extends Exception {
25 private static final long serialVersionUID = 3258128055204460344L;
26 public CannotReadException( String message ) {
27 super( message );
28 }
29 public CannotReadException() {
30 super();
31 }
32}
33
diff --git a/songdbj/entagged/audioformats/exceptions/CannotWriteException.java b/songdbj/entagged/audioformats/exceptions/CannotWriteException.java
new file mode 100644
index 0000000000..b7b91d9a69
--- /dev/null
+++ b/songdbj/entagged/audioformats/exceptions/CannotWriteException.java
@@ -0,0 +1,33 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.exceptions;
23
24public class CannotWriteException extends Exception {
25 private static final long serialVersionUID = 3256719572253095479L;
26 public CannotWriteException( String message ) {
27 super( message );
28 }
29 public CannotWriteException() {
30 super();
31 }
32}
33
diff --git a/songdbj/entagged/audioformats/generic/AbstractTag.java b/songdbj/entagged/audioformats/generic/AbstractTag.java
new file mode 100644
index 0000000000..138a39ae62
--- /dev/null
+++ b/songdbj/entagged/audioformats/generic/AbstractTag.java
@@ -0,0 +1,308 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.generic;
23
24import java.util.ArrayList;
25import java.util.HashMap;
26import java.util.Iterator;
27import java.util.List;
28import java.util.Map;
29
30import entagged.audioformats.Tag;
31
32public abstract class AbstractTag implements Tag {
33
34
35 protected HashMap fields = new HashMap();
36 protected int commonNumber = 0;
37
38 public List getTitle() {
39 return get(getTitleId());
40 }
41 public List getAlbum() {
42 return get(getAlbumId());
43 }
44 public List getArtist() {
45 return get(getArtistId());
46 }
47 public List getGenre() {
48 return get(getGenreId());
49 }
50 public List getTrack() {
51 return get(getTrackId());
52 }
53 public List getYear() {
54 return get(getYearId());
55 }
56 public List getComment() {
57 return get(getCommentId());
58 }
59
60 public String getFirstTitle() {
61 List l = get(getTitleId());
62 return (l.size() != 0) ? ((TagTextField)l.get(0)).getContent() : "";
63 }
64 public String getFirstAlbum() {
65 List l = get(getAlbumId());
66 return (l.size() != 0) ? ((TagTextField)l.get(0)).getContent() : "";
67 }
68 public String getFirstArtist() {
69 List l = get(getArtistId());
70 return (l.size() != 0) ? ((TagTextField)l.get(0)).getContent() : "";
71 }
72 public String getFirstGenre() {
73 List l = get(getGenreId());
74 return (l.size() != 0) ? ((TagTextField)l.get(0)).getContent() : "";
75 }
76 public String getFirstTrack() {
77 List l = get(getTrackId());
78 return (l.size() != 0) ? ((TagTextField)l.get(0)).getContent() : "";
79 }
80 public String getFirstYear() {
81 List l = get(getYearId());
82 return (l.size() != 0) ? ((TagTextField)l.get(0)).getContent() : "";
83 }
84 public String getFirstComment() {
85 List l = get(getCommentId());
86 return (l.size() != 0) ? ((TagTextField)l.get(0)).getContent() : "";
87 }
88
89
90 public void setTitle(String s) {
91 set(createTitleField(s));
92 }
93 public void setAlbum(String s) {
94 set(createAlbumField(s));
95 }
96 public void setArtist(String s) {
97 set(createArtistField(s));
98 }
99 public void setGenre(String s) {
100 set(createGenreField(s));
101 }
102 public void setTrack(String s) {
103 set(createTrackField(s));
104 }
105 public void setYear(String s) {
106 set(createYearField(s));
107 }
108 public void setComment(String s) {
109 set(createCommentField(s));
110 }
111
112
113 public void addTitle(String s) {
114 add(createTitleField(s));
115 }
116 public void addAlbum(String s) {
117 add(createAlbumField(s));
118 }
119 public void addArtist(String s) {
120 add(createArtistField(s));
121 }
122 public void addGenre(String s) {
123 add(createGenreField(s));
124 }
125 public void addTrack(String s) {
126 add(createTrackField(s));
127 }
128 public void addYear(String s) {
129 add(createYearField(s));
130 }
131 public void addComment(String s) {
132 add(createCommentField(s));
133 }
134
135
136 public boolean hasField(String id) {
137 return get(id).size() != 0;
138 }
139 public boolean isEmpty() {
140 return fields.size() == 0;
141 }
142 public boolean hasCommonFields() {
143 return commonNumber != 0;
144 }
145
146
147 public Iterator getFields() {
148 final Iterator it = this.fields.entrySet().iterator();
149 return new Iterator() {
150 private Iterator fieldsIt;
151
152 public boolean hasNext() {
153 if(fieldsIt == null) {
154 changeIt();
155 }
156 return it.hasNext() || (fieldsIt != null && fieldsIt.hasNext());
157 }
158
159 public Object next() {
160 if(!fieldsIt.hasNext())
161 changeIt();
162
163 return fieldsIt.next();
164 }
165
166 private void changeIt() {
167 if(!it.hasNext())
168 return;
169
170 List l = (List) ((Map.Entry)it.next()).getValue();
171 fieldsIt = l.iterator();
172 }
173
174 public void remove() {
175 /* We don't want to remove */
176 }
177 };
178 }
179
180
181 public List get(String id) {
182 List list = (List) fields.get(id);
183
184 if(list == null)
185 return new ArrayList();
186
187 return list;
188 }
189 public void set(TagField field){
190 if(field == null)
191 return;
192
193 //If an empty field is passed, we delete all the previous ones
194 if(field.isEmpty()) {
195 Object removed = fields.remove(field.getId());
196 if(removed != null && field.isCommon())
197 commonNumber--;
198 return;
199 }
200
201 //If there is already an existing field with same id
202 //and both are TextFields, we update the first element
203 List l = (List) fields.get(field.getId());
204 if(l != null) {
205 TagField f = (TagField) l.get(0);
206 f.copyContent(field);
207 return;
208 }
209
210 //Else we put the new field in the fields.
211 l = new ArrayList();
212 l.add(field);
213 fields.put(field.getId(), l);
214 if(field.isCommon())
215 commonNumber++;
216 }
217 public void add(TagField field) {
218 if(field == null || field.isEmpty())
219 return;
220
221 List list = (List) fields.get(field.getId());
222
223 //There was no previous item
224 if(list == null) {
225 list = new ArrayList();
226 list.add(field);
227 fields.put(field.getId(), list);
228 if(field.isCommon())
229 commonNumber++;
230 }
231 else {
232 //We append to existing list
233 list.add(field);
234 }
235 }
236
237 public String toString() {
238 StringBuffer out = new StringBuffer();
239 out.append("Tag content:\n");
240 Iterator it = getFields();
241 while(it.hasNext()) {
242 TagField field = (TagField) it.next();
243 out.append("\t");
244 out.append(field.getId());
245 out.append(" : ");
246 out.append(field.toString());
247 out.append("\n");
248 }
249 return out.toString().substring(0,out.length()-1);
250 }
251
252 public void merge(Tag tag) {
253 //FIXME: Improve me, for the moment,
254 //it overwrites this tag with other values
255 //FIXME: TODO: an abstract method that merges particular things for each
256 //format
257 if( getTitle().size() == 0)
258 setTitle(tag.getFirstTitle());
259 if( getArtist().size() == 0 )
260 setArtist(tag.getFirstArtist());
261 if( getAlbum().size() == 0 )
262 setAlbum(tag.getFirstAlbum());
263 if( getYear().size() == 0 )
264 setYear(tag.getFirstYear());
265 if( getComment().size() == 0 )
266 setComment(tag.getFirstComment());
267 if( getTrack().size() == 0 )
268 setTrack(tag.getFirstTrack());
269 if( getGenre().size() == 0 )
270 setGenre(tag.getFirstGenre());
271 }
272
273 /*public boolean setEncoding(String enc) {
274 if(!isAllowedEncoding(enc)) {
275 return false;
276 }
277
278 Iterator it = getFields();
279 while(it.hasNext()) {
280 TagField field = (TagField) it.next();
281 if(field instanceof TagTextField) {
282 ((TagTextField)field).setEncoding(enc);
283 }
284 }
285
286 return true;
287 }*/
288 //--------------------------------
289 protected abstract String getArtistId();
290 protected abstract String getAlbumId();
291 protected abstract String getTitleId();
292 protected abstract String getTrackId();
293 protected abstract String getYearId();
294 protected abstract String getCommentId();
295 protected abstract String getGenreId();
296
297 protected abstract TagField createArtistField(String content);
298 protected abstract TagField createAlbumField(String content);
299 protected abstract TagField createTitleField(String content);
300 protected abstract TagField createTrackField(String content);
301 protected abstract TagField createYearField(String content);
302 protected abstract TagField createCommentField(String content);
303 protected abstract TagField createGenreField(String content);
304
305 protected abstract boolean isAllowedEncoding(String enc);
306 //---------------------------------------
307}
308
diff --git a/songdbj/entagged/audioformats/generic/AbstractTagCreator.java b/songdbj/entagged/audioformats/generic/AbstractTagCreator.java
new file mode 100644
index 0000000000..bdc8236c99
--- /dev/null
+++ b/songdbj/entagged/audioformats/generic/AbstractTagCreator.java
@@ -0,0 +1,66 @@
1package entagged.audioformats.generic;
2
3import java.io.UnsupportedEncodingException;
4import java.nio.ByteBuffer;
5import java.util.Iterator;
6import java.util.LinkedList;
7import java.util.List;
8
9import entagged.audioformats.Tag;
10
11public abstract class AbstractTagCreator {
12
13 public ByteBuffer convert(Tag tag) throws UnsupportedEncodingException {
14 return convert(tag, 0);
15 }
16
17 public ByteBuffer convert(Tag tag, int padding) throws UnsupportedEncodingException {
18 Tag compatibleTag = getCompatibleTag(tag);
19
20 List fields = createFields(compatibleTag);
21 int tagSize = computeTagLength(compatibleTag, fields);
22
23 ByteBuffer buf = ByteBuffer.allocate( tagSize + padding );
24 create(compatibleTag, buf, fields, tagSize, padding);
25
26 buf.rewind();
27 return buf;
28 }
29
30 protected List createFields(Tag tag) throws UnsupportedEncodingException {
31 List fields = new LinkedList();
32
33 Iterator it = tag.getFields();
34 while(it.hasNext()) {
35 TagField frame = (TagField) it.next();
36 fields.add(frame.getRawContent());
37 }
38
39 return fields;
40 }
41
42 //Compute the number of bytes the tag will be.
43 protected int computeTagLength(Tag tag, List l) throws UnsupportedEncodingException {
44 int length = getFixedTagLength(tag);
45
46 Iterator it = l.iterator();
47 while(it.hasNext())
48 length += ((byte[])it.next()).length;
49
50 return length;
51 }
52
53 public int getTagLength(Tag tag) throws UnsupportedEncodingException {
54 Tag compatibleTag = getCompatibleTag(tag);
55 List fields = createFields(compatibleTag);
56 return computeTagLength(compatibleTag, fields);
57 }
58
59 //This method is always called with a compatible tag, as returned from getCompatibleTag()
60 protected abstract int getFixedTagLength(Tag tag) throws UnsupportedEncodingException;
61
62 protected abstract Tag getCompatibleTag(Tag tag);
63
64 //This method is always called with a compatible tag, as returned from getCompatibleTag()
65 protected abstract void create(Tag tag, ByteBuffer buf, List fields, int tagSize, int padding) throws UnsupportedEncodingException;
66}
diff --git a/songdbj/entagged/audioformats/generic/AudioFileReader.java b/songdbj/entagged/audioformats/generic/AudioFileReader.java
new file mode 100644
index 0000000000..5560f29d8b
--- /dev/null
+++ b/songdbj/entagged/audioformats/generic/AudioFileReader.java
@@ -0,0 +1,126 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.generic;
23
24import java.io.File;
25import java.io.IOException;
26import java.io.RandomAccessFile;
27
28import entagged.audioformats.AudioFile;
29import entagged.audioformats.Tag;
30import entagged.audioformats.EncodingInfo;
31import entagged.audioformats.exceptions.CannotReadException;
32
33/*
34 * This abstract class is the skeleton for tag readers. It handles the creation/closing of
35 * the randomaccessfile objects and then call the subclass method getEncodingInfo and getTag.
36 * These two method have to be implemented in te subclass.
37 *
38 *@author Raphael Slinckx
39 *@version $Id$
40 *@since v0.02
41 */
42public abstract class AudioFileReader {
43
44 /*
45 * Returns the encoding info object associated wih the current File.
46 * The subclass can assume the RAF pointer is at the first byte of the file.
47 * The RandomAccessFile must be kept open after this function, but can point
48 * at any offset in the file.
49 *
50 * @param raf The RandomAccessFile associtaed with the current file
51 * @exception IOException is thrown when the RandomAccessFile operations throw it (you should never throw them manually)
52 * @exception CannotReadException when an error occured during the parsing of the encoding infos
53 */
54 protected abstract EncodingInfo getEncodingInfo( RandomAccessFile raf ) throws CannotReadException, IOException;
55
56 /*
57 * Same as above but returns the Tag contained in the file, or a new one.
58 *
59 * @param raf The RandomAccessFile associted with the current file
60 * @exception IOException is thrown when the RandomAccessFile operations throw it (you should never throw them manually)
61 * @exception CannotReadException when an error occured during the parsing of the tag
62 */
63 protected abstract Tag getTag( RandomAccessFile raf ) throws CannotReadException, IOException;
64
65 /*
66 * Reads the given file, and return an AudioFile object containing the Tag
67 * and the encoding infos present in the file. If the file has no tag, an
68 * empty one is returned. If the encodinginfo is not valid , an error is thrown.
69 *
70 * @param f The file to read
71 * @exception CannotReadException If anything went bad during the read of this file
72 */
73 public AudioFile read(File f) throws CannotReadException {
74 if (!f.canRead())
75 throw new CannotReadException("Can't read file \""+f.getAbsolutePath()+"\"");
76
77 if(f.length() <= 150)
78 throw new CannotReadException("Less than 150 byte \""+f.getAbsolutePath()+"\"");
79
80 RandomAccessFile raf = null;
81 try{
82 raf = new RandomAccessFile( f, "r" );
83 return read( f, raf );
84 } catch ( Exception e ) {
85 throw new CannotReadException("\""+f+"\" :"+e);
86 }
87 finally {
88 try{
89 if(raf != null)
90 raf.close();
91 }catch(Exception ex){
92 System.err.println("\""+f+"\" :"+ex);
93 }
94 }
95 }
96
97 /*
98 * Reads the given file, and return an AudioFile object containing the Tag
99 * and the encoding infos present in the file. If the file has no tag, an
100 * empty one is returned. If the encodinginfo is not valid , an error is thrown.
101 *
102 * @param f The RandomAccessFile to read
103 * @exception CannotReadException If anything went bad during the read of this file
104 */
105 public AudioFile read(File f, RandomAccessFile raf) throws CannotReadException {
106 try{
107 raf.seek( 0 );
108
109 EncodingInfo info = getEncodingInfo(raf);
110
111 Tag tag;
112 try {
113 raf.seek( 0 );
114 tag = getTag(raf);
115 } catch (CannotReadException e) {
116 System.err.println(e.getMessage());
117 tag = new GenericTag();
118 }
119
120 return new AudioFile(f, info, tag);
121
122 } catch ( Exception e ) {
123 throw new CannotReadException("\""+f+"\" :"+e);
124 }
125 }
126}
diff --git a/songdbj/entagged/audioformats/generic/GenericTag.java b/songdbj/entagged/audioformats/generic/GenericTag.java
new file mode 100644
index 0000000000..fb2ff43f37
--- /dev/null
+++ b/songdbj/entagged/audioformats/generic/GenericTag.java
@@ -0,0 +1,133 @@
1package entagged.audioformats.generic;
2
3
4public class GenericTag extends AbstractTag {
5 private final static String[] keys =
6 {
7 "ARTIST",
8 "ALBUM",
9 "TITLE",
10 "TRACK",
11 "YEAR",
12 "GENRE",
13 "COMMENT",
14 };
15
16 public static final int ARTIST = 0;
17 public static final int ALBUM = 1;
18 public static final int TITLE = 2;
19 public static final int TRACK = 3;
20 public static final int YEAR = 4;
21 public static final int GENRE = 5;
22 public static final int COMMENT = 6;
23
24 protected String getArtistId() {
25 return keys[ARTIST];
26 }
27 protected String getAlbumId() {
28 return keys[ALBUM];
29 }
30 protected String getTitleId() {
31 return keys[TITLE];
32 }
33 protected String getTrackId() {
34 return keys[TRACK];
35 }
36 protected String getYearId() {
37 return keys[YEAR];
38 }
39 protected String getCommentId() {
40 return keys[COMMENT];
41 }
42 protected String getGenreId() {
43 return keys[GENRE];
44 }
45
46 protected TagField createArtistField(String content) {
47 return new GenericTagTextField(keys[ARTIST], content);
48 }
49 protected TagField createAlbumField(String content) {
50 return new GenericTagTextField(keys[ALBUM], content);
51 }
52 protected TagField createTitleField(String content) {
53 return new GenericTagTextField(keys[TITLE], content);
54 }
55 protected TagField createTrackField(String content) {
56 return new GenericTagTextField(keys[TRACK], content);
57 }
58 protected TagField createYearField(String content) {
59 return new GenericTagTextField(keys[YEAR], content);
60 }
61 protected TagField createCommentField(String content) {
62 return new GenericTagTextField(keys[COMMENT], content);
63 }
64 protected TagField createGenreField(String content) {
65 return new GenericTagTextField(keys[GENRE], content);
66 }
67
68 protected boolean isAllowedEncoding(String enc) {
69 return true;
70 }
71
72 private class GenericTagTextField implements TagTextField {
73
74 private String id;
75 private String content;
76
77 public GenericTagTextField(String id, String content) {
78 this.id = id;
79 this.content = content;
80 }
81
82 public String getContent() {
83 return this.content;
84 }
85
86 public String getEncoding() {
87 return "ISO-8859-1";
88 }
89
90 public void setContent(String s) {
91 this.content = s;
92 }
93
94 public void setEncoding(String s) {
95 /* Not allowed */
96 }
97
98 public String getId() {
99 return id;
100 }
101
102 public byte[] getRawContent() {
103 /* FIXME: What to do here ? not supported */
104 return new byte[] {};
105 }
106
107 public boolean isBinary() {
108 return false;
109 }
110
111 public void isBinary(boolean b) {
112 /* not supported */
113 }
114
115 public boolean isCommon() {
116 return true;
117 }
118
119 public boolean isEmpty() {
120 return this.content.equals("");
121 }
122
123 public String toString() {
124 return getId() + " : " + getContent();
125 }
126
127 public void copyContent(TagField field) {
128 if(field instanceof TagTextField) {
129 this.content = ((TagTextField)field).getContent();
130 }
131 }
132 }
133}
diff --git a/songdbj/entagged/audioformats/generic/OldTag.java b/songdbj/entagged/audioformats/generic/OldTag.java
new file mode 100644
index 0000000000..a4f19cbbc9
--- /dev/null
+++ b/songdbj/entagged/audioformats/generic/OldTag.java
@@ -0,0 +1,382 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.generic;
23
24import java.util.*;
25
26import entagged.audioformats.Tag;
27
28/**
29 * <p>This class stores all the meta-data (artist, album, ..) contained in an AudioFile.</p>
30 * <p>All the <code>set</code> operation are not "real-time", they only apply to this object. To commit the modification, either the <code>AudioFile</code>'s <code>commit()</code> or the <code>AudioFileIO.write(AudioFile)</code> have to be called</p>
31 * <p>There are two types of fields contained in a <code>Tag</code>. The most commonly used (the <em>common fields</em>) are accessible through get/set methods, like the artist, tha album, the track number, etc.</p>
32 * <p>Each tag format has then <em>specific fields</em> (eg. graphics, urls, etc) that do not exist in the other formats, or that cannot be mapped to <em>common fields</em></p>
33 * <p>To retreive the content of these <em>specific fields</em>, the <code>getSpecificields()</code> can be called giving the names of the <em>specific fields</em> stored in this tag</p>
34 * <p>This ensures that all the old meta-data contained in a tag read from <code>AudioFileIO</code> is kept and rewritten when the tag is updated</p>
35 *
36 *@author Raphael Slinckx
37 *@version $Id$
38 *@since v0.01
39 *@see AudioFile
40 */
41public class OldTag {
42 /**
43 * This final field contains all the tags that id3v1 supports. The list has
44 * the same order as the id3v1 genres. To be perfectly compatible (with id3v1)
45 * the genre field should match one of these genre (case ignored). You can also use
46 * this list to present a list of basic (modifiable) possible choices for the genre field.
47 */
48 public static final String[] DEFAULT_GENRES = {"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz",
49 "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative",
50 "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion",
51 "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock",
52 "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
53 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
54 "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave",
55 "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro",
56 "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival",
57 "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
58 "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata",
59 "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad",
60 "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall"};
61
62
63 //Contains all the fields found in a tag
64 protected Hashtable fields;
65
66 /**
67 * <p>Creates a new empty tag, all the common fields are initialized to the empty string, and no specific fields exists.</p>
68 */
69 public OldTag() {
70 fields = new Hashtable();
71 fields.put("TITLE" ,"");
72 fields.put("ALBUM" ,"");
73 fields.put("ARTIST" ,"");
74 fields.put("GENRE" ,"");
75 fields.put("TRACK" ,"");
76 fields.put("YEAR" ,"");
77 fields.put("COMMENT","");
78 }
79
80 /**
81 * <p>Returns the title of this song, eg: "Stairway to Heaven".</p>
82 * <p>If there wasn't such a field in the AudioFile, an empty String is returned</p>
83 *
84 *@return Returns the title of this song
85 */
86 public String getTitle() {
87 return (String) fields.get("TITLE");
88 }
89
90 /**
91 * <p>Returns the album of this song, eg: "Led Zeppelin IV".</p>
92 * <p>If there wasn't such a field in the AudioFile, an empty String is returned</p>
93 *
94 *@return Returns the album of this song
95 */
96 public String getAlbum() {
97 return (String) fields.get("ALBUM");
98 }
99
100 /**
101 * <p>Returns the artist of this song, eg: "Led Zeppelin".</p>
102 * <p>If there wasn't such a field in the AudioFile, an empty String is returned</p>
103 *
104 *@return Returns the artist of this song
105 */
106 public String getArtist() {
107 return (String) fields.get("ARTIST");
108 }
109
110 /**
111 * <p>Returns the genre of this song, eg: "Classic Rock".</p>
112 * <p>If there wasn't such a field in the AudioFile, an empty String is returned</p>
113 *
114 *@return Returns the genre of this song
115 */
116 public String getGenre() {
117 return (String) fields.get("GENRE");
118 }
119
120 /**
121 * <p>Returns the track number of this song.</p>
122 * <p>The String can be anything, so don't expect a simple number, it could be "10" but also "10 / 15"</p>
123 * <p>If there wasn't such a field in the AudioFile, an empty String is returned</p>
124 *
125 *@return Returns the track number of this song
126 */
127 public String getTrack() {
128 return (String) fields.get("TRACK");
129 }
130
131 /**
132 * <p>Returns the date of this song.</p>
133 * <p>Most of the time the year of release of the album eg: "1970", but this can also be an arbitrary string like "19 december 1934"</p>
134 * <p>If there wasn't such a field in the AudioFile, an empty String is returned</p>
135 *
136 *@return Returns the date of this song
137 */
138 public String getYear() {
139 return (String) fields.get("YEAR");
140 }
141
142 /**
143 * <p>Returns the comment associated with this song, eg: "Recorded live at the Royal Albert Hall".</p>
144 * <p>Some tag format allow multi-line comments, line are separated with "\n" strings ("\\n" in java not "\n"). That means the String returned may have to be parsed to transform those strings in newline characters ("\n" in java)</p>
145 * <p>If there wasn't such a field in the AudioFile, an empty String is returned</p>
146 *
147 *@return Returns the comment associated with this song
148 *@todo Parse the returned string to replace \\n by \n for multiline comments
149 */
150 public String getComment() {
151 return (String) fields.get("COMMENT");
152 }
153
154 /**
155 * <p>Sets the title for this song, replacing the previous one.</p>
156 * <p><code>s</code> can be an arbitrary string, but keep in mind that some tag formats have limited space to store informations, if <code>s</code> is too long, it will be cut at the maximum length allowed by the tag format</p>
157 * <p>If a null string is passed, it is converted to an empty String</p>
158 *
159 *@param s the new title of this song
160 */
161 public void setTitle(String s) {
162 if(s == null)
163 fields.put("TITLE","");
164 else
165 fields.put("TITLE",s);
166 }
167
168 /**
169 * <p>Sets the new album for this song, replacing the previous one.</p>
170 * <p><code>s</code> can be an arbitrary string, but keep in mind that some tag formats have limited space to store informations, if <code>s</code> is too long, it will be cut at the maximum length allowed by the tag format</p>
171 * <p>If a null string is passed, it is converted to an empty String</p>
172 *
173 *@param s the new album for this song
174 */
175 public void setAlbum(String s) {
176 if(s == null)
177 fields.put("ALBUM","");
178 else
179 fields.put("ALBUM",s);
180 }
181
182 /**
183 * <p>Sets the new artist for this song, replacing the previous one.</p>
184 * <p><code>s</code> can be an arbitrary string, but keep in mind that some tag formats have limited space to store informations, if <code>s</code> is too long, it will be cut at the maximum length allowed by the tag format</p>
185 * <p>If a null string is passed, it is converted to an empty String</p>
186 *
187 *@param s the new artist for this song
188 */
189 public void setArtist(String s) {
190 if(s == null)
191 fields.put("ARTIST","");
192 else
193 fields.put("ARTIST",s);
194 }
195
196 /**
197 * <p>Sets the new genre for this song, replacing the previous one.</p>
198 * <p>Some formats does not support an arbitrary string as genre and use a predefined list of genres, with an index. If this is the case, the given genre will be matched against a predefined list, if a correspondance is found, that index is used, if not, a "no genre" or equivalent will be used instead</p>
199 * <p><code>s</code> can be an arbitrary string, but keep in mind that some tag formats have limited space to store informations, if <code>s</code> is too long, it will be cut at the maximum length allowed by the tag format</p>
200 * <p>If a null string is passed, it is converted to an empty String</p>
201 *
202 *@param s the new genre for this song
203 */
204 public void setGenre(String s) {
205 if(s == null)
206 fields.put("GENRE","");
207 else
208 fields.put("GENRE",s);
209 }
210
211 /**
212 * <p>Sets the new track number for this song, replacing the previous one.</p>
213 * <p>Some formats use a single byte track encoding, allowing tracks to be only a number from 0 to 255. If this is the case, and the track number is not a simple number (like "19/30"), the track number is set to 0</p>
214 * <p><code>s</code> can be an arbitrary string, but keep in mind that some tag formats have limited space to store informations, if <code>s</code> is too long, it will be cut at the maximum length allowed by the tag format</p>
215 * <p>If a null string is passed, it is converted to an empty String</p>
216 *
217 *@param s the new track number for this song
218 */
219 public void setTrack(String s) {
220 if(s == null)
221 fields.put("TRACK","");
222 else
223 fields.put("TRACK",s);
224 }
225
226 /**
227 * <p>Sets the new date for this song, replacing the previous one.</p>
228 * <p><code>s</code> can be an arbitrary string, but keep in mind that some tag formats have limited space to store informations, if <code>s</code> is too long, it will be cut at the maximum length allowed by the tag format</p>
229 * <p>If a null string is passed, it is converted to an empty String</p>
230 *
231 *@param s the new date for this song
232 */
233 public void setYear(String s) {
234 if(s == null)
235 fields.put("YEAR","");
236 else
237 fields.put("YEAR",s);
238 }
239
240 /**
241 * <p>Sets the new comment of this song, replacing the previous one.</p>
242 * <p>Some tag allow multi-line formats, using the "\n" string ("\\n" in java) but not the newline character ("\n" in java)</p>
243 * <p><code>s</code> can be an arbitrary string, but keep in mind that some tag formats have limited space to store informations, if <code>s</code> is too long, it will be cut at the maximum length allowed by the tag format</p>
244 * <p>If a null string is passed, it is converted to an empty String</p>
245 *
246 *@param s the new comment for this song
247 *@todo Parse the given string to replace \n by \\n for multiline comments
248 */
249 public void setComment(String s) {
250 if(s == null)
251 fields.put("COMMENT","");
252 else
253 fields.put("COMMENT",s);
254 }
255
256
257 /**
258 * <p>This creates an iterator over the specific fields for this tag. Specific fields are tag-format specific fields (other than artist, album, etc).</p>
259 * <p>If this tag was created by <code>new Tag()</code>, the iterator will be empty</p>
260 * <p>To retreive the value associated to a specific field use the <code>getSpecificField(String)</code> method in this class</p>
261 * <p>Example: an ogg file can contain an arbitrary number of arbitrary fields, so a field like MYCUSTOMFIELD cannot be mapped to artist, album, or other common field, it is instead stored as a specific field that can be retreived using this iterator</p>
262 *@return an iterator over the specific fields of this tag
263 */
264 public Iterator getSpecificFields() {
265 //Those fileds are created by subclasses of this class
266 //And begin with a "-", the iterator contains the fields without the leading "-"
267 List l = new LinkedList();
268 Enumeration en = fields.keys();
269 while(en.hasMoreElements()) {
270 String key = (String) en.nextElement();
271 if( key.startsWith("-") )
272 l.add(key.substring(1));
273 }
274
275 return l.iterator();
276 }
277
278 /**
279 * <p>Returns the specific field's content.</p>
280 * <p>if <code>s</code> is not a valid specific field, the empty string is returned</p>
281 * <p>Valid specific fields are returned by the iterator created by <code>getSpecificFields()</code> method</p>
282 * <p>Note that some specific fields can have binary value (not a human readable string), the binary data can be obtained back using the <code>getBytes()</code> method on the String</p>
283 *
284 *@param s the specific field to retreive
285 *@return the value associated to this specific field, or the empty string if the field wasn't valid
286 *@todo binary strings ??
287 */
288 public String getSpecificField(String s) {
289 //Return the value associated with a specific field
290 //User must ensure that the field actually exists, otherwise an empty string will be returned !
291 //The given field must not contain the leading "-", it is appended here !
292 String content = (String) fields.get("-"+s);
293 if(content == null)
294 return "";
295 return content;
296 }
297
298
299 /**
300 * <p>Checks wether all the common fields (artist, genre, ..) are empty, that is: contains the empty string or only spaces.</p>
301 * <p>Specific fields can exist even if this returns true, use the <code>isSpecificEmpty()</code> to check if the specific fields are also empty</p>
302 *
303 *@return a boolean indicating if the common fields of this tag are empty or not
304 */
305 public boolean isEmpty() {
306 Enumeration en = fields.keys();
307 while(en.hasMoreElements()) {
308 String key = (String) en.nextElement();
309 String val = (String) fields.get(key);
310 if( !key.startsWith("-") && !val.trim().equals("") )
311 return false;
312 }
313
314 return true;
315 }
316
317
318 /**
319 * <p>Checks wether all the specific fields (other than artist, genre, ..) are empty, that is: contains the empty string or only spaces.</p>
320 * <p>Common fields can exist even if this returns true, use the <code>isEmpty()</code> to check if the common fields are also empty</p>
321 *
322 *@return a boolean indicating if the specific fields of this tag are empty or not
323 */
324 public boolean isSpecificEmpty() {
325 Enumeration en = fields.keys();
326 while(en.hasMoreElements()) {
327 String key = (String) en.nextElement();
328 String val = (String) fields.get(key);
329 if( key.startsWith("-") && !val.trim().equals("") )
330 return false;
331 }
332
333 return true;
334 }
335
336 /*
337 * Merge the content of the given tag with the content of this tag.
338 * It keeps this tag fields, but if one field is empty, it looks for a
339 * non-empty value in the given tag and place it's value in this tag.
340 * Note that it only looks in the "common" fields (artist, album).
341 *
342 * @param tag The tag to use if one of this tag's field is empty.
343 */
344 /*public void merge(Tag tag) {
345 if( getTitle().trim().equals("") )
346 setTitle(tag.getTitle());
347 if( getArtist().trim().equals("") )
348 setArtist(tag.getArtist());
349 if( getAlbum().trim().equals("") )
350 setAlbum(tag.getAlbum());
351 if( getYear().trim().equals("") )
352 setYear(tag.getYear());
353 if( getComment().trim().equals("") )
354 setComment(tag.getComment());
355 if( getTrack().trim().equals("") )
356 setTrack(tag.getTrack());
357 if( getGenre().trim().equals("") )
358 setGenre(tag.getGenre());
359 }*/
360
361 /**
362 * <p>Returns a multi-line string showing all the meta-data of this tag (the common fields, and any specific field).</p>
363 * <p>Specific fields are denoted with a "-" appended to the field name</p>
364 *
365 *@return the contents of this tag
366 */
367 public String toString() {
368 StringBuffer out = new StringBuffer(50);
369 out.append("Tag content:\n");
370 Enumeration en = fields.keys();
371 while(en.hasMoreElements()) {
372 Object field = en.nextElement();
373 Object content = fields.get(field);
374 out.append("\t");
375 out.append(field);
376 out.append(" : ");
377 out.append(content);
378 out.append("\n");
379 }
380 return out.toString().substring(0,out.length()-1);
381 }
382}
diff --git a/songdbj/entagged/audioformats/generic/TagField.java b/songdbj/entagged/audioformats/generic/TagField.java
new file mode 100644
index 0000000000..435bec8b19
--- /dev/null
+++ b/songdbj/entagged/audioformats/generic/TagField.java
@@ -0,0 +1,43 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.generic;
23
24import java.io.UnsupportedEncodingException;
25
26public interface TagField {
27
28 public String getId();
29
30 public byte[] getRawContent() throws UnsupportedEncodingException;
31
32 public boolean isBinary();
33
34 public void isBinary(boolean b);
35
36 public boolean isCommon();
37
38 public boolean isEmpty();
39
40 public String toString();
41
42 public void copyContent(TagField field);
43} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/generic/TagTextField.java b/songdbj/entagged/audioformats/generic/TagTextField.java
new file mode 100644
index 0000000000..b54f8c96ca
--- /dev/null
+++ b/songdbj/entagged/audioformats/generic/TagTextField.java
@@ -0,0 +1,33 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.generic;
23
24public interface TagTextField extends TagField {
25
26 public String getContent();
27
28 public String getEncoding();
29
30 public void setContent(String s);
31
32 public void setEncoding(String s);
33} \ No newline at end of file
diff --git a/songdbj/entagged/audioformats/generic/Utils.java b/songdbj/entagged/audioformats/generic/Utils.java
new file mode 100644
index 0000000000..dd2ccd06db
--- /dev/null
+++ b/songdbj/entagged/audioformats/generic/Utils.java
@@ -0,0 +1,95 @@
1/*
2 * ******************************************************************** **
3 * Copyright notice **
4 * ** **
5 * (c) 2003 Entagged Developpement Team **
6 * http://www.sourceforge.net/projects/entagged **
7 * ** **
8 * All rights reserved **
9 * ** **
10 * This script is part of the Entagged project. The Entagged **
11 * project is free software; you can redistribute it and/or modify **
12 * it under the terms of the GNU General Public License as published by **
13 * the Free Software Foundation; either version 2 of the License, or **
14 * (at your option) any later version. **
15 * ** **
16 * The GNU General Public License can be found at **
17 * http://www.gnu.org/copyleft/gpl.html. **
18 * ** **
19 * This copyright notice MUST APPEAR in all copies of the file! **
20 * ********************************************************************
21 */
22package entagged.audioformats.generic;
23
24import java.io.*;
25
26/*
27 * Contains various frequently used static functions in the different tag formats
28 *
29 *@author Raphael Slinckx
30 *@version $Id$
31 *@since v0.02
32 */
33public class Utils {
34 /*
35 * Returns the extension of the given file.
36 * The extension is empty if there is no extension
37 * The extension is the string after the last "."
38 *
39 * @param f The file whose extension is requested
40 * @return The extension of the given file
41 */
42 public static String getExtension(File f) {
43 String name = f.getName().toLowerCase();
44 int i = name.lastIndexOf( "." );
45 if(i == -1)
46 return "";
47
48 return name.substring( i + 1 );
49 }
50
51 /*
52 * Tries to convert a string into an UTF8 array of bytes
53 * If the conversion fails, return the string converted with the default
54 * encoding.
55 *
56 * @param s The string to convert
57 * @return The byte array representation of this string in UTF8 encoding
58 */
59 public static byte[] getUTF8Bytes(String s) throws UnsupportedEncodingException {
60 return s.getBytes("UTF-8");
61 }
62
63 /*
64 * Computes a number composed of (end-start) bytes in the b array.
65 *
66 * @param b The byte array
67 * @param start The starting offset in b (b[offset]). The less significant byte
68 * @param end The end index (included) in b (b[end]). The most significant byte
69 * @return a long number represented by the byte sequence.
70 */
71 public static long getLongNumber(byte[] b, int start, int end) {
72 long number = 0;
73 for(int i = 0; i<(end-start+1); i++) {
74 number += ((b[start+i]&0xFF) << i*8);
75 }
76
77 return number;
78 }
79
80 /*
81 * same as above, but returns an int instead of a long
82 * @param b The byte array
83 * @param start The starting offset in b (b[offset]). The less significant byte
84 * @param end The end index (included) in b (b[end]). The most significant byte
85 * @return a int number represented by the byte sequence.
86 */
87 public static int getNumber( byte[] b, int start, int end) {
88 int number = 0;
89 for(int i = 0; i<(end-start+1); i++) {
90 number += ((b[start+i]&0xFF) << i*8);
91 }
92
93 return number;
94 }
95}
diff --git a/songdbj/javazoom/jl/converter/Converter.java b/songdbj/javazoom/jl/converter/Converter.java
new file mode 100644
index 0000000000..845082e626
--- /dev/null
+++ b/songdbj/javazoom/jl/converter/Converter.java
@@ -0,0 +1,411 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Original verion. mdm@techie.com.
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.converter;
22
23import java.io.BufferedInputStream;
24import java.io.File;
25import java.io.FileInputStream;
26import java.io.IOException;
27import java.io.InputStream;
28import java.io.PrintWriter;
29
30import javazoom.jl.decoder.Bitstream;
31import javazoom.jl.decoder.Decoder;
32import javazoom.jl.decoder.Header;
33import javazoom.jl.decoder.JavaLayerException;
34import javazoom.jl.decoder.Obuffer;
35
36/**
37 * The <code>Converter</code> class implements the conversion of
38 * an MPEG audio file to a .WAV file. To convert an MPEG audio stream,
39 * just create an instance of this class and call the convert()
40 * method, passing in the names of the input and output files. You can
41 * pass in optional <code>ProgressListener</code> and
42 * <code>Decoder.Params</code> objects also to customize the conversion.
43 *
44 * @author MDM 12/12/99
45 * @since 0.0.7
46 */
47public class Converter
48{
49 /**
50 * Creates a new converter instance.
51 */
52 public Converter()
53 {
54 }
55
56 public synchronized void convert(String sourceName, String destName)
57 throws JavaLayerException
58 {
59 convert(sourceName, destName, null, null);
60 }
61
62 public synchronized void convert(String sourceName, String destName,
63 ProgressListener progressListener)
64 throws JavaLayerException
65 {
66 convert(sourceName, destName, progressListener, null);
67 }
68
69
70 public void convert(String sourceName, String destName,
71 ProgressListener progressListener, Decoder.Params decoderParams)
72 throws JavaLayerException
73 {
74 if (destName.length()==0)
75 destName = null;
76 try {
77 InputStream in = openInput(sourceName);
78 convert(in, destName, progressListener, decoderParams);
79 in.close();
80 } catch(IOException ioe) {
81 throw new JavaLayerException(ioe.getLocalizedMessage(), ioe);
82 }
83 }
84
85 public synchronized void convert(InputStream sourceStream, String destName,
86 ProgressListener progressListener, Decoder.Params decoderParams)
87 throws JavaLayerException
88 {
89 if (progressListener==null)
90 progressListener = PrintWriterProgressListener.newStdOut(
91 PrintWriterProgressListener.NO_DETAIL);
92 try {
93 if (!(sourceStream instanceof BufferedInputStream))
94 sourceStream = new BufferedInputStream(sourceStream);
95 int frameCount = -1;
96 if (sourceStream.markSupported()) {
97 sourceStream.mark(-1);
98 frameCount = countFrames(sourceStream);
99 sourceStream.reset();
100 }
101 progressListener.converterUpdate(ProgressListener.UPDATE_FRAME_COUNT, frameCount, 0);
102
103
104 Obuffer output = null;
105 Decoder decoder = new Decoder(decoderParams);
106 Bitstream stream = new Bitstream(sourceStream);
107
108 if (frameCount==-1)
109 frameCount = Integer.MAX_VALUE;
110
111 int frame = 0;
112 long startTime = System.currentTimeMillis();
113
114 try
115 {
116 for (; frame<frameCount; frame++)
117 {
118 try
119 {
120 Header header = stream.readFrame();
121 if (header==null)
122 break;
123
124 progressListener.readFrame(frame, header);
125
126 if (output==null)
127 {
128 // REVIEW: Incorrect functionality.
129 // the decoder should provide decoded
130 // frequency and channels output as it may differ from
131 // the source (e.g. when downmixing stereo to mono.)
132 int channels = (header.mode()==Header.SINGLE_CHANNEL) ? 1 : 2;
133 int freq = header.frequency();
134 output = new WaveFileObuffer(channels, freq, destName);
135 decoder.setOutputBuffer(output);
136 }
137
138 Obuffer decoderOutput = decoder.decodeFrame(header, stream);
139
140 // REVIEW: the way the output buffer is set
141 // on the decoder is a bit dodgy. Even though
142 // this exception should never happen, we test to be sure.
143 if (decoderOutput!=output)
144 throw new InternalError("Output buffers are different.");
145
146
147 progressListener.decodedFrame(frame, header, output);
148
149 stream.closeFrame();
150
151 }
152 catch (Exception ex)
153 {
154 boolean stop = !progressListener.converterException(ex);
155
156 if (stop)
157 {
158 throw new JavaLayerException(ex.getLocalizedMessage(), ex);
159 }
160 }
161 }
162
163 }
164 finally
165 {
166
167 if (output!=null)
168 output.close();
169 }
170
171 int time = (int)(System.currentTimeMillis()-startTime);
172 progressListener.converterUpdate(ProgressListener.UPDATE_CONVERT_COMPLETE,
173 time, frame);
174 }
175 catch (IOException ex)
176 {
177 throw new JavaLayerException(ex.getLocalizedMessage(), ex);
178 }
179 }
180
181
182 protected int countFrames(InputStream in)
183 {
184 return -1;
185 }
186
187
188 protected InputStream openInput(String fileName)
189 throws IOException
190 {
191 // ensure name is abstract path name
192 File file = new File(fileName);
193 InputStream fileIn = new FileInputStream(file);
194 BufferedInputStream bufIn = new BufferedInputStream(fileIn);
195
196 return bufIn;
197 }
198
199
200 /**
201 * This interface is used by the Converter to provide
202 * notification of tasks being carried out by the converter,
203 * and to provide new information as it becomes available.
204 */
205
206 static public interface ProgressListener
207 {
208 public static final int UPDATE_FRAME_COUNT = 1;
209
210 /**
211 * Conversion is complete. Param1 contains the time
212 * to convert in milliseconds. Param2 contains the number
213 * of MPEG audio frames converted.
214 */
215 public static final int UPDATE_CONVERT_COMPLETE = 2;
216
217
218 /**
219 * Notifies the listener that new information is available.
220 *
221 * @param updateID Code indicating the information that has been
222 * updated.
223 *
224 * @param param1 Parameter whose value depends upon the update code.
225 * @param param2 Parameter whose value depends upon the update code.
226 *
227 * The <code>updateID</code> parameter can take these values:
228 *
229 * UPDATE_FRAME_COUNT: param1 is the frame count, or -1 if not known.
230 * UPDATE_CONVERT_COMPLETE: param1 is the conversion time, param2
231 * is the number of frames converted.
232 */
233 public void converterUpdate(int updateID, int param1, int param2);
234
235 /**
236 * If the converter wishes to make a first pass over the
237 * audio frames, this is called as each frame is parsed.
238 */
239 public void parsedFrame(int frameNo, Header header);
240
241 /**
242 * This method is called after each frame has been read,
243 * but before it has been decoded.
244 *
245 * @param frameNo The 0-based sequence number of the frame.
246 * @param header The Header rerpesenting the frame just read.
247 */
248 public void readFrame(int frameNo, Header header);
249
250 /**
251 * This method is called after a frame has been decoded.
252 *
253 * @param frameNo The 0-based sequence number of the frame.
254 * @param header The Header rerpesenting the frame just read.
255 * @param o The Obuffer the deocded data was written to.
256 */
257 public void decodedFrame(int frameNo, Header header, Obuffer o);
258
259 /**
260 * Called when an exception is thrown during while converting
261 * a frame.
262 *
263 * @param t The <code>Throwable</code> instance that
264 * was thrown.
265 *
266 * @return <code>true</code> to continue processing, or false
267 * to abort conversion.
268 *
269 * If this method returns <code>false</code>, the exception
270 * is propagated to the caller of the convert() method. If
271 * <code>true</code> is returned, the exception is silently
272 * ignored and the converter moves onto the next frame.
273 */
274 public boolean converterException(Throwable t);
275
276 }
277
278
279 /**
280 * Implementation of <code>ProgressListener</code> that writes
281 * notification text to a <code>PrintWriter</code>.
282 */
283 // REVIEW: i18n of text and order required.
284 static public class PrintWriterProgressListener implements ProgressListener
285 {
286 static public final int NO_DETAIL = 0;
287
288 /**
289 * Level of detail typically expected of expert
290 * users.
291 */
292 static public final int EXPERT_DETAIL = 1;
293
294 /**
295 * Verbose detail.
296 */
297 static public final int VERBOSE_DETAIL = 2;
298
299 /**
300 * Debug detail. All frame read notifications are shown.
301 */
302 static public final int DEBUG_DETAIL = 7;
303
304 static public final int MAX_DETAIL = 10;
305
306 private PrintWriter pw;
307
308 private int detailLevel;
309
310 static public PrintWriterProgressListener newStdOut(int detail)
311 {
312 return new PrintWriterProgressListener(
313 new PrintWriter(System.out, true), detail);
314 }
315
316 public PrintWriterProgressListener(PrintWriter writer, int detailLevel)
317 {
318 this.pw = writer;
319 this.detailLevel = detailLevel;
320 }
321
322
323 public boolean isDetail(int detail)
324 {
325 return (this.detailLevel >= detail);
326 }
327
328 public void converterUpdate(int updateID, int param1, int param2)
329 {
330 if (isDetail(VERBOSE_DETAIL))
331 {
332 switch (updateID)
333 {
334 case UPDATE_CONVERT_COMPLETE:
335 // catch divide by zero errors.
336 if (param2==0)
337 param2 = 1;
338
339 pw.println();
340 pw.println("Converted "+param2+" frames in "+param1+" ms ("+
341 (param1/param2)+" ms per frame.)");
342 }
343 }
344 }
345
346 public void parsedFrame(int frameNo, Header header)
347 {
348 if ((frameNo==0) && isDetail(VERBOSE_DETAIL))
349 {
350 String headerString = header.toString();
351 pw.println("File is a "+headerString);
352 }
353 else if (isDetail(MAX_DETAIL))
354 {
355 String headerString = header.toString();
356 pw.println("Prased frame "+frameNo+": "+headerString);
357 }
358 }
359
360 public void readFrame(int frameNo, Header header)
361 {
362 if ((frameNo==0) && isDetail(VERBOSE_DETAIL))
363 {
364 String headerString = header.toString();
365 pw.println("File is a "+headerString);
366 }
367 else if (isDetail(MAX_DETAIL))
368 {
369 String headerString = header.toString();
370 pw.println("Read frame "+frameNo+": "+headerString);
371 }
372 }
373
374 public void decodedFrame(int frameNo, Header header, Obuffer o)
375 {
376 if (isDetail(MAX_DETAIL))
377 {
378 String headerString = header.toString();
379 pw.println("Decoded frame "+frameNo+": "+headerString);
380 pw.println("Output: "+o);
381 }
382 else if (isDetail(VERBOSE_DETAIL))
383 {
384 if (frameNo==0)
385 {
386 pw.print("Converting.");
387 pw.flush();
388 }
389
390 if ((frameNo % 10)==0)
391 {
392 pw.print('.');
393 pw.flush();
394 }
395 }
396 }
397
398 public boolean converterException(Throwable t)
399 {
400 if (this.detailLevel>NO_DETAIL)
401 {
402 t.printStackTrace(pw);
403 pw.flush();
404 }
405 return false;
406 }
407
408 }
409
410
411} \ No newline at end of file
diff --git a/songdbj/javazoom/jl/converter/RiffFile.java b/songdbj/javazoom/jl/converter/RiffFile.java
new file mode 100644
index 0000000000..fb5d9e53c6
--- /dev/null
+++ b/songdbj/javazoom/jl/converter/RiffFile.java
@@ -0,0 +1,495 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 02/23/99 JavaConversion by E.B
4 * Don Cross, April 1993.
5 * RIFF file format classes.
6 * See Chapter 8 of "Multimedia Programmer's Reference" in
7 * the Microsoft Windows SDK.
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.jl.converter;
27
28import java.io.IOException;
29import java.io.RandomAccessFile;
30
31
32/**
33 * Class to manage RIFF files
34 */
35public class RiffFile
36{
37 class RiffChunkHeader
38 {
39 public int ckID = 0; // Four-character chunk ID
40 public int ckSize = 0; // Length of data in chunk
41 public RiffChunkHeader()
42 {}
43 }
44
45
46 // DDCRET
47 public static final int DDC_SUCCESS = 0; // The operation succeded
48 public static final int DDC_FAILURE = 1; // The operation failed for unspecified reasons
49 public static final int DDC_OUT_OF_MEMORY = 2; // Operation failed due to running out of memory
50 public static final int DDC_FILE_ERROR = 3; // Operation encountered file I/O error
51 public static final int DDC_INVALID_CALL = 4; // Operation was called with invalid parameters
52 public static final int DDC_USER_ABORT = 5; // Operation was aborted by the user
53 public static final int DDC_INVALID_FILE = 6; // File format does not match
54
55 // RiffFileMode
56 public static final int RFM_UNKNOWN = 0; // undefined type (can use to mean "N/A" or "not open")
57 public static final int RFM_WRITE = 1; // open for write
58 public static final int RFM_READ = 2; // open for read
59
60 private RiffChunkHeader riff_header; // header for whole file
61 protected int fmode; // current file I/O mode
62 protected RandomAccessFile file; // I/O stream to use
63
64 /**
65 * Dummy Constructor
66 */
67 public RiffFile()
68 {
69 file = null;
70 fmode = RFM_UNKNOWN;
71 riff_header = new RiffChunkHeader();
72
73 riff_header.ckID = FourCC("RIFF");
74 riff_header.ckSize = 0;
75 }
76
77 /**
78 * Return File Mode.
79 */
80 public int CurrentFileMode()
81 {return fmode;}
82
83 /**
84 * Open a RIFF file.
85 */
86 public int Open(String Filename, int NewMode)
87 {
88 int retcode = DDC_SUCCESS;
89
90 if ( fmode != RFM_UNKNOWN )
91 {
92 retcode = Close();
93 }
94
95 if ( retcode == DDC_SUCCESS )
96 {
97 switch ( NewMode )
98 {
99 case RFM_WRITE:
100 try
101 {
102 file = new RandomAccessFile(Filename,"rw");
103
104 try
105 {
106 // Write the RIFF header...
107 // We will have to come back later and patch it!
108 byte[] br = new byte[8];
109 br[0] = (byte) ((riff_header.ckID >>> 24) & 0x000000FF);
110 br[1] = (byte) ((riff_header.ckID >>> 16) & 0x000000FF);
111 br[2] = (byte) ((riff_header.ckID >>> 8) & 0x000000FF);
112 br[3] = (byte) (riff_header.ckID & 0x000000FF);
113
114 byte br4 = (byte) ((riff_header.ckSize >>> 24)& 0x000000FF);
115 byte br5 = (byte) ((riff_header.ckSize >>> 16)& 0x000000FF);
116 byte br6 = (byte) ((riff_header.ckSize >>> 8)& 0x000000FF);
117 byte br7 = (byte) (riff_header.ckSize & 0x000000FF);
118
119 br[4] = br7;
120 br[5] = br6;
121 br[6] = br5;
122 br[7] = br4;
123
124 file.write(br,0,8);
125 fmode = RFM_WRITE;
126 } catch (IOException ioe)
127 {
128 file.close();
129 fmode = RFM_UNKNOWN;
130 }
131 } catch (IOException ioe)
132 {
133 fmode = RFM_UNKNOWN;
134 retcode = DDC_FILE_ERROR;
135 }
136 break;
137
138 case RFM_READ:
139 try
140 {
141 file = new RandomAccessFile(Filename,"r");
142 try
143 {
144 // Try to read the RIFF header...
145 byte[] br = new byte[8];
146 file.read(br,0,8);
147 fmode = RFM_READ;
148 riff_header.ckID = ((br[0]<<24)& 0xFF000000) | ((br[1]<<16)&0x00FF0000) | ((br[2]<<8)&0x0000FF00) | (br[3]&0x000000FF);
149 riff_header.ckSize = ((br[4]<<24)& 0xFF000000) | ((br[5]<<16)&0x00FF0000) | ((br[6]<<8)&0x0000FF00) | (br[7]&0x000000FF);
150 } catch (IOException ioe)
151 {
152 file.close();
153 fmode = RFM_UNKNOWN;
154 }
155 } catch (IOException ioe)
156 {
157 fmode = RFM_UNKNOWN;
158 retcode = DDC_FILE_ERROR;
159 }
160 break;
161 default:
162 retcode = DDC_INVALID_CALL;
163 }
164 }
165 return retcode;
166 }
167
168 /**
169 * Write NumBytes data.
170 */
171 public int Write(byte[] Data, int NumBytes )
172 {
173 if ( fmode != RFM_WRITE )
174 {
175 return DDC_INVALID_CALL;
176 }
177 try
178 {
179 file.write(Data,0,NumBytes);
180 fmode = RFM_WRITE;
181 }
182 catch (IOException ioe)
183 {
184 return DDC_FILE_ERROR;
185 }
186 riff_header.ckSize += NumBytes;
187 return DDC_SUCCESS;
188 }
189
190
191
192 /**
193 * Write NumBytes data.
194 */
195 public int Write(short[] Data, int NumBytes )
196 {
197 byte[] theData = new byte[NumBytes];
198 int yc = 0;
199 for (int y = 0;y<NumBytes;y=y+2)
200 {
201 theData[y] = (byte) (Data[yc] & 0x00FF);
202 theData[y+1] =(byte) ((Data[yc++] >>> 8) & 0x00FF);
203 }
204 if ( fmode != RFM_WRITE )
205 {
206 return DDC_INVALID_CALL;
207 }
208 try
209 {
210 file.write(theData,0,NumBytes);
211 fmode = RFM_WRITE;
212 }
213 catch (IOException ioe)
214 {
215 return DDC_FILE_ERROR;
216 }
217 riff_header.ckSize += NumBytes;
218 return DDC_SUCCESS;
219 }
220
221 /**
222 * Write NumBytes data.
223 */
224 public int Write(RiffChunkHeader Triff_header, int NumBytes )
225 {
226 byte[] br = new byte[8];
227 br[0] = (byte) ((Triff_header.ckID >>> 24) & 0x000000FF);
228 br[1] = (byte) ((Triff_header.ckID >>> 16) & 0x000000FF);
229 br[2] = (byte) ((Triff_header.ckID >>> 8) & 0x000000FF);
230 br[3] = (byte) (Triff_header.ckID & 0x000000FF);
231
232 byte br4 = (byte) ((Triff_header.ckSize >>> 24)& 0x000000FF);
233 byte br5 = (byte) ((Triff_header.ckSize >>> 16)& 0x000000FF);
234 byte br6 = (byte) ((Triff_header.ckSize >>> 8)& 0x000000FF);
235 byte br7 = (byte) (Triff_header.ckSize & 0x000000FF);
236
237 br[4] = br7;
238 br[5] = br6;
239 br[6] = br5;
240 br[7] = br4;
241
242 if ( fmode != RFM_WRITE )
243 {
244 return DDC_INVALID_CALL;
245 }
246 try
247 {
248 file.write(br,0,NumBytes);
249 fmode = RFM_WRITE;
250 } catch (IOException ioe)
251 {
252 return DDC_FILE_ERROR;
253 }
254 riff_header.ckSize += NumBytes;
255 return DDC_SUCCESS;
256 }
257
258 /**
259 * Write NumBytes data.
260 */
261 public int Write(short Data, int NumBytes )
262 {
263 short theData = (short) ( ((Data>>>8)&0x00FF) | ((Data<<8)&0xFF00) );
264 if ( fmode != RFM_WRITE )
265 {
266 return DDC_INVALID_CALL;
267 }
268 try
269 {
270 file.writeShort(theData);
271 fmode = RFM_WRITE;
272 } catch (IOException ioe)
273 {
274 return DDC_FILE_ERROR;
275 }
276 riff_header.ckSize += NumBytes;
277 return DDC_SUCCESS;
278 }
279 /**
280 * Write NumBytes data.
281 */
282 public int Write(int Data, int NumBytes )
283 {
284 short theDataL = (short) ((Data>>>16)&0x0000FFFF);
285 short theDataR = (short) (Data&0x0000FFFF);
286 short theDataLI = (short) ( ((theDataL>>>8)&0x00FF) | ((theDataL<<8)&0xFF00) );
287 short theDataRI = (short) ( ((theDataR>>>8)&0x00FF) | ((theDataR<<8)&0xFF00) );
288 int theData = ((theDataRI<<16)&0xFFFF0000) | (theDataLI&0x0000FFFF);
289 if ( fmode != RFM_WRITE )
290 {
291 return DDC_INVALID_CALL;
292 }
293 try
294 {
295 file.writeInt(theData);
296 fmode = RFM_WRITE;
297 } catch (IOException ioe)
298 {
299 return DDC_FILE_ERROR;
300 }
301 riff_header.ckSize += NumBytes;
302 return DDC_SUCCESS;
303 }
304
305
306
307 /**
308 * Read NumBytes data.
309 */
310 public int Read (byte[] Data, int NumBytes)
311 {
312 int retcode = DDC_SUCCESS;
313 try
314 {
315 file.read(Data,0,NumBytes);
316 } catch (IOException ioe)
317 {
318 retcode = DDC_FILE_ERROR;
319 }
320 return retcode;
321 }
322
323 /**
324 * Expect NumBytes data.
325 */
326 public int Expect(String Data, int NumBytes )
327 {
328 byte target = 0;
329 int cnt = 0;
330 try
331 {
332 while ((NumBytes--) != 0)
333 {
334 target = file.readByte();
335 if (target != Data.charAt(cnt++)) return DDC_FILE_ERROR;
336 }
337 } catch (IOException ioe)
338 {
339 return DDC_FILE_ERROR;
340 }
341 return DDC_SUCCESS;
342 }
343
344 /**
345 * Close Riff File.
346 * Length is written too.
347 */
348 public int Close()
349 {
350 int retcode = DDC_SUCCESS;
351
352 switch ( fmode )
353 {
354 case RFM_WRITE:
355 try
356 {
357 file.seek(0);
358 try
359 {
360 byte[] br = new byte[8];
361 br[0] = (byte) ((riff_header.ckID >>> 24) & 0x000000FF);
362 br[1] = (byte) ((riff_header.ckID >>> 16) & 0x000000FF);
363 br[2] = (byte) ((riff_header.ckID >>> 8) & 0x000000FF);
364 br[3] = (byte) (riff_header.ckID & 0x000000FF);
365
366 br[7] = (byte) ((riff_header.ckSize >>> 24)& 0x000000FF);
367 br[6] = (byte) ((riff_header.ckSize >>> 16)& 0x000000FF);
368 br[5] = (byte) ((riff_header.ckSize >>> 8)& 0x000000FF);
369 br[4] = (byte) (riff_header.ckSize & 0x000000FF);
370 file.write(br,0,8);
371 file.close();
372 } catch (IOException ioe)
373 {
374 retcode = DDC_FILE_ERROR;
375 }
376 } catch (IOException ioe)
377 {
378 retcode = DDC_FILE_ERROR;
379 }
380 break;
381
382 case RFM_READ:
383 try
384 {
385 file.close();
386 } catch (IOException ioe)
387 {
388 retcode = DDC_FILE_ERROR;
389 }
390 break;
391 }
392 file = null;
393 fmode = RFM_UNKNOWN;
394 return retcode;
395 }
396
397 /**
398 * Return File Position.
399 */
400 public long CurrentFilePosition()
401 {
402 long position;
403 try
404 {
405 position = file.getFilePointer();
406 } catch (IOException ioe)
407 {
408 position = -1;
409 }
410 return position;
411 }
412
413 /**
414 * Write Data to specified offset.
415 */
416 public int Backpatch (long FileOffset, RiffChunkHeader Data, int NumBytes )
417 {
418 if (file == null)
419 {
420 return DDC_INVALID_CALL;
421 }
422 try
423 {
424 file.seek(FileOffset);
425 } catch (IOException ioe)
426 {
427 return DDC_FILE_ERROR;
428 }
429 return Write ( Data, NumBytes );
430 }
431
432 public int Backpatch (long FileOffset, byte[] Data, int NumBytes )
433 {
434 if (file == null)
435 {
436 return DDC_INVALID_CALL;
437 }
438 try
439 {
440 file.seek(FileOffset);
441 } catch (IOException ioe)
442 {
443 return DDC_FILE_ERROR;
444 }
445 return Write ( Data, NumBytes );
446 }
447
448
449 /**
450 * Seek in the File.
451 */
452 protected int Seek(long offset)
453 {
454 int rc;
455 try
456 {
457 file.seek(offset);
458 rc = DDC_SUCCESS;
459 } catch (IOException ioe)
460 {
461 rc = DDC_FILE_ERROR;
462 }
463 return rc;
464 }
465
466 /**
467 * Error Messages.
468 */
469 private String DDCRET_String(int retcode)
470 {
471 switch ( retcode )
472 {
473 case DDC_SUCCESS: return "DDC_SUCCESS";
474 case DDC_FAILURE: return "DDC_FAILURE";
475 case DDC_OUT_OF_MEMORY: return "DDC_OUT_OF_MEMORY";
476 case DDC_FILE_ERROR: return "DDC_FILE_ERROR";
477 case DDC_INVALID_CALL: return "DDC_INVALID_CALL";
478 case DDC_USER_ABORT: return "DDC_USER_ABORT";
479 case DDC_INVALID_FILE: return "DDC_INVALID_FILE";
480 }
481 return "Unknown Error";
482 }
483
484 /**
485 * Fill the header.
486 */
487 public static int FourCC(String ChunkName)
488 {
489 byte[] p = {0x20,0x20,0x20,0x20};
490 ChunkName.getBytes(0,4,p,0);
491 int ret = (((p[0] << 24)& 0xFF000000) | ((p[1] << 16)&0x00FF0000) | ((p[2] << 8)&0x0000FF00) | (p[3]&0x000000FF));
492 return ret;
493 }
494
495}
diff --git a/songdbj/javazoom/jl/converter/WaveFile.java b/songdbj/javazoom/jl/converter/WaveFile.java
new file mode 100644
index 0000000000..f158d7a39a
--- /dev/null
+++ b/songdbj/javazoom/jl/converter/WaveFile.java
@@ -0,0 +1,522 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 02/23/99 JavaConversion by E.B
4 * Don Cross, April 1993.
5 * RIFF file format classes.
6 * See Chapter 8 of "Multimedia Programmer's Reference" in
7 * the Microsoft Windows SDK.
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.jl.converter;
27
28/**
29 * Class allowing WaveFormat Access
30 */
31public class WaveFile extends RiffFile
32{
33 public static final int MAX_WAVE_CHANNELS = 2;
34
35 class WaveFormat_ChunkData
36 {
37 public short wFormatTag = 0; // Format category (PCM=1)
38 public short nChannels = 0; // Number of channels (mono=1, stereo=2)
39 public int nSamplesPerSec = 0; // Sampling rate [Hz]
40 public int nAvgBytesPerSec = 0;
41 public short nBlockAlign = 0;
42 public short nBitsPerSample = 0;
43
44 public WaveFormat_ChunkData()
45 {
46 wFormatTag = 1; // PCM
47 Config(44100,(short)16,(short)1);
48 }
49
50 public void Config (int NewSamplingRate, short NewBitsPerSample, short NewNumChannels)
51 {
52 nSamplesPerSec = NewSamplingRate;
53 nChannels = NewNumChannels;
54 nBitsPerSample = NewBitsPerSample;
55 nAvgBytesPerSec = (nChannels * nSamplesPerSec * nBitsPerSample) / 8;
56 nBlockAlign = (short) ((nChannels * nBitsPerSample) / 8);
57 }
58 }
59
60
61 class WaveFormat_Chunk
62 {
63 public RiffChunkHeader header;
64 public WaveFormat_ChunkData data;
65
66 public WaveFormat_Chunk()
67 {
68 header = new RiffChunkHeader();
69 data = new WaveFormat_ChunkData();
70 header.ckID = FourCC("fmt ");
71 header.ckSize = 16;
72 }
73
74 public int VerifyValidity()
75 {
76 boolean ret = header.ckID == FourCC("fmt ") &&
77
78 (data.nChannels == 1 || data.nChannels == 2) &&
79
80 data.nAvgBytesPerSec == ( data.nChannels *
81 data.nSamplesPerSec *
82 data.nBitsPerSample ) / 8 &&
83
84 data.nBlockAlign == ( data.nChannels *
85 data.nBitsPerSample ) / 8;
86 if (ret == true) return 1;
87 else return 0;
88 }
89 }
90
91 public class WaveFileSample
92 {
93 public short[] chan;
94
95 public WaveFileSample()
96 {chan = new short[WaveFile.MAX_WAVE_CHANNELS];}
97 }
98
99 private WaveFormat_Chunk wave_format;
100 private RiffChunkHeader pcm_data;
101 private long pcm_data_offset = 0; // offset of 'pcm_data' in output file
102 private int num_samples = 0;
103
104
105 /**
106 * Constructs a new WaveFile instance.
107 */
108 public WaveFile()
109 {
110 pcm_data = new RiffChunkHeader();
111 wave_format = new WaveFormat_Chunk();
112 pcm_data.ckID = FourCC("data");
113 pcm_data.ckSize = 0;
114 num_samples = 0;
115 }
116
117 /**
118 *
119 *
120 public int OpenForRead (String Filename)
121 {
122 // Verify filename parameter as best we can...
123 if (Filename == null)
124 {
125 return DDC_INVALID_CALL;
126 }
127 int retcode = Open ( Filename, RFM_READ );
128
129 if ( retcode == DDC_SUCCESS )
130 {
131 retcode = Expect ( "WAVE", 4 );
132
133 if ( retcode == DDC_SUCCESS )
134 {
135 retcode = Read(wave_format,24);
136
137 if ( retcode == DDC_SUCCESS && !wave_format.VerifyValidity() )
138 {
139 // This isn't standard PCM, so we don't know what it is!
140 retcode = DDC_FILE_ERROR;
141 }
142
143 if ( retcode == DDC_SUCCESS )
144 {
145 pcm_data_offset = CurrentFilePosition();
146
147 // Figure out number of samples from
148 // file size, current file position, and
149 // WAVE header.
150 retcode = Read (pcm_data, 8 );
151 num_samples = filelength(fileno(file)) - CurrentFilePosition();
152 num_samples /= NumChannels();
153 num_samples /= (BitsPerSample() / 8);
154 }
155 }
156 }
157 return retcode;
158 }*/
159
160 /**
161 *
162 */
163 public int OpenForWrite (String Filename, int SamplingRate, short BitsPerSample, short NumChannels)
164 {
165 // Verify parameters...
166 if ( (Filename==null) ||
167 (BitsPerSample != 8 && BitsPerSample != 16) ||
168 NumChannels < 1 || NumChannels > 2 )
169 {
170 return DDC_INVALID_CALL;
171 }
172
173 wave_format.data.Config ( SamplingRate, BitsPerSample, NumChannels );
174
175 int retcode = Open ( Filename, RFM_WRITE );
176
177 if ( retcode == DDC_SUCCESS )
178 {
179 byte [] theWave = {(byte)'W',(byte)'A',(byte)'V',(byte)'E'};
180 retcode = Write ( theWave, 4 );
181
182 if ( retcode == DDC_SUCCESS )
183 {
184 // Ecriture de wave_format
185 retcode = Write (wave_format.header, 8);
186 retcode = Write (wave_format.data.wFormatTag, 2);
187 retcode = Write (wave_format.data.nChannels, 2);
188 retcode = Write (wave_format.data.nSamplesPerSec, 4);
189 retcode = Write (wave_format.data.nAvgBytesPerSec, 4);
190 retcode = Write (wave_format.data.nBlockAlign, 2);
191 retcode = Write (wave_format.data.nBitsPerSample, 2);
192 /* byte[] br = new byte[16];
193 br[0] = (byte) ((wave_format.data.wFormatTag >> 8) & 0x00FF);
194 br[1] = (byte) (wave_format.data.wFormatTag & 0x00FF);
195
196 br[2] = (byte) ((wave_format.data.nChannels >> 8) & 0x00FF);
197 br[3] = (byte) (wave_format.data.nChannels & 0x00FF);
198
199 br[4] = (byte) ((wave_format.data.nSamplesPerSec >> 24)& 0x000000FF);
200 br[5] = (byte) ((wave_format.data.nSamplesPerSec >> 16)& 0x000000FF);
201 br[6] = (byte) ((wave_format.data.nSamplesPerSec >> 8)& 0x000000FF);
202 br[7] = (byte) (wave_format.data.nSamplesPerSec & 0x000000FF);
203
204 br[8] = (byte) ((wave_format.data.nAvgBytesPerSec>> 24)& 0x000000FF);
205 br[9] = (byte) ((wave_format.data.nAvgBytesPerSec >> 16)& 0x000000FF);
206 br[10] = (byte) ((wave_format.data.nAvgBytesPerSec >> 8)& 0x000000FF);
207 br[11] = (byte) (wave_format.data.nAvgBytesPerSec & 0x000000FF);
208
209 br[12] = (byte) ((wave_format.data.nBlockAlign >> 8) & 0x00FF);
210 br[13] = (byte) (wave_format.data.nBlockAlign & 0x00FF);
211
212 br[14] = (byte) ((wave_format.data.nBitsPerSample >> 8) & 0x00FF);
213 br[15] = (byte) (wave_format.data.nBitsPerSample & 0x00FF);
214 retcode = Write (br, 16); */
215
216
217 if ( retcode == DDC_SUCCESS )
218 {
219 pcm_data_offset = CurrentFilePosition();
220 retcode = Write ( pcm_data, 8 );
221 }
222 }
223 }
224
225 return retcode;
226 }
227
228 /**
229 *
230 *
231 public int ReadSample ( short[] Sample )
232 {
233
234 }*/
235
236 /**
237 *
238 *
239 public int WriteSample( short[] Sample )
240 {
241 int retcode = DDC_SUCCESS;
242 switch ( wave_format.data.nChannels )
243 {
244 case 1:
245 switch ( wave_format.data.nBitsPerSample )
246 {
247 case 8:
248 pcm_data.ckSize += 1;
249 retcode = Write ( Sample, 1 );
250 break;
251
252 case 16:
253 pcm_data.ckSize += 2;
254 retcode = Write ( Sample, 2 );
255 break;
256
257 default:
258 retcode = DDC_INVALID_CALL;
259 }
260 break;
261
262 case 2:
263 switch ( wave_format.data.nBitsPerSample )
264 {
265 case 8:
266 retcode = Write ( Sample, 1 );
267 if ( retcode == DDC_SUCCESS )
268 {
269 // &Sample[1]
270 retcode = Write (Sample, 1 );
271 if ( retcode == DDC_SUCCESS )
272 {
273 pcm_data.ckSize += 2;
274 }
275 }
276 break;
277
278 case 16:
279 retcode = Write ( Sample, 2 );
280 if ( retcode == DDC_SUCCESS )
281 {
282 // &Sample[1]
283 retcode = Write (Sample, 2 );
284 if ( retcode == DDC_SUCCESS )
285 {
286 pcm_data.ckSize += 4;
287 }
288 }
289 break;
290
291 default:
292 retcode = DDC_INVALID_CALL;
293 }
294 break;
295
296 default:
297 retcode = DDC_INVALID_CALL;
298 }
299
300 return retcode;
301 }*/
302
303 /**
304 *
305 *
306 public int SeekToSample ( long SampleIndex )
307 {
308 if ( SampleIndex >= NumSamples() )
309 {
310 return DDC_INVALID_CALL;
311 }
312 int SampleSize = (BitsPerSample() + 7) / 8;
313 int rc = Seek ( pcm_data_offset + 8 +
314 SampleSize * NumChannels() * SampleIndex );
315 return rc;
316 }*/
317
318 /**
319 * Write 16-bit audio
320 */
321 public int WriteData ( short[] data, int numData )
322 {
323 int extraBytes = numData * 2;
324 pcm_data.ckSize += extraBytes;
325 return super.Write ( data, extraBytes );
326 }
327
328 /**
329 * Read 16-bit audio.
330 *
331 public int ReadData (short[] data, int numData)
332 {return super.Read ( data, numData * 2);} */
333
334 /**
335 * Write 8-bit audio.
336 *
337 public int WriteData ( byte[] data, int numData )
338 {
339 pcm_data.ckSize += numData;
340 return super.Write ( data, numData );
341 }*/
342
343 /**
344 * Read 8-bit audio.
345 *
346 public int ReadData ( byte[] data, int numData )
347 {return super.Read ( data, numData );} */
348
349
350 /**
351 *
352 *
353 public int ReadSamples (int num, int [] WaveFileSample)
354 {
355
356 }*/
357
358 /**
359 *
360 *
361 public int WriteMonoSample ( short[] SampleData )
362 {
363 switch ( wave_format.data.nBitsPerSample )
364 {
365 case 8:
366 pcm_data.ckSize += 1;
367 return Write ( SampleData, 1 );
368
369 case 16:
370 pcm_data.ckSize += 2;
371 return Write ( SampleData, 2 );
372 }
373 return DDC_INVALID_CALL;
374 }*/
375
376 /**
377 *
378 *
379 public int WriteStereoSample ( short[] LeftSample, short[] RightSample )
380 {
381 int retcode = DDC_SUCCESS;
382 switch ( wave_format.data.nBitsPerSample )
383 {
384 case 8:
385 retcode = Write ( LeftSample, 1 );
386 if ( retcode == DDC_SUCCESS )
387 {
388 retcode = Write ( RightSample, 1 );
389 if ( retcode == DDC_SUCCESS )
390 {
391 pcm_data.ckSize += 2;
392 }
393 }
394 break;
395
396 case 16:
397 retcode = Write ( LeftSample, 2 );
398 if ( retcode == DDC_SUCCESS )
399 {
400 retcode = Write ( RightSample, 2 );
401 if ( retcode == DDC_SUCCESS )
402 {
403 pcm_data.ckSize += 4;
404 }
405 }
406 break;
407
408 default:
409 retcode = DDC_INVALID_CALL;
410 }
411 return retcode;
412 }*/
413
414 /**
415 *
416 *
417 public int ReadMonoSample ( short[] Sample )
418 {
419 int retcode = DDC_SUCCESS;
420 switch ( wave_format.data.nBitsPerSample )
421 {
422 case 8:
423 byte[] x = {0};
424 retcode = Read ( x, 1 );
425 Sample[0] = (short)(x[0]);
426 break;
427
428 case 16:
429 retcode = Read ( Sample, 2 );
430 break;
431
432 default:
433 retcode = DDC_INVALID_CALL;
434 }
435 return retcode;
436 }*/
437
438 /**
439 *
440 *
441 public int ReadStereoSample ( short[] LeftSampleData, short[] RightSampleData )
442 {
443 int retcode = DDC_SUCCESS;
444 byte[] x = new byte[2];
445 short[] y = new short[2];
446 switch ( wave_format.data.nBitsPerSample )
447 {
448 case 8:
449 retcode = Read ( x, 2 );
450 L[0] = (short) ( x[0] );
451 R[0] = (short) ( x[1] );
452 break;
453
454 case 16:
455 retcode = Read ( y, 4 );
456 L[0] = (short) ( y[0] );
457 R[0] = (short) ( y[1] );
458 break;
459
460 default:
461 retcode = DDC_INVALID_CALL;
462 }
463 return retcode;
464 }*/
465
466
467 /**
468 *
469 */
470 public int Close()
471 {
472 int rc = DDC_SUCCESS;
473
474 if ( fmode == RFM_WRITE )
475 rc = Backpatch ( pcm_data_offset, pcm_data, 8 );
476 if ( rc == DDC_SUCCESS )
477 rc = super.Close();
478 return rc;
479 }
480
481 // [Hz]
482 public int SamplingRate()
483 {return wave_format.data.nSamplesPerSec;}
484
485 public short BitsPerSample()
486 {return wave_format.data.nBitsPerSample;}
487
488 public short NumChannels()
489 {return wave_format.data.nChannels;}
490
491 public int NumSamples()
492 {return num_samples;}
493
494
495 /**
496 * Open for write using another wave file's parameters...
497 */
498 public int OpenForWrite (String Filename, WaveFile OtherWave )
499 {
500 return OpenForWrite ( Filename,
501 OtherWave.SamplingRate(),
502 OtherWave.BitsPerSample(),
503 OtherWave.NumChannels() );
504 }
505
506 /**
507 *
508 */
509 public long CurrentFilePosition()
510 {
511 return super.CurrentFilePosition();
512 }
513
514 /* public int FourCC(String ChunkName)
515 {
516 byte[] p = {0x20,0x20,0x20,0x20};
517 ChunkName.getBytes(0,4,p,0);
518 int ret = (((p[0] << 24)& 0xFF000000) | ((p[1] << 16)&0x00FF0000) | ((p[2] << 8)&0x0000FF00) | (p[3]&0x000000FF));
519 return ret;
520 }*/
521
522} \ No newline at end of file
diff --git a/songdbj/javazoom/jl/converter/WaveFileObuffer.java b/songdbj/javazoom/jl/converter/WaveFileObuffer.java
new file mode 100644
index 0000000000..eaa1dd46d4
--- /dev/null
+++ b/songdbj/javazoom/jl/converter/WaveFileObuffer.java
@@ -0,0 +1,141 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *
4 * 12/12/99 0.0.7 Renamed class, additional constructor arguments
5 * and larger write buffers. mdm@techie.com.
6 *
7 * 15/02/99 Java Conversion by E.B ,javalayer@javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.jl.converter;
27
28import javazoom.jl.decoder.Obuffer;
29
30/**
31 * Implements an Obuffer by writing the data to
32 * a file in RIFF WAVE format.
33 *
34 * @since 0.0
35 */
36
37
38public class WaveFileObuffer extends Obuffer
39{
40 private short[] buffer;
41 private short[] bufferp;
42 private int channels;
43 private WaveFile outWave;
44
45 /**
46 * Creates a new WareFileObuffer instance.
47 *
48 * @param number_of_channels
49 * The number of channels of audio data
50 * this buffer will receive.
51 *
52 * @param freq The sample frequency of the samples in the buffer.
53 *
54 * @param fileName The filename to write the data to.
55 */
56 public WaveFileObuffer(int number_of_channels, int freq, String FileName)
57 {
58 if (FileName==null)
59 throw new NullPointerException("FileName");
60
61 buffer = new short[OBUFFERSIZE];
62 bufferp = new short[MAXCHANNELS];
63 channels = number_of_channels;
64
65 for (int i = 0; i < number_of_channels; ++i)
66 bufferp[i] = (short)i;
67
68 outWave = new WaveFile();
69
70 int rc = outWave.OpenForWrite (FileName,freq,(short)16,(short)channels);
71 }
72
73 /**
74 * Takes a 16 Bit PCM sample.
75 */
76 public void append(int channel, short value)
77 {
78 buffer[bufferp[channel]] = value;
79 bufferp[channel] += channels;
80 }
81
82 /**
83 * Write the samples to the file (Random Acces).
84 */
85 short[] myBuffer = new short[2];
86 public void write_buffer(int val)
87 {
88
89 int k = 0;
90 int rc = 0;
91
92 rc = outWave.WriteData(buffer, bufferp[0]);
93 // REVIEW: handle RiffFile errors.
94 /*
95 for (int j=0;j<bufferp[0];j=j+2)
96 {
97
98 //myBuffer[0] = (short)(((buffer[j]>>8)&0x000000FF) | ((buffer[j]<<8)&0x0000FF00));
99 //myBuffer[1] = (short) (((buffer[j+1]>>8)&0x000000FF) | ((buffer[j+1]<<8)&0x0000FF00));
100 myBuffer[0] = buffer[j];
101 myBuffer[1] = buffer[j+1];
102 rc = outWave.WriteData (myBuffer,2);
103 }
104 */
105 for (int i = 0; i < channels; ++i) bufferp[i] = (short)i;
106 }
107
108 public void close()
109 {
110 outWave.Close();
111 }
112
113 /**
114 *
115 */
116 public void clear_buffer()
117 {}
118
119 /**
120 *
121 */
122 public void set_stop_flag()
123 {}
124
125 /*
126 * Create STDOUT buffer
127 *
128 *
129 public static Obuffer create_stdout_obuffer(MPEG_Args maplay_args)
130 {
131 Obuffer thebuffer = null;
132 int mode = maplay_args.MPEGheader.mode();
133 int which_channels = maplay_args.which_c;
134 if (mode == Header.single_channel || which_channels != MPEG_Args.both)
135 thebuffer = new FileObuffer(1,maplay_args.output_filename);
136 else
137 thebuffer = new FileObuffer(2,maplay_args.output_filename);
138 return(thebuffer);
139 }
140 */
141}
diff --git a/songdbj/javazoom/jl/converter/jlc.java b/songdbj/javazoom/jl/converter/jlc.java
new file mode 100644
index 0000000000..57c84eba4a
--- /dev/null
+++ b/songdbj/javazoom/jl/converter/jlc.java
@@ -0,0 +1,216 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *
4 * 29/01/00 Initial version. mdm@techie.com
5 *
6 * 12/12/99 JavaLayer 0.0.7 mdm@techie.com
7 *
8 * 14/02/99 MPEG_Args Based Class - E.B
9 * Adapted from javalayer and MPEG_Args.
10 * Doc'ed and integerated with JL converter. Removed
11 * Win32 specifics from original Maplay code.
12 *-----------------------------------------------------------------------
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Library General Public License as published
15 * by the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Library General Public License for more details.
22 *
23 * You should have received a copy of the GNU Library General Public
24 * License along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 *----------------------------------------------------------------------
27 */
28
29package javazoom.jl.converter;
30
31import java.io.PrintWriter;
32
33import javazoom.jl.decoder.Crc16;
34import javazoom.jl.decoder.JavaLayerException;
35import javazoom.jl.decoder.OutputChannels;
36
37/**
38 * The <code>jlc</code> class presents the JavaLayer
39 * Conversion functionality as a command-line program.
40 *
41 * @since 0.0.7
42 */
43public class jlc
44{
45
46 static public void main(String args[])
47 {
48 String[] argv;
49 long start = System.currentTimeMillis();
50 int argc = args.length + 1;
51 argv = new String[argc];
52 argv[0] = "jlc";
53 for(int i=0;i<args.length;i++)
54 argv[i+1] = args[i];
55
56 jlcArgs ma = new jlcArgs();
57 if (!ma.processArgs(argv))
58 System.exit(1);
59
60 Converter conv = new Converter();
61
62 int detail = (ma.verbose_mode ?
63 ma.verbose_level :
64 Converter.PrintWriterProgressListener.NO_DETAIL);
65
66 Converter.ProgressListener listener =
67 new Converter.PrintWriterProgressListener(
68 new PrintWriter(System.out, true), detail);
69
70 try
71 {
72 conv.convert(ma.filename, ma.output_filename, listener);
73 }
74 catch (JavaLayerException ex)
75 {
76 System.err.println("Convertion failure: "+ex);
77 }
78
79 System.exit(0);
80 }
81
82
83 /**
84 * Class to contain arguments for maplay.
85 */
86 static class jlcArgs
87 {
88 // channel constants moved into OutputChannels class.
89 //public static final int both = 0;
90 //public static final int left = 1;
91 //public static final int right = 2;
92 //public static final int downmix = 3;
93
94 public int which_c;
95 public int output_mode;
96 public boolean use_own_scalefactor;
97 public float scalefactor;
98 public String output_filename;
99 public String filename;
100 //public boolean stdout_mode;
101 public boolean verbose_mode;
102 public int verbose_level = 3;
103
104 public jlcArgs()
105 {
106 which_c = OutputChannels.BOTH_CHANNELS;
107 use_own_scalefactor = false;
108 scalefactor = (float) 32768.0;
109 //stdout_mode = false;
110 verbose_mode = false;
111 }
112
113 /**
114 * Process user arguments.
115 *
116 * Returns true if successful.
117 */
118 public boolean processArgs(String[] argv)
119 {
120 filename = null;
121 Crc16[] crc;
122 crc = new Crc16[1];
123 int i;
124 int argc = argv.length;
125
126 //stdout_mode = false;
127 verbose_mode = false;
128 output_mode = OutputChannels.BOTH_CHANNELS;
129 output_filename = "";
130 if (argc < 2 || argv[1].equals("-h"))
131 return Usage();
132
133 i = 1;
134 while (i < argc)
135 {
136 /* System.out.println("Option = "+argv[i]);*/
137 if (argv[i].charAt(0) == '-')
138 {
139 if (argv[i].startsWith("-v"))
140 {
141 verbose_mode = true;
142 if (argv[i].length()>2)
143 {
144 try
145 {
146 String level = argv[i].substring(2);
147 verbose_level = Integer.parseInt(level);
148 }
149 catch (NumberFormatException ex)
150 {
151 System.err.println("Invalid verbose level. Using default.");
152 }
153 }
154 System.out.println("Verbose Activated (level "+verbose_level+")");
155 }
156 /* else if (argv[i].equals("-s"))
157 ma.stdout_mode = true; */
158 else if (argv[i].equals("-p"))
159 {
160 if (++i == argc)
161 {
162 System.out.println("Please specify an output filename after the -p option!");
163 System.exit (1);
164 }
165 //output_mode = O_WAVEFILE;
166 output_filename = argv[i];
167 }
168 /*else if (argv[i].equals("-f"))
169 {
170 if (++i == argc)
171 {
172 System.out.println("Please specify a new scalefactor after the -f option!");
173 System.exit(1);
174 }
175 ma.use_own_scalefactor = true;
176 // ma.scalefactor = argv[i];
177 }*/
178 else return Usage();
179 }
180 else
181 {
182 filename = argv[i];
183 System.out.println("FileName = "+argv[i]);
184 if (filename == null) return Usage();
185 }
186 i++;
187 }
188 if (filename == null)
189 return Usage();
190
191 return true;
192 }
193
194
195 /**
196 * Usage of JavaLayer.
197 */
198 public boolean Usage()
199 {
200 System.out.println("JavaLayer Converter :");
201 System.out.println(" -v[x] verbose mode. ");
202 System.out.println(" default = 2");
203 /* System.out.println(" -s write u-law samples at 8 kHz rate to stdout");
204 System.out.println(" -l decode only the left channel");
205 System.out.println(" -r decode only the right channel");
206 System.out.println(" -d downmix mode (layer III only)");
207 System.out.println(" -s write pcm samples to stdout");
208 System.out.println(" -d downmix mode (layer III only)");*/
209 System.out.println(" -p name output as a PCM wave file");
210 System.out.println("");
211 System.out.println(" More info on http://www.javazoom.net");
212 /* System.out.println(" -f ushort use this scalefactor instead of the default value 32768");*/
213 return false;
214 }
215 };
216}; \ No newline at end of file
diff --git a/songdbj/javazoom/jl/decoder/BitReserve.java b/songdbj/javazoom/jl/decoder/BitReserve.java
new file mode 100644
index 0000000000..a5d3056d61
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/BitReserve.java
@@ -0,0 +1,223 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *
4 * 12/12/99 0.0.7 Implementation stores single bits
5 * as ints for better performance. mdm@techie.com.
6 *
7 * 02/28/99 0.0 Java Conversion by E.B, javalayer@javazoom.net
8 *
9 * Adapted from the public c code by Jeff Tsay.
10 *
11 *-----------------------------------------------------------------------
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *----------------------------------------------------------------------
26 */
27
28package javazoom.jl.decoder;
29
30/**
31 * Implementation of Bit Reservoir for Layer III.
32 * <p>
33 * The implementation stores single bits as a word in the buffer. If
34 * a bit is set, the corresponding word in the buffer will be non-zero.
35 * If a bit is clear, the corresponding word is zero. Although this
36 * may seem waseful, this can be a factor of two quicker than
37 * packing 8 bits to a byte and extracting.
38 * <p>
39 */
40
41// REVIEW: there is no range checking, so buffer underflow or overflow
42// can silently occur.
43final class BitReserve
44{
45 /**
46 * Size of the internal buffer to store the reserved bits.
47 * Must be a power of 2. And x8, as each bit is stored as a single
48 * entry.
49 */
50 private static final int BUFSIZE = 4096*8;
51
52 /**
53 * Mask that can be used to quickly implement the
54 * modulus operation on BUFSIZE.
55 */
56 private static final int BUFSIZE_MASK = BUFSIZE-1;
57
58 private int offset, totbit, buf_byte_idx;
59 private final int[] buf = new int[BUFSIZE];
60 private int buf_bit_idx;
61
62 BitReserve()
63 {
64
65 offset = 0;
66 totbit = 0;
67 buf_byte_idx = 0;
68 }
69
70
71 /**
72 * Return totbit Field.
73 */
74 public int hsstell()
75 {
76 return(totbit);
77 }
78
79 /**
80 * Read a number bits from the bit stream.
81 * @param N the number of
82 */
83 public int hgetbits(int N)
84 {
85 totbit += N;
86
87 int val = 0;
88
89 int pos = buf_byte_idx;
90 if (pos+N < BUFSIZE)
91 {
92 while (N-- > 0)
93 {
94 val <<= 1;
95 val |= ((buf[pos++]!=0) ? 1 : 0);
96 }
97 }
98 else
99 {
100 while (N-- > 0)
101 {
102 val <<= 1;
103 val |= ((buf[pos]!=0) ? 1 : 0);
104 pos = (pos+1) & BUFSIZE_MASK;
105 }
106 }
107 buf_byte_idx = pos;
108 return val;
109 }
110
111
112
113 /**
114 * Read 1 bit from the bit stream.
115 */
116/*
117 public int hget1bit_old()
118 {
119 int val;
120 totbit++;
121 if (buf_bit_idx == 0)
122 {
123 buf_bit_idx = 8;
124 buf_byte_idx++;
125 }
126 // BUFSIZE = 4096 = 2^12, so
127 // buf_byte_idx%BUFSIZE == buf_byte_idx & 0xfff
128 val = buf[buf_byte_idx & BUFSIZE_MASK] & putmask[buf_bit_idx];
129 buf_bit_idx--;
130 val = val >>> buf_bit_idx;
131 return val;
132 }
133 */
134 /**
135 * Returns next bit from reserve.
136 * @returns 0 if next bit is reset, or 1 if next bit is set.
137 */
138 public int hget1bit()
139 {
140 totbit++;
141 int val = buf[buf_byte_idx];
142 buf_byte_idx = (buf_byte_idx+1) & BUFSIZE_MASK;
143 return val;
144 }
145
146 /**
147 * Retrieves bits from the reserve.
148 */
149/*
150 public int readBits(int[] out, int len)
151 {
152 if (buf_bit_idx == 0)
153 {
154 buf_bit_idx = 8;
155 buf_byte_idx++;
156 current = buf[buf_byte_idx & BUFSIZE_MASK];
157 }
158
159
160
161 // save total number of bits returned
162 len = buf_bit_idx;
163 buf_bit_idx = 0;
164
165 int b = current;
166 int count = len-1;
167
168 while (count >= 0)
169 {
170 out[count--] = (b & 0x1);
171 b >>>= 1;
172 }
173
174 totbit += len;
175 return len;
176 }
177 */
178
179 /**
180 * Write 8 bits into the bit stream.
181 */
182 public void hputbuf(int val)
183 {
184 int ofs = offset;
185 buf[ofs++] = val & 0x80;
186 buf[ofs++] = val & 0x40;
187 buf[ofs++] = val & 0x20;
188 buf[ofs++] = val & 0x10;
189 buf[ofs++] = val & 0x08;
190 buf[ofs++] = val & 0x04;
191 buf[ofs++] = val & 0x02;
192 buf[ofs++] = val & 0x01;
193
194 if (ofs==BUFSIZE)
195 offset = 0;
196 else
197 offset = ofs;
198
199 }
200
201 /**
202 * Rewind N bits in Stream.
203 */
204 public void rewindNbits(int N)
205 {
206 totbit -= N;
207 buf_byte_idx -= N;
208 if (buf_byte_idx<0)
209 buf_byte_idx += BUFSIZE;
210 }
211
212 /**
213 * Rewind N bytes in Stream.
214 */
215 public void rewindNbytes(int N)
216 {
217 int bits = (N << 3);
218 totbit -= bits;
219 buf_byte_idx -= bits;
220 if (buf_byte_idx<0)
221 buf_byte_idx += BUFSIZE;
222 }
223}
diff --git a/songdbj/javazoom/jl/decoder/Bitstream.java b/songdbj/javazoom/jl/decoder/Bitstream.java
new file mode 100644
index 0000000000..cebbd5b03b
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/Bitstream.java
@@ -0,0 +1,655 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *
4 * 11/17/04 Uncomplete frames discarded. E.B, javalayer@javazoom.net
5 *
6 * 12/05/03 ID3v2 tag returned. E.B, javalayer@javazoom.net
7 *
8 * 12/12/99 Based on Ibitstream. Exceptions thrown on errors,
9 * Temporary removed seek functionality. mdm@techie.com
10 *
11 * 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net
12 *
13 * 04/14/97 : Added function prototypes for new syncing and seeking
14 * mechanisms. Also made this file portable. Changes made by Jeff Tsay
15 *
16 * @(#) ibitstream.h 1.5, last edit: 6/15/94 16:55:34
17 * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
18 * @(#) Berlin University of Technology
19 *-----------------------------------------------------------------------
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU Library General Public License as published
22 * by the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU Library General Public License for more details.
29 *
30 * You should have received a copy of the GNU Library General Public
31 * License along with this program; if not, write to the Free Software
32 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 *----------------------------------------------------------------------
34 */
35
36package javazoom.jl.decoder;
37
38import java.io.BufferedInputStream;
39import java.io.ByteArrayInputStream;
40import java.io.IOException;
41import java.io.InputStream;
42import java.io.PushbackInputStream;
43
44
45/**
46 * The <code>Bistream</code> class is responsible for parsing
47 * an MPEG audio bitstream.
48 *
49 * <b>REVIEW:</b> much of the parsing currently occurs in the
50 * various decoders. This should be moved into this class and associated
51 * inner classes.
52 */
53public final class Bitstream implements BitstreamErrors
54{
55 /**
56 * Synchronization control constant for the initial
57 * synchronization to the start of a frame.
58 */
59 static byte INITIAL_SYNC = 0;
60
61 /**
62 * Synchronization control constant for non-initial frame
63 * synchronizations.
64 */
65 static byte STRICT_SYNC = 1;
66
67 // max. 1730 bytes per frame: 144 * 384kbit/s / 32000 Hz + 2 Bytes CRC
68 /**
69 * Maximum size of the frame buffer.
70 */
71 private static final int BUFFER_INT_SIZE = 433;
72
73 /**
74 * The frame buffer that holds the data for the current frame.
75 */
76 private final int[] framebuffer = new int[BUFFER_INT_SIZE];
77
78 /**
79 * Number of valid bytes in the frame buffer.
80 */
81 private int framesize;
82
83 /**
84 * The bytes read from the stream.
85 */
86 private byte[] frame_bytes = new byte[BUFFER_INT_SIZE*4];
87
88 /**
89 * Index into <code>framebuffer</code> where the next bits are
90 * retrieved.
91 */
92 private int wordpointer;
93
94 /**
95 * Number (0-31, from MSB to LSB) of next bit for get_bits()
96 */
97 private int bitindex;
98
99 /**
100 * The current specified syncword
101 */
102 private int syncword;
103
104 /**
105 * Audio header position in stream.
106 */
107 private int header_pos = 0;
108
109 /**
110 *
111 */
112 private boolean single_ch_mode;
113 //private int current_frame_number;
114 //private int last_frame_number;
115
116 private final int bitmask[] = {0, // dummy
117 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
118 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
119 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
120 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
121 0x0001FFFF };
122
123 private final PushbackInputStream source;
124
125 private final Header header = new Header();
126
127 private final byte syncbuf[] = new byte[4];
128
129 private Crc16[] crc = new Crc16[1];
130
131 private byte[] rawid3v2 = null;
132
133 private boolean firstframe = true;
134
135
136 /**
137 * Construct a IBitstream that reads data from a
138 * given InputStream.
139 *
140 * @param in The InputStream to read from.
141 */
142 public Bitstream(InputStream in)
143 {
144 if (in==null) throw new NullPointerException("in");
145 in = new BufferedInputStream(in);
146 loadID3v2(in);
147 firstframe = true;
148 //source = new PushbackInputStream(in, 1024);
149 source = new PushbackInputStream(in, BUFFER_INT_SIZE*4);
150
151 closeFrame();
152 //current_frame_number = -1;
153 //last_frame_number = -1;
154 }
155
156 /**
157 * Return position of the first audio header.
158 * @return size of ID3v2 tag frames.
159 */
160 public int header_pos()
161 {
162 return header_pos;
163 }
164
165 /**
166 * Load ID3v2 frames.
167 * @param in MP3 InputStream.
168 * @author JavaZOOM
169 */
170 private void loadID3v2(InputStream in)
171 {
172 int size = -1;
173 try
174 {
175 // Read ID3v2 header (10 bytes).
176 in.mark(10);
177 size = readID3v2Header(in);
178 header_pos = size;
179 }
180 catch (IOException e)
181 {}
182 finally
183 {
184 try
185 {
186 // Unread ID3v2 header (10 bytes).
187 in.reset();
188 }
189 catch (IOException e)
190 {}
191 }
192 // Load ID3v2 tags.
193 try
194 {
195 if (size > 0)
196 {
197 rawid3v2 = new byte[size];
198 in.read(rawid3v2,0,rawid3v2.length);
199 }
200 }
201 catch (IOException e)
202 {}
203 }
204
205 /**
206 * Parse ID3v2 tag header to find out size of ID3v2 frames.
207 * @param in MP3 InputStream
208 * @return size of ID3v2 frames + header
209 * @throws IOException
210 * @author JavaZOOM
211 */
212 private int readID3v2Header(InputStream in) throws IOException
213 {
214 byte[] id3header = new byte[4];
215 int size = -10;
216 in.read(id3header,0,3);
217 // Look for ID3v2
218 if ( (id3header[0]=='I') && (id3header[1]=='D') && (id3header[2]=='3'))
219 {
220 in.read(id3header,0,3);
221 int majorVersion = id3header[0];
222 int revision = id3header[1];
223 in.read(id3header,0,4);
224 size = (int) (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]);
225 }
226 return (size+10);
227 }
228
229 /**
230 * Return raw ID3v2 frames + header.
231 * @return ID3v2 InputStream or null if ID3v2 frames are not available.
232 */
233 public InputStream getRawID3v2()
234 {
235 if (rawid3v2 == null) return null;
236 else
237 {
238 ByteArrayInputStream bain = new ByteArrayInputStream(rawid3v2);
239 return bain;
240 }
241 }
242
243 /**
244 * Close the Bitstream.
245 * @throws BitstreamException
246 */
247 public void close() throws BitstreamException
248 {
249 try
250 {
251 source.close();
252 }
253 catch (IOException ex)
254 {
255 throw newBitstreamException(STREAM_ERROR, ex);
256 }
257 }
258
259 /**
260 * Reads and parses the next frame from the input source.
261 * @return the Header describing details of the frame read,
262 * or null if the end of the stream has been reached.
263 */
264 public Header readFrame() throws BitstreamException
265 {
266 Header result = null;
267 try
268 {
269 result = readNextFrame();
270 // E.B, Parse VBR (if any) first frame.
271 if (firstframe == true)
272 {
273 result.parseVBR(frame_bytes);
274 firstframe = false;
275 }
276 }
277 catch (BitstreamException ex)
278 {
279 if ((ex.getErrorCode()==INVALIDFRAME))
280 {
281 // Try to skip this frame.
282 //System.out.println("INVALIDFRAME");
283 try
284 {
285 closeFrame();
286 result = readNextFrame();
287 }
288 catch (BitstreamException e)
289 {
290 if ((e.getErrorCode()!=STREAM_EOF))
291 {
292 // wrap original exception so stack trace is maintained.
293 throw newBitstreamException(e.getErrorCode(), e);
294 }
295 }
296 }
297 else if ((ex.getErrorCode()!=STREAM_EOF))
298 {
299 // wrap original exception so stack trace is maintained.
300 throw newBitstreamException(ex.getErrorCode(), ex);
301 }
302 }
303 return result;
304 }
305
306 /**
307 * Read next MP3 frame.
308 * @return MP3 frame header.
309 * @throws BitstreamException
310 */
311 private Header readNextFrame() throws BitstreamException
312 {
313 if (framesize == -1)
314 {
315 nextFrame();
316 }
317 return header;
318 }
319
320
321 /**
322 * Read next MP3 frame.
323 * @throws BitstreamException
324 */
325 private void nextFrame() throws BitstreamException
326 {
327 // entire frame is read by the header class.
328 header.read_header(this, crc);
329 }
330
331 /**
332 * Unreads the bytes read from the frame.
333 * @throws BitstreamException
334 */
335 // REVIEW: add new error codes for this.
336 public void unreadFrame() throws BitstreamException
337 {
338 if (wordpointer==-1 && bitindex==-1 && (framesize>0))
339 {
340 try
341 {
342 source.unread(frame_bytes, 0, framesize);
343 }
344 catch (IOException ex)
345 {
346 throw newBitstreamException(STREAM_ERROR);
347 }
348 }
349 }
350
351 /**
352 * Close MP3 frame.
353 */
354 public void closeFrame()
355 {
356 framesize = -1;
357 wordpointer = -1;
358 bitindex = -1;
359 }
360
361 /**
362 * Determines if the next 4 bytes of the stream represent a
363 * frame header.
364 */
365 public boolean isSyncCurrentPosition(int syncmode) throws BitstreamException
366 {
367 int read = readBytes(syncbuf, 0, 4);
368 int headerstring = ((syncbuf[0] << 24) & 0xFF000000) | ((syncbuf[1] << 16) & 0x00FF0000) | ((syncbuf[2] << 8) & 0x0000FF00) | ((syncbuf[3] << 0) & 0x000000FF);
369
370 try
371 {
372 source.unread(syncbuf, 0, read);
373 }
374 catch (IOException ex)
375 {
376 }
377
378 boolean sync = false;
379 switch (read)
380 {
381 case 0:
382 sync = true;
383 break;
384 case 4:
385 sync = isSyncMark(headerstring, syncmode, syncword);
386 break;
387 }
388
389 return sync;
390 }
391
392
393 // REVIEW: this class should provide inner classes to
394 // parse the frame contents. Eventually, readBits will
395 // be removed.
396 public int readBits(int n)
397 {
398 return get_bits(n);
399 }
400
401 public int readCheckedBits(int n)
402 {
403 // REVIEW: implement CRC check.
404 return get_bits(n);
405 }
406
407 protected BitstreamException newBitstreamException(int errorcode)
408 {
409 return new BitstreamException(errorcode, null);
410 }
411 protected BitstreamException newBitstreamException(int errorcode, Throwable throwable)
412 {
413 return new BitstreamException(errorcode, throwable);
414 }
415
416 /**
417 * Get next 32 bits from bitstream.
418 * They are stored in the headerstring.
419 * syncmod allows Synchro flag ID
420 * The returned value is False at the end of stream.
421 */
422
423 int syncHeader(byte syncmode) throws BitstreamException
424 {
425 boolean sync;
426 int headerstring;
427 // read additional 2 bytes
428 int bytesRead = readBytes(syncbuf, 0, 3);
429
430 if (bytesRead!=3) throw newBitstreamException(STREAM_EOF, null);
431
432 headerstring = ((syncbuf[0] << 16) & 0x00FF0000) | ((syncbuf[1] << 8) & 0x0000FF00) | ((syncbuf[2] << 0) & 0x000000FF);
433
434 do
435 {
436 headerstring <<= 8;
437
438 if (readBytes(syncbuf, 3, 1)!=1)
439 throw newBitstreamException(STREAM_EOF, null);
440
441 headerstring |= (syncbuf[3] & 0x000000FF);
442
443 sync = isSyncMark(headerstring, syncmode, syncword);
444 }
445 while (!sync);
446
447 //current_frame_number++;
448 //if (last_frame_number < current_frame_number) last_frame_number = current_frame_number;
449
450 return headerstring;
451 }
452
453 public boolean isSyncMark(int headerstring, int syncmode, int word)
454 {
455 boolean sync = false;
456
457 if (syncmode == INITIAL_SYNC)
458 {
459 //sync = ((headerstring & 0xFFF00000) == 0xFFF00000);
460 sync = ((headerstring & 0xFFE00000) == 0xFFE00000); // SZD: MPEG 2.5
461 }
462 else
463 {
464 sync = ((headerstring & 0xFFF80C00) == word) &&
465 (((headerstring & 0x000000C0) == 0x000000C0) == single_ch_mode);
466 }
467
468 // filter out invalid sample rate
469 if (sync)
470 sync = (((headerstring >>> 10) & 3)!=3);
471 // filter out invalid layer
472 if (sync)
473 sync = (((headerstring >>> 17) & 3)!=0);
474 // filter out invalid version
475 if (sync)
476 sync = (((headerstring >>> 19) & 3)!=1);
477
478 return sync;
479 }
480
481 /**
482 * Reads the data for the next frame. The frame is not parsed
483 * until parse frame is called.
484 */
485 int read_frame_data(int bytesize) throws BitstreamException
486 {
487 int numread = 0;
488 numread = readFully(frame_bytes, 0, bytesize);
489 framesize = bytesize;
490 wordpointer = -1;
491 bitindex = -1;
492 return numread;
493 }
494
495 /**
496 * Parses the data previously read with read_frame_data().
497 */
498 void parse_frame() throws BitstreamException
499 {
500 // Convert Bytes read to int
501 int b=0;
502 byte[] byteread = frame_bytes;
503 int bytesize = framesize;
504
505 // Check ID3v1 TAG (True only if last frame).
506 //for (int t=0;t<(byteread.length)-2;t++)
507 //{
508 // if ((byteread[t]=='T') && (byteread[t+1]=='A') && (byteread[t+2]=='G'))
509 // {
510 // System.out.println("ID3v1 detected at offset "+t);
511 // throw newBitstreamException(INVALIDFRAME, null);
512 // }
513 //}
514
515 for (int k=0;k<bytesize;k=k+4)
516 {
517 int convert = 0;
518 byte b0 = 0;
519 byte b1 = 0;
520 byte b2 = 0;
521 byte b3 = 0;
522 b0 = byteread[k];
523 if (k+1<bytesize) b1 = byteread[k+1];
524 if (k+2<bytesize) b2 = byteread[k+2];
525 if (k+3<bytesize) b3 = byteread[k+3];
526 framebuffer[b++] = ((b0 << 24) &0xFF000000) | ((b1 << 16) & 0x00FF0000) | ((b2 << 8) & 0x0000FF00) | (b3 & 0x000000FF);
527 }
528 wordpointer = 0;
529 bitindex = 0;
530 }
531
532 /**
533 * Read bits from buffer into the lower bits of an unsigned int.
534 * The LSB contains the latest read bit of the stream.
535 * (1 <= number_of_bits <= 16)
536 */
537 public int get_bits(int number_of_bits)
538 {
539 int returnvalue = 0;
540 int sum = bitindex + number_of_bits;
541
542 // E.B
543 // There is a problem here, wordpointer could be -1 ?!
544 if (wordpointer < 0) wordpointer = 0;
545 // E.B : End.
546
547 if (sum <= 32)
548 {
549 // all bits contained in *wordpointer
550 returnvalue = (framebuffer[wordpointer] >>> (32 - sum)) & bitmask[number_of_bits];
551 // returnvalue = (wordpointer[0] >> (32 - sum)) & bitmask[number_of_bits];
552 if ((bitindex += number_of_bits) == 32)
553 {
554 bitindex = 0;
555 wordpointer++; // added by me!
556 }
557 return returnvalue;
558 }
559
560 // E.B : Check that ?
561 //((short[])&returnvalue)[0] = ((short[])wordpointer + 1)[0];
562 //wordpointer++; // Added by me!
563 //((short[])&returnvalue + 1)[0] = ((short[])wordpointer)[0];
564 int Right = (framebuffer[wordpointer] & 0x0000FFFF);
565 wordpointer++;
566 int Left = (framebuffer[wordpointer] & 0xFFFF0000);
567 returnvalue = ((Right << 16) & 0xFFFF0000) | ((Left >>> 16)& 0x0000FFFF);
568
569 returnvalue >>>= 48 - sum; // returnvalue >>= 16 - (number_of_bits - (32 - bitindex))
570 returnvalue &= bitmask[number_of_bits];
571 bitindex = sum - 32;
572 return returnvalue;
573}
574
575 /**
576 * Set the word we want to sync the header to.
577 * In Big-Endian byte order
578 */
579 void set_syncword(int syncword0)
580 {
581 syncword = syncword0 & 0xFFFFFF3F;
582 single_ch_mode = ((syncword0 & 0x000000C0) == 0x000000C0);
583 }
584 /**
585 * Reads the exact number of bytes from the source
586 * input stream into a byte array.
587 *
588 * @param b The byte array to read the specified number
589 * of bytes into.
590 * @param offs The index in the array where the first byte
591 * read should be stored.
592 * @param len the number of bytes to read.
593 *
594 * @exception BitstreamException is thrown if the specified
595 * number of bytes could not be read from the stream.
596 */
597 private int readFully(byte[] b, int offs, int len)
598 throws BitstreamException
599 {
600 int nRead = 0;
601 try
602 {
603 while (len > 0)
604 {
605 int bytesread = source.read(b, offs, len);
606 if (bytesread == -1)
607 {
608 while (len-->0)
609 {
610 b[offs++] = 0;
611 }
612 break;
613 //throw newBitstreamException(UNEXPECTED_EOF, new EOFException());
614 }
615 nRead = nRead + bytesread;
616 offs += bytesread;
617 len -= bytesread;
618 }
619 }
620 catch (IOException ex)
621 {
622 throw newBitstreamException(STREAM_ERROR, ex);
623 }
624 return nRead;
625 }
626
627 /**
628 * Simlar to readFully, but doesn't throw exception when
629 * EOF is reached.
630 */
631 private int readBytes(byte[] b, int offs, int len)
632 throws BitstreamException
633 {
634 int totalBytesRead = 0;
635 try
636 {
637 while (len > 0)
638 {
639 int bytesread = source.read(b, offs, len);
640 if (bytesread == -1)
641 {
642 break;
643 }
644 totalBytesRead += bytesread;
645 offs += bytesread;
646 len -= bytesread;
647 }
648 }
649 catch (IOException ex)
650 {
651 throw newBitstreamException(STREAM_ERROR, ex);
652 }
653 return totalBytesRead;
654 }
655}
diff --git a/songdbj/javazoom/jl/decoder/BitstreamErrors.java b/songdbj/javazoom/jl/decoder/BitstreamErrors.java
new file mode 100644
index 0000000000..2bdee6d797
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/BitstreamErrors.java
@@ -0,0 +1,72 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 11/17/04 INVALIDFRAME code added. javalayer@javazoom.net
4 * 12/12/99 Initial version. mdm@techie.com
5 *-----------------------------------------------------------------------
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *----------------------------------------------------------------------
20 */
21
22package javazoom.jl.decoder;
23
24/**
25 * This interface describes all error codes that can be thrown
26 * in <code>BistreamException</code>s.
27 *
28 * @see BitstreamException
29 *
30 * @author MDM 12/12/99
31 * @since 0.0.6
32 */
33
34public interface BitstreamErrors extends JavaLayerErrors
35{
36
37 /**
38 * An undeterminable error occurred.
39 */
40 static public final int UNKNOWN_ERROR = BITSTREAM_ERROR + 0;
41
42 /**
43 * The header describes an unknown sample rate.
44 */
45 static public final int UNKNOWN_SAMPLE_RATE = BITSTREAM_ERROR + 1;
46
47 /**
48 * A problem occurred reading from the stream.
49 */
50 static public final int STREAM_ERROR = BITSTREAM_ERROR + 2;
51
52 /**
53 * The end of the stream was reached prematurely.
54 */
55 static public final int UNEXPECTED_EOF = BITSTREAM_ERROR + 3;
56
57 /**
58 * The end of the stream was reached.
59 */
60 static public final int STREAM_EOF = BITSTREAM_ERROR + 4;
61
62 /**
63 * Frame data are missing.
64 */
65 static public final int INVALIDFRAME = BITSTREAM_ERROR + 5;
66
67 /**
68 *
69 */
70 static public final int BITSTREAM_LAST = 0x1ff;
71
72}
diff --git a/songdbj/javazoom/jl/decoder/BitstreamException.java b/songdbj/javazoom/jl/decoder/BitstreamException.java
new file mode 100644
index 0000000000..99faa8962d
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/BitstreamException.java
@@ -0,0 +1,71 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23/**
24 * Instances of <code>BitstreamException</code> are thrown
25 * when operations on a <code>Bitstream</code> fail.
26 * <p>
27 * The exception provides details of the exception condition
28 * in two ways:
29 * <ol><li>
30 * as an error-code describing the nature of the error
31 * </li><br></br><li>
32 * as the <code>Throwable</code> instance, if any, that was thrown
33 * indicating that an exceptional condition has occurred.
34 * </li></ol></p>
35 *
36 * @since 0.0.6
37 * @author MDM 12/12/99
38 */
39
40public class BitstreamException extends JavaLayerException
41 implements BitstreamErrors
42{
43 private int errorcode = UNKNOWN_ERROR;
44
45 public BitstreamException(String msg, Throwable t)
46 {
47 super(msg, t);
48 }
49
50 public BitstreamException(int errorcode, Throwable t)
51 {
52 this(getErrorString(errorcode), t);
53 this.errorcode = errorcode;
54 }
55
56 public int getErrorCode()
57 {
58 return errorcode;
59 }
60
61
62 static public String getErrorString(int errorcode)
63 {
64 // REVIEW: use resource bundle to map error codes
65 // to locale-sensitive strings.
66
67 return "Bitstream errorcode "+Integer.toHexString(errorcode);
68 }
69
70
71}
diff --git a/songdbj/javazoom/jl/decoder/Control.java b/songdbj/javazoom/jl/decoder/Control.java
new file mode 100644
index 0000000000..080ed5215e
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/Control.java
@@ -0,0 +1,57 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *-----------------------------------------------------------------------
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *----------------------------------------------------------------------
18 */
19
20package javazoom.jl.decoder;
21
22/**
23 * Work in progress.
24 */
25
26public interface Control
27{
28
29 /**
30 * Starts playback of the media presented by this control.
31 */
32 public void start();
33
34 /**
35 * Stops playback of the media presented by this control.
36 */
37 public void stop();
38
39 public boolean isPlaying();
40
41 public void pause();
42
43
44 public boolean isRandomAccess();
45
46 /**
47 * Retrieves the current position.
48 */
49 public double getPosition();
50
51 /**
52 *
53 */
54 public void setPosition(double d);
55
56
57}
diff --git a/songdbj/javazoom/jl/decoder/Crc16.java b/songdbj/javazoom/jl/decoder/Crc16.java
new file mode 100644
index 0000000000..c35cc19341
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/Crc16.java
@@ -0,0 +1,70 @@
1/*
2 * 11/19/04 : 1.0 moved to LGPL.
3 *
4 * 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net
5 *
6 * @(#) crc.h 1.5, last edit: 6/15/94 16:55:32
7 * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
8 * @(#) Berlin University of Technology
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25package javazoom.jl.decoder;
26
27/**
28 * 16-Bit CRC checksum
29 */
30public final class Crc16
31{
32 private static short polynomial=(short)0x8005;
33 private short crc;
34
35 /**
36 * Dummy Constructor
37 */
38 public Crc16()
39 {
40 crc = (short) 0xFFFF;
41 }
42
43 /**
44 * Feed a bitstring to the crc calculation (0 < length <= 32).
45 */
46 public void add_bits (int bitstring, int length)
47 {
48 int bitmask = 1 << (length - 1);
49 do
50 if (((crc & 0x8000) == 0) ^ ((bitstring & bitmask) == 0 ))
51 {
52 crc <<= 1;
53 crc ^= polynomial;
54 }
55 else
56 crc <<= 1;
57 while ((bitmask >>>= 1) != 0);
58 }
59
60 /**
61 * Return the calculated checksum.
62 * Erase it for next calls to add_bits().
63 */
64 public short checksum()
65 {
66 short sum = crc;
67 crc = (short) 0xFFFF;
68 return sum;
69 }
70}
diff --git a/songdbj/javazoom/jl/decoder/Decoder.java b/songdbj/javazoom/jl/decoder/Decoder.java
new file mode 100644
index 0000000000..076f9dea27
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/Decoder.java
@@ -0,0 +1,357 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 01/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23/**
24 * The <code>Decoder</code> class encapsulates the details of
25 * decoding an MPEG audio frame.
26 *
27 * @author MDM
28 * @version 0.0.7 12/12/99
29 * @since 0.0.5
30 */
31public class Decoder implements DecoderErrors
32{
33 static private final Params DEFAULT_PARAMS = new Params();
34
35 /**
36 * The Bistream from which the MPEG audio frames are read.
37 */
38 //private Bitstream stream;
39
40 /**
41 * The Obuffer instance that will receive the decoded
42 * PCM samples.
43 */
44 private Obuffer output;
45
46 /**
47 * Synthesis filter for the left channel.
48 */
49 private SynthesisFilter filter1;
50
51 /**
52 * Sythesis filter for the right channel.
53 */
54 private SynthesisFilter filter2;
55
56 /**
57 * The decoder used to decode layer III frames.
58 */
59 private LayerIIIDecoder l3decoder;
60 private LayerIIDecoder l2decoder;
61 private LayerIDecoder l1decoder;
62
63 private int outputFrequency;
64 private int outputChannels;
65
66 private Equalizer equalizer = new Equalizer();
67
68 private Params params;
69
70 private boolean initialized;
71
72
73 /**
74 * Creates a new <code>Decoder</code> instance with default
75 * parameters.
76 */
77
78 public Decoder()
79 {
80 this(null);
81 }
82
83 /**
84 * Creates a new <code>Decoder</code> instance with default
85 * parameters.
86 *
87 * @param params The <code>Params</code> instance that describes
88 * the customizable aspects of the decoder.
89 */
90 public Decoder(Params params0)
91 {
92 if (params0==null)
93 params0 = DEFAULT_PARAMS;
94
95 params = params0;
96
97 Equalizer eq = params.getInitialEqualizerSettings();
98 if (eq!=null)
99 {
100 equalizer.setFrom(eq);
101 }
102 }
103
104 static public Params getDefaultParams()
105 {
106 return (Params)DEFAULT_PARAMS.clone();
107 }
108
109 public void setEqualizer(Equalizer eq)
110 {
111 if (eq==null)
112 eq = Equalizer.PASS_THRU_EQ;
113
114 equalizer.setFrom(eq);
115
116 float[] factors = equalizer.getBandFactors();
117
118 if (filter1!=null)
119 filter1.setEQ(factors);
120
121 if (filter2!=null)
122 filter2.setEQ(factors);
123 }
124
125 /**
126 * Decodes one frame from an MPEG audio bitstream.
127 *
128 * @param header The header describing the frame to decode.
129 * @param bitstream The bistream that provides the bits for te body of the frame.
130 *
131 * @return A SampleBuffer containing the decoded samples.
132 */
133 public Obuffer decodeFrame(Header header, Bitstream stream)
134 throws DecoderException
135 {
136 if (!initialized)
137 {
138 initialize(header);
139 }
140
141 int layer = header.layer();
142
143 output.clear_buffer();
144
145 FrameDecoder decoder = retrieveDecoder(header, stream, layer);
146
147 decoder.decodeFrame();
148
149 output.write_buffer(1);
150
151 return output;
152 }
153
154 /**
155 * Changes the output buffer. This will take effect the next time
156 * decodeFrame() is called.
157 */
158 public void setOutputBuffer(Obuffer out)
159 {
160 output = out;
161 }
162
163 /**
164 * Retrieves the sample frequency of the PCM samples output
165 * by this decoder. This typically corresponds to the sample
166 * rate encoded in the MPEG audio stream.
167 *
168 * @param the sample rate (in Hz) of the samples written to the
169 * output buffer when decoding.
170 */
171 public int getOutputFrequency()
172 {
173 return outputFrequency;
174 }
175
176 /**
177 * Retrieves the number of channels of PCM samples output by
178 * this decoder. This usually corresponds to the number of
179 * channels in the MPEG audio stream, although it may differ.
180 *
181 * @return The number of output channels in the decoded samples: 1
182 * for mono, or 2 for stereo.
183 *
184 */
185 public int getOutputChannels()
186 {
187 return outputChannels;
188 }
189
190 /**
191 * Retrieves the maximum number of samples that will be written to
192 * the output buffer when one frame is decoded. This can be used to
193 * help calculate the size of other buffers whose size is based upon
194 * the number of samples written to the output buffer. NB: this is
195 * an upper bound and fewer samples may actually be written, depending
196 * upon the sample rate and number of channels.
197 *
198 * @return The maximum number of samples that are written to the
199 * output buffer when decoding a single frame of MPEG audio.
200 */
201 public int getOutputBlockSize()
202 {
203 return Obuffer.OBUFFERSIZE;
204 }
205
206
207 protected DecoderException newDecoderException(int errorcode)
208 {
209 return new DecoderException(errorcode, null);
210 }
211
212 protected DecoderException newDecoderException(int errorcode, Throwable throwable)
213 {
214 return new DecoderException(errorcode, throwable);
215 }
216
217 protected FrameDecoder retrieveDecoder(Header header, Bitstream stream, int layer)
218 throws DecoderException
219 {
220 FrameDecoder decoder = null;
221
222 // REVIEW: allow channel output selection type
223 // (LEFT, RIGHT, BOTH, DOWNMIX)
224 switch (layer)
225 {
226 case 3:
227 if (l3decoder==null)
228 {
229 l3decoder = new LayerIIIDecoder(stream,
230 header, filter1, filter2,
231 output, OutputChannels.BOTH_CHANNELS);
232 }
233
234 decoder = l3decoder;
235 break;
236 case 2:
237 if (l2decoder==null)
238 {
239 l2decoder = new LayerIIDecoder();
240 l2decoder.create(stream,
241 header, filter1, filter2,
242 output, OutputChannels.BOTH_CHANNELS);
243 }
244 decoder = l2decoder;
245 break;
246 case 1:
247 if (l1decoder==null)
248 {
249 l1decoder = new LayerIDecoder();
250 l1decoder.create(stream,
251 header, filter1, filter2,
252 output, OutputChannels.BOTH_CHANNELS);
253 }
254 decoder = l1decoder;
255 break;
256 }
257
258 if (decoder==null)
259 {
260 throw newDecoderException(UNSUPPORTED_LAYER, null);
261 }
262
263 return decoder;
264 }
265
266 private void initialize(Header header)
267 throws DecoderException
268 {
269
270 // REVIEW: allow customizable scale factor
271 float scalefactor = 32700.0f;
272
273 int mode = header.mode();
274 int layer = header.layer();
275 int channels = mode==Header.SINGLE_CHANNEL ? 1 : 2;
276
277
278 // set up output buffer if not set up by client.
279 if (output==null)
280 output = new SampleBuffer(header.frequency(), channels);
281
282 float[] factors = equalizer.getBandFactors();
283 filter1 = new SynthesisFilter(0, scalefactor, factors);
284
285 // REVIEW: allow mono output for stereo
286 if (channels==2)
287 filter2 = new SynthesisFilter(1, scalefactor, factors);
288
289 outputChannels = channels;
290 outputFrequency = header.frequency();
291
292 initialized = true;
293 }
294
295 /**
296 * The <code>Params</code> class presents the customizable
297 * aspects of the decoder.
298 * <p>
299 * Instances of this class are not thread safe.
300 */
301 public static class Params implements Cloneable
302 {
303 private OutputChannels outputChannels = OutputChannels.BOTH;
304
305 private Equalizer equalizer = new Equalizer();
306
307 public Params()
308 {
309 }
310
311 public Object clone()
312 {
313 try
314 {
315 return super.clone();
316 }
317 catch (CloneNotSupportedException ex)
318 {
319 throw new InternalError(this+": "+ex);
320 }
321 }
322
323 public void setOutputChannels(OutputChannels out)
324 {
325 if (out==null)
326 throw new NullPointerException("out");
327
328 outputChannels = out;
329 }
330
331 public OutputChannels getOutputChannels()
332 {
333 return outputChannels;
334 }
335
336 /**
337 * Retrieves the equalizer settings that the decoder's equalizer
338 * will be initialized from.
339 * <p>
340 * The <code>Equalizer</code> instance returned
341 * cannot be changed in real time to affect the
342 * decoder output as it is used only to initialize the decoders
343 * EQ settings. To affect the decoder's output in realtime,
344 * use the Equalizer returned from the getEqualizer() method on
345 * the decoder.
346 *
347 * @return The <code>Equalizer</code> used to initialize the
348 * EQ settings of the decoder.
349 */
350 public Equalizer getInitialEqualizerSettings()
351 {
352 return equalizer;
353 }
354
355 };
356}
357
diff --git a/songdbj/javazoom/jl/decoder/DecoderErrors.java b/songdbj/javazoom/jl/decoder/DecoderErrors.java
new file mode 100644
index 0000000000..66c1935051
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/DecoderErrors.java
@@ -0,0 +1,38 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 01/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23/**
24 * This interface provides constants describing the error
25 * codes used by the Decoder to indicate errors.
26 *
27 * @author MDM
28 */
29public interface DecoderErrors extends JavaLayerErrors
30{
31
32 static public final int UNKNOWN_ERROR = DECODER_ERROR + 0;
33
34 /**
35 * Layer not supported by the decoder.
36 */
37 static public final int UNSUPPORTED_LAYER = DECODER_ERROR + 1;
38}
diff --git a/songdbj/javazoom/jl/decoder/DecoderException.java b/songdbj/javazoom/jl/decoder/DecoderException.java
new file mode 100644
index 0000000000..b75710870f
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/DecoderException.java
@@ -0,0 +1,61 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 01/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23/**
24 * The <code>DecoderException</code> represents the class of
25 * errors that can occur when decoding MPEG audio.
26 *
27 * @author MDM
28 */
29public class DecoderException extends JavaLayerException
30 implements DecoderErrors
31{
32 private int errorcode = UNKNOWN_ERROR;
33
34 public DecoderException(String msg, Throwable t)
35 {
36 super(msg, t);
37 }
38
39 public DecoderException(int errorcode, Throwable t)
40 {
41 this(getErrorString(errorcode), t);
42 this.errorcode = errorcode;
43 }
44
45 public int getErrorCode()
46 {
47 return errorcode;
48 }
49
50
51 static public String getErrorString(int errorcode)
52 {
53 // REVIEW: use resource file to map error codes
54 // to locale-sensitive strings.
55
56 return "Decoder errorcode "+Integer.toHexString(errorcode);
57 }
58
59
60}
61
diff --git a/songdbj/javazoom/jl/decoder/Equalizer.java b/songdbj/javazoom/jl/decoder/Equalizer.java
new file mode 100644
index 0000000000..57545a939d
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/Equalizer.java
@@ -0,0 +1,227 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21
22package javazoom.jl.decoder;
23
24/**
25 * The <code>Equalizer</code> class can be used to specify
26 * equalization settings for the MPEG audio decoder.
27 * <p>
28 * The equalizer consists of 32 band-pass filters.
29 * Each band of the equalizer can take on a fractional value between
30 * -1.0 and +1.0.
31 * At -1.0, the input signal is attenuated by 6dB, at +1.0 the signal is
32 * amplified by 6dB.
33 *
34 * @see Decoder
35 *
36 * @author MDM
37 */
38public final class Equalizer
39{
40 /**
41 * Equalizer setting to denote that a given band will not be
42 * present in the output signal.
43 */
44 static public final float BAND_NOT_PRESENT = Float.NEGATIVE_INFINITY;
45
46 static public final Equalizer PASS_THRU_EQ = new Equalizer();
47
48 private static final int BANDS = 32;
49
50 private final float[] settings = new float[BANDS];
51
52 /**
53 * Creates a new <code>Equalizer</code> instance.
54 */
55 public Equalizer()
56 {
57 }
58
59// private Equalizer(float b1, float b2, float b3, float b4, float b5,
60// float b6, float b7, float b8, float b9, float b10, float b11,
61// float b12, float b13, float b14, float b15, float b16,
62// float b17, float b18, float b19, float b20);
63
64 public Equalizer(float[] settings)
65 {
66 setFrom(settings);
67 }
68
69 public Equalizer(EQFunction eq)
70 {
71 setFrom(eq);
72 }
73
74 public void setFrom(float[] eq)
75 {
76 reset();
77 int max = (eq.length > BANDS) ? BANDS : eq.length;
78
79 for (int i=0; i<max; i++)
80 {
81 settings[i] = limit(eq[i]);
82 }
83 }
84
85 public void setFrom(EQFunction eq)
86 {
87 reset();
88 int max = BANDS;
89
90 for (int i=0; i<max; i++)
91 {
92 settings[i] = limit(eq.getBand(i));
93 }
94 }
95
96 /**
97 * Sets the bands of this equalizer to the value the bands of
98 * another equalizer. Bands that are not present in both equalizers are ignored.
99 */
100 public void setFrom(Equalizer eq)
101 {
102 if (eq!=this)
103 {
104 setFrom(eq.settings);
105 }
106 }
107
108
109
110
111 /**
112 * Sets all bands to 0.0
113 */
114 public void reset()
115 {
116 for (int i=0; i<BANDS; i++)
117 {
118 settings[i] = 0.0f;
119 }
120 }
121
122
123 /**
124 * Retrieves the number of bands present in this equalizer.
125 */
126 public int getBandCount()
127 {
128 return settings.length;
129 }
130
131 public float setBand(int band, float neweq)
132 {
133 float eq = 0.0f;
134
135 if ((band>=0) && (band<BANDS))
136 {
137 eq = settings[band];
138 settings[band] = limit(neweq);
139 }
140
141 return eq;
142 }
143
144
145
146 /**
147 * Retrieves the eq setting for a given band.
148 */
149 public float getBand(int band)
150 {
151 float eq = 0.0f;
152
153 if ((band>=0) && (band<BANDS))
154 {
155 eq = settings[band];
156 }
157
158 return eq;
159 }
160
161 private float limit(float eq)
162 {
163 if (eq==BAND_NOT_PRESENT)
164 return eq;
165 if (eq > 1.0f)
166 return 1.0f;
167 if (eq < -1.0f)
168 return -1.0f;
169
170 return eq;
171 }
172
173 /**
174 * Retrieves an array of floats whose values represent a
175 * scaling factor that can be applied to linear samples
176 * in each band to provide the equalization represented by
177 * this instance.
178 *
179 * @return an array of factors that can be applied to the
180 * subbands.
181 */
182 float[] getBandFactors()
183 {
184 float[] factors = new float[BANDS];
185 for (int i=0, maxCount=BANDS; i<maxCount; i++)
186 {
187 factors[i] = getBandFactor(settings[i]);
188 }
189
190 return factors;
191 }
192
193 /**
194 * Converts an equalizer band setting to a sample factor.
195 * The factor is determined by the function f = 2^n where
196 * n is the equalizer band setting in the range [-1.0,1.0].
197 *
198 */
199 float getBandFactor(float eq)
200 {
201 if (eq==BAND_NOT_PRESENT)
202 return 0.0f;
203
204 float f = (float)Math.pow(2.0, eq);
205 return f;
206 }
207
208
209 static abstract public class EQFunction
210 {
211 /**
212 * Returns the setting of a band in the equalizer.
213 *
214 * @param band The index of the band to retrieve the setting
215 * for.
216 *
217 * @return the setting of the specified band. This is a value between
218 * -1 and +1.
219 */
220 public float getBand(int band)
221 {
222 return 0.0f;
223 }
224
225 }
226
227}
diff --git a/songdbj/javazoom/jl/decoder/FrameDecoder.java b/songdbj/javazoom/jl/decoder/FrameDecoder.java
new file mode 100644
index 0000000000..eec6ac6a22
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/FrameDecoder.java
@@ -0,0 +1,38 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23/**
24 * Implementations of FrameDecoder are responsible for decoding
25 * an MPEG audio frame.
26 *
27 */
28//REVIEW: the interface currently is too thin. There should be
29// methods to specify the output buffer, the synthesis filters and
30// possibly other objects used by the decoder.
31public interface FrameDecoder
32{
33 /**
34 * Decodes one frame of MPEG audio.
35 */
36 public void decodeFrame();
37
38}
diff --git a/songdbj/javazoom/jl/decoder/Header.java b/songdbj/javazoom/jl/decoder/Header.java
new file mode 100644
index 0000000000..e85fe19f64
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/Header.java
@@ -0,0 +1,762 @@
1/*
2 * 11/19/04 : 1.0 moved to LGPL.
3 * VBRI header support added, E.B javalayer@javazoom.net
4 *
5 * 12/04/03 : VBR (XING) header support added, E.B javalayer@javazoom.net
6 *
7 * 02/13/99 : Java Conversion by JavaZOOM , E.B javalayer@javazoom.net
8 *
9 * Declarations for MPEG header class
10 * A few layer III, MPEG-2 LSF, and seeking modifications made by Jeff Tsay.
11 * Last modified : 04/19/97
12 *
13 * @(#) header.h 1.7, last edit: 6/15/94 16:55:33
14 * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
15 * @(#) Berlin University of Technology
16 *-----------------------------------------------------------------------
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU Library General Public License as published
19 * by the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU Library General Public License for more details.
26 *
27 * You should have received a copy of the GNU Library General Public
28 * License along with this program; if not, write to the Free Software
29 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 *----------------------------------------------------------------------
31 */
32package javazoom.jl.decoder;
33
34/**
35 * Class for extracting information from a frame header.
36 */
37public final class Header
38{
39 public static final int[][] frequencies =
40 {{22050, 24000, 16000, 1},
41 {44100, 48000, 32000, 1},
42 {11025, 12000, 8000, 1}}; // SZD: MPEG25
43
44 /**
45 * Constant for MPEG-2 LSF version
46 */
47 public static final int MPEG2_LSF = 0;
48 public static final int MPEG25_LSF = 2; // SZD
49
50 /**
51 * Constant for MPEG-1 version
52 */
53 public static final int MPEG1 = 1;
54
55 public static final int STEREO = 0;
56 public static final int JOINT_STEREO = 1;
57 public static final int DUAL_CHANNEL = 2;
58 public static final int SINGLE_CHANNEL = 3;
59 public static final int FOURTYFOUR_POINT_ONE = 0;
60 public static final int FOURTYEIGHT=1;
61 public static final int THIRTYTWO=2;
62
63 private int h_layer, h_protection_bit, h_bitrate_index,
64 h_padding_bit, h_mode_extension;
65 private int h_version;
66 private int h_mode;
67 private int h_sample_frequency;
68 private int h_number_of_subbands, h_intensity_stereo_bound;
69 private boolean h_copyright, h_original;
70 // VBR support added by E.B
71 private double[] h_vbr_time_per_frame = {-1, 384, 1152, 1152};
72 private boolean h_vbr;
73 private int h_vbr_frames;
74 private int h_vbr_scale;
75 private int h_vbr_bytes;
76 private byte[] h_vbr_toc;
77
78 private byte syncmode = Bitstream.INITIAL_SYNC;
79 private Crc16 crc;
80
81 public short checksum;
82 public int framesize;
83 public int nSlots;
84
85 private int _headerstring = -1; // E.B
86
87 Header()
88 {
89 }
90 public String toString()
91 {
92 StringBuffer buffer = new StringBuffer(200);
93 buffer.append("Layer ");
94 buffer.append(layer_string());
95 buffer.append(" frame ");
96 buffer.append(mode_string());
97 buffer.append(' ');
98 buffer.append(version_string());
99 if (!checksums())
100 buffer.append(" no");
101 buffer.append(" checksums");
102 buffer.append(' ');
103 buffer.append(sample_frequency_string());
104 buffer.append(',');
105 buffer.append(' ');
106 buffer.append(bitrate_string());
107
108 String s = buffer.toString();
109 return s;
110 }
111
112 /**
113 * Read a 32-bit header from the bitstream.
114 */
115 void read_header(Bitstream stream, Crc16[] crcp) throws BitstreamException
116 {
117 int headerstring;
118 int channel_bitrate;
119 boolean sync = false;
120 do
121 {
122 headerstring = stream.syncHeader(syncmode);
123 _headerstring = headerstring; // E.B
124 if (syncmode == Bitstream.INITIAL_SYNC)
125 {
126 h_version = ((headerstring >>> 19) & 1);
127 if (((headerstring >>> 20) & 1) == 0) // SZD: MPEG2.5 detection
128 if (h_version == MPEG2_LSF)
129 h_version = MPEG25_LSF;
130 else
131 throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);
132 if ((h_sample_frequency = ((headerstring >>> 10) & 3)) == 3)
133 {
134 throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);
135 }
136 }
137 h_layer = 4 - (headerstring >>> 17) & 3;
138 h_protection_bit = (headerstring >>> 16) & 1;
139 h_bitrate_index = (headerstring >>> 12) & 0xF;
140 h_padding_bit = (headerstring >>> 9) & 1;
141 h_mode = ((headerstring >>> 6) & 3);
142 h_mode_extension = (headerstring >>> 4) & 3;
143 if (h_mode == JOINT_STEREO)
144 h_intensity_stereo_bound = (h_mode_extension << 2) + 4;
145 else
146 h_intensity_stereo_bound = 0; // should never be used
147 if (((headerstring >>> 3) & 1) == 1)
148 h_copyright = true;
149 if (((headerstring >>> 2) & 1) == 1)
150 h_original = true;
151 // calculate number of subbands:
152 if (h_layer == 1)
153 h_number_of_subbands = 32;
154 else
155 {
156 channel_bitrate = h_bitrate_index;
157 // calculate bitrate per channel:
158 if (h_mode != SINGLE_CHANNEL)
159 if (channel_bitrate == 4)
160 channel_bitrate = 1;
161 else
162 channel_bitrate -= 4;
163 if ((channel_bitrate == 1) || (channel_bitrate == 2))
164 if (h_sample_frequency == THIRTYTWO)
165 h_number_of_subbands = 12;
166 else
167 h_number_of_subbands = 8;
168 else if ((h_sample_frequency == FOURTYEIGHT) || ((channel_bitrate >= 3) && (channel_bitrate <= 5)))
169 h_number_of_subbands = 27;
170 else
171 h_number_of_subbands = 30;
172 }
173 if (h_intensity_stereo_bound > h_number_of_subbands)
174 h_intensity_stereo_bound = h_number_of_subbands;
175 // calculate framesize and nSlots
176 calculate_framesize();
177 // read framedata:
178 int framesizeloaded = stream.read_frame_data(framesize);
179 if ((framesize >=0) && (framesizeloaded != framesize))
180 {
181 // Data loaded does not match to expected framesize,
182 // it might be an ID3v1 TAG. (Fix 11/17/04).
183 throw stream.newBitstreamException(Bitstream.INVALIDFRAME);
184 }
185 if (stream.isSyncCurrentPosition(syncmode))
186 {
187 if (syncmode == Bitstream.INITIAL_SYNC)
188 {
189 syncmode = Bitstream.STRICT_SYNC;
190 stream.set_syncword(headerstring & 0xFFF80CC0);
191 }
192 sync = true;
193 }
194 else
195 {
196 stream.unreadFrame();
197 }
198 }
199 while (!sync);
200 stream.parse_frame();
201 if (h_protection_bit == 0)
202 {
203 // frame contains a crc checksum
204 checksum = (short) stream.get_bits(16);
205 if (crc == null)
206 crc = new Crc16();
207 crc.add_bits(headerstring, 16);
208 crcp[0] = crc;
209 }
210 else
211 crcp[0] = null;
212 if (h_sample_frequency == FOURTYFOUR_POINT_ONE)
213 {
214 /*
215 if (offset == null)
216 {
217 int max = max_number_of_frames(stream);
218 offset = new int[max];
219 for(int i=0; i<max; i++) offset[i] = 0;
220 }
221 // E.B : Investigate more
222 int cf = stream.current_frame();
223 int lf = stream.last_frame();
224 if ((cf > 0) && (cf == lf))
225 {
226 offset[cf] = offset[cf-1] + h_padding_bit;
227 }
228 else
229 {
230 offset[0] = h_padding_bit;
231 }
232 */
233 }
234 }
235
236 /**
237 * Parse frame to extract optionnal VBR frame.
238 * @param firstframe
239 * @author E.B (javalayer@javazoom.net)
240 */
241 void parseVBR(byte[] firstframe) throws BitstreamException
242 {
243 // Trying Xing header.
244 String xing = "Xing";
245 byte tmp[] = new byte[4];
246 int offset = 0;
247 // Compute "Xing" offset depending on MPEG version and channels.
248 if (h_version == MPEG1)
249 {
250 if (h_mode == SINGLE_CHANNEL) offset=21-4;
251 else offset=36-4;
252 }
253 else
254 {
255 if (h_mode == SINGLE_CHANNEL) offset=13-4;
256 else offset = 21-4;
257 }
258 try
259 {
260 System.arraycopy(firstframe, offset, tmp, 0, 4);
261 // Is "Xing" ?
262 if (xing.equals(new String(tmp)))
263 {
264 //Yes.
265 h_vbr = true;
266 h_vbr_frames = -1;
267 h_vbr_bytes = -1;
268 h_vbr_scale = -1;
269 h_vbr_toc = new byte[100];
270
271 int length = 4;
272 // Read flags.
273 byte flags[] = new byte[4];
274 System.arraycopy(firstframe, offset + length, flags, 0, flags.length);
275 length += flags.length;
276 // Read number of frames (if available).
277 if ((flags[3] & (byte) (1 << 0)) != 0)
278 {
279 System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
280 h_vbr_frames = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;
281 length += 4;
282 }
283 // Read size (if available).
284 if ((flags[3] & (byte) (1 << 1)) != 0)
285 {
286 System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
287 h_vbr_bytes = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;
288 length += 4;
289 }
290 // Read TOC (if available).
291 if ((flags[3] & (byte) (1 << 2)) != 0)
292 {
293 System.arraycopy(firstframe, offset + length, h_vbr_toc, 0, h_vbr_toc.length);
294 length += h_vbr_toc.length;
295 }
296 // Read scale (if available).
297 if ((flags[3] & (byte) (1 << 3)) != 0)
298 {
299 System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
300 h_vbr_scale = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;
301 length += 4;
302 }
303 //System.out.println("VBR:"+xing+" Frames:"+ h_vbr_frames +" Size:"+h_vbr_bytes);
304 }
305 }
306 catch (ArrayIndexOutOfBoundsException e)
307 {
308 throw new BitstreamException("XingVBRHeader Corrupted",e);
309 }
310
311 // Trying VBRI header.
312 String vbri = "VBRI";
313 offset = 36-4;
314 try
315 {
316 System.arraycopy(firstframe, offset, tmp, 0, 4);
317 // Is "VBRI" ?
318 if (vbri.equals(new String(tmp)))
319 {
320 //Yes.
321 h_vbr = true;
322 h_vbr_frames = -1;
323 h_vbr_bytes = -1;
324 h_vbr_scale = -1;
325 h_vbr_toc = new byte[100];
326 // Bytes.
327 int length = 4 + 6;
328 System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
329 h_vbr_bytes = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;
330 length += 4;
331 // Frames.
332 System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
333 h_vbr_frames = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;
334 length += 4;
335 //System.out.println("VBR:"+vbri+" Frames:"+ h_vbr_frames +" Size:"+h_vbr_bytes);
336 // TOC
337 // TODO
338 }
339 }
340 catch (ArrayIndexOutOfBoundsException e)
341 {
342 throw new BitstreamException("VBRIVBRHeader Corrupted",e);
343 }
344 }
345
346 // Functions to query header contents:
347 /**
348 * Returns version.
349 */
350 public int version() { return h_version; }
351
352 /**
353 * Returns Layer ID.
354 */
355 public int layer() { return h_layer; }
356
357 /**
358 * Returns bitrate index.
359 */
360 public int bitrate_index() { return h_bitrate_index; }
361
362 /**
363 * Returns Sample Frequency.
364 */
365 public int sample_frequency() { return h_sample_frequency; }
366
367 /**
368 * Returns Frequency.
369 */
370 public int frequency() {return frequencies[h_version][h_sample_frequency];}
371
372 /**
373 * Returns Mode.
374 */
375 public int mode() { return h_mode; }
376
377 /**
378 * Returns Protection bit.
379 */
380 public boolean checksums()
381 {
382 if (h_protection_bit == 0) return true;
383 else return false;
384 }
385
386 /**
387 * Returns Copyright.
388 */
389 public boolean copyright() { return h_copyright; }
390
391 /**
392 * Returns Original.
393 */
394 public boolean original() { return h_original; }
395
396 /**
397 * Return VBR.
398 * @return true if VBR header is found
399 */
400 public boolean vbr() { return h_vbr; }
401
402 /**
403 * Return VBR scale.
404 * @return scale of -1 if not available
405 */
406 public int vbr_scale() { return h_vbr_scale; }
407
408 /**
409 * Return VBR TOC.
410 * @return vbr toc ot null if not available
411 */
412 public byte[] vbr_toc() { return h_vbr_toc; }
413
414 /**
415 * Returns Checksum flag.
416 * Compares computed checksum with stream checksum.
417 */
418 public boolean checksum_ok () { return (checksum == crc.checksum()); }
419
420 // Seeking and layer III stuff
421 /**
422 * Returns Layer III Padding bit.
423 */
424 public boolean padding()
425 {
426 if (h_padding_bit == 0) return false;
427 else return true;
428 }
429
430 /**
431 * Returns Slots.
432 */
433 public int slots() { return nSlots; }
434
435 /**
436 * Returns Mode Extension.
437 */
438 public int mode_extension() { return h_mode_extension; }
439
440 // E.B -> private to public
441 public static final int bitrates[][][] = {
442 {{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,
443 112000, 128000, 144000, 160000, 176000, 192000 ,224000, 256000, 0},
444 {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
445 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0},
446 {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
447 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}},
448
449 {{0 /*free format*/, 32000, 64000, 96000, 128000, 160000, 192000,
450 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000, 0},
451 {0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,
452 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, 0},
453 {0 /*free format*/, 32000, 40000, 48000, 56000, 64000, 80000,
454 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 0}},
455 // SZD: MPEG2.5
456 {{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,
457 112000, 128000, 144000, 160000, 176000, 192000 ,224000, 256000, 0},
458 {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
459 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0},
460 {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
461 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}},
462
463 };
464
465 // E.B -> private to public
466 /**
467 * Calculate Frame size.
468 * Calculates framesize in bytes excluding header size.
469 */
470 public int calculate_framesize()
471 {
472
473 if (h_layer == 1)
474 {
475 framesize = (12 * bitrates[h_version][0][h_bitrate_index]) /
476 frequencies[h_version][h_sample_frequency];
477 if (h_padding_bit != 0 ) framesize++;
478 framesize <<= 2; // one slot is 4 bytes long
479 nSlots = 0;
480 }
481 else
482 {
483 framesize = (144 * bitrates[h_version][h_layer - 1][h_bitrate_index]) /
484 frequencies[h_version][h_sample_frequency];
485 if (h_version == MPEG2_LSF || h_version == MPEG25_LSF) framesize >>= 1; // SZD
486 if (h_padding_bit != 0) framesize++;
487 // Layer III slots
488 if (h_layer == 3)
489 {
490 if (h_version == MPEG1)
491 {
492 nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 17 : 32) // side info size
493 - ((h_protection_bit!=0) ? 0 : 2) // CRC size
494 - 4; // header size
495 }
496 else
497 { // MPEG-2 LSF, SZD: MPEG-2.5 LSF
498 nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 9 : 17) // side info size
499 - ((h_protection_bit!=0) ? 0 : 2) // CRC size
500 - 4; // header size
501 }
502 }
503 else
504 {
505 nSlots = 0;
506 }
507 }
508 framesize -= 4; // subtract header size
509 return framesize;
510 }
511
512 /**
513 * Returns the maximum number of frames in the stream.
514 * @param streamsize
515 * @return number of frames
516 */
517 public int max_number_of_frames(int streamsize) // E.B
518 {
519 if (h_vbr == true) return h_vbr_frames;
520 else
521 {
522 if ((framesize + 4 - h_padding_bit) == 0) return 0;
523 else return(streamsize / (framesize + 4 - h_padding_bit));
524 }
525 }
526
527 /**
528 * Returns the maximum number of frames in the stream.
529 * @param streamsize
530 * @return number of frames
531 */
532 public int min_number_of_frames(int streamsize) // E.B
533 {
534 if (h_vbr == true) return h_vbr_frames;
535 else
536 {
537 if ((framesize + 5 - h_padding_bit) == 0) return 0;
538 else return(streamsize / (framesize + 5 - h_padding_bit));
539 }
540 }
541
542
543 /**
544 * Returns ms/frame.
545 * @return milliseconds per frame
546 */
547 public float ms_per_frame() // E.B
548 {
549 if (h_vbr == true)
550 {
551 double tpf = h_vbr_time_per_frame[layer()] / frequency();
552 if ((h_version == MPEG2_LSF) || (h_version == MPEG25_LSF)) tpf /= 2;
553 return ((float) (tpf * 1000));
554 }
555 else
556 {
557 float ms_per_frame_array[][] = {{8.707483f, 8.0f, 12.0f},
558 {26.12245f, 24.0f, 36.0f},
559 {26.12245f, 24.0f, 36.0f}};
560 return(ms_per_frame_array[h_layer-1][h_sample_frequency]);
561 }
562 }
563
564 /**
565 * Returns total ms.
566 * @param streamsize
567 * @return total milliseconds
568 */
569 public float total_ms(int streamsize) // E.B
570 {
571 return(max_number_of_frames(streamsize) * ms_per_frame());
572 }
573
574 /**
575 * Returns synchronized header.
576 */
577 public int getSyncHeader() // E.B
578 {
579 return _headerstring;
580 }
581
582 // functions which return header informations as strings:
583 /**
584 * Return Layer version.
585 */
586 public String layer_string()
587 {
588 switch (h_layer)
589 {
590 case 1:
591 return "I";
592 case 2:
593 return "II";
594 case 3:
595 return "III";
596 }
597 return null;
598 }
599
600 // E.B -> private to public
601 public static final String bitrate_str[][][] = {
602 {{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",
603 "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s",
604 "160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s",
605 "forbidden"},
606 {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
607 "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
608 "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
609 "forbidden"},
610 {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
611 "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
612 "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
613 "forbidden"}},
614
615 {{"free format", "32 kbit/s", "64 kbit/s", "96 kbit/s", "128 kbit/s",
616 "160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "288 kbit/s",
617 "320 kbit/s", "352 kbit/s", "384 kbit/s", "416 kbit/s", "448 kbit/s",
618 "forbidden"},
619 {"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",
620 "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "160 kbit/s",
621 "192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s", "384 kbit/s",
622 "forbidden"},
623 {"free format", "32 kbit/s", "40 kbit/s", "48 kbit/s", "56 kbit/s",
624 "64 kbit/s", "80 kbit/s" , "96 kbit/s", "112 kbit/s", "128 kbit/s",
625 "160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s",
626 "forbidden"}},
627 // SZD: MPEG2.5
628 {{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",
629 "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s",
630 "160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s",
631 "forbidden"},
632 {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
633 "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
634 "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
635 "forbidden"},
636 {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
637 "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
638 "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
639 "forbidden"}},
640 };
641
642 /**
643 * Return Bitrate.
644 * @return bitrate in bps
645 */
646 public String bitrate_string()
647 {
648 if (h_vbr == true)
649 {
650 return Integer.toString(bitrate()/1000)+" kb/s";
651 }
652 else return bitrate_str[h_version][h_layer - 1][h_bitrate_index];
653 }
654
655 /**
656 * Return Bitrate.
657 * @return bitrate in bps and average bitrate for VBR header
658 */
659 public int bitrate()
660 {
661 if (h_vbr == true)
662 {
663 return ((int) ((h_vbr_bytes * 8) / (ms_per_frame() * h_vbr_frames)))*1000;
664 }
665 else return bitrates[h_version][h_layer - 1][h_bitrate_index];
666 }
667
668 /**
669 * Return Instant Bitrate.
670 * Bitrate for VBR is not constant.
671 * @return bitrate in bps
672 */
673 public int bitrate_instant()
674 {
675 return bitrates[h_version][h_layer - 1][h_bitrate_index];
676 }
677
678 /**
679 * Returns Frequency
680 * @return frequency string in kHz
681 */
682 public String sample_frequency_string()
683 {
684 switch (h_sample_frequency)
685 {
686 case THIRTYTWO:
687 if (h_version == MPEG1)
688 return "32 kHz";
689 else if (h_version == MPEG2_LSF)
690 return "16 kHz";
691 else // SZD
692 return "8 kHz";
693 case FOURTYFOUR_POINT_ONE:
694 if (h_version == MPEG1)
695 return "44.1 kHz";
696 else if (h_version == MPEG2_LSF)
697 return "22.05 kHz";
698 else // SZD
699 return "11.025 kHz";
700 case FOURTYEIGHT:
701 if (h_version == MPEG1)
702 return "48 kHz";
703 else if (h_version == MPEG2_LSF)
704 return "24 kHz";
705 else // SZD
706 return "12 kHz";
707 }
708 return(null);
709 }
710
711 /**
712 * Returns Mode.
713 */
714 public String mode_string()
715 {
716 switch (h_mode)
717 {
718 case STEREO:
719 return "Stereo";
720 case JOINT_STEREO:
721 return "Joint stereo";
722 case DUAL_CHANNEL:
723 return "Dual channel";
724 case SINGLE_CHANNEL:
725 return "Single channel";
726 }
727 return null;
728 }
729
730 /**
731 * Returns Version.
732 * @return MPEG-1 or MPEG-2 LSF or MPEG-2.5 LSF
733 */
734 public String version_string()
735 {
736 switch (h_version)
737 {
738 case MPEG1:
739 return "MPEG-1";
740 case MPEG2_LSF:
741 return "MPEG-2 LSF";
742 case MPEG25_LSF: // SZD
743 return "MPEG-2.5 LSF";
744 }
745 return(null);
746 }
747
748 /**
749 * Returns the number of subbands in the current frame.
750 * @return number of subbands
751 */
752 public int number_of_subbands() {return h_number_of_subbands;}
753
754 /**
755 * Returns Intensity Stereo.
756 * (Layer II joint stereo only).
757 * Returns the number of subbands which are in stereo mode,
758 * subbands above that limit are in intensity stereo mode.
759 * @return intensity
760 */
761 public int intensity_stereo_bound() {return h_intensity_stereo_bound;}
762}
diff --git a/songdbj/javazoom/jl/decoder/InputStreamSource.java b/songdbj/javazoom/jl/decoder/InputStreamSource.java
new file mode 100644
index 0000000000..5c62947049
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/InputStreamSource.java
@@ -0,0 +1,80 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23import java.io.IOException;
24import java.io.InputStream;
25
26/**
27 * <i>Work In Progress.</i>
28 *
29 * An instance of <code>InputStreamSource</code> implements a
30 * <code>Source</code> that provides data from an <code>InputStream
31 * </code>. Seeking functionality is not supported.
32 *
33 * @author MDM
34 */
35public class InputStreamSource implements Source
36{
37 private final InputStream in;
38
39 public InputStreamSource(InputStream in)
40 {
41 if (in==null)
42 throw new NullPointerException("in");
43
44 this.in = in;
45 }
46
47 public int read(byte[] b, int offs, int len)
48 throws IOException
49 {
50 int read = in.read(b, offs, len);
51 return read;
52 }
53
54 public boolean willReadBlock()
55 {
56 return true;
57 //boolean block = (in.available()==0);
58 //return block;
59 }
60
61 public boolean isSeekable()
62 {
63 return false;
64 }
65
66 public long tell()
67 {
68 return -1;
69 }
70
71 public long seek(long to)
72 {
73 return -1;
74 }
75
76 public long length()
77 {
78 return -1;
79 }
80}
diff --git a/songdbj/javazoom/jl/decoder/JavaLayerError.java b/songdbj/javazoom/jl/decoder/JavaLayerError.java
new file mode 100644
index 0000000000..d9910bcc71
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/JavaLayerError.java
@@ -0,0 +1,31 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23/**
24 * Work in progress.
25 *
26 * API usage errors may be handled by throwing an instance of this
27 * class, as per JMF 2.0.
28 */
29public class JavaLayerError extends Error
30{
31}
diff --git a/songdbj/javazoom/jl/decoder/JavaLayerErrors.java b/songdbj/javazoom/jl/decoder/JavaLayerErrors.java
new file mode 100644
index 0000000000..3b9c2ff9d7
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/JavaLayerErrors.java
@@ -0,0 +1,40 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23/**
24 * Exception erorr codes for components of the JavaLayer API.
25 */
26public interface JavaLayerErrors
27{
28 /**
29 * The first bitstream error code. See the {@link DecoderErrors DecoderErrors}
30 * interface for other bitstream error codes.
31 */
32 static public final int BITSTREAM_ERROR = 0x100;
33
34 /**
35 * The first decoder error code. See the {@link DecoderErrors DecoderErrors}
36 * interface for other decoder error codes.
37 */
38 static public final int DECODER_ERROR = 0x200;
39
40}
diff --git a/songdbj/javazoom/jl/decoder/JavaLayerException.java b/songdbj/javazoom/jl/decoder/JavaLayerException.java
new file mode 100644
index 0000000000..e7a50a8340
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/JavaLayerException.java
@@ -0,0 +1,80 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23import java.io.PrintStream;
24
25
26/**
27 * The JavaLayerException is the base class for all API-level
28 * exceptions thrown by JavaLayer. To facilitate conversion and
29 * common handling of exceptions from other domains, the class
30 * can delegate some functionality to a contained Throwable instance.
31 * <p>
32 *
33 * @author MDM
34 */
35public class JavaLayerException extends Exception
36{
37
38 private Throwable exception;
39
40
41 public JavaLayerException()
42 {
43 }
44
45 public JavaLayerException(String msg)
46 {
47 super(msg);
48 }
49
50 public JavaLayerException(String msg, Throwable t)
51 {
52 super(msg);
53 exception = t;
54 }
55
56 public Throwable getException()
57 {
58 return exception;
59 }
60
61
62 public void printStackTrace()
63 {
64 printStackTrace(System.err);
65 }
66
67 public void printStackTrace(PrintStream ps)
68 {
69 if (this.exception==null)
70 {
71 super.printStackTrace(ps);
72 }
73 else
74 {
75 exception.printStackTrace();
76 }
77 }
78
79
80}
diff --git a/songdbj/javazoom/jl/decoder/JavaLayerHook.java b/songdbj/javazoom/jl/decoder/JavaLayerHook.java
new file mode 100644
index 0000000000..352059433d
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/JavaLayerHook.java
@@ -0,0 +1,36 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *-----------------------------------------------------------------------
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *----------------------------------------------------------------------
18 */
19
20package javazoom.jl.decoder;
21
22import java.io.InputStream;
23
24/**
25 * The <code>JavaLayerHooks</code> class allows developers to change
26 * the way the JavaLayer library uses Resources.
27 */
28
29public interface JavaLayerHook
30{
31 /**
32 * Retrieves the named resource. This allows resources to be
33 * obtained without specifying how they are retrieved.
34 */
35 public InputStream getResourceAsStream(String name);
36}
diff --git a/songdbj/javazoom/jl/decoder/JavaLayerUtils.java b/songdbj/javazoom/jl/decoder/JavaLayerUtils.java
new file mode 100644
index 0000000000..c9ce3838e5
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/JavaLayerUtils.java
@@ -0,0 +1,207 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23import java.io.IOException;
24import java.io.InputStream;
25import java.io.InvalidClassException;
26import java.io.InvalidObjectException;
27import java.io.ObjectInputStream;
28import java.io.ObjectOutputStream;
29import java.io.OutputStream;
30import java.lang.reflect.Array;
31
32/**
33 * The JavaLayerUtils class is not strictly part of the JavaLayer API.
34 * It serves to provide useful methods and system-wide hooks.
35 *
36 * @author MDM
37 */
38public class JavaLayerUtils
39{
40 static private JavaLayerHook hook = null;
41
42 /**
43 * Deserializes the object contained in the given input stream.
44 * @param in The input stream to deserialize an object from.
45 * @param cls The expected class of the deserialized object.
46 */
47 static public Object deserialize(InputStream in, Class cls)
48 throws IOException
49 {
50 if (cls==null)
51 throw new NullPointerException("cls");
52
53 Object obj = deserialize(in, cls);
54 if (!cls.isInstance(obj))
55 {
56 throw new InvalidObjectException("type of deserialized instance not of required class.");
57 }
58
59 return obj;
60 }
61
62 /**
63 * Deserializes an object from the given <code>InputStream</code>.
64 * The deserialization is delegated to an <code>
65 * ObjectInputStream</code> instance.
66 *
67 * @param in The <code>InputStream</code> to deserialize an object
68 * from.
69 *
70 * @return The object deserialized from the stream.
71 * @exception IOException is thrown if there was a problem reading
72 * the underlying stream, or an object could not be deserialized
73 * from the stream.
74 *
75 * @see java.io.ObjectInputStream
76 */
77 static public Object deserialize(InputStream in)
78 throws IOException
79 {
80 if (in==null)
81 throw new NullPointerException("in");
82
83 ObjectInputStream objIn = new ObjectInputStream(in);
84
85 Object obj;
86
87 try
88 {
89 obj = objIn.readObject();
90 }
91 catch (ClassNotFoundException ex)
92 {
93 throw new InvalidClassException(ex.toString());
94 }
95
96 return obj;
97 }
98
99 /**
100 * Deserializes an array from a given <code>InputStream</code>.
101 *
102 * @param in The <code>InputStream</code> to
103 * deserialize an object from.
104 *
105 * @param elemType The class denoting the type of the array
106 * elements.
107 * @param length The expected length of the array, or -1 if
108 * any length is expected.
109 */
110 static public Object deserializeArray(InputStream in, Class elemType, int length)
111 throws IOException
112 {
113 if (elemType==null)
114 throw new NullPointerException("elemType");
115
116 if (length<-1)
117 throw new IllegalArgumentException("length");
118
119 Object obj = deserialize(in);
120
121 Class cls = obj.getClass();
122
123
124 if (!cls.isArray())
125 throw new InvalidObjectException("object is not an array");
126
127 Class arrayElemType = cls.getComponentType();
128 if (arrayElemType!=elemType)
129 throw new InvalidObjectException("unexpected array component type");
130
131 if (length != -1)
132 {
133 int arrayLength = Array.getLength(obj);
134 if (arrayLength!=length)
135 throw new InvalidObjectException("array length mismatch");
136 }
137
138 return obj;
139 }
140
141 static public Object deserializeArrayResource(String name, Class elemType, int length)
142 throws IOException
143 {
144 InputStream str = getResourceAsStream(name);
145 if (str==null)
146 throw new IOException("unable to load resource '"+name+"'");
147
148 Object obj = deserializeArray(str, elemType, length);
149
150 return obj;
151 }
152
153 static public void serialize(OutputStream out, Object obj)
154 throws IOException
155 {
156 if (out==null)
157 throw new NullPointerException("out");
158
159 if (obj==null)
160 throw new NullPointerException("obj");
161
162 ObjectOutputStream objOut = new ObjectOutputStream(out);
163 objOut.writeObject(obj);
164
165 }
166
167 /**
168 * Sets the system-wide JavaLayer hook.
169 */
170 static synchronized public void setHook(JavaLayerHook hook0)
171 {
172 hook = hook0;
173 }
174
175 static synchronized public JavaLayerHook getHook()
176 {
177 return hook;
178 }
179
180 /**
181 * Retrieves an InputStream for a named resource.
182 *
183 * @param name The name of the resource. This must be a simple
184 * name, and not a qualified package name.
185 *
186 * @return The InputStream for the named resource, or null if
187 * the resource has not been found. If a hook has been
188 * provided, its getResourceAsStream() method is called
189 * to retrieve the resource.
190 */
191 static synchronized public InputStream getResourceAsStream(String name)
192 {
193 InputStream is = null;
194
195 if (hook!=null)
196 {
197 is = hook.getResourceAsStream(name);
198 }
199 else
200 {
201 Class cls = JavaLayerUtils.class;
202 is = cls.getResourceAsStream(name);
203 }
204
205 return is;
206 }
207}
diff --git a/songdbj/javazoom/jl/decoder/LayerIDecoder.java b/songdbj/javazoom/jl/decoder/LayerIDecoder.java
new file mode 100644
index 0000000000..b633dd2403
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/LayerIDecoder.java
@@ -0,0 +1,444 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *
4 * 12/12/99 Initial version. Adapted from javalayer.java
5 * and Subband*.java. mdm@techie.com
6 *
7 * 02/28/99 Initial version : javalayer.java by E.B
8 *-----------------------------------------------------------------------
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Library General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *----------------------------------------------------------------------
23 */
24
25package javazoom.jl.decoder;
26
27/**
28 * Implements decoding of MPEG Audio Layer I frames.
29 */
30class LayerIDecoder implements FrameDecoder
31{
32 protected Bitstream stream;
33 protected Header header;
34 protected SynthesisFilter filter1, filter2;
35 protected Obuffer buffer;
36 protected int which_channels;
37 protected int mode;
38
39 protected int num_subbands;
40 protected Subband[] subbands;
41 protected Crc16 crc = null; // new Crc16[1] to enable CRC checking.
42
43 public LayerIDecoder()
44 {
45 crc = new Crc16();
46 }
47
48 public void create(Bitstream stream0, Header header0,
49 SynthesisFilter filtera, SynthesisFilter filterb,
50 Obuffer buffer0, int which_ch0)
51 {
52 stream = stream0;
53 header = header0;
54 filter1 = filtera;
55 filter2 = filterb;
56 buffer = buffer0;
57 which_channels = which_ch0;
58
59 }
60
61
62
63 public void decodeFrame()
64 {
65
66 num_subbands = header.number_of_subbands();
67 subbands = new Subband[32];
68 mode = header.mode();
69
70 createSubbands();
71
72 readAllocation();
73 readScaleFactorSelection();
74
75 if ((crc != null) || header.checksum_ok())
76 {
77 readScaleFactors();
78
79 readSampleData();
80 }
81
82 }
83
84 protected void createSubbands()
85 {
86 int i;
87 if (mode == Header.SINGLE_CHANNEL)
88 for (i = 0; i < num_subbands; ++i)
89 subbands[i] = new SubbandLayer1(i);
90 else if (mode == Header.JOINT_STEREO)
91 {
92 for (i = 0; i < header.intensity_stereo_bound(); ++i)
93 subbands[i] = new SubbandLayer1Stereo(i);
94 for (; i < num_subbands; ++i)
95 subbands[i] = new SubbandLayer1IntensityStereo(i);
96 }
97 else
98 {
99 for (i = 0; i < num_subbands; ++i)
100 subbands[i] = new SubbandLayer1Stereo(i);
101 }
102 }
103
104 protected void readAllocation()
105 {
106 // start to read audio data:
107 for (int i = 0; i < num_subbands; ++i)
108 subbands[i].read_allocation(stream, header, crc);
109
110 }
111
112 protected void readScaleFactorSelection()
113 {
114 // scale factor selection not present for layer I.
115 }
116
117 protected void readScaleFactors()
118 {
119 for (int i = 0; i < num_subbands; ++i)
120 subbands[i].read_scalefactor(stream, header);
121 }
122
123 protected void readSampleData()
124 {
125 boolean read_ready = false;
126 boolean write_ready = false;
127 int mode = header.mode();
128 int i;
129 do
130 {
131 for (i = 0; i < num_subbands; ++i)
132 read_ready = subbands[i].read_sampledata(stream);
133 do
134 {
135 for (i = 0; i < num_subbands; ++i)
136 write_ready = subbands[i].put_next_sample(which_channels,filter1, filter2);
137
138 filter1.calculate_pcm_samples(buffer);
139 if ((which_channels == OutputChannels.BOTH_CHANNELS) && (mode != Header.SINGLE_CHANNEL))
140 filter2.calculate_pcm_samples(buffer);
141 } while (!write_ready);
142 } while (!read_ready);
143
144 }
145
146 /**
147 * Abstract base class for subband classes of layer I and II
148 */
149 static abstract class Subband
150 {
151 /*
152 * Changes from version 1.1 to 1.2:
153 * - array size increased by one, although a scalefactor with index 63
154 * is illegal (to prevent segmentation faults)
155 */
156 // Scalefactors for layer I and II, Annex 3-B.1 in ISO/IEC DIS 11172:
157 public static final float scalefactors[] =
158 {
159 2.00000000000000f, 1.58740105196820f, 1.25992104989487f, 1.00000000000000f,
160 0.79370052598410f, 0.62996052494744f, 0.50000000000000f, 0.39685026299205f,
161 0.31498026247372f, 0.25000000000000f, 0.19842513149602f, 0.15749013123686f,
162 0.12500000000000f, 0.09921256574801f, 0.07874506561843f, 0.06250000000000f,
163 0.04960628287401f, 0.03937253280921f, 0.03125000000000f, 0.02480314143700f,
164 0.01968626640461f, 0.01562500000000f, 0.01240157071850f, 0.00984313320230f,
165 0.00781250000000f, 0.00620078535925f, 0.00492156660115f, 0.00390625000000f,
166 0.00310039267963f, 0.00246078330058f, 0.00195312500000f, 0.00155019633981f,
167 0.00123039165029f, 0.00097656250000f, 0.00077509816991f, 0.00061519582514f,
168 0.00048828125000f, 0.00038754908495f, 0.00030759791257f, 0.00024414062500f,
169 0.00019377454248f, 0.00015379895629f, 0.00012207031250f, 0.00009688727124f,
170 0.00007689947814f, 0.00006103515625f, 0.00004844363562f, 0.00003844973907f,
171 0.00003051757813f, 0.00002422181781f, 0.00001922486954f, 0.00001525878906f,
172 0.00001211090890f, 0.00000961243477f, 0.00000762939453f, 0.00000605545445f,
173 0.00000480621738f, 0.00000381469727f, 0.00000302772723f, 0.00000240310869f,
174 0.00000190734863f, 0.00000151386361f, 0.00000120155435f, 0.00000000000000f /* illegal scalefactor */
175 };
176
177 public abstract void read_allocation (Bitstream stream, Header header, Crc16 crc);
178 public abstract void read_scalefactor (Bitstream stream, Header header);
179 public abstract boolean read_sampledata (Bitstream stream);
180 public abstract boolean put_next_sample (int channels, SynthesisFilter filter1, SynthesisFilter filter2);
181 };
182
183 /**
184 * Class for layer I subbands in single channel mode.
185 * Used for single channel mode
186 * and in derived class for intensity stereo mode
187 */
188 static class SubbandLayer1 extends Subband
189 {
190
191 // Factors and offsets for sample requantization
192 public static final float table_factor[] = {
193 0.0f, (1.0f/2.0f) * (4.0f/3.0f), (1.0f/4.0f) * (8.0f/7.0f), (1.0f/8.0f) * (16.0f/15.0f),
194 (1.0f/16.0f) * (32.0f/31.0f), (1.0f/32.0f) * (64.0f/63.0f), (1.0f/64.0f) * (128.0f/127.0f),
195 (1.0f/128.0f) * (256.0f/255.0f), (1.0f/256.0f) * (512.0f/511.0f),
196 (1.0f/512.0f) * (1024.0f/1023.0f), (1.0f/1024.0f) * (2048.0f/2047.0f),
197 (1.0f/2048.0f) * (4096.0f/4095.0f), (1.0f/4096.0f) * (8192.0f/8191.0f),
198 (1.0f/8192.0f) * (16384.0f/16383.0f), (1.0f/16384.0f) * (32768.0f/32767.0f)
199 };
200
201 public static final float table_offset[] = {
202 0.0f, ((1.0f/2.0f)-1.0f) * (4.0f/3.0f), ((1.0f/4.0f)-1.0f) * (8.0f/7.0f), ((1.0f/8.0f)-1.0f) * (16.0f/15.0f),
203 ((1.0f/16.0f)-1.0f) * (32.0f/31.0f), ((1.0f/32.0f)-1.0f) * (64.0f/63.0f), ((1.0f/64.0f)-1.0f) * (128.0f/127.0f),
204 ((1.0f/128.0f)-1.0f) * (256.0f/255.0f), ((1.0f/256.0f)-1.0f) * (512.0f/511.0f),
205 ((1.0f/512.0f)-1.0f) * (1024.0f/1023.0f), ((1.0f/1024.0f)-1.0f) * (2048.0f/2047.0f),
206 ((1.0f/2048.0f)-1.0f) * (4096.0f/4095.0f), ((1.0f/4096.0f)-1.0f) * (8192.0f/8191.0f),
207 ((1.0f/8192.0f)-1.0f) * (16384.0f/16383.0f), ((1.0f/16384.0f)-1.0f) * (32768.0f/32767.0f)
208 };
209
210 protected int subbandnumber;
211 protected int samplenumber;
212 protected int allocation;
213 protected float scalefactor;
214 protected int samplelength;
215 protected float sample;
216 protected float factor, offset;
217
218 /**
219 * Construtor.
220 */
221 public SubbandLayer1(int subbandnumber)
222 {
223 this.subbandnumber = subbandnumber;
224 samplenumber = 0;
225 }
226
227 /**
228 *
229 */
230 public void read_allocation(Bitstream stream, Header header, Crc16 crc)
231 {
232 if ((allocation = stream.get_bits (4)) == 15) ;
233 // cerr << "WARNING: stream contains an illegal allocation!\n";
234 // MPEG-stream is corrupted!
235 if (crc != null)
236 crc.add_bits (allocation, 4);
237 if (allocation != 0)
238 {
239 samplelength = allocation + 1;
240 factor = table_factor[allocation];
241 offset = table_offset[allocation];
242 }
243 }
244
245 /**
246 *
247 */
248 public void read_scalefactor(Bitstream stream, Header header)
249 {
250 if (allocation != 0) scalefactor = scalefactors[stream.get_bits(6)];
251 }
252
253 /**
254 *
255 */
256 public boolean read_sampledata(Bitstream stream)
257 {
258 if (allocation != 0)
259 {
260 sample = (float) (stream.get_bits(samplelength));
261 }
262 if (++samplenumber == 12)
263 {
264 samplenumber = 0;
265 return true;
266 }
267 return false;
268 }
269
270 /**
271 *
272 */
273 public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2)
274 {
275 if ((allocation !=0) && (channels != OutputChannels.RIGHT_CHANNEL))
276 {
277 float scaled_sample = (sample * factor + offset) * scalefactor;
278 filter1.input_sample (scaled_sample, subbandnumber);
279 }
280 return true;
281 }
282 };
283
284 /**
285 * Class for layer I subbands in joint stereo mode.
286 */
287 static class SubbandLayer1IntensityStereo extends SubbandLayer1
288 {
289 protected float channel2_scalefactor;
290
291 /**
292 * Constructor
293 */
294 public SubbandLayer1IntensityStereo(int subbandnumber)
295 {
296 super(subbandnumber);
297 }
298
299 /**
300 *
301 */
302 public void read_allocation(Bitstream stream, Header header, Crc16 crc)
303 {
304 super.read_allocation (stream, header, crc);
305 }
306
307 /**
308 *
309 */
310 public void read_scalefactor (Bitstream stream, Header header)
311 {
312 if (allocation != 0)
313 {
314 scalefactor = scalefactors[stream.get_bits(6)];
315 channel2_scalefactor = scalefactors[stream.get_bits(6)];
316 }
317 }
318
319 /**
320 *
321 */
322 public boolean read_sampledata(Bitstream stream)
323 {
324 return super.read_sampledata (stream);
325 }
326
327 /**
328 *
329 */
330 public boolean put_next_sample (int channels, SynthesisFilter filter1, SynthesisFilter filter2)
331 {
332 if (allocation !=0 )
333 {
334 sample = sample * factor + offset; // requantization
335 if (channels == OutputChannels.BOTH_CHANNELS)
336 {
337 float sample1 = sample * scalefactor,
338 sample2 = sample * channel2_scalefactor;
339 filter1.input_sample(sample1, subbandnumber);
340 filter2.input_sample(sample2, subbandnumber);
341 }
342 else if (channels == OutputChannels.LEFT_CHANNEL)
343 {
344 float sample1 = sample * scalefactor;
345 filter1.input_sample(sample1, subbandnumber);
346 }
347 else
348 {
349 float sample2 = sample * channel2_scalefactor;
350 filter1.input_sample(sample2, subbandnumber);
351 }
352 }
353 return true;
354 }
355 };
356
357 /**
358 * Class for layer I subbands in stereo mode.
359 */
360 static class SubbandLayer1Stereo extends SubbandLayer1
361 {
362 protected int channel2_allocation;
363 protected float channel2_scalefactor;
364 protected int channel2_samplelength;
365 protected float channel2_sample;
366 protected float channel2_factor, channel2_offset;
367
368
369 /**
370 * Constructor
371 */
372 public SubbandLayer1Stereo(int subbandnumber)
373 {
374 super(subbandnumber);
375 }
376
377 /**
378 *
379 */
380 public void read_allocation (Bitstream stream, Header header, Crc16 crc)
381 {
382 allocation = stream.get_bits(4);
383 channel2_allocation = stream.get_bits(4);
384 if (crc != null)
385 {
386 crc.add_bits (allocation, 4);
387 crc.add_bits (channel2_allocation, 4);
388 }
389 if (allocation != 0)
390 {
391 samplelength = allocation + 1;
392 factor = table_factor[allocation];
393 offset = table_offset[allocation];
394 }
395 if (channel2_allocation != 0)
396 {
397 channel2_samplelength = channel2_allocation + 1;
398 channel2_factor = table_factor[channel2_allocation];
399 channel2_offset = table_offset[channel2_allocation];
400 }
401 }
402
403 /**
404 *
405 */
406 public void read_scalefactor(Bitstream stream, Header header)
407 {
408 if (allocation != 0) scalefactor = scalefactors[stream.get_bits(6)];
409 if (channel2_allocation != 0) channel2_scalefactor = scalefactors[stream.get_bits(6)];
410 }
411
412 /**
413 *
414 */
415 public boolean read_sampledata (Bitstream stream)
416 {
417 boolean returnvalue = super.read_sampledata(stream);
418 if (channel2_allocation != 0)
419 {
420 channel2_sample = (float) (stream.get_bits(channel2_samplelength));
421 }
422 return(returnvalue);
423 }
424
425 /**
426 *
427 */
428 public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2)
429 {
430 super.put_next_sample (channels, filter1, filter2);
431 if ((channel2_allocation != 0) && (channels != OutputChannels.LEFT_CHANNEL))
432 {
433 float sample2 = (channel2_sample * channel2_factor + channel2_offset) *
434 channel2_scalefactor;
435 if (channels == OutputChannels.BOTH_CHANNELS)
436 filter2.input_sample (sample2, subbandnumber);
437 else
438 filter1.input_sample (sample2, subbandnumber);
439 }
440 return true;
441 }
442 };
443
444}
diff --git a/songdbj/javazoom/jl/decoder/LayerIIDecoder.java b/songdbj/javazoom/jl/decoder/LayerIIDecoder.java
new file mode 100644
index 0000000000..7265b1f8fa
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/LayerIIDecoder.java
@@ -0,0 +1,1064 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *
4 * 29/05/01 Michael Scheerer, Fixed some C++ to Java porting bugs.
5 *
6 * 16/07/01 Michael Scheerer, Catched a bug in method
7 * read_sampledata, which causes an outOfIndexException.
8 *
9 * 12/12/99 Initial version. Adapted from javalayer.java
10 * and Subband*.java. mdm@techie.com
11 *
12 * 02/28/99 Initial version : javalayer.java by E.B
13 *-----------------------------------------------------------------------
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as published
16 * by the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 *----------------------------------------------------------------------
28 */
29
30package javazoom.jl.decoder;
31
32/**
33 * Implements decoding of MPEG Audio Layer II frames.
34 */
35class LayerIIDecoder extends LayerIDecoder implements FrameDecoder
36{
37
38 public LayerIIDecoder()
39 {
40 }
41
42
43 protected void createSubbands()
44 {
45 int i;
46 if (mode == Header.SINGLE_CHANNEL)
47 for (i = 0; i < num_subbands; ++i)
48 subbands[i] = new SubbandLayer2(i);
49 else if (mode == Header.JOINT_STEREO)
50 {
51 for (i = 0; i < header.intensity_stereo_bound(); ++i)
52 subbands[i] = new SubbandLayer2Stereo(i);
53 for (; i < num_subbands; ++i)
54 subbands[i] = new SubbandLayer2IntensityStereo(i);
55 }
56 else
57 {
58 for (i = 0; i < num_subbands; ++i)
59 subbands[i] = new SubbandLayer2Stereo(i);
60 }
61
62 }
63
64 protected void readScaleFactorSelection()
65 {
66 for (int i = 0; i < num_subbands; ++i)
67 ((SubbandLayer2)subbands[i]).read_scalefactor_selection(stream, crc);
68 }
69
70
71
72 /**
73 * Class for layer II subbands in single channel mode.
74 */
75 static class SubbandLayer2 extends Subband
76 {
77 // this table contains 3 requantized samples for each legal codeword
78 // when grouped in 5 bits, i.e. 3 quantizationsteps per sample
79 public static final float grouping_5bits[] = new float[]
80 {
81 -2.0f/3.0f, -2.0f/3.0f, -2.0f/3.0f,
82 0.0f, -2.0f/3.0f, -2.0f/3.0f,
83 2.0f/3.0f, -2.0f/3.0f, -2.0f/3.0f,
84 -2.0f/3.0f, 0.0f, -2.0f/3.0f,
85 0.0f, 0.0f, -2.0f/3.0f,
86 2.0f/3.0f, 0.0f, -2.0f/3.0f,
87 -2.0f/3.0f, 2.0f/3.0f, -2.0f/3.0f,
88 0.0f, 2.0f/3.0f, -2.0f/3.0f,
89 2.0f/3.0f, 2.0f/3.0f, -2.0f/3.0f,
90 -2.0f/3.0f, -2.0f/3.0f, 0.0f,
91 0.0f, -2.0f/3.0f, 0.0f,
92 2.0f/3.0f, -2.0f/3.0f, 0.0f,
93 -2.0f/3.0f, 0.0f, 0.0f,
94 0.0f, 0.0f, 0.0f,
95 2.0f/3.0f, 0.0f, 0.0f,
96 -2.0f/3.0f, 2.0f/3.0f, 0.0f,
97 0.0f, 2.0f/3.0f, 0.0f,
98 2.0f/3.0f, 2.0f/3.0f, 0.0f,
99 -2.0f/3.0f, -2.0f/3.0f, 2.0f/3.0f,
100 0.0f, -2.0f/3.0f, 2.0f/3.0f,
101 2.0f/3.0f, -2.0f/3.0f, 2.0f/3.0f,
102 -2.0f/3.0f, 0.0f, 2.0f/3.0f,
103 0.0f, 0.0f, 2.0f/3.0f,
104 2.0f/3.0f, 0.0f, 2.0f/3.0f,
105 -2.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f,
106 0.0f, 2.0f/3.0f, 2.0f/3.0f,
107 2.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f
108 };
109
110 // this table contains 3 requantized samples for each legal codeword
111 // when grouped in 7 bits, i.e. 5 quantizationsteps per sample
112 public static final float grouping_7bits[] = new float[]
113 {
114 -0.8f, -0.8f, -0.8f, -0.4f, -0.8f, -0.8f, 0.0f, -0.8f, -0.8f, 0.4f, -0.8f, -0.8f, 0.8f, -0.8f, -0.8f,
115 -0.8f, -0.4f, -0.8f, -0.4f, -0.4f, -0.8f, 0.0f, -0.4f, -0.8f, 0.4f, -0.4f, -0.8f, 0.8f, -0.4f, -0.8f,
116 -0.8f, 0.0f, -0.8f, -0.4f, 0.0f, -0.8f, 0.0f, 0.0f, -0.8f, 0.4f, 0.0f, -0.8f, 0.8f, 0.0f, -0.8f,
117 -0.8f, 0.4f, -0.8f, -0.4f, 0.4f, -0.8f, 0.0f, 0.4f, -0.8f, 0.4f, 0.4f, -0.8f, 0.8f, 0.4f, -0.8f,
118 -0.8f, 0.8f, -0.8f, -0.4f, 0.8f, -0.8f, 0.0f, 0.8f, -0.8f, 0.4f, 0.8f, -0.8f, 0.8f, 0.8f, -0.8f,
119 -0.8f, -0.8f, -0.4f, -0.4f, -0.8f, -0.4f, 0.0f, -0.8f, -0.4f, 0.4f, -0.8f, -0.4f, 0.8f, -0.8f, -0.4f,
120 -0.8f, -0.4f, -0.4f, -0.4f, -0.4f, -0.4f, 0.0f, -0.4f, -0.4f, 0.4f, -0.4f, -0.4f, 0.8f, -0.4f, -0.4f,
121 -0.8f, 0.0f, -0.4f, -0.4f, 0.0f, -0.4f, 0.0f, 0.0f, -0.4f, 0.4f, 0.0f, -0.4f, 0.8f, 0.0f, -0.4f,
122 -0.8f, 0.4f, -0.4f, -0.4f, 0.4f, -0.4f, 0.0f, 0.4f, -0.4f, 0.4f, 0.4f, -0.4f, 0.8f, 0.4f, -0.4f,
123 -0.8f, 0.8f, -0.4f, -0.4f, 0.8f, -0.4f, 0.0f, 0.8f, -0.4f, 0.4f, 0.8f, -0.4f, 0.8f, 0.8f, -0.4f,
124 -0.8f, -0.8f, 0.0f, -0.4f, -0.8f, 0.0f, 0.0f, -0.8f, 0.0f, 0.4f, -0.8f, 0.0f, 0.8f, -0.8f, 0.0f,
125 -0.8f, -0.4f, 0.0f, -0.4f, -0.4f, 0.0f, 0.0f, -0.4f, 0.0f, 0.4f, -0.4f, 0.0f, 0.8f, -0.4f, 0.0f,
126 -0.8f, 0.0f, 0.0f, -0.4f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.0f, 0.0f, 0.8f, 0.0f, 0.0f,
127 -0.8f, 0.4f, 0.0f, -0.4f, 0.4f, 0.0f, 0.0f, 0.4f, 0.0f, 0.4f, 0.4f, 0.0f, 0.8f, 0.4f, 0.0f,
128 -0.8f, 0.8f, 0.0f, -0.4f, 0.8f, 0.0f, 0.0f, 0.8f, 0.0f, 0.4f, 0.8f, 0.0f, 0.8f, 0.8f, 0.0f,
129 -0.8f, -0.8f, 0.4f, -0.4f, -0.8f, 0.4f, 0.0f, -0.8f, 0.4f, 0.4f, -0.8f, 0.4f, 0.8f, -0.8f, 0.4f,
130 -0.8f, -0.4f, 0.4f, -0.4f, -0.4f, 0.4f, 0.0f, -0.4f, 0.4f, 0.4f, -0.4f, 0.4f, 0.8f, -0.4f, 0.4f,
131 -0.8f, 0.0f, 0.4f, -0.4f, 0.0f, 0.4f, 0.0f, 0.0f, 0.4f, 0.4f, 0.0f, 0.4f, 0.8f, 0.0f, 0.4f,
132 -0.8f, 0.4f, 0.4f, -0.4f, 0.4f, 0.4f, 0.0f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f, 0.8f, 0.4f, 0.4f,
133 -0.8f, 0.8f, 0.4f, -0.4f, 0.8f, 0.4f, 0.0f, 0.8f, 0.4f, 0.4f, 0.8f, 0.4f, 0.8f, 0.8f, 0.4f,
134 -0.8f, -0.8f, 0.8f, -0.4f, -0.8f, 0.8f, 0.0f, -0.8f, 0.8f, 0.4f, -0.8f, 0.8f, 0.8f, -0.8f, 0.8f,
135 -0.8f, -0.4f, 0.8f, -0.4f, -0.4f, 0.8f, 0.0f, -0.4f, 0.8f, 0.4f, -0.4f, 0.8f, 0.8f, -0.4f, 0.8f,
136 -0.8f, 0.0f, 0.8f, -0.4f, 0.0f, 0.8f, 0.0f, 0.0f, 0.8f, 0.4f, 0.0f, 0.8f, 0.8f, 0.0f, 0.8f,
137 -0.8f, 0.4f, 0.8f, -0.4f, 0.4f, 0.8f, 0.0f, 0.4f, 0.8f, 0.4f, 0.4f, 0.8f, 0.8f, 0.4f, 0.8f,
138 -0.8f, 0.8f, 0.8f, -0.4f, 0.8f, 0.8f, 0.0f, 0.8f, 0.8f, 0.4f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f
139 };
140
141 // this table contains 3 requantized samples for each legal codeword
142 // when grouped in 10 bits, i.e. 9 quantizationsteps per sample
143 public static final float grouping_10bits[] =
144 {
145 -8.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f,
146 -2.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, 0.0f, -8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f,
147 4.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -8.0f/9.0f,
148 -8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f,
149 -2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 0.0f, -6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f,
150 4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f,
151 -8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f,
152 -2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 0.0f, -4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f,
153 4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f,
154 -8.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f,
155 -2.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, 0.0f, -2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f,
156 4.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -8.0f/9.0f,
157 -8.0f/9.0f, 0.0f, -8.0f/9.0f, -6.0f/9.0f, 0.0f, -8.0f/9.0f, -4.0f/9.0f, 0.0f, -8.0f/9.0f,
158 -2.0f/9.0f, 0.0f, -8.0f/9.0f, 0.0f, 0.0f, -8.0f/9.0f, 2.0f/9.0f, 0.0f, -8.0f/9.0f,
159 4.0f/9.0f, 0.0f, -8.0f/9.0f, 6.0f/9.0f, 0.0f, -8.0f/9.0f, 8.0f/9.0f, 0.0f, -8.0f/9.0f,
160 -8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f,
161 -2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 0.0f, 2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f,
162 4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f,
163 -8.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f,
164 -2.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, 0.0f, 4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f,
165 4.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -8.0f/9.0f,
166 -8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f,
167 -2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 0.0f, 6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f,
168 4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f,
169 -8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f,
170 -2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 0.0f, 8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f,
171 4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f,
172 -8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f,
173 -2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 0.0f, -8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f,
174 4.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -6.0f/9.0f,
175 -8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f,
176 -2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 0.0f, -6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f,
177 4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f,
178 -8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f,
179 -2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 0.0f, -4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f,
180 4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f,
181 -8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f,
182 -2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 0.0f, -2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f,
183 4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f,
184 -8.0f/9.0f, 0.0f, -6.0f/9.0f, -6.0f/9.0f, 0.0f, -6.0f/9.0f, -4.0f/9.0f, 0.0f, -6.0f/9.0f,
185 -2.0f/9.0f, 0.0f, -6.0f/9.0f, 0.0f, 0.0f, -6.0f/9.0f, 2.0f/9.0f, 0.0f, -6.0f/9.0f,
186 4.0f/9.0f, 0.0f, -6.0f/9.0f, 6.0f/9.0f, 0.0f, -6.0f/9.0f, 8.0f/9.0f, 0.0f, -6.0f/9.0f,
187 -8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f,
188 -2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 0.0f, 2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f,
189 4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f,
190 -8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f,
191 -2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 0.0f, 4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f,
192 4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f,
193 -8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f,
194 -2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 0.0f, 6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f,
195 4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f,
196 -8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f,
197 -2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 0.0f, 8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f,
198 4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f,
199 -8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f,
200 -2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 0.0f, -8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f,
201 4.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -4.0f/9.0f,
202 -8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f,
203 -2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 0.0f, -6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f,
204 4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f,
205 -8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f,
206 -2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 0.0f, -4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f,
207 4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f,
208 -8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f,
209 -2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 0.0f, -2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f,
210 4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f,
211 -8.0f/9.0f, 0.0f, -4.0f/9.0f, -6.0f/9.0f, 0.0f, -4.0f/9.0f, -4.0f/9.0f, 0.0f, -4.0f/9.0f,
212 -2.0f/9.0f, 0.0f, -4.0f/9.0f, 0.0f, 0.0f, -4.0f/9.0f, 2.0f/9.0f, 0.0f, -4.0f/9.0f,
213 4.0f/9.0f, 0.0f, -4.0f/9.0f, 6.0f/9.0f, 0.0f, -4.0f/9.0f, 8.0f/9.0f, 0.0f, -4.0f/9.0f,
214 -8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f,
215 -2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 0.0f, 2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f,
216 4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f,
217 -8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f,
218 -2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 0.0f, 4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f,
219 4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f,
220 -8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f,
221 -2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 0.0f, 6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f,
222 4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f,
223 -8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f,
224 -2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 0.0f, 8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f,
225 4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f,
226 -8.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f,
227 -2.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, 0.0f, -8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f,
228 4.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, -2.0f/9.0f,
229 -8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f,
230 -2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 0.0f, -6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f,
231 4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f,
232 -8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f,
233 -2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 0.0f, -4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f,
234 4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f,
235 -8.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f,
236 -2.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, 0.0f, -2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f,
237 4.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -2.0f/9.0f,
238 -8.0f/9.0f, 0.0f, -2.0f/9.0f, -6.0f/9.0f, 0.0f, -2.0f/9.0f, -4.0f/9.0f, 0.0f, -2.0f/9.0f,
239 -2.0f/9.0f, 0.0f, -2.0f/9.0f, 0.0f, 0.0f, -2.0f/9.0f, 2.0f/9.0f, 0.0f, -2.0f/9.0f,
240 4.0f/9.0f, 0.0f, -2.0f/9.0f, 6.0f/9.0f, 0.0f, -2.0f/9.0f, 8.0f/9.0f, 0.0f, -2.0f/9.0f,
241 -8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f,
242 -2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 0.0f, 2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f,
243 4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f,
244 -8.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f,
245 -2.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, 0.0f, 4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f,
246 4.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -2.0f/9.0f,
247 -8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f,
248 -2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 0.0f, 6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f,
249 4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f,
250 -8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f,
251 -2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 0.0f, 8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f,
252 4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f,
253 -8.0f/9.0f, -8.0f/9.0f, 0.0f, -6.0f/9.0f, -8.0f/9.0f, 0.0f, -4.0f/9.0f, -8.0f/9.0f, 0.0f,
254 -2.0f/9.0f, -8.0f/9.0f, 0.0f, 0.0f, -8.0f/9.0f, 0.0f, 2.0f/9.0f, -8.0f/9.0f, 0.0f,
255 4.0f/9.0f, -8.0f/9.0f, 0.0f, 6.0f/9.0f, -8.0f/9.0f, 0.0f, 8.0f/9.0f, -8.0f/9.0f, 0.0f,
256 -8.0f/9.0f, -6.0f/9.0f, 0.0f, -6.0f/9.0f, -6.0f/9.0f, 0.0f, -4.0f/9.0f, -6.0f/9.0f, 0.0f,
257 -2.0f/9.0f, -6.0f/9.0f, 0.0f, 0.0f, -6.0f/9.0f, 0.0f, 2.0f/9.0f, -6.0f/9.0f, 0.0f,
258 4.0f/9.0f, -6.0f/9.0f, 0.0f, 6.0f/9.0f, -6.0f/9.0f, 0.0f, 8.0f/9.0f, -6.0f/9.0f, 0.0f,
259 -8.0f/9.0f, -4.0f/9.0f, 0.0f, -6.0f/9.0f, -4.0f/9.0f, 0.0f, -4.0f/9.0f, -4.0f/9.0f, 0.0f,
260 -2.0f/9.0f, -4.0f/9.0f, 0.0f, 0.0f, -4.0f/9.0f, 0.0f, 2.0f/9.0f, -4.0f/9.0f, 0.0f,
261 4.0f/9.0f, -4.0f/9.0f, 0.0f, 6.0f/9.0f, -4.0f/9.0f, 0.0f, 8.0f/9.0f, -4.0f/9.0f, 0.0f,
262 -8.0f/9.0f, -2.0f/9.0f, 0.0f, -6.0f/9.0f, -2.0f/9.0f, 0.0f, -4.0f/9.0f, -2.0f/9.0f, 0.0f,
263 -2.0f/9.0f, -2.0f/9.0f, 0.0f, 0.0f, -2.0f/9.0f, 0.0f, 2.0f/9.0f, -2.0f/9.0f, 0.0f,
264 4.0f/9.0f, -2.0f/9.0f, 0.0f, 6.0f/9.0f, -2.0f/9.0f, 0.0f, 8.0f/9.0f, -2.0f/9.0f, 0.0f,
265 -8.0f/9.0f, 0.0f, 0.0f, -6.0f/9.0f, 0.0f, 0.0f, -4.0f/9.0f, 0.0f, 0.0f,
266 -2.0f/9.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f/9.0f, 0.0f, 0.0f,
267 4.0f/9.0f, 0.0f, 0.0f, 6.0f/9.0f, 0.0f, 0.0f, 8.0f/9.0f, 0.0f, 0.0f,
268 -8.0f/9.0f, 2.0f/9.0f, 0.0f, -6.0f/9.0f, 2.0f/9.0f, 0.0f, -4.0f/9.0f, 2.0f/9.0f, 0.0f,
269 -2.0f/9.0f, 2.0f/9.0f, 0.0f, 0.0f, 2.0f/9.0f, 0.0f, 2.0f/9.0f, 2.0f/9.0f, 0.0f,
270 4.0f/9.0f, 2.0f/9.0f, 0.0f, 6.0f/9.0f, 2.0f/9.0f, 0.0f, 8.0f/9.0f, 2.0f/9.0f, 0.0f,
271 -8.0f/9.0f, 4.0f/9.0f, 0.0f, -6.0f/9.0f, 4.0f/9.0f, 0.0f, -4.0f/9.0f, 4.0f/9.0f, 0.0f,
272 -2.0f/9.0f, 4.0f/9.0f, 0.0f, 0.0f, 4.0f/9.0f, 0.0f, 2.0f/9.0f, 4.0f/9.0f, 0.0f,
273 4.0f/9.0f, 4.0f/9.0f, 0.0f, 6.0f/9.0f, 4.0f/9.0f, 0.0f, 8.0f/9.0f, 4.0f/9.0f, 0.0f,
274 -8.0f/9.0f, 6.0f/9.0f, 0.0f, -6.0f/9.0f, 6.0f/9.0f, 0.0f, -4.0f/9.0f, 6.0f/9.0f, 0.0f,
275 -2.0f/9.0f, 6.0f/9.0f, 0.0f, 0.0f, 6.0f/9.0f, 0.0f, 2.0f/9.0f, 6.0f/9.0f, 0.0f,
276 4.0f/9.0f, 6.0f/9.0f, 0.0f, 6.0f/9.0f, 6.0f/9.0f, 0.0f, 8.0f/9.0f, 6.0f/9.0f, 0.0f,
277 -8.0f/9.0f, 8.0f/9.0f, 0.0f, -6.0f/9.0f, 8.0f/9.0f, 0.0f, -4.0f/9.0f, 8.0f/9.0f, 0.0f,
278 -2.0f/9.0f, 8.0f/9.0f, 0.0f, 0.0f, 8.0f/9.0f, 0.0f, 2.0f/9.0f, 8.0f/9.0f, 0.0f,
279 4.0f/9.0f, 8.0f/9.0f, 0.0f, 6.0f/9.0f, 8.0f/9.0f, 0.0f, 8.0f/9.0f, 8.0f/9.0f, 0.0f,
280 -8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f,
281 -2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 0.0f, -8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f,
282 4.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 2.0f/9.0f,
283 -8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f,
284 -2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 0.0f, -6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f,
285 4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f,
286 -8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f,
287 -2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 0.0f, -4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f,
288 4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f,
289 -8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f,
290 -2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 0.0f, -2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f,
291 4.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 2.0f/9.0f,
292 -8.0f/9.0f, 0.0f, 2.0f/9.0f, -6.0f/9.0f, 0.0f, 2.0f/9.0f, -4.0f/9.0f, 0.0f, 2.0f/9.0f,
293 -2.0f/9.0f, 0.0f, 2.0f/9.0f, 0.0f, 0.0f, 2.0f/9.0f, 2.0f/9.0f, 0.0f, 2.0f/9.0f,
294 4.0f/9.0f, 0.0f, 2.0f/9.0f, 6.0f/9.0f, 0.0f, 2.0f/9.0f, 8.0f/9.0f, 0.0f, 2.0f/9.0f,
295 -8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f,
296 -2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 0.0f, 2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f,
297 4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f,
298 -8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f,
299 -2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 0.0f, 4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f,
300 4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f,
301 -8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f,
302 -2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 0.0f, 6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f,
303 4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f,
304 -8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f,
305 -2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 0.0f, 8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f,
306 4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f,
307 -8.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f,
308 -2.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, 0.0f, -8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f,
309 4.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 4.0f/9.0f,
310 -8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f,
311 -2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 0.0f, -6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f,
312 4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f,
313 -8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f,
314 -2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 0.0f, -4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f,
315 4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f,
316 -8.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f,
317 -2.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, 0.0f, -2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f,
318 4.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 4.0f/9.0f,
319 -8.0f/9.0f, 0.0f, 4.0f/9.0f, -6.0f/9.0f, 0.0f, 4.0f/9.0f, -4.0f/9.0f, 0.0f, 4.0f/9.0f,
320 -2.0f/9.0f, 0.0f, 4.0f/9.0f, 0.0f, 0.0f, 4.0f/9.0f, 2.0f/9.0f, 0.0f, 4.0f/9.0f,
321 4.0f/9.0f, 0.0f, 4.0f/9.0f, 6.0f/9.0f, 0.0f, 4.0f/9.0f, 8.0f/9.0f, 0.0f, 4.0f/9.0f,
322 -8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f,
323 -2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 0.0f, 2.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f,
324 4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f,
325 -8.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f,
326 -2.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, 0.0f, 4.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f,
327 4.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 4.0f/9.0f,
328 -8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f,
329 -2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 0.0f, 6.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f,
330 4.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f,
331 -8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f,
332 -2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 0.0f, 8.0f/9.0f, 4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f,
333 4.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f,
334 -8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f,
335 -2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 0.0f, -8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f,
336 4.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 6.0f/9.0f,
337 -8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f,
338 -2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 0.0f, -6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f,
339 4.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f,
340 -8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f,
341 -2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 0.0f, -4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f,
342 4.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f,
343 -8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f,
344 -2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 0.0f, -2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f,
345 4.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 6.0f/9.0f,
346 -8.0f/9.0f, 0.0f, 6.0f/9.0f, -6.0f/9.0f, 0.0f, 6.0f/9.0f, -4.0f/9.0f, 0.0f, 6.0f/9.0f,
347 -2.0f/9.0f, 0.0f, 6.0f/9.0f, 0.0f, 0.0f, 6.0f/9.0f, 2.0f/9.0f, 0.0f, 6.0f/9.0f,
348 4.0f/9.0f, 0.0f, 6.0f/9.0f, 6.0f/9.0f, 0.0f, 6.0f/9.0f, 8.0f/9.0f, 0.0f, 6.0f/9.0f,
349 -8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f,
350 -2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 0.0f, 2.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f,
351 4.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f,
352 -8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f,
353 -2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 0.0f, 4.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f,
354 4.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 6.0f/9.0f,
355 -8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f,
356 -2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 0.0f, 6.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f,
357 4.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f,
358 -8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f,
359 -2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 0.0f, 8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f,
360 4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f,
361 -8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f,
362 -2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 0.0f, -8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f,
363 4.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -8.0f/9.0f, 8.0f/9.0f,
364 -8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f,
365 -2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 0.0f, -6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f,
366 4.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f,
367 -8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f,
368 -2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 0.0f, -4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f,
369 4.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f,
370 -8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f,
371 -2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 0.0f, -2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f,
372 4.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -2.0f/9.0f, 8.0f/9.0f,
373 -8.0f/9.0f, 0.0f, 8.0f/9.0f, -6.0f/9.0f, 0.0f, 8.0f/9.0f, -4.0f/9.0f, 0.0f, 8.0f/9.0f,
374 -2.0f/9.0f, 0.0f, 8.0f/9.0f, 0.0f, 0.0f, 8.0f/9.0f, 2.0f/9.0f, 0.0f, 8.0f/9.0f,
375 4.0f/9.0f, 0.0f, 8.0f/9.0f, 6.0f/9.0f, 0.0f, 8.0f/9.0f, 8.0f/9.0f, 0.0f, 8.0f/9.0f,
376 -8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f,
377 -2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 0.0f, 2.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f,
378 4.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f,
379 -8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f,
380 -2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 0.0f, 4.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f,
381 4.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 4.0f/9.0f, 8.0f/9.0f,
382 -8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f,
383 -2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 0.0f, 6.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f,
384 4.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f,
385 -8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, -4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f,
386 -2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 0.0f, 8.0f/9.0f, 8.0f/9.0f, 2.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f,
387 4.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 6.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f, 8.0f/9.0f
388 };
389
390 // data taken from ISO/IEC DIS 11172, Annexes 3-B.2[abcd] and 3-B.4:
391
392 // subbands 0-2 in tables 3-B.2a and 2b: (index is allocation)
393 public static final int table_ab1_codelength[] =
394 // bits per codeword
395 { 0, 5, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
396
397 public static final float table_ab1_groupingtables[][] =
398 // pointer to sample grouping table, or NULL-pointer if ungrouped
399 { null, grouping_5bits, null, null, null, null, null, null, null, null, null, null, null, null, null, null };
400
401 public static final float table_ab1_factor[] =
402 // factor for requantization: (real)sample * factor - 1.0 gives requantized sample
403 { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/16.0f, 1.0f/32.0f, 1.0f/64.0f,
404 1.0f/128.0f, 1.0f/256.0f, 1.0f/512.0f, 1.0f/1024.0f, 1.0f/2048.0f,
405 1.0f/4096.0f, 1.0f/8192.0f, 1.0f/16384.0f, 1.0f/32768.0f };
406
407 public static final float table_ab1_c[] =
408 // factor c for requantization from table 3-B.4
409 { 0.0f, 1.33333333333f, 1.14285714286f, 1.06666666666f, 1.03225806452f,
410 1.01587301587f, 1.00787401575f, 1.00392156863f, 1.00195694716f, 1.00097751711f,
411 1.00048851979f, 1.00024420024f, 1.00012208522f, 1.00006103888f, 1.00003051851f,
412 1.00001525902f };
413
414 public static final float table_ab1_d[] =
415 // addend d for requantization from table 3-B.4
416 { 0.0f, 0.50000000000f, 0.25000000000f, 0.12500000000f, 0.06250000000f,
417 0.03125000000f, 0.01562500000f, 0.00781250000f, 0.00390625000f, 0.00195312500f,
418 0.00097656250f, 0.00048828125f, 0.00024414063f, 0.00012207031f, 0.00006103516f,
419 0.00003051758f };
420
421 // subbands 3-... tables 3-B.2a and 2b:
422 public static final float[] table_ab234_groupingtables[] =
423 { null, grouping_5bits, grouping_7bits, null, grouping_10bits, null, null, null, null, null, null, null, null, null, null, null };
424
425 // subbands 3-10 in tables 3-B.2a and 2b:
426 public static final int table_ab2_codelength[] =
427 { 0, 5, 7, 3, 10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 };
428 public static final float table_ab2_factor[] =
429 { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/8.0f, 1.0f/16.0f,
430 1.0f/32.0f, 1.0f/64.0f, 1.0f/128.0f, 1.0f/256.0f, 1.0f/512.0f,
431 1.0f/1024.0f, 1.0f/2048.0f, 1.0f/4096.0f, 1.0f/32768.0f };
432 public static final float table_ab2_c[] =
433 { 0.0f, 1.33333333333f, 1.60000000000f, 1.14285714286f, 1.77777777777f,
434 1.06666666666f, 1.03225806452f, 1.01587301587f, 1.00787401575f, 1.00392156863f,
435 1.00195694716f, 1.00097751711f, 1.00048851979f, 1.00024420024f, 1.00012208522f,
436 1.00001525902f };
437 public static final float table_ab2_d[] =
438 { 0.0f, 0.50000000000f, 0.50000000000f, 0.25000000000f, 0.50000000000f,
439 0.12500000000f, 0.06250000000f, 0.03125000000f, 0.01562500000f, 0.00781250000f,
440 0.00390625000f, 0.00195312500f, 0.00097656250f, 0.00048828125f, 0.00024414063f,
441 0.00003051758f };
442
443 // subbands 11-22 in tables 3-B.2a and 2b:
444 public static final int table_ab3_codelength[] = { 0, 5, 7, 3, 10, 4, 5, 16 };
445 public static final float table_ab3_factor[] =
446 { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/8.0f, 1.0f/16.0f, 1.0f/32768.0f };
447 public static final float table_ab3_c[] =
448 { 0.0f, 1.33333333333f, 1.60000000000f, 1.14285714286f, 1.77777777777f,
449 1.06666666666f, 1.03225806452f, 1.00001525902f };
450 public static final float table_ab3_d[] =
451 { 0.0f, 0.50000000000f, 0.50000000000f, 0.25000000000f, 0.50000000000f,
452 0.12500000000f, 0.06250000000f, 0.00003051758f };
453
454 // subbands 23-... in tables 3-B.2a and 2b:
455 public static final int table_ab4_codelength[] = { 0, 5, 7, 16 };
456 public static final float table_ab4_factor[] = { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/32768.0f };
457 public static final float table_ab4_c[] = { 0.0f, 1.33333333333f, 1.60000000000f, 1.00001525902f };
458 public static final float table_ab4_d[] = { 0.0f, 0.50000000000f, 0.50000000000f, 0.00003051758f };
459
460 // subbands in tables 3-B.2c and 2d:
461 public static final int table_cd_codelength[] =
462 { 0, 5, 7, 10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
463 public static final float table_cd_groupingtables[][] =
464 { null, grouping_5bits, grouping_7bits, grouping_10bits, null, null, null, null, null, null, null, null, null, null, null, null };
465 public static final float table_cd_factor[] =
466 { 0.0f, 1.0f/2.0f, 1.0f/4.0f, 1.0f/8.0f, 1.0f/8.0f, 1.0f/16.0f, 1.0f/32.0f, 1.0f/64.0f,
467 1.0f/128.0f, 1.0f/256.0f, 1.0f/512.0f, 1.0f/1024.0f, 1.0f/2048.0f, 1.0f/4096.0f,
468 1.0f/8192.0f, 1.0f/16384.0f };
469 public static final float table_cd_c[] =
470 { 0.0f, 1.33333333333f, 1.60000000000f, 1.77777777777f, 1.06666666666f,
471 1.03225806452f, 1.01587301587f, 1.00787401575f, 1.00392156863f, 1.00195694716f,
472 1.00097751711f, 1.00048851979f, 1.00024420024f, 1.00012208522f, 1.00006103888f,
473 1.00003051851f };
474 public static final float table_cd_d[] =
475 { 0.0f, 0.50000000000f, 0.50000000000f, 0.50000000000f, 0.12500000000f,
476 0.06250000000f, 0.03125000000f, 0.01562500000f, 0.00781250000f, 0.00390625000f,
477 0.00195312500f, 0.00097656250f, 0.00048828125f, 0.00024414063f, 0.00012207031f,
478 0.00006103516f };
479
480
481
482 protected int subbandnumber;
483 protected int allocation;
484 protected int scfsi;
485 protected float scalefactor1, scalefactor2, scalefactor3;
486 protected int[] codelength = {0};
487 protected float groupingtable[][] = new float[2][];
488 //protected float[][] groupingtable = {{0},{0}} ;
489 protected float[] factor = {0.0f};
490 protected int groupnumber;
491 protected int samplenumber;
492 protected float[] samples = new float[3];
493 protected float[] c = {0};
494 protected float[] d = {0};
495 /**
496 * Constructor
497 */
498 public SubbandLayer2(int subbandnumber)
499 {
500 this.subbandnumber = subbandnumber;
501 groupnumber = samplenumber = 0;
502 }
503
504
505 /**
506 *
507 */
508 protected int get_allocationlength (Header header)
509 {
510 if (header.version() == Header.MPEG1)
511 {
512 int channel_bitrate = header.bitrate_index();
513
514 // calculate bitrate per channel:
515 if (header.mode() != Header.SINGLE_CHANNEL)
516 if (channel_bitrate == 4)
517 channel_bitrate = 1;
518 else
519 channel_bitrate -= 4;
520
521 if (channel_bitrate == 1 || channel_bitrate == 2)
522 // table 3-B.2c or 3-B.2d
523 if (subbandnumber <= 1)
524 return 4;
525 else
526 return 3;
527 else
528 // tables 3-B.2a or 3-B.2b
529 if (subbandnumber <= 10)
530 return 4;
531 else if (subbandnumber <= 22)
532 return 3;
533 else
534 return 2;
535 }
536 else
537 { // MPEG-2 LSF -- Jeff
538
539 // table B.1 of ISO/IEC 13818-3
540 if (subbandnumber <= 3)
541 return 4;
542 else if (subbandnumber <= 10)
543 return 3;
544 else
545 return 2;
546 }
547 }
548
549 /**
550 *
551 */
552 protected void prepare_sample_reading(Header header, int allocation,
553 //float[][] groupingtable,
554 int channel,
555 float[] factor, int[] codelength,
556 float[] c, float[] d)
557 {
558 int channel_bitrate = header.bitrate_index();
559 // calculate bitrate per channel:
560 if (header.mode() != Header.SINGLE_CHANNEL)
561 if (channel_bitrate == 4)
562 channel_bitrate = 1;
563 else
564 channel_bitrate -= 4;
565
566 if (channel_bitrate == 1 || channel_bitrate == 2)
567 {
568 // table 3-B.2c or 3-B.2d
569 groupingtable[channel] = table_cd_groupingtables[allocation];
570 factor[0] = table_cd_factor[allocation];
571 codelength[0] = table_cd_codelength[allocation];
572 c[0] = table_cd_c[allocation];
573 d[0] = table_cd_d[allocation];
574 }
575 else
576 {
577 // tables 3-B.2a or 3-B.2b
578 if (subbandnumber <= 2)
579 {
580 groupingtable[channel] = table_ab1_groupingtables[allocation];
581 factor[0] = table_ab1_factor[allocation];
582 codelength[0] = table_ab1_codelength[allocation];
583 c[0] = table_ab1_c[allocation];
584 d[0] = table_ab1_d[allocation];
585 }
586 else
587 {
588 groupingtable[channel] = table_ab234_groupingtables[allocation];
589 if (subbandnumber <= 10)
590 {
591 factor[0] = table_ab2_factor[allocation];
592 codelength[0] = table_ab2_codelength[allocation];
593 c[0] = table_ab2_c[allocation];
594 d[0] = table_ab2_d[allocation];
595 }
596 else if (subbandnumber <= 22)
597 {
598 factor[0] = table_ab3_factor[allocation];
599 codelength[0] = table_ab3_codelength[allocation];
600 c[0] = table_ab3_c[allocation];
601 d[0] = table_ab3_d[allocation];
602 }
603 else
604 {
605 factor[0] = table_ab4_factor[allocation];
606 codelength[0] = table_ab4_codelength[allocation];
607 c[0] = table_ab4_c[allocation];
608 d[0] = table_ab4_d[allocation];
609 }
610 }
611 }
612 }
613
614
615 /**
616 *
617 */
618 public void read_allocation(Bitstream stream, Header header, Crc16 crc)
619 {
620 int length = get_allocationlength(header);
621 allocation = stream.get_bits(length);
622 if (crc != null)
623 crc.add_bits(allocation, length);
624 }
625
626 /**
627 *
628 */
629 public void read_scalefactor_selection (Bitstream stream, Crc16 crc)
630 {
631 if (allocation != 0)
632 {
633 scfsi = stream.get_bits(2);
634 if (crc != null) crc.add_bits(scfsi, 2);
635 }
636 }
637
638 /**
639 *
640 */
641 public void read_scalefactor (Bitstream stream, Header header)
642 {
643 if (allocation != 0)
644 {
645 switch (scfsi)
646 {
647 case 0:
648 scalefactor1 = scalefactors[stream.get_bits(6)];
649 scalefactor2 = scalefactors[stream.get_bits(6)];
650 scalefactor3 = scalefactors[stream.get_bits(6)];
651 break;
652 case 1:
653 scalefactor1 = scalefactor2 = scalefactors[stream.get_bits(6)];
654 scalefactor3 = scalefactors[stream.get_bits(6)];
655 break;
656 case 2:
657 scalefactor1 = scalefactor2 = scalefactor3 = scalefactors[stream.get_bits(6)];
658 break;
659 case 3:
660 scalefactor1 = scalefactors[stream.get_bits(6)];
661 scalefactor2 = scalefactor3 = scalefactors[stream.get_bits(6)];
662 break;
663 }
664 prepare_sample_reading(header, allocation, 0,
665 factor, codelength, c, d);
666 }
667 }
668
669 /**
670 *
671 */
672 public boolean read_sampledata (Bitstream stream)
673 {
674 if (allocation != 0)
675 if (groupingtable[0] != null)
676 {
677 int samplecode = stream.get_bits(codelength[0]);
678 // create requantized samples:
679 samplecode += samplecode << 1;
680 float[] target = samples;
681 float[] source = groupingtable[0];
682 /*
683 int tmp = 0;
684 int temp = 0;
685 target[tmp++] = source[samplecode + temp];
686 temp++;
687 target[tmp++] = source[samplecode + temp];
688 temp++;
689 target[tmp] = source[samplecode + temp];
690 */
691 //Bugfix:
692 int tmp = 0;
693 int temp = samplecode;
694
695 if(temp > source.length - 3) temp = source.length - 3;
696
697 target[tmp] = source[temp];
698 temp++;tmp++;
699 target[tmp] = source[temp];
700 temp++;tmp++;
701 target[tmp] = source[temp];
702
703 // memcpy (samples, groupingtable + samplecode, 3 * sizeof (real));
704 }
705 else
706 {
707 samples[0] = (float) ((stream.get_bits(codelength[0])) * factor[0] - 1.0);
708 samples[1] = (float) ((stream.get_bits(codelength[0])) * factor[0] - 1.0);
709 samples[2] = (float) ((stream.get_bits(codelength[0])) * factor[0] - 1.0);
710 }
711
712 samplenumber = 0;
713 if (++groupnumber == 12)
714 return true;
715 else
716 return false;
717 }
718
719 /**
720 *
721 */
722 public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2)
723 {
724 if ((allocation != 0) && (channels != OutputChannels.RIGHT_CHANNEL))
725 {
726 float sample = samples[samplenumber];
727
728 if (groupingtable[0] == null)
729 sample = (sample + d[0]) * c[0];
730 if (groupnumber <= 4)
731 sample *= scalefactor1;
732 else if (groupnumber <= 8)
733 sample *= scalefactor2;
734 else
735 sample *= scalefactor3;
736 filter1.input_sample(sample, subbandnumber);
737 }
738
739 if (++samplenumber == 3)
740 return true;
741 else
742 return false;
743 }
744 };
745
746 /**
747 * Class for layer II subbands in joint stereo mode.
748 */
749 static class SubbandLayer2IntensityStereo extends SubbandLayer2
750 {
751 protected int channel2_scfsi;
752 protected float channel2_scalefactor1, channel2_scalefactor2, channel2_scalefactor3;
753
754 /**
755 * Constructor
756 */
757 public SubbandLayer2IntensityStereo (int subbandnumber)
758 {
759 super(subbandnumber);
760 }
761
762 /**
763 *
764 */
765 public void read_allocation(Bitstream stream, Header header, Crc16 crc)
766 {
767 super.read_allocation (stream, header, crc);
768 }
769
770 /**
771 *
772 */
773 public void read_scalefactor_selection(Bitstream stream, Crc16 crc)
774 {
775 if (allocation != 0)
776 {
777 scfsi = stream.get_bits(2);
778 channel2_scfsi = stream.get_bits(2);
779 if (crc != null)
780 {
781 crc.add_bits(scfsi, 2);
782 crc.add_bits(channel2_scfsi, 2);
783 }
784 }
785 }
786
787 /**
788 *
789 */
790 public void read_scalefactor(Bitstream stream, Header header)
791 {
792 if (allocation != 0)
793 {
794 super.read_scalefactor(stream, header);
795 switch (channel2_scfsi)
796 {
797 case 0:
798 channel2_scalefactor1 = scalefactors[stream.get_bits(6)];
799 channel2_scalefactor2 = scalefactors[stream.get_bits(6)];
800 channel2_scalefactor3 = scalefactors[stream.get_bits(6)];
801 break;
802
803 case 1:
804 channel2_scalefactor1 = channel2_scalefactor2 = scalefactors[stream.get_bits (6)];
805 channel2_scalefactor3 = scalefactors[stream.get_bits(6)];
806 break;
807
808 case 2:
809 channel2_scalefactor1 = channel2_scalefactor2 =
810 channel2_scalefactor3 = scalefactors[stream.get_bits(6)];
811 break;
812
813 case 3:
814 channel2_scalefactor1 = scalefactors[stream.get_bits(6)];
815 channel2_scalefactor2 = channel2_scalefactor3 = scalefactors[stream.get_bits (6)];
816 break;
817 }
818 }
819
820 }
821
822 /**
823 *
824 */
825 public boolean read_sampledata(Bitstream stream)
826 {
827 return super.read_sampledata (stream);
828 }
829
830 /**
831 *
832 */
833 public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2)
834 {
835 if (allocation != 0)
836 {
837 float sample = samples[samplenumber];
838
839 if (groupingtable[0] == null)
840 sample = (sample + d[0]) * c[0];
841 if (channels == OutputChannels.BOTH_CHANNELS)
842 {
843 float sample2 = sample;
844 if (groupnumber <= 4)
845 {
846 sample *= scalefactor1;
847 sample2 *= channel2_scalefactor1;
848 }
849 else if (groupnumber <= 8)
850 {
851 sample *= scalefactor2;
852 sample2 *= channel2_scalefactor2;
853 }
854 else
855 {
856 sample *= scalefactor3;
857 sample2 *= channel2_scalefactor3;
858 }
859 filter1.input_sample(sample, subbandnumber);
860 filter2.input_sample(sample2, subbandnumber);
861 }
862 else if (channels == OutputChannels.LEFT_CHANNEL)
863 {
864 if (groupnumber <= 4)
865 sample *= scalefactor1;
866 else if (groupnumber <= 8)
867 sample *= scalefactor2;
868 else
869 sample *= scalefactor3;
870 filter1.input_sample(sample, subbandnumber);
871 }
872 else
873 {
874 if (groupnumber <= 4)
875 sample *= channel2_scalefactor1;
876 else if (groupnumber <= 8)
877 sample *= channel2_scalefactor2;
878 else
879 sample *= channel2_scalefactor3;
880 filter1.input_sample(sample, subbandnumber);
881 }
882 }
883
884 if (++samplenumber == 3)
885 return true;
886 else
887 return false;
888 }
889 };
890
891 /**
892 * Class for layer II subbands in stereo mode.
893 */
894 static class SubbandLayer2Stereo extends SubbandLayer2
895 {
896 protected int channel2_allocation;
897 protected int channel2_scfsi;
898 protected float channel2_scalefactor1, channel2_scalefactor2, channel2_scalefactor3;
899 //protected boolean channel2_grouping; ???? Never used!
900 protected int[] channel2_codelength = {0};
901 //protected float[][] channel2_groupingtable = {{0},{0}};
902 protected float[] channel2_factor = {0};
903 protected float[] channel2_samples;
904 protected float[] channel2_c = {0};
905 protected float[] channel2_d = {0};
906
907 /**
908 * Constructor
909 */
910 public SubbandLayer2Stereo(int subbandnumber)
911 {
912 super(subbandnumber);
913 channel2_samples = new float[3];
914 }
915
916 /**
917 *
918 */
919 public void read_allocation (Bitstream stream, Header header, Crc16 crc)
920 {
921 int length = get_allocationlength(header);
922 allocation = stream.get_bits(length);
923 channel2_allocation = stream.get_bits(length);
924 if (crc != null)
925 {
926 crc.add_bits(allocation, length);
927 crc.add_bits(channel2_allocation, length);
928 }
929 }
930
931 /**
932 *
933 */
934 public void read_scalefactor_selection(Bitstream stream, Crc16 crc)
935 {
936 if (allocation != 0)
937 {
938 scfsi = stream.get_bits(2);
939 if (crc != null)
940 crc.add_bits(scfsi, 2);
941 }
942 if (channel2_allocation != 0)
943 {
944 channel2_scfsi = stream.get_bits(2);
945 if (crc != null)
946 crc.add_bits(channel2_scfsi, 2);
947 }
948 }
949
950 /**
951 *
952 */
953 public void read_scalefactor(Bitstream stream, Header header)
954 {
955 super.read_scalefactor(stream, header);
956 if (channel2_allocation != 0)
957 {
958 switch (channel2_scfsi)
959 {
960 case 0:
961 channel2_scalefactor1 = scalefactors[stream.get_bits(6)];
962 channel2_scalefactor2 = scalefactors[stream.get_bits(6)];
963 channel2_scalefactor3 = scalefactors[stream.get_bits(6)];
964 break;
965
966 case 1:
967 channel2_scalefactor1 = channel2_scalefactor2 =
968 scalefactors[stream.get_bits(6)];
969 channel2_scalefactor3 = scalefactors[stream.get_bits(6)];
970 break;
971
972 case 2:
973 channel2_scalefactor1 = channel2_scalefactor2 =
974 channel2_scalefactor3 = scalefactors[stream.get_bits(6)];
975 break;
976
977 case 3:
978 channel2_scalefactor1 = scalefactors[stream.get_bits(6)];
979 channel2_scalefactor2 = channel2_scalefactor3 =
980 scalefactors[stream.get_bits(6)];
981 break;
982 }
983 prepare_sample_reading(header, channel2_allocation, 1,
984 channel2_factor, channel2_codelength, channel2_c,
985 channel2_d);
986 }
987 }
988
989 /**
990 *
991 */
992 public boolean read_sampledata (Bitstream stream)
993 {
994 boolean returnvalue = super.read_sampledata(stream);
995
996 if (channel2_allocation != 0)
997 if (groupingtable[1] != null)
998 {
999 int samplecode = stream.get_bits(channel2_codelength[0]);
1000 // create requantized samples:
1001 samplecode += samplecode << 1;
1002 /*
1003 float[] target = channel2_samples;
1004 float[] source = channel2_groupingtable[0];
1005 int tmp = 0;
1006 int temp = 0;
1007 target[tmp++] = source[samplecode + temp];
1008 temp++;
1009 target[tmp++] = source[samplecode + temp];
1010 temp++;
1011 target[tmp] = source[samplecode + temp];
1012 // memcpy (channel2_samples, channel2_groupingtable + samplecode, 3 * sizeof (real));
1013 */
1014 float[] target = channel2_samples;
1015 float[] source = groupingtable[1];
1016 int tmp = 0;
1017 int temp = samplecode;
1018 target[tmp] = source[temp];
1019 temp++;tmp++;
1020 target[tmp] = source[temp];
1021 temp++;tmp++;
1022 target[tmp] = source[temp];
1023
1024 }
1025 else
1026 {
1027 channel2_samples[0] = (float) ((stream.get_bits(channel2_codelength[0])) *
1028 channel2_factor[0] - 1.0);
1029 channel2_samples[1] = (float) ((stream.get_bits(channel2_codelength[0])) *
1030 channel2_factor[0] - 1.0);
1031 channel2_samples[2] = (float) ((stream.get_bits(channel2_codelength[0])) *
1032 channel2_factor[0] - 1.0);
1033 }
1034 return returnvalue;
1035 }
1036
1037 /**
1038 *
1039 */
1040 public boolean put_next_sample(int channels, SynthesisFilter filter1, SynthesisFilter filter2)
1041 {
1042 boolean returnvalue = super.put_next_sample(channels, filter1, filter2);
1043 if ((channel2_allocation != 0) && (channels != OutputChannels.LEFT_CHANNEL))
1044 {
1045 float sample = channel2_samples[samplenumber - 1];
1046
1047 if (groupingtable[1] == null)
1048 sample = (sample + channel2_d[0]) * channel2_c[0];
1049
1050 if (groupnumber <= 4)
1051 sample *= channel2_scalefactor1;
1052 else if (groupnumber <= 8)
1053 sample *= channel2_scalefactor2;
1054 else
1055 sample *= channel2_scalefactor3;
1056 if (channels == OutputChannels.BOTH_CHANNELS)
1057 filter2.input_sample(sample, subbandnumber);
1058 else
1059 filter1.input_sample(sample, subbandnumber);
1060 }
1061 return returnvalue;
1062 }
1063 }
1064}
diff --git a/songdbj/javazoom/jl/decoder/LayerIIIDecoder.java b/songdbj/javazoom/jl/decoder/LayerIIIDecoder.java
new file mode 100644
index 0000000000..602badf0f2
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/LayerIIIDecoder.java
@@ -0,0 +1,2439 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *
4 * 18/06/01 Michael Scheerer, Fixed bugs which causes
5 * negative indexes in method huffmann_decode and in method
6 * dequanisize_sample.
7 *
8 * 16/07/01 Michael Scheerer, Catched a bug in method
9 * huffmann_decode, which causes an outOfIndexException.
10 * Cause : Indexnumber of 24 at SfBandIndex,
11 * which has only a length of 22. I have simply and dirty
12 * fixed the index to <= 22, because I'm not really be able
13 * to fix the bug. The Indexnumber is taken from the MP3
14 * file and the origin Ma-Player with the same code works
15 * well.
16 *
17 * 02/19/99 Java Conversion by E.B, javalayer@javazoom.net
18 *-----------------------------------------------------------------------
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU Library General Public License as published
21 * by the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU Library General Public License for more details.
28 *
29 * You should have received a copy of the GNU Library General Public
30 * License along with this program; if not, write to the Free Software
31 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 *----------------------------------------------------------------------
33 */
34
35package javazoom.jl.decoder;
36
37/**
38 * Class Implementing Layer 3 Decoder.
39 *
40 * @since 0.0
41 */
42final class LayerIIIDecoder implements FrameDecoder
43{
44 final double d43 = (4.0/3.0);
45
46 public int[] scalefac_buffer;
47
48 // MDM: removed, as this wasn't being used.
49 //private float CheckSumOut1d = 0.0f;
50 private int CheckSumHuff = 0;
51 private int[] is_1d;
52 private float[][][] ro;
53 private float[][][] lr;
54 private float[] out_1d;
55 private float[][] prevblck;
56 private float[][] k;
57 private int[] nonzero;
58 private Bitstream stream;
59 private Header header;
60 private SynthesisFilter filter1, filter2;
61 private Obuffer buffer;
62 private int which_channels;
63 private BitReserve br;
64 private III_side_info_t si;
65
66 private temporaire2[] III_scalefac_t;
67 private temporaire2[] scalefac;
68 // private III_scalefac_t scalefac;
69
70 private int max_gr;
71 private int frame_start;
72 private int part2_start;
73 private int channels;
74 private int first_channel;
75 private int last_channel;
76 private int sfreq;
77
78
79 /**
80 * Constructor.
81 */
82 // REVIEW: these constructor arguments should be moved to the
83 // decodeFrame() method, where possible, so that one
84 public LayerIIIDecoder(Bitstream stream0, Header header0,
85 SynthesisFilter filtera, SynthesisFilter filterb,
86 Obuffer buffer0, int which_ch0)
87 {
88 huffcodetab.inithuff();
89 is_1d = new int[SBLIMIT*SSLIMIT+4];
90 ro = new float[2][SBLIMIT][SSLIMIT];
91 lr = new float[2][SBLIMIT][SSLIMIT];
92 out_1d = new float[SBLIMIT*SSLIMIT];
93 prevblck = new float[2][SBLIMIT*SSLIMIT];
94 k = new float[2][SBLIMIT*SSLIMIT];
95 nonzero = new int[2];
96
97 //III_scalefact_t
98 III_scalefac_t = new temporaire2[2];
99 III_scalefac_t[0] = new temporaire2();
100 III_scalefac_t[1] = new temporaire2();
101 scalefac = III_scalefac_t;
102 // L3TABLE INIT
103
104 sfBandIndex = new SBI[9]; // SZD: MPEG2.5 +3 indices
105 int[] l0 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576};
106 int[] s0 = {0,4,8,12,18,24,32,42,56,74,100,132,174,192};
107 int[] l1 = {0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,330,394,464,540,576};
108 int[] s1 = {0,4,8,12,18,26,36,48,62,80,104,136,180,192};
109 int[] l2 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576};
110 int[] s2 = {0,4,8,12,18,26,36,48,62,80,104,134,174,192};
111
112 int[] l3 = {0,4,8,12,16,20,24,30,36,44,52,62,74,90,110,134,162,196,238,288,342,418,576};
113 int[] s3 = {0,4,8,12,16,22,30,40,52,66,84,106,136,192};
114 int[] l4 = {0,4,8,12,16,20,24,30,36,42,50,60,72,88,106,128,156,190,230,276,330,384,576};
115 int[] s4 = {0,4,8,12,16,22,28,38,50,64,80,100,126,192};
116 int[] l5 = {0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576};
117 int[] s5 = {0,4,8,12,16,22,30,42,58,78,104,138,180,192};
118 // SZD: MPEG2.5
119 int[] l6 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576};
120 int[] s6 = {0,4,8,12,18,26,36,48,62,80,104,134,174,192};
121 int[] l7 = {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576};
122 int[] s7 = {0,4,8,12,18,26,36,48,62,80,104,134,174,192};
123 int[] l8 = {0,12,24,36,48,60,72,88,108,132,160,192,232,280,336,400,476,566,568,570,572,574,576};
124 int[] s8 = {0,8,16,24,36,52,72,96,124,160,162,164,166,192};
125
126 sfBandIndex[0]= new SBI(l0,s0);
127 sfBandIndex[1]= new SBI(l1,s1);
128 sfBandIndex[2]= new SBI(l2,s2);
129
130 sfBandIndex[3]= new SBI(l3,s3);
131 sfBandIndex[4]= new SBI(l4,s4);
132 sfBandIndex[5]= new SBI(l5,s5);
133 //SZD: MPEG2.5
134 sfBandIndex[6]= new SBI(l6,s6);
135 sfBandIndex[7]= new SBI(l7,s7);
136 sfBandIndex[8]= new SBI(l8,s8);
137 // END OF L3TABLE INIT
138
139 if(reorder_table == null) { // SZD: generate LUT
140 reorder_table = new int[9][];
141 for(int i = 0; i < 9; i++)
142 reorder_table[i] = reorder(sfBandIndex[i].s);
143 }
144
145 // Sftable
146 int[] ll0 = {0, 6, 11, 16, 21};
147 int[] ss0 = {0, 6, 12};
148 sftable = new Sftable(ll0,ss0);
149 // END OF Sftable
150
151 // scalefac_buffer
152 scalefac_buffer = new int[54];
153 // END OF scalefac_buffer
154
155 stream = stream0;
156 header = header0;
157 filter1 = filtera;
158 filter2 = filterb;
159 buffer = buffer0;
160 which_channels = which_ch0;
161
162 frame_start = 0;
163 channels = (header.mode() == Header.SINGLE_CHANNEL) ? 1 : 2;
164 max_gr = (header.version() == Header.MPEG1) ? 2 : 1;
165
166 sfreq = header.sample_frequency() +
167 ((header.version() == Header.MPEG1) ? 3 :
168 (header.version() == Header.MPEG25_LSF) ? 6 : 0); // SZD
169
170 if (channels == 2)
171 {
172 switch (which_channels)
173 {
174 case OutputChannels.LEFT_CHANNEL:
175 case OutputChannels.DOWNMIX_CHANNELS:
176 first_channel = last_channel = 0;
177 break;
178
179 case OutputChannels.RIGHT_CHANNEL:
180 first_channel = last_channel = 1;
181 break;
182
183 case OutputChannels.BOTH_CHANNELS:
184 default:
185 first_channel = 0;
186 last_channel = 1;
187 break;
188 }
189 }
190 else
191 {
192 first_channel = last_channel = 0;
193 }
194
195 for(int ch=0;ch<2;ch++)
196 for (int j=0; j<576; j++)
197 prevblck[ch][j] = 0.0f;
198
199 nonzero[0] = nonzero[1] = 576;
200
201 br = new BitReserve();
202 si = new III_side_info_t();
203 }
204
205 /**
206 * Notify decoder that a seek is being made.
207 */
208 public void seek_notify()
209 {
210 frame_start = 0;
211 for(int ch=0;ch<2;ch++)
212 for (int j=0; j<576; j++)
213 prevblck[ch][j] = 0.0f;
214 br = new BitReserve();
215 }
216
217 public void decodeFrame()
218 {
219 decode();
220 }
221
222 /**
223 * Decode one frame, filling the buffer with the output samples.
224 */
225
226 // subband samples are buffered and passed to the
227 // SynthesisFilter in one go.
228 private float[] samples1 = new float[32];
229 private float[] samples2 = new float[32];
230
231 public void decode()
232 {
233 int nSlots = header.slots();
234 int flush_main;
235 int gr, ch, ss, sb, sb18;
236 int main_data_end;
237 int bytes_to_discard;
238 int i;
239
240 get_side_info();
241
242 for (i=0; i<nSlots; i++)
243 br.hputbuf(stream.get_bits(8));
244
245 main_data_end = br.hsstell() >>> 3; // of previous frame
246
247 if ((flush_main = (br.hsstell() & 7)) != 0) {
248 br.hgetbits(8 - flush_main);
249 main_data_end++;
250 }
251
252 bytes_to_discard = frame_start - main_data_end
253 - si.main_data_begin;
254
255 frame_start += nSlots;
256
257 if (bytes_to_discard < 0)
258 return;
259
260 if (main_data_end > 4096) {
261 frame_start -= 4096;
262 br.rewindNbytes(4096);
263 }
264
265 for (; bytes_to_discard > 0; bytes_to_discard--)
266 br.hgetbits(8);
267
268 for (gr=0;gr<max_gr;gr++) {
269
270 for (ch=0; ch<channels; ch++) {
271 part2_start = br.hsstell();
272
273 if (header.version() == Header.MPEG1)
274 get_scale_factors(ch, gr);
275 else // MPEG-2 LSF, SZD: MPEG-2.5 LSF
276 get_LSF_scale_factors(ch, gr);
277
278 huffman_decode(ch, gr);
279 // System.out.println("CheckSum HuffMan = " + CheckSumHuff);
280 dequantize_sample(ro[ch], ch, gr);
281 }
282
283 stereo(gr);
284
285 if ((which_channels == OutputChannels.DOWNMIX_CHANNELS) && (channels > 1))
286 do_downmix();
287
288 for (ch=first_channel; ch<=last_channel; ch++) {
289
290 reorder(lr[ch], ch, gr);
291 antialias(ch, gr);
292 //for (int hb = 0;hb<576;hb++) CheckSumOut1d = CheckSumOut1d + out_1d[hb];
293 //System.out.println("CheckSumOut1d = "+CheckSumOut1d);
294
295 hybrid(ch, gr);
296
297 //for (int hb = 0;hb<576;hb++) CheckSumOut1d = CheckSumOut1d + out_1d[hb];
298 //System.out.println("CheckSumOut1d = "+CheckSumOut1d);
299
300 for (sb18=18;sb18<576;sb18+=36) // Frequency inversion
301 for (ss=1;ss<SSLIMIT;ss+=2)
302 out_1d[sb18 + ss] = -out_1d[sb18 + ss];
303
304 if ((ch == 0) || (which_channels == OutputChannels.RIGHT_CHANNEL)) {
305 for (ss=0;ss<SSLIMIT;ss++) { // Polyphase synthesis
306 sb = 0;
307 for (sb18=0; sb18<576; sb18+=18) {
308 samples1[sb] = out_1d[sb18+ss];
309 //filter1.input_sample(out_1d[sb18+ss], sb);
310 sb++;
311 }
312 filter1.input_samples(samples1);
313 filter1.calculate_pcm_samples(buffer);
314 }
315 } else {
316 for (ss=0;ss<SSLIMIT;ss++) { // Polyphase synthesis
317 sb = 0;
318 for (sb18=0; sb18<576; sb18+=18) {
319 samples2[sb] = out_1d[sb18+ss];
320 //filter2.input_sample(out_1d[sb18+ss], sb);
321 sb++;
322 }
323 filter2.input_samples(samples2);
324 filter2.calculate_pcm_samples(buffer);
325 }
326
327 }
328 } // channels
329 } // granule
330
331
332 // System.out.println("Counter = ................................."+counter);
333 //if (counter < 609)
334 //{
335 counter++;
336 buffer.write_buffer(1);
337 //}
338 //else if (counter == 609)
339 //{
340 // buffer.close();
341 // counter++;
342 //}
343 //else
344 //{
345 //}
346
347 }
348
349 /**
350 * Reads the side info from the stream, assuming the entire.
351 * frame has been read already.
352 * Mono : 136 bits (= 17 bytes)
353 * Stereo : 256 bits (= 32 bytes)
354 */
355 private boolean get_side_info()
356 {
357 int ch, gr;
358 if (header.version() == Header.MPEG1)
359 {
360
361 si.main_data_begin = stream.get_bits(9);
362 if (channels == 1)
363 si.private_bits = stream.get_bits(5);
364 else si.private_bits = stream.get_bits(3);
365
366 for (ch=0; ch<channels; ch++) {
367 si.ch[ch].scfsi[0] = stream.get_bits(1);
368 si.ch[ch].scfsi[1] = stream.get_bits(1);
369 si.ch[ch].scfsi[2] = stream.get_bits(1);
370 si.ch[ch].scfsi[3] = stream.get_bits(1);
371 }
372
373 for (gr=0; gr<2; gr++) {
374 for (ch=0; ch<channels; ch++) {
375 si.ch[ch].gr[gr].part2_3_length = stream.get_bits(12);
376 si.ch[ch].gr[gr].big_values = stream.get_bits(9);
377 si.ch[ch].gr[gr].global_gain = stream.get_bits(8);
378 si.ch[ch].gr[gr].scalefac_compress = stream.get_bits(4);
379 si.ch[ch].gr[gr].window_switching_flag = stream.get_bits(1);
380 if ((si.ch[ch].gr[gr].window_switching_flag) != 0) {
381 si.ch[ch].gr[gr].block_type = stream.get_bits(2);
382 si.ch[ch].gr[gr].mixed_block_flag = stream.get_bits(1);
383
384 si.ch[ch].gr[gr].table_select[0] = stream.get_bits(5);
385 si.ch[ch].gr[gr].table_select[1] = stream.get_bits(5);
386
387 si.ch[ch].gr[gr].subblock_gain[0] = stream.get_bits(3);
388 si.ch[ch].gr[gr].subblock_gain[1] = stream.get_bits(3);
389 si.ch[ch].gr[gr].subblock_gain[2] = stream.get_bits(3);
390
391 // Set region_count parameters since they are implicit in this case.
392
393 if (si.ch[ch].gr[gr].block_type == 0) {
394 // Side info bad: block_type == 0 in split block
395 return false;
396 } else if (si.ch[ch].gr[gr].block_type == 2
397 && si.ch[ch].gr[gr].mixed_block_flag == 0) {
398 si.ch[ch].gr[gr].region0_count = 8;
399 } else {
400 si.ch[ch].gr[gr].region0_count = 7;
401 }
402 si.ch[ch].gr[gr].region1_count = 20 -
403 si.ch[ch].gr[gr].region0_count;
404 } else {
405 si.ch[ch].gr[gr].table_select[0] = stream.get_bits(5);
406 si.ch[ch].gr[gr].table_select[1] = stream.get_bits(5);
407 si.ch[ch].gr[gr].table_select[2] = stream.get_bits(5);
408 si.ch[ch].gr[gr].region0_count = stream.get_bits(4);
409 si.ch[ch].gr[gr].region1_count = stream.get_bits(3);
410 si.ch[ch].gr[gr].block_type = 0;
411 }
412 si.ch[ch].gr[gr].preflag = stream.get_bits(1);
413 si.ch[ch].gr[gr].scalefac_scale = stream.get_bits(1);
414 si.ch[ch].gr[gr].count1table_select = stream.get_bits(1);
415 }
416 }
417
418 } else { // MPEG-2 LSF, SZD: MPEG-2.5 LSF
419
420 si.main_data_begin = stream.get_bits(8);
421 if (channels == 1)
422 si.private_bits = stream.get_bits(1);
423 else si.private_bits = stream.get_bits(2);
424
425 for (ch=0; ch<channels; ch++) {
426
427 si.ch[ch].gr[0].part2_3_length = stream.get_bits(12);
428 si.ch[ch].gr[0].big_values = stream.get_bits(9);
429 si.ch[ch].gr[0].global_gain = stream.get_bits(8);
430 si.ch[ch].gr[0].scalefac_compress = stream.get_bits(9);
431 si.ch[ch].gr[0].window_switching_flag = stream.get_bits(1);
432
433 if ((si.ch[ch].gr[0].window_switching_flag) != 0) {
434
435 si.ch[ch].gr[0].block_type = stream.get_bits(2);
436 si.ch[ch].gr[0].mixed_block_flag = stream.get_bits(1);
437 si.ch[ch].gr[0].table_select[0] = stream.get_bits(5);
438 si.ch[ch].gr[0].table_select[1] = stream.get_bits(5);
439
440 si.ch[ch].gr[0].subblock_gain[0] = stream.get_bits(3);
441 si.ch[ch].gr[0].subblock_gain[1] = stream.get_bits(3);
442 si.ch[ch].gr[0].subblock_gain[2] = stream.get_bits(3);
443
444 // Set region_count parameters since they are implicit in this case.
445
446 if (si.ch[ch].gr[0].block_type == 0) {
447 // Side info bad: block_type == 0 in split block
448 return false;
449 } else if (si.ch[ch].gr[0].block_type == 2
450 && si.ch[ch].gr[0].mixed_block_flag == 0) {
451 si.ch[ch].gr[0].region0_count = 8;
452 } else {
453 si.ch[ch].gr[0].region0_count = 7;
454 si.ch[ch].gr[0].region1_count = 20 -
455 si.ch[ch].gr[0].region0_count;
456 }
457
458 } else {
459 si.ch[ch].gr[0].table_select[0] = stream.get_bits(5);
460 si.ch[ch].gr[0].table_select[1] = stream.get_bits(5);
461 si.ch[ch].gr[0].table_select[2] = stream.get_bits(5);
462 si.ch[ch].gr[0].region0_count = stream.get_bits(4);
463 si.ch[ch].gr[0].region1_count = stream.get_bits(3);
464 si.ch[ch].gr[0].block_type = 0;
465 }
466
467 si.ch[ch].gr[0].scalefac_scale = stream.get_bits(1);
468 si.ch[ch].gr[0].count1table_select = stream.get_bits(1);
469 } // for(ch=0; ch<channels; ch++)
470 } // if (header.version() == MPEG1)
471 return true;
472 }
473
474 /**
475 *
476 */
477 private void get_scale_factors(int ch, int gr)
478 {
479 int sfb, window;
480 gr_info_s gr_info = (si.ch[ch].gr[gr]);
481 int scale_comp = gr_info.scalefac_compress;
482 int length0 = slen[0][scale_comp];
483 int length1 = slen[1][scale_comp];
484
485 if ((gr_info.window_switching_flag != 0) && (gr_info.block_type == 2)) {
486 if ((gr_info.mixed_block_flag) != 0) { // MIXED
487 for (sfb = 0; sfb < 8; sfb++)
488 scalefac[ch].l[sfb] = br.hgetbits(
489 slen[0][gr_info.scalefac_compress]);
490 for (sfb = 3; sfb < 6; sfb++)
491 for (window=0; window<3; window++)
492 scalefac[ch].s[window][sfb] = br.hgetbits(
493 slen[0][gr_info.scalefac_compress]);
494 for (sfb = 6; sfb < 12; sfb++)
495 for (window=0; window<3; window++)
496 scalefac[ch].s[window][sfb] = br.hgetbits(
497 slen[1][gr_info.scalefac_compress]);
498 for (sfb=12,window=0; window<3; window++)
499 scalefac[ch].s[window][sfb] = 0;
500
501 } else { // SHORT
502
503 scalefac[ch].s[0][0] = br.hgetbits(length0);
504 scalefac[ch].s[1][0] = br.hgetbits(length0);
505 scalefac[ch].s[2][0] = br.hgetbits(length0);
506 scalefac[ch].s[0][1] = br.hgetbits(length0);
507 scalefac[ch].s[1][1] = br.hgetbits(length0);
508 scalefac[ch].s[2][1] = br.hgetbits(length0);
509 scalefac[ch].s[0][2] = br.hgetbits(length0);
510 scalefac[ch].s[1][2] = br.hgetbits(length0);
511 scalefac[ch].s[2][2] = br.hgetbits(length0);
512 scalefac[ch].s[0][3] = br.hgetbits(length0);
513 scalefac[ch].s[1][3] = br.hgetbits(length0);
514 scalefac[ch].s[2][3] = br.hgetbits(length0);
515 scalefac[ch].s[0][4] = br.hgetbits(length0);
516 scalefac[ch].s[1][4] = br.hgetbits(length0);
517 scalefac[ch].s[2][4] = br.hgetbits(length0);
518 scalefac[ch].s[0][5] = br.hgetbits(length0);
519 scalefac[ch].s[1][5] = br.hgetbits(length0);
520 scalefac[ch].s[2][5] = br.hgetbits(length0);
521 scalefac[ch].s[0][6] = br.hgetbits(length1);
522 scalefac[ch].s[1][6] = br.hgetbits(length1);
523 scalefac[ch].s[2][6] = br.hgetbits(length1);
524 scalefac[ch].s[0][7] = br.hgetbits(length1);
525 scalefac[ch].s[1][7] = br.hgetbits(length1);
526 scalefac[ch].s[2][7] = br.hgetbits(length1);
527 scalefac[ch].s[0][8] = br.hgetbits(length1);
528 scalefac[ch].s[1][8] = br.hgetbits(length1);
529 scalefac[ch].s[2][8] = br.hgetbits(length1);
530 scalefac[ch].s[0][9] = br.hgetbits(length1);
531 scalefac[ch].s[1][9] = br.hgetbits(length1);
532 scalefac[ch].s[2][9] = br.hgetbits(length1);
533 scalefac[ch].s[0][10] = br.hgetbits(length1);
534 scalefac[ch].s[1][10] = br.hgetbits(length1);
535 scalefac[ch].s[2][10] = br.hgetbits(length1);
536 scalefac[ch].s[0][11] = br.hgetbits(length1);
537 scalefac[ch].s[1][11] = br.hgetbits(length1);
538 scalefac[ch].s[2][11] = br.hgetbits(length1);
539 scalefac[ch].s[0][12] = 0;
540 scalefac[ch].s[1][12] = 0;
541 scalefac[ch].s[2][12] = 0;
542 } // SHORT
543
544 } else { // LONG types 0,1,3
545
546 if ((si.ch[ch].scfsi[0] == 0) || (gr == 0)) {
547 scalefac[ch].l[0] = br.hgetbits(length0);
548 scalefac[ch].l[1] = br.hgetbits(length0);
549 scalefac[ch].l[2] = br.hgetbits(length0);
550 scalefac[ch].l[3] = br.hgetbits(length0);
551 scalefac[ch].l[4] = br.hgetbits(length0);
552 scalefac[ch].l[5] = br.hgetbits(length0);
553 }
554 if ((si.ch[ch].scfsi[1] == 0) || (gr == 0)) {
555 scalefac[ch].l[6] = br.hgetbits(length0);
556 scalefac[ch].l[7] = br.hgetbits(length0);
557 scalefac[ch].l[8] = br.hgetbits(length0);
558 scalefac[ch].l[9] = br.hgetbits(length0);
559 scalefac[ch].l[10] = br.hgetbits(length0);
560 }
561 if ((si.ch[ch].scfsi[2] == 0) || (gr == 0)) {
562 scalefac[ch].l[11] = br.hgetbits(length1);
563 scalefac[ch].l[12] = br.hgetbits(length1);
564 scalefac[ch].l[13] = br.hgetbits(length1);
565 scalefac[ch].l[14] = br.hgetbits(length1);
566 scalefac[ch].l[15] = br.hgetbits(length1);
567 }
568 if ((si.ch[ch].scfsi[3] == 0) || (gr == 0)) {
569 scalefac[ch].l[16] = br.hgetbits(length1);
570 scalefac[ch].l[17] = br.hgetbits(length1);
571 scalefac[ch].l[18] = br.hgetbits(length1);
572 scalefac[ch].l[19] = br.hgetbits(length1);
573 scalefac[ch].l[20] = br.hgetbits(length1);
574 }
575
576 scalefac[ch].l[21] = 0;
577 scalefac[ch].l[22] = 0;
578 }
579 }
580
581 /**
582 *
583 */
584 // MDM: new_slen is fully initialized before use, no need
585 // to reallocate array.
586 private final int[] new_slen = new int[4];
587
588 private void get_LSF_scale_data(int ch, int gr)
589 {
590
591 int scalefac_comp, int_scalefac_comp;
592 int mode_ext = header.mode_extension();
593 int m;
594 int blocktypenumber;
595 int blocknumber = 0;
596
597 gr_info_s gr_info = (si.ch[ch].gr[gr]);
598
599 scalefac_comp = gr_info.scalefac_compress;
600
601 if (gr_info.block_type == 2) {
602 if (gr_info.mixed_block_flag == 0)
603 blocktypenumber = 1;
604 else if (gr_info.mixed_block_flag == 1)
605 blocktypenumber = 2;
606 else
607 blocktypenumber = 0;
608 } else {
609 blocktypenumber = 0;
610 }
611
612 if(!(((mode_ext == 1) || (mode_ext == 3)) && (ch == 1))) {
613
614 if(scalefac_comp < 400) {
615
616 new_slen[0] = (scalefac_comp >>> 4) / 5 ;
617 new_slen[1] = (scalefac_comp >>> 4) % 5 ;
618 new_slen[2] = (scalefac_comp & 0xF) >>> 2 ;
619 new_slen[3] = (scalefac_comp & 3);
620 si.ch[ch].gr[gr].preflag = 0;
621 blocknumber = 0;
622
623 } else if (scalefac_comp < 500) {
624
625 new_slen[0] = ((scalefac_comp - 400) >>> 2) / 5 ;
626 new_slen[1] = ((scalefac_comp - 400) >>> 2) % 5 ;
627 new_slen[2] = (scalefac_comp - 400 ) & 3 ;
628 new_slen[3] = 0;
629 si.ch[ch].gr[gr].preflag = 0;
630 blocknumber = 1;
631
632 } else if (scalefac_comp < 512) {
633
634 new_slen[0] = (scalefac_comp - 500 ) / 3 ;
635 new_slen[1] = (scalefac_comp - 500) % 3 ;
636 new_slen[2] = 0;
637 new_slen[3] = 0;
638 si.ch[ch].gr[gr].preflag = 1;
639 blocknumber = 2;
640 }
641 }
642
643 if((((mode_ext == 1) || (mode_ext == 3)) && (ch == 1)))
644 {
645 int_scalefac_comp = scalefac_comp >>> 1;
646
647 if (int_scalefac_comp < 180)
648 {
649 new_slen[0] = int_scalefac_comp / 36 ;
650 new_slen[1] = (int_scalefac_comp % 36 ) / 6 ;
651 new_slen[2] = (int_scalefac_comp % 36) % 6;
652 new_slen[3] = 0;
653 si.ch[ch].gr[gr].preflag = 0;
654 blocknumber = 3;
655 } else if (int_scalefac_comp < 244) {
656 new_slen[0] = ((int_scalefac_comp - 180 ) & 0x3F) >>> 4 ;
657 new_slen[1] = ((int_scalefac_comp - 180) & 0xF) >>> 2 ;
658 new_slen[2] = (int_scalefac_comp - 180 ) & 3 ;
659 new_slen[3] = 0;
660 si.ch[ch].gr[gr].preflag = 0;
661 blocknumber = 4;
662 } else if (int_scalefac_comp < 255) {
663 new_slen[0] = (int_scalefac_comp - 244 ) / 3 ;
664 new_slen[1] = (int_scalefac_comp - 244 ) % 3 ;
665 new_slen[2] = 0 ;
666 new_slen[3] = 0;
667 si.ch[ch].gr[gr].preflag = 0;
668 blocknumber = 5;
669 }
670 }
671
672 for (int x=0; x<45; x++) // why 45, not 54?
673 scalefac_buffer[x] = 0;
674
675 m = 0;
676 for (int i=0; i<4;i++) {
677 for (int j = 0; j < nr_of_sfb_block[blocknumber][blocktypenumber][i];
678 j++)
679 {
680 scalefac_buffer[m] = (new_slen[i] == 0) ? 0 :
681 br.hgetbits(new_slen[i]);
682 m++;
683
684 } // for (unint32 j ...
685 } // for (uint32 i ...
686 }
687
688 /**
689 *
690 */
691 private void get_LSF_scale_factors(int ch, int gr)
692 {
693 int m = 0;
694 int sfb, window;
695 gr_info_s gr_info = (si.ch[ch].gr[gr]);
696
697 get_LSF_scale_data(ch, gr);
698
699 if ((gr_info.window_switching_flag != 0) && (gr_info.block_type == 2)) {
700 if (gr_info.mixed_block_flag != 0) { // MIXED
701 for (sfb = 0; sfb < 8; sfb++)
702 {
703 scalefac[ch].l[sfb] = scalefac_buffer[m];
704 m++;
705 }
706 for (sfb = 3; sfb < 12; sfb++) {
707 for (window=0; window<3; window++)
708 {
709 scalefac[ch].s[window][sfb] = scalefac_buffer[m];
710 m++;
711 }
712 }
713 for (window=0; window<3; window++)
714 scalefac[ch].s[window][12] = 0;
715
716 } else { // SHORT
717
718 for (sfb = 0; sfb < 12; sfb++) {
719 for (window=0; window<3; window++)
720 {
721 scalefac[ch].s[window][sfb] = scalefac_buffer[m];
722 m++;
723 }
724 }
725
726 for (window=0; window<3; window++)
727 scalefac[ch].s[window][12] = 0;
728 }
729 } else { // LONG types 0,1,3
730
731 for (sfb = 0; sfb < 21; sfb++) {
732 scalefac[ch].l[sfb] = scalefac_buffer[m];
733 m++;
734 }
735 scalefac[ch].l[21] = 0; // Jeff
736 scalefac[ch].l[22] = 0;
737 }
738 }
739
740 /**
741 *
742 */
743 int[] x = {0};
744 int[] y = {0};
745 int[] v = {0};
746 int[] w = {0};
747 private void huffman_decode(int ch, int gr)
748 {
749 x[0] = 0;
750 y[0] = 0;
751 v[0] = 0;
752 w[0] = 0;
753
754 int part2_3_end = part2_start + si.ch[ch].gr[gr].part2_3_length;
755 int num_bits;
756 int region1Start;
757 int region2Start;
758 int index;
759
760 int buf, buf1;
761
762 huffcodetab h;
763
764 // Find region boundary for short block case
765
766 if ( ((si.ch[ch].gr[gr].window_switching_flag) != 0) &&
767 (si.ch[ch].gr[gr].block_type == 2) ) {
768
769 // Region2.
770 //MS: Extrahandling for 8KHZ
771 region1Start = (sfreq == 8) ? 72 : 36; // sfb[9/3]*3=36 or in case 8KHZ = 72
772 region2Start = 576; // No Region2 for short block case
773
774 } else { // Find region boundary for long block case
775
776 buf = si.ch[ch].gr[gr].region0_count + 1;
777 buf1 = buf + si.ch[ch].gr[gr].region1_count + 1;
778
779 if(buf1 > sfBandIndex[sfreq].l.length - 1) buf1 = sfBandIndex[sfreq].l.length - 1;
780
781 region1Start = sfBandIndex[sfreq].l[buf];
782 region2Start = sfBandIndex[sfreq].l[buf1]; /* MI */
783 }
784
785 index = 0;
786 // Read bigvalues area
787 for (int i=0; i<(si.ch[ch].gr[gr].big_values<<1); i+=2) {
788 if (i<region1Start) h = huffcodetab.ht[si.ch[ch].gr[gr].table_select[0]];
789 else if (i<region2Start) h = huffcodetab.ht[si.ch[ch].gr[gr].table_select[1]];
790 else h = huffcodetab.ht[si.ch[ch].gr[gr].table_select[2]];
791
792 huffcodetab.huffman_decoder(h, x, y, v, w, br);
793 //if (index >= is_1d.length) System.out.println("i0="+i+"/"+(si.ch[ch].gr[gr].big_values<<1)+" Index="+index+" is_1d="+is_1d.length);
794
795 is_1d[index++] = x[0];
796 is_1d[index++] = y[0];
797
798 CheckSumHuff = CheckSumHuff + x[0] + y[0];
799 // System.out.println("x = "+x[0]+" y = "+y[0]);
800 }
801
802 // Read count1 area
803 h = huffcodetab.ht[si.ch[ch].gr[gr].count1table_select+32];
804 num_bits = br.hsstell();
805
806 while ((num_bits < part2_3_end) && (index < 576)) {
807
808 huffcodetab.huffman_decoder(h, x, y, v, w, br);
809
810 is_1d[index++] = v[0];
811 is_1d[index++] = w[0];
812 is_1d[index++] = x[0];
813 is_1d[index++] = y[0];
814 CheckSumHuff = CheckSumHuff + v[0] + w[0] + x[0] + y[0];
815 // System.out.println("v = "+v[0]+" w = "+w[0]);
816 // System.out.println("x = "+x[0]+" y = "+y[0]);
817 num_bits = br.hsstell();
818 }
819
820 if (num_bits > part2_3_end) {
821 br.rewindNbits(num_bits - part2_3_end);
822 index-=4;
823 }
824
825 num_bits = br.hsstell();
826
827 // Dismiss stuffing bits
828 if (num_bits < part2_3_end)
829 br.hgetbits(part2_3_end - num_bits);
830
831 // Zero out rest
832
833 if (index < 576)
834 nonzero[ch] = index;
835 else
836 nonzero[ch] = 576;
837
838 if (index < 0) index = 0;
839
840 // may not be necessary
841 for (; index<576; index++)
842 is_1d[index] = 0;
843 }
844
845 /**
846 *
847 */
848 private void i_stereo_k_values(int is_pos, int io_type, int i)
849 {
850 if (is_pos == 0) {
851 k[0][i] = 1.0f;
852 k[1][i] = 1.0f;
853 } else if ((is_pos & 1) != 0) {
854 k[0][i] = io[io_type][(is_pos + 1) >>> 1];
855 k[1][i] = 1.0f;
856 } else {
857 k[0][i] = 1.0f;
858 k[1][i] = io[io_type][is_pos >>> 1];
859 }
860 }
861
862 /**
863 *
864 */
865 private void dequantize_sample(float xr[][], int ch, int gr)
866 {
867 gr_info_s gr_info = (si.ch[ch].gr[gr]);
868 int cb=0;
869 int next_cb_boundary;
870 int cb_begin = 0;
871 int cb_width = 0;
872 int index=0, t_index, j;
873 float g_gain;
874 float[][] xr_1d = xr;
875
876 // choose correct scalefactor band per block type, initalize boundary
877
878 if ((gr_info.window_switching_flag !=0 ) && (gr_info.block_type == 2) ) {
879 if (gr_info.mixed_block_flag != 0)
880 next_cb_boundary=sfBandIndex[sfreq].l[1]; // LONG blocks: 0,1,3
881 else {
882 cb_width = sfBandIndex[sfreq].s[1];
883 next_cb_boundary = (cb_width << 2) - cb_width;
884 cb_begin = 0;
885 }
886 } else {
887 next_cb_boundary=sfBandIndex[sfreq].l[1]; // LONG blocks: 0,1,3
888 }
889
890 // Compute overall (global) scaling.
891
892 g_gain = (float) Math.pow(2.0 , (0.25 * (gr_info.global_gain - 210.0)));
893
894 for (j=0; j<nonzero[ch]; j++)
895 {
896 // Modif E.B 02/22/99
897 int reste = j % SSLIMIT;
898 int quotien = (int) ((j-reste)/SSLIMIT);
899 if (is_1d[j] == 0) xr_1d[quotien][reste] = 0.0f;
900 else
901 {
902 int abv = is_1d[j];
903 // Pow Array fix (11/17/04)
904 if (abv < t_43.length)
905 {
906 if (is_1d[j] > 0) xr_1d[quotien][reste] = g_gain * t_43[abv];
907 else
908 {
909 if (-abv < t_43.length) xr_1d[quotien][reste] = -g_gain * t_43[-abv];
910 else xr_1d[quotien][reste] = -g_gain * (float)Math.pow(-abv, d43);
911 }
912 }
913 else
914 {
915 if (is_1d[j] > 0) xr_1d[quotien][reste] = g_gain * (float)Math.pow(abv, d43);
916 else xr_1d[quotien][reste] = -g_gain * (float)Math.pow(-abv, d43);
917 }
918 }
919 }
920
921 // apply formula per block type
922 for (j=0; j<nonzero[ch]; j++)
923 {
924 // Modif E.B 02/22/99
925 int reste = j % SSLIMIT;
926 int quotien = (int) ((j-reste)/SSLIMIT);
927
928 if (index == next_cb_boundary) { /* Adjust critical band boundary */
929 if ((gr_info.window_switching_flag != 0) && (gr_info.block_type == 2)) {
930 if (gr_info.mixed_block_flag != 0) {
931
932 if (index == sfBandIndex[sfreq].l[8]) {
933 next_cb_boundary = sfBandIndex[sfreq].s[4];
934 next_cb_boundary = (next_cb_boundary << 2) -
935 next_cb_boundary;
936 cb = 3;
937 cb_width = sfBandIndex[sfreq].s[4] -
938 sfBandIndex[sfreq].s[3];
939
940 cb_begin = sfBandIndex[sfreq].s[3];
941 cb_begin = (cb_begin << 2) - cb_begin;
942
943 } else if (index < sfBandIndex[sfreq].l[8]) {
944
945 next_cb_boundary = sfBandIndex[sfreq].l[(++cb)+1];
946
947 } else {
948
949 next_cb_boundary = sfBandIndex[sfreq].s[(++cb)+1];
950 next_cb_boundary = (next_cb_boundary << 2) -
951 next_cb_boundary;
952
953 cb_begin = sfBandIndex[sfreq].s[cb];
954 cb_width = sfBandIndex[sfreq].s[cb+1] -
955 cb_begin;
956 cb_begin = (cb_begin << 2) - cb_begin;
957 }
958
959 } else {
960
961 next_cb_boundary = sfBandIndex[sfreq].s[(++cb)+1];
962 next_cb_boundary = (next_cb_boundary << 2) -
963 next_cb_boundary;
964
965 cb_begin = sfBandIndex[sfreq].s[cb];
966 cb_width = sfBandIndex[sfreq].s[cb+1] -
967 cb_begin;
968 cb_begin = (cb_begin << 2) - cb_begin;
969 }
970
971 } else { // long blocks
972
973 next_cb_boundary = sfBandIndex[sfreq].l[(++cb)+1];
974
975 }
976 }
977
978 // Do long/short dependent scaling operations
979
980 if ((gr_info.window_switching_flag !=0)&&
981 (((gr_info.block_type == 2) && (gr_info.mixed_block_flag == 0)) ||
982 ((gr_info.block_type == 2) && (gr_info.mixed_block_flag!=0) && (j >= 36)) ))
983 {
984
985 t_index = (index - cb_begin) / cb_width;
986 /* xr[sb][ss] *= pow(2.0, ((-2.0 * gr_info.subblock_gain[t_index])
987 -(0.5 * (1.0 + gr_info.scalefac_scale)
988 * scalefac[ch].s[t_index][cb]))); */
989 int idx = scalefac[ch].s[t_index][cb]
990 << gr_info.scalefac_scale;
991 idx += (gr_info.subblock_gain[t_index] << 2);
992
993 xr_1d[quotien][reste] *= two_to_negative_half_pow[idx];
994
995 } else { // LONG block types 0,1,3 & 1st 2 subbands of switched blocks
996 /* xr[sb][ss] *= pow(2.0, -0.5 * (1.0+gr_info.scalefac_scale)
997 * (scalefac[ch].l[cb]
998 + gr_info.preflag * pretab[cb])); */
999 int idx = scalefac[ch].l[cb];
1000
1001 if (gr_info.preflag != 0)
1002 idx += pretab[cb];
1003
1004 idx = idx << gr_info.scalefac_scale;
1005 xr_1d[quotien][reste] *= two_to_negative_half_pow[idx];
1006 }
1007 index++;
1008 }
1009
1010 for (j=nonzero[ch]; j<576; j++)
1011 {
1012 // Modif E.B 02/22/99
1013 int reste = j % SSLIMIT;
1014 int quotien = (int) ((j-reste)/SSLIMIT);
1015 if(reste < 0) reste = 0;
1016 if(quotien < 0) quotien = 0;
1017 xr_1d[quotien][reste] = 0.0f;
1018 }
1019
1020 return;
1021 }
1022
1023 /**
1024 *
1025 */
1026 private void reorder(float xr[][], int ch, int gr)
1027 {
1028 gr_info_s gr_info = (si.ch[ch].gr[gr]);
1029 int freq, freq3;
1030 int index;
1031 int sfb, sfb_start, sfb_lines;
1032 int src_line, des_line;
1033 float[][] xr_1d = xr;
1034
1035 if ((gr_info.window_switching_flag !=0) && (gr_info.block_type == 2)) {
1036
1037 for(index=0; index<576; index++)
1038 out_1d[index] = 0.0f;
1039
1040 if (gr_info.mixed_block_flag !=0 ) {
1041 // NO REORDER FOR LOW 2 SUBBANDS
1042 for (index = 0; index < 36; index++)
1043 {
1044 // Modif E.B 02/22/99
1045 int reste = index % SSLIMIT;
1046 int quotien = (int) ((index-reste)/SSLIMIT);
1047 out_1d[index] = xr_1d[quotien][reste];
1048 }
1049 // REORDERING FOR REST SWITCHED SHORT
1050 /*for( sfb=3,sfb_start=sfBandIndex[sfreq].s[3],
1051 sfb_lines=sfBandIndex[sfreq].s[4] - sfb_start;
1052 sfb < 13; sfb++,sfb_start = sfBandIndex[sfreq].s[sfb],
1053 sfb_lines = sfBandIndex[sfreq].s[sfb+1] - sfb_start )
1054 {*/
1055 for( sfb=3; sfb < 13; sfb++)
1056 {
1057 //System.out.println("sfreq="+sfreq+" sfb="+sfb+" sfBandIndex="+sfBandIndex.length+" sfBandIndex[sfreq].s="+sfBandIndex[sfreq].s.length);
1058 sfb_start = sfBandIndex[sfreq].s[sfb];
1059 sfb_lines = sfBandIndex[sfreq].s[sfb+1] - sfb_start;
1060
1061 int sfb_start3 = (sfb_start << 2) - sfb_start;
1062
1063 for(freq=0, freq3=0; freq<sfb_lines;
1064 freq++, freq3+=3) {
1065
1066 src_line = sfb_start3 + freq;
1067 des_line = sfb_start3 + freq3;
1068 // Modif E.B 02/22/99
1069 int reste = src_line % SSLIMIT;
1070 int quotien = (int) ((src_line-reste)/SSLIMIT);
1071
1072 out_1d[des_line] = xr_1d[quotien][reste];
1073 src_line += sfb_lines;
1074 des_line++;
1075
1076 reste = src_line % SSLIMIT;
1077 quotien = (int) ((src_line-reste)/SSLIMIT);
1078
1079 out_1d[des_line] = xr_1d[quotien][reste];
1080 src_line += sfb_lines;
1081 des_line++;
1082
1083 reste = src_line % SSLIMIT;
1084 quotien = (int) ((src_line-reste)/SSLIMIT);
1085
1086 out_1d[des_line] = xr_1d[quotien][reste];
1087 }
1088 }
1089
1090 } else { // pure short
1091 for(index=0;index<576;index++)
1092 {
1093 int j = reorder_table[sfreq][index];
1094 int reste = j % SSLIMIT;
1095 int quotien = (int) ((j-reste)/SSLIMIT);
1096 out_1d[index] = xr_1d[quotien][reste];
1097 }
1098 }
1099 }
1100 else { // long blocks
1101 for(index=0; index<576; index++)
1102 {
1103 // Modif E.B 02/22/99
1104 int reste = index % SSLIMIT;
1105 int quotien = (int) ((index-reste)/SSLIMIT);
1106 out_1d[index] = xr_1d[quotien][reste];
1107 }
1108 }
1109 }
1110
1111 /**
1112 *
1113 */
1114
1115 int[] is_pos = new int[576];
1116 float[] is_ratio = new float[576];
1117
1118 private void stereo(int gr)
1119 {
1120 int sb, ss;
1121
1122 if (channels == 1) { // mono , bypass xr[0][][] to lr[0][][]
1123
1124 for(sb=0;sb<SBLIMIT;sb++)
1125 for(ss=0;ss<SSLIMIT;ss+=3) {
1126 lr[0][sb][ss] = ro[0][sb][ss];
1127 lr[0][sb][ss+1] = ro[0][sb][ss+1];
1128 lr[0][sb][ss+2] = ro[0][sb][ss+2];
1129 }
1130
1131 } else {
1132
1133 gr_info_s gr_info = (si.ch[0].gr[gr]);
1134 int mode_ext = header.mode_extension();
1135 int sfb;
1136 int i;
1137 int lines, temp, temp2;
1138
1139 boolean ms_stereo = ((header.mode() == Header.JOINT_STEREO) && ((mode_ext & 0x2)!=0));
1140 boolean i_stereo = ((header.mode() == Header.JOINT_STEREO) && ((mode_ext & 0x1)!=0));
1141 boolean lsf = ((header.version() == Header.MPEG2_LSF || header.version() == Header.MPEG25_LSF )); // SZD
1142
1143 int io_type = (gr_info.scalefac_compress & 1);
1144
1145 // initialization
1146
1147 for (i=0; i<576; i++)
1148 {
1149 is_pos[i] = 7;
1150
1151 is_ratio[i] = 0.0f;
1152 }
1153
1154 if (i_stereo) {
1155 if ((gr_info.window_switching_flag !=0 )&& (gr_info.block_type == 2)) {
1156 if (gr_info.mixed_block_flag != 0) {
1157
1158 int max_sfb = 0;
1159
1160 for (int j=0; j<3; j++) {
1161 int sfbcnt;
1162 sfbcnt = 2;
1163 for( sfb=12; sfb >=3; sfb-- ) {
1164 i = sfBandIndex[sfreq].s[sfb];
1165 lines = sfBandIndex[sfreq].s[sfb+1] - i;
1166 i = (i << 2) - i + (j+1) * lines - 1;
1167
1168 while (lines > 0) {
1169 if (ro[1][i/18][i%18] != 0.0f) {
1170 // MDM: in java, array access is very slow.
1171 // Is quicker to compute div and mod values.
1172 //if (ro[1][ss_div[i]][ss_mod[i]] != 0.0f) {
1173 sfbcnt = sfb;
1174 sfb = -10;
1175 lines = -10;
1176 }
1177
1178 lines--;
1179 i--;
1180
1181 } // while (lines > 0)
1182
1183 } // for (sfb=12 ...
1184 sfb = sfbcnt + 1;
1185
1186 if (sfb > max_sfb)
1187 max_sfb = sfb;
1188
1189 while(sfb < 12) {
1190 temp = sfBandIndex[sfreq].s[sfb];
1191 sb = sfBandIndex[sfreq].s[sfb+1] - temp;
1192 i = (temp << 2) - temp + j * sb;
1193
1194 for ( ; sb > 0; sb--) {
1195 is_pos[i] = scalefac[1].s[j][sfb];
1196 if (is_pos[i] != 7)
1197 if (lsf)
1198 i_stereo_k_values(is_pos[i], io_type, i);
1199 else
1200 is_ratio[i] = TAN12[is_pos[i]];
1201
1202 i++;
1203 } // for (; sb>0...
1204 sfb++;
1205 } // while (sfb < 12)
1206 sfb = sfBandIndex[sfreq].s[10];
1207 sb = sfBandIndex[sfreq].s[11] - sfb;
1208 sfb = (sfb << 2) - sfb + j * sb;
1209 temp = sfBandIndex[sfreq].s[11];
1210 sb = sfBandIndex[sfreq].s[12] - temp;
1211 i = (temp << 2) - temp + j * sb;
1212
1213 for (; sb > 0; sb--) {
1214 is_pos[i] = is_pos[sfb];
1215
1216 if (lsf) {
1217 k[0][i] = k[0][sfb];
1218 k[1][i] = k[1][sfb];
1219 } else {
1220 is_ratio[i] = is_ratio[sfb];
1221 }
1222 i++;
1223 } // for (; sb > 0 ...
1224 }
1225 if (max_sfb <= 3) {
1226 i = 2;
1227 ss = 17;
1228 sb = -1;
1229 while (i >= 0) {
1230 if (ro[1][i][ss] != 0.0f) {
1231 sb = (i<<4) + (i<<1) + ss;
1232 i = -1;
1233 } else {
1234 ss--;
1235 if (ss < 0) {
1236 i--;
1237 ss = 17;
1238 }
1239 } // if (ro ...
1240 } // while (i>=0)
1241 i = 0;
1242 while (sfBandIndex[sfreq].l[i] <= sb)
1243 i++;
1244 sfb = i;
1245 i = sfBandIndex[sfreq].l[i];
1246 for (; sfb<8; sfb++) {
1247 sb = sfBandIndex[sfreq].l[sfb+1]-sfBandIndex[sfreq].l[sfb];
1248 for (; sb>0; sb--) {
1249 is_pos[i] = scalefac[1].l[sfb];
1250 if (is_pos[i] != 7)
1251 if (lsf)
1252 i_stereo_k_values(is_pos[i], io_type, i);
1253 else
1254 is_ratio[i] = TAN12[is_pos[i]];
1255 i++;
1256 } // for (; sb>0 ...
1257 } // for (; sfb<8 ...
1258 } // for (j=0 ...
1259 } else { // if (gr_info.mixed_block_flag)
1260 for (int j=0; j<3; j++) {
1261 int sfbcnt;
1262 sfbcnt = -1;
1263 for( sfb=12; sfb >=0; sfb-- )
1264 {
1265 temp = sfBandIndex[sfreq].s[sfb];
1266 lines = sfBandIndex[sfreq].s[sfb+1] - temp;
1267 i = (temp << 2) - temp + (j+1) * lines - 1;
1268
1269 while (lines > 0) {
1270 if (ro[1][i/18][i%18] != 0.0f) {
1271 // MDM: in java, array access is very slow.
1272 // Is quicker to compute div and mod values.
1273 //if (ro[1][ss_div[i]][ss_mod[i]] != 0.0f) {
1274 sfbcnt = sfb;
1275 sfb = -10;
1276 lines = -10;
1277 }
1278 lines--;
1279 i--;
1280 } // while (lines > 0) */
1281
1282 } // for (sfb=12 ...
1283 sfb = sfbcnt + 1;
1284 while(sfb<12) {
1285 temp = sfBandIndex[sfreq].s[sfb];
1286 sb = sfBandIndex[sfreq].s[sfb+1] - temp;
1287 i = (temp << 2) - temp + j * sb;
1288 for ( ; sb > 0; sb--) {
1289 is_pos[i] = scalefac[1].s[j][sfb];
1290 if (is_pos[i] != 7)
1291 if (lsf)
1292 i_stereo_k_values(is_pos[i], io_type, i);
1293 else
1294 is_ratio[i] = TAN12[is_pos[i]];
1295 i++;
1296 } // for (; sb>0 ...
1297 sfb++;
1298 } // while (sfb<12)
1299
1300 temp = sfBandIndex[sfreq].s[10];
1301 temp2= sfBandIndex[sfreq].s[11];
1302 sb = temp2 - temp;
1303 sfb = (temp << 2) - temp + j * sb;
1304 sb = sfBandIndex[sfreq].s[12] - temp2;
1305 i = (temp2 << 2) - temp2 + j * sb;
1306
1307 for (; sb>0; sb--) {
1308 is_pos[i] = is_pos[sfb];
1309
1310 if (lsf) {
1311 k[0][i] = k[0][sfb];
1312 k[1][i] = k[1][sfb];
1313 } else {
1314 is_ratio[i] = is_ratio[sfb];
1315 }
1316 i++;
1317 } // for (; sb>0 ...
1318 } // for (sfb=12
1319 } // for (j=0 ...
1320 } else { // if (gr_info.window_switching_flag ...
1321 i = 31;
1322 ss = 17;
1323 sb = 0;
1324 while (i >= 0) {
1325 if (ro[1][i][ss] != 0.0f) {
1326 sb = (i<<4) + (i<<1) + ss;
1327 i = -1;
1328 } else {
1329 ss--;
1330 if (ss < 0) {
1331 i--;
1332 ss = 17;
1333 }
1334 }
1335 }
1336 i = 0;
1337 while (sfBandIndex[sfreq].l[i] <= sb)
1338 i++;
1339
1340 sfb = i;
1341 i = sfBandIndex[sfreq].l[i];
1342 for (; sfb<21; sfb++) {
1343 sb = sfBandIndex[sfreq].l[sfb+1] - sfBandIndex[sfreq].l[sfb];
1344 for (; sb > 0; sb--) {
1345 is_pos[i] = scalefac[1].l[sfb];
1346 if (is_pos[i] != 7)
1347 if (lsf)
1348 i_stereo_k_values(is_pos[i], io_type, i);
1349 else
1350 is_ratio[i] = TAN12[is_pos[i]];
1351 i++;
1352 }
1353 }
1354 sfb = sfBandIndex[sfreq].l[20];
1355 for (sb = 576 - sfBandIndex[sfreq].l[21]; (sb > 0) && (i<576); sb--)
1356 {
1357 is_pos[i] = is_pos[sfb]; // error here : i >=576
1358
1359 if (lsf) {
1360 k[0][i] = k[0][sfb];
1361 k[1][i] = k[1][sfb];
1362 } else {
1363 is_ratio[i] = is_ratio[sfb];
1364 }
1365 i++;
1366 } // if (gr_info.mixed_block_flag)
1367 } // if (gr_info.window_switching_flag ...
1368 } // if (i_stereo)
1369
1370 i = 0;
1371 for(sb=0;sb<SBLIMIT;sb++)
1372 for(ss=0;ss<SSLIMIT;ss++) {
1373 if (is_pos[i] == 7) {
1374 if (ms_stereo) {
1375 lr[0][sb][ss] = (ro[0][sb][ss]+ro[1][sb][ss]) * 0.707106781f;
1376 lr[1][sb][ss] = (ro[0][sb][ss]-ro[1][sb][ss]) * 0.707106781f;
1377 } else {
1378 lr[0][sb][ss] = ro[0][sb][ss];
1379 lr[1][sb][ss] = ro[1][sb][ss];
1380 }
1381 }
1382 else if (i_stereo) {
1383
1384 if (lsf) {
1385 lr[0][sb][ss] = ro[0][sb][ss] * k[0][i];
1386 lr[1][sb][ss] = ro[0][sb][ss] * k[1][i];
1387 } else {
1388 lr[1][sb][ss] = ro[0][sb][ss] / (float) (1 + is_ratio[i]);
1389 lr[0][sb][ss] = lr[1][sb][ss] * is_ratio[i];
1390 }
1391 }
1392 /* else {
1393 System.out.println("Error in stereo processing\n");
1394 } */
1395 i++;
1396 }
1397
1398 } // channels == 2
1399
1400 }
1401
1402 /**
1403 *
1404 */
1405 private void antialias(int ch, int gr)
1406 {
1407 int sb18, ss, sb18lim;
1408 gr_info_s gr_info = (si.ch[ch].gr[gr]);
1409 // 31 alias-reduction operations between each pair of sub-bands
1410 // with 8 butterflies between each pair
1411
1412 if ((gr_info.window_switching_flag !=0) && (gr_info.block_type == 2) &&
1413 !(gr_info.mixed_block_flag != 0) )
1414 return;
1415
1416 if ((gr_info.window_switching_flag !=0) && (gr_info.mixed_block_flag != 0)&&
1417 (gr_info.block_type == 2)) {
1418 sb18lim = 18;
1419 } else {
1420 sb18lim = 558;
1421 }
1422
1423 for (sb18=0; sb18 < sb18lim; sb18+=18) {
1424 for (ss=0;ss<8;ss++) {
1425 int src_idx1 = sb18 + 17 - ss;
1426 int src_idx2 = sb18 + 18 + ss;
1427 float bu = out_1d[src_idx1];
1428 float bd = out_1d[src_idx2];
1429 out_1d[src_idx1] = (bu * cs[ss]) - (bd * ca[ss]);
1430 out_1d[src_idx2] = (bd * cs[ss]) + (bu * ca[ss]);
1431 }
1432 }
1433 }
1434
1435 /**
1436 *
1437 */
1438
1439 // MDM: tsOutCopy and rawout do not need initializing, so the arrays
1440 // can be reused.
1441 float[] tsOutCopy = new float[18];
1442 float[] rawout = new float[36];
1443
1444 private void hybrid(int ch, int gr)
1445 {
1446 int bt;
1447 int sb18;
1448 gr_info_s gr_info = (si.ch[ch].gr[gr]);
1449 float[] tsOut;
1450
1451 float[][] prvblk;
1452
1453 for(sb18=0;sb18<576;sb18+=18)
1454 {
1455 bt = ((gr_info.window_switching_flag !=0 ) && (gr_info.mixed_block_flag !=0) &&
1456 (sb18 < 36)) ? 0 : gr_info.block_type;
1457
1458 tsOut = out_1d;
1459 // Modif E.B 02/22/99
1460 for (int cc = 0;cc<18;cc++)
1461 tsOutCopy[cc] = tsOut[cc+sb18];
1462
1463 inv_mdct(tsOutCopy, rawout, bt);
1464
1465
1466 for (int cc = 0;cc<18;cc++)
1467 tsOut[cc+sb18] = tsOutCopy[cc];
1468 // Fin Modif
1469
1470 // overlap addition
1471 prvblk = prevblck;
1472
1473 tsOut[0 + sb18] = rawout[0] + prvblk[ch][sb18 + 0];
1474 prvblk[ch][sb18 + 0] = rawout[18];
1475 tsOut[1 + sb18] = rawout[1] + prvblk[ch][sb18 + 1];
1476 prvblk[ch][sb18 + 1] = rawout[19];
1477 tsOut[2 + sb18] = rawout[2] + prvblk[ch][sb18 + 2];
1478 prvblk[ch][sb18 + 2] = rawout[20];
1479 tsOut[3 + sb18] = rawout[3] + prvblk[ch][sb18 + 3];
1480 prvblk[ch][sb18 + 3] = rawout[21];
1481 tsOut[4 + sb18] = rawout[4] + prvblk[ch][sb18 + 4];
1482 prvblk[ch][sb18 + 4] = rawout[22];
1483 tsOut[5 + sb18] = rawout[5] + prvblk[ch][sb18 + 5];
1484 prvblk[ch][sb18 + 5] = rawout[23];
1485 tsOut[6 + sb18] = rawout[6] + prvblk[ch][sb18 + 6];
1486 prvblk[ch][sb18 + 6] = rawout[24];
1487 tsOut[7 + sb18] = rawout[7] + prvblk[ch][sb18 + 7];
1488 prvblk[ch][sb18 + 7] = rawout[25];
1489 tsOut[8 + sb18] = rawout[8] + prvblk[ch][sb18 + 8];
1490 prvblk[ch][sb18 + 8] = rawout[26];
1491 tsOut[9 + sb18] = rawout[9] + prvblk[ch][sb18 + 9];
1492 prvblk[ch][sb18 + 9] = rawout[27];
1493 tsOut[10 + sb18] = rawout[10] + prvblk[ch][sb18 + 10];
1494 prvblk[ch][sb18 + 10] = rawout[28];
1495 tsOut[11 + sb18] = rawout[11] + prvblk[ch][sb18 + 11];
1496 prvblk[ch][sb18 + 11] = rawout[29];
1497 tsOut[12 + sb18] = rawout[12] + prvblk[ch][sb18 + 12];
1498 prvblk[ch][sb18 + 12] = rawout[30];
1499 tsOut[13 + sb18] = rawout[13] + prvblk[ch][sb18 + 13];
1500 prvblk[ch][sb18 + 13] = rawout[31];
1501 tsOut[14 + sb18] = rawout[14] + prvblk[ch][sb18 + 14];
1502 prvblk[ch][sb18 + 14] = rawout[32];
1503 tsOut[15 + sb18] = rawout[15] + prvblk[ch][sb18 + 15];
1504 prvblk[ch][sb18 + 15] = rawout[33];
1505 tsOut[16 + sb18] = rawout[16] + prvblk[ch][sb18 + 16];
1506 prvblk[ch][sb18 + 16] = rawout[34];
1507 tsOut[17 + sb18] = rawout[17] + prvblk[ch][sb18 + 17];
1508 prvblk[ch][sb18 + 17] = rawout[35];
1509 }
1510 }
1511
1512 /**
1513 *
1514 */
1515 private void do_downmix()
1516 {
1517 for (int sb=0; sb<SSLIMIT; sb++) {
1518 for (int ss=0; ss<SSLIMIT; ss+=3) {
1519 lr[0][sb][ss] = (lr[0][sb][ss] + lr[1][sb][ss]) * 0.5f;
1520 lr[0][sb][ss+1] = (lr[0][sb][ss+1] + lr[1][sb][ss+1]) * 0.5f;
1521 lr[0][sb][ss+2] = (lr[0][sb][ss+2] + lr[1][sb][ss+2]) * 0.5f;
1522 }
1523 }
1524 }
1525
1526 /**
1527 * Fast INV_MDCT.
1528 */
1529
1530 public void inv_mdct(float[] in, float[] out, int block_type)
1531 {
1532 float[] win_bt;
1533 int i;
1534
1535 float tmpf_0, tmpf_1, tmpf_2, tmpf_3, tmpf_4, tmpf_5, tmpf_6, tmpf_7, tmpf_8, tmpf_9;
1536 float tmpf_10, tmpf_11, tmpf_12, tmpf_13, tmpf_14, tmpf_15, tmpf_16, tmpf_17;
1537
1538 tmpf_0 = tmpf_1 = tmpf_2 = tmpf_3 = tmpf_4 = tmpf_5 = tmpf_6 = tmpf_7 = tmpf_8 = tmpf_9 =
1539 tmpf_10 = tmpf_11 = tmpf_12 = tmpf_13 = tmpf_14 = tmpf_15 = tmpf_16 = tmpf_17 = 0.0f;
1540
1541
1542
1543 if(block_type == 2)
1544 {
1545
1546 /*
1547 *
1548 * Under MicrosoftVM 2922, This causes a GPF, or
1549 * At best, an ArrayIndexOutOfBoundsExceptin.
1550 for(int p=0;p<36;p+=9)
1551 {
1552 out[p] = out[p+1] = out[p+2] = out[p+3] =
1553 out[p+4] = out[p+5] = out[p+6] = out[p+7] =
1554 out[p+8] = 0.0f;
1555 }
1556 */
1557 out[0] = 0.0f;
1558 out[1] = 0.0f;
1559 out[2] = 0.0f;
1560 out[3] = 0.0f;
1561 out[4] = 0.0f;
1562 out[5] = 0.0f;
1563 out[6] = 0.0f;
1564 out[7] = 0.0f;
1565 out[8] = 0.0f;
1566 out[9] = 0.0f;
1567 out[10] = 0.0f;
1568 out[11] = 0.0f;
1569 out[12] = 0.0f;
1570 out[13] = 0.0f;
1571 out[14] = 0.0f;
1572 out[15] = 0.0f;
1573 out[16] = 0.0f;
1574 out[17] = 0.0f;
1575 out[18] = 0.0f;
1576 out[19] = 0.0f;
1577 out[20] = 0.0f;
1578 out[21] = 0.0f;
1579 out[22] = 0.0f;
1580 out[23] = 0.0f;
1581 out[24] = 0.0f;
1582 out[25] = 0.0f;
1583 out[26] = 0.0f;
1584 out[27] = 0.0f;
1585 out[28] = 0.0f;
1586 out[29] = 0.0f;
1587 out[30] = 0.0f;
1588 out[31] = 0.0f;
1589 out[32] = 0.0f;
1590 out[33] = 0.0f;
1591 out[34] = 0.0f;
1592 out[35] = 0.0f;
1593
1594 int six_i = 0;
1595
1596 for(i=0;i<3;i++)
1597 {
1598 // 12 point IMDCT
1599 // Begin 12 point IDCT
1600 // Input aliasing for 12 pt IDCT
1601 in[15+i] += in[12+i]; in[12+i] += in[9+i]; in[9+i] += in[6+i];
1602 in[6+i] += in[3+i]; in[3+i] += in[0+i];
1603
1604 // Input aliasing on odd indices (for 6 point IDCT)
1605 in[15+i] += in[9+i]; in[9+i] += in[3+i];
1606
1607 // 3 point IDCT on even indices
1608 float pp1, pp2, sum;
1609 pp2 = in[12+i] * 0.500000000f;
1610 pp1 = in[ 6+i] * 0.866025403f;
1611 sum = in[0+i] + pp2;
1612 tmpf_1 = in[0+i] - in[12+i];
1613 tmpf_0 = sum + pp1;
1614 tmpf_2 = sum - pp1;
1615
1616 // End 3 point IDCT on even indices
1617 // 3 point IDCT on odd indices (for 6 point IDCT)
1618 pp2 = in[15+i] * 0.500000000f;
1619 pp1 = in[ 9+i] * 0.866025403f;
1620 sum = in[ 3+i] + pp2;
1621 tmpf_4 = in[3+i] - in[15+i];
1622 tmpf_5 = sum + pp1;
1623 tmpf_3 = sum - pp1;
1624 // End 3 point IDCT on odd indices
1625 // Twiddle factors on odd indices (for 6 point IDCT)
1626
1627 tmpf_3 *= 1.931851653f;
1628 tmpf_4 *= 0.707106781f;
1629 tmpf_5 *= 0.517638090f;
1630
1631 // Output butterflies on 2 3 point IDCT's (for 6 point IDCT)
1632 float save = tmpf_0;
1633 tmpf_0 += tmpf_5;
1634 tmpf_5 = save - tmpf_5;
1635 save = tmpf_1;
1636 tmpf_1 += tmpf_4;
1637 tmpf_4 = save - tmpf_4;
1638 save = tmpf_2;
1639 tmpf_2 += tmpf_3;
1640 tmpf_3 = save - tmpf_3;
1641
1642 // End 6 point IDCT
1643 // Twiddle factors on indices (for 12 point IDCT)
1644
1645 tmpf_0 *= 0.504314480f;
1646 tmpf_1 *= 0.541196100f;
1647 tmpf_2 *= 0.630236207f;
1648 tmpf_3 *= 0.821339815f;
1649 tmpf_4 *= 1.306562965f;
1650 tmpf_5 *= 3.830648788f;
1651
1652 // End 12 point IDCT
1653
1654 // Shift to 12 point modified IDCT, multiply by window type 2
1655 tmpf_8 = -tmpf_0 * 0.793353340f;
1656 tmpf_9 = -tmpf_0 * 0.608761429f;
1657 tmpf_7 = -tmpf_1 * 0.923879532f;
1658 tmpf_10 = -tmpf_1 * 0.382683432f;
1659 tmpf_6 = -tmpf_2 * 0.991444861f;
1660 tmpf_11 = -tmpf_2 * 0.130526192f;
1661
1662 tmpf_0 = tmpf_3;
1663 tmpf_1 = tmpf_4 * 0.382683432f;
1664 tmpf_2 = tmpf_5 * 0.608761429f;
1665
1666 tmpf_3 = -tmpf_5 * 0.793353340f;
1667 tmpf_4 = -tmpf_4 * 0.923879532f;
1668 tmpf_5 = -tmpf_0 * 0.991444861f;
1669
1670 tmpf_0 *= 0.130526192f;
1671
1672 out[six_i + 6] += tmpf_0;
1673 out[six_i + 7] += tmpf_1;
1674 out[six_i + 8] += tmpf_2;
1675 out[six_i + 9] += tmpf_3;
1676 out[six_i + 10] += tmpf_4;
1677 out[six_i + 11] += tmpf_5;
1678 out[six_i + 12] += tmpf_6;
1679 out[six_i + 13] += tmpf_7;
1680 out[six_i + 14] += tmpf_8;
1681 out[six_i + 15] += tmpf_9;
1682 out[six_i + 16] += tmpf_10;
1683 out[six_i + 17] += tmpf_11;
1684
1685 six_i += 6;
1686 }
1687 }
1688 else
1689 {
1690 // 36 point IDCT
1691 // input aliasing for 36 point IDCT
1692 in[17]+=in[16]; in[16]+=in[15]; in[15]+=in[14]; in[14]+=in[13];
1693 in[13]+=in[12]; in[12]+=in[11]; in[11]+=in[10]; in[10]+=in[9];
1694 in[9] +=in[8]; in[8] +=in[7]; in[7] +=in[6]; in[6] +=in[5];
1695 in[5] +=in[4]; in[4] +=in[3]; in[3] +=in[2]; in[2] +=in[1];
1696 in[1] +=in[0];
1697
1698 // 18 point IDCT for odd indices
1699 // input aliasing for 18 point IDCT
1700 in[17]+=in[15]; in[15]+=in[13]; in[13]+=in[11]; in[11]+=in[9];
1701 in[9] +=in[7]; in[7] +=in[5]; in[5] +=in[3]; in[3] +=in[1];
1702
1703 float tmp0,tmp1,tmp2,tmp3,tmp4,tmp0_,tmp1_,tmp2_,tmp3_;
1704 float tmp0o,tmp1o,tmp2o,tmp3o,tmp4o,tmp0_o,tmp1_o,tmp2_o,tmp3_o;
1705
1706 // Fast 9 Point Inverse Discrete Cosine Transform
1707 //
1708 // By Francois-Raymond Boyer
1709 // mailto:boyerf@iro.umontreal.ca
1710 // http://www.iro.umontreal.ca/~boyerf
1711 //
1712 // The code has been optimized for Intel processors
1713 // (takes a lot of time to convert float to and from iternal FPU representation)
1714 //
1715 // It is a simple "factorization" of the IDCT matrix.
1716
1717 // 9 point IDCT on even indices
1718
1719 // 5 points on odd indices (not realy an IDCT)
1720 float i00 = in[0]+in[0];
1721 float iip12 = i00 + in[12];
1722
1723 tmp0 = iip12 + in[4]*1.8793852415718f + in[8]*1.532088886238f + in[16]*0.34729635533386f;
1724 tmp1 = i00 + in[4] - in[8] - in[12] - in[12] - in[16];
1725 tmp2 = iip12 - in[4]*0.34729635533386f - in[8]*1.8793852415718f + in[16]*1.532088886238f;
1726 tmp3 = iip12 - in[4]*1.532088886238f + in[8]*0.34729635533386f - in[16]*1.8793852415718f;
1727 tmp4 = in[0] - in[4] + in[8] - in[12] + in[16];
1728
1729 // 4 points on even indices
1730 float i66_ = in[6]*1.732050808f; // Sqrt[3]
1731
1732 tmp0_ = in[2]*1.9696155060244f + i66_ + in[10]*1.2855752193731f + in[14]*0.68404028665134f;
1733 tmp1_ = (in[2] - in[10] - in[14])*1.732050808f;
1734 tmp2_ = in[2]*1.2855752193731f - i66_ - in[10]*0.68404028665134f + in[14]*1.9696155060244f;
1735 tmp3_ = in[2]*0.68404028665134f - i66_ + in[10]*1.9696155060244f - in[14]*1.2855752193731f;
1736
1737 // 9 point IDCT on odd indices
1738 // 5 points on odd indices (not realy an IDCT)
1739 float i0 = in[0+1]+in[0+1];
1740 float i0p12 = i0 + in[12+1];
1741
1742 tmp0o = i0p12 + in[4+1]*1.8793852415718f + in[8+1]*1.532088886238f + in[16+1]*0.34729635533386f;
1743 tmp1o = i0 + in[4+1] - in[8+1] - in[12+1] - in[12+1] - in[16+1];
1744 tmp2o = i0p12 - in[4+1]*0.34729635533386f - in[8+1]*1.8793852415718f + in[16+1]*1.532088886238f;
1745 tmp3o = i0p12 - in[4+1]*1.532088886238f + in[8+1]*0.34729635533386f - in[16+1]*1.8793852415718f;
1746 tmp4o = (in[0+1] - in[4+1] + in[8+1] - in[12+1] + in[16+1])*0.707106781f; // Twiddled
1747
1748 // 4 points on even indices
1749 float i6_ = in[6+1]*1.732050808f; // Sqrt[3]
1750
1751 tmp0_o = in[2+1]*1.9696155060244f + i6_ + in[10+1]*1.2855752193731f + in[14+1]*0.68404028665134f;
1752 tmp1_o = (in[2+1] - in[10+1] - in[14+1])*1.732050808f;
1753 tmp2_o = in[2+1]*1.2855752193731f - i6_ - in[10+1]*0.68404028665134f + in[14+1]*1.9696155060244f;
1754 tmp3_o = in[2+1]*0.68404028665134f - i6_ + in[10+1]*1.9696155060244f - in[14+1]*1.2855752193731f;
1755
1756 // Twiddle factors on odd indices
1757 // and
1758 // Butterflies on 9 point IDCT's
1759 // and
1760 // twiddle factors for 36 point IDCT
1761
1762 float e, o;
1763 e = tmp0 + tmp0_; o = (tmp0o + tmp0_o)*0.501909918f; tmpf_0 = e + o; tmpf_17 = e - o;
1764 e = tmp1 + tmp1_; o = (tmp1o + tmp1_o)*0.517638090f; tmpf_1 = e + o; tmpf_16 = e - o;
1765 e = tmp2 + tmp2_; o = (tmp2o + tmp2_o)*0.551688959f; tmpf_2 = e + o; tmpf_15 = e - o;
1766 e = tmp3 + tmp3_; o = (tmp3o + tmp3_o)*0.610387294f; tmpf_3 = e + o; tmpf_14 = e - o;
1767 tmpf_4 = tmp4 + tmp4o; tmpf_13 = tmp4 - tmp4o;
1768 e = tmp3 - tmp3_; o = (tmp3o - tmp3_o)*0.871723397f; tmpf_5 = e + o; tmpf_12 = e - o;
1769 e = tmp2 - tmp2_; o = (tmp2o - tmp2_o)*1.183100792f; tmpf_6 = e + o; tmpf_11 = e - o;
1770 e = tmp1 - tmp1_; o = (tmp1o - tmp1_o)*1.931851653f; tmpf_7 = e + o; tmpf_10 = e - o;
1771 e = tmp0 - tmp0_; o = (tmp0o - tmp0_o)*5.736856623f; tmpf_8 = e + o; tmpf_9 = e - o;
1772
1773 // end 36 point IDCT */
1774 // shift to modified IDCT
1775 win_bt = win[block_type];
1776
1777 out[0] =-tmpf_9 * win_bt[0];
1778 out[1] =-tmpf_10 * win_bt[1];
1779 out[2] =-tmpf_11 * win_bt[2];
1780 out[3] =-tmpf_12 * win_bt[3];
1781 out[4] =-tmpf_13 * win_bt[4];
1782 out[5] =-tmpf_14 * win_bt[5];
1783 out[6] =-tmpf_15 * win_bt[6];
1784 out[7] =-tmpf_16 * win_bt[7];
1785 out[8] =-tmpf_17 * win_bt[8];
1786 out[9] = tmpf_17 * win_bt[9];
1787 out[10]= tmpf_16 * win_bt[10];
1788 out[11]= tmpf_15 * win_bt[11];
1789 out[12]= tmpf_14 * win_bt[12];
1790 out[13]= tmpf_13 * win_bt[13];
1791 out[14]= tmpf_12 * win_bt[14];
1792 out[15]= tmpf_11 * win_bt[15];
1793 out[16]= tmpf_10 * win_bt[16];
1794 out[17]= tmpf_9 * win_bt[17];
1795 out[18]= tmpf_8 * win_bt[18];
1796 out[19]= tmpf_7 * win_bt[19];
1797 out[20]= tmpf_6 * win_bt[20];
1798 out[21]= tmpf_5 * win_bt[21];
1799 out[22]= tmpf_4 * win_bt[22];
1800 out[23]= tmpf_3 * win_bt[23];
1801 out[24]= tmpf_2 * win_bt[24];
1802 out[25]= tmpf_1 * win_bt[25];
1803 out[26]= tmpf_0 * win_bt[26];
1804 out[27]= tmpf_0 * win_bt[27];
1805 out[28]= tmpf_1 * win_bt[28];
1806 out[29]= tmpf_2 * win_bt[29];
1807 out[30]= tmpf_3 * win_bt[30];
1808 out[31]= tmpf_4 * win_bt[31];
1809 out[32]= tmpf_5 * win_bt[32];
1810 out[33]= tmpf_6 * win_bt[33];
1811 out[34]= tmpf_7 * win_bt[34];
1812 out[35]= tmpf_8 * win_bt[35];
1813 }
1814 }
1815
1816 private int counter = 0;
1817 private static final int SSLIMIT=18;
1818 private static final int SBLIMIT=32;
1819 // Size of the table of whole numbers raised to 4/3 power.
1820 // This may be adjusted for performance without any problems.
1821 //public static final int POW_TABLE_LIMIT=512;
1822
1823 /************************************************************/
1824 /* L3TABLE */
1825 /************************************************************/
1826
1827 static class SBI
1828 {
1829 public int[] l;
1830 public int[] s;
1831
1832 public SBI()
1833 {
1834 l = new int[23];
1835 s = new int[14];
1836 }
1837 public SBI(int[] thel, int[] thes)
1838 {
1839 l = thel;
1840 s = thes;
1841 }
1842 }
1843
1844 static class gr_info_s
1845 {
1846 public int part2_3_length = 0;
1847 public int big_values = 0;
1848 public int global_gain = 0;
1849 public int scalefac_compress = 0;
1850 public int window_switching_flag = 0;
1851 public int block_type = 0;
1852 public int mixed_block_flag = 0;
1853 public int[] table_select;
1854 public int[] subblock_gain;
1855 public int region0_count = 0;
1856 public int region1_count = 0;
1857 public int preflag = 0;
1858 public int scalefac_scale = 0;
1859 public int count1table_select = 0;
1860
1861 /**
1862 * Dummy Constructor
1863 */
1864 public gr_info_s()
1865 {
1866 table_select = new int[3];
1867 subblock_gain = new int[3];
1868 }
1869 }
1870
1871 static class temporaire
1872 {
1873 public int[] scfsi;
1874 public gr_info_s[] gr;
1875
1876 /**
1877 * Dummy Constructor
1878 */
1879 public temporaire()
1880 {
1881 scfsi = new int[4];
1882 gr = new gr_info_s[2];
1883 gr[0] = new gr_info_s();
1884 gr[1] = new gr_info_s();
1885 }
1886 }
1887
1888 static class III_side_info_t
1889 {
1890
1891 public int main_data_begin = 0;
1892 public int private_bits = 0;
1893 public temporaire[] ch;
1894 /**
1895 * Dummy Constructor
1896 */
1897 public III_side_info_t()
1898 {
1899 ch = new temporaire[2];
1900 ch[0] = new temporaire();
1901 ch[1] = new temporaire();
1902 }
1903 }
1904
1905 static class temporaire2
1906 {
1907 public int[] l; /* [cb] */
1908 public int[][] s; /* [window][cb] */
1909
1910 /**
1911 * Dummy Constructor
1912 */
1913 public temporaire2()
1914 {
1915 l = new int[23];
1916 s = new int[3][13];
1917 }
1918 }
1919 //class III_scalefac_t
1920 //{
1921 // public temporaire2[] tab;
1922 // /**
1923 // * Dummy Constructor
1924 // */
1925 // public III_scalefac_t()
1926 // {
1927 // tab = new temporaire2[2];
1928 // }
1929 //}
1930
1931 private static final int slen[][] =
1932 {
1933 {0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4},
1934 {0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3}
1935 };
1936
1937 public static final int pretab[] =
1938 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0};
1939
1940 private SBI[] sfBandIndex; // Init in the constructor.
1941
1942 public static final float two_to_negative_half_pow[] =
1943 { 1.0000000000E+00f, 7.0710678119E-01f, 5.0000000000E-01f, 3.5355339059E-01f,
1944 2.5000000000E-01f, 1.7677669530E-01f, 1.2500000000E-01f, 8.8388347648E-02f,
1945 6.2500000000E-02f, 4.4194173824E-02f, 3.1250000000E-02f, 2.2097086912E-02f,
1946 1.5625000000E-02f, 1.1048543456E-02f, 7.8125000000E-03f, 5.5242717280E-03f,
1947 3.9062500000E-03f, 2.7621358640E-03f, 1.9531250000E-03f, 1.3810679320E-03f,
1948 9.7656250000E-04f, 6.9053396600E-04f, 4.8828125000E-04f, 3.4526698300E-04f,
1949 2.4414062500E-04f, 1.7263349150E-04f, 1.2207031250E-04f, 8.6316745750E-05f,
1950 6.1035156250E-05f, 4.3158372875E-05f, 3.0517578125E-05f, 2.1579186438E-05f,
1951 1.5258789062E-05f, 1.0789593219E-05f, 7.6293945312E-06f, 5.3947966094E-06f,
1952 3.8146972656E-06f, 2.6973983047E-06f, 1.9073486328E-06f, 1.3486991523E-06f,
1953 9.5367431641E-07f, 6.7434957617E-07f, 4.7683715820E-07f, 3.3717478809E-07f,
1954 2.3841857910E-07f, 1.6858739404E-07f, 1.1920928955E-07f, 8.4293697022E-08f,
1955 5.9604644775E-08f, 4.2146848511E-08f, 2.9802322388E-08f, 2.1073424255E-08f,
1956 1.4901161194E-08f, 1.0536712128E-08f, 7.4505805969E-09f, 5.2683560639E-09f,
1957 3.7252902985E-09f, 2.6341780319E-09f, 1.8626451492E-09f, 1.3170890160E-09f,
1958 9.3132257462E-10f, 6.5854450798E-10f, 4.6566128731E-10f, 3.2927225399E-10f
1959 };
1960
1961
1962 public static final float t_43[] = create_t_43();
1963
1964 static private float[] create_t_43()
1965 {
1966 float[] t43 = new float[8192];
1967 final double d43 = (4.0/3.0);
1968
1969 for (int i=0; i<8192; i++)
1970 {
1971 t43[i] = (float)Math.pow(i, d43);
1972 }
1973 return t43;
1974 }
1975
1976 public static final float io[][] =
1977 {
1978 { 1.0000000000E+00f, 8.4089641526E-01f, 7.0710678119E-01f, 5.9460355751E-01f,
1979 5.0000000001E-01f, 4.2044820763E-01f, 3.5355339060E-01f, 2.9730177876E-01f,
1980 2.5000000001E-01f, 2.1022410382E-01f, 1.7677669530E-01f, 1.4865088938E-01f,
1981 1.2500000000E-01f, 1.0511205191E-01f, 8.8388347652E-02f, 7.4325444691E-02f,
1982 6.2500000003E-02f, 5.2556025956E-02f, 4.4194173826E-02f, 3.7162722346E-02f,
1983 3.1250000002E-02f, 2.6278012978E-02f, 2.2097086913E-02f, 1.8581361173E-02f,
1984 1.5625000001E-02f, 1.3139006489E-02f, 1.1048543457E-02f, 9.2906805866E-03f,
1985 7.8125000006E-03f, 6.5695032447E-03f, 5.5242717285E-03f, 4.6453402934E-03f },
1986 { 1.0000000000E+00f, 7.0710678119E-01f, 5.0000000000E-01f, 3.5355339060E-01f,
1987 2.5000000000E-01f, 1.7677669530E-01f, 1.2500000000E-01f, 8.8388347650E-02f,
1988 6.2500000001E-02f, 4.4194173825E-02f, 3.1250000001E-02f, 2.2097086913E-02f,
1989 1.5625000000E-02f, 1.1048543456E-02f, 7.8125000002E-03f, 5.5242717282E-03f,
1990 3.9062500001E-03f, 2.7621358641E-03f, 1.9531250001E-03f, 1.3810679321E-03f,
1991 9.7656250004E-04f, 6.9053396603E-04f, 4.8828125002E-04f, 3.4526698302E-04f,
1992 2.4414062501E-04f, 1.7263349151E-04f, 1.2207031251E-04f, 8.6316745755E-05f,
1993 6.1035156254E-05f, 4.3158372878E-05f, 3.0517578127E-05f, 2.1579186439E-05f }
1994 };
1995
1996
1997
1998 public static final float TAN12[] =
1999 {
2000 0.0f, 0.26794919f, 0.57735027f, 1.0f,
2001 1.73205081f, 3.73205081f, 9.9999999e10f, -3.73205081f,
2002 -1.73205081f, -1.0f, -0.57735027f, -0.26794919f,
2003 0.0f, 0.26794919f, 0.57735027f, 1.0f
2004 };
2005
2006 // REVIEW: in java, the array lookup may well be slower than
2007 // the actual calculation
2008 // 576 / 18
2009/*
2010 private static final int ss_div[] =
2011 {
2012 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2013 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2014 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2015 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2016 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
2017 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2018 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2019 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2020 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
2021 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
2022 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
2023 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
2024 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
2025 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2026 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
2027 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
2028 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2029 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2030 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
2031 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
2032 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
2033 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
2034 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
2035 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
2036 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
2037 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
2038 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
2039 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
2040 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
2041 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
2042 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
2043 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31
2044 };
2045
2046 // 576 % 18
2047 private static final int ss_mod[] =
2048 {
2049 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2050 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2051 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2052 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2053 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2054 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2055 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2056 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2057 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2058 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2059 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2060 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2061 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2062 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2063 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2064 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2065 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2066 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2067 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2068 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2069 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2070 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2071 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2072 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2073 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2074 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2075 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2076 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2077 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2078 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2079 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
2080 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
2081 };
2082*/
2083 private static /*final*/ int reorder_table[][]/* = loadReorderTable()*/; // SZD: will be generated on demand
2084
2085 /**
2086 * Loads the data for the reorder
2087 */
2088 /*private static int[][] loadReorderTable() // SZD: table will be generated
2089 {
2090 try
2091 {
2092 Class elemType = int[][].class.getComponentType();
2093 Object o = JavaLayerUtils.deserializeArrayResource("l3reorder.ser", elemType, 6);
2094 return (int[][])o;
2095 }
2096 catch (IOException ex)
2097 {
2098 throw new ExceptionInInitializerError(ex);
2099 }
2100 }*/
2101
2102 static int[] reorder(int scalefac_band[]) { // SZD: converted from LAME
2103 int j = 0;
2104 int ix[] = new int[576];
2105 for(int sfb = 0; sfb < 13; sfb++) {
2106 int start = scalefac_band[sfb];
2107 int end = scalefac_band[sfb + 1];
2108 for(int window = 0; window < 3; window++)
2109 for(int i = start; i < end; i++)
2110 ix[3 * i + window] = j++;
2111 }
2112 return ix;
2113 }
2114
2115 /*static final int reorder_table_data[][]; =
2116 {
2117 { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11, 12, 16, 20, 13,
2118 17, 21, 14, 18, 22, 15, 19, 23, 24, 28, 32, 25, 29, 33, 26, 30,
2119 34, 27, 31, 35, 36, 42, 48, 37, 43, 49, 38, 44, 50, 39, 45, 51,
2120 40, 46, 52, 41, 47, 53, 54, 60, 66, 55, 61, 67, 56, 62, 68, 57,
2121 63, 69, 58, 64, 70, 59, 65, 71, 72, 80, 88, 73, 81, 89, 74, 82,
2122 90, 75, 83, 91, 76, 84, 92, 77, 85, 93, 78, 86, 94, 79, 87, 95,
2123 96,106,116, 97,107,117, 98,108,118, 99,109,119,100,110,120,101,
2124 111,121,102,112,122,103,113,123,104,114,124,105,115,125,126,140,
2125 154,127,141,155,128,142,156,129,143,157,130,144,158,131,145,159,
2126 132,146,160,133,147,161,134,148,162,135,149,163,136,150,164,137,
2127 151,165,138,152,166,139,153,167,168,186,204,169,187,205,170,188,
2128 206,171,189,207,172,190,208,173,191,209,174,192,210,175,193,211,
2129 176,194,212,177,195,213,178,196,214,179,197,215,180,198,216,181,
2130 199,217,182,200,218,183,201,219,184,202,220,185,203,221,222,248,
2131 274,223,249,275,224,250,276,225,251,277,226,252,278,227,253,279,
2132 228,254,280,229,255,281,230,256,282,231,257,283,232,258,284,233,
2133 259,285,234,260,286,235,261,287,236,262,288,237,263,289,238,264,
2134 290,239,265,291,240,266,292,241,267,293,242,268,294,243,269,295,
2135 244,270,296,245,271,297,246,272,298,247,273,299,300,332,364,301,
2136 333,365,302,334,366,303,335,367,304,336,368,305,337,369,306,338,
2137 370,307,339,371,308,340,372,309,341,373,310,342,374,311,343,375,
2138 312,344,376,313,345,377,314,346,378,315,347,379,316,348,380,317,
2139 349,381,318,350,382,319,351,383,320,352,384,321,353,385,322,354,
2140 386,323,355,387,324,356,388,325,357,389,326,358,390,327,359,391,
2141 328,360,392,329,361,393,330,362,394,331,363,395,396,438,480,397,
2142 439,481,398,440,482,399,441,483,400,442,484,401,443,485,402,444,
2143 486,403,445,487,404,446,488,405,447,489,406,448,490,407,449,491,
2144 408,450,492,409,451,493,410,452,494,411,453,495,412,454,496,413,
2145 455,497,414,456,498,415,457,499,416,458,500,417,459,501,418,460,
2146 502,419,461,503,420,462,504,421,463,505,422,464,506,423,465,507,
2147 424,466,508,425,467,509,426,468,510,427,469,511,428,470,512,429,
2148 471,513,430,472,514,431,473,515,432,474,516,433,475,517,434,476,
2149 518,435,477,519,436,478,520,437,479,521,522,540,558,523,541,559,
2150 524,542,560,525,543,561,526,544,562,527,545,563,528,546,564,529,
2151 547,565,530,548,566,531,549,567,532,550,568,533,551,569,534,552,
2152 570,535,553,571,536,554,572,537,555,573,538,556,574,539,557,575},
2153 { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11, 12, 16, 20, 13,
2154 17, 21, 14, 18, 22, 15, 19, 23, 24, 28, 32, 25, 29, 33, 26, 30,
2155 34, 27, 31, 35, 36, 42, 48, 37, 43, 49, 38, 44, 50, 39, 45, 51,
2156 40, 46, 52, 41, 47, 53, 54, 62, 70, 55, 63, 71, 56, 64, 72, 57,
2157 65, 73, 58, 66, 74, 59, 67, 75, 60, 68, 76, 61, 69, 77, 78, 88,
2158 98, 79, 89, 99, 80, 90,100, 81, 91,101, 82, 92,102, 83, 93,103,
2159 84, 94,104, 85, 95,105, 86, 96,106, 87, 97,107,108,120,132,109,
2160 121,133,110,122,134,111,123,135,112,124,136,113,125,137,114,126,
2161 138,115,127,139,116,128,140,117,129,141,118,130,142,119,131,143,
2162 144,158,172,145,159,173,146,160,174,147,161,175,148,162,176,149,
2163 163,177,150,164,178,151,165,179,152,166,180,153,167,181,154,168,
2164 182,155,169,183,156,170,184,157,171,185,186,204,222,187,205,223,
2165 188,206,224,189,207,225,190,208,226,191,209,227,192,210,228,193,
2166 211,229,194,212,230,195,213,231,196,214,232,197,215,233,198,216,
2167 234,199,217,235,200,218,236,201,219,237,202,220,238,203,221,239,
2168 240,264,288,241,265,289,242,266,290,243,267,291,244,268,292,245,
2169 269,293,246,270,294,247,271,295,248,272,296,249,273,297,250,274,
2170 298,251,275,299,252,276,300,253,277,301,254,278,302,255,279,303,
2171 256,280,304,257,281,305,258,282,306,259,283,307,260,284,308,261,
2172 285,309,262,286,310,263,287,311,312,344,376,313,345,377,314,346,
2173 378,315,347,379,316,348,380,317,349,381,318,350,382,319,351,383,
2174 320,352,384,321,353,385,322,354,386,323,355,387,324,356,388,325,
2175 357,389,326,358,390,327,359,391,328,360,392,329,361,393,330,362,
2176 394,331,363,395,332,364,396,333,365,397,334,366,398,335,367,399,
2177 336,368,400,337,369,401,338,370,402,339,371,403,340,372,404,341,
2178 373,405,342,374,406,343,375,407,408,452,496,409,453,497,410,454,
2179 498,411,455,499,412,456,500,413,457,501,414,458,502,415,459,503,
2180 416,460,504,417,461,505,418,462,506,419,463,507,420,464,508,421,
2181 465,509,422,466,510,423,467,511,424,468,512,425,469,513,426,470,
2182 514,427,471,515,428,472,516,429,473,517,430,474,518,431,475,519,
2183 432,476,520,433,477,521,434,478,522,435,479,523,436,480,524,437,
2184 481,525,438,482,526,439,483,527,440,484,528,441,485,529,442,486,
2185 530,443,487,531,444,488,532,445,489,533,446,490,534,447,491,535,
2186 448,492,536,449,493,537,450,494,538,451,495,539,540,552,564,541,
2187 553,565,542,554,566,543,555,567,544,556,568,545,557,569,546,558,
2188 570,547,559,571,548,560,572,549,561,573,550,562,574,551,563,575},
2189 { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11, 12, 16, 20, 13,
2190 17, 21, 14, 18, 22, 15, 19, 23, 24, 28, 32, 25, 29, 33, 26, 30,
2191 34, 27, 31, 35, 36, 42, 48, 37, 43, 49, 38, 44, 50, 39, 45, 51,
2192 40, 46, 52, 41, 47, 53, 54, 62, 70, 55, 63, 71, 56, 64, 72, 57,
2193 65, 73, 58, 66, 74, 59, 67, 75, 60, 68, 76, 61, 69, 77, 78, 88,
2194 98, 79, 89, 99, 80, 90,100, 81, 91,101, 82, 92,102, 83, 93,103,
2195 84, 94,104, 85, 95,105, 86, 96,106, 87, 97,107,108,120,132,109,
2196 121,133,110,122,134,111,123,135,112,124,136,113,125,137,114,126,
2197 138,115,127,139,116,128,140,117,129,141,118,130,142,119,131,143,
2198 144,158,172,145,159,173,146,160,174,147,161,175,148,162,176,149,
2199 163,177,150,164,178,151,165,179,152,166,180,153,167,181,154,168,
2200 182,155,169,183,156,170,184,157,171,185,186,204,222,187,205,223,
2201 188,206,224,189,207,225,190,208,226,191,209,227,192,210,228,193,
2202 211,229,194,212,230,195,213,231,196,214,232,197,215,233,198,216,
2203 234,199,217,235,200,218,236,201,219,237,202,220,238,203,221,239,
2204 240,264,288,241,265,289,242,266,290,243,267,291,244,268,292,245,
2205 269,293,246,270,294,247,271,295,248,272,296,249,273,297,250,274,
2206 298,251,275,299,252,276,300,253,277,301,254,278,302,255,279,303,
2207 256,280,304,257,281,305,258,282,306,259,283,307,260,284,308,261,
2208 285,309,262,286,310,263,287,311,312,342,372,313,343,373,314,344,
2209 374,315,345,375,316,346,376,317,347,377,318,348,378,319,349,379,
2210 320,350,380,321,351,381,322,352,382,323,353,383,324,354,384,325,
2211 355,385,326,356,386,327,357,387,328,358,388,329,359,389,330,360,
2212 390,331,361,391,332,362,392,333,363,393,334,364,394,335,365,395,
2213 336,366,396,337,367,397,338,368,398,339,369,399,340,370,400,341,
2214 371,401,402,442,482,403,443,483,404,444,484,405,445,485,406,446,
2215 486,407,447,487,408,448,488,409,449,489,410,450,490,411,451,491,
2216 412,452,492,413,453,493,414,454,494,415,455,495,416,456,496,417,
2217 457,497,418,458,498,419,459,499,420,460,500,421,461,501,422,462,
2218 502,423,463,503,424,464,504,425,465,505,426,466,506,427,467,507,
2219 428,468,508,429,469,509,430,470,510,431,471,511,432,472,512,433,
2220 473,513,434,474,514,435,475,515,436,476,516,437,477,517,438,478,
2221 518,439,479,519,440,480,520,441,481,521,522,540,558,523,541,559,
2222 524,542,560,525,543,561,526,544,562,527,545,563,528,546,564,529,
2223 547,565,530,548,566,531,549,567,532,550,568,533,551,569,534,552,
2224 570,535,553,571,536,554,572,537,555,573,538,556,574,539,557,575},
2225 { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11, 12, 16, 20, 13,
2226 17, 21, 14, 18, 22, 15, 19, 23, 24, 28, 32, 25, 29, 33, 26, 30,
2227 34, 27, 31, 35, 36, 40, 44, 37, 41, 45, 38, 42, 46, 39, 43, 47,
2228 48, 54, 60, 49, 55, 61, 50, 56, 62, 51, 57, 63, 52, 58, 64, 53,
2229 59, 65, 66, 74, 82, 67, 75, 83, 68, 76, 84, 69, 77, 85, 70, 78,
2230 86, 71, 79, 87, 72, 80, 88, 73, 81, 89, 90,100,110, 91,101,111,
2231 92,102,112, 93,103,113, 94,104,114, 95,105,115, 96,106,116, 97,
2232 107,117, 98,108,118, 99,109,119,120,132,144,121,133,145,122,134,
2233 146,123,135,147,124,136,148,125,137,149,126,138,150,127,139,151,
2234 128,140,152,129,141,153,130,142,154,131,143,155,156,170,184,157,
2235 171,185,158,172,186,159,173,187,160,174,188,161,175,189,162,176,
2236 190,163,177,191,164,178,192,165,179,193,166,180,194,167,181,195,
2237 168,182,196,169,183,197,198,216,234,199,217,235,200,218,236,201,
2238 219,237,202,220,238,203,221,239,204,222,240,205,223,241,206,224,
2239 242,207,225,243,208,226,244,209,227,245,210,228,246,211,229,247,
2240 212,230,248,213,231,249,214,232,250,215,233,251,252,274,296,253,
2241 275,297,254,276,298,255,277,299,256,278,300,257,279,301,258,280,
2242 302,259,281,303,260,282,304,261,283,305,262,284,306,263,285,307,
2243 264,286,308,265,287,309,266,288,310,267,289,311,268,290,312,269,
2244 291,313,270,292,314,271,293,315,272,294,316,273,295,317,318,348,
2245 378,319,349,379,320,350,380,321,351,381,322,352,382,323,353,383,
2246 324,354,384,325,355,385,326,356,386,327,357,387,328,358,388,329,
2247 359,389,330,360,390,331,361,391,332,362,392,333,363,393,334,364,
2248 394,335,365,395,336,366,396,337,367,397,338,368,398,339,369,399,
2249 340,370,400,341,371,401,342,372,402,343,373,403,344,374,404,345,
2250 375,405,346,376,406,347,377,407,408,464,520,409,465,521,410,466,
2251 522,411,467,523,412,468,524,413,469,525,414,470,526,415,471,527,
2252 416,472,528,417,473,529,418,474,530,419,475,531,420,476,532,421,
2253 477,533,422,478,534,423,479,535,424,480,536,425,481,537,426,482,
2254 538,427,483,539,428,484,540,429,485,541,430,486,542,431,487,543,
2255 432,488,544,433,489,545,434,490,546,435,491,547,436,492,548,437,
2256 493,549,438,494,550,439,495,551,440,496,552,441,497,553,442,498,
2257 554,443,499,555,444,500,556,445,501,557,446,502,558,447,503,559,
2258 448,504,560,449,505,561,450,506,562,451,507,563,452,508,564,453,
2259 509,565,454,510,566,455,511,567,456,512,568,457,513,569,458,514,
2260 570,459,515,571,460,516,572,461,517,573,462,518,574,463,519,575},
2261 { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11, 12, 16, 20, 13,
2262 17, 21, 14, 18, 22, 15, 19, 23, 24, 28, 32, 25, 29, 33, 26, 30,
2263 34, 27, 31, 35, 36, 40, 44, 37, 41, 45, 38, 42, 46, 39, 43, 47,
2264 48, 54, 60, 49, 55, 61, 50, 56, 62, 51, 57, 63, 52, 58, 64, 53,
2265 59, 65, 66, 72, 78, 67, 73, 79, 68, 74, 80, 69, 75, 81, 70, 76,
2266 82, 71, 77, 83, 84, 94,104, 85, 95,105, 86, 96,106, 87, 97,107,
2267 88, 98,108, 89, 99,109, 90,100,110, 91,101,111, 92,102,112, 93,
2268 103,113,114,126,138,115,127,139,116,128,140,117,129,141,118,130,
2269 142,119,131,143,120,132,144,121,133,145,122,134,146,123,135,147,
2270 124,136,148,125,137,149,150,164,178,151,165,179,152,166,180,153,
2271 167,181,154,168,182,155,169,183,156,170,184,157,171,185,158,172,
2272 186,159,173,187,160,174,188,161,175,189,162,176,190,163,177,191,
2273 192,208,224,193,209,225,194,210,226,195,211,227,196,212,228,197,
2274 213,229,198,214,230,199,215,231,200,216,232,201,217,233,202,218,
2275 234,203,219,235,204,220,236,205,221,237,206,222,238,207,223,239,
2276 240,260,280,241,261,281,242,262,282,243,263,283,244,264,284,245,
2277 265,285,246,266,286,247,267,287,248,268,288,249,269,289,250,270,
2278 290,251,271,291,252,272,292,253,273,293,254,274,294,255,275,295,
2279 256,276,296,257,277,297,258,278,298,259,279,299,300,326,352,301,
2280 327,353,302,328,354,303,329,355,304,330,356,305,331,357,306,332,
2281 358,307,333,359,308,334,360,309,335,361,310,336,362,311,337,363,
2282 312,338,364,313,339,365,314,340,366,315,341,367,316,342,368,317,
2283 343,369,318,344,370,319,345,371,320,346,372,321,347,373,322,348,
2284 374,323,349,375,324,350,376,325,351,377,378,444,510,379,445,511,
2285 380,446,512,381,447,513,382,448,514,383,449,515,384,450,516,385,
2286 451,517,386,452,518,387,453,519,388,454,520,389,455,521,390,456,
2287 522,391,457,523,392,458,524,393,459,525,394,460,526,395,461,527,
2288 396,462,528,397,463,529,398,464,530,399,465,531,400,466,532,401,
2289 467,533,402,468,534,403,469,535,404,470,536,405,471,537,406,472,
2290 538,407,473,539,408,474,540,409,475,541,410,476,542,411,477,543,
2291 412,478,544,413,479,545,414,480,546,415,481,547,416,482,548,417,
2292 483,549,418,484,550,419,485,551,420,486,552,421,487,553,422,488,
2293 554,423,489,555,424,490,556,425,491,557,426,492,558,427,493,559,
2294 428,494,560,429,495,561,430,496,562,431,497,563,432,498,564,433,
2295 499,565,434,500,566,435,501,567,436,502,568,437,503,569,438,504,
2296 570,439,505,571,440,506,572,441,507,573,442,508,574,443,509,575},
2297 { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11, 12, 16, 20, 13,
2298 17, 21, 14, 18, 22, 15, 19, 23, 24, 28, 32, 25, 29, 33, 26, 30,
2299 34, 27, 31, 35, 36, 40, 44, 37, 41, 45, 38, 42, 46, 39, 43, 47,
2300 48, 54, 60, 49, 55, 61, 50, 56, 62, 51, 57, 63, 52, 58, 64, 53,
2301 59, 65, 66, 74, 82, 67, 75, 83, 68, 76, 84, 69, 77, 85, 70, 78,
2302 86, 71, 79, 87, 72, 80, 88, 73, 81, 89, 90,102,114, 91,103,115,
2303 92,104,116, 93,105,117, 94,106,118, 95,107,119, 96,108,120, 97,
2304 109,121, 98,110,122, 99,111,123,100,112,124,101,113,125,126,142,
2305 158,127,143,159,128,144,160,129,145,161,130,146,162,131,147,163,
2306 132,148,164,133,149,165,134,150,166,135,151,167,136,152,168,137,
2307 153,169,138,154,170,139,155,171,140,156,172,141,157,173,174,194,
2308 214,175,195,215,176,196,216,177,197,217,178,198,218,179,199,219,
2309 180,200,220,181,201,221,182,202,222,183,203,223,184,204,224,185,
2310 205,225,186,206,226,187,207,227,188,208,228,189,209,229,190,210,
2311 230,191,211,231,192,212,232,193,213,233,234,260,286,235,261,287,
2312 236,262,288,237,263,289,238,264,290,239,265,291,240,266,292,241,
2313 267,293,242,268,294,243,269,295,244,270,296,245,271,297,246,272,
2314 298,247,273,299,248,274,300,249,275,301,250,276,302,251,277,303,
2315 252,278,304,253,279,305,254,280,306,255,281,307,256,282,308,257,
2316 283,309,258,284,310,259,285,311,312,346,380,313,347,381,314,348,
2317 382,315,349,383,316,350,384,317,351,385,318,352,386,319,353,387,
2318 320,354,388,321,355,389,322,356,390,323,357,391,324,358,392,325,
2319 359,393,326,360,394,327,361,395,328,362,396,329,363,397,330,364,
2320 398,331,365,399,332,366,400,333,367,401,334,368,402,335,369,403,
2321 336,370,404,337,371,405,338,372,406,339,373,407,340,374,408,341,
2322 375,409,342,376,410,343,377,411,344,378,412,345,379,413,414,456,
2323 498,415,457,499,416,458,500,417,459,501,418,460,502,419,461,503,
2324 420,462,504,421,463,505,422,464,506,423,465,507,424,466,508,425,
2325 467,509,426,468,510,427,469,511,428,470,512,429,471,513,430,472,
2326 514,431,473,515,432,474,516,433,475,517,434,476,518,435,477,519,
2327 436,478,520,437,479,521,438,480,522,439,481,523,440,482,524,441,
2328 483,525,442,484,526,443,485,527,444,486,528,445,487,529,446,488,
2329 530,447,489,531,448,490,532,449,491,533,450,492,534,451,493,535,
2330 452,494,536,453,495,537,454,496,538,455,497,539,540,552,564,541,
2331 553,565,542,554,566,543,555,567,544,556,568,545,557,569,546,558,
2332 570,547,559,571,548,560,572,549,561,573,550,562,574,551,563,575}
2333 };
2334*/
2335
2336 private static final float cs[] =
2337 {
2338 0.857492925712f, 0.881741997318f, 0.949628649103f, 0.983314592492f,
2339 0.995517816065f, 0.999160558175f, 0.999899195243f, 0.999993155067f
2340 };
2341
2342 private static final float ca[] =
2343 {
2344 -0.5144957554270f, -0.4717319685650f, -0.3133774542040f, -0.1819131996110f,
2345 -0.0945741925262f, -0.0409655828852f, -0.0141985685725f, -0.00369997467375f
2346 };
2347
2348 /************************************************************/
2349 /* END OF L3TABLE */
2350 /************************************************************/
2351
2352 /************************************************************/
2353 /* L3TYPE */
2354 /************************************************************/
2355
2356
2357 /***************************************************************/
2358 /* END OF L3TYPE */
2359 /***************************************************************/
2360
2361 /***************************************************************/
2362 /* INV_MDCT */
2363 /***************************************************************/
2364 public static final float win[][] =
2365 {
2366 { -1.6141214951E-02f, -5.3603178919E-02f, -1.0070713296E-01f, -1.6280817573E-01f,
2367 -4.9999999679E-01f, -3.8388735032E-01f, -6.2061144372E-01f, -1.1659756083E+00f,
2368 -3.8720752656E+00f, -4.2256286556E+00f, -1.5195289984E+00f, -9.7416483388E-01f,
2369 -7.3744074053E-01f, -1.2071067773E+00f, -5.1636156596E-01f, -4.5426052317E-01f,
2370 -4.0715656898E-01f, -3.6969460527E-01f, -3.3876269197E-01f, -3.1242222492E-01f,
2371 -2.8939587111E-01f, -2.6880081906E-01f, -5.0000000266E-01f, -2.3251417468E-01f,
2372 -2.1596714708E-01f, -2.0004979098E-01f, -1.8449493497E-01f, -1.6905846094E-01f,
2373 -1.5350360518E-01f, -1.3758624925E-01f, -1.2103922149E-01f, -2.0710679058E-01f,
2374 -8.4752577594E-02f, -6.4157525656E-02f, -4.1131172614E-02f, -1.4790705759E-02f },
2375
2376 { -1.6141214951E-02f, -5.3603178919E-02f, -1.0070713296E-01f, -1.6280817573E-01f,
2377 -4.9999999679E-01f, -3.8388735032E-01f, -6.2061144372E-01f, -1.1659756083E+00f,
2378 -3.8720752656E+00f, -4.2256286556E+00f, -1.5195289984E+00f, -9.7416483388E-01f,
2379 -7.3744074053E-01f, -1.2071067773E+00f, -5.1636156596E-01f, -4.5426052317E-01f,
2380 -4.0715656898E-01f, -3.6969460527E-01f, -3.3908542600E-01f, -3.1511810350E-01f,
2381 -2.9642226150E-01f, -2.8184548650E-01f, -5.4119610000E-01f, -2.6213228100E-01f,
2382 -2.5387916537E-01f, -2.3296291359E-01f, -1.9852728987E-01f, -1.5233534808E-01f,
2383 -9.6496400054E-02f, -3.3423828516E-02f, 0.0000000000E+00f, 0.0000000000E+00f,
2384 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f },
2385
2386 { -4.8300800645E-02f, -1.5715656932E-01f, -2.8325045177E-01f, -4.2953747763E-01f,
2387 -1.2071067795E+00f, -8.2426483178E-01f, -1.1451749106E+00f, -1.7695290101E+00f,
2388 -4.5470225061E+00f, -3.4890531002E+00f, -7.3296292804E-01f, -1.5076514758E-01f,
2389 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f,
2390 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f,
2391 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f,
2392 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f,
2393 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f,
2394 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f },
2395
2396 { 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f, 0.0000000000E+00f,
2397 0.0000000000E+00f, 0.0000000000E+00f, -1.5076513660E-01f, -7.3296291107E-01f,
2398 -3.4890530566E+00f, -4.5470224727E+00f, -1.7695290031E+00f, -1.1451749092E+00f,
2399 -8.3137738100E-01f, -1.3065629650E+00f, -5.4142014250E-01f, -4.6528974900E-01f,
2400 -4.1066990750E-01f, -3.7004680800E-01f, -3.3876269197E-01f, -3.1242222492E-01f,
2401 -2.8939587111E-01f, -2.6880081906E-01f, -5.0000000266E-01f, -2.3251417468E-01f,
2402 -2.1596714708E-01f, -2.0004979098E-01f, -1.8449493497E-01f, -1.6905846094E-01f,
2403 -1.5350360518E-01f, -1.3758624925E-01f, -1.2103922149E-01f, -2.0710679058E-01f,
2404 -8.4752577594E-02f, -6.4157525656E-02f, -4.1131172614E-02f, -1.4790705759E-02f }
2405 };
2406 /***************************************************************/
2407 /* END OF INV_MDCT */
2408 /***************************************************************/
2409
2410 class Sftable
2411 {
2412 public int[] l;
2413 public int[] s;
2414
2415 public Sftable()
2416 {
2417 l = new int[5];
2418 s = new int[3];
2419 }
2420
2421 public Sftable(int[] thel, int[] thes)
2422 {
2423 l = thel;
2424 s = thes;
2425 }
2426 }
2427
2428 public Sftable sftable;
2429
2430 public static final int nr_of_sfb_block[][][] =
2431 {{{ 6, 5, 5, 5} , { 9, 9, 9, 9} , { 6, 9, 9, 9}},
2432 {{ 6, 5, 7, 3} , { 9, 9,12, 6} , { 6, 9,12, 6}},
2433 {{11,10, 0, 0} , {18,18, 0, 0} , {15,18, 0, 0}},
2434 {{ 7, 7, 7, 0} , {12,12,12, 0} , { 6,15,12, 0}},
2435 {{ 6, 6, 6, 3} , {12, 9, 9, 6} , { 6,12, 9, 6}},
2436 {{ 8, 8, 5, 0} , {15,12, 9, 0} , { 6,18, 9, 0}}};
2437
2438
2439}
diff --git a/songdbj/javazoom/jl/decoder/Manager.java b/songdbj/javazoom/jl/decoder/Manager.java
new file mode 100644
index 0000000000..f566a232e7
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/Manager.java
@@ -0,0 +1,46 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *-----------------------------------------------------------------------
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *----------------------------------------------------------------------
18 */
19
20package javazoom.jl.decoder;
21
22/**
23 * Work in progress.
24 *
25 * Manages a number of controls.
26 */
27public class Manager //implements Control
28{
29 public void addControl(Control c)
30 {
31
32 }
33
34 public void removeControl(Control c)
35 {
36
37 }
38
39 public void removeAll()
40 {
41
42 }
43
44 // control interface delegates to a managed control
45
46}
diff --git a/songdbj/javazoom/jl/decoder/Obuffer.java b/songdbj/javazoom/jl/decoder/Obuffer.java
new file mode 100644
index 0000000000..45a71a9baf
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/Obuffer.java
@@ -0,0 +1,88 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Added appendSamples() method for efficiency. MDM.
4 * 15/02/99 ,Java Conversion by E.B ,ebsp@iname.com, JavaLayer
5 *
6 * Declarations for output buffer, includes operating system
7 * implementation of the virtual Obuffer. Optional routines
8 * enabling seeks and stops added by Jeff Tsay.
9 *
10 * @(#) obuffer.h 1.8, last edit: 6/15/94 16:51:56
11 * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
12 * @(#) Berlin University of Technology
13 *
14 * Idea and first implementation for u-law output with fast downsampling by
15 * Jim Boucher (jboucher@flash.bu.edu)
16 *
17 * LinuxObuffer class written by
18 * Louis P. Kruger (lpkruger@phoenix.princeton.edu)
19 *-----------------------------------------------------------------------
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU Library General Public License as published
22 * by the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU Library General Public License for more details.
29 *
30 * You should have received a copy of the GNU Library General Public
31 * License along with this program; if not, write to the Free Software
32 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 *----------------------------------------------------------------------
34 */
35package javazoom.jl.decoder;
36
37/**
38 * Base Class for audio output.
39 */
40public abstract class Obuffer
41{
42 public static final int OBUFFERSIZE = 2 * 1152; // max. 2 * 1152 samples per frame
43 public static final int MAXCHANNELS = 2; // max. number of channels
44
45 /**
46 * Takes a 16 Bit PCM sample.
47 */
48 public abstract void append(int channel, short value);
49
50 /**
51 * Accepts 32 new PCM samples.
52 */
53 public void appendSamples(int channel, float[] f)
54 {
55 short s;
56 for (int i=0; i<32;)
57 {
58 s = clip(f[i++]);
59 append(channel, s);
60 }
61 }
62
63 /**
64 * Clip Sample to 16 Bits
65 */
66 private final short clip(float sample)
67 {
68 return ((sample > 32767.0f) ? 32767 :
69 ((sample < -32768.0f) ? -32768 :
70 (short) sample));
71 }
72
73 /**
74 * Write the samples to the file or directly to the audio hardware.
75 */
76 public abstract void write_buffer(int val);
77 public abstract void close();
78
79 /**
80 * Clears all data in the buffer (for seeking).
81 */
82 public abstract void clear_buffer();
83
84 /**
85 * Notify the buffer that the user has stopped the stream.
86 */
87 public abstract void set_stop_flag();
88}
diff --git a/songdbj/javazoom/jl/decoder/OutputChannels.java b/songdbj/javazoom/jl/decoder/OutputChannels.java
new file mode 100644
index 0000000000..58c8310de7
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/OutputChannels.java
@@ -0,0 +1,143 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 12/12/99 Initial implementation. mdm@techie.com.
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.decoder;
22
23
24/**
25 * A Type-safe representation of the the supported output channel
26 * constants.
27 *
28 * This class is immutable and, hence, is thread safe.
29 *
30 * @author Mat McGowan 12/12/99
31 * @since 0.0.7
32 */
33public class OutputChannels
34{
35 /**
36 * Flag to indicate output should include both channels.
37 */
38 public static final int BOTH_CHANNELS = 0;
39
40 /**
41 * Flag to indicate output should include the left channel only.
42 */
43 public static final int LEFT_CHANNEL = 1;
44
45 /**
46 * Flag to indicate output should include the right channel only.
47 */
48 public static final int RIGHT_CHANNEL = 2;
49
50 /**
51 * Flag to indicate output is mono.
52 */
53 public static final int DOWNMIX_CHANNELS = 3;
54
55
56 public static final OutputChannels LEFT = new OutputChannels(LEFT_CHANNEL);
57 public static final OutputChannels RIGHT = new OutputChannels(RIGHT_CHANNEL);
58 public static final OutputChannels BOTH = new OutputChannels(BOTH_CHANNELS);
59 public static final OutputChannels DOWNMIX = new OutputChannels(DOWNMIX_CHANNELS);
60
61
62 private /*final*/ int outputChannels;
63
64 /**
65 * Creates an <code>OutputChannels</code> instance
66 * corresponding to the given channel code.
67 *
68 * @param code one of the OutputChannels channel code constants.
69 *
70 * @throws IllegalArgumentException if code is not a valid
71 * channel code.
72 */
73 static public OutputChannels fromInt(int code)
74 {
75 switch (code)
76 {
77 case LEFT_CHANNEL:
78 return LEFT;
79 case RIGHT_CHANNEL:
80 return RIGHT;
81 case BOTH_CHANNELS:
82 return BOTH;
83 case DOWNMIX_CHANNELS:
84 return DOWNMIX;
85 default:
86 throw new IllegalArgumentException("Invalid channel code: "+code);
87 }
88 }
89
90 private OutputChannels(int channels)
91 {
92 outputChannels = channels;
93
94 if (channels<0 || channels>3)
95 throw new IllegalArgumentException("channels");
96 }
97
98 /**
99 * Retrieves the code representing the desired output channels.
100 * Will be one of LEFT_CHANNEL, RIGHT_CHANNEL, BOTH_CHANNELS
101 * or DOWNMIX_CHANNELS.
102 *
103 * @return the channel code represented by this instance.
104 */
105 public int getChannelsOutputCode()
106 {
107 return outputChannels;
108 }
109
110 /**
111 * Retrieves the number of output channels represented
112 * by this channel output type.
113 *
114 * @return The number of output channels for this channel output
115 * type. This will be 2 for BOTH_CHANNELS only, and 1
116 * for all other types.
117 */
118 public int getChannelCount()
119 {
120 int count = (outputChannels==BOTH_CHANNELS) ? 2 : 1;
121 return count;
122 }
123
124
125 public boolean equals(Object o)
126 {
127 boolean equals = false;
128
129 if (o instanceof OutputChannels)
130 {
131 OutputChannels oc = (OutputChannels)o;
132 equals = (oc.outputChannels == outputChannels);
133 }
134
135 return equals;
136 }
137
138 public int hashCode()
139 {
140 return outputChannels;
141 }
142
143}
diff --git a/songdbj/javazoom/jl/decoder/SampleBuffer.java b/songdbj/javazoom/jl/decoder/SampleBuffer.java
new file mode 100644
index 0000000000..ba4bfa060f
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/SampleBuffer.java
@@ -0,0 +1,132 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *
4 * 12/12/99 Initial Version based on FileObuffer. mdm@techie.com.
5 *
6 * FileObuffer:
7 * 15/02/99 Java Conversion by E.B ,javalayer@javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.jl.decoder;
27
28/**
29 * The <code>SampleBuffer</code> class implements an output buffer
30 * that provides storage for a fixed size block of samples.
31 */
32public class SampleBuffer extends Obuffer
33{
34 private short[] buffer;
35 private int[] bufferp;
36 private int channels;
37 private int frequency;
38
39 /**
40 * Constructor
41 */
42 public SampleBuffer(int sample_frequency, int number_of_channels)
43 {
44 buffer = new short[OBUFFERSIZE];
45 bufferp = new int[MAXCHANNELS];
46 channels = number_of_channels;
47 frequency = sample_frequency;
48
49 for (int i = 0; i < number_of_channels; ++i)
50 bufferp[i] = (short)i;
51
52 }
53
54 public int getChannelCount()
55 {
56 return this.channels;
57 }
58
59 public int getSampleFrequency()
60 {
61 return this.frequency;
62 }
63
64 public short[] getBuffer()
65 {
66 return this.buffer;
67 }
68
69 public int getBufferLength()
70 {
71 return bufferp[0];
72 }
73
74 /**
75 * Takes a 16 Bit PCM sample.
76 */
77 public void append(int channel, short value)
78 {
79 buffer[bufferp[channel]] = value;
80 bufferp[channel] += channels;
81 }
82
83 public void appendSamples(int channel, float[] f)
84 {
85 int pos = bufferp[channel];
86
87 short s;
88 float fs;
89 for (int i=0; i<32;)
90 {
91 fs = f[i++];
92 fs = (fs>32767.0f ? 32767.0f
93 : (fs < -32767.0f ? -32767.0f : fs));
94
95 s = (short)fs;
96 buffer[pos] = s;
97 pos += channels;
98 }
99
100 bufferp[channel] = pos;
101 }
102
103
104 /**
105 * Write the samples to the file (Random Acces).
106 */
107 public void write_buffer(int val)
108 {
109
110 //for (int i = 0; i < channels; ++i)
111 // bufferp[i] = (short)i;
112
113 }
114
115 public void close()
116 {}
117
118 /**
119 *
120 */
121 public void clear_buffer()
122 {
123 for (int i = 0; i < channels; ++i)
124 bufferp[i] = (short)i;
125 }
126
127 /**
128 *
129 */
130 public void set_stop_flag()
131 {}
132}
diff --git a/songdbj/javazoom/jl/decoder/Source.java b/songdbj/javazoom/jl/decoder/Source.java
new file mode 100644
index 0000000000..9d6a5d732e
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/Source.java
@@ -0,0 +1,49 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *-----------------------------------------------------------------------
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *----------------------------------------------------------------------
18 */
19
20package javazoom.jl.decoder;
21
22import java.io.IOException;
23
24/**
25 * Work in progress.
26 *
27 * Class to describe a seekable data source.
28 *
29 */
30public interface Source
31{
32
33 public static final long LENGTH_UNKNOWN = -1;
34
35 public int read(byte[] b, int offs, int len)
36 throws IOException;
37
38
39 public boolean willReadBlock();
40
41 public boolean isSeekable();
42
43 public long length();
44
45 public long tell();
46
47 public long seek(long pos);
48
49}
diff --git a/songdbj/javazoom/jl/decoder/SynthesisFilter.java b/songdbj/javazoom/jl/decoder/SynthesisFilter.java
new file mode 100644
index 0000000000..581ab03cc2
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/SynthesisFilter.java
@@ -0,0 +1,1817 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *
4 * 04/01/00 Fixes for running under build 23xx Microsoft JVM. mdm.
5 *
6 * 19/12/99 Performance improvements to compute_pcm_samples().
7 * Mat McGowan. mdm@techie.com.
8 *
9 * 16/02/99 Java Conversion by E.B , javalayer@javazoom.net
10 *
11 * @(#) synthesis_filter.h 1.8, last edit: 6/15/94 16:52:00
12 * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
13 * @(#) Berlin University of Technology
14 *
15 *-----------------------------------------------------------------------
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU Library General Public License as published
18 * by the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU Library General Public License for more details.
25 *
26 * You should have received a copy of the GNU Library General Public
27 * License along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *----------------------------------------------------------------------
30 */
31package javazoom.jl.decoder;
32
33import java.io.IOException;
34
35/**
36 * A class for the synthesis filter bank.
37 * This class does a fast downsampling from 32, 44.1 or 48 kHz to 8 kHz, if ULAW is defined.
38 * Frequencies above 4 kHz are removed by ignoring higher subbands.
39 */
40final class SynthesisFilter
41{
42 private float[] v1;
43 private float[] v2;
44 private float[] actual_v; // v1 or v2
45 private int actual_write_pos; // 0-15
46 private float[] samples; // 32 new subband samples
47 private int channel;
48 private float scalefactor;
49 private float[] eq;
50
51 /**
52 * Quality value for controlling CPU usage/quality tradeoff.
53 */
54 /*
55 private int quality;
56
57 private int v_inc;
58
59
60
61 public static final int HIGH_QUALITY = 1;
62 public static final int MEDIUM_QUALITY = 2;
63 public static final int LOW_QUALITY = 4;
64 */
65
66 /**
67 * Contructor.
68 * The scalefactor scales the calculated float pcm samples to short values
69 * (raw pcm samples are in [-1.0, 1.0], if no violations occur).
70 */
71 public SynthesisFilter(int channelnumber, float factor, float[] eq0)
72 {
73 if (d==null)
74 {
75 d = load_d();
76 d16 = splitArray(d, 16);
77 }
78
79 v1 = new float[512];
80 v2 = new float[512];
81 samples = new float[32];
82 channel = channelnumber;
83 scalefactor = factor;
84 setEQ(eq);
85 //setQuality(HIGH_QUALITY);
86
87 reset();
88 }
89
90 public void setEQ(float[] eq0)
91 {
92 this.eq = eq0;
93 if (eq==null)
94 {
95 eq = new float[32];
96 for (int i=0; i<32; i++)
97 eq[i] = 1.0f;
98 }
99 if (eq.length<32)
100 {
101 throw new IllegalArgumentException("eq0");
102 }
103
104 }
105
106 /*
107 private void setQuality(int quality0)
108 {
109 switch (quality0)
110 {
111 case HIGH_QUALITY:
112 case MEDIUM_QUALITY:
113 case LOW_QUALITY:
114 v_inc = 16 * quality0;
115 quality = quality0;
116 break;
117 default :
118 throw new IllegalArgumentException("Unknown quality value");
119 }
120 }
121
122 public int getQuality()
123 {
124 return quality;
125 }
126 */
127
128 /**
129 * Reset the synthesis filter.
130 */
131 public void reset()
132 {
133 //float[] floatp;
134 // float[] floatp2;
135
136 // initialize v1[] and v2[]:
137 //for (floatp = v1 + 512, floatp2 = v2 + 512; floatp > v1; )
138 // *--floatp = *--floatp2 = 0.0;
139 for (int p=0;p<512;p++)
140 v1[p] = v2[p] = 0.0f;
141
142 // initialize samples[]:
143 //for (floatp = samples + 32; floatp > samples; )
144 // *--floatp = 0.0;
145 for (int p2=0;p2<32;p2++)
146 samples[p2] = 0.0f;
147
148 actual_v = v1;
149 actual_write_pos = 15;
150 }
151
152
153 /**
154 * Inject Sample.
155 */
156 public void input_sample(float sample, int subbandnumber)
157 {
158 samples[subbandnumber] = eq[subbandnumber]*sample;
159 }
160
161 public void input_samples(float[] s)
162 {
163 for (int i=31; i>=0; i--)
164 {
165 samples[i] = s[i]*eq[i];
166 }
167 }
168
169 /**
170 * Compute new values via a fast cosine transform.
171 */
172 private void compute_new_v()
173 {
174 // p is fully initialized from x1
175 //float[] p = _p;
176 // pp is fully initialized from p
177 //float[] pp = _pp;
178
179 //float[] new_v = _new_v;
180
181 //float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3
182 //float[] p = new float[16];
183 //float[] pp = new float[16];
184
185 /*
186 for (int i=31; i>=0; i--)
187 {
188 new_v[i] = 0.0f;
189 }
190 */
191
192 float new_v0, new_v1, new_v2, new_v3, new_v4, new_v5, new_v6, new_v7, new_v8, new_v9;
193 float new_v10, new_v11, new_v12, new_v13, new_v14, new_v15, new_v16, new_v17, new_v18, new_v19;
194 float new_v20, new_v21, new_v22, new_v23, new_v24, new_v25, new_v26, new_v27, new_v28, new_v29;
195 float new_v30, new_v31;
196
197 new_v0 = new_v1 = new_v2 = new_v3 = new_v4 = new_v5 = new_v6 = new_v7 = new_v8 = new_v9 =
198 new_v10 = new_v11 = new_v12 = new_v13 = new_v14 = new_v15 = new_v16 = new_v17 = new_v18 = new_v19 =
199 new_v20 = new_v21 = new_v22 = new_v23 = new_v24 = new_v25 = new_v26 = new_v27 = new_v28 = new_v29 =
200 new_v30 = new_v31 = 0.0f;
201
202
203// float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3
204// float[] p = new float[16];
205// float[] pp = new float[16];
206
207 float[] s = samples;
208
209 float s0 = s[0];
210 float s1 = s[1];
211 float s2 = s[2];
212 float s3 = s[3];
213 float s4 = s[4];
214 float s5 = s[5];
215 float s6 = s[6];
216 float s7 = s[7];
217 float s8 = s[8];
218 float s9 = s[9];
219 float s10 = s[10];
220 float s11 = s[11];
221 float s12 = s[12];
222 float s13 = s[13];
223 float s14 = s[14];
224 float s15 = s[15];
225 float s16 = s[16];
226 float s17 = s[17];
227 float s18 = s[18];
228 float s19 = s[19];
229 float s20 = s[20];
230 float s21 = s[21];
231 float s22 = s[22];
232 float s23 = s[23];
233 float s24 = s[24];
234 float s25 = s[25];
235 float s26 = s[26];
236 float s27 = s[27];
237 float s28 = s[28];
238 float s29 = s[29];
239 float s30 = s[30];
240 float s31 = s[31];
241
242 float p0 = s0 + s31;
243 float p1 = s1 + s30;
244 float p2 = s2 + s29;
245 float p3 = s3 + s28;
246 float p4 = s4 + s27;
247 float p5 = s5 + s26;
248 float p6 = s6 + s25;
249 float p7 = s7 + s24;
250 float p8 = s8 + s23;
251 float p9 = s9 + s22;
252 float p10 = s10 + s21;
253 float p11 = s11 + s20;
254 float p12 = s12 + s19;
255 float p13 = s13 + s18;
256 float p14 = s14 + s17;
257 float p15 = s15 + s16;
258
259 float pp0 = p0 + p15;
260 float pp1 = p1 + p14;
261 float pp2 = p2 + p13;
262 float pp3 = p3 + p12;
263 float pp4 = p4 + p11;
264 float pp5 = p5 + p10;
265 float pp6 = p6 + p9;
266 float pp7 = p7 + p8;
267 float pp8 = (p0 - p15) * cos1_32;
268 float pp9 = (p1 - p14) * cos3_32;
269 float pp10 = (p2 - p13) * cos5_32;
270 float pp11 = (p3 - p12) * cos7_32;
271 float pp12 = (p4 - p11) * cos9_32;
272 float pp13 = (p5 - p10) * cos11_32;
273 float pp14 = (p6 - p9) * cos13_32;
274 float pp15 = (p7 - p8) * cos15_32;
275
276 p0 = pp0 + pp7;
277 p1 = pp1 + pp6;
278 p2 = pp2 + pp5;
279 p3 = pp3 + pp4;
280 p4 = (pp0 - pp7) * cos1_16;
281 p5 = (pp1 - pp6) * cos3_16;
282 p6 = (pp2 - pp5) * cos5_16;
283 p7 = (pp3 - pp4) * cos7_16;
284 p8 = pp8 + pp15;
285 p9 = pp9 + pp14;
286 p10 = pp10 + pp13;
287 p11 = pp11 + pp12;
288 p12 = (pp8 - pp15) * cos1_16;
289 p13 = (pp9 - pp14) * cos3_16;
290 p14 = (pp10 - pp13) * cos5_16;
291 p15 = (pp11 - pp12) * cos7_16;
292
293
294 pp0 = p0 + p3;
295 pp1 = p1 + p2;
296 pp2 = (p0 - p3) * cos1_8;
297 pp3 = (p1 - p2) * cos3_8;
298 pp4 = p4 + p7;
299 pp5 = p5 + p6;
300 pp6 = (p4 - p7) * cos1_8;
301 pp7 = (p5 - p6) * cos3_8;
302 pp8 = p8 + p11;
303 pp9 = p9 + p10;
304 pp10 = (p8 - p11) * cos1_8;
305 pp11 = (p9 - p10) * cos3_8;
306 pp12 = p12 + p15;
307 pp13 = p13 + p14;
308 pp14 = (p12 - p15) * cos1_8;
309 pp15 = (p13 - p14) * cos3_8;
310
311 p0 = pp0 + pp1;
312 p1 = (pp0 - pp1) * cos1_4;
313 p2 = pp2 + pp3;
314 p3 = (pp2 - pp3) * cos1_4;
315 p4 = pp4 + pp5;
316 p5 = (pp4 - pp5) * cos1_4;
317 p6 = pp6 + pp7;
318 p7 = (pp6 - pp7) * cos1_4;
319 p8 = pp8 + pp9;
320 p9 = (pp8 - pp9) * cos1_4;
321 p10 = pp10 + pp11;
322 p11 = (pp10 - pp11) * cos1_4;
323 p12 = pp12 + pp13;
324 p13 = (pp12 - pp13) * cos1_4;
325 p14 = pp14 + pp15;
326 p15 = (pp14 - pp15) * cos1_4;
327
328 // this is pretty insane coding
329 float tmp1;
330 new_v19/*36-17*/ = -(new_v4 = (new_v12 = p7) + p5) - p6;
331 new_v27/*44-17*/ = -p6 - p7 - p4;
332 new_v6 = (new_v10 = (new_v14 = p15) + p11) + p13;
333 new_v17/*34-17*/ = -(new_v2 = p15 + p13 + p9) - p14;
334 new_v21/*38-17*/ = (tmp1 = -p14 - p15 - p10 - p11) - p13;
335 new_v29/*46-17*/ = -p14 - p15 - p12 - p8;
336 new_v25/*42-17*/ = tmp1 - p12;
337 new_v31/*48-17*/ = -p0;
338 new_v0 = p1;
339 new_v23/*40-17*/ = -(new_v8 = p3) - p2;
340
341 p0 = (s0 - s31) * cos1_64;
342 p1 = (s1 - s30) * cos3_64;
343 p2 = (s2 - s29) * cos5_64;
344 p3 = (s3 - s28) * cos7_64;
345 p4 = (s4 - s27) * cos9_64;
346 p5 = (s5 - s26) * cos11_64;
347 p6 = (s6 - s25) * cos13_64;
348 p7 = (s7 - s24) * cos15_64;
349 p8 = (s8 - s23) * cos17_64;
350 p9 = (s9 - s22) * cos19_64;
351 p10 = (s10 - s21) * cos21_64;
352 p11 = (s11 - s20) * cos23_64;
353 p12 = (s12 - s19) * cos25_64;
354 p13 = (s13 - s18) * cos27_64;
355 p14 = (s14 - s17) * cos29_64;
356 p15 = (s15 - s16) * cos31_64;
357
358
359 pp0 = p0 + p15;
360 pp1 = p1 + p14;
361 pp2 = p2 + p13;
362 pp3 = p3 + p12;
363 pp4 = p4 + p11;
364 pp5 = p5 + p10;
365 pp6 = p6 + p9;
366 pp7 = p7 + p8;
367 pp8 = (p0 - p15) * cos1_32;
368 pp9 = (p1 - p14) * cos3_32;
369 pp10 = (p2 - p13) * cos5_32;
370 pp11 = (p3 - p12) * cos7_32;
371 pp12 = (p4 - p11) * cos9_32;
372 pp13 = (p5 - p10) * cos11_32;
373 pp14 = (p6 - p9) * cos13_32;
374 pp15 = (p7 - p8) * cos15_32;
375
376
377 p0 = pp0 + pp7;
378 p1 = pp1 + pp6;
379 p2 = pp2 + pp5;
380 p3 = pp3 + pp4;
381 p4 = (pp0 - pp7) * cos1_16;
382 p5 = (pp1 - pp6) * cos3_16;
383 p6 = (pp2 - pp5) * cos5_16;
384 p7 = (pp3 - pp4) * cos7_16;
385 p8 = pp8 + pp15;
386 p9 = pp9 + pp14;
387 p10 = pp10 + pp13;
388 p11 = pp11 + pp12;
389 p12 = (pp8 - pp15) * cos1_16;
390 p13 = (pp9 - pp14) * cos3_16;
391 p14 = (pp10 - pp13) * cos5_16;
392 p15 = (pp11 - pp12) * cos7_16;
393
394
395 pp0 = p0 + p3;
396 pp1 = p1 + p2;
397 pp2 = (p0 - p3) * cos1_8;
398 pp3 = (p1 - p2) * cos3_8;
399 pp4 = p4 + p7;
400 pp5 = p5 + p6;
401 pp6 = (p4 - p7) * cos1_8;
402 pp7 = (p5 - p6) * cos3_8;
403 pp8 = p8 + p11;
404 pp9 = p9 + p10;
405 pp10 = (p8 - p11) * cos1_8;
406 pp11 = (p9 - p10) * cos3_8;
407 pp12 = p12 + p15;
408 pp13 = p13 + p14;
409 pp14 = (p12 - p15) * cos1_8;
410 pp15 = (p13 - p14) * cos3_8;
411
412
413 p0 = pp0 + pp1;
414 p1 = (pp0 - pp1) * cos1_4;
415 p2 = pp2 + pp3;
416 p3 = (pp2 - pp3) * cos1_4;
417 p4 = pp4 + pp5;
418 p5 = (pp4 - pp5) * cos1_4;
419 p6 = pp6 + pp7;
420 p7 = (pp6 - pp7) * cos1_4;
421 p8 = pp8 + pp9;
422 p9 = (pp8 - pp9) * cos1_4;
423 p10 = pp10 + pp11;
424 p11 = (pp10 - pp11) * cos1_4;
425 p12 = pp12 + pp13;
426 p13 = (pp12 - pp13) * cos1_4;
427 p14 = pp14 + pp15;
428 p15 = (pp14 - pp15) * cos1_4;
429
430
431 // manually doing something that a compiler should handle sucks
432 // coding like this is hard to read
433 float tmp2;
434 new_v5 = (new_v11 = (new_v13 = (new_v15 = p15) + p7) + p11)
435 + p5 + p13;
436 new_v7 = (new_v9 = p15 + p11 + p3) + p13;
437 new_v16/*33-17*/ = -(new_v1 = (tmp1 = p13 + p15 + p9) + p1) - p14;
438 new_v18/*35-17*/ = -(new_v3 = tmp1 + p5 + p7) - p6 - p14;
439
440 new_v22/*39-17*/ = (tmp1 = -p10 - p11 - p14 - p15)
441 - p13 - p2 - p3;
442 new_v20/*37-17*/ = tmp1 - p13 - p5 - p6 - p7;
443 new_v24/*41-17*/ = tmp1 - p12 - p2 - p3;
444 new_v26/*43-17*/ = tmp1 - p12 - (tmp2 = p4 + p6 + p7);
445 new_v30/*47-17*/ = (tmp1 = -p8 - p12 - p14 - p15) - p0;
446 new_v28/*45-17*/ = tmp1 - tmp2;
447
448 // insert V[0-15] (== new_v[0-15]) into actual v:
449 // float[] x2 = actual_v + actual_write_pos;
450 float dest[] = actual_v;
451
452 int pos = actual_write_pos;
453
454 dest[0 + pos] = new_v0;
455 dest[16 + pos] = new_v1;
456 dest[32 + pos] = new_v2;
457 dest[48 + pos] = new_v3;
458 dest[64 + pos] = new_v4;
459 dest[80 + pos] = new_v5;
460 dest[96 + pos] = new_v6;
461 dest[112 + pos] = new_v7;
462 dest[128 + pos] = new_v8;
463 dest[144 + pos] = new_v9;
464 dest[160 + pos] = new_v10;
465 dest[176 + pos] = new_v11;
466 dest[192 + pos] = new_v12;
467 dest[208 + pos] = new_v13;
468 dest[224 + pos] = new_v14;
469 dest[240 + pos] = new_v15;
470
471 // V[16] is always 0.0:
472 dest[256 + pos] = 0.0f;
473
474 // insert V[17-31] (== -new_v[15-1]) into actual v:
475 dest[272 + pos] = -new_v15;
476 dest[288 + pos] = -new_v14;
477 dest[304 + pos] = -new_v13;
478 dest[320 + pos] = -new_v12;
479 dest[336 + pos] = -new_v11;
480 dest[352 + pos] = -new_v10;
481 dest[368 + pos] = -new_v9;
482 dest[384 + pos] = -new_v8;
483 dest[400 + pos] = -new_v7;
484 dest[416 + pos] = -new_v6;
485 dest[432 + pos] = -new_v5;
486 dest[448 + pos] = -new_v4;
487 dest[464 + pos] = -new_v3;
488 dest[480 + pos] = -new_v2;
489 dest[496 + pos] = -new_v1;
490
491 // insert V[32] (== -new_v[0]) into other v:
492 dest = (actual_v==v1) ? v2 : v1;
493
494 dest[0 + pos] = -new_v0;
495 // insert V[33-48] (== new_v[16-31]) into other v:
496 dest[16 + pos] = new_v16;
497 dest[32 + pos] = new_v17;
498 dest[48 + pos] = new_v18;
499 dest[64 + pos] = new_v19;
500 dest[80 + pos] = new_v20;
501 dest[96 + pos] = new_v21;
502 dest[112 + pos] = new_v22;
503 dest[128 + pos] = new_v23;
504 dest[144 + pos] = new_v24;
505 dest[160 + pos] = new_v25;
506 dest[176 + pos] = new_v26;
507 dest[192 + pos] = new_v27;
508 dest[208 + pos] = new_v28;
509 dest[224 + pos] = new_v29;
510 dest[240 + pos] = new_v30;
511 dest[256 + pos] = new_v31;
512
513 // insert V[49-63] (== new_v[30-16]) into other v:
514 dest[272 + pos] = new_v30;
515 dest[288 + pos] = new_v29;
516 dest[304 + pos] = new_v28;
517 dest[320 + pos] = new_v27;
518 dest[336 + pos] = new_v26;
519 dest[352 + pos] = new_v25;
520 dest[368 + pos] = new_v24;
521 dest[384 + pos] = new_v23;
522 dest[400 + pos] = new_v22;
523 dest[416 + pos] = new_v21;
524 dest[432 + pos] = new_v20;
525 dest[448 + pos] = new_v19;
526 dest[464 + pos] = new_v18;
527 dest[480 + pos] = new_v17;
528 dest[496 + pos] = new_v16;
529/*
530 }
531 else
532 {
533 v1[0 + actual_write_pos] = -new_v0;
534 // insert V[33-48] (== new_v[16-31]) into other v:
535 v1[16 + actual_write_pos] = new_v16;
536 v1[32 + actual_write_pos] = new_v17;
537 v1[48 + actual_write_pos] = new_v18;
538 v1[64 + actual_write_pos] = new_v19;
539 v1[80 + actual_write_pos] = new_v20;
540 v1[96 + actual_write_pos] = new_v21;
541 v1[112 + actual_write_pos] = new_v22;
542 v1[128 + actual_write_pos] = new_v23;
543 v1[144 + actual_write_pos] = new_v24;
544 v1[160 + actual_write_pos] = new_v25;
545 v1[176 + actual_write_pos] = new_v26;
546 v1[192 + actual_write_pos] = new_v27;
547 v1[208 + actual_write_pos] = new_v28;
548 v1[224 + actual_write_pos] = new_v29;
549 v1[240 + actual_write_pos] = new_v30;
550 v1[256 + actual_write_pos] = new_v31;
551
552 // insert V[49-63] (== new_v[30-16]) into other v:
553 v1[272 + actual_write_pos] = new_v30;
554 v1[288 + actual_write_pos] = new_v29;
555 v1[304 + actual_write_pos] = new_v28;
556 v1[320 + actual_write_pos] = new_v27;
557 v1[336 + actual_write_pos] = new_v26;
558 v1[352 + actual_write_pos] = new_v25;
559 v1[368 + actual_write_pos] = new_v24;
560 v1[384 + actual_write_pos] = new_v23;
561 v1[400 + actual_write_pos] = new_v22;
562 v1[416 + actual_write_pos] = new_v21;
563 v1[432 + actual_write_pos] = new_v20;
564 v1[448 + actual_write_pos] = new_v19;
565 v1[464 + actual_write_pos] = new_v18;
566 v1[480 + actual_write_pos] = new_v17;
567 v1[496 + actual_write_pos] = new_v16;
568 }
569*/
570 }
571
572 /**
573 * Compute new values via a fast cosine transform.
574 */
575 private void compute_new_v_old()
576 {
577 // p is fully initialized from x1
578 //float[] p = _p;
579 // pp is fully initialized from p
580 //float[] pp = _pp;
581
582 //float[] new_v = _new_v;
583
584 float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3
585 float[] p = new float[16];
586 float[] pp = new float[16];
587
588
589 for (int i=31; i>=0; i--)
590 {
591 new_v[i] = 0.0f;
592 }
593
594// float[] new_v = new float[32]; // new V[0-15] and V[33-48] of Figure 3-A.2 in ISO DIS 11172-3
595// float[] p = new float[16];
596// float[] pp = new float[16];
597
598 float[] x1 = samples;
599
600 p[0] = x1[0] + x1[31];
601 p[1] = x1[1] + x1[30];
602 p[2] = x1[2] + x1[29];
603 p[3] = x1[3] + x1[28];
604 p[4] = x1[4] + x1[27];
605 p[5] = x1[5] + x1[26];
606 p[6] = x1[6] + x1[25];
607 p[7] = x1[7] + x1[24];
608 p[8] = x1[8] + x1[23];
609 p[9] = x1[9] + x1[22];
610 p[10] = x1[10] + x1[21];
611 p[11] = x1[11] + x1[20];
612 p[12] = x1[12] + x1[19];
613 p[13] = x1[13] + x1[18];
614 p[14] = x1[14] + x1[17];
615 p[15] = x1[15] + x1[16];
616
617 pp[0] = p[0] + p[15];
618 pp[1] = p[1] + p[14];
619 pp[2] = p[2] + p[13];
620 pp[3] = p[3] + p[12];
621 pp[4] = p[4] + p[11];
622 pp[5] = p[5] + p[10];
623 pp[6] = p[6] + p[9];
624 pp[7] = p[7] + p[8];
625 pp[8] = (p[0] - p[15]) * cos1_32;
626 pp[9] = (p[1] - p[14]) * cos3_32;
627 pp[10] = (p[2] - p[13]) * cos5_32;
628 pp[11] = (p[3] - p[12]) * cos7_32;
629 pp[12] = (p[4] - p[11]) * cos9_32;
630 pp[13] = (p[5] - p[10]) * cos11_32;
631 pp[14] = (p[6] - p[9]) * cos13_32;
632 pp[15] = (p[7] - p[8]) * cos15_32;
633
634 p[0] = pp[0] + pp[7];
635 p[1] = pp[1] + pp[6];
636 p[2] = pp[2] + pp[5];
637 p[3] = pp[3] + pp[4];
638 p[4] = (pp[0] - pp[7]) * cos1_16;
639 p[5] = (pp[1] - pp[6]) * cos3_16;
640 p[6] = (pp[2] - pp[5]) * cos5_16;
641 p[7] = (pp[3] - pp[4]) * cos7_16;
642 p[8] = pp[8] + pp[15];
643 p[9] = pp[9] + pp[14];
644 p[10] = pp[10] + pp[13];
645 p[11] = pp[11] + pp[12];
646 p[12] = (pp[8] - pp[15]) * cos1_16;
647 p[13] = (pp[9] - pp[14]) * cos3_16;
648 p[14] = (pp[10] - pp[13]) * cos5_16;
649 p[15] = (pp[11] - pp[12]) * cos7_16;
650
651
652 pp[0] = p[0] + p[3];
653 pp[1] = p[1] + p[2];
654 pp[2] = (p[0] - p[3]) * cos1_8;
655 pp[3] = (p[1] - p[2]) * cos3_8;
656 pp[4] = p[4] + p[7];
657 pp[5] = p[5] + p[6];
658 pp[6] = (p[4] - p[7]) * cos1_8;
659 pp[7] = (p[5] - p[6]) * cos3_8;
660 pp[8] = p[8] + p[11];
661 pp[9] = p[9] + p[10];
662 pp[10] = (p[8] - p[11]) * cos1_8;
663 pp[11] = (p[9] - p[10]) * cos3_8;
664 pp[12] = p[12] + p[15];
665 pp[13] = p[13] + p[14];
666 pp[14] = (p[12] - p[15]) * cos1_8;
667 pp[15] = (p[13] - p[14]) * cos3_8;
668
669 p[0] = pp[0] + pp[1];
670 p[1] = (pp[0] - pp[1]) * cos1_4;
671 p[2] = pp[2] + pp[3];
672 p[3] = (pp[2] - pp[3]) * cos1_4;
673 p[4] = pp[4] + pp[5];
674 p[5] = (pp[4] - pp[5]) * cos1_4;
675 p[6] = pp[6] + pp[7];
676 p[7] = (pp[6] - pp[7]) * cos1_4;
677 p[8] = pp[8] + pp[9];
678 p[9] = (pp[8] - pp[9]) * cos1_4;
679 p[10] = pp[10] + pp[11];
680 p[11] = (pp[10] - pp[11]) * cos1_4;
681 p[12] = pp[12] + pp[13];
682 p[13] = (pp[12] - pp[13]) * cos1_4;
683 p[14] = pp[14] + pp[15];
684 p[15] = (pp[14] - pp[15]) * cos1_4;
685
686 // this is pretty insane coding
687 float tmp1;
688 new_v[36-17] = -(new_v[4] = (new_v[12] = p[7]) + p[5]) - p[6];
689 new_v[44-17] = -p[6] - p[7] - p[4];
690 new_v[6] = (new_v[10] = (new_v[14] = p[15]) + p[11]) + p[13];
691 new_v[34-17] = -(new_v[2] = p[15] + p[13] + p[9]) - p[14];
692 new_v[38-17] = (tmp1 = -p[14] - p[15] - p[10] - p[11]) - p[13];
693 new_v[46-17] = -p[14] - p[15] - p[12] - p[8];
694 new_v[42-17] = tmp1 - p[12];
695 new_v[48-17] = -p[0];
696 new_v[0] = p[1];
697 new_v[40-17] = -(new_v[8] = p[3]) - p[2];
698
699 p[0] = (x1[0] - x1[31]) * cos1_64;
700 p[1] = (x1[1] - x1[30]) * cos3_64;
701 p[2] = (x1[2] - x1[29]) * cos5_64;
702 p[3] = (x1[3] - x1[28]) * cos7_64;
703 p[4] = (x1[4] - x1[27]) * cos9_64;
704 p[5] = (x1[5] - x1[26]) * cos11_64;
705 p[6] = (x1[6] - x1[25]) * cos13_64;
706 p[7] = (x1[7] - x1[24]) * cos15_64;
707 p[8] = (x1[8] - x1[23]) * cos17_64;
708 p[9] = (x1[9] - x1[22]) * cos19_64;
709 p[10] = (x1[10] - x1[21]) * cos21_64;
710 p[11] = (x1[11] - x1[20]) * cos23_64;
711 p[12] = (x1[12] - x1[19]) * cos25_64;
712 p[13] = (x1[13] - x1[18]) * cos27_64;
713 p[14] = (x1[14] - x1[17]) * cos29_64;
714 p[15] = (x1[15] - x1[16]) * cos31_64;
715
716
717 pp[0] = p[0] + p[15];
718 pp[1] = p[1] + p[14];
719 pp[2] = p[2] + p[13];
720 pp[3] = p[3] + p[12];
721 pp[4] = p[4] + p[11];
722 pp[5] = p[5] + p[10];
723 pp[6] = p[6] + p[9];
724 pp[7] = p[7] + p[8];
725 pp[8] = (p[0] - p[15]) * cos1_32;
726 pp[9] = (p[1] - p[14]) * cos3_32;
727 pp[10] = (p[2] - p[13]) * cos5_32;
728 pp[11] = (p[3] - p[12]) * cos7_32;
729 pp[12] = (p[4] - p[11]) * cos9_32;
730 pp[13] = (p[5] - p[10]) * cos11_32;
731 pp[14] = (p[6] - p[9]) * cos13_32;
732 pp[15] = (p[7] - p[8]) * cos15_32;
733
734
735 p[0] = pp[0] + pp[7];
736 p[1] = pp[1] + pp[6];
737 p[2] = pp[2] + pp[5];
738 p[3] = pp[3] + pp[4];
739 p[4] = (pp[0] - pp[7]) * cos1_16;
740 p[5] = (pp[1] - pp[6]) * cos3_16;
741 p[6] = (pp[2] - pp[5]) * cos5_16;
742 p[7] = (pp[3] - pp[4]) * cos7_16;
743 p[8] = pp[8] + pp[15];
744 p[9] = pp[9] + pp[14];
745 p[10] = pp[10] + pp[13];
746 p[11] = pp[11] + pp[12];
747 p[12] = (pp[8] - pp[15]) * cos1_16;
748 p[13] = (pp[9] - pp[14]) * cos3_16;
749 p[14] = (pp[10] - pp[13]) * cos5_16;
750 p[15] = (pp[11] - pp[12]) * cos7_16;
751
752
753 pp[0] = p[0] + p[3];
754 pp[1] = p[1] + p[2];
755 pp[2] = (p[0] - p[3]) * cos1_8;
756 pp[3] = (p[1] - p[2]) * cos3_8;
757 pp[4] = p[4] + p[7];
758 pp[5] = p[5] + p[6];
759 pp[6] = (p[4] - p[7]) * cos1_8;
760 pp[7] = (p[5] - p[6]) * cos3_8;
761 pp[8] = p[8] + p[11];
762 pp[9] = p[9] + p[10];
763 pp[10] = (p[8] - p[11]) * cos1_8;
764 pp[11] = (p[9] - p[10]) * cos3_8;
765 pp[12] = p[12] + p[15];
766 pp[13] = p[13] + p[14];
767 pp[14] = (p[12] - p[15]) * cos1_8;
768 pp[15] = (p[13] - p[14]) * cos3_8;
769
770
771 p[0] = pp[0] + pp[1];
772 p[1] = (pp[0] - pp[1]) * cos1_4;
773 p[2] = pp[2] + pp[3];
774 p[3] = (pp[2] - pp[3]) * cos1_4;
775 p[4] = pp[4] + pp[5];
776 p[5] = (pp[4] - pp[5]) * cos1_4;
777 p[6] = pp[6] + pp[7];
778 p[7] = (pp[6] - pp[7]) * cos1_4;
779 p[8] = pp[8] + pp[9];
780 p[9] = (pp[8] - pp[9]) * cos1_4;
781 p[10] = pp[10] + pp[11];
782 p[11] = (pp[10] - pp[11]) * cos1_4;
783 p[12] = pp[12] + pp[13];
784 p[13] = (pp[12] - pp[13]) * cos1_4;
785 p[14] = pp[14] + pp[15];
786 p[15] = (pp[14] - pp[15]) * cos1_4;
787
788
789 // manually doing something that a compiler should handle sucks
790 // coding like this is hard to read
791 float tmp2;
792 new_v[5] = (new_v[11] = (new_v[13] = (new_v[15] = p[15]) + p[7]) + p[11])
793 + p[5] + p[13];
794 new_v[7] = (new_v[9] = p[15] + p[11] + p[3]) + p[13];
795 new_v[33-17] = -(new_v[1] = (tmp1 = p[13] + p[15] + p[9]) + p[1]) - p[14];
796 new_v[35-17] = -(new_v[3] = tmp1 + p[5] + p[7]) - p[6] - p[14];
797
798 new_v[39-17] = (tmp1 = -p[10] - p[11] - p[14] - p[15])
799 - p[13] - p[2] - p[3];
800 new_v[37-17] = tmp1 - p[13] - p[5] - p[6] - p[7];
801 new_v[41-17] = tmp1 - p[12] - p[2] - p[3];
802 new_v[43-17] = tmp1 - p[12] - (tmp2 = p[4] + p[6] + p[7]);
803 new_v[47-17] = (tmp1 = -p[8] - p[12] - p[14] - p[15]) - p[0];
804 new_v[45-17] = tmp1 - tmp2;
805
806 // insert V[0-15] (== new_v[0-15]) into actual v:
807 x1 = new_v;
808 // float[] x2 = actual_v + actual_write_pos;
809 float[] dest = actual_v;
810
811 dest[0 + actual_write_pos] = x1[0];
812 dest[16 + actual_write_pos] = x1[1];
813 dest[32 + actual_write_pos] = x1[2];
814 dest[48 + actual_write_pos] = x1[3];
815 dest[64 + actual_write_pos] = x1[4];
816 dest[80 + actual_write_pos] = x1[5];
817 dest[96 + actual_write_pos] = x1[6];
818 dest[112 + actual_write_pos] = x1[7];
819 dest[128 + actual_write_pos] = x1[8];
820 dest[144 + actual_write_pos] = x1[9];
821 dest[160 + actual_write_pos] = x1[10];
822 dest[176 + actual_write_pos] = x1[11];
823 dest[192 + actual_write_pos] = x1[12];
824 dest[208 + actual_write_pos] = x1[13];
825 dest[224 + actual_write_pos] = x1[14];
826 dest[240 + actual_write_pos] = x1[15];
827
828 // V[16] is always 0.0:
829 dest[256 + actual_write_pos] = 0.0f;
830
831 // insert V[17-31] (== -new_v[15-1]) into actual v:
832 dest[272 + actual_write_pos] = -x1[15];
833 dest[288 + actual_write_pos] = -x1[14];
834 dest[304 + actual_write_pos] = -x1[13];
835 dest[320 + actual_write_pos] = -x1[12];
836 dest[336 + actual_write_pos] = -x1[11];
837 dest[352 + actual_write_pos] = -x1[10];
838 dest[368 + actual_write_pos] = -x1[9];
839 dest[384 + actual_write_pos] = -x1[8];
840 dest[400 + actual_write_pos] = -x1[7];
841 dest[416 + actual_write_pos] = -x1[6];
842 dest[432 + actual_write_pos] = -x1[5];
843 dest[448 + actual_write_pos] = -x1[4];
844 dest[464 + actual_write_pos] = -x1[3];
845 dest[480 + actual_write_pos] = -x1[2];
846 dest[496 + actual_write_pos] = -x1[1];
847
848 // insert V[32] (== -new_v[0]) into other v:
849
850 }
851
852 /**
853 * Compute PCM Samples.
854 */
855
856 private float[] _tmpOut = new float[32];
857
858
859 private void compute_pcm_samples0(Obuffer buffer)
860 {
861 final float[] vp = actual_v;
862 //int inc = v_inc;
863 final float[] tmpOut = _tmpOut;
864 int dvp =0;
865
866 // fat chance of having this loop unroll
867 for( int i=0; i<32; i++)
868 {
869 float pcm_sample;
870 final float[] dp = d16[i];
871 pcm_sample = (float)(((vp[0 + dvp] * dp[0]) +
872 (vp[15 + dvp] * dp[1]) +
873 (vp[14 + dvp] * dp[2]) +
874 (vp[13 + dvp] * dp[3]) +
875 (vp[12 + dvp] * dp[4]) +
876 (vp[11 + dvp] * dp[5]) +
877 (vp[10 + dvp] * dp[6]) +
878 (vp[9 + dvp] * dp[7]) +
879 (vp[8 + dvp] * dp[8]) +
880 (vp[7 + dvp] * dp[9]) +
881 (vp[6 + dvp] * dp[10]) +
882 (vp[5 + dvp] * dp[11]) +
883 (vp[4 + dvp] * dp[12]) +
884 (vp[3 + dvp] * dp[13]) +
885 (vp[2 + dvp] * dp[14]) +
886 (vp[1 + dvp] * dp[15])
887 ) * scalefactor);
888
889 tmpOut[i] = pcm_sample;
890
891 dvp += 16;
892 } // for
893 }
894
895 private void compute_pcm_samples1(Obuffer buffer)
896 {
897 final float[] vp = actual_v;
898 //int inc = v_inc;
899 final float[] tmpOut = _tmpOut;
900 int dvp =0;
901
902 // fat chance of having this loop unroll
903 for( int i=0; i<32; i++)
904 {
905 final float[] dp = d16[i];
906 float pcm_sample;
907
908 pcm_sample = (float)(((vp[1 + dvp] * dp[0]) +
909 (vp[0 + dvp] * dp[1]) +
910 (vp[15 + dvp] * dp[2]) +
911 (vp[14 + dvp] * dp[3]) +
912 (vp[13 + dvp] * dp[4]) +
913 (vp[12 + dvp] * dp[5]) +
914 (vp[11 + dvp] * dp[6]) +
915 (vp[10 + dvp] * dp[7]) +
916 (vp[9 + dvp] * dp[8]) +
917 (vp[8 + dvp] * dp[9]) +
918 (vp[7 + dvp] * dp[10]) +
919 (vp[6 + dvp] * dp[11]) +
920 (vp[5 + dvp] * dp[12]) +
921 (vp[4 + dvp] * dp[13]) +
922 (vp[3 + dvp] * dp[14]) +
923 (vp[2 + dvp] * dp[15])
924 ) * scalefactor);
925
926 tmpOut[i] = pcm_sample;
927
928 dvp += 16;
929 } // for
930 }
931 private void compute_pcm_samples2(Obuffer buffer)
932 {
933 final float[] vp = actual_v;
934
935 //int inc = v_inc;
936 final float[] tmpOut = _tmpOut;
937 int dvp =0;
938
939 // fat chance of having this loop unroll
940 for( int i=0; i<32; i++)
941 {
942 final float[] dp = d16[i];
943 float pcm_sample;
944
945 pcm_sample = (float)(((vp[2 + dvp] * dp[0]) +
946 (vp[1 + dvp] * dp[1]) +
947 (vp[0 + dvp] * dp[2]) +
948 (vp[15 + dvp] * dp[3]) +
949 (vp[14 + dvp] * dp[4]) +
950 (vp[13 + dvp] * dp[5]) +
951 (vp[12 + dvp] * dp[6]) +
952 (vp[11 + dvp] * dp[7]) +
953 (vp[10 + dvp] * dp[8]) +
954 (vp[9 + dvp] * dp[9]) +
955 (vp[8 + dvp] * dp[10]) +
956 (vp[7 + dvp] * dp[11]) +
957 (vp[6 + dvp] * dp[12]) +
958 (vp[5 + dvp] * dp[13]) +
959 (vp[4 + dvp] * dp[14]) +
960 (vp[3 + dvp] * dp[15])
961 ) * scalefactor);
962
963 tmpOut[i] = pcm_sample;
964
965 dvp += 16;
966 } // for
967 }
968
969 private void compute_pcm_samples3(Obuffer buffer)
970 {
971 final float[] vp = actual_v;
972
973 int idx = 0;
974 //int inc = v_inc;
975 final float[] tmpOut = _tmpOut;
976 int dvp =0;
977
978 // fat chance of having this loop unroll
979 for( int i=0; i<32; i++)
980 {
981 final float[] dp = d16[i];
982 float pcm_sample;
983
984 pcm_sample = (float)(((vp[3 + dvp] * dp[0]) +
985 (vp[2 + dvp] * dp[1]) +
986 (vp[1 + dvp] * dp[2]) +
987 (vp[0 + dvp] * dp[3]) +
988 (vp[15 + dvp] * dp[4]) +
989 (vp[14 + dvp] * dp[5]) +
990 (vp[13 + dvp] * dp[6]) +
991 (vp[12 + dvp] * dp[7]) +
992 (vp[11 + dvp] * dp[8]) +
993 (vp[10 + dvp] * dp[9]) +
994 (vp[9 + dvp] * dp[10]) +
995 (vp[8 + dvp] * dp[11]) +
996 (vp[7 + dvp] * dp[12]) +
997 (vp[6 + dvp] * dp[13]) +
998 (vp[5 + dvp] * dp[14]) +
999 (vp[4 + dvp] * dp[15])
1000 ) * scalefactor);
1001
1002 tmpOut[i] = pcm_sample;
1003
1004 dvp += 16;
1005 } // for
1006 }
1007
1008 private void compute_pcm_samples4(Obuffer buffer)
1009 {
1010 final float[] vp = actual_v;
1011
1012 //int inc = v_inc;
1013 final float[] tmpOut = _tmpOut;
1014 int dvp =0;
1015
1016 // fat chance of having this loop unroll
1017 for( int i=0; i<32; i++)
1018 {
1019 final float[] dp = d16[i];
1020 float pcm_sample;
1021
1022 pcm_sample = (float)(((vp[4 + dvp] * dp[0]) +
1023 (vp[3 + dvp] * dp[1]) +
1024 (vp[2 + dvp] * dp[2]) +
1025 (vp[1 + dvp] * dp[3]) +
1026 (vp[0 + dvp] * dp[4]) +
1027 (vp[15 + dvp] * dp[5]) +
1028 (vp[14 + dvp] * dp[6]) +
1029 (vp[13 + dvp] * dp[7]) +
1030 (vp[12 + dvp] * dp[8]) +
1031 (vp[11 + dvp] * dp[9]) +
1032 (vp[10 + dvp] * dp[10]) +
1033 (vp[9 + dvp] * dp[11]) +
1034 (vp[8 + dvp] * dp[12]) +
1035 (vp[7 + dvp] * dp[13]) +
1036 (vp[6 + dvp] * dp[14]) +
1037 (vp[5 + dvp] * dp[15])
1038 ) * scalefactor);
1039
1040 tmpOut[i] = pcm_sample;
1041
1042 dvp += 16;
1043 } // for
1044 }
1045
1046 private void compute_pcm_samples5(Obuffer buffer)
1047 {
1048 final float[] vp = actual_v;
1049
1050 //int inc = v_inc;
1051 final float[] tmpOut = _tmpOut;
1052 int dvp =0;
1053
1054 // fat chance of having this loop unroll
1055 for( int i=0; i<32; i++)
1056 {
1057 final float[] dp = d16[i];
1058 float pcm_sample;
1059
1060 pcm_sample = (float)(((vp[5 + dvp] * dp[0]) +
1061 (vp[4 + dvp] * dp[1]) +
1062 (vp[3 + dvp] * dp[2]) +
1063 (vp[2 + dvp] * dp[3]) +
1064 (vp[1 + dvp] * dp[4]) +
1065 (vp[0 + dvp] * dp[5]) +
1066 (vp[15 + dvp] * dp[6]) +
1067 (vp[14 + dvp] * dp[7]) +
1068 (vp[13 + dvp] * dp[8]) +
1069 (vp[12 + dvp] * dp[9]) +
1070 (vp[11 + dvp] * dp[10]) +
1071 (vp[10 + dvp] * dp[11]) +
1072 (vp[9 + dvp] * dp[12]) +
1073 (vp[8 + dvp] * dp[13]) +
1074 (vp[7 + dvp] * dp[14]) +
1075 (vp[6 + dvp] * dp[15])
1076 ) * scalefactor);
1077
1078 tmpOut[i] = pcm_sample;
1079
1080 dvp += 16;
1081 } // for
1082 }
1083
1084 private void compute_pcm_samples6(Obuffer buffer)
1085 {
1086 final float[] vp = actual_v;
1087 //int inc = v_inc;
1088 final float[] tmpOut = _tmpOut;
1089 int dvp =0;
1090
1091 // fat chance of having this loop unroll
1092 for( int i=0; i<32; i++)
1093 {
1094 final float[] dp = d16[i];
1095 float pcm_sample;
1096
1097 pcm_sample = (float)(((vp[6 + dvp] * dp[0]) +
1098 (vp[5 + dvp] * dp[1]) +
1099 (vp[4 + dvp] * dp[2]) +
1100 (vp[3 + dvp] * dp[3]) +
1101 (vp[2 + dvp] * dp[4]) +
1102 (vp[1 + dvp] * dp[5]) +
1103 (vp[0 + dvp] * dp[6]) +
1104 (vp[15 + dvp] * dp[7]) +
1105 (vp[14 + dvp] * dp[8]) +
1106 (vp[13 + dvp] * dp[9]) +
1107 (vp[12 + dvp] * dp[10]) +
1108 (vp[11 + dvp] * dp[11]) +
1109 (vp[10 + dvp] * dp[12]) +
1110 (vp[9 + dvp] * dp[13]) +
1111 (vp[8 + dvp] * dp[14]) +
1112 (vp[7 + dvp] * dp[15])
1113 ) * scalefactor);
1114
1115 tmpOut[i] = pcm_sample;
1116
1117 dvp += 16;
1118 } // for
1119 }
1120
1121 private void compute_pcm_samples7(Obuffer buffer)
1122 {
1123 final float[] vp = actual_v;
1124
1125 //int inc = v_inc;
1126 final float[] tmpOut = _tmpOut;
1127 int dvp =0;
1128
1129 // fat chance of having this loop unroll
1130 for( int i=0; i<32; i++)
1131 {
1132 final float[] dp = d16[i];
1133 float pcm_sample;
1134
1135 pcm_sample = (float)(((vp[7 + dvp] * dp[0]) +
1136 (vp[6 + dvp] * dp[1]) +
1137 (vp[5 + dvp] * dp[2]) +
1138 (vp[4 + dvp] * dp[3]) +
1139 (vp[3 + dvp] * dp[4]) +
1140 (vp[2 + dvp] * dp[5]) +
1141 (vp[1 + dvp] * dp[6]) +
1142 (vp[0 + dvp] * dp[7]) +
1143 (vp[15 + dvp] * dp[8]) +
1144 (vp[14 + dvp] * dp[9]) +
1145 (vp[13 + dvp] * dp[10]) +
1146 (vp[12 + dvp] * dp[11]) +
1147 (vp[11 + dvp] * dp[12]) +
1148 (vp[10 + dvp] * dp[13]) +
1149 (vp[9 + dvp] * dp[14]) +
1150 (vp[8 + dvp] * dp[15])
1151 ) * scalefactor);
1152
1153 tmpOut[i] = pcm_sample;
1154
1155 dvp += 16;
1156 } // for
1157 }
1158 private void compute_pcm_samples8(Obuffer buffer)
1159 {
1160 final float[] vp = actual_v;
1161
1162 //int inc = v_inc;
1163 final float[] tmpOut = _tmpOut;
1164 int dvp =0;
1165
1166 // fat chance of having this loop unroll
1167 for( int i=0; i<32; i++)
1168 {
1169 final float[] dp = d16[i];
1170 float pcm_sample;
1171
1172 pcm_sample = (float)(((vp[8 + dvp] * dp[0]) +
1173 (vp[7 + dvp] * dp[1]) +
1174 (vp[6 + dvp] * dp[2]) +
1175 (vp[5 + dvp] * dp[3]) +
1176 (vp[4 + dvp] * dp[4]) +
1177 (vp[3 + dvp] * dp[5]) +
1178 (vp[2 + dvp] * dp[6]) +
1179 (vp[1 + dvp] * dp[7]) +
1180 (vp[0 + dvp] * dp[8]) +
1181 (vp[15 + dvp] * dp[9]) +
1182 (vp[14 + dvp] * dp[10]) +
1183 (vp[13 + dvp] * dp[11]) +
1184 (vp[12 + dvp] * dp[12]) +
1185 (vp[11 + dvp] * dp[13]) +
1186 (vp[10 + dvp] * dp[14]) +
1187 (vp[9 + dvp] * dp[15])
1188 ) * scalefactor);
1189
1190 tmpOut[i] = pcm_sample;
1191
1192 dvp += 16;
1193 } // for
1194 }
1195
1196 private void compute_pcm_samples9(Obuffer buffer)
1197 {
1198 final float[] vp = actual_v;
1199
1200 //int inc = v_inc;
1201 final float[] tmpOut = _tmpOut;
1202 int dvp =0;
1203
1204 // fat chance of having this loop unroll
1205 for( int i=0; i<32; i++)
1206 {
1207 final float[] dp = d16[i];
1208 float pcm_sample;
1209
1210 pcm_sample = (float)(((vp[9 + dvp] * dp[0]) +
1211 (vp[8 + dvp] * dp[1]) +
1212 (vp[7 + dvp] * dp[2]) +
1213 (vp[6 + dvp] * dp[3]) +
1214 (vp[5 + dvp] * dp[4]) +
1215 (vp[4 + dvp] * dp[5]) +
1216 (vp[3 + dvp] * dp[6]) +
1217 (vp[2 + dvp] * dp[7]) +
1218 (vp[1 + dvp] * dp[8]) +
1219 (vp[0 + dvp] * dp[9]) +
1220 (vp[15 + dvp] * dp[10]) +
1221 (vp[14 + dvp] * dp[11]) +
1222 (vp[13 + dvp] * dp[12]) +
1223 (vp[12 + dvp] * dp[13]) +
1224 (vp[11 + dvp] * dp[14]) +
1225 (vp[10 + dvp] * dp[15])
1226 ) * scalefactor);
1227
1228 tmpOut[i] = pcm_sample;
1229
1230 dvp += 16;
1231 } // for
1232 }
1233
1234 private void compute_pcm_samples10(Obuffer buffer)
1235 {
1236 final float[] vp = actual_v;
1237 //int inc = v_inc;
1238 final float[] tmpOut = _tmpOut;
1239 int dvp =0;
1240
1241 // fat chance of having this loop unroll
1242 for( int i=0; i<32; i++)
1243 {
1244 final float[] dp = d16[i];
1245 float pcm_sample;
1246
1247 pcm_sample = (float)(((vp[10 + dvp] * dp[0]) +
1248 (vp[9 + dvp] * dp[1]) +
1249 (vp[8 + dvp] * dp[2]) +
1250 (vp[7 + dvp] * dp[3]) +
1251 (vp[6 + dvp] * dp[4]) +
1252 (vp[5 + dvp] * dp[5]) +
1253 (vp[4 + dvp] * dp[6]) +
1254 (vp[3 + dvp] * dp[7]) +
1255 (vp[2 + dvp] * dp[8]) +
1256 (vp[1 + dvp] * dp[9]) +
1257 (vp[0 + dvp] * dp[10]) +
1258 (vp[15 + dvp] * dp[11]) +
1259 (vp[14 + dvp] * dp[12]) +
1260 (vp[13 + dvp] * dp[13]) +
1261 (vp[12 + dvp] * dp[14]) +
1262 (vp[11 + dvp] * dp[15])
1263 ) * scalefactor);
1264
1265 tmpOut[i] = pcm_sample;
1266
1267 dvp += 16;
1268 } // for
1269 }
1270 private void compute_pcm_samples11(Obuffer buffer)
1271 {
1272 final float[] vp = actual_v;
1273
1274 //int inc = v_inc;
1275 final float[] tmpOut = _tmpOut;
1276 int dvp =0;
1277
1278 // fat chance of having this loop unroll
1279 for( int i=0; i<32; i++)
1280 {
1281 final float[] dp = d16[i];
1282 float pcm_sample;
1283
1284 pcm_sample = (float)(((vp[11 + dvp] * dp[0]) +
1285 (vp[10 + dvp] * dp[1]) +
1286 (vp[9 + dvp] * dp[2]) +
1287 (vp[8 + dvp] * dp[3]) +
1288 (vp[7 + dvp] * dp[4]) +
1289 (vp[6 + dvp] * dp[5]) +
1290 (vp[5 + dvp] * dp[6]) +
1291 (vp[4 + dvp] * dp[7]) +
1292 (vp[3 + dvp] * dp[8]) +
1293 (vp[2 + dvp] * dp[9]) +
1294 (vp[1 + dvp] * dp[10]) +
1295 (vp[0 + dvp] * dp[11]) +
1296 (vp[15 + dvp] * dp[12]) +
1297 (vp[14 + dvp] * dp[13]) +
1298 (vp[13 + dvp] * dp[14]) +
1299 (vp[12 + dvp] * dp[15])
1300 ) * scalefactor);
1301
1302 tmpOut[i] = pcm_sample;
1303
1304 dvp += 16;
1305 } // for
1306 }
1307 private void compute_pcm_samples12(Obuffer buffer)
1308 {
1309 final float[] vp = actual_v;
1310 //int inc = v_inc;
1311 final float[] tmpOut = _tmpOut;
1312 int dvp =0;
1313
1314 // fat chance of having this loop unroll
1315 for( int i=0; i<32; i++)
1316 {
1317 final float[] dp = d16[i];
1318 float pcm_sample;
1319
1320 pcm_sample = (float)(((vp[12 + dvp] * dp[0]) +
1321 (vp[11 + dvp] * dp[1]) +
1322 (vp[10 + dvp] * dp[2]) +
1323 (vp[9 + dvp] * dp[3]) +
1324 (vp[8 + dvp] * dp[4]) +
1325 (vp[7 + dvp] * dp[5]) +
1326 (vp[6 + dvp] * dp[6]) +
1327 (vp[5 + dvp] * dp[7]) +
1328 (vp[4 + dvp] * dp[8]) +
1329 (vp[3 + dvp] * dp[9]) +
1330 (vp[2 + dvp] * dp[10]) +
1331 (vp[1 + dvp] * dp[11]) +
1332 (vp[0 + dvp] * dp[12]) +
1333 (vp[15 + dvp] * dp[13]) +
1334 (vp[14 + dvp] * dp[14]) +
1335 (vp[13 + dvp] * dp[15])
1336 ) * scalefactor);
1337
1338 tmpOut[i] = pcm_sample;
1339
1340 dvp += 16;
1341 } // for
1342 }
1343 private void compute_pcm_samples13(Obuffer buffer)
1344 {
1345 final float[] vp = actual_v;
1346
1347 //int inc = v_inc;
1348 final float[] tmpOut = _tmpOut;
1349 int dvp =0;
1350
1351 // fat chance of having this loop unroll
1352 for( int i=0; i<32; i++)
1353 {
1354 final float[] dp = d16[i];
1355 float pcm_sample;
1356
1357 pcm_sample = (float)(((vp[13 + dvp] * dp[0]) +
1358 (vp[12 + dvp] * dp[1]) +
1359 (vp[11 + dvp] * dp[2]) +
1360 (vp[10 + dvp] * dp[3]) +
1361 (vp[9 + dvp] * dp[4]) +
1362 (vp[8 + dvp] * dp[5]) +
1363 (vp[7 + dvp] * dp[6]) +
1364 (vp[6 + dvp] * dp[7]) +
1365 (vp[5 + dvp] * dp[8]) +
1366 (vp[4 + dvp] * dp[9]) +
1367 (vp[3 + dvp] * dp[10]) +
1368 (vp[2 + dvp] * dp[11]) +
1369 (vp[1 + dvp] * dp[12]) +
1370 (vp[0 + dvp] * dp[13]) +
1371 (vp[15 + dvp] * dp[14]) +
1372 (vp[14 + dvp] * dp[15])
1373 ) * scalefactor);
1374
1375 tmpOut[i] = pcm_sample;
1376
1377 dvp += 16;
1378 } // for
1379 }
1380 private void compute_pcm_samples14(Obuffer buffer)
1381 {
1382 final float[] vp = actual_v;
1383
1384 //int inc = v_inc;
1385 final float[] tmpOut = _tmpOut;
1386 int dvp =0;
1387
1388 // fat chance of having this loop unroll
1389 for( int i=0; i<32; i++)
1390 {
1391 final float[] dp = d16[i];
1392 float pcm_sample;
1393
1394 pcm_sample = (float)(((vp[14 + dvp] * dp[0]) +
1395 (vp[13 + dvp] * dp[1]) +
1396 (vp[12 + dvp] * dp[2]) +
1397 (vp[11 + dvp] * dp[3]) +
1398 (vp[10 + dvp] * dp[4]) +
1399 (vp[9 + dvp] * dp[5]) +
1400 (vp[8 + dvp] * dp[6]) +
1401 (vp[7 + dvp] * dp[7]) +
1402 (vp[6 + dvp] * dp[8]) +
1403 (vp[5 + dvp] * dp[9]) +
1404 (vp[4 + dvp] * dp[10]) +
1405 (vp[3 + dvp] * dp[11]) +
1406 (vp[2 + dvp] * dp[12]) +
1407 (vp[1 + dvp] * dp[13]) +
1408 (vp[0 + dvp] * dp[14]) +
1409 (vp[15 + dvp] * dp[15])
1410 ) * scalefactor);
1411
1412 tmpOut[i] = pcm_sample;
1413
1414 dvp += 16;
1415 } // for
1416 }
1417 private void compute_pcm_samples15(Obuffer buffer)
1418 {
1419 final float[] vp = actual_v;
1420
1421 //int inc = v_inc;
1422 final float[] tmpOut = _tmpOut;
1423 int dvp =0;
1424
1425 // fat chance of having this loop unroll
1426 for( int i=0; i<32; i++)
1427 {
1428 float pcm_sample;
1429 final float dp[] = d16[i];
1430 pcm_sample = (float)(((vp[15 + dvp] * dp[0]) +
1431 (vp[14 + dvp] * dp[1]) +
1432 (vp[13 + dvp] * dp[2]) +
1433 (vp[12 + dvp] * dp[3]) +
1434 (vp[11 + dvp] * dp[4]) +
1435 (vp[10 + dvp] * dp[5]) +
1436 (vp[9 + dvp] * dp[6]) +
1437 (vp[8 + dvp] * dp[7]) +
1438 (vp[7 + dvp] * dp[8]) +
1439 (vp[6 + dvp] * dp[9]) +
1440 (vp[5 + dvp] * dp[10]) +
1441 (vp[4 + dvp] * dp[11]) +
1442 (vp[3 + dvp] * dp[12]) +
1443 (vp[2 + dvp] * dp[13]) +
1444 (vp[1 + dvp] * dp[14]) +
1445 (vp[0 + dvp] * dp[15])
1446 ) * scalefactor);
1447
1448 tmpOut[i] = pcm_sample;
1449 dvp += 16;
1450 } // for
1451 }
1452
1453private void compute_pcm_samples(Obuffer buffer)
1454{
1455
1456 switch (actual_write_pos)
1457 {
1458 case 0:
1459 compute_pcm_samples0(buffer);
1460 break;
1461 case 1:
1462 compute_pcm_samples1(buffer);
1463 break;
1464 case 2:
1465 compute_pcm_samples2(buffer);
1466 break;
1467 case 3:
1468 compute_pcm_samples3(buffer);
1469 break;
1470 case 4:
1471 compute_pcm_samples4(buffer);
1472 break;
1473 case 5:
1474 compute_pcm_samples5(buffer);
1475 break;
1476 case 6:
1477 compute_pcm_samples6(buffer);
1478 break;
1479 case 7:
1480 compute_pcm_samples7(buffer);
1481 break;
1482 case 8:
1483 compute_pcm_samples8(buffer);
1484 break;
1485 case 9:
1486 compute_pcm_samples9(buffer);
1487 break;
1488 case 10:
1489 compute_pcm_samples10(buffer);
1490 break;
1491 case 11:
1492 compute_pcm_samples11(buffer);
1493 break;
1494 case 12:
1495 compute_pcm_samples12(buffer);
1496 break;
1497 case 13:
1498 compute_pcm_samples13(buffer);
1499 break;
1500 case 14:
1501 compute_pcm_samples14(buffer);
1502 break;
1503 case 15:
1504 compute_pcm_samples15(buffer);
1505 break;
1506 }
1507
1508 if (buffer!=null)
1509 {
1510 buffer.appendSamples(channel, _tmpOut);
1511 }
1512
1513/*
1514 // MDM: I was considering putting in quality control for
1515 // low-spec CPUs, but the performance gain (about 10-15%)
1516 // did not justify the considerable drop in audio quality.
1517 switch (inc)
1518 {
1519 case 16:
1520 buffer.appendSamples(channel, tmpOut);
1521 break;
1522 case 32:
1523 for (int i=0; i<16; i++)
1524 {
1525 buffer.append(channel, (short)tmpOut[i]);
1526 buffer.append(channel, (short)tmpOut[i]);
1527 }
1528 break;
1529 case 64:
1530 for (int i=0; i<8; i++)
1531 {
1532 buffer.append(channel, (short)tmpOut[i]);
1533 buffer.append(channel, (short)tmpOut[i]);
1534 buffer.append(channel, (short)tmpOut[i]);
1535 buffer.append(channel, (short)tmpOut[i]);
1536 }
1537 break;
1538
1539 }
1540*/
1541 }
1542
1543 /**
1544 * Calculate 32 PCM samples and put the into the Obuffer-object.
1545 */
1546
1547 public void calculate_pcm_samples(Obuffer buffer)
1548 {
1549 compute_new_v();
1550 compute_pcm_samples(buffer);
1551
1552 actual_write_pos = (actual_write_pos + 1) & 0xf;
1553 actual_v = (actual_v == v1) ? v2 : v1;
1554
1555 // initialize samples[]:
1556 //for (register float *floatp = samples + 32; floatp > samples; )
1557 // *--floatp = 0.0f;
1558
1559 // MDM: this may not be necessary. The Layer III decoder always
1560 // outputs 32 subband samples, but I haven't checked layer I & II.
1561 for (int p=0;p<32;p++)
1562 samples[p] = 0.0f;
1563 }
1564
1565
1566 private static final double MY_PI = 3.14159265358979323846;
1567 private static final float cos1_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 64.0)));
1568 private static final float cos3_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 64.0)));
1569 private static final float cos5_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 5.0 / 64.0)));
1570 private static final float cos7_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 7.0 / 64.0)));
1571 private static final float cos9_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 9.0 / 64.0)));
1572 private static final float cos11_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 11.0 / 64.0)));
1573 private static final float cos13_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 13.0 / 64.0)));
1574 private static final float cos15_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 15.0 / 64.0)));
1575 private static final float cos17_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 17.0 / 64.0)));
1576 private static final float cos19_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 19.0 / 64.0)));
1577 private static final float cos21_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 21.0 / 64.0)));
1578 private static final float cos23_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 23.0 / 64.0)));
1579 private static final float cos25_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 25.0 / 64.0)));
1580 private static final float cos27_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 27.0 / 64.0)));
1581 private static final float cos29_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 29.0 / 64.0)));
1582 private static final float cos31_64 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 31.0 / 64.0)));
1583 private static final float cos1_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 32.0)));
1584 private static final float cos3_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 32.0)));
1585 private static final float cos5_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 5.0 / 32.0)));
1586 private static final float cos7_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 7.0 / 32.0)));
1587 private static final float cos9_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 9.0 / 32.0)));
1588 private static final float cos11_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 11.0 / 32.0)));
1589 private static final float cos13_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 13.0 / 32.0)));
1590 private static final float cos15_32 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 15.0 / 32.0)));
1591 private static final float cos1_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 16.0)));
1592 private static final float cos3_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 16.0)));
1593 private static final float cos5_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 5.0 / 16.0)));
1594 private static final float cos7_16 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 7.0 / 16.0)));
1595 private static final float cos1_8 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 8.0)));
1596 private static final float cos3_8 =(float) (1.0 / (2.0 * Math.cos(MY_PI * 3.0 / 8.0)));
1597 private static final float cos1_4 =(float) (1.0 / (2.0 * Math.cos(MY_PI / 4.0)));
1598
1599 // Note: These values are not in the same order
1600 // as in Annex 3-B.3 of the ISO/IEC DIS 11172-3
1601 // private float d[] = {0.000000000, -4.000442505};
1602
1603 private static float d[] = null;
1604
1605 /**
1606 * d[] split into subarrays of length 16. This provides for
1607 * more faster access by allowing a block of 16 to be addressed
1608 * with constant offset.
1609 **/
1610 private static float d16[][] = null;
1611
1612 /**
1613 * Loads the data for the d[] from the resource SFd.ser.
1614 * @return the loaded values for d[].
1615 */
1616 static private float[] load_d()
1617 {
1618 try
1619 {
1620 Class elemType = Float.TYPE;
1621 Object o = JavaLayerUtils.deserializeArrayResource("sfd.ser", elemType, 512);
1622 return (float[])o;
1623 }
1624 catch (IOException ex)
1625 {
1626 throw new ExceptionInInitializerError(ex);
1627 }
1628 }
1629
1630 /**
1631 * Converts a 1D array into a number of smaller arrays. This is used
1632 * to achieve offset + constant indexing into an array. Each sub-array
1633 * represents a block of values of the original array.
1634 * @param array The array to split up into blocks.
1635 * @param blockSize The size of the blocks to split the array
1636 * into. This must be an exact divisor of
1637 * the length of the array, or some data
1638 * will be lost from the main array.
1639 *
1640 * @return An array of arrays in which each element in the returned
1641 * array will be of length <code>blockSize</code>.
1642 */
1643 static private float[][] splitArray(final float[] array, final int blockSize)
1644 {
1645 int size = array.length / blockSize;
1646 float[][] split = new float[size][];
1647 for (int i=0; i<size; i++)
1648 {
1649 split[i] = subArray(array, i*blockSize, blockSize);
1650 }
1651 return split;
1652 }
1653
1654 /**
1655 * Returns a subarray of an existing array.
1656 *
1657 * @param array The array to retrieve a subarra from.
1658 * @param offs The offset in the array that corresponds to
1659 * the first index of the subarray.
1660 * @param len The number of indeces in the subarray.
1661 * @return The subarray, which may be of length 0.
1662 */
1663 static private float[] subArray(final float[] array, final int offs, int len)
1664 {
1665 if (offs+len > array.length)
1666 {
1667 len = array.length-offs;
1668 }
1669
1670 if (len < 0)
1671 len = 0;
1672
1673 float[] subarray = new float[len];
1674 for (int i=0; i<len; i++)
1675 {
1676 subarray[i] = array[offs+i];
1677 }
1678
1679 return subarray;
1680 }
1681
1682 // The original data for d[]. This data is loaded from a file
1683 // to reduce the overall package size and to improve performance.
1684/*
1685 static final float d_data[] = {
1686 0.000000000f, -0.000442505f, 0.003250122f, -0.007003784f,
1687 0.031082153f, -0.078628540f, 0.100311279f, -0.572036743f,
1688 1.144989014f, 0.572036743f, 0.100311279f, 0.078628540f,
1689 0.031082153f, 0.007003784f, 0.003250122f, 0.000442505f,
1690 -0.000015259f, -0.000473022f, 0.003326416f, -0.007919312f,
1691 0.030517578f, -0.084182739f, 0.090927124f, -0.600219727f,
1692 1.144287109f, 0.543823242f, 0.108856201f, 0.073059082f,
1693 0.031478882f, 0.006118774f, 0.003173828f, 0.000396729f,
1694 -0.000015259f, -0.000534058f, 0.003387451f, -0.008865356f,
1695 0.029785156f, -0.089706421f, 0.080688477f, -0.628295898f,
1696 1.142211914f, 0.515609741f, 0.116577148f, 0.067520142f,
1697 0.031738281f, 0.005294800f, 0.003082275f, 0.000366211f,
1698 -0.000015259f, -0.000579834f, 0.003433228f, -0.009841919f,
1699 0.028884888f, -0.095169067f, 0.069595337f, -0.656219482f,
1700 1.138763428f, 0.487472534f, 0.123474121f, 0.061996460f,
1701 0.031845093f, 0.004486084f, 0.002990723f, 0.000320435f,
1702 -0.000015259f, -0.000625610f, 0.003463745f, -0.010848999f,
1703 0.027801514f, -0.100540161f, 0.057617188f, -0.683914185f,
1704 1.133926392f, 0.459472656f, 0.129577637f, 0.056533813f,
1705 0.031814575f, 0.003723145f, 0.002899170f, 0.000289917f,
1706 -0.000015259f, -0.000686646f, 0.003479004f, -0.011886597f,
1707 0.026535034f, -0.105819702f, 0.044784546f, -0.711318970f,
1708 1.127746582f, 0.431655884f, 0.134887695f, 0.051132202f,
1709 0.031661987f, 0.003005981f, 0.002792358f, 0.000259399f,
1710 -0.000015259f, -0.000747681f, 0.003479004f, -0.012939453f,
1711 0.025085449f, -0.110946655f, 0.031082153f, -0.738372803f,
1712 1.120223999f, 0.404083252f, 0.139450073f, 0.045837402f,
1713 0.031387329f, 0.002334595f, 0.002685547f, 0.000244141f,
1714 -0.000030518f, -0.000808716f, 0.003463745f, -0.014022827f,
1715 0.023422241f, -0.115921021f, 0.016510010f, -0.765029907f,
1716 1.111373901f, 0.376800537f, 0.143264771f, 0.040634155f,
1717 0.031005859f, 0.001693726f, 0.002578735f, 0.000213623f,
1718 -0.000030518f, -0.000885010f, 0.003417969f, -0.015121460f,
1719 0.021575928f, -0.120697021f, 0.001068115f, -0.791213989f,
1720 1.101211548f, 0.349868774f, 0.146362305f, 0.035552979f,
1721 0.030532837f, 0.001098633f, 0.002456665f, 0.000198364f,
1722 -0.000030518f, -0.000961304f, 0.003372192f, -0.016235352f,
1723 0.019531250f, -0.125259399f, -0.015228271f, -0.816864014f,
1724 1.089782715f, 0.323318481f, 0.148773193f, 0.030609131f,
1725 0.029937744f, 0.000549316f, 0.002349854f, 0.000167847f,
1726 -0.000030518f, -0.001037598f, 0.003280640f, -0.017349243f,
1727 0.017257690f, -0.129562378f, -0.032379150f, -0.841949463f,
1728 1.077117920f, 0.297210693f, 0.150497437f, 0.025817871f,
1729 0.029281616f, 0.000030518f, 0.002243042f, 0.000152588f,
1730 -0.000045776f, -0.001113892f, 0.003173828f, -0.018463135f,
1731 0.014801025f, -0.133590698f, -0.050354004f, -0.866363525f,
1732 1.063217163f, 0.271591187f, 0.151596069f, 0.021179199f,
1733 0.028533936f, -0.000442505f, 0.002120972f, 0.000137329f,
1734 -0.000045776f, -0.001205444f, 0.003051758f, -0.019577026f,
1735 0.012115479f, -0.137298584f, -0.069168091f, -0.890090942f,
1736 1.048156738f, 0.246505737f, 0.152069092f, 0.016708374f,
1737 0.027725220f, -0.000869751f, 0.002014160f, 0.000122070f,
1738 -0.000061035f, -0.001296997f, 0.002883911f, -0.020690918f,
1739 0.009231567f, -0.140670776f, -0.088775635f, -0.913055420f,
1740 1.031936646f, 0.221984863f, 0.151962280f, 0.012420654f,
1741 0.026840210f, -0.001266479f, 0.001907349f, 0.000106812f,
1742 -0.000061035f, -0.001388550f, 0.002700806f, -0.021789551f,
1743 0.006134033f, -0.143676758f, -0.109161377f, -0.935195923f,
1744 1.014617920f, 0.198059082f, 0.151306152f, 0.008316040f,
1745 0.025909424f, -0.001617432f, 0.001785278f, 0.000106812f,
1746 -0.000076294f, -0.001480103f, 0.002487183f, -0.022857666f,
1747 0.002822876f, -0.146255493f, -0.130310059f, -0.956481934f,
1748 0.996246338f, 0.174789429f, 0.150115967f, 0.004394531f,
1749 0.024932861f, -0.001937866f, 0.001693726f, 0.000091553f,
1750 -0.000076294f, -0.001586914f, 0.002227783f, -0.023910522f,
1751 -0.000686646f, -0.148422241f, -0.152206421f, -0.976852417f,
1752 0.976852417f, 0.152206421f, 0.148422241f, 0.000686646f,
1753 0.023910522f, -0.002227783f, 0.001586914f, 0.000076294f,
1754 -0.000091553f, -0.001693726f, 0.001937866f, -0.024932861f,
1755 -0.004394531f, -0.150115967f, -0.174789429f, -0.996246338f,
1756 0.956481934f, 0.130310059f, 0.146255493f, -0.002822876f,
1757 0.022857666f, -0.002487183f, 0.001480103f, 0.000076294f,
1758 -0.000106812f, -0.001785278f, 0.001617432f, -0.025909424f,
1759 -0.008316040f, -0.151306152f, -0.198059082f, -1.014617920f,
1760 0.935195923f, 0.109161377f, 0.143676758f, -0.006134033f,
1761 0.021789551f, -0.002700806f, 0.001388550f, 0.000061035f,
1762 -0.000106812f, -0.001907349f, 0.001266479f, -0.026840210f,
1763 -0.012420654f, -0.151962280f, -0.221984863f, -1.031936646f,
1764 0.913055420f, 0.088775635f, 0.140670776f, -0.009231567f,
1765 0.020690918f, -0.002883911f, 0.001296997f, 0.000061035f,
1766 -0.000122070f, -0.002014160f, 0.000869751f, -0.027725220f,
1767 -0.016708374f, -0.152069092f, -0.246505737f, -1.048156738f,
1768 0.890090942f, 0.069168091f, 0.137298584f, -0.012115479f,
1769 0.019577026f, -0.003051758f, 0.001205444f, 0.000045776f,
1770 -0.000137329f, -0.002120972f, 0.000442505f, -0.028533936f,
1771 -0.021179199f, -0.151596069f, -0.271591187f, -1.063217163f,
1772 0.866363525f, 0.050354004f, 0.133590698f, -0.014801025f,
1773 0.018463135f, -0.003173828f, 0.001113892f, 0.000045776f,
1774 -0.000152588f, -0.002243042f, -0.000030518f, -0.029281616f,
1775 -0.025817871f, -0.150497437f, -0.297210693f, -1.077117920f,
1776 0.841949463f, 0.032379150f, 0.129562378f, -0.017257690f,
1777 0.017349243f, -0.003280640f, 0.001037598f, 0.000030518f,
1778 -0.000167847f, -0.002349854f, -0.000549316f, -0.029937744f,
1779 -0.030609131f, -0.148773193f, -0.323318481f, -1.089782715f,
1780 0.816864014f, 0.015228271f, 0.125259399f, -0.019531250f,
1781 0.016235352f, -0.003372192f, 0.000961304f, 0.000030518f,
1782 -0.000198364f, -0.002456665f, -0.001098633f, -0.030532837f,
1783 -0.035552979f, -0.146362305f, -0.349868774f, -1.101211548f,
1784 0.791213989f, -0.001068115f, 0.120697021f, -0.021575928f,
1785 0.015121460f, -0.003417969f, 0.000885010f, 0.000030518f,
1786 -0.000213623f, -0.002578735f, -0.001693726f, -0.031005859f,
1787 -0.040634155f, -0.143264771f, -0.376800537f, -1.111373901f,
1788 0.765029907f, -0.016510010f, 0.115921021f, -0.023422241f,
1789 0.014022827f, -0.003463745f, 0.000808716f, 0.000030518f,
1790 -0.000244141f, -0.002685547f, -0.002334595f, -0.031387329f,
1791 -0.045837402f, -0.139450073f, -0.404083252f, -1.120223999f,
1792 0.738372803f, -0.031082153f, 0.110946655f, -0.025085449f,
1793 0.012939453f, -0.003479004f, 0.000747681f, 0.000015259f,
1794 -0.000259399f, -0.002792358f, -0.003005981f, -0.031661987f,
1795 -0.051132202f, -0.134887695f, -0.431655884f, -1.127746582f,
1796 0.711318970f, -0.044784546f, 0.105819702f, -0.026535034f,
1797 0.011886597f, -0.003479004f, 0.000686646f, 0.000015259f,
1798 -0.000289917f, -0.002899170f, -0.003723145f, -0.031814575f,
1799 -0.056533813f, -0.129577637f, -0.459472656f, -1.133926392f,
1800 0.683914185f, -0.057617188f, 0.100540161f, -0.027801514f,
1801 0.010848999f, -0.003463745f, 0.000625610f, 0.000015259f,
1802 -0.000320435f, -0.002990723f, -0.004486084f, -0.031845093f,
1803 -0.061996460f, -0.123474121f, -0.487472534f, -1.138763428f,
1804 0.656219482f, -0.069595337f, 0.095169067f, -0.028884888f,
1805 0.009841919f, -0.003433228f, 0.000579834f, 0.000015259f,
1806 -0.000366211f, -0.003082275f, -0.005294800f, -0.031738281f,
1807 -0.067520142f, -0.116577148f, -0.515609741f, -1.142211914f,
1808 0.628295898f, -0.080688477f, 0.089706421f, -0.029785156f,
1809 0.008865356f, -0.003387451f, 0.000534058f, 0.000015259f,
1810 -0.000396729f, -0.003173828f, -0.006118774f, -0.031478882f,
1811 -0.073059082f, -0.108856201f, -0.543823242f, -1.144287109f,
1812 0.600219727f, -0.090927124f, 0.084182739f, -0.030517578f,
1813 0.007919312f, -0.003326416f, 0.000473022f, 0.000015259f
1814 };
1815 */
1816
1817}
diff --git a/songdbj/javazoom/jl/decoder/au2lin.ser b/songdbj/javazoom/jl/decoder/au2lin.ser
new file mode 100644
index 0000000000..de0d1f62d9
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/au2lin.ser
Binary files differ
diff --git a/songdbj/javazoom/jl/decoder/huffcodetab.java b/songdbj/javazoom/jl/decoder/huffcodetab.java
new file mode 100644
index 0000000000..86975646f0
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/huffcodetab.java
@@ -0,0 +1,600 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 16/11/99 Renamed class, added javadoc, and changed table
4 * name from String to 3 chars. mdm@techie.com
5 * 02/15/99 Java Conversion by E.B, javalayer@javazoom.net
6 *
7 * 04/19/97 : Adapted from the ISO MPEG Audio Subgroup Software Simulation
8 * Group's public c source for its MPEG audio decoder. Miscellaneous
9 * changes by Jeff Tsay (ctsay@pasteur.eecs.berkeley.edu).
10 *-----------------------------------------------------------------------
11 * Copyright (c) 1991 MPEG/audio software simulation group, All Rights Reserved
12 * MPEG/audio coding/decoding software, work in progress
13 * NOT for public distribution until verified and approved by the
14 * MPEG/audio committee. For further information, please contact
15 * Davis Pan, 508-493-2241, e-mail: pan@3d.enet.dec.com
16 *
17 * VERSION 4.1
18 * changes made since last update:
19 * date programmers comment
20 * 27.2.92 F.O.Witte (ITT Intermetall)
21 * 8/24/93 M. Iwadare Changed for 1 pass decoding.
22 * 7/14/94 J. Koller useless 'typedef' before huffcodetab removed
23 *-----------------------------------------------------------------------
24 * This program is free software; you can redistribute it and/or modify
25 * it under the terms of the GNU Library General Public License as published
26 * by the Free Software Foundation; either version 2 of the License, or
27 * (at your option) any later version.
28 *
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU Library General Public License for more details.
33 *
34 * You should have received a copy of the GNU Library General Public
35 * License along with this program; if not, write to the Free Software
36 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37 *----------------------------------------------------------------------
38 */
39
40package javazoom.jl.decoder;
41
42/**
43 * Class to implements Huffman decoder.
44 */
45final class huffcodetab
46{
47 private static final int MXOFF=250;
48 private static final int HTN=34;
49
50 private char tablename0 = ' '; /* string, containing table_description */
51 private char tablename1 = ' '; /* string, containing table_description */
52 private char tablename2 = ' '; /* string, containing table_description */
53
54 private int xlen; /* max. x-index+ */
55 private int ylen; /* max. y-index+ */
56 private int linbits; /* number of linbits */
57 private int linmax; /* max number to be stored in linbits */
58 private int ref; /* a positive value indicates a reference */
59 private int[] table=null; /* pointer to array[xlen][ylen] */
60 private int[] hlen=null; /* pointer to array[xlen][ylen] */
61 private int[][] val=null; /* decoder tree */
62 private int treelen; /* length of decoder tree */
63
64 private static int ValTab0[][] = {
65 {0,0} // dummy
66 };
67
68 private static int ValTab1[][] = {
69 {2,1},{0,0},{2,1},{0,16},{2,1},{0,1},{0,17},
70 };
71
72 private static int ValTab2[][] = {
73 {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1},{2,1},
74 {0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34},
75 };
76
77 private static int ValTab3[][] = {
78 {4,1},{2,1},{0,0},{0,1},{2,1},{0,17},{2,1},{0,16},{4,1},{2,1},
79 {0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34},
80 };
81
82 private static int ValTab4[][] = {{0,0}}; // dummy
83
84 private static int ValTab5[][] = {
85 {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{8,1},{4,1},
86 {2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{8,1},{4,1},{2,1},{0,34},
87 {0,48},{2,1},{0,3},{0,19},{2,1},{0,49},{2,1},{0,50},{2,1},{0,35},
88 {0,51},
89 };
90
91 private static int ValTab6[][] = {
92 {6,1},{4,1},{2,1},{0,0},{0,16},{0,17},{6,1},{2,1},{0,1},{2,1},
93 {0,32},{0,33},{6,1},{2,1},{0,18},{2,1},{0,2},{0,34},{4,1},{2,1},
94 {0,49},{0,19},{4,1},{2,1},{0,48},{0,50},{2,1},{0,35},{2,1},{0,3},
95 {0,51},
96 };
97
98 private static int ValTab7[][] = {
99 {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{8,1},{2,1},{0,17},{4,1},
100 {2,1},{0,32},{0,2},{0,33},{18,1},{6,1},{2,1},{0,18},{2,1},{0,34},
101 {0,48},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1},{0,3},{0,50},{2,1},
102 {0,35},{0,4},{10,1},{4,1},{2,1},{0,64},{0,65},{2,1},{0,20},{2,1},
103 {0,66},{0,36},{12,1},{6,1},{4,1},{2,1},{0,51},{0,67},{0,80},{4,1},
104 {2,1},{0,52},{0,5},{0,81},{6,1},{2,1},{0,21},{2,1},{0,82},{0,37},
105 {4,1},{2,1},{0,68},{0,53},{4,1},{2,1},{0,83},{0,84},{2,1},{0,69},
106 {0,85},
107 };
108
109 private static int ValTab8[][] = {
110 {6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1},{2,1},
111 {0,33},{0,18},{14,1},{4,1},{2,1},{0,32},{0,2},{2,1},{0,34},{4,1},
112 {2,1},{0,48},{0,3},{2,1},{0,49},{0,19},{14,1},{8,1},{4,1},{2,1},
113 {0,50},{0,35},{2,1},{0,64},{0,4},{2,1},{0,65},{2,1},{0,20},{0,66},
114 {12,1},{6,1},{2,1},{0,36},{2,1},{0,51},{0,80},{4,1},{2,1},{0,67},
115 {0,52},{0,81},{6,1},{2,1},{0,21},{2,1},{0,5},{0,82},{6,1},{2,1},
116 {0,37},{2,1},{0,68},{0,53},{2,1},{0,83},{2,1},{0,69},{2,1},{0,84},
117 {0,85},
118 };
119
120 private static int ValTab9[][] = {
121 {8,1},{4,1},{2,1},{0,0},{0,16},{2,1},{0,1},{0,17},{10,1},{4,1},
122 {2,1},{0,32},{0,33},{2,1},{0,18},{2,1},{0,2},{0,34},{12,1},{6,1},
123 {4,1},{2,1},{0,48},{0,3},{0,49},{2,1},{0,19},{2,1},{0,50},{0,35},
124 {12,1},{4,1},{2,1},{0,65},{0,20},{4,1},{2,1},{0,64},{0,51},{2,1},
125 {0,66},{0,36},{10,1},{6,1},{4,1},{2,1},{0,4},{0,80},{0,67},{2,1},
126 {0,52},{0,81},{8,1},{4,1},{2,1},{0,21},{0,82},{2,1},{0,37},{0,68},
127 {6,1},{4,1},{2,1},{0,5},{0,84},{0,83},{2,1},{0,53},{2,1},{0,69},
128 {0,85},
129 };
130
131 private static int ValTab10[][] = {
132 {2,1},{0,0},{4,1},{2,1},{0,16},{0,1},{10,1},{2,1},{0,17},{4,1},
133 {2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{28,1},{8,1},{4,1},{2,1},
134 {0,34},{0,48},{2,1},{0,49},{0,19},{8,1},{4,1},{2,1},{0,3},{0,50},
135 {2,1},{0,35},{0,64},{4,1},{2,1},{0,65},{0,20},{4,1},{2,1},{0,4},
136 {0,51},{2,1},{0,66},{0,36},{28,1},{10,1},{6,1},{4,1},{2,1},{0,80},
137 {0,5},{0,96},{2,1},{0,97},{0,22},{12,1},{6,1},{4,1},{2,1},{0,67},
138 {0,52},{0,81},{2,1},{0,21},{2,1},{0,82},{0,37},{4,1},{2,1},{0,38},
139 {0,54},{0,113},{20,1},{8,1},{2,1},{0,23},{4,1},{2,1},{0,68},{0,83},
140 {0,6},{6,1},{4,1},{2,1},{0,53},{0,69},{0,98},{2,1},{0,112},{2,1},
141 {0,7},{0,100},{14,1},{4,1},{2,1},{0,114},{0,39},{6,1},{2,1},{0,99},
142 {2,1},{0,84},{0,85},{2,1},{0,70},{0,115},{8,1},{4,1},{2,1},{0,55},
143 {0,101},{2,1},{0,86},{0,116},{6,1},{2,1},{0,71},{2,1},{0,102},{0,117},
144 {4,1},{2,1},{0,87},{0,118},{2,1},{0,103},{0,119},
145 };
146
147 private static int ValTab11[][] = {
148 {6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{8,1},{2,1},{0,17},{4,1},
149 {2,1},{0,32},{0,2},{0,18},{24,1},{8,1},{2,1},{0,33},{2,1},{0,34},
150 {2,1},{0,48},{0,3},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1},{0,50},
151 {0,35},{4,1},{2,1},{0,64},{0,4},{2,1},{0,65},{0,20},{30,1},{16,1},
152 {10,1},{4,1},{2,1},{0,66},{0,36},{4,1},{2,1},{0,51},{0,67},{0,80},
153 {4,1},{2,1},{0,52},{0,81},{0,97},{6,1},{2,1},{0,22},{2,1},{0,6},
154 {0,38},{2,1},{0,98},{2,1},{0,21},{2,1},{0,5},{0,82},{16,1},{10,1},
155 {6,1},{4,1},{2,1},{0,37},{0,68},{0,96},{2,1},{0,99},{0,54},{4,1},
156 {2,1},{0,112},{0,23},{0,113},{16,1},{6,1},{4,1},{2,1},{0,7},{0,100},
157 {0,114},{2,1},{0,39},{4,1},{2,1},{0,83},{0,53},{2,1},{0,84},{0,69},
158 {10,1},{4,1},{2,1},{0,70},{0,115},{2,1},{0,55},{2,1},{0,101},{0,86},
159 {10,1},{6,1},{4,1},{2,1},{0,85},{0,87},{0,116},{2,1},{0,71},{0,102},
160 {4,1},{2,1},{0,117},{0,118},{2,1},{0,103},{0,119},
161 };
162
163 private static int ValTab12[][] = {
164 {12,1},{4,1},{2,1},{0,16},{0,1},{2,1},{0,17},{2,1},{0,0},{2,1},
165 {0,32},{0,2},{16,1},{4,1},{2,1},{0,33},{0,18},{4,1},{2,1},{0,34},
166 {0,49},{2,1},{0,19},{2,1},{0,48},{2,1},{0,3},{0,64},{26,1},{8,1},
167 {4,1},{2,1},{0,50},{0,35},{2,1},{0,65},{0,51},{10,1},{4,1},{2,1},
168 {0,20},{0,66},{2,1},{0,36},{2,1},{0,4},{0,80},{4,1},{2,1},{0,67},
169 {0,52},{2,1},{0,81},{0,21},{28,1},{14,1},{8,1},{4,1},{2,1},{0,82},
170 {0,37},{2,1},{0,83},{0,53},{4,1},{2,1},{0,96},{0,22},{0,97},{4,1},
171 {2,1},{0,98},{0,38},{6,1},{4,1},{2,1},{0,5},{0,6},{0,68},{2,1},
172 {0,84},{0,69},{18,1},{10,1},{4,1},{2,1},{0,99},{0,54},{4,1},{2,1},
173 {0,112},{0,7},{0,113},{4,1},{2,1},{0,23},{0,100},{2,1},{0,70},{0,114},
174 {10,1},{6,1},{2,1},{0,39},{2,1},{0,85},{0,115},{2,1},{0,55},{0,86},
175 {8,1},{4,1},{2,1},{0,101},{0,116},{2,1},{0,71},{0,102},{4,1},{2,1},
176 {0,117},{0,87},{2,1},{0,118},{2,1},{0,103},{0,119},
177 };
178
179 private static int ValTab13[][] = {
180 {2,1},{0,0},{6,1},{2,1},{0,16},{2,1},{0,1},{0,17},{28,1},{8,1},
181 {4,1},{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{8,1},{4,1},{2,1},
182 {0,34},{0,48},{2,1},{0,3},{0,49},{6,1},{2,1},{0,19},{2,1},{0,50},
183 {0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{70,1},{28,1},{14,1},{6,1},
184 {2,1},{0,20},{2,1},{0,51},{0,66},{4,1},{2,1},{0,36},{0,80},{2,1},
185 {0,67},{0,52},{4,1},{2,1},{0,81},{0,21},{4,1},{2,1},{0,5},{0,82},
186 {2,1},{0,37},{2,1},{0,68},{0,83},{14,1},{8,1},{4,1},{2,1},{0,96},
187 {0,6},{2,1},{0,97},{0,22},{4,1},{2,1},{0,128},{0,8},{0,129},{16,1},
188 {8,1},{4,1},{2,1},{0,53},{0,98},{2,1},{0,38},{0,84},{4,1},{2,1},
189 {0,69},{0,99},{2,1},{0,54},{0,112},{6,1},{4,1},{2,1},{0,7},{0,85},
190 {0,113},{2,1},{0,23},{2,1},{0,39},{0,55},{72,1},{24,1},{12,1},{4,1},
191 {2,1},{0,24},{0,130},{2,1},{0,40},{4,1},{2,1},{0,100},{0,70},{0,114},
192 {8,1},{4,1},{2,1},{0,132},{0,72},{2,1},{0,144},{0,9},{2,1},{0,145},
193 {0,25},{24,1},{14,1},{8,1},{4,1},{2,1},{0,115},{0,101},{2,1},{0,86},
194 {0,116},{4,1},{2,1},{0,71},{0,102},{0,131},{6,1},{2,1},{0,56},{2,1},
195 {0,117},{0,87},{2,1},{0,146},{0,41},{14,1},{8,1},{4,1},{2,1},{0,103},
196 {0,133},{2,1},{0,88},{0,57},{2,1},{0,147},{2,1},{0,73},{0,134},{6,1},
197 {2,1},{0,160},{2,1},{0,104},{0,10},{2,1},{0,161},{0,26},{68,1},{24,1},
198 {12,1},{4,1},{2,1},{0,162},{0,42},{4,1},{2,1},{0,149},{0,89},{2,1},
199 {0,163},{0,58},{8,1},{4,1},{2,1},{0,74},{0,150},{2,1},{0,176},{0,11},
200 {2,1},{0,177},{0,27},{20,1},{8,1},{2,1},{0,178},{4,1},{2,1},{0,118},
201 {0,119},{0,148},{6,1},{4,1},{2,1},{0,135},{0,120},{0,164},{4,1},{2,1},
202 {0,105},{0,165},{0,43},{12,1},{6,1},{4,1},{2,1},{0,90},{0,136},{0,179},
203 {2,1},{0,59},{2,1},{0,121},{0,166},{6,1},{4,1},{2,1},{0,106},{0,180},
204 {0,192},{4,1},{2,1},{0,12},{0,152},{0,193},{60,1},{22,1},{10,1},{6,1},
205 {2,1},{0,28},{2,1},{0,137},{0,181},{2,1},{0,91},{0,194},{4,1},{2,1},
206 {0,44},{0,60},{4,1},{2,1},{0,182},{0,107},{2,1},{0,196},{0,76},{16,1},
207 {8,1},{4,1},{2,1},{0,168},{0,138},{2,1},{0,208},{0,13},{2,1},{0,209},
208 {2,1},{0,75},{2,1},{0,151},{0,167},{12,1},{6,1},{2,1},{0,195},{2,1},
209 {0,122},{0,153},{4,1},{2,1},{0,197},{0,92},{0,183},{4,1},{2,1},{0,29},
210 {0,210},{2,1},{0,45},{2,1},{0,123},{0,211},{52,1},{28,1},{12,1},{4,1},
211 {2,1},{0,61},{0,198},{4,1},{2,1},{0,108},{0,169},{2,1},{0,154},{0,212},
212 {8,1},{4,1},{2,1},{0,184},{0,139},{2,1},{0,77},{0,199},{4,1},{2,1},
213 {0,124},{0,213},{2,1},{0,93},{0,224},{10,1},{4,1},{2,1},{0,225},{0,30},
214 {4,1},{2,1},{0,14},{0,46},{0,226},{8,1},{4,1},{2,1},{0,227},{0,109},
215 {2,1},{0,140},{0,228},{4,1},{2,1},{0,229},{0,186},{0,240},{38,1},{16,1},
216 {4,1},{2,1},{0,241},{0,31},{6,1},{4,1},{2,1},{0,170},{0,155},{0,185},
217 {2,1},{0,62},{2,1},{0,214},{0,200},{12,1},{6,1},{2,1},{0,78},{2,1},
218 {0,215},{0,125},{2,1},{0,171},{2,1},{0,94},{0,201},{6,1},{2,1},{0,15},
219 {2,1},{0,156},{0,110},{2,1},{0,242},{0,47},{32,1},{16,1},{6,1},{4,1},
220 {2,1},{0,216},{0,141},{0,63},{6,1},{2,1},{0,243},{2,1},{0,230},{0,202},
221 {2,1},{0,244},{0,79},{8,1},{4,1},{2,1},{0,187},{0,172},{2,1},{0,231},
222 {0,245},{4,1},{2,1},{0,217},{0,157},{2,1},{0,95},{0,232},{30,1},{12,1},
223 {6,1},{2,1},{0,111},{2,1},{0,246},{0,203},{4,1},{2,1},{0,188},{0,173},
224 {0,218},{8,1},{2,1},{0,247},{4,1},{2,1},{0,126},{0,127},{0,142},{6,1},
225 {4,1},{2,1},{0,158},{0,174},{0,204},{2,1},{0,248},{0,143},{18,1},{8,1},
226 {4,1},{2,1},{0,219},{0,189},{2,1},{0,234},{0,249},{4,1},{2,1},{0,159},
227 {0,235},{2,1},{0,190},{2,1},{0,205},{0,250},{14,1},{4,1},{2,1},{0,221},
228 {0,236},{6,1},{4,1},{2,1},{0,233},{0,175},{0,220},{2,1},{0,206},{0,251},
229 {8,1},{4,1},{2,1},{0,191},{0,222},{2,1},{0,207},{0,238},{4,1},{2,1},
230 {0,223},{0,239},{2,1},{0,255},{2,1},{0,237},{2,1},{0,253},{2,1},{0,252},
231 {0,254},
232 };
233
234 private static int ValTab14[][] = {
235 {0,0} // dummy
236 };
237
238 private static int ValTab15[][] = {
239 {16,1},{6,1},{2,1},{0,0},{2,1},{0,16},{0,1},{2,1},{0,17},{4,1},
240 {2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{50,1},{16,1},{6,1},{2,1},
241 {0,34},{2,1},{0,48},{0,49},{6,1},{2,1},{0,19},{2,1},{0,3},{0,64},
242 {2,1},{0,50},{0,35},{14,1},{6,1},{4,1},{2,1},{0,4},{0,20},{0,65},
243 {4,1},{2,1},{0,51},{0,66},{2,1},{0,36},{0,67},{10,1},{6,1},{2,1},
244 {0,52},{2,1},{0,80},{0,5},{2,1},{0,81},{0,21},{4,1},{2,1},{0,82},
245 {0,37},{4,1},{2,1},{0,68},{0,83},{0,97},{90,1},{36,1},{18,1},{10,1},
246 {6,1},{2,1},{0,53},{2,1},{0,96},{0,6},{2,1},{0,22},{0,98},{4,1},
247 {2,1},{0,38},{0,84},{2,1},{0,69},{0,99},{10,1},{6,1},{2,1},{0,54},
248 {2,1},{0,112},{0,7},{2,1},{0,113},{0,85},{4,1},{2,1},{0,23},{0,100},
249 {2,1},{0,114},{0,39},{24,1},{16,1},{8,1},{4,1},{2,1},{0,70},{0,115},
250 {2,1},{0,55},{0,101},{4,1},{2,1},{0,86},{0,128},{2,1},{0,8},{0,116},
251 {4,1},{2,1},{0,129},{0,24},{2,1},{0,130},{0,40},{16,1},{8,1},{4,1},
252 {2,1},{0,71},{0,102},{2,1},{0,131},{0,56},{4,1},{2,1},{0,117},{0,87},
253 {2,1},{0,132},{0,72},{6,1},{4,1},{2,1},{0,144},{0,25},{0,145},{4,1},
254 {2,1},{0,146},{0,118},{2,1},{0,103},{0,41},{92,1},{36,1},{18,1},{10,1},
255 {4,1},{2,1},{0,133},{0,88},{4,1},{2,1},{0,9},{0,119},{0,147},{4,1},
256 {2,1},{0,57},{0,148},{2,1},{0,73},{0,134},{10,1},{6,1},{2,1},{0,104},
257 {2,1},{0,160},{0,10},{2,1},{0,161},{0,26},{4,1},{2,1},{0,162},{0,42},
258 {2,1},{0,149},{0,89},{26,1},{14,1},{6,1},{2,1},{0,163},{2,1},{0,58},
259 {0,135},{4,1},{2,1},{0,120},{0,164},{2,1},{0,74},{0,150},{6,1},{4,1},
260 {2,1},{0,105},{0,176},{0,177},{4,1},{2,1},{0,27},{0,165},{0,178},{14,1},
261 {8,1},{4,1},{2,1},{0,90},{0,43},{2,1},{0,136},{0,151},{2,1},{0,179},
262 {2,1},{0,121},{0,59},{8,1},{4,1},{2,1},{0,106},{0,180},{2,1},{0,75},
263 {0,193},{4,1},{2,1},{0,152},{0,137},{2,1},{0,28},{0,181},{80,1},{34,1},
264 {16,1},{6,1},{4,1},{2,1},{0,91},{0,44},{0,194},{6,1},{4,1},{2,1},
265 {0,11},{0,192},{0,166},{2,1},{0,167},{0,122},{10,1},{4,1},{2,1},{0,195},
266 {0,60},{4,1},{2,1},{0,12},{0,153},{0,182},{4,1},{2,1},{0,107},{0,196},
267 {2,1},{0,76},{0,168},{20,1},{10,1},{4,1},{2,1},{0,138},{0,197},{4,1},
268 {2,1},{0,208},{0,92},{0,209},{4,1},{2,1},{0,183},{0,123},{2,1},{0,29},
269 {2,1},{0,13},{0,45},{12,1},{4,1},{2,1},{0,210},{0,211},{4,1},{2,1},
270 {0,61},{0,198},{2,1},{0,108},{0,169},{6,1},{4,1},{2,1},{0,154},{0,184},
271 {0,212},{4,1},{2,1},{0,139},{0,77},{2,1},{0,199},{0,124},{68,1},{34,1},
272 {18,1},{10,1},{4,1},{2,1},{0,213},{0,93},{4,1},{2,1},{0,224},{0,14},
273 {0,225},{4,1},{2,1},{0,30},{0,226},{2,1},{0,170},{0,46},{8,1},{4,1},
274 {2,1},{0,185},{0,155},{2,1},{0,227},{0,214},{4,1},{2,1},{0,109},{0,62},
275 {2,1},{0,200},{0,140},{16,1},{8,1},{4,1},{2,1},{0,228},{0,78},{2,1},
276 {0,215},{0,125},{4,1},{2,1},{0,229},{0,186},{2,1},{0,171},{0,94},{8,1},
277 {4,1},{2,1},{0,201},{0,156},{2,1},{0,241},{0,31},{6,1},{4,1},{2,1},
278 {0,240},{0,110},{0,242},{2,1},{0,47},{0,230},{38,1},{18,1},{8,1},{4,1},
279 {2,1},{0,216},{0,243},{2,1},{0,63},{0,244},{6,1},{2,1},{0,79},{2,1},
280 {0,141},{0,217},{2,1},{0,187},{0,202},{8,1},{4,1},{2,1},{0,172},{0,231},
281 {2,1},{0,126},{0,245},{8,1},{4,1},{2,1},{0,157},{0,95},{2,1},{0,232},
282 {0,142},{2,1},{0,246},{0,203},{34,1},{18,1},{10,1},{6,1},{4,1},{2,1},
283 {0,15},{0,174},{0,111},{2,1},{0,188},{0,218},{4,1},{2,1},{0,173},{0,247},
284 {2,1},{0,127},{0,233},{8,1},{4,1},{2,1},{0,158},{0,204},{2,1},{0,248},
285 {0,143},{4,1},{2,1},{0,219},{0,189},{2,1},{0,234},{0,249},{16,1},{8,1},
286 {4,1},{2,1},{0,159},{0,220},{2,1},{0,205},{0,235},{4,1},{2,1},{0,190},
287 {0,250},{2,1},{0,175},{0,221},{14,1},{6,1},{4,1},{2,1},{0,236},{0,206},
288 {0,251},{4,1},{2,1},{0,191},{0,237},{2,1},{0,222},{0,252},{6,1},{4,1},
289 {2,1},{0,207},{0,253},{0,238},{4,1},{2,1},{0,223},{0,254},{2,1},{0,239},
290 {0,255},
291 };
292
293 private static int ValTab16[][] = {
294 {2,1},{0,0},{6,1},{2,1},{0,16},{2,1},{0,1},{0,17},{42,1},{8,1},
295 {4,1},{2,1},{0,32},{0,2},{2,1},{0,33},{0,18},{10,1},{6,1},{2,1},
296 {0,34},{2,1},{0,48},{0,3},{2,1},{0,49},{0,19},{10,1},{4,1},{2,1},
297 {0,50},{0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{6,1},{2,1},{0,20},
298 {2,1},{0,51},{0,66},{4,1},{2,1},{0,36},{0,80},{2,1},{0,67},{0,52},
299 {138,1},{40,1},{16,1},{6,1},{4,1},{2,1},{0,5},{0,21},{0,81},{4,1},
300 {2,1},{0,82},{0,37},{4,1},{2,1},{0,68},{0,53},{0,83},{10,1},{6,1},
301 {4,1},{2,1},{0,96},{0,6},{0,97},{2,1},{0,22},{0,98},{8,1},{4,1},
302 {2,1},{0,38},{0,84},{2,1},{0,69},{0,99},{4,1},{2,1},{0,54},{0,112},
303 {0,113},{40,1},{18,1},{8,1},{2,1},{0,23},{2,1},{0,7},{2,1},{0,85},
304 {0,100},{4,1},{2,1},{0,114},{0,39},{4,1},{2,1},{0,70},{0,101},{0,115},
305 {10,1},{6,1},{2,1},{0,55},{2,1},{0,86},{0,8},{2,1},{0,128},{0,129},
306 {6,1},{2,1},{0,24},{2,1},{0,116},{0,71},{2,1},{0,130},{2,1},{0,40},
307 {0,102},{24,1},{14,1},{8,1},{4,1},{2,1},{0,131},{0,56},{2,1},{0,117},
308 {0,132},{4,1},{2,1},{0,72},{0,144},{0,145},{6,1},{2,1},{0,25},{2,1},
309 {0,9},{0,118},{2,1},{0,146},{0,41},{14,1},{8,1},{4,1},{2,1},{0,133},
310 {0,88},{2,1},{0,147},{0,57},{4,1},{2,1},{0,160},{0,10},{0,26},{8,1},
311 {2,1},{0,162},{2,1},{0,103},{2,1},{0,87},{0,73},{6,1},{2,1},{0,148},
312 {2,1},{0,119},{0,134},{2,1},{0,161},{2,1},{0,104},{0,149},{220,1},{126,1},
313 {50,1},{26,1},{12,1},{6,1},{2,1},{0,42},{2,1},{0,89},{0,58},{2,1},
314 {0,163},{2,1},{0,135},{0,120},{8,1},{4,1},{2,1},{0,164},{0,74},{2,1},
315 {0,150},{0,105},{4,1},{2,1},{0,176},{0,11},{0,177},{10,1},{4,1},{2,1},
316 {0,27},{0,178},{2,1},{0,43},{2,1},{0,165},{0,90},{6,1},{2,1},{0,179},
317 {2,1},{0,166},{0,106},{4,1},{2,1},{0,180},{0,75},{2,1},{0,12},{0,193},
318 {30,1},{14,1},{6,1},{4,1},{2,1},{0,181},{0,194},{0,44},{4,1},{2,1},
319 {0,167},{0,195},{2,1},{0,107},{0,196},{8,1},{2,1},{0,29},{4,1},{2,1},
320 {0,136},{0,151},{0,59},{4,1},{2,1},{0,209},{0,210},{2,1},{0,45},{0,211},
321 {18,1},{6,1},{4,1},{2,1},{0,30},{0,46},{0,226},{6,1},{4,1},{2,1},
322 {0,121},{0,152},{0,192},{2,1},{0,28},{2,1},{0,137},{0,91},{14,1},{6,1},
323 {2,1},{0,60},{2,1},{0,122},{0,182},{4,1},{2,1},{0,76},{0,153},{2,1},
324 {0,168},{0,138},{6,1},{2,1},{0,13},{2,1},{0,197},{0,92},{4,1},{2,1},
325 {0,61},{0,198},{2,1},{0,108},{0,154},{88,1},{86,1},{36,1},{16,1},{8,1},
326 {4,1},{2,1},{0,139},{0,77},{2,1},{0,199},{0,124},{4,1},{2,1},{0,213},
327 {0,93},{2,1},{0,224},{0,14},{8,1},{2,1},{0,227},{4,1},{2,1},{0,208},
328 {0,183},{0,123},{6,1},{4,1},{2,1},{0,169},{0,184},{0,212},{2,1},{0,225},
329 {2,1},{0,170},{0,185},{24,1},{10,1},{6,1},{4,1},{2,1},{0,155},{0,214},
330 {0,109},{2,1},{0,62},{0,200},{6,1},{4,1},{2,1},{0,140},{0,228},{0,78},
331 {4,1},{2,1},{0,215},{0,229},{2,1},{0,186},{0,171},{12,1},{4,1},{2,1},
332 {0,156},{0,230},{4,1},{2,1},{0,110},{0,216},{2,1},{0,141},{0,187},{8,1},
333 {4,1},{2,1},{0,231},{0,157},{2,1},{0,232},{0,142},{4,1},{2,1},{0,203},
334 {0,188},{0,158},{0,241},{2,1},{0,31},{2,1},{0,15},{0,47},{66,1},{56,1},
335 {2,1},{0,242},{52,1},{50,1},{20,1},{8,1},{2,1},{0,189},{2,1},{0,94},
336 {2,1},{0,125},{0,201},{6,1},{2,1},{0,202},{2,1},{0,172},{0,126},{4,1},
337 {2,1},{0,218},{0,173},{0,204},{10,1},{6,1},{2,1},{0,174},{2,1},{0,219},
338 {0,220},{2,1},{0,205},{0,190},{6,1},{4,1},{2,1},{0,235},{0,237},{0,238},
339 {6,1},{4,1},{2,1},{0,217},{0,234},{0,233},{2,1},{0,222},{4,1},{2,1},
340 {0,221},{0,236},{0,206},{0,63},{0,240},{4,1},{2,1},{0,243},{0,244},{2,1},
341 {0,79},{2,1},{0,245},{0,95},{10,1},{2,1},{0,255},{4,1},{2,1},{0,246},
342 {0,111},{2,1},{0,247},{0,127},{12,1},{6,1},{2,1},{0,143},{2,1},{0,248},
343 {0,249},{4,1},{2,1},{0,159},{0,250},{0,175},{8,1},{4,1},{2,1},{0,251},
344 {0,191},{2,1},{0,252},{0,207},{4,1},{2,1},{0,253},{0,223},{2,1},{0,254},
345 {0,239},
346 };
347
348 private static int ValTab24[][] = {
349 {60,1},{8,1},{4,1},{2,1},{0,0},{0,16},{2,1},{0,1},{0,17},{14,1},
350 {6,1},{4,1},{2,1},{0,32},{0,2},{0,33},{2,1},{0,18},{2,1},{0,34},
351 {2,1},{0,48},{0,3},{14,1},{4,1},{2,1},{0,49},{0,19},{4,1},{2,1},
352 {0,50},{0,35},{4,1},{2,1},{0,64},{0,4},{0,65},{8,1},{4,1},{2,1},
353 {0,20},{0,51},{2,1},{0,66},{0,36},{6,1},{4,1},{2,1},{0,67},{0,52},
354 {0,81},{6,1},{4,1},{2,1},{0,80},{0,5},{0,21},{2,1},{0,82},{0,37},
355 {250,1},{98,1},{34,1},{18,1},{10,1},{4,1},{2,1},{0,68},{0,83},{2,1},
356 {0,53},{2,1},{0,96},{0,6},{4,1},{2,1},{0,97},{0,22},{2,1},{0,98},
357 {0,38},{8,1},{4,1},{2,1},{0,84},{0,69},{2,1},{0,99},{0,54},{4,1},
358 {2,1},{0,113},{0,85},{2,1},{0,100},{0,70},{32,1},{14,1},{6,1},{2,1},
359 {0,114},{2,1},{0,39},{0,55},{2,1},{0,115},{4,1},{2,1},{0,112},{0,7},
360 {0,23},{10,1},{4,1},{2,1},{0,101},{0,86},{4,1},{2,1},{0,128},{0,8},
361 {0,129},{4,1},{2,1},{0,116},{0,71},{2,1},{0,24},{0,130},{16,1},{8,1},
362 {4,1},{2,1},{0,40},{0,102},{2,1},{0,131},{0,56},{4,1},{2,1},{0,117},
363 {0,87},{2,1},{0,132},{0,72},{8,1},{4,1},{2,1},{0,145},{0,25},{2,1},
364 {0,146},{0,118},{4,1},{2,1},{0,103},{0,41},{2,1},{0,133},{0,88},{92,1},
365 {34,1},{16,1},{8,1},{4,1},{2,1},{0,147},{0,57},{2,1},{0,148},{0,73},
366 {4,1},{2,1},{0,119},{0,134},{2,1},{0,104},{0,161},{8,1},{4,1},{2,1},
367 {0,162},{0,42},{2,1},{0,149},{0,89},{4,1},{2,1},{0,163},{0,58},{2,1},
368 {0,135},{2,1},{0,120},{0,74},{22,1},{12,1},{4,1},{2,1},{0,164},{0,150},
369 {4,1},{2,1},{0,105},{0,177},{2,1},{0,27},{0,165},{6,1},{2,1},{0,178},
370 {2,1},{0,90},{0,43},{2,1},{0,136},{0,179},{16,1},{10,1},{6,1},{2,1},
371 {0,144},{2,1},{0,9},{0,160},{2,1},{0,151},{0,121},{4,1},{2,1},{0,166},
372 {0,106},{0,180},{12,1},{6,1},{2,1},{0,26},{2,1},{0,10},{0,176},{2,1},
373 {0,59},{2,1},{0,11},{0,192},{4,1},{2,1},{0,75},{0,193},{2,1},{0,152},
374 {0,137},{67,1},{34,1},{16,1},{8,1},{4,1},{2,1},{0,28},{0,181},{2,1},
375 {0,91},{0,194},{4,1},{2,1},{0,44},{0,167},{2,1},{0,122},{0,195},{10,1},
376 {6,1},{2,1},{0,60},{2,1},{0,12},{0,208},{2,1},{0,182},{0,107},{4,1},
377 {2,1},{0,196},{0,76},{2,1},{0,153},{0,168},{16,1},{8,1},{4,1},{2,1},
378 {0,138},{0,197},{2,1},{0,92},{0,209},{4,1},{2,1},{0,183},{0,123},{2,1},
379 {0,29},{0,210},{9,1},{4,1},{2,1},{0,45},{0,211},{2,1},{0,61},{0,198},
380 {85,250},{4,1},{2,1},{0,108},{0,169},{2,1},{0,154},{0,212},{32,1},{16,1},
381 {8,1},{4,1},{2,1},{0,184},{0,139},{2,1},{0,77},{0,199},{4,1},{2,1},
382 {0,124},{0,213},{2,1},{0,93},{0,225},{8,1},{4,1},{2,1},{0,30},{0,226},
383 {2,1},{0,170},{0,185},{4,1},{2,1},{0,155},{0,227},{2,1},{0,214},{0,109},
384 {20,1},{10,1},{6,1},{2,1},{0,62},{2,1},{0,46},{0,78},{2,1},{0,200},
385 {0,140},{4,1},{2,1},{0,228},{0,215},{4,1},{2,1},{0,125},{0,171},{0,229},
386 {10,1},{4,1},{2,1},{0,186},{0,94},{2,1},{0,201},{2,1},{0,156},{0,110},
387 {8,1},{2,1},{0,230},{2,1},{0,13},{2,1},{0,224},{0,14},{4,1},{2,1},
388 {0,216},{0,141},{2,1},{0,187},{0,202},{74,1},{2,1},{0,255},{64,1},{58,1},
389 {32,1},{16,1},{8,1},{4,1},{2,1},{0,172},{0,231},{2,1},{0,126},{0,217},
390 {4,1},{2,1},{0,157},{0,232},{2,1},{0,142},{0,203},{8,1},{4,1},{2,1},
391 {0,188},{0,218},{2,1},{0,173},{0,233},{4,1},{2,1},{0,158},{0,204},{2,1},
392 {0,219},{0,189},{16,1},{8,1},{4,1},{2,1},{0,234},{0,174},{2,1},{0,220},
393 {0,205},{4,1},{2,1},{0,235},{0,190},{2,1},{0,221},{0,236},{8,1},{4,1},
394 {2,1},{0,206},{0,237},{2,1},{0,222},{0,238},{0,15},{4,1},{2,1},{0,240},
395 {0,31},{0,241},{4,1},{2,1},{0,242},{0,47},{2,1},{0,243},{0,63},{18,1},
396 {8,1},{4,1},{2,1},{0,244},{0,79},{2,1},{0,245},{0,95},{4,1},{2,1},
397 {0,246},{0,111},{2,1},{0,247},{2,1},{0,127},{0,143},{10,1},{4,1},{2,1},
398 {0,248},{0,249},{4,1},{2,1},{0,159},{0,175},{0,250},{8,1},{4,1},{2,1},
399 {0,251},{0,191},{2,1},{0,252},{0,207},{4,1},{2,1},{0,253},{0,223},{2,1},
400 {0,254},{0,239},
401 };
402
403 private static int ValTab32[][] = {
404 {2,1},{0,0},{8,1},{4,1},{2,1},{0,8},{0,4},{2,1},{0,1},{0,2},
405 {8,1},{4,1},{2,1},{0,12},{0,10},{2,1},{0,3},{0,6},{6,1},{2,1},
406 {0,9},{2,1},{0,5},{0,7},{4,1},{2,1},{0,14},{0,13},{2,1},{0,15},
407 {0,11},
408 };
409
410 private static int ValTab33[][] = {
411 {16,1},{8,1},{4,1},{2,1},{0,0},{0,1},{2,1},{0,2},{0,3},{4,1},
412 {2,1},{0,4},{0,5},{2,1},{0,6},{0,7},{8,1},{4,1},{2,1},{0,8},
413 {0,9},{2,1},{0,10},{0,11},{4,1},{2,1},{0,12},{0,13},{2,1},{0,14},
414 {0,15},
415 };
416
417
418 public static huffcodetab[] ht = null; /* Simulate extern struct */
419
420 private static int[] bitbuf = new int[32];
421
422 /**
423 * Big Constructor : Computes all Huffman Tables.
424 */
425 private huffcodetab(String S,int XLEN, int YLEN, int LINBITS, int LINMAX, int REF,
426 int[] TABLE, int[] HLEN, int[][] VAL, int TREELEN)
427 {
428 tablename0 = S.charAt(0);
429 tablename1 = S.charAt(1);
430 tablename2 = S.charAt(2);
431 xlen = XLEN;
432 ylen = YLEN;
433 linbits = LINBITS;
434 linmax = LINMAX;
435 ref = REF;
436 table = TABLE;
437 hlen = HLEN;
438 val = VAL;
439 treelen = TREELEN;
440 }
441
442
443
444 /**
445 * Do the huffman-decoding.
446 * note! for counta,countb -the 4 bit value is returned in y,
447 * discard x.
448 */
449 public static int huffman_decoder(huffcodetab h, int[] x, int[] y, int[] v, int[] w, BitReserve br)
450 {
451 // array of all huffcodtable headers
452 // 0..31 Huffman code table 0..31
453 // 32,33 count1-tables
454
455 int dmask = 1 << ((4 * 8) - 1);
456 int hs = 4 * 8;
457 int level;
458 int point = 0;
459 int error = 1;
460 level = dmask;
461
462 if (h.val == null) return 2;
463
464 /* table 0 needs no bits */
465 if ( h.treelen == 0)
466 {
467 x[0] = y[0] = 0;
468 return 0;
469 }
470
471 /* Lookup in Huffman table. */
472
473 /*int bitsAvailable = 0;
474 int bitIndex = 0;
475
476 int bits[] = bitbuf;*/
477 do
478 {
479 if (h.val[point][0]==0)
480 { /*end of tree*/
481 x[0] = h.val[point][1] >>> 4;
482 y[0] = h.val[point][1] & 0xf;
483 error = 0;
484 break;
485 }
486
487 // hget1bit() is called thousands of times, and so needs to be
488 // ultra fast.
489 /*
490 if (bitIndex==bitsAvailable)
491 {
492 bitsAvailable = br.readBits(bits, 32);
493 bitIndex = 0;
494 }
495 */
496 //if (bits[bitIndex++]!=0)
497 if (br.hget1bit()!=0)
498 {
499 while (h.val[point][1] >= MXOFF) point += h.val[point][1];
500 point += h.val[point][1];
501 }
502 else
503 {
504 while (h.val[point][0] >= MXOFF) point += h.val[point][0];
505 point += h.val[point][0];
506 }
507 level >>>= 1;
508 // MDM: ht[0] is always 0;
509 } while ((level !=0 ) || (point < 0 /*ht[0].treelen*/) );
510
511 // put back any bits not consumed
512 /*
513 int unread = (bitsAvailable-bitIndex);
514 if (unread>0)
515 br.rewindNbits(unread);
516 */
517 /* Process sign encodings for quadruples tables. */
518 // System.out.println(h.tablename);
519 if (h.tablename0 == '3' && (h.tablename1 == '2' || h.tablename1 == '3'))
520 {
521 v[0] = (y[0]>>3) & 1;
522 w[0] = (y[0]>>2) & 1;
523 x[0] = (y[0]>>1) & 1;
524 y[0] = y[0] & 1;
525
526 /* v, w, x and y are reversed in the bitstream.
527 switch them around to make test bistream work. */
528
529 if (v[0]!=0)
530 if (br.hget1bit() != 0) v[0] = -v[0];
531 if (w[0]!=0)
532 if (br.hget1bit() != 0) w[0] = -w[0];
533 if (x[0]!=0)
534 if (br.hget1bit() != 0) x[0] = -x[0];
535 if (y[0]!=0)
536 if (br.hget1bit() != 0) y[0] = -y[0];
537 }
538 else
539 {
540 // Process sign and escape encodings for dual tables.
541 // x and y are reversed in the test bitstream.
542 // Reverse x and y here to make test bitstream work.
543
544 if (h.linbits != 0)
545 if ((h.xlen-1) == x[0])
546 x[0] += br.hgetbits(h.linbits);
547 if (x[0] != 0)
548 if (br.hget1bit() != 0) x[0] = -x[0];
549 if (h.linbits != 0)
550 if ((h.ylen-1) == y[0])
551 y[0] += br.hgetbits(h.linbits);
552 if (y[0] != 0)
553 if (br.hget1bit() != 0) y[0] = -y[0];
554 }
555 return error;
556 }
557
558 public static void inithuff()
559 {
560
561 if (ht!=null)
562 return;
563
564 ht = new huffcodetab[HTN];
565 ht[0] = new huffcodetab("0 ",0,0,0,0,-1,null,null,ValTab0,0);
566 ht[1] = new huffcodetab("1 ",2,2,0,0,-1,null,null,ValTab1,7);
567 ht[2] = new huffcodetab("2 ",3,3,0,0,-1,null,null,ValTab2,17);
568 ht[3] = new huffcodetab("3 ",3,3,0,0,-1,null,null,ValTab3,17);
569 ht[4] = new huffcodetab("4 ",0,0,0,0,-1,null,null,ValTab4,0);
570 ht[5] = new huffcodetab("5 ",4,4,0,0,-1,null,null,ValTab5,31);
571 ht[6] = new huffcodetab("6 ",4,4,0,0,-1,null,null,ValTab6,31);
572 ht[7] = new huffcodetab("7 ",6,6,0,0,-1,null,null,ValTab7,71);
573 ht[8] = new huffcodetab("8 ",6,6,0,0,-1,null,null,ValTab8,71);
574 ht[9] = new huffcodetab("9 ",6,6,0,0,-1,null,null,ValTab9,71);
575 ht[10] = new huffcodetab("10 ",8,8,0,0,-1,null,null,ValTab10,127);
576 ht[11] = new huffcodetab("11 ",8,8,0,0,-1,null,null,ValTab11,127);
577 ht[12] = new huffcodetab("12 ",8,8,0,0,-1,null,null,ValTab12,127);
578 ht[13] = new huffcodetab("13 ",16,16,0,0,-1,null,null,ValTab13,511);
579 ht[14] = new huffcodetab("14 ",0,0,0,0,-1,null,null,ValTab14,0);
580 ht[15] = new huffcodetab("15 ",16,16,0,0,-1,null,null,ValTab15,511);
581 ht[16] = new huffcodetab("16 ",16,16,1,1,-1,null,null,ValTab16,511);
582 ht[17] = new huffcodetab("17 ",16,16,2,3,16,null,null,ValTab16,511);
583 ht[18] = new huffcodetab("18 ",16,16,3,7,16,null,null,ValTab16,511);
584 ht[19] = new huffcodetab("19 ",16,16,4,15,16,null,null,ValTab16,511);
585 ht[20] = new huffcodetab("20 ",16,16,6,63,16,null,null,ValTab16,511);
586 ht[21] = new huffcodetab("21 ",16,16,8,255,16,null,null,ValTab16,511);
587 ht[22] = new huffcodetab("22 ",16,16,10,1023,16,null,null,ValTab16,511);
588 ht[23] = new huffcodetab("23 ",16,16,13,8191,16,null,null,ValTab16,511);
589 ht[24] = new huffcodetab("24 ",16,16,4,15,-1,null,null,ValTab24,512);
590 ht[25] = new huffcodetab("25 ",16,16,5,31,24,null,null,ValTab24,512);
591 ht[26] = new huffcodetab("26 ",16,16,6,63,24,null,null,ValTab24,512);
592 ht[27] = new huffcodetab("27 ",16,16,7,127,24,null,null,ValTab24,512);
593 ht[28] = new huffcodetab("28 ",16,16,8,255,24,null,null,ValTab24,512);
594 ht[29] = new huffcodetab("29 ",16,16,9,511,24,null,null,ValTab24,512);
595 ht[30] = new huffcodetab("30 ",16,16,11,2047,24,null,null,ValTab24,512);
596 ht[31] = new huffcodetab("31 ",16,16,13,8191,24,null,null,ValTab24,512);
597 ht[32] = new huffcodetab("32 ",1,16,0,0,-1,null,null,ValTab32,31);
598 ht[33] = new huffcodetab("33 ",1,16,0,0,-1,null,null,ValTab33,31);
599 }
600}
diff --git a/songdbj/javazoom/jl/decoder/l3reorder.ser b/songdbj/javazoom/jl/decoder/l3reorder.ser
new file mode 100644
index 0000000000..d7e3e0fa61
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/l3reorder.ser
Binary files differ
diff --git a/songdbj/javazoom/jl/decoder/lin2au.ser b/songdbj/javazoom/jl/decoder/lin2au.ser
new file mode 100644
index 0000000000..258231516e
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/lin2au.ser
Binary files differ
diff --git a/songdbj/javazoom/jl/decoder/readme.txt b/songdbj/javazoom/jl/decoder/readme.txt
new file mode 100644
index 0000000000..7a765ec7dc
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/readme.txt
@@ -0,0 +1,15 @@
1
2TODO:
3
4
5Implement high-level Player and Converter classes.
6
7Add MP1 and MP2 support and test.
8
9Add option to run each "stage" on own thread.
10E.g. read & parse input, decode subbands, subband synthesis, audio output.
11
12Retrofit seek support (temporarily removed when reworking classes.)
13
14
15Document and give example code. \ No newline at end of file
diff --git a/songdbj/javazoom/jl/decoder/sfd.ser b/songdbj/javazoom/jl/decoder/sfd.ser
new file mode 100644
index 0000000000..e65b782f36
--- /dev/null
+++ b/songdbj/javazoom/jl/decoder/sfd.ser
Binary files differ
diff --git a/songdbj/javazoom/jl/player/AudioDevice.java b/songdbj/javazoom/jl/player/AudioDevice.java
new file mode 100644
index 0000000000..45c28600e6
--- /dev/null
+++ b/songdbj/javazoom/jl/player/AudioDevice.java
@@ -0,0 +1,103 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 29/01/00 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.player;
22
23import javazoom.jl.decoder.Decoder;
24import javazoom.jl.decoder.JavaLayerException;
25
26/**
27 * The <code>AudioDevice</code> interface provides an abstraction for
28 * a device capable of sounding audio samples. Samples are written to
29 * the device wia the write() method. The device assumes
30 * that these samples are signed 16-bit samples taken at the output frequency
31 * of the decoder. If the decoder outputs more than one channel, the samples for
32 * each channel are assumed to appear consecutively, with the lower numbered
33 * channels preceeding higher-numbered channels. E.g. if there are two
34 * channels, the samples will appear in this order:
35 * <pre><code>
36 *
37 * l0, r0, l1, r1, l2, r2...
38 *
39 * where
40 * l<i>x</i> indicates the <i>x</i>th sample on channel 0
41 * r<i>x</i> indicates the <i>x</i>th sample on channel 1
42 * </code></pre>
43 *
44 * @since 0.0.8
45 * @author Mat McGowan
46 */
47public interface AudioDevice
48{
49 /**
50 * Prepares the AudioDevice for playback of audio samples.
51 * @param decoder The decoder that will be providing the audio
52 * samples.
53 *
54 * If the audio device is already open, this method returns silently.
55 *
56 */
57 public void open(Decoder decoder) throws JavaLayerException;
58
59 /**
60 * Retrieves the open state of this audio device.
61 *
62 * @return <code>true</code> if this audio device is open and playing
63 * audio samples, or <code>false</code> otherwise.
64 */
65 public boolean isOpen();
66
67 /**
68 * Writes a number of samples to this <code>AudioDevice</code>.
69 *
70 * @param samples The array of signed 16-bit samples to write
71 * to the audio device.
72 * @param offs The offset of the first sample.
73 * @param len The number of samples to write.
74 *
75 * This method may return prior to the samples actually being played
76 * by the audio device.
77 */
78 public void write(short[] samples, int offs, int len) throws JavaLayerException;
79
80
81 /**
82 * Closes this audio device. Any currently playing audio is stopped
83 * as soon as possible. Any previously written audio data that has not been heard
84 * is discarded.
85 *
86 * The implementation should ensure that any threads currently blocking
87 * on the device (e.g. during a <code>write</code> or <code>flush</code>
88 * operation should be unblocked by this method.
89 */
90 public void close();
91
92
93 /**
94 * Blocks until all audio samples previously written to this audio device have
95 * been heard.
96 */
97 public void flush();
98
99 /**
100 * Retrieves the current playback position in milliseconds.
101 */
102 public int getPosition();
103}
diff --git a/songdbj/javazoom/jl/player/AudioDeviceBase.java b/songdbj/javazoom/jl/player/AudioDeviceBase.java
new file mode 100644
index 0000000000..d9c84f08e7
--- /dev/null
+++ b/songdbj/javazoom/jl/player/AudioDeviceBase.java
@@ -0,0 +1,177 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 29/01/00 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.player;
22
23import javazoom.jl.decoder.Decoder;
24import javazoom.jl.decoder.JavaLayerException;
25
26/**
27 * The <code>AudioDeviceBase</code> class provides a simple thread-safe
28 * implementation of the <code>AudioDevice</code> interface.
29 * Template methods are provided for subclasses to override and
30 * in doing so provide the implementation for the main operations
31 * of the <code>AudioDevice</code> interface.
32 *
33 * @since 0.0.8
34 * @author Mat McGowan
35 */
36/*
37 * REVIEW: It is desirable to be able to use the decoder whe
38 * in the implementation of open(), but the decoder
39 * has not yet read a frame, and so much of the
40 * desired information (sample rate, channels etc.)
41 * are not available.
42 */
43public abstract class AudioDeviceBase implements AudioDevice
44{
45 private boolean open = false;
46
47 private Decoder decoder = null;
48
49 /**
50 * Opens this audio device.
51 *
52 * @param decoder The decoder that will provide audio data
53 * to this audio device.
54 */
55 public synchronized void open(Decoder decoder) throws JavaLayerException
56 {
57 if (!isOpen())
58 {
59 this.decoder = decoder;
60 openImpl();
61 setOpen(true);
62 }
63 }
64
65 /**
66 * Template method to provide the
67 * implementation for the opening of the audio device.
68 */
69 protected void openImpl() throws JavaLayerException
70 {
71 }
72
73 /**
74 * Sets the open state for this audio device.
75 */
76 protected void setOpen(boolean open)
77 {
78 this.open = open;
79 }
80
81 /**
82 * Determines if this audio device is open or not.
83 *
84 * @return <code>true</code> if the audio device is open,
85 * <code>false</code> if it is not.
86 */
87 public synchronized boolean isOpen()
88 {
89 return open;
90 }
91
92 /**
93 * Closes this audio device. If the device is currently playing
94 * audio, playback is stopped immediately without flushing
95 * any buffered audio data.
96 */
97 public synchronized void close()
98 {
99 if (isOpen())
100 {
101 closeImpl();
102 setOpen(false);
103 decoder = null;
104 }
105 }
106
107 /**
108 * Template method to provide the implementation for
109 * closing the audio device.
110 */
111 protected void closeImpl()
112 {
113 }
114
115 /**
116 * Writes audio data to this audio device. Audio data is
117 * assumed to be in the output format of the decoder. This
118 * method may return before the data has actually been sounded
119 * by the device if the device buffers audio samples.
120 *
121 * @param samples The samples to write to the audio device.
122 * @param offs The offset into the array of the first sample to write.
123 * @param len The number of samples from the array to write.
124 * @throws JavaLayerException if the audio data could not be
125 * written to the audio device.
126 * If the audio device is not open, this method does nthing.
127 */
128 public void write(short[] samples, int offs, int len)
129 throws JavaLayerException
130 {
131 if (isOpen())
132 {
133 writeImpl(samples, offs, len);
134 }
135 }
136
137 /**
138 * Template method to provide the implementation for
139 * writing audio samples to the audio device.
140 */
141 protected void writeImpl(short[] samples, int offs, int len)
142 throws JavaLayerException
143 {
144 }
145
146 /**
147 * Waits for any buffered audio samples to be played by the
148 * audio device. This method should only be called prior
149 * to closing the device.
150 */
151 public void flush()
152 {
153 if (isOpen())
154 {
155 flushImpl();
156 }
157 }
158
159 /**
160 * Template method to provide the implementation for
161 * flushing any buffered audio data.
162 */
163 protected void flushImpl()
164 {
165 }
166
167 /**
168 * Retrieves the decoder that provides audio data to this
169 * audio device.
170 *
171 * @return The associated decoder.
172 */
173 protected Decoder getDecoder()
174 {
175 return decoder;
176 }
177}
diff --git a/songdbj/javazoom/jl/player/AudioDeviceFactory.java b/songdbj/javazoom/jl/player/AudioDeviceFactory.java
new file mode 100644
index 0000000000..2d502d2aad
--- /dev/null
+++ b/songdbj/javazoom/jl/player/AudioDeviceFactory.java
@@ -0,0 +1,87 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 29/01/00 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.player;
22
23import javazoom.jl.decoder.JavaLayerException;
24
25/**
26 * An <code>AudioDeviceFactory</code> class is responsible for creating
27 * a specific <code>AudioDevice</code> implementation. A factory implementation
28 * can be as simple or complex as desired and may support just one implementation
29 * or may return several implementations depending upon the execution
30 * environment.
31 * <p>
32 * When implementing a factory that provides an AudioDevice that uses
33 * class that may not be present, the factory should dynamically link to any
34 * specific implementation classes required to instantiate or test the audio
35 * implementation. This is so that the application as a whole
36 * can run without these classes being present. The audio
37 * device implementation, however, will usually statically link to the classes
38 * required. (See the JavaSound deivce and factory for an example
39 * of this.)
40 *
41 * @see FactoryRegistry
42 *
43 * @since 0.0.8
44 * @author Mat McGowan
45 */
46public abstract class AudioDeviceFactory
47{
48 /**
49 * Creates a new <code>AudioDevice</code>.
50 *
51 * @return a new instance of a specific class of <code>AudioDevice</code>.
52 * @throws JavaLayerException if an instance of AudioDevice could not
53 * be created.
54 */
55 public abstract AudioDevice createAudioDevice() throws JavaLayerException;
56
57 /**
58 * Creates an instance of an AudioDevice implementation.
59 * @param loader The <code>ClassLoader</code> to use to
60 * load the named class, or null to use the
61 * system class loader.
62 * @param name The name of the class to load.
63 * @return A newly-created instance of the audio device class.
64 */
65 protected AudioDevice instantiate(ClassLoader loader, String name)
66 throws ClassNotFoundException,
67 IllegalAccessException,
68 InstantiationException
69 {
70 AudioDevice dev = null;
71
72 Class cls = null;
73 if (loader==null)
74 {
75 cls = Class.forName(name);
76 }
77 else
78 {
79 cls = loader.loadClass(name);
80 }
81
82 Object o = cls.newInstance();
83 dev = (AudioDevice)o;
84
85 return dev;
86 }
87}
diff --git a/songdbj/javazoom/jl/player/FactoryRegistry.java b/songdbj/javazoom/jl/player/FactoryRegistry.java
new file mode 100644
index 0000000000..8919995802
--- /dev/null
+++ b/songdbj/javazoom/jl/player/FactoryRegistry.java
@@ -0,0 +1,129 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 29/01/00 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.player;
22
23import java.util.Enumeration;
24import java.util.Hashtable;
25
26import javazoom.jl.decoder.JavaLayerException;
27
28/**
29 * The <code>FactoryRegistry</code> class stores the factories
30 * for all the audio device implementations available in the system.
31 * <p>
32 * Instances of this class are thread-safe.
33 *
34 * @since 0.0.8
35 * @author Mat McGowan
36 */
37
38public class FactoryRegistry extends AudioDeviceFactory
39{
40 static private FactoryRegistry instance = null;
41
42 static synchronized public FactoryRegistry systemRegistry()
43 {
44 if (instance==null)
45 {
46 instance = new FactoryRegistry();
47 instance.registerDefaultFactories();
48 }
49 return instance;
50 }
51
52
53 protected Hashtable factories = new Hashtable();
54
55 /**
56 * Registers an <code>AudioDeviceFactory</code> instance
57 * with this registry.
58 */
59 public void addFactory(AudioDeviceFactory factory)
60 {
61 factories.put(factory.getClass(), factory);
62 }
63
64 public void removeFactoryType(Class cls)
65 {
66 factories.remove(cls);
67 }
68
69 public void removeFactory(AudioDeviceFactory factory)
70 {
71 factories.remove(factory.getClass());
72 }
73
74 public AudioDevice createAudioDevice() throws JavaLayerException
75 {
76 AudioDevice device = null;
77 AudioDeviceFactory[] factories = getFactoriesPriority();
78
79 if (factories==null)
80 throw new JavaLayerException(this+": no factories registered");
81
82 JavaLayerException lastEx = null;
83 for (int i=0; (device==null) && (i<factories.length); i++)
84 {
85 try
86 {
87 device = factories[i].createAudioDevice();
88 }
89 catch (JavaLayerException ex)
90 {
91 lastEx = ex;
92 }
93 }
94
95 if (device==null && lastEx!=null)
96 {
97 throw new JavaLayerException("Cannot create AudioDevice", lastEx);
98 }
99
100 return device;
101 }
102
103
104 protected AudioDeviceFactory[] getFactoriesPriority()
105 {
106 AudioDeviceFactory[] fa = null;
107 synchronized (factories)
108 {
109 int size = factories.size();
110 if (size!=0)
111 {
112 fa = new AudioDeviceFactory[size];
113 int idx = 0;
114 Enumeration e = factories.elements();
115 while (e.hasMoreElements())
116 {
117 AudioDeviceFactory factory = (AudioDeviceFactory)e.nextElement();
118 fa[idx++] = factory;
119 }
120 }
121 }
122 return fa;
123 }
124
125 protected void registerDefaultFactories()
126 {
127 addFactory(new JavaSoundAudioDeviceFactory());
128 }
129}
diff --git a/songdbj/javazoom/jl/player/JavaSoundAudioDevice.java b/songdbj/javazoom/jl/player/JavaSoundAudioDevice.java
new file mode 100644
index 0000000000..caa92cd6fc
--- /dev/null
+++ b/songdbj/javazoom/jl/player/JavaSoundAudioDevice.java
@@ -0,0 +1,215 @@
1/*
2 * 11/26/04 Buffer size modified to support JRE 1.5 optimizations.
3 * (CPU usage < 1% under P4/2Ghz, RAM < 12MB).
4 * jlayer@javazoom.net
5 * 11/19/04 1.0 moved to LGPL.
6 * 06/04/01 Too fast playback fixed. mdm@techie.com
7 * 29/01/00 Initial version. mdm@techie.com
8 *-----------------------------------------------------------------------
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Library General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *----------------------------------------------------------------------
23 */
24
25package javazoom.jl.player;
26
27import javax.sound.sampled.AudioFormat;
28import javax.sound.sampled.AudioSystem;
29import javax.sound.sampled.DataLine;
30import javax.sound.sampled.Line;
31import javax.sound.sampled.LineUnavailableException;
32import javax.sound.sampled.SourceDataLine;
33
34import javazoom.jl.decoder.Decoder;
35import javazoom.jl.decoder.JavaLayerException;
36
37/**
38 * The <code>JavaSoundAudioDevice</code> implements an audio
39 * device by using the JavaSound API.
40 *
41 * @since 0.0.8
42 * @author Mat McGowan
43 */
44public class JavaSoundAudioDevice extends AudioDeviceBase
45{
46 private SourceDataLine source = null;
47
48 private AudioFormat fmt = null;
49
50 private byte[] byteBuf = new byte[4096];
51
52 protected void setAudioFormat(AudioFormat fmt0)
53 {
54 fmt = fmt0;
55 }
56
57 protected AudioFormat getAudioFormat()
58 {
59 if (fmt==null)
60 {
61 Decoder decoder = getDecoder();
62 fmt = new AudioFormat(decoder.getOutputFrequency(),
63 16,
64 decoder.getOutputChannels(),
65 true,
66 false);
67 }
68 return fmt;
69 }
70
71 protected DataLine.Info getSourceLineInfo()
72 {
73 AudioFormat fmt = getAudioFormat();
74 //DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt, 4000);
75 DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt);
76 return info;
77 }
78
79 public void open(AudioFormat fmt) throws JavaLayerException
80 {
81 if (!isOpen())
82 {
83 setAudioFormat(fmt);
84 openImpl();
85 setOpen(true);
86 }
87 }
88
89 protected void openImpl()
90 throws JavaLayerException
91 {
92 }
93
94
95 // createSource fix.
96 protected void createSource() throws JavaLayerException
97 {
98 Throwable t = null;
99 try
100 {
101 Line line = AudioSystem.getLine(getSourceLineInfo());
102 if (line instanceof SourceDataLine)
103 {
104 source = (SourceDataLine)line;
105 //source.open(fmt, millisecondsToBytes(fmt, 2000));
106 source.open(fmt);
107 /*
108 if (source.isControlSupported(FloatControl.Type.MASTER_GAIN))
109 {
110 FloatControl c = (FloatControl)source.getControl(FloatControl.Type.MASTER_GAIN);
111 c.setValue(c.getMaximum());
112 }*/
113 source.start();
114
115 }
116 } catch (RuntimeException ex)
117 {
118 t = ex;
119 }
120 catch (LinkageError ex)
121 {
122 t = ex;
123 }
124 catch (LineUnavailableException ex)
125 {
126 t = ex;
127 }
128 if (source==null) throw new JavaLayerException("cannot obtain source audio line", t);
129 }
130
131 public int millisecondsToBytes(AudioFormat fmt, int time)
132 {
133 return (int)(time*(fmt.getSampleRate()*fmt.getChannels()*fmt.getSampleSizeInBits())/8000.0);
134 }
135
136 protected void closeImpl()
137 {
138 if (source!=null)
139 {
140 source.close();
141 }
142 }
143
144 protected void writeImpl(short[] samples, int offs, int len)
145 throws JavaLayerException
146 {
147 if (source==null)
148 createSource();
149
150 byte[] b = toByteArray(samples, offs, len);
151 source.write(b, 0, len*2);
152 }
153
154 protected byte[] getByteArray(int length)
155 {
156 if (byteBuf.length < length)
157 {
158 byteBuf = new byte[length+1024];
159 }
160 return byteBuf;
161 }
162
163 protected byte[] toByteArray(short[] samples, int offs, int len)
164 {
165 byte[] b = getByteArray(len*2);
166 int idx = 0;
167 short s;
168 while (len-- > 0)
169 {
170 s = samples[offs++];
171 b[idx++] = (byte)s;
172 b[idx++] = (byte)(s>>>8);
173 }
174 return b;
175 }
176
177 protected void flushImpl()
178 {
179 if (source!=null)
180 {
181 source.drain();
182 }
183 }
184
185 public int getPosition()
186 {
187 int pos = 0;
188 if (source!=null)
189 {
190 pos = (int)(source.getMicrosecondPosition()/1000);
191 }
192 return pos;
193 }
194
195 /**
196 * Runs a short test by playing a short silent sound.
197 */
198 public void test()
199 throws JavaLayerException
200 {
201 try
202 {
203 open(new AudioFormat(22050, 16, 1, true, false));
204 short[] data = new short[22050/10];
205 write(data, 0, data.length);
206 flush();
207 close();
208 }
209 catch (RuntimeException ex)
210 {
211 throw new JavaLayerException("Device test failed: "+ex);
212 }
213
214 }
215}
diff --git a/songdbj/javazoom/jl/player/JavaSoundAudioDeviceFactory.java b/songdbj/javazoom/jl/player/JavaSoundAudioDeviceFactory.java
new file mode 100644
index 0000000000..92af492f65
--- /dev/null
+++ b/songdbj/javazoom/jl/player/JavaSoundAudioDeviceFactory.java
@@ -0,0 +1,85 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 29/01/00 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.player;
22
23import javazoom.jl.decoder.JavaLayerException;
24
25/**
26 * This class is responsible for creating instances of the
27 * JavaSoundAudioDevice. The audio device implementation is loaded
28 * and tested dynamically as not all systems will have support
29 * for JavaSound, or they may have the incorrect version.
30 */
31public class JavaSoundAudioDeviceFactory extends AudioDeviceFactory
32{
33 private boolean tested = false;
34
35 static private final String DEVICE_CLASS_NAME = "javazoom.jl.player.JavaSoundAudioDevice";
36
37 public synchronized AudioDevice createAudioDevice()
38 throws JavaLayerException
39 {
40 if (!tested)
41 {
42 testAudioDevice();
43 tested = true;
44 }
45
46 try
47 {
48 return createAudioDeviceImpl();
49 }
50 catch (Exception ex)
51 {
52 throw new JavaLayerException("unable to create JavaSound device: "+ex);
53 }
54 catch (LinkageError ex)
55 {
56 throw new JavaLayerException("unable to create JavaSound device: "+ex);
57 }
58 }
59
60 protected JavaSoundAudioDevice createAudioDeviceImpl()
61 throws JavaLayerException
62 {
63 ClassLoader loader = getClass().getClassLoader();
64 try
65 {
66 JavaSoundAudioDevice dev = (JavaSoundAudioDevice)instantiate(loader, DEVICE_CLASS_NAME);
67 return dev;
68 }
69 catch (Exception ex)
70 {
71 throw new JavaLayerException("Cannot create JavaSound device", ex);
72 }
73 catch (LinkageError ex)
74 {
75 throw new JavaLayerException("Cannot create JavaSound device", ex);
76 }
77
78 }
79
80 public void testAudioDevice() throws JavaLayerException
81 {
82 JavaSoundAudioDevice dev = createAudioDeviceImpl();
83 dev.test();
84 }
85}
diff --git a/songdbj/javazoom/jl/player/NullAudioDevice.java b/songdbj/javazoom/jl/player/NullAudioDevice.java
new file mode 100644
index 0000000000..4145feecd4
--- /dev/null
+++ b/songdbj/javazoom/jl/player/NullAudioDevice.java
@@ -0,0 +1,37 @@
1/*
2 * 11/19/04 1.0 moved o LGPL.
3 * 29/01/00 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.player;
22
23/**
24 * The <code>NullAudioDevice</code> implements a silent, no-op
25 * audio device. This is useful for testing purposes.
26 *
27 * @since 0.0.8
28 * @author Mat McGowan
29 */
30public class NullAudioDevice extends AudioDeviceBase
31{
32
33 public int getPosition()
34 {
35 return 0;
36 }
37}
diff --git a/songdbj/javazoom/jl/player/Player.java b/songdbj/javazoom/jl/player/Player.java
new file mode 100644
index 0000000000..32fb1f3051
--- /dev/null
+++ b/songdbj/javazoom/jl/player/Player.java
@@ -0,0 +1,251 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 29/01/00 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.player;
22
23import java.io.InputStream;
24
25import javazoom.jl.decoder.Bitstream;
26import javazoom.jl.decoder.BitstreamException;
27import javazoom.jl.decoder.Decoder;
28import javazoom.jl.decoder.Header;
29import javazoom.jl.decoder.JavaLayerException;
30import javazoom.jl.decoder.SampleBuffer;
31
32/**
33 * The <code>Player</code> class implements a simple player for playback
34 * of an MPEG audio stream.
35 *
36 * @author Mat McGowan
37 * @since 0.0.8
38 */
39
40// REVIEW: the audio device should not be opened until the
41// first MPEG audio frame has been decoded.
42public class Player
43{
44 /**
45 * The current frame number.
46 */
47 private int frame = 0;
48
49 /**
50 * The MPEG audio bitstream.
51 */
52 // javac blank final bug.
53 /*final*/ private Bitstream bitstream;
54
55 /**
56 * The MPEG audio decoder.
57 */
58 /*final*/ private Decoder decoder;
59
60 /**
61 * The AudioDevice the audio samples are written to.
62 */
63 private AudioDevice audio;
64
65 /**
66 * Has the player been closed?
67 */
68 private boolean closed = false;
69
70 /**
71 * Has the player played back all frames from the stream?
72 */
73 private boolean complete = false;
74
75 private int lastPosition = 0;
76
77 /**
78 * Creates a new <code>Player</code> instance.
79 */
80 public Player(InputStream stream) throws JavaLayerException
81 {
82 this(stream, null);
83 }
84
85 public Player(InputStream stream, AudioDevice device) throws JavaLayerException
86 {
87 bitstream = new Bitstream(stream);
88 decoder = new Decoder();
89
90 if (device!=null)
91 {
92 audio = device;
93 }
94 else
95 {
96 FactoryRegistry r = FactoryRegistry.systemRegistry();
97 audio = r.createAudioDevice();
98 }
99 audio.open(decoder);
100 }
101
102 public void play() throws JavaLayerException
103 {
104 play(Integer.MAX_VALUE);
105 }
106
107 /**
108 * Plays a number of MPEG audio frames.
109 *
110 * @param frames The number of frames to play.
111 * @return true if the last frame was played, or false if there are
112 * more frames.
113 */
114 public boolean play(int frames) throws JavaLayerException
115 {
116 boolean ret = true;
117
118 while (frames-- > 0 && ret)
119 {
120 ret = decodeFrame();
121 }
122
123 if (!ret)
124 {
125 // last frame, ensure all data flushed to the audio device.
126 AudioDevice out = audio;
127 if (out!=null)
128 {
129 out.flush();
130 synchronized (this)
131 {
132 complete = (!closed);
133 close();
134 }
135 }
136 }
137 return ret;
138 }
139
140 /**
141 * Cloases this player. Any audio currently playing is stopped
142 * immediately.
143 */
144 public synchronized void close()
145 {
146 AudioDevice out = audio;
147 if (out!=null)
148 {
149 closed = true;
150 audio = null;
151 // this may fail, so ensure object state is set up before
152 // calling this method.
153 out.close();
154 lastPosition = out.getPosition();
155 try
156 {
157 bitstream.close();
158 }
159 catch (BitstreamException ex)
160 {
161 }
162 }
163 }
164
165 /**
166 * Returns the completed status of this player.
167 *
168 * @return true if all available MPEG audio frames have been
169 * decoded, or false otherwise.
170 */
171 public synchronized boolean isComplete()
172 {
173 return complete;
174 }
175
176 /**
177 * Retrieves the position in milliseconds of the current audio
178 * sample being played. This method delegates to the <code>
179 * AudioDevice</code> that is used by this player to sound
180 * the decoded audio samples.
181 */
182 public int getPosition()
183 {
184 int position = lastPosition;
185
186 AudioDevice out = audio;
187 if (out!=null)
188 {
189 position = out.getPosition();
190 }
191 return position;
192 }
193
194 /**
195 * Decodes a single frame.
196 *
197 * @return true if there are no more frames to decode, false otherwise.
198 */
199 protected boolean decodeFrame() throws JavaLayerException
200 {
201 try
202 {
203 AudioDevice out = audio;
204 if (out==null)
205 return false;
206
207 Header h = bitstream.readFrame();
208
209 if (h==null)
210 return false;
211
212 // sample buffer set when decoder constructed
213 SampleBuffer output = (SampleBuffer)decoder.decodeFrame(h, bitstream);
214
215 synchronized (this)
216 {
217 out = audio;
218 if (out!=null)
219 {
220 out.write(output.getBuffer(), 0, output.getBufferLength());
221 }
222 }
223
224 bitstream.closeFrame();
225 }
226 catch (RuntimeException ex)
227 {
228 throw new JavaLayerException("Exception decoding audio frame", ex);
229 }
230/*
231 catch (IOException ex)
232 {
233 System.out.println("exception decoding audio frame: "+ex);
234 return false;
235 }
236 catch (BitstreamException bitex)
237 {
238 System.out.println("exception decoding audio frame: "+bitex);
239 return false;
240 }
241 catch (DecoderException decex)
242 {
243 System.out.println("exception decoding audio frame: "+decex);
244 return false;
245 }
246*/
247 return true;
248 }
249
250
251}
diff --git a/songdbj/javazoom/jl/player/PlayerApplet.java b/songdbj/javazoom/jl/player/PlayerApplet.java
new file mode 100644
index 0000000000..d7c7dc2ffc
--- /dev/null
+++ b/songdbj/javazoom/jl/player/PlayerApplet.java
@@ -0,0 +1,246 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 * 29/01/00 Initial version. mdm@techie.com
4 *-----------------------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *----------------------------------------------------------------------
19 */
20
21package javazoom.jl.player;
22
23import java.applet.Applet;
24import java.io.IOException;
25import java.io.InputStream;
26import java.net.URL;
27
28import javazoom.jl.decoder.JavaLayerException;
29
30/**
31 * A simple applet that plays an MPEG audio file.
32 * The URL (relative to the document base)
33 * is passed as the "audioURL" parameter.
34 *
35 * @author Mat McGowan
36 * @since 0.0.8
37 */
38public class PlayerApplet extends Applet implements Runnable
39{
40 static public final String AUDIO_PARAMETER = "audioURL";
41
42 /**
43 * The Player used to play the MPEG audio file.
44 */
45 private Player player = null;
46
47 /**
48 * The thread that runs the player.
49 */
50 private Thread playerThread = null;
51
52 private String fileName = null;
53
54
55 /**
56 * Retrieves the <code>AudioDevice</code> instance that will
57 * be used to sound the audio data.
58 *
59 * @return an audio device instance that will be used to
60 * sound the audio stream.
61 */
62 protected AudioDevice getAudioDevice() throws JavaLayerException
63 {
64 return FactoryRegistry.systemRegistry().createAudioDevice();
65 }
66
67 /**
68 * Retrieves the InputStream that provides the MPEG audio
69 * stream data.
70 *
71 * @return an InputStream from which the MPEG audio data
72 * is read, or null if an error occurs.
73 */
74 protected InputStream getAudioStream()
75 {
76 InputStream in = null;
77
78 try
79 {
80 URL url = getAudioURL();
81 if (url!=null)
82 in = url.openStream();
83 }
84 catch (IOException ex)
85 {
86 System.err.println(ex);
87 }
88 return in;
89 }
90
91 protected String getAudioFileName()
92 {
93 String urlString = fileName;
94 if (urlString==null)
95 {
96 urlString = getParameter(AUDIO_PARAMETER);
97 }
98 return urlString;
99 }
100
101 protected URL getAudioURL()
102 {
103 String urlString = getAudioFileName();
104 URL url = null;
105 if (urlString!=null)
106 {
107 try
108 {
109 url = new URL(getDocumentBase(), urlString);
110 }
111 catch (Exception ex)
112 {
113 System.err.println(ex);
114 }
115 }
116 return url;
117 }
118
119 /**
120 * Sets the URL of the audio stream to play.
121 */
122 public void setFileName(String name)
123 {
124 fileName = name;
125 }
126
127 public String getFileName()
128 {
129 return fileName;
130 }
131
132 /**
133 * Stops the audio player. If the player is already stopped
134 * this method is a no-op.
135 */
136 protected void stopPlayer() throws JavaLayerException
137 {
138 if (player!=null)
139 {
140 player.close();
141 player = null;
142 playerThread = null;
143 }
144 }
145
146 /**
147 * Decompresses audio data from an InputStream and plays it
148 * back through an AudioDevice. The playback is run on a newly
149 * created thread.
150 *
151 * @param in The InputStream that provides the MPEG audio data.
152 * @param dev The AudioDevice to use to sound the decompressed data.
153 *
154 * @throws JavaLayerException if there was a problem decoding
155 * or playing the audio data.
156 */
157 protected void play(InputStream in, AudioDevice dev) throws JavaLayerException
158 {
159 stopPlayer();
160
161 if (in!=null && dev!=null)
162 {
163 player = new Player(in, dev);
164 playerThread = createPlayerThread();
165 playerThread.start();
166 }
167 }
168
169 /**
170 * Creates a new thread used to run the audio player.
171 * @return A new Thread that, once started, runs the audio player.
172 */
173 protected Thread createPlayerThread()
174 {
175 return new Thread(this, "Audio player thread");
176 }
177
178 /**
179 * Initializes this applet.
180 */
181 public void init()
182 {
183 }
184
185 /**
186 * Starts this applet. An input stream and audio device
187 * are created and passed to the play() method.
188 */
189 public void start()
190 {
191 String name = getAudioFileName();
192 try
193 {
194 InputStream in = getAudioStream();
195 AudioDevice dev = getAudioDevice();
196 play(in, dev);
197 }
198 catch (JavaLayerException ex)
199 {
200 synchronized (System.err)
201 {
202 System.err.println("Unable to play "+name);
203 ex.printStackTrace(System.err);
204 }
205 }
206 }
207
208 /**
209 * Stops this applet. If audio is currently playing, it is
210 * stopped.
211 */
212 public void stop()
213 {
214 try
215 {
216 stopPlayer();
217 }
218 catch (JavaLayerException ex)
219 {
220 System.err.println(ex);
221 }
222 }
223
224 public void destroy()
225 {
226 }
227
228 /**
229 * The run method for the audio player thread. Simply calls
230 * play() on the player to play the entire stream.
231 */
232 public void run()
233 {
234 if (player!=null)
235 {
236 try
237 {
238 player.play();
239 }
240 catch (JavaLayerException ex)
241 {
242 System.err.println("Problem playing audio: "+ex);
243 }
244 }
245 }
246}
diff --git a/songdbj/javazoom/jl/player/advanced/AdvancedPlayer.java b/songdbj/javazoom/jl/player/advanced/AdvancedPlayer.java
new file mode 100644
index 0000000000..45a31e46e1
--- /dev/null
+++ b/songdbj/javazoom/jl/player/advanced/AdvancedPlayer.java
@@ -0,0 +1,242 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *-----------------------------------------------------------------------
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *----------------------------------------------------------------------
18 */
19
20package javazoom.jl.player.advanced;
21
22import java.io.InputStream;
23
24import javazoom.jl.decoder.Bitstream;
25import javazoom.jl.decoder.BitstreamException;
26import javazoom.jl.decoder.Decoder;
27import javazoom.jl.decoder.Header;
28import javazoom.jl.decoder.JavaLayerException;
29import javazoom.jl.decoder.SampleBuffer;
30import javazoom.jl.player.AudioDevice;
31import javazoom.jl.player.FactoryRegistry;
32
33/**
34 * a hybrid of javazoom.jl.player.Player tweeked to include <code>play(startFrame, endFrame)</code>
35 * hopefully this will be included in the api
36 */
37public class AdvancedPlayer
38{
39 /** The MPEG audio bitstream.*/
40 private Bitstream bitstream;
41 /** The MPEG audio decoder. */
42 private Decoder decoder;
43 /** The AudioDevice the audio samples are written to. */
44 private AudioDevice audio;
45 /** Has the player been closed? */
46 private boolean closed = false;
47 /** Has the player played back all frames from the stream? */
48 private boolean complete = false;
49 private int lastPosition = 0;
50 /** Listener for the playback process */
51 private PlaybackListener listener;
52
53 /**
54 * Creates a new <code>Player</code> instance.
55 */
56 public AdvancedPlayer(InputStream stream) throws JavaLayerException
57 {
58 this(stream, null);
59 }
60
61 public AdvancedPlayer(InputStream stream, AudioDevice device) throws JavaLayerException
62 {
63 bitstream = new Bitstream(stream);
64
65 if (device!=null) audio = device;
66 else audio = FactoryRegistry.systemRegistry().createAudioDevice();
67 audio.open(decoder = new Decoder());
68 }
69
70 public void play() throws JavaLayerException
71 {
72 play(Integer.MAX_VALUE);
73 }
74
75 /**
76 * Plays a number of MPEG audio frames.
77 *
78 * @param frames The number of frames to play.
79 * @return true if the last frame was played, or false if there are
80 * more frames.
81 */
82 public boolean play(int frames) throws JavaLayerException
83 {
84 boolean ret = true;
85
86 // report to listener
87 if(listener != null) listener.playbackStarted(createEvent(PlaybackEvent.STARTED));
88
89 while (frames-- > 0 && ret)
90 {
91 ret = decodeFrame();
92 }
93
94// if (!ret)
95 {
96 // last frame, ensure all data flushed to the audio device.
97 AudioDevice out = audio;
98 if (out != null)
99 {
100// System.out.println(audio.getPosition());
101 out.flush();
102// System.out.println(audio.getPosition());
103 synchronized (this)
104 {
105 complete = (!closed);
106 close();
107 }
108
109 // report to listener
110 if(listener != null) listener.playbackFinished(createEvent(out, PlaybackEvent.STOPPED));
111 }
112 }
113 return ret;
114 }
115
116 /**
117 * Cloases this player. Any audio currently playing is stopped
118 * immediately.
119 */
120 public synchronized void close()
121 {
122 AudioDevice out = audio;
123 if (out != null)
124 {
125 closed = true;
126 audio = null;
127 // this may fail, so ensure object state is set up before
128 // calling this method.
129 out.close();
130 lastPosition = out.getPosition();
131 try
132 {
133 bitstream.close();
134 }
135 catch (BitstreamException ex)
136 {}
137 }
138 }
139
140 /**
141 * Decodes a single frame.
142 *
143 * @return true if there are no more frames to decode, false otherwise.
144 */
145 protected boolean decodeFrame() throws JavaLayerException
146 {
147 try
148 {
149 AudioDevice out = audio;
150 if (out == null) return false;
151
152 Header h = bitstream.readFrame();
153 if (h == null) return false;
154
155 // sample buffer set when decoder constructed
156 SampleBuffer output = (SampleBuffer) decoder.decodeFrame(h, bitstream);
157
158 synchronized (this)
159 {
160 out = audio;
161 if(out != null)
162 {
163 out.write(output.getBuffer(), 0, output.getBufferLength());
164 }
165 }
166
167 bitstream.closeFrame();
168 }
169 catch (RuntimeException ex)
170 {
171 throw new JavaLayerException("Exception decoding audio frame", ex);
172 }
173 return true;
174 }
175
176 /**
177 * skips over a single frame
178 * @return false if there are no more frames to decode, true otherwise.
179 */
180 protected boolean skipFrame() throws JavaLayerException
181 {
182 Header h = bitstream.readFrame();
183 if (h == null) return false;
184 bitstream.closeFrame();
185 return true;
186 }
187
188 /**
189 * Plays a range of MPEG audio frames
190 * @param start The first frame to play
191 * @param end The last frame to play
192 * @return true if the last frame was played, or false if there are more frames.
193 */
194 public boolean play(final int start, final int end) throws JavaLayerException
195 {
196 boolean ret = true;
197 int offset = start;
198 while (offset-- > 0 && ret) ret = skipFrame();
199 return play(end - start);
200 }
201
202 /**
203 * Constructs a <code>PlaybackEvent</code>
204 */
205 private PlaybackEvent createEvent(int id)
206 {
207 return createEvent(audio, id);
208 }
209
210 /**
211 * Constructs a <code>PlaybackEvent</code>
212 */
213 private PlaybackEvent createEvent(AudioDevice dev, int id)
214 {
215 return new PlaybackEvent(this, id, dev.getPosition());
216 }
217
218 /**
219 * sets the <code>PlaybackListener</code>
220 */
221 public void setPlayBackListener(PlaybackListener listener)
222 {
223 this.listener = listener;
224 }
225
226 /**
227 * gets the <code>PlaybackListener</code>
228 */
229 public PlaybackListener getPlayBackListener()
230 {
231 return listener;
232 }
233
234 /**
235 * closes the player and notifies <code>PlaybackListener</code>
236 */
237 public void stop()
238 {
239 listener.playbackFinished(createEvent(PlaybackEvent.STOPPED));
240 close();
241 }
242} \ No newline at end of file
diff --git a/songdbj/javazoom/jl/player/advanced/PlaybackEvent.java b/songdbj/javazoom/jl/player/advanced/PlaybackEvent.java
new file mode 100644
index 0000000000..08e3cae958
--- /dev/null
+++ b/songdbj/javazoom/jl/player/advanced/PlaybackEvent.java
@@ -0,0 +1,51 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *-----------------------------------------------------------------------
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *----------------------------------------------------------------------
18 */
19
20package javazoom.jl.player.advanced;
21
22/**
23 * An event which indicates a <code>Player</code> has performed an 'playback action'
24 * @author Paul Stanton (http://wanto.f2o.org/)
25 */
26public class PlaybackEvent
27{
28 public static int STOPPED = 1;
29 public static int STARTED = 2;
30
31 private AdvancedPlayer source;
32 private int frame;
33 private int id;
34
35 public PlaybackEvent(AdvancedPlayer source, int id, int frame)
36 {
37 this.id = id;
38 this.source = source;
39 this.frame = frame;
40 }
41
42 public int getId(){return id;}
43 public void setId(int id){this.id = id;}
44
45 public int getFrame(){return frame;}
46 public void setFrame(int frame){this.frame = frame;}
47
48 public AdvancedPlayer getSource(){return source;}
49 public void setSource(AdvancedPlayer source){this.source = source;}
50
51}
diff --git a/songdbj/javazoom/jl/player/advanced/PlaybackListener.java b/songdbj/javazoom/jl/player/advanced/PlaybackListener.java
new file mode 100644
index 0000000000..9b042988b8
--- /dev/null
+++ b/songdbj/javazoom/jl/player/advanced/PlaybackListener.java
@@ -0,0 +1,30 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *-----------------------------------------------------------------------
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *----------------------------------------------------------------------
18 */
19
20package javazoom.jl.player.advanced;
21
22/**
23 * Listener for javalayer Player playback
24 * @author Paul Stanton (http://wanto.f2o.org/)
25 */
26public abstract class PlaybackListener
27{
28 public void playbackStarted(PlaybackEvent evt){}
29 public void playbackFinished(PlaybackEvent evt){}
30}
diff --git a/songdbj/javazoom/jl/player/advanced/jlap.java b/songdbj/javazoom/jl/player/advanced/jlap.java
new file mode 100644
index 0000000000..beedea6716
--- /dev/null
+++ b/songdbj/javazoom/jl/player/advanced/jlap.java
@@ -0,0 +1,116 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *-----------------------------------------------------------------------
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *----------------------------------------------------------------------
18 */
19
20package javazoom.jl.player.advanced;
21
22import java.io.BufferedInputStream;
23import java.io.File;
24import java.io.FileInputStream;
25import java.io.IOException;
26import java.io.InputStream;
27
28import javazoom.jl.decoder.JavaLayerException;
29
30/**
31 * This class implements a sample player using Playback listener.
32 */
33public class jlap
34{
35
36 public static void main(String[] args)
37 {
38 jlap test = new jlap();
39 if (args.length != 1)
40 {
41 test.showUsage();
42 System.exit(0);
43 }
44 else
45 {
46 try
47 {
48 test.play(args[0]);
49 }
50 catch (Exception ex)
51 {
52 System.err.println(ex.getMessage());
53 System.exit(0);
54 }
55 }
56 }
57
58 public void play(String filename) throws JavaLayerException, IOException
59 {
60 InfoListener lst = new InfoListener();
61 playMp3(new File(filename), lst);
62 }
63
64 public void showUsage()
65 {
66 System.out.println("Usage: jla <filename>");
67 System.out.println("");
68 System.out.println(" e.g. : java javazoom.jl.player.advanced.jlap localfile.mp3");
69 }
70
71 public static AdvancedPlayer playMp3(File mp3, PlaybackListener listener) throws IOException, JavaLayerException
72 {
73 return playMp3(mp3, 0, Integer.MAX_VALUE, listener);
74 }
75
76 public static AdvancedPlayer playMp3(File mp3, int start, int end, PlaybackListener listener) throws IOException, JavaLayerException
77 {
78 return playMp3(new BufferedInputStream(new FileInputStream(mp3)), start, end, listener);
79 }
80
81 public static AdvancedPlayer playMp3(final InputStream is, final int start, final int end, PlaybackListener listener) throws JavaLayerException
82 {
83 final AdvancedPlayer player = new AdvancedPlayer(is);
84 player.setPlayBackListener(listener);
85 // run in new thread
86 new Thread()
87 {
88 public void run()
89 {
90 try
91 {
92 player.play(start, end);
93 }
94 catch (Exception e)
95 {
96 throw new RuntimeException(e.getMessage());
97 }
98 }
99 }.start();
100 return player;
101 }
102
103 public class InfoListener extends PlaybackListener
104 {
105 public void playbackStarted(PlaybackEvent evt)
106 {
107 System.out.println("Play started from frame " + evt.getFrame());
108 }
109
110 public void playbackFinished(PlaybackEvent evt)
111 {
112 System.out.println("Play completed at frame " + evt.getFrame());
113 System.exit(0);
114 }
115 }
116} \ No newline at end of file
diff --git a/songdbj/javazoom/jl/player/jlp.java b/songdbj/javazoom/jl/player/jlp.java
new file mode 100644
index 0000000000..ddb3d5ecca
--- /dev/null
+++ b/songdbj/javazoom/jl/player/jlp.java
@@ -0,0 +1,176 @@
1/*
2 * 11/19/04 1.0 moved to LGPL.
3 *
4 * 06/04/01 Streaming support added. javalayer@javazoom.net
5 *
6 * 29/01/00 Initial version. mdm@techie.com
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.jl.player;
25
26import java.io.BufferedInputStream;
27import java.io.FileInputStream;
28import java.io.IOException;
29import java.io.InputStream;
30import java.net.URL;
31
32import javazoom.jl.decoder.JavaLayerException;
33
34/**
35 * The <code>jlp</code> class implements a simple command-line
36 * player for MPEG audio files.
37 *
38 * @author Mat McGowan (mdm@techie.com)
39 */
40public class jlp
41{
42 private String fFilename = null;
43 private boolean remote = false;
44
45 public static void main(String[] args)
46 {
47 int retval = 0;
48 try
49 {
50 jlp player = createInstance(args);
51 if (player!=null)
52 player.play();
53 }
54 catch (Exception ex)
55 {
56 System.err.println(ex);
57 ex.printStackTrace(System.err);
58 retval = 1;
59 }
60 System.exit(retval);
61 }
62
63 static public jlp createInstance(String[] args)
64 {
65 jlp player = new jlp();
66 if (!player.parseArgs(args))
67 player = null;
68 return player;
69 }
70
71 private jlp()
72 {
73 }
74
75 public jlp(String filename)
76 {
77 init(filename);
78 }
79
80 protected void init(String filename)
81 {
82 fFilename = filename;
83 }
84
85 protected boolean parseArgs(String[] args)
86 {
87 boolean parsed = false;
88 if (args.length == 1)
89 {
90 init(args[0]);
91 parsed = true;
92 remote = false;
93 }
94 else if (args.length == 2)
95 {
96 if (!(args[0].equals("-url")))
97 {
98 showUsage();
99 }
100 else
101 {
102 init(args[1]);
103 parsed = true;
104 remote = true;
105 }
106 }
107 else
108 {
109 showUsage();
110 }
111 return parsed;
112 }
113
114 public void showUsage()
115 {
116 System.out.println("Usage: jlp [-url] <filename>");
117 System.out.println("");
118 System.out.println(" e.g. : java javazoom.jl.player.jlp localfile.mp3");
119 System.out.println(" java javazoom.jl.player.jlp -url http://www.server.com/remotefile.mp3");
120 System.out.println(" java javazoom.jl.player.jlp -url http://www.shoutcastserver.com:8000");
121 }
122
123 public void play()
124 throws JavaLayerException
125 {
126 try
127 {
128 System.out.println("playing "+fFilename+"...");
129 InputStream in = null;
130 if (remote == true) in = getURLInputStream();
131 else in = getInputStream();
132 AudioDevice dev = getAudioDevice();
133 Player player = new Player(in, dev);
134 player.play();
135 }
136 catch (IOException ex)
137 {
138 throw new JavaLayerException("Problem playing file "+fFilename, ex);
139 }
140 catch (Exception ex)
141 {
142 throw new JavaLayerException("Problem playing file "+fFilename, ex);
143 }
144 }
145
146 /**
147 * Playing file from URL (Streaming).
148 */
149 protected InputStream getURLInputStream()
150 throws Exception
151 {
152
153 URL url = new URL(fFilename);
154 InputStream fin = url.openStream();
155 BufferedInputStream bin = new BufferedInputStream(fin);
156 return bin;
157 }
158
159 /**
160 * Playing file from FileInputStream.
161 */
162 protected InputStream getInputStream()
163 throws IOException
164 {
165 FileInputStream fin = new FileInputStream(fFilename);
166 BufferedInputStream bin = new BufferedInputStream(fin);
167 return bin;
168 }
169
170 protected AudioDevice getAudioDevice()
171 throws JavaLayerException
172 {
173 return FactoryRegistry.systemRegistry().createAudioDevice();
174 }
175
176}
diff --git a/songdbj/javazoom/spi/PropertiesContainer.java b/songdbj/javazoom/spi/PropertiesContainer.java
new file mode 100644
index 0000000000..27ed85f904
--- /dev/null
+++ b/songdbj/javazoom/spi/PropertiesContainer.java
@@ -0,0 +1,31 @@
1/*
2 * PropertiesContainer.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.spi;
25
26import java.util.Map;
27
28public interface PropertiesContainer
29{
30 public Map properties();
31}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java b/songdbj/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java
new file mode 100644
index 0000000000..e4e6fed00a
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java
@@ -0,0 +1,334 @@
1/*
2 * DecodedMpegAudioInputStream.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *------------------------------------------------------------------------
22 */
23
24package javazoom.spi.mpeg.sampled.convert;
25import java.io.IOException;
26import java.io.InputStream;
27import java.util.HashMap;
28import java.util.Map;
29
30import javax.sound.sampled.AudioFormat;
31import javax.sound.sampled.AudioInputStream;
32
33import javazoom.jl.decoder.Bitstream;
34import javazoom.jl.decoder.BitstreamException;
35import javazoom.jl.decoder.Decoder;
36import javazoom.jl.decoder.DecoderException;
37import javazoom.jl.decoder.Equalizer;
38import javazoom.jl.decoder.Header;
39import javazoom.jl.decoder.Obuffer;
40import javazoom.spi.PropertiesContainer;
41import javazoom.spi.mpeg.sampled.file.IcyListener;
42import javazoom.spi.mpeg.sampled.file.tag.TagParseEvent;
43import javazoom.spi.mpeg.sampled.file.tag.TagParseListener;
44
45import org.tritonus.share.TDebug;
46import org.tritonus.share.sampled.convert.TAsynchronousFilteredAudioInputStream;
47
48/**
49 * Main decoder.
50 */
51public class DecodedMpegAudioInputStream extends TAsynchronousFilteredAudioInputStream implements PropertiesContainer, TagParseListener
52{
53 private InputStream m_encodedStream;
54 private Bitstream m_bitstream;
55 private Decoder m_decoder;
56 private Equalizer m_equalizer;
57 private float[] m_equalizer_values;
58 private Header m_header;
59 private DMAISObuffer m_oBuffer;
60
61 // Bytes info.
62 private long byteslength = -1;
63 private long currentByte = 0;
64 // Frame info.
65 private int frameslength = -1;
66 private long currentFrame = 0;
67 private int currentFramesize = 0;
68 private int currentBitrate = -1;
69 // Time info.
70 private long currentMicrosecond = 0;
71 // Shoutcast stream info
72 private IcyListener shoutlst = null;
73
74
75 private HashMap properties = null;
76
77 public DecodedMpegAudioInputStream(AudioFormat outputFormat, AudioInputStream inputStream)
78 {
79 super(outputFormat, -1);
80 if (TDebug.TraceAudioConverter)
81 {
82 TDebug.out(">DecodedMpegAudioInputStream(AudioFormat outputFormat, AudioInputStream inputStream)");
83 }
84 try
85 {
86 // Try to find out inputstream length to allow skip.
87 byteslength = inputStream.available();
88 }
89 catch (IOException e)
90 {
91 TDebug.out("DecodedMpegAudioInputStream : Cannot run inputStream.available() : "+e.getMessage());
92 byteslength = -1;
93 }
94 m_encodedStream = inputStream;
95 shoutlst = IcyListener.getInstance();
96 shoutlst.reset();
97 m_bitstream = new Bitstream(inputStream);
98 m_decoder = new Decoder(null);
99 m_equalizer = new Equalizer();
100 m_equalizer_values = new float[32];
101 for (int b=0;b<m_equalizer.getBandCount();b++)
102 {
103 m_equalizer_values[b] = m_equalizer.getBand(b);
104 }
105 m_decoder.setEqualizer(m_equalizer);
106 m_oBuffer = new DMAISObuffer(outputFormat.getChannels());
107 m_decoder.setOutputBuffer(m_oBuffer);
108 try
109 {
110 m_header = m_bitstream.readFrame();
111 if ((m_header != null) && (frameslength == -1) && (byteslength > 0)) frameslength = m_header.max_number_of_frames((int)byteslength);
112 }
113 catch (BitstreamException e)
114 {
115 TDebug.out("DecodedMpegAudioInputStream : Cannot read first frame : "+e.getMessage());
116 byteslength = -1;
117 }
118 properties = new HashMap();
119 }
120
121 /**
122 * Return dynamic properties.
123 *
124 * <ul>
125 * <li><b>mp3.frame</b> [Long], current frame position.
126 * <li><b>mp3.frame.bitrate</b> [Integer], bitrate of the current frame.
127 * <li><b>mp3.frame.size.bytes</b> [Integer], size in bytes of the current frame.
128 * <li><b>mp3.position.byte</b> [Long], current position in bytes in the stream.
129 * <li><b>mp3.position.microseconds</b> [Long], elapsed microseconds.
130 * <li><b>mp3.equalizer</b> float[32], interactive equalizer array, values could be in [-1.0, +1.0].
131 * <li><b>mp3.shoutcast.metadata.key</b> [String], Shoutcast meta key with matching value.
132 * <br>For instance :
133 * <br>mp3.shoutcast.metadata.StreamTitle=Current song playing in stream.
134 * <br>mp3.shoutcast.metadata.StreamUrl=Url info.
135 * </ul>
136 */
137 public Map properties()
138 {
139 properties.put("mp3.frame",new Long(currentFrame));
140 properties.put("mp3.frame.bitrate",new Integer(currentBitrate));
141 properties.put("mp3.frame.size.bytes",new Integer(currentFramesize));
142 properties.put("mp3.position.byte",new Long(currentByte));
143 properties.put("mp3.position.microseconds",new Long(currentMicrosecond));
144 properties.put("mp3.equalizer",m_equalizer_values);
145 // Optionnal shoutcast stream meta-data.
146 if (shoutlst != null)
147 {
148 String surl = shoutlst.getStreamUrl();
149 String stitle = shoutlst.getStreamTitle();
150 if ((stitle != null) && (stitle.trim().length()>0)) properties.put("mp3.shoutcast.metadata.StreamTitle",stitle);
151 if ((surl != null) && (surl.trim().length()>0)) properties.put("mp3.shoutcast.metadata.StreamUrl",surl);
152 }
153 return properties;
154 }
155
156 public void execute()
157 {
158 if (TDebug.TraceAudioConverter) TDebug.out("execute() : begin");
159 try
160 {
161 // Following line hangs when FrameSize is available in AudioFormat.
162 Header header = null;
163 if (m_header == null) header = m_bitstream.readFrame();
164 else header = m_header;
165 if (TDebug.TraceAudioConverter) TDebug.out("execute() : header = "+header);
166 if (header == null)
167 {
168 if (TDebug.TraceAudioConverter)
169 {
170 TDebug.out("header is null (end of mpeg stream)");
171 }
172 getCircularBuffer().close();
173 return;
174 }
175 currentFrame++;
176 currentBitrate = header.bitrate_instant();
177 currentFramesize = header.calculate_framesize();
178 currentByte = currentByte + currentFramesize;
179 currentMicrosecond = (long) (currentFrame* header.ms_per_frame()*1000.0f);
180 for (int b=0;b<m_equalizer_values.length;b++)
181 {
182 m_equalizer.setBand(b,m_equalizer_values[b]);
183 }
184 m_decoder.setEqualizer(m_equalizer);
185 Obuffer decoderOutput = m_decoder.decodeFrame(header, m_bitstream);
186 m_bitstream.closeFrame();
187 getCircularBuffer().write(m_oBuffer.getBuffer(), 0, m_oBuffer.getCurrentBufferSize());
188 m_oBuffer.reset();
189 if (m_header != null) m_header = null;
190 }
191 catch (BitstreamException e)
192 {
193 if (TDebug.TraceAudioConverter)
194 {
195 TDebug.out(e);
196 }
197 }
198 catch (DecoderException e)
199 {
200 if (TDebug.TraceAudioConverter)
201 {
202 TDebug.out(e);
203 }
204 }
205 if (TDebug.TraceAudioConverter) TDebug.out("execute() : end");
206 }
207
208 public long skip(long bytes)
209 {
210 if ((byteslength > 0) && (frameslength > 0))
211 {
212 float ratio = bytes*1.0f/byteslength*1.0f;
213 long bytesread = skipFrames((long) (ratio*frameslength));
214 currentByte = currentByte + bytesread;
215 return bytesread;
216 }
217 else return -1;
218 }
219
220 /**
221 * Skip frames.
222 * You don't need to call it severals times, it will exactly skip given frames number.
223 * @param frames
224 * @return bytes length skipped matching to frames skipped.
225 */
226 public long skipFrames(long frames)
227 {
228 if (TDebug.TraceAudioConverter) TDebug.out("skip(long frames) : begin");
229 int framesRead = 0;
230 int bytesReads = 0;
231 try
232 {
233 for (int i=0;i<frames;i++)
234 {
235 Header header = m_bitstream.readFrame();
236 if (header != null)
237 {
238 int fsize = header.calculate_framesize();
239 bytesReads = bytesReads + fsize;
240 }
241 m_bitstream.closeFrame();
242 framesRead++;
243 }
244 }
245 catch (BitstreamException e)
246 {
247 if (TDebug.TraceAudioConverter) TDebug.out(e);
248 }
249 if (TDebug.TraceAudioConverter) TDebug.out("skip(long frames) : end");
250 currentFrame = currentFrame + framesRead;
251 return bytesReads;
252 }
253
254 private boolean isBigEndian()
255 {
256 return getFormat().isBigEndian();
257 }
258
259 public void close() throws IOException
260 {
261 super.close();
262 m_encodedStream.close();
263 }
264
265 private class DMAISObuffer extends Obuffer
266 {
267 private int m_nChannels;
268 private byte[] m_abBuffer;
269 private int[] m_anBufferPointers;
270 private boolean m_bIsBigEndian;
271 public DMAISObuffer(int nChannels)
272 {
273 m_nChannels = nChannels;
274 m_abBuffer = new byte[OBUFFERSIZE * nChannels];
275 m_anBufferPointers = new int[nChannels];
276 reset();
277 m_bIsBigEndian = DecodedMpegAudioInputStream.this.isBigEndian();
278 }
279 public void append(int nChannel, short sValue)
280 {
281 byte bFirstByte;
282 byte bSecondByte;
283 if (m_bIsBigEndian)
284 {
285 bFirstByte = (byte) ((sValue >>> 8) & 0xFF);
286 bSecondByte = (byte) (sValue & 0xFF);
287 }
288 else // little endian
289 {
290 bFirstByte = (byte) (sValue & 0xFF);
291 bSecondByte = (byte) ((sValue >>> 8) & 0xFF);
292 }
293 m_abBuffer[m_anBufferPointers[nChannel]] = bFirstByte;
294 m_abBuffer[m_anBufferPointers[nChannel] + 1] = bSecondByte;
295 m_anBufferPointers[nChannel] += m_nChannels * 2;
296 }
297 public void set_stop_flag()
298 {
299 }
300 public void close()
301 {
302 }
303 public void write_buffer(int nValue)
304 {
305 }
306 public void clear_buffer()
307 {
308 }
309 public byte[] getBuffer()
310 {
311 return m_abBuffer;
312 }
313 public int getCurrentBufferSize()
314 {
315 return m_anBufferPointers[0];
316 }
317 public void reset()
318 {
319 for (int i = 0; i < m_nChannels; i++)
320 {
321 /* Points to byte location,
322 * implicitely assuming 16 bit
323 * samples.
324 */
325 m_anBufferPointers[i] = i * 2;
326 }
327 }
328 }
329
330 public void tagParsed(TagParseEvent tpe)
331 {
332 System.out.println("TAG:"+tpe.getTag());
333 }
334}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/convert/MpegFormatConversionProvider.java b/songdbj/javazoom/spi/mpeg/sampled/convert/MpegFormatConversionProvider.java
new file mode 100644
index 0000000000..1a3d51d9ad
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/convert/MpegFormatConversionProvider.java
@@ -0,0 +1,120 @@
1/*
2 * MpegFormatConversionProvider.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * ---------------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * --------------------------------------------------------------------------
22 */
23
24
25package javazoom.spi.mpeg.sampled.convert;
26
27
28import java.util.Arrays;
29
30import javax.sound.sampled.AudioFormat;
31import javax.sound.sampled.AudioInputStream;
32import javax.sound.sampled.AudioSystem;
33
34import javazoom.spi.mpeg.sampled.file.MpegEncoding;
35
36import org.tritonus.share.TDebug;
37import org.tritonus.share.sampled.Encodings;
38import org.tritonus.share.sampled.convert.TEncodingFormatConversionProvider;
39
40/**
41 * ConversionProvider for MPEG files.
42 */
43public class MpegFormatConversionProvider extends TEncodingFormatConversionProvider
44{
45 private static final AudioFormat.Encoding MP3 = Encodings.getEncoding("MP3");
46 private static final AudioFormat.Encoding PCM_SIGNED = Encodings.getEncoding("PCM_SIGNED");
47
48 private static final AudioFormat[] INPUT_FORMATS =
49 {
50 // mono
51 new AudioFormat(MP3, -1.0F, -1, 1, -1, -1.0F, false),
52 new AudioFormat(MP3, -1.0F, -1, 1, -1, -1.0F, true),
53 // stereo
54 new AudioFormat(MP3, -1.0F, -1, 2, -1, -1.0F, false),
55 new AudioFormat(MP3, -1.0F, -1, 2, -1, -1.0F, true),
56 };
57
58
59 private static final AudioFormat[] OUTPUT_FORMATS =
60 {
61 // mono, 16 bit signed
62 new AudioFormat(PCM_SIGNED, -1.0F, 16, 1, 2, -1.0F, false),
63 new AudioFormat(PCM_SIGNED, -1.0F, 16, 1, 2, -1.0F, true),
64 // stereo, 16 bit signed
65 new AudioFormat(PCM_SIGNED, -1.0F, 16, 2, 4, -1.0F, false),
66 new AudioFormat(PCM_SIGNED, -1.0F, 16, 2, 4, -1.0F, true),
67 };
68
69 /**
70 * Constructor.
71 */
72 public MpegFormatConversionProvider()
73 {
74 super(Arrays.asList(INPUT_FORMATS), Arrays.asList(OUTPUT_FORMATS));
75 if (TDebug.TraceAudioConverter)
76 {
77 TDebug.out(">MpegFormatConversionProvider()");
78 }
79 }
80
81 public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream audioInputStream)
82 {
83 if (TDebug.TraceAudioConverter)
84 {
85 TDebug.out(">MpegFormatConversionProvider.getAudioInputStream(AudioFormat targetFormat, AudioInputStream audioInputStream):");
86 }
87 return new DecodedMpegAudioInputStream(targetFormat, audioInputStream);
88 }
89
90 /**
91 * Add conversion support for any MpegEncoding source with FrameRate or FrameSize not empty.
92 * @param targetFormat
93 * @param sourceFormat
94 * @return
95 */
96 public boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat)
97 {
98 if (TDebug.TraceAudioConverter)
99 {
100 TDebug.out(">MpegFormatConversionProvider.isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat):");
101 TDebug.out("checking if conversion possible");
102 TDebug.out("from: " + sourceFormat);
103 TDebug.out("to: " + targetFormat);
104 }
105
106 boolean conversion = super.isConversionSupported(targetFormat, sourceFormat);
107 if (conversion == false)
108 {
109 AudioFormat.Encoding enc = sourceFormat.getEncoding();
110 if (enc instanceof MpegEncoding)
111 {
112 if ((sourceFormat.getFrameRate() != AudioSystem.NOT_SPECIFIED) || (sourceFormat.getFrameSize() != AudioSystem.NOT_SPECIFIED))
113 {
114 conversion = true;
115 }
116 }
117 }
118 return conversion;
119 }
120}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/IcyListener.java b/songdbj/javazoom/spi/mpeg/sampled/file/IcyListener.java
new file mode 100644
index 0000000000..8e49e6e2ef
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/IcyListener.java
@@ -0,0 +1,131 @@
1/*
2 * IcyListener.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.spi.mpeg.sampled.file;
25
26import javazoom.spi.mpeg.sampled.file.tag.MP3Tag;
27import javazoom.spi.mpeg.sampled.file.tag.TagParseEvent;
28import javazoom.spi.mpeg.sampled.file.tag.TagParseListener;
29
30/**
31 * This class (singleton) allow to be notified on shoutcast meta data
32 * while playing the stream (such as song title).
33 */
34public class IcyListener implements TagParseListener
35{
36 private static IcyListener instance = null;
37 private MP3Tag lastTag = null;
38 private String streamTitle = null;
39 private String streamUrl = null;
40
41
42 private IcyListener()
43 {
44 super();
45 }
46
47 public static synchronized IcyListener getInstance()
48 {
49 if (instance == null)
50 {
51 instance = new IcyListener();
52 }
53 return instance;
54 }
55
56 /* (non-Javadoc)
57 * @see javazoom.spi.mpeg.sampled.file.tag.TagParseListener#tagParsed(javazoom.spi.mpeg.sampled.file.tag.TagParseEvent)
58 */
59 public void tagParsed(TagParseEvent tpe)
60 {
61 lastTag = tpe.getTag();
62 String name = lastTag.getName();
63 if ((name != null) && (name.equalsIgnoreCase("streamtitle")))
64 {
65 streamTitle = (String) lastTag.getValue();
66 }
67 else if ((name != null) && (name.equalsIgnoreCase("streamurl")))
68 {
69 streamUrl = (String) lastTag.getValue();
70 }
71 }
72
73 /**
74 * @return
75 */
76 public MP3Tag getLastTag()
77 {
78 return lastTag;
79 }
80
81 /**
82 * @param tag
83 */
84 public void setLastTag(MP3Tag tag)
85 {
86 lastTag = tag;
87 }
88
89 /**
90 * @return
91 */
92 public String getStreamTitle()
93 {
94 return streamTitle;
95 }
96
97 /**
98 * @return
99 */
100 public String getStreamUrl()
101 {
102 return streamUrl;
103 }
104
105 /**
106 * @param string
107 */
108 public void setStreamTitle(String string)
109 {
110 streamTitle = string;
111 }
112
113 /**
114 * @param string
115 */
116 public void setStreamUrl(String string)
117 {
118 streamUrl = string;
119 }
120
121 /**
122 * Reset all properties.
123 */
124 public void reset()
125 {
126 lastTag = null;
127 streamTitle = null;
128 streamUrl = null;
129 }
130
131}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileFormat.java b/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileFormat.java
new file mode 100644
index 0000000000..afdc4c5e9c
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileFormat.java
@@ -0,0 +1,103 @@
1/*
2 * MpegAudioFileFormat.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23package javazoom.spi.mpeg.sampled.file;
24
25import java.util.Map;
26
27import javax.sound.sampled.AudioFormat;
28
29import org.tritonus.share.sampled.file.TAudioFileFormat;
30
31/**
32 * @author JavaZOOM
33 */
34public class MpegAudioFileFormat extends TAudioFileFormat
35{
36 /**
37 * Contructor.
38 * @param type
39 * @param audioFormat
40 * @param nLengthInFrames
41 * @param nLengthInBytes
42 */
43 public MpegAudioFileFormat(Type type, AudioFormat audioFormat, int nLengthInFrames, int nLengthInBytes, Map properties)
44 {
45 super(type, audioFormat, nLengthInFrames, nLengthInBytes, properties);
46 }
47
48 /**
49 * MP3 audio file format parameters.
50 * Some parameters might be unavailable. So availability test is required before reading any parameter.
51 *
52 * <br>AudioFileFormat parameters.
53 * <ul>
54 * <li><b>duration</b> [Long], duration in microseconds.
55 * <li><b>title</b> [String], Title of the stream.
56 * <li><b>author</b> [String], Name of the artist of the stream.
57 * <li><b>album</b> [String], Name of the album of the stream.
58 * <li><b>date</b> [String], The date (year) of the recording or release of the stream.
59 * <li><b>copyright</b> [String], Copyright message of the stream.
60 * <li><b>comment</b> [String], Comment of the stream.
61 * </ul>
62 * <br>MP3 parameters.
63 * <ul>
64 * <li><b>mp3.version.mpeg</b> [String], mpeg version : 1,2 or 2.5
65 * <li><b>mp3.version.layer</b> [String], layer version 1, 2 or 3
66 * <li><b>mp3.version.encoding</b> [String], mpeg encoding : MPEG1, MPEG2-LSF, MPEG2.5-LSF
67 * <li><b>mp3.channels</b> [Integer], number of channels 1 : mono, 2 : stereo.
68 * <li><b>mp3.frequency.hz</b> [Integer], sampling rate in hz.
69 * <li><b>mp3.bitrate.nominal.bps</b> [Integer], nominal bitrate in bps.
70 * <li><b>mp3.length.bytes</b> [Integer], length in bytes.
71 * <li><b>mp3.length.frames</b> [Integer], length in frames.
72 * <li><b>mp3.framesize.bytes</b> [Integer], framesize of the first frame. framesize is not constant for VBR streams.
73 * <li><b>mp3.framerate.fps</b> [Float], framerate in frames per seconds.
74 * <li><b>mp3.header.pos</b> [Integer], position of first audio header (or ID3v2 size).
75 * <li><b>mp3.vbr</b> [Boolean], vbr flag.
76 * <li><b>mp3.vbr.scale</b> [Integer], vbr scale.
77 * <li><b>mp3.crc</b> [Boolean], crc flag.
78 * <li><b>mp3.original</b> [Boolean], original flag.
79 * <li><b>mp3.copyright</b> [Boolean], copyright flag.
80 * <li><b>mp3.padding</b> [Boolean], padding flag.
81 * <li><b>mp3.mode</b> [Integer], mode 0:STEREO 1:JOINT_STEREO 2:DUAL_CHANNEL 3:SINGLE_CHANNEL
82 * <li><b>mp3.id3tag.genre</b> [String], ID3 tag (v1 or v2) genre.
83 * <li><b>mp3.id3tag.track</b> [String], ID3 tag (v1 or v2) track info.
84 * <li><b>mp3.id3tag.encoded</b> [String], ID3 tag v2 encoded by info.
85 * <li><b>mp3.id3tag.composer</b> [String], ID3 tag v2 composer info.
86 * <li><b>mp3.id3tag.grouping</b> [String], ID3 tag v2 grouping info.
87 * <li><b>mp3.id3tag.disc</b> [String], ID3 tag v2 track info.
88 * <li><b>mp3.id3tag.v2</b> [InputStream], ID3v2 frames.
89 * <li><b>mp3.id3tag.v2.version</b> [String], ID3v2 major version (2=v2.2.0, 3=v2.3.0, 4=v2.4.0).
90 * <li><b>mp3.shoutcast.metadata.key</b> [String], Shoutcast meta key with matching value.
91 * <br>For instance :
92 * <br>mp3.shoutcast.metadata.icy-irc=#shoutcast
93 * <br>mp3.shoutcast.metadata.icy-metaint=8192
94 * <br>mp3.shoutcast.metadata.icy-genre=Trance Techno Dance
95 * <br>mp3.shoutcast.metadata.icy-url=http://www.di.fm
96 * <br>and so on ...
97 * </ul>
98 */
99 public Map properties()
100 {
101 return super.properties();
102 }
103}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileReader.java b/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileReader.java
new file mode 100644
index 0000000000..54440551a1
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileReader.java
@@ -0,0 +1,772 @@
1/*
2 * MpegAudioFileReader.
3 *
4 * 12/31/04 : mp3spi.weak system property added to skip controls.
5 *
6 * 11/29/04 : ID3v2.2, v2.3 & v2.4 support improved.
7 * "mp3.id3tag.composer" (TCOM/TCM) added
8 * "mp3.id3tag.grouping" (TIT1/TT1) added
9 * "mp3.id3tag.disc" (TPA/TPOS) added
10 * "mp3.id3tag.encoded" (TEN/TENC) added
11 * "mp3.id3tag.v2.version" added
12 *
13 * 11/28/04 : String encoding bug fix in chopSubstring method.
14 *
15 * JavaZOOM : mp3spi@javazoom.net
16 * http://www.javazoom.net
17 *
18 *-----------------------------------------------------------------------
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU Library General Public License as published
21 * by the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU Library General Public License for more details.
28 *
29 * You should have received a copy of the GNU Library General Public
30 * License along with this program; if not, write to the Free Software
31 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 *----------------------------------------------------------------------
33 */
34
35package javazoom.spi.mpeg.sampled.file;
36
37
38import java.io.BufferedInputStream;
39import java.io.File;
40import java.io.FileInputStream;
41import java.io.IOException;
42import java.io.InputStream;
43import java.io.PushbackInputStream;
44import java.io.UnsupportedEncodingException;
45import java.net.URL;
46import java.net.URLConnection;
47import java.security.AccessControlException;
48import java.util.HashMap;
49
50import javax.sound.sampled.AudioFileFormat;
51import javax.sound.sampled.AudioFormat;
52import javax.sound.sampled.AudioInputStream;
53import javax.sound.sampled.AudioSystem;
54import javax.sound.sampled.UnsupportedAudioFileException;
55
56import javazoom.jl.decoder.Bitstream;
57import javazoom.jl.decoder.Header;
58import javazoom.spi.mpeg.sampled.file.tag.IcyInputStream;
59import javazoom.spi.mpeg.sampled.file.tag.MP3Tag;
60
61import org.tritonus.share.TDebug;
62import org.tritonus.share.sampled.file.TAudioFileReader;
63
64/**
65 * This class implements AudioFileReader for MP3 SPI.
66 */
67public class MpegAudioFileReader extends TAudioFileReader
68{
69 private final int SYNC = 0xFFE00000;
70 private String weak = null;
71 private final AudioFormat.Encoding[][] sm_aEncodings =
72 {
73 {MpegEncoding.MPEG2L1, MpegEncoding.MPEG2L2, MpegEncoding.MPEG2L3},
74 {MpegEncoding.MPEG1L1, MpegEncoding.MPEG1L2, MpegEncoding.MPEG1L3},
75 {MpegEncoding.MPEG2DOT5L1, MpegEncoding.MPEG2DOT5L2, MpegEncoding.MPEG2DOT5L3},
76
77 };
78
79 private static final int INITAL_READ_LENGTH = 64000;
80 private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
81
82 private static final String[] id3v1genres = {
83 "Blues"
84 , "Classic Rock"
85 , "Country"
86 , "Dance"
87 , "Disco"
88 , "Funk"
89 , "Grunge"
90 , "Hip-Hop"
91 , "Jazz"
92 , "Metal"
93 , "New Age"
94 , "Oldies"
95 , "Other"
96 , "Pop"
97 , "R&B"
98 , "Rap"
99 , "Reggae"
100 , "Rock"
101 , "Techno"
102 , "Industrial"
103 , "Alternative"
104 , "Ska"
105 , "Death Metal"
106 , "Pranks"
107 , "Soundtrack"
108 , "Euro-Techno"
109 , "Ambient"
110 , "Trip-Hop"
111 , "Vocal"
112 , "Jazz+Funk"
113 , "Fusion"
114 , "Trance"
115 , "Classical"
116 , "Instrumental"
117 , "Acid"
118 , "House"
119 , "Game"
120 , "Sound Clip"
121 , "Gospel"
122 , "Noise"
123 , "AlternRock"
124 , "Bass"
125 , "Soul"
126 , "Punk"
127 , "Space"
128 , "Meditative"
129 , "Instrumental Pop"
130 , "Instrumental Rock"
131 , "Ethnic"
132 , "Gothic"
133 , "Darkwave"
134 , "Techno-Industrial"
135 , "Electronic"
136 , "Pop-Folk"
137 , "Eurodance"
138 , "Dream"
139 , "Southern Rock"
140 , "Comedy"
141 , "Cult"
142 , "Gangsta"
143 , "Top 40"
144 , "Christian Rap"
145 , "Pop/Funk"
146 , "Jungle"
147 , "Native American"
148 , "Cabaret"
149 , "New Wave"
150 , "Psychadelic"
151 , "Rave"
152 , "Showtunes"
153 , "Trailer"
154 , "Lo-Fi"
155 , "Tribal"
156 , "Acid Punk"
157 , "Acid Jazz"
158 , "Polka"
159 , "Retro"
160 , "Musical"
161 , "Rock & Roll"
162 , "Hard Rock"
163 , "Folk"
164 , "Folk-Rock"
165 , "National Folk"
166 , "Swing"
167 , "Fast Fusion"
168 , "Bebob"
169 , "Latin"
170 , "Revival"
171 , "Celtic"
172 , "Bluegrass"
173 , "Avantgarde"
174 , "Gothic Rock"
175 , "Progressive Rock"
176 , "Psychedelic Rock"
177 , "Symphonic Rock"
178 , "Slow Rock"
179 , "Big Band"
180 , "Chorus"
181 , "Easy Listening"
182 , "Acoustic"
183 , "Humour"
184 , "Speech"
185 , "Chanson"
186 , "Opera"
187 , "Chamber Music"
188 , "Sonata"
189 , "Symphony"
190 , "Booty Brass"
191 , "Primus"
192 , "Porn Groove"
193 , "Satire"
194 , "Slow Jam"
195 , "Club"
196 , "Tango"
197 , "Samba"
198 , "Folklore"
199 , "Ballad"
200 , "Power Ballad"
201 , "Rhythmic Soul"
202 , "Freestyle"
203 , "Duet"
204 , "Punk Rock"
205 , "Drum Solo"
206 , "A Capela"
207 , "Euro-House"
208 , "Dance Hall"
209 , "Goa"
210 , "Drum & Bass"
211 , "Club-House"
212 , "Hardcore"
213 , "Terror"
214 , "Indie"
215 , "BritPop"
216 , "Negerpunk"
217 , "Polsk Punk"
218 , "Beat"
219 , "Christian Gangsta Rap"
220 , "Heavy Metal"
221 , "Black Metal"
222 , "Crossover"
223 , "Contemporary Christian"
224 , "Christian Rock"
225 , "Merengue"
226 , "Salsa"
227 , "Thrash Metal"
228 , "Anime"
229 , "JPop"
230 , "SynthPop"
231 };
232
233 public MpegAudioFileReader()
234 {
235 super(MARK_LIMIT, true);
236 if (TDebug.TraceAudioFileReader) TDebug.out(">MpegAudioFileReader(1.9.2-FINAL)");
237 try
238 {
239 weak = System.getProperty("mp3spi.weak");
240 }
241 catch(AccessControlException e)
242 {}
243 }
244
245 /**
246 * Returns AudioFileFormat from File.
247 */
248 public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException
249 {
250 return super.getAudioFileFormat(file);
251 }
252
253 /**
254 * Returns AudioFileFormat from URL.
255 */
256 public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException
257 {
258 if (TDebug.TraceAudioFileReader) {TDebug.out("MpegAudioFileReader.getAudioFileFormat(URL): begin"); }
259 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
260 URLConnection conn = url.openConnection();
261 // Tell shoucast server (if any) that SPI support shoutcast stream.
262 conn.setRequestProperty ("Icy-Metadata", "1");
263 InputStream inputStream = conn.getInputStream();
264 AudioFileFormat audioFileFormat = null;
265 try
266 {
267 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
268 }
269 finally
270 {
271 inputStream.close();
272 }
273 if (TDebug.TraceAudioFileReader) {TDebug.out("MpegAudioFileReader.getAudioFileFormat(URL): end"); }
274 return audioFileFormat;
275 }
276
277 /**
278 * Returns AudioFileFormat from inputstream and medialength.
279 */
280 public AudioFileFormat getAudioFileFormat(InputStream inputStream, long mediaLength) throws UnsupportedAudioFileException, IOException
281 {
282 if (TDebug.TraceAudioFileReader) TDebug.out(">MpegAudioFileReader.getAudioFileFormat(InputStream inputStream, long mediaLength): begin");
283 HashMap aff_properties = new HashMap();
284 HashMap af_properties = new HashMap();
285 int mLength = (int) mediaLength;
286 int size = inputStream.available();
287 PushbackInputStream pis = new PushbackInputStream(inputStream, MARK_LIMIT);
288 byte head[] = new byte[12];
289 pis.read(head);
290 if (TDebug.TraceAudioFileReader)
291 {
292 TDebug.out("InputStream : "+inputStream + " =>" + new String(head));
293 }
294 /*
295 * Check for WAV, AU, and AIFF file formats.
296 *
297 * Next check for Shoutcast (supported) and OGG (unsupported) streams.
298 *
299 * Note -- the check for WAV files will reject Broadcast WAV files.
300 * This may be incorrect as broadcast WAV files may contain MPEG data.
301 * Need to investigate.
302 *
303 */
304 if ((head[0] == 'R') && (head[1] == 'I') && (head[2] == 'F') && (head[3] == 'F') && (head[8] == 'W') && (head[9] == 'A') && (head[10] == 'V') && (head[11] == 'E'))
305 {
306 if (TDebug.TraceAudioFileReader) TDebug.out("WAV stream found");
307 if (weak == null) throw new UnsupportedAudioFileException("WAV stream found");
308 }
309 else if ((head[0] == '.') && (head[1] == 's') && (head[2] == 'n') && (head[3] == 'd'))
310 {
311 if (TDebug.TraceAudioFileReader) TDebug.out("AU stream found");
312 if (weak == null) throw new UnsupportedAudioFileException("AU stream found");
313 }
314 else if ((head[0] == 'F') && (head[1] == 'O') && (head[2] == 'R') && (head[3] == 'M') && (head[8] == 'A') && (head[9] == 'I') && (head[10] == 'F') && (head[11] == 'F'))
315 {
316 if (TDebug.TraceAudioFileReader) TDebug.out("AIFF stream found");
317 if (weak == null) throw new UnsupportedAudioFileException("AIFF stream found");
318 }
319 // Shoutcast stream ?
320 else if (((head[0] == 'I') | (head[0] == 'i')) && ((head[1] == 'C') | (head[1] == 'c')) && ((head[2] == 'Y') | (head[2] == 'y')))
321 {
322 pis.unread(head);
323 // Load shoutcast meta data.
324 loadShoutcastInfo(pis, aff_properties);
325 }
326 // Ogg stream ?
327 else if (((head[0] == 'O') | (head[0] == 'o')) && ((head[1] == 'G') | (head[1] == 'g')) && ((head[2] == 'G') | (head[2] == 'g')))
328 {
329 if (TDebug.TraceAudioFileReader) TDebug.out("Ogg stream found");
330 if (weak == null) throw new UnsupportedAudioFileException("Ogg stream found");
331 }
332 // No, so pushback.
333 else
334 {
335 pis.unread(head);
336 }
337 // MPEG header info.
338 int nVersion = AudioSystem.NOT_SPECIFIED;
339 int nLayer = AudioSystem.NOT_SPECIFIED;
340 int nSFIndex = AudioSystem.NOT_SPECIFIED;
341 int nMode = AudioSystem.NOT_SPECIFIED;
342 int FrameSize = AudioSystem.NOT_SPECIFIED;
343 int nFrameSize = AudioSystem.NOT_SPECIFIED;
344 int nFrequency = AudioSystem.NOT_SPECIFIED;
345 int nTotalFrames = AudioSystem.NOT_SPECIFIED;
346 float FrameRate = AudioSystem.NOT_SPECIFIED;
347 int BitRate = AudioSystem.NOT_SPECIFIED;
348 int nChannels = AudioSystem.NOT_SPECIFIED;
349 int nHeader = AudioSystem.NOT_SPECIFIED;
350 int nTotalMS = AudioSystem.NOT_SPECIFIED;
351 boolean nVBR = false;
352 AudioFormat.Encoding encoding = null;
353 try
354 {
355 Bitstream m_bitstream = new Bitstream(pis);
356 aff_properties.put("mp3.header.pos",new Integer(m_bitstream.header_pos()));
357 Header m_header = m_bitstream.readFrame();
358 // nVersion = 0 => MPEG2-LSF (Including MPEG2.5), nVersion = 1 => MPEG1
359 nVersion = m_header.version();
360 if (nVersion == 2) aff_properties.put("mp3.version.mpeg",Float.toString(2.5f));
361 else aff_properties.put("mp3.version.mpeg",Integer.toString(2-nVersion));
362 // nLayer = 1,2,3
363 nLayer = m_header.layer();
364 aff_properties.put("mp3.version.layer",Integer.toString(nLayer));
365 nSFIndex = m_header.sample_frequency();
366 nMode = m_header.mode();
367 aff_properties.put("mp3.mode",new Integer(nMode));
368 nChannels = nMode == 3 ? 1 : 2;
369 aff_properties.put("mp3.channels",new Integer(nChannels));
370 nVBR = m_header.vbr();
371 af_properties.put("vbr",new Boolean(nVBR));
372 aff_properties.put("mp3.vbr",new Boolean(nVBR));
373 aff_properties.put("mp3.vbr.scale",new Integer(m_header.vbr_scale()));
374 FrameSize = m_header.calculate_framesize();
375 aff_properties.put("mp3.framesize.bytes",new Integer(FrameSize));
376 if (FrameSize < 0) throw new UnsupportedAudioFileException("Invalid FrameSize : " + FrameSize);
377 nFrequency = m_header.frequency();
378 aff_properties.put("mp3.frequency.hz",new Integer(nFrequency));
379 FrameRate = (float) ((1.0 / (m_header.ms_per_frame())) * 1000.0);
380 aff_properties.put("mp3.framerate.fps",new Float(FrameRate));
381 if (FrameRate < 0) throw new UnsupportedAudioFileException("Invalid FrameRate : " + FrameRate);
382 if (mLength != AudioSystem.NOT_SPECIFIED)
383 {
384 aff_properties.put("mp3.length.bytes",new Integer(mLength));
385 nTotalFrames = m_header.max_number_of_frames(mLength);
386 aff_properties.put("mp3.length.frames",new Integer(nTotalFrames));
387 }
388 BitRate = m_header.bitrate();
389 af_properties.put("bitrate",new Integer(BitRate));
390 aff_properties.put("mp3.bitrate.nominal.bps",new Integer(BitRate));
391 nHeader = m_header.getSyncHeader();
392 encoding = sm_aEncodings[nVersion][nLayer - 1];
393 aff_properties.put("mp3.version.encoding",encoding.toString());
394 if (mLength != AudioSystem.NOT_SPECIFIED)
395 {
396 nTotalMS = Math.round(m_header.total_ms(mLength));
397 aff_properties.put("duration",new Long((long)nTotalMS*1000L));
398 }
399 aff_properties.put("mp3.copyright",new Boolean(m_header.copyright()));
400 aff_properties.put("mp3.original",new Boolean(m_header.original()));
401 aff_properties.put("mp3.crc",new Boolean(m_header.checksums()));
402 aff_properties.put("mp3.padding",new Boolean(m_header.padding()));
403 InputStream id3v2 = m_bitstream.getRawID3v2();
404 if (id3v2 != null)
405 {
406 aff_properties.put("mp3.id3tag.v2",id3v2);
407 parseID3v2Frames(id3v2,aff_properties);
408 }
409 if (TDebug.TraceAudioFileReader) TDebug.out(m_header.toString());
410 }
411 catch (Exception e)
412 {
413 if (TDebug.TraceAudioFileReader) TDebug.out("not a MPEG stream:" + e.getMessage());
414 throw new UnsupportedAudioFileException("not a MPEG stream:" + e.getMessage());
415 }
416
417 // Deeper checks ?
418 int cVersion = (nHeader >> 19) & 0x3;
419 if (cVersion == 1)
420 {
421 if (TDebug.TraceAudioFileReader) TDebug.out("not a MPEG stream: wrong version");
422 throw new UnsupportedAudioFileException("not a MPEG stream: wrong version");
423 }
424
425 int cSFIndex = (nHeader >> 10) & 0x3;
426 if (cSFIndex == 3)
427 {
428 if (TDebug.TraceAudioFileReader) TDebug.out("not a MPEG stream: wrong sampling rate");
429 throw new UnsupportedAudioFileException("not a MPEG stream: wrong sampling rate");
430 }
431
432 // Look up for ID3v1 tag
433 if ((size == mediaLength) && (mediaLength != AudioSystem.NOT_SPECIFIED))
434 {
435 FileInputStream fis = (FileInputStream) inputStream;
436 byte[] id3v1 = new byte[128];
437 long bytesSkipped = fis.skip(inputStream.available()-id3v1.length);
438 int read = fis.read(id3v1,0,id3v1.length);
439 if ((id3v1[0]=='T') && (id3v1[1]=='A') && (id3v1[2]=='G'))
440 {
441 parseID3v1Frames(id3v1, aff_properties);
442 }
443 }
444
445 AudioFormat format = new MpegAudioFormat(encoding, (float) nFrequency, AudioSystem.NOT_SPECIFIED // SampleSizeInBits - The size of a sample
446 , nChannels // Channels - The number of channels
447 , -1 // The number of bytes in each frame
448 , FrameRate // FrameRate - The number of frames played or recorded per second
449 , true
450 , af_properties);
451 return new MpegAudioFileFormat(MpegFileFormatType.MP3, format, nTotalFrames, mLength,aff_properties);
452 }
453
454 /**
455 * Returns AudioInputStream from file.
456 */
457 public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException
458 {
459 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(File file)");
460 InputStream inputStream = new FileInputStream(file);
461 try
462 {
463 return getAudioInputStream(inputStream);
464 }
465 catch (UnsupportedAudioFileException e)
466 {
467 if (inputStream != null) inputStream.close();
468 throw e;
469 }
470 catch (IOException e)
471 {
472 if (inputStream != null) inputStream.close();
473 throw e;
474 }
475 }
476
477 /**
478 * Returns AudioInputStream from url.
479 */
480 public AudioInputStream getAudioInputStream(URL url)
481 throws UnsupportedAudioFileException, IOException
482 {
483 if (TDebug.TraceAudioFileReader) {TDebug.out("MpegAudioFileReader.getAudioInputStream(URL): begin"); }
484 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
485 URLConnection conn = url.openConnection();
486 // Tell shoucast server (if any) that SPI support shoutcast stream.
487 boolean isShout = false;
488 int toRead=4;
489 byte[] head = new byte[toRead];
490
491 conn.setRequestProperty ("Icy-Metadata", "1");
492 BufferedInputStream bInputStream = new BufferedInputStream(conn.getInputStream());
493 bInputStream.mark(toRead);
494 int read = bInputStream.read(head,0,toRead);
495 if ((read>2) && (((head[0] == 'I') | (head[0] == 'i')) && ((head[1] == 'C') | (head[1] == 'c')) && ((head[2] == 'Y') | (head[2] == 'y')))) isShout = true;
496 bInputStream.reset();
497 InputStream inputStream = null;
498 // Is is a shoutcast server ?
499 if (isShout == true)
500 {
501 // Yes
502 IcyInputStream icyStream = new IcyInputStream(bInputStream);
503 icyStream.addTagParseListener(IcyListener.getInstance());
504 inputStream = icyStream;
505 }
506 else
507 {
508 // No, is Icecast 2 ?
509 String metaint = conn.getHeaderField("icy-metaint");
510 if (metaint != null)
511 {
512 // Yes, it might be icecast 2 mp3 stream.
513 IcyInputStream icyStream = new IcyInputStream(bInputStream,metaint);
514 icyStream.addTagParseListener(IcyListener.getInstance());
515 inputStream = icyStream;
516 }
517 else
518 {
519 // No
520 inputStream = bInputStream;
521 }
522 }
523 AudioInputStream audioInputStream = null;
524 try
525 {
526 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
527 }
528 catch (UnsupportedAudioFileException e)
529 {
530 inputStream.close();
531 throw e;
532 }
533 catch (IOException e)
534 {
535 inputStream.close();
536 throw e;
537 }
538 if (TDebug.TraceAudioFileReader) {TDebug.out("MpegAudioFileReader.getAudioInputStream(URL): end"); }
539 return audioInputStream;
540 }
541
542 /**
543 * Return the AudioInputStream from the given InputStream.
544 */
545 public AudioInputStream getAudioInputStream(InputStream inputStream) throws UnsupportedAudioFileException, IOException
546 {
547 if (TDebug.TraceAudioFileReader) TDebug.out("MpegAudioFileReader.getAudioInputStream(InputStream inputStream)");
548 if (!inputStream.markSupported()) inputStream = new BufferedInputStream(inputStream);
549 return super.getAudioInputStream(inputStream);
550 }
551
552 /**
553 * Parser ID3v1 frames
554 * @param frames
555 * @param props
556 */
557 protected void parseID3v1Frames(byte[] frames, HashMap props)
558 {
559 if (TDebug.TraceAudioFileReader) TDebug.out("Parsing ID3v1");
560 String tag = null;
561 try
562 {
563 tag = new String(frames, 0, frames.length, "ISO-8859-1");
564 }
565 catch (UnsupportedEncodingException e)
566 {
567 tag = new String(frames, 0, frames.length);
568 if (TDebug.TraceAudioFileReader) TDebug.out("Cannot use ISO-8859-1");
569 }
570 if (TDebug.TraceAudioFileReader) TDebug.out("ID3v1 frame dump='"+tag+"'");
571 int start = 3;
572 String titlev1 = chopSubstring(tag, start, start += 30);
573 String titlev2 = (String) props.get("title");
574 if (((titlev2==null) || (titlev2.length()==0)) && (titlev1 != null)) props.put("title",titlev1);
575 String artistv1 = chopSubstring(tag, start, start += 30);
576 String artistv2 = (String) props.get("author");
577 if (((artistv2==null) || (artistv2.length()==0)) && (artistv1 != null)) props.put("author",artistv1);
578 String albumv1 = chopSubstring(tag, start, start += 30);
579 String albumv2 = (String) props.get("album");
580 if (((albumv2==null) || (albumv2.length()==0)) && (albumv1 != null)) props.put("album",albumv1);
581 String yearv1 = chopSubstring(tag, start, start += 4);
582 String yearv2 = (String) props.get("year");
583 if (((yearv2==null) || (yearv2.length()==0)) && (yearv1 != null)) props.put("date",yearv1);
584 String commentv1 = chopSubstring(tag, start, start += 28);
585 String commentv2 = (String) props.get("comment");
586 if (((commentv2==null) || (commentv2.length()==0)) && (commentv1 != null)) props.put("comment",commentv1);
587 String trackv1 = ""+((int) (frames[126] & 0xff));
588 String trackv2 = (String) props.get("mp3.id3tag.track");
589 if (((trackv2==null) || (trackv2.length()==0)) && (trackv1 != null)) props.put("mp3.id3tag.track",trackv1);
590
591 int genrev1 = (int) (frames[127] & 0xff);
592 if ((genrev1 >=0) && (genrev1<id3v1genres.length))
593 {
594 String genrev2 = (String) props.get("mp3.id3tag.genre");
595 if (((genrev2==null) || (genrev2.length()==0))) props.put("mp3.id3tag.genre",id3v1genres[genrev1]);
596 }
597 if (TDebug.TraceAudioFileReader) TDebug.out("ID3v1 parsed");
598 }
599
600 /**
601 * Extract
602 * @param s
603 * @param start
604 * @param end
605 * @return
606 */
607 private String chopSubstring(String s, int start, int end)
608 {
609 String str = null;
610 // 11/28/04 - String encoding bug fix.
611 try
612 {
613 str = s.substring(start, end);
614 int loc = str.indexOf('\0');
615 if (loc != -1) str = str.substring(0, loc);
616 }
617 catch (StringIndexOutOfBoundsException e)
618 {
619 // Skip encoding issues.
620 if (TDebug.TraceAudioFileReader) TDebug.out("Cannot chopSubString "+e.getMessage());
621 }
622 return str;
623 }
624 /**
625 * Parse ID3v2 frames to add album (TALB), title (TIT2), date (TYER), author (TPE1), copyright (TCOP), comment (COMM) ...
626 * @param frames
627 * @param props
628 */
629 protected void parseID3v2Frames(InputStream frames, HashMap props)
630 {
631 if (TDebug.TraceAudioFileReader) TDebug.out("Parsing ID3v2");
632 byte[] bframes = null;
633 int size = -1;
634 try
635 {
636 size = frames.available();
637 bframes = new byte[size];
638 frames.mark(size);
639 frames.read(bframes);
640 frames.reset();
641 }
642 catch (IOException e)
643 {
644 if (TDebug.TraceAudioFileReader) TDebug.out("Cannot parse ID3v2 :"+e.getMessage());
645 }
646
647 try
648 {
649 if (TDebug.TraceAudioFileReader) TDebug.out("ID3v2 frame dump='"+new String(bframes,0,bframes.length)+"'");
650 /* ID3 tags : http://www.unixgods.org/~tilo/ID3/docs/ID3_comparison.html */
651 String value = null;
652 for (int i=0;i<bframes.length-4;i++)
653 {
654 String code = new String(bframes,i,4);
655 String scode = new String(bframes,i,3);
656 // ID3v2.3 & v2.4
657 if ((code.equals("TALB")) || (code.equals("TIT2")) || (code.equals("TYER")) || (code.equals("TPE1")) || (code.equals("TCOP")) || (code.equals("COMM")) || (code.equals("TCON")) || (code.equals("TRCK")) || (code.equals("TPOS")) || (code.equals("TDRC")) || (code.equals("TCOM")) || (code.equals("TIT1")) || (code.equals("TENC")))
658 {
659 i=i+10;
660 size = (int) (bframes[i-6] << 24) + (bframes[i-5] << 16) + (bframes[i-4] << 8) + (bframes[i-3]);
661 if (code.equals("COMM")) value = parseText(bframes, i, size, 5);
662 else value = parseText(bframes,i, size, 1);
663 if ((value != null) && (value.length()>0))
664 {
665 if (code.equals("TALB")) props.put("album",value);
666 else if (code.equals("TIT2")) props.put("title",value);
667 else if (code.equals("TYER")) props.put("date",value);
668 // ID3v2.4 date fix.
669 else if (code.equals("TDRC")) props.put("date",value);
670 else if (code.equals("TPE1")) props.put("author",value);
671 else if (code.equals("TCOP")) props.put("copyright",value);
672 else if (code.equals("COMM")) props.put("comment",value);
673 else if (code.equals("TCON")) props.put("mp3.id3tag.genre",value);
674 else if (code.equals("TRCK")) props.put("mp3.id3tag.track",value);
675 else if (code.equals("TPOS")) props.put("mp3.id3tag.disc",value);
676 else if (code.equals("TCOM")) props.put("mp3.id3tag.composer",value);
677 else if (code.equals("TIT1")) props.put("mp3.id3tag.grouping",value);
678 else if (code.equals("TENC")) props.put("mp3.id3tag.encoded",value);
679 }
680 i=i+size-1;
681 }
682 // ID3v2.2.
683 else if ((scode.equals("TAL")) || (scode.equals("TT2")) || (scode.equals("TP1")) || (scode.equals("TYE")) || (scode.equals("TRK")) || (scode.equals("TPA")) || (scode.equals("TCR")) || (scode.equals("TCO")) || (scode.equals("TCM")) || (scode.equals("COM")) || (scode.equals("TT1")) || (scode.equals("TEN")))
684 {
685 i=i+6;
686 size = (int) (0x00000000) + (bframes[i-3] << 16) + (bframes[i-2] << 8) + (bframes[i-1]);
687 if (scode.equals("COM")) value = parseText(bframes, i, size, 5);
688 else value = parseText(bframes,i, size, 1);
689 if ((value != null) && (value.length()>0))
690 {
691 if (scode.equals("TAL")) props.put("album",value);
692 else if (scode.equals("TT2")) props.put("title",value);
693 else if (scode.equals("TYE")) props.put("date",value);
694 else if (scode.equals("TP1")) props.put("author",value);
695 else if (scode.equals("TCR")) props.put("copyright",value);
696 else if (scode.equals("COM")) props.put("comment",value);
697 else if (scode.equals("TCO")) props.put("mp3.id3tag.genre",value);
698 else if (scode.equals("TRK")) props.put("mp3.id3tag.track",value);
699 else if (scode.equals("TPA")) props.put("mp3.id3tag.disc",value);
700 else if (scode.equals("TCM")) props.put("mp3.id3tag.composer",value);
701 else if (scode.equals("TT1")) props.put("mp3.id3tag.grouping",value);
702 else if (scode.equals("TEN")) props.put("mp3.id3tag.encoded",value);
703 }
704 i=i+size-1;
705 }
706 else if (code.startsWith("ID3"))
707 {
708 // ID3v2 Header.
709 int v2version = (int) (bframes[3] & 0xFF);
710 props.put("mp3.id3tag.v2.version",String.valueOf(v2version));
711 i=i+4;
712 }
713 }
714 }
715 catch (RuntimeException e)
716 {
717 // Ignore all parsing errors.
718 if (TDebug.TraceAudioFileReader) TDebug.out("Cannot parse ID3v2 :"+e.getMessage());
719 }
720 if (TDebug.TraceAudioFileReader) TDebug.out("ID3v2 parsed");
721 }
722
723 /**
724 * Parse Text Frames.
725 * @param bframes
726 * @param offset
727 * @param size
728 * @param skip
729 * @return
730 */
731 protected String parseText(byte[] bframes, int offset, int size, int skip)
732 {
733 String value = null;
734 try
735 {
736 String[] ENC_TYPES = {"ISO-8859-1", "UTF16","UTF-16BE", "UTF-8"};
737 value = new String(bframes,offset+skip,size-skip,ENC_TYPES[bframes[offset]]);
738 value = chopSubstring(value,0,value.length());
739 }
740 catch (UnsupportedEncodingException e)
741 {
742 if (TDebug.TraceAudioFileReader) TDebug.out("ID3v2 Encoding error :"+e.getMessage());
743 }
744 return value;
745 }
746
747 /**
748 * Load shoutcast (ICY) info.
749 * @param input
750 * @param props
751 * @throws IOException
752 */
753 protected void loadShoutcastInfo(InputStream input, HashMap props) throws IOException
754 {
755 IcyInputStream icy = new IcyInputStream(new BufferedInputStream(input));
756 HashMap metadata = icy.getTagHash();
757 MP3Tag titleMP3Tag = icy.getTag("icy-name");
758 if (titleMP3Tag != null) props.put("title",((String) titleMP3Tag.getValue()).trim());
759 MP3Tag[] meta = icy.getTags();
760 if (meta != null)
761 {
762 StringBuffer metaStr = new StringBuffer();
763 for (int i=0;i<meta.length;i++)
764 {
765 String key = meta[i].getName();
766 String value = ((String) icy.getTag(key).getValue()).trim();
767 props.put("mp3.shoutcast.metadata."+key, value);
768 }
769 }
770 }
771
772} \ No newline at end of file
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFormat.java b/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFormat.java
new file mode 100644
index 0000000000..29a66a3d93
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFormat.java
@@ -0,0 +1,67 @@
1/*
2 * MpegAudioFormat.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.spi.mpeg.sampled.file;
25
26import java.util.Map;
27
28import javax.sound.sampled.AudioFormat;
29
30import org.tritonus.share.sampled.TAudioFormat;
31
32/**
33 * @author JavaZOOM
34 */
35public class MpegAudioFormat extends TAudioFormat
36{
37 /**
38 * Constructor.
39 * @param encoding
40 * @param nFrequency
41 * @param SampleSizeInBits
42 * @param nChannels
43 * @param FrameSize
44 * @param FrameRate
45 * @param isBigEndian
46 * @param properties
47 */
48 public MpegAudioFormat(AudioFormat.Encoding encoding, float nFrequency, int SampleSizeInBits, int nChannels, int FrameSize, float FrameRate, boolean isBigEndian, Map properties)
49 {
50 super(encoding, nFrequency, SampleSizeInBits, nChannels, FrameSize, FrameRate, isBigEndian, properties);
51 }
52
53 /**
54 * MP3 audio format parameters.
55 * Some parameters might be unavailable. So availability test is required before reading any parameter.
56 *
57 * <br>AudioFormat parameters.
58 * <ul>
59 * <li><b>bitrate</b> [Integer], bitrate in bits per seconds, average bitrate for VBR enabled stream.
60 * <li><b>vbr</b> [Boolean], VBR flag.
61 * </ul>
62 */
63 public Map properties()
64 {
65 return super.properties();
66 }
67}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/MpegEncoding.java b/songdbj/javazoom/spi/mpeg/sampled/file/MpegEncoding.java
new file mode 100644
index 0000000000..6306d9ec80
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/MpegEncoding.java
@@ -0,0 +1,47 @@
1/*
2 * MpegEncoding.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.spi.mpeg.sampled.file;
25
26import javax.sound.sampled.AudioFormat;
27
28/**
29 * Encodings used by the MPEG audio decoder.
30 */
31public class MpegEncoding extends AudioFormat.Encoding
32{
33 public static final AudioFormat.Encoding MPEG1L1 = new MpegEncoding("MPEG1L1");
34 public static final AudioFormat.Encoding MPEG1L2 = new MpegEncoding("MPEG1L2");
35 public static final AudioFormat.Encoding MPEG1L3 = new MpegEncoding("MPEG1L3");
36 public static final AudioFormat.Encoding MPEG2L1 = new MpegEncoding("MPEG2L1");
37 public static final AudioFormat.Encoding MPEG2L2 = new MpegEncoding("MPEG2L2");
38 public static final AudioFormat.Encoding MPEG2L3 = new MpegEncoding("MPEG2L3");
39 public static final AudioFormat.Encoding MPEG2DOT5L1 = new MpegEncoding("MPEG2DOT5L1");
40 public static final AudioFormat.Encoding MPEG2DOT5L2 = new MpegEncoding("MPEG2DOT5L2");
41 public static final AudioFormat.Encoding MPEG2DOT5L3 = new MpegEncoding("MPEG2DOT5L3");
42
43 public MpegEncoding(String strName)
44 {
45 super(strName);
46 }
47}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/MpegFileFormatType.java b/songdbj/javazoom/spi/mpeg/sampled/file/MpegFileFormatType.java
new file mode 100644
index 0000000000..2c59ad8621
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/MpegFileFormatType.java
@@ -0,0 +1,40 @@
1/*
2 * MpegFileFormatType.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.spi.mpeg.sampled.file;
25
26import javax.sound.sampled.AudioFileFormat;
27
28/**
29 * FileFormatTypes used by the MPEG audio decoder.
30 */
31public class MpegFileFormatType extends AudioFileFormat.Type
32{
33 public static final AudioFileFormat.Type MPEG = new MpegFileFormatType("MPEG", "mpeg");
34 public static final AudioFileFormat.Type MP3 = new MpegFileFormatType("MP3", "mp3");
35
36 public MpegFileFormatType(String strName, String strExtension)
37 {
38 super(strName, strExtension);
39 }
40}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyInputStream.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyInputStream.java
new file mode 100644
index 0000000000..22aa4439fe
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyInputStream.java
@@ -0,0 +1,412 @@
1/*
2 * IcyInputStream.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28import java.io.BufferedInputStream;
29import java.io.IOException;
30import java.io.InputStream;
31import java.net.URL;
32import java.net.URLConnection;
33import java.util.HashMap;
34import java.util.StringTokenizer;
35
36/** An BufferedInputStream that parses Shoutcast's "icy" metadata
37 from the stream. Gets headers at the beginning and if the
38 "icy-metaint" tag is found, it parses and strips in-stream
39 metadata.
40 <p>
41 <b>The deal with metaint</b>: Icy streams don't try to put
42 tags between MP3 frames the way that ID3 does. Instead, it
43 requires the client to strip metadata from the stream before
44 it hits the decoder. You get an
45 <code>icy-metaint</code> name/val in the beginning of the
46 stream iff you sent "Icy-Metadata" with value "1" in the
47 request headers (SimpleMP3DataSource does this if the
48 "parseStreamMetadata" boolean is true). If this is the case
49 then the value of icy-metaint is the amount of real data
50 between metadata blocks. Each block begins with an int
51 indicating how much metadata there is -- the block is this
52 value times 16 (it can be, and often is, 0).
53 <p>
54 Originally thought that "icy" implied Icecast, but this is
55 completely wrong -- real Icecast servers, found through
56 www.icecast.net and typified by URLs with a trailing directory
57 (like CalArts School of Music - http://65.165.174.100:8000/som)
58 do not have the "ICY 200 OK" magic string or any of the
59 CRLF-separated headers. Apparently, "icy" means "Shoutcast".
60 Yep, that's weird.
61 @author Chris Adamson, invalidname@mac.com
62 */
63public class IcyInputStream
64 extends BufferedInputStream
65 implements MP3MetadataParser {
66
67 public static boolean DEBUG = false;
68
69 MP3TagParseSupport tagParseSupport;
70 /** inline tags are delimited by ';', also filter out
71 null bytes
72 */
73 protected static final String INLINE_TAG_SEPARATORS = ";\u0000";
74 /* looks like icy streams start start with
75 ICY 200 OK\r\n
76 then the tags are like
77 icy-notice1:<BR>This stream requires <a href="http://www.winamp.com/">Winamp</a><BR>\r\n
78 icy-notice2:SHOUTcast Distributed Network Audio Server/win32 v1.8.2<BR>\r\n
79 icy-name:Core-upt Radio\r\n
80 icy-genre:Punk Ska Emo\r\n
81 icy-url:http://www.core-uptrecords.com\r\n
82 icy-pub:1\r\n
83 icy-metaint:8192\r\n
84 icy-br:56\r\n
85 \r\n (signifies end of headers)
86 we only get icy-metaint if the http request that created
87 this stream sent the header "icy-metadata:1"
88 //
89 in in-line metadata, we read a byte that tells us how
90 many 16-byte blocks there are (presumably, we still use
91 \r\n for the separator... the block is padded out with
92 0x00's that we can ignore)
93
94 // when server is full/down/etc, we get the following for
95 // one of the notice lines:
96 icy-notice2:This server has reached its user limit<BR>
97 or
98 icy-notice2:The resource requested is currently unavailable<BR>
99 */
100 /** Tags that have been discovered in the stream.
101 */
102 HashMap tags;
103 /** Buffer for readCRLF line... note this limits lines to
104 1024 chars (I've read that WinAmp barfs at 128, so
105 this is generous)
106 */
107 protected byte[] crlfBuffer = new byte[1024];
108 /** value of the "metaint" tag, which tells us how many bytes
109 of real data are between the metadata tags. if -1, this stream
110 does not have metadata after the header.
111 */
112 protected int metaint = -1;
113 /** how many bytes of real data remain before the next
114 block of metadata. Only meaningful if metaint != -1.
115 */
116 protected int bytesUntilNextMetadata = -1;
117 // TODO: comment for constructor
118 /** Reads the initial headers of the stream and adds
119 tags appropriatly. Gets set up to find, read,
120 and strip blocks of in-line metadata if the
121 <code>icy-metaint</code> header is found.
122 */
123 public IcyInputStream(InputStream in) throws IOException {
124 super(in);
125 tags = new HashMap();
126 tagParseSupport = new MP3TagParseSupport();
127 // read the initial tags here, including the metaint
128 // and set the counter for how far we read until
129 // the next metadata block (if any).
130 readInitialHeaders();
131 IcyTag metaIntTag = (IcyTag) getTag("icy-metaint");
132 if (DEBUG) System.out.println("METATAG:"+metaIntTag);
133 if (metaIntTag != null) {
134 String metaIntString = metaIntTag.getValueAsString();
135 try {
136 metaint = Integer.parseInt(metaIntString.trim());
137 if (DEBUG) System.out.println("METAINT:"+metaint);
138 bytesUntilNextMetadata = metaint;
139 }
140 catch (NumberFormatException nfe) {
141 }
142 }
143 }
144
145 /**
146 * IcyInputStream constructor for know meta-interval (Icecast 2)
147 * @param in
148 * @param metaint
149 * @throws IOException
150 */
151 public IcyInputStream(InputStream in, String metaIntString) throws IOException {
152 super(in);
153 tags = new HashMap();
154 tagParseSupport = new MP3TagParseSupport();
155 try
156 {
157 metaint = Integer.parseInt(metaIntString.trim());
158 if (DEBUG) System.out.println("METAINT:"+metaint);
159 bytesUntilNextMetadata = metaint;
160 }
161 catch (NumberFormatException nfe) {
162 }
163 }
164
165 /** Assuming we're at the top of the stream, read lines one
166 by one until we hit a completely blank \r\n. Parse the
167 data as IcyTags.
168 */
169 protected void readInitialHeaders() throws IOException {
170 String line = null;
171 while (!((line = readCRLFLine()).equals(""))) {
172 int colonIndex = line.indexOf(':');
173 // does it have a ':' separator
174 if (colonIndex == -1)
175 continue;
176 IcyTag tag =
177 new IcyTag(
178 line.substring(0, colonIndex),
179 line.substring(colonIndex + 1));
180 //System.out.println(tag);
181 addTag(tag);
182 }
183 }
184 /** Read everything up to the next CRLF, return it as
185 a String.
186 */
187 protected String readCRLFLine() throws IOException {
188 int i = 0;
189 for (; i < crlfBuffer.length; i++) {
190 byte aByte = (byte) read();
191 if (aByte == '\r') {
192 // possible end of line
193 byte anotherByte = (byte) read();
194 i++; // since we read again
195 if (anotherByte == '\n') {
196 break; // break out of while
197 }
198 else {
199 // oops, not end of line - put these in array
200 crlfBuffer[i - 1] = aByte;
201 crlfBuffer[i] = anotherByte;
202 }
203 }
204 else {
205 // if not \r
206 crlfBuffer[i] = aByte;
207 }
208 } // for
209 // get the string from the byte[]. i is 1 too high because of
210 // read-ahead in crlf block
211 return new String(crlfBuffer, 0, i - 1);
212 }
213 /** Reads and returns a single byte.
214 If the next byte is a metadata block, then that
215 block is read, stripped, and parsed before reading
216 and returning the first byte after the metadata block.
217 */
218 public int read() throws IOException {
219 if (bytesUntilNextMetadata > 0) {
220 bytesUntilNextMetadata--;
221 return super.read();
222 }
223 else if (bytesUntilNextMetadata == 0) {
224 // we need to read next metadata block
225 readMetadata();
226 bytesUntilNextMetadata = metaint - 1;
227 // -1 because we read byte on next line
228 return super.read();
229 }
230 else {
231 // no metadata in this stream
232 return super.read();
233 }
234 }
235 /** Reads a block of bytes. If the next byte is known
236 to be a block of metadata, then that is read, parsed,
237 and stripped, and then a block of bytes is read and
238 returned.
239 Otherwise, it may read up to but
240 not into the next metadata block if
241 <code>bytesUntilNextMetadata &lt; length</code>
242 */
243 public int read(byte[] buf, int offset, int length) throws IOException {
244 // if not on metadata, do the usual read so long as we
245 // don't read past metadata
246 if (bytesUntilNextMetadata > 0) {
247 int adjLength = Math.min(length, bytesUntilNextMetadata);
248 int got = super.read(buf, offset, adjLength);
249 bytesUntilNextMetadata -= got;
250 return got;
251 }
252 else if (bytesUntilNextMetadata == 0) {
253 // read/parse the metadata
254 readMetadata();
255 // now as above, except that we reset
256 // bytesUntilNextMetadata differently
257
258 //int adjLength = Math.min(length, bytesUntilNextMetadata);
259 //int got = super.read(buf, offset, adjLength);
260 //bytesUntilNextMetadata = metaint - got;
261
262 // Chop Fix - JavaZOOM (3 lines above seem buggy)
263 bytesUntilNextMetadata = metaint;
264 int adjLength = Math.min(length, bytesUntilNextMetadata);
265 int got = super.read(buf, offset, adjLength);
266 bytesUntilNextMetadata -= got;
267 // End fix - JavaZOOM
268
269
270 return got;
271 }
272 else {
273 // not even reading metadata
274 return super.read(buf, offset, length);
275 }
276 }
277 /** trivial <code>return read (buf, 0, buf.length)</code>
278 */
279 public int read(byte[] buf) throws IOException {
280 return read(buf, 0, buf.length);
281 }
282 /** Read the next segment of metadata. The stream <b>must</b>
283 be right on the segment, ie, the next byte to read is
284 the metadata block count. The metadata is parsed and
285 new tags are added with addTag(), which fires events
286 */
287 protected void readMetadata() throws IOException {
288 int blockCount = super.read();
289 if (DEBUG) System.out.println("BLOCKCOUNT:"+blockCount);
290 // System.out.println ("blocks to read: " + blockCount);
291 int byteCount = (blockCount * 16); // 16 bytes per block
292 if (byteCount < 0)
293 return; // WTF?!
294 byte[] metadataBlock = new byte[byteCount];
295 int index = 0;
296 // build an array of this metadata
297 while (byteCount > 0) {
298 int bytesRead = super.read(metadataBlock, index, byteCount);
299 index += bytesRead;
300 byteCount -= bytesRead;
301 }
302 // now parse it
303 if (blockCount > 0)
304 parseInlineIcyTags(metadataBlock);
305 } // readMetadata
306 /** Parse metadata from an in-stream "block" of bytes, add
307 a tag for each one.
308 <p>
309 Hilariously, the inline data format is totally different
310 than the top-of-stream header. For example, here's a
311 block I saw on "Final Fantasy Radio":
312 <pre>
313 StreamTitle='Final Fantasy 8 - Nobuo Uematsu - Blue Fields';StreamUrl='';
314 </pre>
315 In other words:
316 <ol>
317 <li>Tags are delimited by semicolons
318 <li>Keys/values are delimited by equals-signs
319 <li>Values are wrapped in single-quotes
320 <li>Key names are in SentenceCase, not lowercase-dashed
321 </ol>
322 */
323 protected void parseInlineIcyTags(byte[] tagBlock) {
324 String blockString = new String(tagBlock);
325 if (DEBUG) System.out.println("BLOCKSTR:"+blockString);
326 StringTokenizer izer =
327 new StringTokenizer(blockString, INLINE_TAG_SEPARATORS);
328 int i = 0;
329 while (izer.hasMoreTokens()) {
330 String tagString = izer.nextToken();
331 int separatorIdx = tagString.indexOf('=');
332 if (separatorIdx == -1)
333 continue; // bogus tagString if no '='
334 // try to strip single-quotes around value, if present
335 int valueStartIdx =
336 (tagString.charAt(separatorIdx + 1) == '\'')
337 ? separatorIdx + 2
338 : separatorIdx + 1;
339 int valueEndIdx =
340 (tagString.charAt(tagString.length() - 1)) == '\''
341 ? tagString.length() - 1
342 : tagString.length();
343 String name = tagString.substring(0, separatorIdx);
344 String value = tagString.substring(valueStartIdx, valueEndIdx);
345 // System.out.println (i++ + " " + name + ":" + value);
346 IcyTag tag = new IcyTag(name, value);
347 addTag(tag);
348 }
349 }
350 /** adds the tag to the HashMap of tags we have encountered
351 either in-stream or as headers, replacing any previous
352 tag with this name.
353 */
354 protected void addTag(IcyTag tag) {
355 tags.put(tag.getName(), tag);
356 // fire this as an event too
357 tagParseSupport.fireTagParsed(this, tag);
358 }
359 /** Get the named tag from the HashMap of headers and
360 in-line tags. Null if no such tag has been encountered.
361 */
362 public MP3Tag getTag(String tagName) {
363 return (MP3Tag) tags.get(tagName);
364 }
365 /** Get all tags (headers or in-stream) encountered thus far.
366 */
367 public MP3Tag[] getTags() {
368 return (MP3Tag[]) tags.values().toArray(new MP3Tag[0]);
369 }
370 /** Returns a HashMap of all headers and in-stream tags
371 parsed so far.
372 */
373 public HashMap getTagHash() {
374 return tags;
375 }
376 /** Adds a TagParseListener to be notified when this stream
377 parses MP3Tags.
378 */
379 public void addTagParseListener(TagParseListener tpl) {
380 tagParseSupport.addTagParseListener(tpl);
381 }
382 /** Removes a TagParseListener, so it won't be notified when
383 this stream parses MP3Tags.
384 */
385 public void removeTagParseListener(TagParseListener tpl) {
386 tagParseSupport.removeTagParseListener(tpl);
387 }
388 /** Quickie unit-test.
389 */
390 public static void main(String args[]) {
391 byte[] chow = new byte[200];
392 if (args.length != 1) {
393 //System.out.println("Usage: IcyInputStream <url>");
394 return;
395 }
396 try {
397 URL url = new URL(args[0]);
398 URLConnection conn = url.openConnection();
399 conn.setRequestProperty("Icy-Metadata", "1");
400 IcyInputStream icy =
401 new IcyInputStream(
402 new BufferedInputStream(conn.getInputStream()));
403 while (icy.available() > -1) {
404 // icy.read();
405 icy.read(chow, 0, chow.length);
406 }
407 }
408 catch (Exception e) {
409 e.printStackTrace();
410 }
411 }
412}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyTag.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyTag.java
new file mode 100644
index 0000000000..bbe70f1f3c
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyTag.java
@@ -0,0 +1,42 @@
1/*
2 * IcyTag.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27/**
28 * A tag parsed from an icecast tag.
29 */
30public class IcyTag extends MP3Tag implements StringableTag {
31 /** Create a new tag, from the parsed name and (String) value.
32 It looks like all Icecast tags are Strings (safe to assume
33 this going forward?)
34 */
35 public IcyTag(String name, String stringValue) {
36 super(name, stringValue);
37 }
38 // so far as I know, all Icecast tags are strings
39 public String getValueAsString() {
40 return (String) getValue();
41 }
42}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3MetadataParser.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3MetadataParser.java
new file mode 100644
index 0000000000..81511064b8
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3MetadataParser.java
@@ -0,0 +1,50 @@
1/*
2 * MP3MetadataParser.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28/** An object that fires off TagParseEvents as they are parsed
29 from a stream, ServerSocket, or other metadata source
30 */
31public interface MP3MetadataParser {
32 /** Adds a TagParseListener to be notified when this object
33 parses MP3Tags.
34 */
35 public void addTagParseListener(TagParseListener tpl);
36 /** Removes a TagParseListener, so it won't be notified when
37 this object parses MP3Tags.
38 */
39 public void removeTagParseListener(TagParseListener tpl);
40 /** Get all tags (headers or in-stream) encountered thusfar.
41 This is included in this otherwise Listener-like scheme
42 because most standards are a mix of start-of-stream
43 metadata tags (like the http headers or the stuff at the
44 top of an ice stream) and inline data. Implementations should
45 hang onto all tags they parse and provide them with this
46 call. Callers should first use this call to get initial
47 tags, then subscribe for events as the stream continues.
48 */
49 public MP3Tag[] getTags();
50}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3Tag.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3Tag.java
new file mode 100644
index 0000000000..b545356240
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3Tag.java
@@ -0,0 +1,52 @@
1/*
2 * MP3Tag.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28/** An individual piece of mp3 metadata, as a name/value pair.
29 Abstract just so that subclasses will indicate their
30 tagging scheme (Icy, ID3, etc.).
31 */
32public abstract class MP3Tag extends Object {
33 protected String name;
34 protected Object value;
35 public MP3Tag(String name, Object value) {
36 this.name = name;
37 this.value = value;
38 }
39 public String getName() {
40 return name;
41 }
42 public Object getValue() {
43 return value;
44 }
45 public String toString() {
46 return getClass().getName()
47 + " -- "
48 + getName()
49 + ":"
50 + getValue().toString();
51 }
52}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3TagParseSupport.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3TagParseSupport.java
new file mode 100644
index 0000000000..1ab6525512
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3TagParseSupport.java
@@ -0,0 +1,62 @@
1/*
2 * MP3TagParseSupport.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28import java.util.ArrayList;
29/**
30*/
31public class MP3TagParseSupport extends Object {
32 ArrayList tagParseListeners;
33 /** trivial constructor, sets up listeners list.
34 */
35 public MP3TagParseSupport() {
36 super();
37 tagParseListeners = new ArrayList();
38 }
39 /** Adds a TagParseListener to be notified when a stream
40 parses MP3Tags.
41 */
42 public void addTagParseListener(TagParseListener tpl) {
43 tagParseListeners.add(tpl);
44 }
45 /** Removes a TagParseListener, so it won't be notified when
46 a stream parses MP3Tags.
47 */
48 public void removeTagParseListener(TagParseListener tpl) {
49 tagParseListeners.add(tpl);
50 }
51 /** Fires the given event to all registered listeners
52 */
53 public void fireTagParseEvent(TagParseEvent tpe) {
54 for (int i = 0; i < tagParseListeners.size(); i++) {
55 TagParseListener l = (TagParseListener) tagParseListeners.get(i);
56 l.tagParsed(tpe);
57 }
58 }
59 public void fireTagParsed(Object source, MP3Tag tag) {
60 fireTagParseEvent(new TagParseEvent(source, tag));
61 }
62}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/StringableTag.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/StringableTag.java
new file mode 100644
index 0000000000..685c5207f9
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/tag/StringableTag.java
@@ -0,0 +1,36 @@
1/*
2 * StringableTag.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28/** Indicates that the value of a tag is a string, and
29 provides a getValueAsString() method to get it.
30 Appropriate for tags like artist, title, etc.
31 */
32public interface StringableTag {
33 /** Return the value of this tag as a string.
34 */
35 public String getValueAsString();
36}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseEvent.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseEvent.java
new file mode 100644
index 0000000000..97e9ec1e19
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseEvent.java
@@ -0,0 +1,44 @@
1/*
2 * TagParseEvent.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28import java.util.EventObject;
29/** Event to indicate that an MP3 tag was received through
30 some means (parsed in stream, received via UDP, whatever)
31 and converted into an MP3Tag object.
32 */
33public class TagParseEvent extends EventObject {
34 protected MP3Tag tag;
35 public TagParseEvent(Object source, MP3Tag tag) {
36 super(source);
37 this.tag = tag;
38 }
39 /** Get the tag that was parsed.
40 */
41 public MP3Tag getTag() {
42 return tag;
43 }
44}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseListener.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseListener.java
new file mode 100644
index 0000000000..a630827297
--- /dev/null
+++ b/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseListener.java
@@ -0,0 +1,37 @@
1/*
2 * TagParseListener.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28import java.util.EventListener;
29/** EventListener to be implemented by objects that want to
30 get callbacks when MP3 tags are received.
31 */
32public interface TagParseListener extends EventListener {
33 /** Called when a tag is found (parsed from the stream,
34 received via UDP, etc.)
35 */
36 public void tagParsed(TagParseEvent tpe);
37}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java b/songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java
new file mode 100644
index 0000000000..b8e8577e13
--- /dev/null
+++ b/songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java
@@ -0,0 +1,519 @@
1/*
2 * DecodedVorbisAudioInputStream
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * ----------------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * ----------------------------------------------------------------------------
22 */
23
24package javazoom.spi.vorbis.sampled.convert;
25
26import java.io.IOException;
27import java.io.InputStream;
28import java.util.HashMap;
29import java.util.Map;
30
31import javax.sound.sampled.AudioFormat;
32import javax.sound.sampled.AudioInputStream;
33
34import javazoom.spi.PropertiesContainer;
35
36import org.tritonus.share.TDebug;
37import org.tritonus.share.sampled.convert.TAsynchronousFilteredAudioInputStream;
38
39import com.jcraft.jogg.Packet;
40import com.jcraft.jogg.Page;
41import com.jcraft.jogg.StreamState;
42import com.jcraft.jogg.SyncState;
43import com.jcraft.jorbis.Block;
44import com.jcraft.jorbis.Comment;
45import com.jcraft.jorbis.DspState;
46import com.jcraft.jorbis.Info;
47
48/**
49 * This class implements the Vorbis decoding.
50 */
51public class DecodedVorbisAudioInputStream extends TAsynchronousFilteredAudioInputStream implements PropertiesContainer
52{
53 private InputStream oggBitStream_ = null;
54
55 private SyncState oggSyncState_ = null;
56 private StreamState oggStreamState_ = null;
57 private Page oggPage_ = null;
58 private Packet oggPacket_ = null;
59 private Info vorbisInfo = null;
60 private Comment vorbisComment = null;
61 private DspState vorbisDspState = null;
62 private Block vorbisBlock = null;
63
64 static final int playState_NeedHeaders = 0;
65 static final int playState_ReadData = 1;
66 static final int playState_WriteData = 2;
67 static final int playState_Done = 3;
68 static final int playState_BufferFull = 4;
69 static final int playState_Corrupt = -1;
70 private int playState;
71
72 private int bufferMultiple_ = 4;
73 private int bufferSize_ = bufferMultiple_ * 256 * 2;
74 private int convsize = bufferSize_ * 2;
75 private byte[] convbuffer = new byte[convsize];
76 private byte[] buffer = null;
77 private int bytes = 0;
78 private float[][][] _pcmf = null;
79 private int[] _index = null;
80 private int index = 0;
81 private int i = 0;
82 // bout is now a global so that we can continue from when we have a buffer full.
83 int bout = 0;
84
85 private HashMap properties = null;
86 private long currentBytes = 0;
87
88 /**
89 * Constructor.
90 */
91 public DecodedVorbisAudioInputStream(AudioFormat outputFormat, AudioInputStream bitStream)
92 {
93 super(outputFormat, -1);
94 this.oggBitStream_ = bitStream;
95 init_jorbis();
96 index = 0;
97 playState = playState_NeedHeaders;
98 properties = new HashMap();
99 }
100
101 /**
102 * Initializes all the jOrbis and jOgg vars that are used for song playback.
103 */
104 private void init_jorbis()
105 {
106 oggSyncState_ = new SyncState();
107 oggStreamState_ = new StreamState();
108 oggPage_ = new Page();
109 oggPacket_ = new Packet();
110 vorbisInfo = new Info();
111 vorbisComment = new Comment();
112 vorbisDspState = new DspState();
113 vorbisBlock = new Block(vorbisDspState);
114 buffer = null;
115 bytes = 0;
116 currentBytes = 0L;
117 oggSyncState_.init();
118 }
119
120 /**
121 * Return dynamic properties.
122 *
123 * <ul>
124 * <li><b>ogg.position.byte</b> [Long], current position in bytes in the stream.
125 *</ul>
126 */
127 public Map properties()
128 {
129 properties.put("ogg.position.byte",new Long(currentBytes));
130 return properties;
131 }
132 /**
133 * Main loop.
134 */
135 public void execute()
136 {
137 if(TDebug.TraceAudioConverter)
138 {
139 switch(playState)
140 {
141 case playState_NeedHeaders:
142 TDebug.out("playState = playState_NeedHeaders");
143 break;
144 case playState_ReadData:
145 TDebug.out("playState = playState_ReadData");
146 break;
147 case playState_WriteData:
148 TDebug.out("playState = playState_WriteData");
149 break;
150 case playState_Done:
151 TDebug.out("playState = playState_Done");
152 break;
153 case playState_BufferFull:
154 TDebug.out("playState = playState_BufferFull");
155 break;
156 case playState_Corrupt:
157 TDebug.out("playState = playState_Corrupt");
158 break;
159 }
160 }
161 // This code was developed by the jCraft group, as JOrbisPlayer.java, slightly
162 // modified by jOggPlayer developer and adapted by JavaZOOM to suit the JavaSound
163 // SPI. Then further modified by Tom Kimpton to correctly play ogg files that
164 // would hang the player.
165 switch(playState)
166 {
167 case playState_NeedHeaders:
168 try
169 {
170 // Headers (+ Comments).
171 readHeaders();
172 }
173 catch(IOException ioe)
174 {
175 playState = playState_Corrupt;
176 return;
177 }
178 playState = playState_ReadData;
179 break;
180
181 case playState_ReadData:
182 int result;
183 index = oggSyncState_.buffer(bufferSize_);
184 buffer = oggSyncState_.data;
185 bytes = readFromStream(buffer, index, bufferSize_);
186 if(TDebug.TraceAudioConverter) TDebug.out("More data : " + bytes);
187 if(bytes == -1)
188 {
189 playState = playState_Done;
190 if(TDebug.TraceAudioConverter) TDebug.out("Ogg Stream empty. Settings playState to playState_Done.");
191 break;
192 }
193 else
194 {
195 oggSyncState_.wrote(bytes);
196 if(bytes == 0)
197 {
198 if((oggPage_.eos() != 0) || (oggStreamState_.e_o_s != 0) || (oggPacket_.e_o_s != 0))
199 {
200 if(TDebug.TraceAudioConverter) TDebug.out("oggSyncState wrote 0 bytes: settings playState to playState_Done.");
201 playState = playState_Done;
202 }
203 if(TDebug.TraceAudioConverter) TDebug.out("oggSyncState wrote 0 bytes: but stream not yet empty.");
204 break;
205 }
206 }
207
208 result = oggSyncState_.pageout(oggPage_);
209 if(result == 0)
210 {
211 if(TDebug.TraceAudioConverter) TDebug.out("Setting playState to playState_ReadData.");
212 playState = playState_ReadData;
213 break;
214 } // need more data
215 if(result == -1)
216 { // missing or corrupt data at this page position
217 if(TDebug.TraceAudioConverter) TDebug.out("Corrupt or missing data in bitstream; setting playState to playState_ReadData");
218 playState = playState_ReadData;
219 break;
220 }
221
222 oggStreamState_.pagein(oggPage_);
223
224 if(TDebug.TraceAudioConverter) TDebug.out("Setting playState to playState_WriteData.");
225 playState = playState_WriteData;
226 break;
227
228 case playState_WriteData:
229 // Decoding !
230 if(TDebug.TraceAudioConverter) TDebug.out("Decoding");
231 while(true)
232 {
233 result = oggStreamState_.packetout(oggPacket_);
234 if(result == 0)
235 {
236 if(TDebug.TraceAudioConverter) TDebug.out("Packetout returned 0, going to read state.");
237 playState = playState_ReadData;
238 break;
239 } // need more data
240 else if(result == -1)
241 {
242 // missing or corrupt data at this page position
243 // no reason to complain; already complained above
244 if(TDebug.TraceAudioConverter) TDebug.out("Corrupt or missing data in packetout bitstream; going to read state...");
245 // playState = playState_ReadData;
246 // break;
247 continue;
248 }
249 else
250 {
251 // we have a packet. Decode it
252 if(vorbisBlock.synthesis(oggPacket_) == 0)
253 { // test for success!
254 vorbisDspState.synthesis_blockin(vorbisBlock);
255 }
256 else
257 {
258 //if(TDebug.TraceAudioConverter) TDebug.out("vorbisBlock.synthesis() returned !0, going to read state");
259 if(TDebug.TraceAudioConverter) TDebug.out("VorbisBlock.synthesis() returned !0, continuing.");
260 continue;
261 }
262
263 outputSamples();
264 if(playState == playState_BufferFull)
265 return;
266
267 } // else result != -1
268 } // while(true)
269 if(oggPage_.eos() != 0)
270 {
271 if(TDebug.TraceAudioConverter) TDebug.out("Settings playState to playState_Done.");
272 playState = playState_Done;
273 }
274 break;
275 case playState_BufferFull:
276 continueFromBufferFull();
277 break;
278
279 case playState_Corrupt:
280 if(TDebug.TraceAudioConverter) TDebug.out("Corrupt Song.");
281 // drop through to playState_Done...
282 case playState_Done:
283 oggStreamState_.clear();
284 vorbisBlock.clear();
285 vorbisDspState.clear();
286 vorbisInfo.clear();
287 oggSyncState_.clear();
288 if(TDebug.TraceAudioConverter) TDebug.out("Done Song.");
289 try
290 {
291 if(oggBitStream_ != null)
292 {
293 oggBitStream_.close();
294 }
295 getCircularBuffer().close();
296 }
297 catch(Exception e)
298 {
299 if(TDebug.TraceAudioConverter) TDebug.out(e.getMessage());
300 }
301 break;
302 } // switch
303 }
304
305 /**
306 * This routine was extracted so that when the output buffer fills up,
307 * we can break out of the loop, let the music channel drain, then
308 * continue from where we were.
309 */
310 private void outputSamples()
311 {
312 int samples;
313 while((samples = vorbisDspState.synthesis_pcmout(_pcmf, _index)) > 0)
314 {
315 float[][] pcmf = _pcmf[0];
316 bout = (samples < convsize ? samples : convsize);
317 double fVal = 0.0;
318 // convert doubles to 16 bit signed ints (host order) and
319 // interleave
320 for(i = 0; i < vorbisInfo.channels; i++)
321 {
322 int pointer = i * 2;
323 //int ptr=i;
324 int mono = _index[i];
325 for(int j = 0; j < bout; j++)
326 {
327 fVal = pcmf[i][mono + j] * 32767.;
328 int val = (int) (fVal);
329 if(val > 32767)
330 {
331 val = 32767;
332 }
333 if(val < -32768)
334 {
335 val = -32768;
336 }
337 if(val < 0)
338 {
339 val = val | 0x8000;
340 }
341 convbuffer[pointer] = (byte) (val);
342 convbuffer[pointer + 1] = (byte) (val >>> 8);
343 pointer += 2 * (vorbisInfo.channels);
344 }
345 }
346 if(TDebug.TraceAudioConverter) TDebug.out("about to write: " + 2 * vorbisInfo.channels * bout);
347 if(getCircularBuffer().availableWrite() < 2 * vorbisInfo.channels * bout)
348 {
349 if(TDebug.TraceAudioConverter) TDebug.out("Too much data in this data packet, better return, let the channel drain, and try again...");
350 playState = playState_BufferFull;
351 return;
352 }
353 getCircularBuffer().write(convbuffer, 0, 2 * vorbisInfo.channels * bout);
354 if(bytes < bufferSize_)
355 if(TDebug.TraceAudioConverter) TDebug.out("Finished with final buffer of music?");
356 if(vorbisDspState.synthesis_read(bout) != 0)
357 {
358 if(TDebug.TraceAudioConverter) TDebug.out("VorbisDspState.synthesis_read returned -1.");
359 }
360 } // while(samples...)
361 playState = playState_ReadData;
362 }
363
364 private void continueFromBufferFull()
365 {
366 if(getCircularBuffer().availableWrite() < 2 * vorbisInfo.channels * bout)
367 {
368 if(TDebug.TraceAudioConverter) TDebug.out("Too much data in this data packet, better return, let the channel drain, and try again...");
369 // Don't change play state.
370 return;
371 }
372 getCircularBuffer().write(convbuffer, 0, 2 * vorbisInfo.channels * bout);
373 // Don't change play state. Let outputSamples change play state, if necessary.
374 outputSamples();
375 }
376 /**
377 * Reads headers and comments.
378 */
379 private void readHeaders() throws IOException
380 {
381 if(TDebug.TraceAudioConverter) TDebug.out("readHeaders(");
382 index = oggSyncState_.buffer(bufferSize_);
383 buffer = oggSyncState_.data;
384 bytes = readFromStream(buffer, index, bufferSize_);
385 if(bytes == -1)
386 {
387 if(TDebug.TraceAudioConverter) TDebug.out("Cannot get any data from selected Ogg bitstream.");
388 throw new IOException("Cannot get any data from selected Ogg bitstream.");
389 }
390 oggSyncState_.wrote(bytes);
391 if(oggSyncState_.pageout(oggPage_) != 1)
392 {
393 if(bytes < bufferSize_)
394 {
395 throw new IOException("EOF");
396 }
397 if(TDebug.TraceAudioConverter) TDebug.out("Input does not appear to be an Ogg bitstream.");
398 throw new IOException("Input does not appear to be an Ogg bitstream.");
399 }
400 oggStreamState_.init(oggPage_.serialno());
401 vorbisInfo.init();
402 vorbisComment.init();
403 if(oggStreamState_.pagein(oggPage_) < 0)
404 {
405 // error; stream version mismatch perhaps
406 if(TDebug.TraceAudioConverter) TDebug.out("Error reading first page of Ogg bitstream data.");
407 throw new IOException("Error reading first page of Ogg bitstream data.");
408 }
409 if(oggStreamState_.packetout(oggPacket_) != 1)
410 {
411 // no page? must not be vorbis
412 if(TDebug.TraceAudioConverter) TDebug.out("Error reading initial header packet.");
413 throw new IOException("Error reading initial header packet.");
414 }
415 if(vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_) < 0)
416 {
417 // error case; not a vorbis header
418 if(TDebug.TraceAudioConverter) TDebug.out("This Ogg bitstream does not contain Vorbis audio data.");
419 throw new IOException("This Ogg bitstream does not contain Vorbis audio data.");
420 }
421 //int i = 0;
422 i = 0;
423 while(i < 2)
424 {
425 while(i < 2)
426 {
427 int result = oggSyncState_.pageout(oggPage_);
428 if(result == 0)
429 {
430 break;
431 } // Need more data
432 if(result == 1)
433 {
434 oggStreamState_.pagein(oggPage_);
435 while(i < 2)
436 {
437 result = oggStreamState_.packetout(oggPacket_);
438 if(result == 0)
439 {
440 break;
441 }
442 if(result == -1)
443 {
444 if(TDebug.TraceAudioConverter) TDebug.out("Corrupt secondary header. Exiting.");
445 throw new IOException("Corrupt secondary header. Exiting.");
446 }
447 vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_);
448 i++;
449 }
450 }
451 }
452 index = oggSyncState_.buffer(bufferSize_);
453 buffer = oggSyncState_.data;
454 bytes = readFromStream(buffer, index, bufferSize_);
455 if(bytes == -1)
456 {
457 break;
458 }
459 if(bytes == 0 && i < 2)
460 {
461 if(TDebug.TraceAudioConverter) TDebug.out("End of file before finding all Vorbis headers!");
462 throw new IOException("End of file before finding all Vorbis headers!");
463 }
464 oggSyncState_.wrote(bytes);
465 }
466
467 byte[][] ptr = vorbisComment.user_comments;
468 String currComment = "";
469
470 for(int j = 0; j < ptr.length; j++)
471 {
472 if(ptr[j] == null)
473 {
474 break;
475 }
476 currComment = (new String(ptr[j], 0, ptr[j].length - 1)).trim();
477 if(TDebug.TraceAudioConverter) TDebug.out("Comment: " + currComment);
478 }
479 convsize = bufferSize_ / vorbisInfo.channels;
480 vorbisDspState.synthesis_init(vorbisInfo);
481 vorbisBlock.init(vorbisDspState);
482 _pcmf = new float[1][][];
483 _index = new int[vorbisInfo.channels];
484 }
485
486 /**
487 * Reads from the oggBitStream_ a specified number of Bytes(bufferSize_) worth
488 * starting at index and puts them in the specified buffer[].
489 *
490 * @param buffer
491 * @param index
492 * @param bufferSize_
493 * @return the number of bytes read or -1 if error.
494 */
495 private int readFromStream(byte[] buffer, int index, int bufferSize_)
496 {
497 int bytes = 0;
498 try
499 {
500 bytes = oggBitStream_.read(buffer, index, bufferSize_);
501 }
502 catch(Exception e)
503 {
504 if(TDebug.TraceAudioConverter) TDebug.out("Cannot Read Selected Song");
505 bytes = -1;
506 }
507 currentBytes = currentBytes + bytes;
508 return bytes;
509 }
510
511 /**
512 * Close the stream.
513 */
514 public void close() throws IOException
515 {
516 super.close();
517 oggBitStream_.close();
518 }
519}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java b/songdbj/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java
new file mode 100644
index 0000000000..d1321f2590
--- /dev/null
+++ b/songdbj/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java
@@ -0,0 +1,244 @@
1/*
2 * VorbisFormatConversionProvider.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.convert;
24
25import java.util.Arrays;
26import javazoom.spi.vorbis.sampled.file.VorbisEncoding;
27import javax.sound.sampled.AudioFormat;
28import javax.sound.sampled.AudioInputStream;
29
30import org.tritonus.share.sampled.convert.TMatrixFormatConversionProvider;
31
32/**
33 * ConversionProvider for VORBIS files.
34 */
35public class VorbisFormatConversionProvider extends TMatrixFormatConversionProvider
36{
37 private static final AudioFormat[] INPUT_FORMATS =
38 {
39 new AudioFormat(VorbisEncoding.VORBISENC, 32000.0F, -1, 1, -1, -1, false), // 0
40 new AudioFormat(VorbisEncoding.VORBISENC, 32000.0F, -1, 2, -1, -1, false), // 1
41 new AudioFormat(VorbisEncoding.VORBISENC, 44100.0F, -1, 1, -1, -1, false), // 2
42 new AudioFormat(VorbisEncoding.VORBISENC, 44100.0F, -1, 2, -1, -1, false), // 3
43 new AudioFormat(VorbisEncoding.VORBISENC, 48000.0F, -1, 1, -1, -1, false), // 4
44 new AudioFormat(VorbisEncoding.VORBISENC, 48000.0F, -1, 2, -1, -1, false), // 5
45
46 new AudioFormat(VorbisEncoding.VORBISENC, 16000.0F, -1, 1, -1, -1, false), // 18
47 new AudioFormat(VorbisEncoding.VORBISENC, 16000.0F, -1, 2, -1, -1, false), // 19
48 new AudioFormat(VorbisEncoding.VORBISENC, 22050.0F, -1, 1, -1, -1, false), // 20
49 new AudioFormat(VorbisEncoding.VORBISENC, 22050.0F, -1, 2, -1, -1, false), // 21
50 new AudioFormat(VorbisEncoding.VORBISENC, 24000.0F, -1, 1, -1, -1, false), // 22
51 new AudioFormat(VorbisEncoding.VORBISENC, 24000.0F, -1, 2, -1, -1, false), // 23
52
53 new AudioFormat(VorbisEncoding.VORBISENC, 8000.0F, -1, 1, -1, -1, false), // 36
54 new AudioFormat(VorbisEncoding.VORBISENC, 8000.0F, -1, 2, -1, -1, false), // 37
55 new AudioFormat(VorbisEncoding.VORBISENC, 11025.0F, -1, 1, -1, -1, false), // 38
56 new AudioFormat(VorbisEncoding.VORBISENC, 11025.0F, -1, 2, -1, -1, false), // 39
57 new AudioFormat(VorbisEncoding.VORBISENC, 12000.0F, -1, 1, -1, -1, false), // 40
58 new AudioFormat(VorbisEncoding.VORBISENC, 12000.0F, -1, 2, -1, -1, false), // 41
59 };
60
61 private static final AudioFormat[] OUTPUT_FORMATS =
62 {
63 new AudioFormat(8000.0F, 16, 1, true, false), // 0
64 new AudioFormat(8000.0F, 16, 1, true, true), // 1
65 new AudioFormat(8000.0F, 16, 2, true, false), // 2
66 new AudioFormat(8000.0F, 16, 2, true, true), // 3
67 /* 24 and 32 bit not yet possible
68 new AudioFormat(8000.0F, 24, 1, true, false),
69 new AudioFormat(8000.0F, 24, 1, true, true),
70 new AudioFormat(8000.0F, 24, 2, true, false),
71 new AudioFormat(8000.0F, 24, 2, true, true),
72 new AudioFormat(8000.0F, 32, 1, true, false),
73 new AudioFormat(8000.0F, 32, 1, true, true),
74 new AudioFormat(8000.0F, 32, 2, true, false),
75 new AudioFormat(8000.0F, 32, 2, true, true),
76 */
77 new AudioFormat(11025.0F, 16, 1, true, false), // 4
78 new AudioFormat(11025.0F, 16, 1, true, true), // 5
79 new AudioFormat(11025.0F, 16, 2, true, false), // 6
80 new AudioFormat(11025.0F, 16, 2, true, true), // 7
81 /* 24 and 32 bit not yet possible
82 new AudioFormat(11025.0F, 24, 1, true, false),
83 new AudioFormat(11025.0F, 24, 1, true, true),
84 new AudioFormat(11025.0F, 24, 2, true, false),
85 new AudioFormat(11025.0F, 24, 2, true, true),
86 new AudioFormat(11025.0F, 32, 1, true, false),
87 new AudioFormat(11025.0F, 32, 1, true, true),
88 new AudioFormat(11025.0F, 32, 2, true, false),
89 new AudioFormat(11025.0F, 32, 2, true, true),
90 */
91 new AudioFormat(12000.0F, 16, 1, true, false), // 8
92 new AudioFormat(12000.0F, 16, 1, true, true), // 9
93 new AudioFormat(12000.0F, 16, 2, true, false), // 10
94 new AudioFormat(12000.0F, 16, 2, true, true), // 11
95 /* 24 and 32 bit not yet possible
96 new AudioFormat(12000.0F, 24, 1, true, false),
97 new AudioFormat(12000.0F, 24, 1, true, true),
98 new AudioFormat(12000.0F, 24, 2, true, false),
99 new AudioFormat(12000.0F, 24, 2, true, true),
100 new AudioFormat(12000.0F, 32, 1, true, false),
101 new AudioFormat(12000.0F, 32, 1, true, true),
102 new AudioFormat(12000.0F, 32, 2, true, false),
103 new AudioFormat(12000.0F, 32, 2, true, true),
104 */
105 new AudioFormat(16000.0F, 16, 1, true, false), // 12
106 new AudioFormat(16000.0F, 16, 1, true, true), // 13
107 new AudioFormat(16000.0F, 16, 2, true, false), // 14
108 new AudioFormat(16000.0F, 16, 2, true, true), // 15
109 /* 24 and 32 bit not yet possible
110 new AudioFormat(16000.0F, 24, 1, true, false),
111 new AudioFormat(16000.0F, 24, 1, true, true),
112 new AudioFormat(16000.0F, 24, 2, true, false),
113 new AudioFormat(16000.0F, 24, 2, true, true),
114 new AudioFormat(16000.0F, 32, 1, true, false),
115 new AudioFormat(16000.0F, 32, 1, true, true),
116 new AudioFormat(16000.0F, 32, 2, true, false),
117 new AudioFormat(16000.0F, 32, 2, true, true),
118 */
119 new AudioFormat(22050.0F, 16, 1, true, false), // 16
120 new AudioFormat(22050.0F, 16, 1, true, true), // 17
121 new AudioFormat(22050.0F, 16, 2, true, false), // 18
122 new AudioFormat(22050.0F, 16, 2, true, true), // 19
123 /* 24 and 32 bit not yet possible
124 new AudioFormat(22050.0F, 24, 1, true, false),
125 new AudioFormat(22050.0F, 24, 1, true, true),
126 new AudioFormat(22050.0F, 24, 2, true, false),
127 new AudioFormat(22050.0F, 24, 2, true, true),
128 new AudioFormat(22050.0F, 32, 1, true, false),
129 new AudioFormat(22050.0F, 32, 1, true, true),
130 new AudioFormat(22050.0F, 32, 2, true, false),
131 new AudioFormat(22050.0F, 32, 2, true, true),
132 */
133 new AudioFormat(24000.0F, 16, 1, true, false), // 20
134 new AudioFormat(24000.0F, 16, 1, true, true), // 21
135 new AudioFormat(24000.0F, 16, 2, true, false), // 22
136 new AudioFormat(24000.0F, 16, 2, true, true), // 23
137 /* 24 and 32 bit not yet possible
138 new AudioFormat(24000.0F, 24, 1, true, false),
139 new AudioFormat(24000.0F, 24, 1, true, true),
140 new AudioFormat(24000.0F, 24, 2, true, false),
141 new AudioFormat(24000.0F, 24, 2, true, true),
142 new AudioFormat(24000.0F, 32, 1, true, false),
143 new AudioFormat(24000.0F, 32, 1, true, true),
144 new AudioFormat(24000.0F, 32, 2, true, false),
145 new AudioFormat(24000.0F, 32, 2, true, true),
146 */
147 new AudioFormat(32000.0F, 16, 1, true, false), // 24
148 new AudioFormat(32000.0F, 16, 1, true, true), // 25
149 new AudioFormat(32000.0F, 16, 2, true, false), // 26
150 new AudioFormat(32000.0F, 16, 2, true, true), // 27
151 /* 24 and 32 bit not yet possible
152 new AudioFormat(32000.0F, 24, 1, true, false),
153 new AudioFormat(32000.0F, 24, 1, true, true),
154 new AudioFormat(32000.0F, 24, 2, true, false),
155 new AudioFormat(32000.0F, 24, 2, true, true),
156 new AudioFormat(32000.0F, 32, 1, true, false),
157 new AudioFormat(32000.0F, 32, 1, true, true),
158 new AudioFormat(32000.0F, 32, 2, true, false),
159 new AudioFormat(32000.0F, 32, 2, true, true),
160 */
161 new AudioFormat(44100.0F, 16, 1, true, false), // 28
162 new AudioFormat(44100.0F, 16, 1, true, true), // 29
163 new AudioFormat(44100.0F, 16, 2, true, false), // 30
164 new AudioFormat(44100.0F, 16, 2, true, true), // 31
165 /* 24 and 32 bit not yet possible
166 new AudioFormat(44100.0F, 24, 1, true, false),
167 new AudioFormat(44100.0F, 24, 1, true, true),
168 new AudioFormat(44100.0F, 24, 2, true, false),
169 new AudioFormat(44100.0F, 24, 2, true, true),
170 new AudioFormat(44100.0F, 32, 1, true, false),
171 new AudioFormat(44100.0F, 32, 1, true, true),
172 new AudioFormat(44100.0F, 32, 2, true, false),
173 new AudioFormat(44100.0F, 32, 2, true, true),
174 */
175 new AudioFormat(48000.0F, 16, 1, true, false), // 32
176 new AudioFormat(48000.0F, 16, 1, true, true), // 33
177 new AudioFormat(48000.0F, 16, 2, true, false), // 34
178 new AudioFormat(48000.0F, 16, 2, true, true), // 35
179 /* 24 and 32 bit not yet possible
180 new AudioFormat(48000.0F, 24, 1, true, false),
181 new AudioFormat(48000.0F, 24, 1, true, true),
182 new AudioFormat(48000.0F, 24, 2, true, false),
183 new AudioFormat(48000.0F, 24, 2, true, true),
184 new AudioFormat(48000.0F, 32, 1, true, false),
185 new AudioFormat(48000.0F, 32, 1, true, true),
186 new AudioFormat(48000.0F, 32, 2, true, false),
187 new AudioFormat(48000.0F, 32, 2, true, true),
188 */
189 };
190
191 private static final boolean t = true;
192 private static final boolean f = false;
193
194 /*
195 * One row for each source format.
196 */
197 private static final boolean[][] CONVERSIONS =
198 {
199 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,t,t,f,f,f,f, f,f,f,f,f,f}, // 0
200 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,t,t,f,f, f,f,f,f,f,f}, // 1
201 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,t,t, f,f,f,f,f,f}, // 2
202 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, t,t,f,f,f,f}, // 3
203 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,t,t,f,f}, // 4
204 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,t,t}, // 5
205
206 {f,f,f,f,f,f,f,f,f,f, f,f,t,t,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 18
207 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,t,t,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 19
208 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,t,t,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 20
209 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,t,t, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 21
210 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, t,t,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 22
211 {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,t,t,f,f,f,f,f,f, f,f,f,f,f,f}, // 23
212
213 {t,t,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 36
214 {f,f,t,t,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 37
215 {f,f,f,f,t,t,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 38
216 {f,f,f,f,f,f,t,t,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 39
217 {f,f,f,f,f,f,f,f,t,t, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 40
218 {f,f,f,f,f,f,f,f,f,f, t,t,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f}, // 41
219
220 };
221
222 /**
223 * Constructor.
224 */
225 public VorbisFormatConversionProvider()
226 {
227 super(Arrays.asList(INPUT_FORMATS), Arrays.asList(OUTPUT_FORMATS), CONVERSIONS);
228 }
229
230 /**
231 * Returns converted AudioInputStream.
232 */
233 public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream audioInputStream)
234 {
235 if (isConversionSupported(targetFormat, audioInputStream.getFormat()))
236 {
237 return new DecodedVorbisAudioInputStream(targetFormat, audioInputStream);
238 }
239 else
240 {
241 throw new IllegalArgumentException("conversion not supported");
242 }
243 }
244}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileFormat.java b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileFormat.java
new file mode 100644
index 0000000000..28b7c92a2a
--- /dev/null
+++ b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileFormat.java
@@ -0,0 +1,85 @@
1/*
2 * VorbisAudioFileFormat.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.file;
24
25import java.util.Map;
26
27import javax.sound.sampled.AudioFormat;
28
29import org.tritonus.share.sampled.file.TAudioFileFormat;
30
31/**
32 * @author JavaZOOM
33 */
34public class VorbisAudioFileFormat extends TAudioFileFormat
35{
36 /**
37 * Contructor.
38 * @param type
39 * @param audioFormat
40 * @param nLengthInFrames
41 * @param nLengthInBytes
42 */
43 public VorbisAudioFileFormat(Type type, AudioFormat audioFormat, int nLengthInFrames, int nLengthInBytes, Map properties)
44 {
45 super(type, audioFormat, nLengthInFrames, nLengthInBytes, properties);
46 }
47
48 /**
49 * Ogg Vorbis audio file format parameters.
50 * Some parameters might be unavailable. So availability test is required before reading any parameter.
51 *
52 * <br>AudioFileFormat parameters.
53 * <ul>
54 * <li><b>duration</b> [Long], duration in microseconds.
55 * <li><b>title</b> [String], Title of the stream.
56 * <li><b>author</b> [String], Name of the artist of the stream.
57 * <li><b>album</b> [String], Name of the album of the stream.
58 * <li><b>date</b> [String], The date (year) of the recording or release of the stream.
59 * <li><b>copyright</b> [String], Copyright message of the stream.
60 * <li><b>comment</b> [String], Comment of the stream.
61 * </ul>
62 * <br>Ogg Vorbis parameters.
63 * <ul>
64 * <li><b>ogg.length.bytes</b> [Integer], length in bytes.
65 * <li><b>ogg.bitrate.min.bps</b> [Integer], minimum bitrate.
66 * <li><b>ogg.bitrate.nominal.bps</b> [Integer], nominal bitrate.
67 * <li><b>ogg.bitrate.max.bps</b> [Integer], maximum bitrate.
68 * <li><b>ogg.channels</b> [Integer], number of channels 1 : mono, 2 : stereo.
69 * <li><b>ogg.frequency.hz</b> [Integer], sampling rate in hz.
70 * <li><b>ogg.version</b> [Integer], version.
71 * <li><b>ogg.serial</b> [Integer], serial number.
72 * <li><b>ogg.comment.track</b> [String], track number.
73 * <li><b>ogg.comment.genre</b> [String], genre field.
74 * <li><b>ogg.comment.encodedby</b> [String], encoded by field.
75 * <li><b>ogg.comment.ext</b> [String], extended comments (indexed):
76 * <br>For instance :
77 * <br>ogg.comment.ext.1=Something
78 * <br>ogg.comment.ext.2=Another comment
79 * </ul>
80 */
81 public Map properties()
82 {
83 return super.properties();
84 }
85}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileReader.java b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileReader.java
new file mode 100644
index 0000000000..40bc9cadee
--- /dev/null
+++ b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileReader.java
@@ -0,0 +1,502 @@
1/*
2 * VorbisAudioFileReader.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.file;
24
25import java.io.BufferedInputStream;
26import java.io.File;
27import java.io.FileInputStream;
28import java.io.IOException;
29import java.io.InputStream;
30import java.net.URL;
31import java.util.HashMap;
32import java.util.StringTokenizer;
33
34import javax.sound.sampled.AudioFileFormat;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioInputStream;
37import javax.sound.sampled.AudioSystem;
38import javax.sound.sampled.UnsupportedAudioFileException;
39
40import org.tritonus.share.TDebug;
41import org.tritonus.share.sampled.file.TAudioFileReader;
42
43import com.jcraft.jogg.Packet;
44import com.jcraft.jogg.Page;
45import com.jcraft.jogg.StreamState;
46import com.jcraft.jogg.SyncState;
47import com.jcraft.jorbis.Block;
48import com.jcraft.jorbis.Comment;
49import com.jcraft.jorbis.DspState;
50import com.jcraft.jorbis.Info;
51import com.jcraft.jorbis.JOrbisException;
52import com.jcraft.jorbis.VorbisFile;
53
54/**
55 * This class implements the AudioFileReader class and provides an
56 * Ogg Vorbis file reader for use with the Java Sound Service Provider Interface.
57 */
58public class VorbisAudioFileReader extends TAudioFileReader
59{
60 private SyncState oggSyncState_ = null;
61 private StreamState oggStreamState_ = null;
62 private Page oggPage_ = null;
63 private Packet oggPacket_ = null;
64 private Info vorbisInfo = null;
65 private Comment vorbisComment = null;
66 private DspState vorbisDspState = null;
67 private Block vorbisBlock = null;
68 private int bufferMultiple_ = 4;
69 private int bufferSize_ = bufferMultiple_ * 256 * 2;
70 private int convsize = bufferSize_ * 2;
71 private byte[] convbuffer = new byte[convsize];
72 private byte[] buffer = null;
73 private int bytes = 0;
74 private int rate = 0;
75 private int channels = 0;
76
77 private int index = 0;
78 private InputStream oggBitStream_ = null;
79
80 private static final int INITAL_READ_LENGTH = 64000;
81 private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
82
83 public VorbisAudioFileReader()
84 {
85 super(MARK_LIMIT, true);
86 }
87
88 /**
89 * Return the AudioFileFormat from the given file.
90 */
91 public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException
92 {
93 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioFileFormat(File file)");
94 InputStream inputStream = null;
95 try
96 {
97 inputStream = new BufferedInputStream(new FileInputStream(file));
98 inputStream.mark(MARK_LIMIT);
99 AudioFileFormat aff = getAudioFileFormat(inputStream);
100 inputStream.reset();
101 // Get Vorbis file info such as length in seconds.
102 VorbisFile vf = new VorbisFile(file.getAbsolutePath());
103 return getAudioFileFormat(inputStream,(int) file.length(), (int) Math.round((vf.time_total(-1))*1000));
104 }
105 catch (JOrbisException e)
106 {
107 throw new IOException(e.getMessage());
108 }
109 finally
110 {
111 if (inputStream != null) inputStream.close();
112 }
113 }
114
115 /**
116 * Return the AudioFileFormat from the given URL.
117 */
118 public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException
119 {
120 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioFileFormat(URL url)");
121 InputStream inputStream = url.openStream();
122 try
123 {
124 return getAudioFileFormat(inputStream);
125 }
126 finally
127 {
128 if (inputStream != null) inputStream.close();
129 }
130 }
131
132 /**
133 * Return the AudioFileFormat from the given InputStream.
134 */
135 public AudioFileFormat getAudioFileFormat(InputStream inputStream) throws UnsupportedAudioFileException, IOException
136 {
137 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioFileFormat(InputStream inputStream)");
138 try
139 {
140 if (!inputStream.markSupported()) inputStream = new BufferedInputStream(inputStream);
141 inputStream.mark(MARK_LIMIT);
142 return getAudioFileFormat(inputStream, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED);
143 }
144 finally
145 {
146 inputStream.reset();
147 }
148 }
149
150 /**
151 * Return the AudioFileFormat from the given InputStream and length in bytes.
152 */
153 public AudioFileFormat getAudioFileFormat(InputStream inputStream, long medialength) throws UnsupportedAudioFileException, IOException
154 {
155 return getAudioFileFormat(inputStream, (int) medialength, AudioSystem.NOT_SPECIFIED);
156 }
157
158
159 /**
160 * Return the AudioFileFormat from the given InputStream, length in bytes and length in milliseconds.
161 */
162 protected AudioFileFormat getAudioFileFormat(InputStream bitStream, int mediaLength, int totalms) throws UnsupportedAudioFileException, IOException
163 {
164 HashMap aff_properties = new HashMap();
165 HashMap af_properties = new HashMap();
166 if (totalms == AudioSystem.NOT_SPECIFIED)
167 {
168 totalms = 0;
169 }
170 if (totalms <= 0)
171 {
172 totalms = 0;
173 }
174 else
175 {
176 aff_properties.put("duration",new Long(totalms*1000));
177 }
178 oggBitStream_ = bitStream;
179 init_jorbis();
180 index = 0;
181 try
182 {
183 readHeaders(aff_properties, af_properties);
184 }
185 catch (IOException ioe)
186 {
187 if (TDebug.TraceAudioFileReader)
188 {
189 TDebug.out(ioe.getMessage());
190 }
191 throw new UnsupportedAudioFileException(ioe.getMessage());
192 }
193
194 String dmp = vorbisInfo.toString();
195 if (TDebug.TraceAudioFileReader)
196 {
197 TDebug.out(dmp);
198 }
199 int ind = dmp.lastIndexOf("bitrate:");
200 int minbitrate = -1;
201 int nominalbitrate = -1;
202 int maxbitrate = -1;
203 if (ind != -1)
204 {
205 dmp = dmp.substring(ind + 8, dmp.length());
206 StringTokenizer st = new StringTokenizer(dmp, ",");
207 if (st.hasMoreTokens())
208 {
209 minbitrate = Integer.parseInt(st.nextToken());
210 }
211 if (st.hasMoreTokens())
212 {
213 nominalbitrate = Integer.parseInt(st.nextToken());
214 }
215 if (st.hasMoreTokens())
216 {
217 maxbitrate = Integer.parseInt(st.nextToken());
218 }
219 }
220 if (nominalbitrate > 0) af_properties.put("bitrate",new Integer(nominalbitrate));
221 af_properties.put("vbr",new Boolean(true));
222
223 if (minbitrate > 0) aff_properties.put("ogg.bitrate.min.bps",new Integer(minbitrate));
224 if (maxbitrate > 0) aff_properties.put("ogg.bitrate.max.bps",new Integer(maxbitrate));
225 if (nominalbitrate > 0) aff_properties.put("ogg.bitrate.nominal.bps",new Integer(nominalbitrate));
226 if (vorbisInfo.channels > 0) aff_properties.put("ogg.channels",new Integer(vorbisInfo.channels));
227 if (vorbisInfo.rate > 0) aff_properties.put("ogg.frequency.hz",new Integer(vorbisInfo.rate));
228 if (mediaLength > 0) aff_properties.put("ogg.length.bytes",new Integer(mediaLength));
229 aff_properties.put("ogg.version",new Integer(vorbisInfo.version));
230
231 AudioFormat.Encoding encoding = VorbisEncoding.VORBISENC;
232 AudioFormat format = new VorbisAudioFormat(encoding, vorbisInfo.rate, AudioSystem.NOT_SPECIFIED, vorbisInfo.channels, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED, true,af_properties);
233 AudioFileFormat.Type type = VorbisFileFormatType.OGG;
234 return new VorbisAudioFileFormat(VorbisFileFormatType.OGG, format, AudioSystem.NOT_SPECIFIED, mediaLength,aff_properties);
235 }
236
237 /**
238 * Return the AudioInputStream from the given InputStream.
239 */
240 public AudioInputStream getAudioInputStream(InputStream inputStream) throws UnsupportedAudioFileException, IOException
241 {
242 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(InputStream inputStream)");
243 return getAudioInputStream(inputStream, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED);
244 }
245
246 /**
247 * Return the AudioInputStream from the given InputStream.
248 */
249 public AudioInputStream getAudioInputStream(InputStream inputStream, int medialength, int totalms) throws UnsupportedAudioFileException, IOException
250 {
251 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(InputStream inputStreamint medialength, int totalms)");
252 try
253 {
254 if (!inputStream.markSupported()) inputStream = new BufferedInputStream(inputStream);
255 inputStream.mark(MARK_LIMIT);
256 AudioFileFormat audioFileFormat = getAudioFileFormat(inputStream, medialength, totalms);
257 inputStream.reset();
258 return new AudioInputStream(inputStream, audioFileFormat.getFormat(), audioFileFormat.getFrameLength());
259 }
260 catch (UnsupportedAudioFileException e)
261 {
262 inputStream.reset();
263 throw e;
264 }
265 catch (IOException e)
266 {
267 inputStream.reset();
268 throw e;
269 }
270 }
271
272 /**
273 * Return the AudioInputStream from the given File.
274 */
275 public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException
276 {
277 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(File file)");
278 InputStream inputStream = new FileInputStream(file);
279 try
280 {
281 return getAudioInputStream(inputStream);
282 }
283 catch (UnsupportedAudioFileException e)
284 {
285 if (inputStream != null) inputStream.close();
286 throw e;
287 }
288 catch (IOException e)
289 {
290 if (inputStream != null) inputStream.close();
291 throw e;
292 }
293 }
294
295 /**
296 * Return the AudioInputStream from the given URL.
297 */
298 public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException
299 {
300 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(URL url)");
301 InputStream inputStream = url.openStream();
302 try
303 {
304 return getAudioInputStream(inputStream);
305 }
306 catch (UnsupportedAudioFileException e)
307 {
308 if (inputStream != null) inputStream.close();
309 throw e;
310 }
311 catch (IOException e)
312 {
313 if (inputStream != null) inputStream.close();
314 throw e;
315 }
316 }
317
318 /**
319 * Reads headers and comments.
320 */
321 private void readHeaders(HashMap aff_properties, HashMap af_properties) throws IOException
322 {
323 if(TDebug.TraceAudioConverter) TDebug.out("readHeaders(");
324 index = oggSyncState_.buffer(bufferSize_);
325 buffer = oggSyncState_.data;
326 bytes = readFromStream(buffer, index, bufferSize_);
327 if(bytes == -1)
328 {
329 if(TDebug.TraceAudioConverter) TDebug.out("Cannot get any data from selected Ogg bitstream.");
330 throw new IOException("Cannot get any data from selected Ogg bitstream.");
331 }
332 oggSyncState_.wrote(bytes);
333 if(oggSyncState_.pageout(oggPage_) != 1)
334 {
335 if(bytes < bufferSize_)
336 {
337 throw new IOException("EOF");
338 }
339 if(TDebug.TraceAudioConverter) TDebug.out("Input does not appear to be an Ogg bitstream.");
340 throw new IOException("Input does not appear to be an Ogg bitstream.");
341 }
342 oggStreamState_.init(oggPage_.serialno());
343 vorbisInfo.init();
344 vorbisComment.init();
345 aff_properties.put("ogg.serial",new Integer(oggPage_.serialno()));
346 if(oggStreamState_.pagein(oggPage_) < 0)
347 {
348 // error; stream version mismatch perhaps
349 if(TDebug.TraceAudioConverter) TDebug.out("Error reading first page of Ogg bitstream data.");
350 throw new IOException("Error reading first page of Ogg bitstream data.");
351 }
352 if(oggStreamState_.packetout(oggPacket_) != 1)
353 {
354 // no page? must not be vorbis
355 if(TDebug.TraceAudioConverter) TDebug.out("Error reading initial header packet.");
356 throw new IOException("Error reading initial header packet.");
357 }
358 if(vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_) < 0)
359 {
360 // error case; not a vorbis header
361 if(TDebug.TraceAudioConverter) TDebug.out("This Ogg bitstream does not contain Vorbis audio data.");
362 throw new IOException("This Ogg bitstream does not contain Vorbis audio data.");
363 }
364 int i = 0;
365 while(i < 2)
366 {
367 while(i < 2)
368 {
369 int result = oggSyncState_.pageout(oggPage_);
370 if(result == 0)
371 {
372 break;
373 } // Need more data
374 if(result == 1)
375 {
376 oggStreamState_.pagein(oggPage_);
377 while(i < 2)
378 {
379 result = oggStreamState_.packetout(oggPacket_);
380 if(result == 0)
381 {
382 break;
383 }
384 if(result == -1)
385 {
386 if(TDebug.TraceAudioConverter) TDebug.out("Corrupt secondary header. Exiting.");
387 throw new IOException("Corrupt secondary header. Exiting.");
388 }
389 vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_);
390 i++;
391 }
392 }
393 }
394 index = oggSyncState_.buffer(bufferSize_);
395 buffer = oggSyncState_.data;
396 bytes = readFromStream(buffer, index, bufferSize_);
397 if(bytes == -1)
398 {
399 break;
400 }
401 if(bytes == 0 && i < 2)
402 {
403 if(TDebug.TraceAudioConverter) TDebug.out("End of file before finding all Vorbis headers!");
404 throw new IOException("End of file before finding all Vorbis headers!");
405 }
406 oggSyncState_.wrote(bytes);
407 }
408 // Read Ogg Vorbis comments.
409 byte[][] ptr = vorbisComment.user_comments;
410 String currComment = "";
411 int c = 0;
412 for(int j = 0; j < ptr.length; j++)
413 {
414 if(ptr[j] == null)
415 {
416 break;
417 }
418 currComment = (new String(ptr[j], 0, ptr[j].length - 1)).trim();
419 if(TDebug.TraceAudioConverter) TDebug.out(currComment);
420 if (currComment.toLowerCase().startsWith("artist"))
421 {
422 aff_properties.put("author",currComment.substring(7));
423 }
424 else if (currComment.toLowerCase().startsWith("title"))
425 {
426 aff_properties.put("title",currComment.substring(6));
427 }
428 else if (currComment.toLowerCase().startsWith("album"))
429 {
430 aff_properties.put("album",currComment.substring(6));
431 }
432 else if (currComment.toLowerCase().startsWith("date"))
433 {
434 aff_properties.put("date",currComment.substring(5));
435 }
436 else if (currComment.toLowerCase().startsWith("copyright"))
437 {
438 aff_properties.put("copyright",currComment.substring(10));
439 }
440 else if (currComment.toLowerCase().startsWith("comment"))
441 {
442 aff_properties.put("comment",currComment.substring(8));
443 }
444 else if (currComment.toLowerCase().startsWith("genre"))
445 {
446 aff_properties.put("ogg.comment.genre",currComment.substring(6));
447 }
448 else if (currComment.toLowerCase().startsWith("tracknumber"))
449 {
450 aff_properties.put("ogg.comment.track",currComment.substring(12));
451 }
452 else
453 {
454 c++;
455 aff_properties.put("ogg.comment.ext."+c,currComment);
456 }
457 aff_properties.put("ogg.comment.encodedby",new String(vorbisComment.vendor, 0, vorbisComment.vendor.length - 1));
458 }
459 }
460
461 /**
462 * Reads from the oggBitStream_ a specified number of Bytes(bufferSize_) worth
463 * starting at index and puts them in the specified buffer[].
464 *
465 * @return the number of bytes read or -1 if error.
466 */
467 private int readFromStream(byte[] buffer, int index, int bufferSize_)
468 {
469 int bytes = 0;
470 try
471 {
472 bytes = oggBitStream_.read(buffer, index, bufferSize_);
473 }
474 catch (Exception e)
475 {
476 if (TDebug.TraceAudioFileReader)
477 {
478 TDebug.out("Cannot Read Selected Song");
479 }
480 bytes = -1;
481 }
482 return bytes;
483 }
484
485 /**
486 * Initializes all the jOrbis and jOgg vars that are used for song playback.
487 */
488 private void init_jorbis()
489 {
490 oggSyncState_ = new SyncState();
491 oggStreamState_ = new StreamState();
492 oggPage_ = new Page();
493 oggPacket_ = new Packet();
494 vorbisInfo = new Info();
495 vorbisComment = new Comment();
496 vorbisDspState = new DspState();
497 vorbisBlock = new Block(vorbisDspState);
498 buffer = null;
499 bytes = 0;
500 oggSyncState_.init();
501 }
502}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFormat.java b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFormat.java
new file mode 100644
index 0000000000..829ab2f8cd
--- /dev/null
+++ b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFormat.java
@@ -0,0 +1,66 @@
1/*
2 * VorbisAudioFormat.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.file;
24
25import java.util.Map;
26
27import javax.sound.sampled.AudioFormat;
28
29import org.tritonus.share.sampled.TAudioFormat;
30
31/**
32 * @author JavaZOOM
33 */
34public class VorbisAudioFormat extends TAudioFormat
35{
36 /**
37 * Constructor.
38 * @param encoding
39 * @param nFrequency
40 * @param SampleSizeInBits
41 * @param nChannels
42 * @param FrameSize
43 * @param FrameRate
44 * @param isBigEndian
45 * @param properties
46 */
47 public VorbisAudioFormat(AudioFormat.Encoding encoding, float nFrequency, int SampleSizeInBits, int nChannels, int FrameSize, float FrameRate, boolean isBigEndian, Map properties)
48 {
49 super(encoding, nFrequency, SampleSizeInBits, nChannels, FrameSize, FrameRate, isBigEndian, properties);
50 }
51
52 /**
53 * Ogg Vorbis audio format parameters.
54 * Some parameters might be unavailable. So availability test is required before reading any parameter.
55 *
56 * <br>AudioFormat parameters.
57 * <ul>
58 * <li><b>bitrate</b> [Integer], bitrate in bits per seconds, average bitrate for VBR enabled stream.
59 * <li><b>vbr</b> [Boolean], VBR flag.
60 * </ul>
61 */
62 public Map properties()
63 {
64 return super.properties();
65 }
66}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisEncoding.java b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisEncoding.java
new file mode 100644
index 0000000000..7800f1556d
--- /dev/null
+++ b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisEncoding.java
@@ -0,0 +1,41 @@
1/*
2 * VorbisEncoding.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.file;
24
25import javax.sound.sampled.AudioFormat;
26
27/**
28 * Encodings used by the VORBIS audio decoder.
29 */
30public class VorbisEncoding extends AudioFormat.Encoding
31{
32 public static final AudioFormat.Encoding VORBISENC = new VorbisEncoding("VORBISENC");
33
34 /**
35 * Constructors.
36 */
37 public VorbisEncoding(String name)
38 {
39 super(name);
40 }
41}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisFileFormatType.java b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisFileFormatType.java
new file mode 100644
index 0000000000..f006bbfe1d
--- /dev/null
+++ b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisFileFormatType.java
@@ -0,0 +1,41 @@
1/*
2 * VorbisFileFormatType.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.file;
24
25import javax.sound.sampled.AudioFileFormat;
26
27/**
28 * FileFormatTypes used by the VORBIS audio decoder.
29 */
30public class VorbisFileFormatType extends AudioFileFormat.Type
31{
32 public static final AudioFileFormat.Type VORBIS = new VorbisFileFormatType("VORBIS", "ogg");
33 public static final AudioFileFormat.Type OGG = new VorbisFileFormatType("OGG", "ogg");
34 /**
35 * Constructor.
36 */
37 public VorbisFileFormatType(String name, String extension)
38 {
39 super(name, extension);
40 }
41}
diff --git a/songdbj/net/shredzone/ifish/ltr/FormatDecodeException.java b/songdbj/net/shredzone/ifish/ltr/FormatDecodeException.java
new file mode 100644
index 0000000000..72522eaa4d
--- /dev/null
+++ b/songdbj/net/shredzone/ifish/ltr/FormatDecodeException.java
@@ -0,0 +1,66 @@
1/*
2 * iFish -- An iRiver iHP jukebox database creation tool
3 *
4 * Copyright (c) 2004 Richard "Shred" Körber
5 * http://www.shredzone.net/go/ifish
6 *
7 *-----------------------------------------------------------------------
8 * ***** BEGIN LICENSE BLOCK *****
9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
10 *
11 * The contents of this file are subject to the Mozilla Public License Version
12 * 1.1 (the "License"); you may not use this file except in compliance with
13 * the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis,
17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
18 * for the specific language governing rights and limitations under the
19 * License.
20 *
21 * The Original Code is IFISH.
22 *
23 * The Initial Developer of the Original Code is
24 * Richard "Shred" Körber.
25 * Portions created by the Initial Developer are Copyright (C) 2004
26 * the Initial Developer. All Rights Reserved.
27 *
28 * Contributor(s):
29 *
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
41 *
42 * ***** END LICENSE BLOCK *****
43 */
44
45package net.shredzone.ifish.ltr;
46
47/**
48 * This exception signals that the Tag could not be decoded for various
49 * reasons.
50 *
51 * @author Richard Körber &lt;dev@shredzone.de&gt;
52 * @version $Id$
53 */
54public class FormatDecodeException extends Exception {
55 private static final long serialVersionUID = 3690758397339187507L;
56
57 /**
58 * Constructor for the FormatDecodeException object
59 *
60 * @param msg A message
61 */
62 public FormatDecodeException( String msg ) {
63 super( msg );
64 }
65
66}
diff --git a/songdbj/net/shredzone/ifish/ltr/LTR.java b/songdbj/net/shredzone/ifish/ltr/LTR.java
new file mode 100644
index 0000000000..8a38676583
--- /dev/null
+++ b/songdbj/net/shredzone/ifish/ltr/LTR.java
@@ -0,0 +1,251 @@
1/*
2 * iFish -- An iRiver iHP jukebox database creation tool
3 *
4 * Copyright (c) 2004 Richard "Shred" Körber
5 * http://www.shredzone.net/go/ifish
6 *
7 *-----------------------------------------------------------------------
8 * ***** BEGIN LICENSE BLOCK *****
9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
10 *
11 * The contents of this file are subject to the Mozilla Public License Version
12 * 1.1 (the "License"); you may not use this file except in compliance with
13 * the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis,
17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
18 * for the specific language governing rights and limitations under the
19 * License.
20 *
21 * The Original Code is IFISH.
22 *
23 * The Initial Developer of the Original Code is
24 * Richard "Shred" Körber.
25 * Portions created by the Initial Developer are Copyright (C) 2004
26 * the Initial Developer. All Rights Reserved.
27 *
28 * Contributor(s):
29 *
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
41 *
42 * ***** END LICENSE BLOCK *****
43 */
44
45package net.shredzone.ifish.ltr;
46
47import java.io.*;
48
49/**
50 * The Base Class for the Lightweight Tag Reader. LTR was made to read
51 * the basic tag information of MP3 (IDv1, IDv2), Ogg Vorbis and ASF/WMA
52 * files. It is lightweight because it is optimized for speed, and is
53 * only able to read the tag information, but unable to edit them.
54 *
55 * @author Richard Körber &lt;dev@shredzone.de&gt;
56 * @version $Id$
57 */
58public abstract class LTR {
59 protected RandomAccessFile in; // The file to be checked
60
61 /**
62 * Create a new LTR object. It is connected to the file to be decoded,
63 * by a RandomAccessFile. The cursor position will be changed during
64 * recognizing and decoding.
65 *
66 * @param in RandomAccessFile to be used
67 * @throws FormatDecodeException Description of the Exception
68 */
69 public LTR( RandomAccessFile in )
70 throws FormatDecodeException {
71 this.in = in;
72 try {
73 in.seek( 0 ); // To the beginning of file
74 } catch( IOException e ) {
75 throw new FormatDecodeException( "couldn't seek: " + e.toString() );
76 }
77 }
78
79 /**
80 * Create an LTR object for a file. If the file given, was not
81 * recognized or did not contain any tags, null will be returned.
82 *
83 * @param file File to open
84 * @return LTR to this file, or null
85 * @exception IOException Description of the Exception
86 */
87 public static LTR create( File file ) {
88 RandomAccessFile in = null;
89 LTR result = null;
90
91 try {
92 in = new RandomAccessFile( file, "r" );
93
94 try {
95 result = new TagOggVorbis( in );
96 return result;
97 } catch( FormatDecodeException e ) {}
98
99 try {
100 result = new TagMp3v2( in );
101 return result;
102 } catch( FormatDecodeException e ) {}
103
104 try {
105 result = new TagMp3v200( in );
106 return result;
107 } catch( FormatDecodeException e ) {}
108
109 try {
110 result = new TagAsf( in, file );
111 return result;
112 }catch( FormatDecodeException e ) {}
113
114 try {
115 // Always check ID3v1 *after* ID3v2, because a lot of ID3v2
116 // files also contain ID3v1 tags with limited content.
117 result = new TagMp3v1( in );
118 return result;
119 } catch( FormatDecodeException e ) {}
120 }catch(IOException e) {
121 return null;
122 } finally {
123 try {
124 if( in!=null ) in.close();
125 } catch(IOException e) {
126 System.out.println("Failed to close file.");
127 }
128 }
129
130 return null;
131 }
132
133 /**
134 * Get the type of this file. This is usually the compression format
135 * itself (e.g. "OGG" or "MP3"). If there are different taggings for
136 * this format, the used tag format is appended after a slash (e.g.
137 * "MP3/id3v2").
138 *
139 * @return The type
140 */
141 public abstract String getType();
142
143 /**
144 * Get the artist.
145 *
146 * @return The artist (never null)
147 */
148 public abstract String getArtist();
149
150 /**
151 * Get the album.
152 *
153 * @return The album (never null)
154 */
155 public abstract String getAlbum();
156
157 /**
158 * Get the title.
159 *
160 * @return The title (never null)
161 */
162 public abstract String getTitle();
163
164 /**
165 * Get the genre.
166 *
167 * @return The genre (never null)
168 */
169 public abstract String getGenre();
170
171 /**
172 * Get the year.
173 *
174 * @return The year (never null)
175 */
176 public abstract String getYear();
177
178 /**
179 * Get the comment.
180 *
181 * @return The comment (never null)
182 */
183 public abstract String getComment();
184
185 /**
186 * Get the track.
187 *
188 * @return The track (never null)
189 */
190 public abstract String getTrack();
191
192 /**
193 * Read a String of a certain length from the file. It will always use
194 * "ISO-8859-1" encoding!
195 *
196 * @param length Maximum number of bytes to read
197 * @return String that was read
198 * @throws IOException If EOF was already reached
199 */
200 protected String readStringLen( int length )
201 throws IOException {
202 return readStringLen( length, "ISO-8859-1" );
203 }
204
205 /**
206 * Read a String of a certain length from the file. The length will
207 * not be exceeded. No null termination is required. Anyhow an
208 * IOException will be thrown if the EOF was reached before invocation.
209 *
210 * @param length Maximum number of bytes to read
211 * @param charset Charset to be used
212 * @return String that was read
213 * @throws IOException If EOF was already reached
214 */
215 protected String readStringLen( int length, String charset )
216 throws IOException {
217 byte[] buf = new byte[length];
218 int readlength = in.read( buf );
219 if( readlength < 0 ) {
220 throw new IOException( "Unexpected EOF" );
221 }
222 return new String( buf, 0, readlength, charset );
223 }
224
225 /**
226 * Return a string representation of the LTR content.
227 *
228 * @return String representation
229 */
230 public String toString() {
231 StringBuffer buff = new StringBuffer();
232 buff.append( getType() );
233 buff.append( "[ART='" );
234 buff.append( getArtist() );
235 buff.append( "' ALB='" );
236 buff.append( getAlbum() );
237 buff.append( "' TIT='" );
238 buff.append( getTitle() );
239 buff.append( "' TRK='" );
240 buff.append( getTrack() );
241 buff.append( "' GEN='" );
242 buff.append( getGenre() );
243 buff.append( "' YR='" );
244 buff.append( getYear() );
245 buff.append( "' CMT='" );
246 buff.append( getComment() );
247 buff.append( "']" );
248 return buff.toString();
249 }
250
251}
diff --git a/songdbj/net/shredzone/ifish/ltr/LTRmp3.java b/songdbj/net/shredzone/ifish/ltr/LTRmp3.java
new file mode 100644
index 0000000000..1b31c405ba
--- /dev/null
+++ b/songdbj/net/shredzone/ifish/ltr/LTRmp3.java
@@ -0,0 +1,165 @@
1/*
2 * iFish -- An iRiver iHP jukebox database creation tool
3 *
4 * Copyright (c) 2004 Richard "Shred" Körber
5 * http://www.shredzone.net/go/ifish
6 *
7 *-----------------------------------------------------------------------
8 * ***** BEGIN LICENSE BLOCK *****
9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
10 *
11 * The contents of this file are subject to the Mozilla Public License Version
12 * 1.1 (the "License"); you may not use this file except in compliance with
13 * the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis,
17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
18 * for the specific language governing rights and limitations under the
19 * License.
20 *
21 * The Original Code is IFISH.
22 *
23 * The Initial Developer of the Original Code is
24 * Richard "Shred" Körber.
25 * Portions created by the Initial Developer are Copyright (C) 2004
26 * the Initial Developer. All Rights Reserved.
27 *
28 * Contributor(s):
29 *
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
41 *
42 * ***** END LICENSE BLOCK *****
43 */
44
45package net.shredzone.ifish.ltr;
46
47import java.io.*;
48
49/**
50 * The Base Class for mp3 decoding of the Lightweight Tag Reader.
51 *
52 * @author Richard Körber &lt;dev@shredzone.de&gt;
53 * @version $Id$
54 */
55public abstract class LTRmp3 extends LTR {
56
57 private final static String[] genres = {
58 //--- Genres as specified in ID3v1 ---
59 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
60 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other",
61 "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial",
62 "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack",
63 "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
64 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House",
65 "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
66 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
67 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
68 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
69 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
70 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
71 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
72 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
73 "Rock & Roll", "Hard Rock",
74
75 //--- This are WinAmp extensions ---
76 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebop",
77 "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
78 "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
79 "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
80 "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
81 "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
82 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
83 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
84 };
85
86 protected final String charsetV1 = "ISO-8859-1";
87 protected final String charsetV2 = "ISO-8859-1";
88
89 /**
90 * Constructor for the LTRmp3 object
91 *
92 * @param in File to be used
93 * @throws FormatDecodeException Could not decode file
94 */
95 public LTRmp3( RandomAccessFile in )
96 throws FormatDecodeException {
97 super( in );
98 }
99
100 /**
101 * Decode the mp3 numerical Genre code and convert it to a human
102 * readable string. The genre is decoded according to the
103 * specifications found at <a href="http://www.id3.org">www.id3.org</a>,
104 * as well as the WinAmp extensions.
105 *
106 * @param id Genre ID
107 * @return ID String, null if the genre ID was unknown
108 */
109 protected String decodeGenre( int id ) {
110 if( id>=genres.length ) return null;
111 return genres[id];
112 }
113
114 /**
115 * Read an ID3v2 integer. This is a 4 byte big endian value, which is
116 * always not syncsafe.
117 *
118 * @return The integer read.
119 * @throws IOException If there were not enough bytes in the file.
120 */
121 protected int readInt()
122 throws IOException {
123 int val = 0;
124 for( int cnt = 4; cnt > 0; cnt-- ) {
125 val <<= 8;
126 val |= ( in.readByte() & 0xFF );
127 }
128 return val;
129 }
130
131 /**
132 * Read an ID3v2 syncsafe integer. This is a 4 byte big endian value
133 * with the bit 7 of each byte always being 0.
134 *
135 * @return The syncsafe integer read.
136 * @throws IOException If there were not enough bytes in the file.
137 */
138 protected int readSyncsafeInt()
139 throws IOException {
140 int val = 0;
141 for( int cnt = 4; cnt > 0; cnt-- ) {
142 val <<= 7;
143 val |= ( readSyncsafe() & 0x7F );
144 }
145 return val;
146 }
147
148 /**
149 * Read a syncsafe byte. It is made sure that a byte is available in
150 * the file, and that bit 7 is 0. An IOException is thrown otherwise.
151 *
152 * @return The byte read.
153 * @throws IOException If premature EOF was reached or byte was not
154 * syncsafe.
155 */
156 protected byte readSyncsafe()
157 throws IOException {
158 byte read = in.readByte();
159 if(( read & 0x80 ) != 0 ) {
160 throw new IOException( "not syncsafe" );
161 }
162 return read;
163 }
164
165}
diff --git a/songdbj/net/shredzone/ifish/ltr/OggFastFileStream.java b/songdbj/net/shredzone/ifish/ltr/OggFastFileStream.java
new file mode 100644
index 0000000000..f86699b0f1
--- /dev/null
+++ b/songdbj/net/shredzone/ifish/ltr/OggFastFileStream.java
@@ -0,0 +1,249 @@
1/*
2 * iFish -- An iRiver iHP jukebox database creation tool
3 *
4 * Copyright (c) 2004 Richard "Shred" Körber
5 * http://www.shredzone.net/go/ifish
6 *
7 *-----------------------------------------------------------------------
8 * ***** BEGIN LICENSE BLOCK *****
9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
10 *
11 * The contents of this file are subject to the Mozilla Public License Version
12 * 1.1 (the "License"); you may not use this file except in compliance with
13 * the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis,
17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
18 * for the specific language governing rights and limitations under the
19 * License.
20 *
21 * The Original Code is IFISH.
22 *
23 * The Initial Developer of the Original Code is
24 * Richard "Shred" Körber.
25 * Portions created by the Initial Developer are Copyright (C) 2004
26 * the Initial Developer. All Rights Reserved.
27 *
28 * Contributor(s):
29 *
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
41 *
42 * ***** END LICENSE BLOCK *****
43 */
44
45package net.shredzone.ifish.ltr;
46
47import java.io.*;
48import java.util.*;
49
50import de.jarnbjo.ogg.*;
51
52/**
53 * Replacement file reader class. The original J-Ogg FileStream has the
54 * major disadvantage that it reads the entire file, even though we just
55 * need a few byte from it. This FastFileStream will only read as little
56 * information as possible.
57 *
58 * @author Richard Körber &lt;dev@shredzone.de&gt;
59 * @version $Id$
60 */
61public class OggFastFileStream implements PhysicalOggStream {
62 private InputStream sourceStream;
63 private boolean closed = false;
64 private int contentLength = 0;
65 private int position = 0;
66 private HashMap logicalStreams = new HashMap();
67 private OggPage firstPage;
68
69 /**
70 * Constructor for the OggFastFileStream object
71 *
72 * @param in RandomAccessFile to be read
73 * @throws OggFormatException Bad format
74 * @throws IOException IO error
75 */
76 public OggFastFileStream( RandomAccessFile in )
77 throws OggFormatException, IOException {
78 this.sourceStream = new RandomAdapterInputStream( in );
79 contentLength = (int) in.length();
80 firstPage = OggPage.create( sourceStream );
81 position += firstPage.getTotalLength();
82 LogicalOggStreamImpl los = new LogicalOggStreamImpl( this, firstPage.getStreamSerialNumber() );
83 logicalStreams.put( new Integer( firstPage.getStreamSerialNumber() ), los );
84 los.checkFormat( firstPage );
85 }
86
87 /**
88 * Get a collection of the logical streams.
89 *
90 * @return Collection
91 */
92 public Collection getLogicalStreams() {
93 return logicalStreams.values();
94 }
95
96 /**
97 * Checks if the file is open.
98 *
99 * @return true: open, false: closed
100 */
101 public boolean isOpen() {
102 return !closed;
103 }
104
105 /**
106 * Closes the stream
107 *
108 * @throws IOException IO error
109 */
110 public void close()
111 throws IOException {
112 closed = true;
113 sourceStream.close();
114 }
115
116 /**
117 * Get the content length
118 *
119 * @return The content length
120 */
121 public int getContentLength() {
122 return contentLength;
123 }
124
125 /**
126 * Get the current position
127 *
128 * @return Position
129 */
130 public int getPosition() {
131 return position;
132 }
133
134 /**
135 * Get an OggPage.
136 *
137 * @param index Index to be fetched
138 * @return The oggPage value
139 * @throws IOException IO Error
140 */
141 public OggPage getOggPage( int index )
142 throws IOException {
143 if( firstPage != null ) {
144 OggPage tmp = firstPage;
145 firstPage = null;
146 return tmp;
147 } else {
148 OggPage page = OggPage.create( sourceStream );
149 position += page.getTotalLength();
150 return page;
151 }
152 }
153
154 /**
155 * Move the stream to a certain time position.
156 *
157 * @param granulePosition The new position
158 * @throws IOException
159 */
160 public void setTime( long granulePosition )
161 throws IOException {
162 throw new UnsupportedOperationException( "not supported" );
163 }
164
165 /**
166 * Is this FileStream seekable? We pretend we are not, so J-Ogg
167 * will not get some stupid thoughts... ;)
168 *
169 * @return false
170 */
171 public boolean isSeekable() {
172 return false;
173 }
174
175/*--------------------------------------------------------------------*/
176
177 /**
178 * This class repairs a design flaw in JDK1.0. A RandomAccessFile
179 * is not derived from InputStream, though it provides the same API.
180 * This Adapter gives an InputStream view of a Random Access File.
181 * <p>
182 * For a detailed method description, see InputStream.
183 */
184 private static class RandomAdapterInputStream extends InputStream {
185 private RandomAccessFile rf;
186
187 /**
188 * Create a new Adapter.
189 *
190 * @param rf RandomAccessFile to be used
191 */
192 public RandomAdapterInputStream( RandomAccessFile rf ) {
193 this.rf = rf;
194 }
195
196 /**
197 * Read a byte.
198 *
199 * @return Read byte or -1.
200 */
201 public int read() throws IOException {
202 return rf.read();
203 }
204
205 /**
206 * Read a byte array.
207 *
208 * @param b Byte array to be read
209 * @return Number of bytes read or -1
210 */
211 public int read( byte[] b) throws IOException {
212 return rf.read(b);
213 }
214
215 /**
216 * Read into a byte array.
217 *
218 * @param b Byte array to be read
219 * @param off Starting offset
220 * @param len Length
221 * @return Number of bytes read or -1
222 */
223 public int read( byte[] b, int off, int len) throws IOException {
224 return rf.read( b, off, len );
225 }
226
227 /**
228 * Skip a number of bytes in forward direction.
229 *
230 * @param n Number of bytes to skip
231 * @return Number of bytes skipped, or -1
232 */
233 public long skip( long n ) throws IOException {
234 return rf.skipBytes( (int) n );
235 }
236
237 /**
238 * Return the number of available bytes. Here it is the number of
239 * bytes remaining until EOF.
240 *
241 * @return Number of bytes available.
242 */
243 public int available() throws IOException {
244 return (int) (rf.length() - rf.getFilePointer());
245 }
246
247 }
248
249}
diff --git a/songdbj/net/shredzone/ifish/ltr/TagAsf.java b/songdbj/net/shredzone/ifish/ltr/TagAsf.java
new file mode 100644
index 0000000000..fc68789345
--- /dev/null
+++ b/songdbj/net/shredzone/ifish/ltr/TagAsf.java
@@ -0,0 +1,170 @@
1/*
2 * iFish -- An iRiver iHP jukebox database creation tool
3 *
4 * Copyright (c) 2004 Richard "Shred" Körber
5 * http://www.shredzone.net/go/ifish
6 *
7 *-----------------------------------------------------------------------
8 * ***** BEGIN LICENSE BLOCK *****
9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
10 *
11 * The contents of this file are subject to the Mozilla Public License Version
12 * 1.1 (the "License"); you may not use this file except in compliance with
13 * the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis,
17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
18 * for the specific language governing rights and limitations under the
19 * License.
20 *
21 * The Original Code is IFISH.
22 *
23 * The Initial Developer of the Original Code is
24 * Richard "Shred" Körber.
25 * Portions created by the Initial Developer are Copyright (C) 2004
26 * the Initial Developer. All Rights Reserved.
27 *
28 * Contributor(s):
29 *
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
41 *
42 * ***** END LICENSE BLOCK *****
43 */
44
45package net.shredzone.ifish.ltr;
46
47import java.io.*;
48import java.util.List;
49
50import de.jarnbjo.ogg.*;
51import de.jarnbjo.vorbis.*;
52import entagged.audioformats.AudioFile;
53import entagged.audioformats.Tag;
54import entagged.audioformats.asf.AsfFileReader;
55import entagged.audioformats.exceptions.CannotReadException;
56
57/**
58 * Decodes an ASF/WMA stream. It uses parts of the
59 * <a href="http://entagged.sf.net/">Entagged</a> software, which is
60 * copyrighted by the Entagged Development Team, and published under
61 * GPL.
62 * <p>
63 * <em>NOTE</em> that due to the fact that Entagged is GPL, you <em>MUST</em>
64 * remove all entagged sources and this class file if you decide to use
65 * the LGPL or MPL part of the iFish licence!
66 *
67 * @author Richard Körber &lt;dev@shredzone.de&gt;
68 * @version $Id$
69 */
70public class TagAsf extends LTR {
71 private final Tag tag;
72
73 /**
74 * Create a new TagAsf object.
75 *
76 * @param in File to read
77 * @param file Reference to the file itself
78 * @throws FormatDecodeException Couldn't decode this file
79 */
80 public TagAsf( RandomAccessFile in, File file )
81 throws FormatDecodeException {
82 super( in );
83
84 try {
85 final AsfFileReader afr = new AsfFileReader();
86 final AudioFile af = afr.read( file, in );
87 tag = af.getTag();
88 }catch( CannotReadException e ) {
89 throw new FormatDecodeException( "could not decode file: " + e.toString() );
90 }catch( RuntimeException e ) {
91 throw new FormatDecodeException( "error decoding file: " + e.toString() );
92 }
93 }
94
95 /**
96 * Get the type of this file. This is usually the compression format
97 * itself (e.g. "OGG" or "MP3"). If there are different taggings for
98 * this format, the used tag format is appended after a slash (e.g.
99 * "MP3/id3v2").
100 *
101 * @return The type
102 */
103 public String getType() {
104 return "ASF";
105 }
106
107 /**
108 * Get the artist.
109 *
110 * @return The artist (never null)
111 */
112 public String getArtist() {
113 return tag.getFirstArtist().trim();
114 }
115
116 /**
117 * Get the album.
118 *
119 * @return The album (never null)
120 */
121 public String getAlbum() {
122 return tag.getFirstAlbum().trim();
123 }
124
125 /**
126 * Get the title.
127 *
128 * @return The title (never null)
129 */
130 public String getTitle() {
131 return tag.getFirstTitle().trim();
132 }
133
134 /**
135 * Get the genre.
136 *
137 * @return The genre (never null)
138 */
139 public String getGenre() {
140 return tag.getFirstGenre().trim();
141 }
142
143 /**
144 * Get the year.
145 *
146 * @return The year (never null)
147 */
148 public String getYear() {
149 return tag.getFirstYear().trim();
150 }
151
152 /**
153 * Get the comment.
154 *
155 * @return The comment (never null)
156 */
157 public String getComment() {
158 return tag.getFirstComment().trim();
159 }
160
161 /**
162 * Get the track.
163 *
164 * @return The track (never null)
165 */
166 public String getTrack() {
167 return tag.getFirstTrack().trim();
168 }
169
170}
diff --git a/songdbj/net/shredzone/ifish/ltr/TagMp3v1.java b/songdbj/net/shredzone/ifish/ltr/TagMp3v1.java
new file mode 100644
index 0000000000..9d3182260a
--- /dev/null
+++ b/songdbj/net/shredzone/ifish/ltr/TagMp3v1.java
@@ -0,0 +1,184 @@
1/*
2 * iFish -- An iRiver iHP jukebox database creation tool
3 *
4 * Copyright (c) 2004 Richard "Shred" Körber
5 * http://www.shredzone.net/go/ifish
6 *
7 *-----------------------------------------------------------------------
8 * ***** BEGIN LICENSE BLOCK *****
9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
10 *
11 * The contents of this file are subject to the Mozilla Public License Version
12 * 1.1 (the "License"); you may not use this file except in compliance with
13 * the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis,
17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
18 * for the specific language governing rights and limitations under the
19 * License.
20 *
21 * The Original Code is IFISH.
22 *
23 * The Initial Developer of the Original Code is
24 * Richard "Shred" Körber.
25 * Portions created by the Initial Developer are Copyright (C) 2004
26 * the Initial Developer. All Rights Reserved.
27 *
28 * Contributor(s):
29 *
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
41 *
42 * ***** END LICENSE BLOCK *****
43 */
44
45package net.shredzone.ifish.ltr;
46
47import java.io.*;
48
49/**
50 * Decodes an MP3 file with ID3v1 tag. The file is compliant to the
51 * specifications found at <a href="http://www.id3.org">www.id3.org</a>.
52 *
53 * @author Richard Körber &lt;dev@shredzone.de&gt;
54 * @version $Id$
55 */
56public class TagMp3v1 extends LTRmp3 {
57 private String artist = "";
58 private String comment = "";
59 private String title = "";
60 private String album = "";
61 private String year = "";
62 private String track = "";
63 private String genre = "";
64
65 /**
66 * Create a new TagMp3v1 object.
67 *
68 * @param in File to be read
69 * @throws FormatDecodeException Description of the Exception
70 */
71 public TagMp3v1( RandomAccessFile in )
72 throws FormatDecodeException {
73 super( in );
74
75 try {
76 //--- Decode header ---
77 in.seek( in.length() - 128 ); // To the place where the tag lives
78 if( !readStringLen( 3 ).equals( "TAG" ) ) {
79 throw new FormatDecodeException( "not an id3v1 tag" );
80 }
81
82 title = readStringLen( 30, charsetV1 ).trim();
83 artist = readStringLen( 30, charsetV1 ).trim();
84 album = readStringLen( 30, charsetV1 ).trim();
85 year = readStringLen( 4, charsetV1 ).trim();
86 comment = readStringLen( 28, charsetV1 );
87
88 byte[] sto = new byte[2];
89 in.readFully( sto );
90 if( sto[0] == 0x00 ) {
91 // ID3v1.1
92 track = ( sto[1]>0 ? String.valueOf(sto[1]) : "" );
93 } else {
94 // ID3v1.0
95 comment += new String( sto, charsetV1 );
96 }
97 comment = comment.trim();
98
99 genre = decodeGenre( in.readUnsignedByte() );
100 if( genre==null ) genre="";
101
102 } catch( IOException e ) {
103 throw new FormatDecodeException( "could not decode file: " + e.toString() );
104 }catch( RuntimeException e ) {
105 throw new FormatDecodeException( "error decoding file: " + e.toString() );
106 }
107 }
108
109 /**
110 * Get the type of this file. This is usually the compression format
111 * itself (e.g. "OGG" or "MP3"). If there are different taggings for
112 * this format, the used tag format is appended after a slash (e.g.
113 * "MP3/id3v2").
114 *
115 * @return The type
116 */
117 public String getType() {
118 return "MP3/id3v1";
119 }
120
121 /**
122 * Get the artist.
123 *
124 * @return The artist (never null)
125 */
126 public String getArtist() {
127 return artist;
128 }
129
130 /**
131 * Get the album.
132 *
133 * @return The album (never null)
134 */
135 public String getAlbum() {
136 return album;
137 }
138
139 /**
140 * Get the title.
141 *
142 * @return The title (never null)
143 */
144 public String getTitle() {
145 return title;
146 }
147
148 /**
149 * Get the genre.
150 *
151 * @return The genre (never null)
152 */
153 public String getGenre() {
154 return genre;
155 }
156
157 /**
158 * Get the year.
159 *
160 * @return The year (never null)
161 */
162 public String getYear() {
163 return year;
164 }
165
166 /**
167 * Get the comment.
168 *
169 * @return The comment (never null)
170 */
171 public String getComment() {
172 return comment;
173 }
174
175 /**
176 * Get the track.
177 *
178 * @return The track (never null)
179 */
180 public String getTrack() {
181 return track;
182 }
183
184}
diff --git a/songdbj/net/shredzone/ifish/ltr/TagMp3v2.java b/songdbj/net/shredzone/ifish/ltr/TagMp3v2.java
new file mode 100644
index 0000000000..689dd21618
--- /dev/null
+++ b/songdbj/net/shredzone/ifish/ltr/TagMp3v2.java
@@ -0,0 +1,441 @@
1/*
2 * iFish -- An iRiver iHP jukebox database creation tool
3 *
4 * Copyright (c) 2004 Richard "Shred" Körber
5 * http://www.shredzone.net/go/ifish
6 *
7 *-----------------------------------------------------------------------
8 * ***** BEGIN LICENSE BLOCK *****
9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
10 *
11 * The contents of this file are subject to the Mozilla Public License Version
12 * 1.1 (the "License"); you may not use this file except in compliance with
13 * the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis,
17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
18 * for the specific language governing rights and limitations under the
19 * License.
20 *
21 * The Original Code is IFISH.
22 *
23 * The Initial Developer of the Original Code is
24 * Richard "Shred" Körber.
25 * Portions created by the Initial Developer are Copyright (C) 2004
26 * the Initial Developer. All Rights Reserved.
27 *
28 * Contributor(s):
29 *
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
41 *
42 * ***** END LICENSE BLOCK *****
43 */
44
45package net.shredzone.ifish.ltr;
46
47import java.io.*;
48import java.util.regex.*;
49
50/**
51 * Decodes an MP3 file with ID3v2 tag. The file is compliant to the
52 * specifications found at <a href="http://www.id3.org">www.id3.org</a>,
53 * V2.4.0 and V2.3.0. ID3 V2.2.0 is handled in a separate tag handler.
54 * Anyhow it has certain limitations regarding tag frames which could
55 * not be used or entirely used to iFish, e.g. multiple genres.
56 *
57 * @author Richard Körber &lt;dev@shredzone.de&gt;
58 * @version $Id$
59 */
60public class TagMp3v2 extends LTRmp3 {
61 private int globalSize;
62 private Pattern patGenre;
63 private boolean v230 = false; // V2.3.0 detected
64
65 private String artist = "";
66 private String comment = "";
67 private String title = "";
68 private String album = "";
69 private String year = "";
70 private String track = "";
71 private String genre = "";
72
73 /**
74 * Create a new TagMp3v2 instance.
75 *
76 * @param in File to be read
77 * @throws FormatDecodeException Couldn't decode this file
78 */
79 public TagMp3v2( RandomAccessFile in )
80 throws FormatDecodeException {
81 super( in );
82
83 patGenre = Pattern.compile( "\\((\\d{1,3})\\).*" );
84
85 try {
86 //--- Decode header ---
87 if( !readStringLen( 3 ).equals( "ID3" ) ) {
88 throw new FormatDecodeException( "not an id3v2 tag" );
89 }
90
91 byte version = in.readByte();
92 byte revision = in.readByte();
93
94 if( version==0xFF || revision==0xFF ) {
95 throw new FormatDecodeException( "not an id3v2 tag" );
96 }
97
98 if( version<=0x02 || version>0x04 ) {
99 throw new FormatDecodeException( "unable to decode ID3v2."+version+"."+revision );
100 }
101
102 byte flags = in.readByte();
103 v230 = (version==0x03);
104 globalSize = readSyncsafeInt() + 10;
105
106 //--- Skip extended header ---
107 if( ( flags & 0x40 ) != 0 ) {
108 int ehsize = readAutoInt();
109 if( ehsize < 6 ) {
110 throw new FormatDecodeException( "extended header too small" );
111 }
112 in.skipBytes( ehsize - 4 );
113 }
114
115 //--- Read all frames ---
116 Frame frm;
117 while( ( frm = readFrame() ) != null ) {
118 String type = frm.getType();
119 String[] answer;
120
121 if( type.equals( "TOPE" ) || type.equals( "TPE1" ) ) {
122
123 answer = frm.getAsStringEnc();
124 artist = (answer.length>0 ? answer[0].trim() : "");
125
126 } else if( type.equals( "COMM" ) ) {
127
128 answer = frm.getAsStringEnc();
129 comment = (answer.length>1 ? answer[1].trim() : "");
130
131 } else if( type.equals( "TIT2" ) ) {
132
133 answer = frm.getAsStringEnc();
134 title =(answer.length>0 ? answer[0].trim() : "");
135
136 } else if( type.equals( "TALB" ) ) {
137
138 answer = frm.getAsStringEnc();
139 album = (answer.length>0 ? answer[0].trim() : "");
140
141 } else if( type.equals( "TYER" ) ) {
142
143 answer = frm.getAsStringEnc();
144 year = (answer.length>0 ? answer[0].trim() : "");
145
146 } else if( type.equals( "TRCK" ) ) {
147
148 answer = frm.getAsStringEnc();
149 track = (answer.length>0 ? answer[0].trim() : "");
150
151 } else if( type.equals( "TCON" ) ) {
152
153 answer = frm.getAsStringEnc();
154 if( answer.length>0 ) {
155 genre = answer[0].trim();
156 Matcher mat = patGenre.matcher( genre );
157 if( mat.matches() ) {
158 genre = decodeGenre( Integer.parseInt( mat.group( 1 ) ) );
159 if( genre==null ) genre="";
160 }
161 }
162 }
163 }
164
165 //--- Footer frame? ---
166 if( ( flags & 0x10 ) != 0 ) {
167 in.skipBytes( 10 ); // Then skip it
168 }
169 // Position is now the start of the MP3 data
170
171 } catch( IOException e ) {
172 throw new FormatDecodeException( "could not decode file: " + e.toString() );
173 }catch( RuntimeException e ) {
174 throw new FormatDecodeException( "error decoding file: " + e.toString() );
175 }
176 }
177
178 /**
179 * Get the type of this file. This is usually the compression format
180 * itself (e.g. "OGG" or "MP3"). If there are different taggings for
181 * this format, the used tag format is appended after a slash (e.g.
182 * "MP3/id3v2").
183 *
184 * @return The type
185 */
186 public String getType() {
187 return ( v230 ? "MP3/id3v2.3.0" : "MP3/id3v2.4.0" );
188 }
189
190 /**
191 * Get the artist.
192 *
193 * @return The artist (never null)
194 */
195 public String getArtist() {
196 return artist;
197 }
198
199 /**
200 * Get the album.
201 *
202 * @return The album (never null)
203 */
204 public String getAlbum() {
205 return album;
206 }
207
208 /**
209 * Get the title.
210 *
211 * @return The title (never null)
212 */
213 public String getTitle() {
214 return title;
215 }
216
217 /**
218 * Get the genre.
219 *
220 * @return The genre (never null)
221 */
222 public String getGenre() {
223 return genre;
224 }
225
226 /**
227 * Get the year.
228 *
229 * @return The year (never null)
230 */
231 public String getYear() {
232 return year;
233 }
234
235 /**
236 * Get the comment.
237 *
238 * @return The comment (never null)
239 */
240 public String getComment() {
241 return comment;
242 }
243
244 /**
245 * Get the track.
246 *
247 * @return The track (never null)
248 */
249 public String getTrack() {
250 return track;
251 }
252
253 /**
254 * Read an ID3v2 integer. This is a 4 byte big endian value, which is
255 * only syncsafe for ID3v2.4 or higher, but not for ID3v2.3.
256 *
257 * @return The integer read.
258 * @throws IOException If there were not enough bytes in the file.
259 */
260 protected int readAutoInt()
261 throws IOException {
262 return( v230 ? readInt() : readSyncsafeInt() );
263 }
264
265 /**
266 * Read a tag frame. A Frame object will be returned, or null if no
267 * more frames were available.
268 *
269 * @return The next frame, or null
270 * @throws IOException If premature EOF was reached.
271 */
272 protected Frame readFrame()
273 throws IOException {
274 if( in.getFilePointer() >= globalSize ) {
275 return null;
276 }
277
278 //--- Get the type ---
279 String type = readStringLen( 4 );
280 if( type.charAt(0)==0 ) { // Optional padding frame
281 in.skipBytes( (int) ( globalSize - in.getFilePointer() ) );// Skip it...
282 return null; // Return null
283 }
284
285 //--- Read the frame ---
286 int size = readAutoInt();
287 byte flag1 = in.readByte();
288 byte flag2 = in.readByte();
289
290 //--- Read the content ---
291 // Stay within reasonable boundaries. If the data part is bigger than
292 // 16K, it's not really useful for us, so we will keep the frame empty.
293 byte[] data = null;
294 if( size<=16384 ) {
295 data = new byte[size];
296 int rlen = in.read( data );
297 if( rlen != size ) {
298 throw new IOException( "unexpected EOF" );
299 }
300 }else {
301 in.skipBytes( size );
302 }
303
304 //--- Return the frame ---
305 return new Frame( type, size, flag1, flag2, data );
306 }
307
308/*--------------------------------------------------------------------*/
309
310 /**
311 * This class contains a ID3v2 frame.
312 */
313 private static class Frame {
314 private final String charset;
315 private final String type;
316// private final int size;
317// private final byte flag1;
318 private final byte flag2;
319 private byte[] data;
320 private boolean decoded = false;
321
322 /**
323 * Constructor for the Frame object
324 *
325 * @param type Frame type
326 * @param size Frame size
327 * @param flag1 Flag 1
328 * @param flag2 Flag 2
329 * @param data Frame content, may be null
330 */
331 public Frame( String type, int size, byte flag1, byte flag2, byte[] data ) {
332 charset = "ISO-8859-1";
333 this.type = type;
334// Currently unused...
335// this.size = size;
336// this.flag1 = flag1;
337 this.flag2 = flag2;
338 this.data = data;
339 }
340
341 /**
342 * Get the type.
343 *
344 * @return The type of this Frame
345 */
346 public String getType() {
347 return type;
348 }
349
350 /**
351 * Return the Frame content as String. This method is to be used for
352 * strings without a leading encoding byte. This machine's default
353 * encoding will be used instead.
354 *
355 * @return Encoded string
356 * @throws FormatDecodeException Could not read or decode frame
357 */
358 public String getAsString()
359 throws FormatDecodeException {
360 if(data==null) return null;
361 decode();
362 return new String( data );
363 }
364
365 /**
366 * Return the Frame content as encoded String. The first byte will
367 * contain the encoding type, following the string itself. Multiple
368 * strings are null-terminated. An array of all strings found, will
369 * be returned.
370 *
371 * @return Array of all strings. Might be an empty array!
372 * @throws FormatDecodeException Could not read or decode frame
373 */
374 public String[] getAsStringEnc()
375 throws FormatDecodeException {
376 if( data==null ) return new String[0];
377 decode();
378 if( data.length==0 ) return new String[0];
379 int len = data.length - 1;
380 String result = "";
381 try {
382 switch ( data[0] ) {
383 case 0x00:
384 result = new String( data, 1, len, charset );
385 break;
386 case 0x01:
387 result = new String( data, 1, len, "UTF-16" );
388 break;
389 case 0x02:
390 result = new String( data, 1, len, "UTF-16BE" );
391 break;
392 case 0x03:
393 result = new String( data, 1, len, "UTF-8" );
394 break;
395 default:
396 throw new FormatDecodeException( "unknown encoding of frame " + type );
397 }
398 }catch( UnsupportedEncodingException e ) {
399 throw new FormatDecodeException( "Java misses a basic encoding!?" );
400 }
401 return result.split( "\0" );
402 }
403
404 /**
405 * Decode a frame, unless already decoded. If the frame was
406 * unsynchronized, it will be synchronized here. Compression and
407 * encryption is not supported yet. You can invoke this method
408 * several times without any effect.
409 *
410 * @throws FormatDecodeException Description of the Exception
411 */
412 private void decode()
413 throws FormatDecodeException {
414 if( decoded ) return;
415 decoded = true;
416
417 if( ( flag2 & 0x02 ) != 0 ) { // Unsynchronize
418 byte decoded[] = new byte[data.length];
419 int pos = 0;
420 for( int ix = 0; ix < data.length - 1; ix++ ) {
421 decoded[pos++] = data[ix];
422 if( data[ix] == 0xFF && data[ix + 1] == 0x00 ) {
423 ix++;
424 }
425 }
426 data = new byte[pos];
427 System.arraycopy( decoded, 0, data, 0, pos );
428 }
429
430 if( ( flag2 & 0x08 ) != 0 ) { // Compression
431 throw new FormatDecodeException( "sorry, compression is not yet supported" );
432 }
433
434 if( ( flag2 & 0x04 ) != 0 ) { // Encryption
435 throw new FormatDecodeException( "sorry, encryption is not yet supported" );
436 }
437 }
438
439 }
440
441}
diff --git a/songdbj/net/shredzone/ifish/ltr/TagMp3v200.java b/songdbj/net/shredzone/ifish/ltr/TagMp3v200.java
new file mode 100644
index 0000000000..28e623f962
--- /dev/null
+++ b/songdbj/net/shredzone/ifish/ltr/TagMp3v200.java
@@ -0,0 +1,373 @@
1/*
2 * iFish -- An iRiver iHP jukebox database creation tool
3 *
4 * Copyright (c) 2004 Richard "Shred" Körber
5 * http://www.shredzone.net/go/ifish
6 *
7 *-----------------------------------------------------------------------
8 * ***** BEGIN LICENSE BLOCK *****
9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
10 *
11 * The contents of this file are subject to the Mozilla Public License Version
12 * 1.1 (the "License"); you may not use this file except in compliance with
13 * the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis,
17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
18 * for the specific language governing rights and limitations under the
19 * License.
20 *
21 * The Original Code is IFISH.
22 *
23 * The Initial Developer of the Original Code is
24 * Richard "Shred" Körber.
25 * Portions created by the Initial Developer are Copyright (C) 2004
26 * the Initial Developer. All Rights Reserved.
27 *
28 * Contributor(s):
29 *
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
41 *
42 * ***** END LICENSE BLOCK *****
43 */
44
45package net.shredzone.ifish.ltr;
46
47import java.io.*;
48import java.util.regex.*;
49
50/**
51 * Decodes an MP3 file with old ID3v2.00 tag. The file is compliant to the
52 * specifications found at <a href="http://www.id3.org/id3v2-00.txt">www.id3.org</a>.
53 * Only ID3 V2.00 up to v2.2.0 is handled here. Newer versions are separately
54 * handled in TagMp3v2.
55 *
56 * @author Richard Körber &lt;dev@shredzone.de&gt;
57 * @version $Id$
58 */
59public class TagMp3v200 extends LTRmp3 {
60 private int globalSize;
61 private Pattern patGenre;
62
63 private String artist = "";
64 private String comment = "";
65 private String title = "";
66 private String album = "";
67 private String year = "";
68 private String track = "";
69 private String genre = "";
70
71 /**
72 * Create a new TagMp3v200 instance.
73 *
74 * @param in File to be read
75 * @throws FormatDecodeException Couldn't decode this file
76 */
77 public TagMp3v200( RandomAccessFile in )
78 throws FormatDecodeException {
79 super( in );
80
81 patGenre = Pattern.compile( "\\((\\d{1,3})\\).*" );
82
83 try {
84 //--- Decode header ---
85 if( !readStringLen( 3 ).equals( "ID3" ) ) {
86 throw new FormatDecodeException( "not an id3v2 tag" );
87 }
88
89 byte version = in.readByte();
90 byte revision = in.readByte();
91
92 if( version!=0x02 || revision==0xFF ) {
93 throw new FormatDecodeException( "not an id3v2.2.0 tag" );
94 }
95
96 byte flags = in.readByte();
97 globalSize = readSyncsafeInt() + 10;
98
99 //--- Read all frames ---
100 Frame frm;
101 while( ( frm = readFrame() ) != null ) {
102 String type = frm.getType();
103 String[] answer;
104
105 if( type.equals( "TOA" ) || type.equals( "TP1" ) ) {
106
107 answer = frm.getAsStringEnc();
108 artist = (answer.length>0 ? answer[0].trim() : "");
109
110 } else if( type.equals( "COM" ) ) {
111
112 answer = frm.getAsStringEnc();
113 comment = (answer.length>1 ? answer[1].trim() : "");
114
115 } else if( type.equals( "TT2" ) ) {
116
117 answer = frm.getAsStringEnc();
118 title =(answer.length>0 ? answer[0].trim() : "");
119
120 } else if( type.equals( "TAL" ) ) {
121
122 answer = frm.getAsStringEnc();
123 album = (answer.length>0 ? answer[0].trim() : "");
124
125 } else if( type.equals( "TYE" ) ) {
126
127 answer = frm.getAsStringEnc();
128 year = (answer.length>0 ? answer[0].trim() : "");
129
130 } else if( type.equals( "TRK" ) ) {
131
132 answer = frm.getAsStringEnc();
133 track = (answer.length>0 ? answer[0].trim() : "");
134
135 } else if( type.equals( "TCO" ) ) {
136
137 answer = frm.getAsStringEnc();
138 if( answer.length>0 ) {
139 genre = answer[0].trim();
140 Matcher mat = patGenre.matcher( genre );
141 if( mat.matches() ) {
142 genre = decodeGenre( Integer.parseInt( mat.group( 1 ) ) );
143 if( genre==null ) genre="";
144 }
145 }
146 }
147 }
148
149 // Position is now the start of the MP3 data
150
151 } catch( IOException e ) {
152 throw new FormatDecodeException( "could not decode file: " + e.toString() );
153 }catch( RuntimeException e ) {
154 throw new FormatDecodeException( "error decoding file: " + e.toString() );
155 }
156 }
157
158 /**
159 * Get the type of this file. This is usually the compression format
160 * itself (e.g. "OGG" or "MP3"). If there are different taggings for
161 * this format, the used tag format is appended after a slash (e.g.
162 * "MP3/id3v2").
163 *
164 * @return The type
165 */
166 public String getType() {
167 return "MP3/id3v2.2.0";
168 }
169
170 /**
171 * Get the artist.
172 *
173 * @return The artist (never null)
174 */
175 public String getArtist() {
176 return artist;
177 }
178
179 /**
180 * Get the album.
181 *
182 * @return The album (never null)
183 */
184 public String getAlbum() {
185 return album;
186 }
187
188 /**
189 * Get the title.
190 *
191 * @return The title (never null)
192 */
193 public String getTitle() {
194 return title;
195 }
196
197 /**
198 * Get the genre.
199 *
200 * @return The genre (never null)
201 */
202 public String getGenre() {
203 return genre;
204 }
205
206 /**
207 * Get the year.
208 *
209 * @return The year (never null)
210 */
211 public String getYear() {
212 return year;
213 }
214
215 /**
216 * Get the comment.
217 *
218 * @return The comment (never null)
219 */
220 public String getComment() {
221 return comment;
222 }
223
224 /**
225 * Get the track.
226 *
227 * @return The track (never null)
228 */
229 public String getTrack() {
230 return track;
231 }
232
233 /**
234 * Read a tag frame. A Frame object will be returned, or null if no
235 * more frames were available.
236 *
237 * @return The next frame, or null
238 * @throws IOException If premature EOF was reached.
239 */
240 protected Frame readFrame()
241 throws IOException {
242 if( in.getFilePointer() >= globalSize ) {
243 return null;
244 }
245
246 //--- Get the type ---
247 String type = readStringLen( 3 );
248 if( type.charAt(0)==0 ) { // Optional padding frame
249 in.skipBytes( (int) ( globalSize - in.getFilePointer() ) );// Skip it...
250 return null; // Return null
251 }
252
253 //--- Read the frame ---
254 int size = read3Int();
255
256 //--- Read the content ---
257 // Stay within reasonable boundaries. If the data part is bigger than
258 // 16K, it's not really useful for us, so we will keep the frame empty.
259 byte[] data = null;
260 if( size<=16384 ) {
261 data = new byte[size];
262 int rlen = in.read( data );
263 if( rlen != size ) {
264 throw new IOException( "unexpected EOF" );
265 }
266 }else {
267 in.skipBytes( size );
268 }
269
270 //--- Return the frame ---
271 return new Frame( type, size, data );
272 }
273
274 /**
275 * Read an ID3v2 3 byte integer. This is a 3 byte big endian value, which is
276 * always not syncsafe.
277 *
278 * @return The integer read.
279 * @throws IOException If there were not enough bytes in the file.
280 */
281 protected int read3Int()
282 throws IOException {
283 int val = 0;
284 for( int cnt = 3; cnt > 0; cnt-- ) {
285 val <<= 8;
286 val |= ( in.readByte() & 0xFF );
287 }
288 return val;
289 }
290
291/*--------------------------------------------------------------------*/
292
293 /**
294 * This class contains a ID3v2.2.0 frame.
295 */
296 private static class Frame {
297 private final String charset;
298 private final String type;
299// private final int size;
300 private byte[] data;
301
302 /**
303 * Constructor for the Frame object
304 *
305 * @param type Frame type
306 * @param size Frame size
307 * @param data Frame content, may be null
308 */
309 public Frame( String type, int size, byte[] data ) {
310 this.charset = "ISO-8859-1";
311 this.type = type;
312// Currently unused...
313// this.size = size;
314 this.data = data;
315 }
316
317 /**
318 * Get the type.
319 *
320 * @return The type of this Frame
321 */
322 public String getType() {
323 return type;
324 }
325
326 /**
327 * Return the Frame content as String. This method is to be used for
328 * strings without a leading encoding byte. This machine's default
329 * encoding will be used instead.
330 *
331 * @return Encoded string
332 * @throws FormatDecodeException Could not read or decode frame
333 */
334 public String getAsString()
335 throws FormatDecodeException {
336 if(data==null) return null;
337 return new String( data );
338 }
339
340 /**
341 * Return the Frame content as encoded String. The first byte will
342 * contain the encoding type, following the string itself. Multiple
343 * strings are null-terminated. An array of all strings found, will
344 * be returned.
345 *
346 * @return Array of all strings. Might be an empty array!
347 * @throws FormatDecodeException Could not read or decode frame
348 */
349 public String[] getAsStringEnc()
350 throws FormatDecodeException {
351 if(data==null) return new String[0];
352 int len = data.length - 1;
353 String result = "";
354 try {
355 switch ( data[0] ) {
356 case 0x00:
357 result = new String( data, 1, len, charset );
358 break;
359 case 0x01:
360 result = new String( data, 1, len, "UTF-16" );
361 break;
362 default:
363 throw new FormatDecodeException( "unknown encoding of frame " + type );
364 }
365 }catch( UnsupportedEncodingException e ) {
366 throw new FormatDecodeException( "Java misses a basic encoding!?" );
367 }
368 return result.split( "\0" );
369 }
370
371 }
372
373}
diff --git a/songdbj/net/shredzone/ifish/ltr/TagOggVorbis.java b/songdbj/net/shredzone/ifish/ltr/TagOggVorbis.java
new file mode 100644
index 0000000000..45b7401437
--- /dev/null
+++ b/songdbj/net/shredzone/ifish/ltr/TagOggVorbis.java
@@ -0,0 +1,207 @@
1/*
2 * iFish -- An iRiver iHP jukebox database creation tool
3 *
4 * Copyright (c) 2004 Richard "Shred" Körber
5 * http://www.shredzone.net/go/ifish
6 *
7 *-----------------------------------------------------------------------
8 * ***** BEGIN LICENSE BLOCK *****
9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
10 *
11 * The contents of this file are subject to the Mozilla Public License Version
12 * 1.1 (the "License"); you may not use this file except in compliance with
13 * the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis,
17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
18 * for the specific language governing rights and limitations under the
19 * License.
20 *
21 * The Original Code is IFISH.
22 *
23 * The Initial Developer of the Original Code is
24 * Richard "Shred" Körber.
25 * Portions created by the Initial Developer are Copyright (C) 2004
26 * the Initial Developer. All Rights Reserved.
27 *
28 * Contributor(s):
29 *
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
41 *
42 * ***** END LICENSE BLOCK *****
43 */
44
45package net.shredzone.ifish.ltr;
46
47import java.io.*;
48import de.jarnbjo.ogg.*;
49import de.jarnbjo.vorbis.*;
50
51/**
52 * Decodes an Ogg Vorbis stream. It uses the
53 * <a href="http://www.j-ogg.de/">J-Ogg</a> library, which is
54 * copyrighted by Tor-Einar Jarnbjo. His licence says that may use and
55 * modify it as will (even commercial), as long as a reference to his
56 * library is stated in the software.
57 * <p>
58 * <b>NOTE:</b> Due to a bug, there is a patch required in the J-Ogg
59 * library. In class de.jarnbjo.vorbis.CommentHeader, private method
60 * <tt>addComment()</tt>, add a line
61 * <pre>
62 * key = key.toUpperCase();
63 * </pre>
64 * after the method declaration header.
65 *
66 * @author Richard Körber &lt;dev@shredzone.de&gt;
67 * @version $Id$
68 */
69public class TagOggVorbis extends LTR {
70 private CommentHeader cmt;
71
72 /**
73 * Create a new TagOggVorbis object.
74 *
75 * @param in File to read
76 * @throws FormatDecodeException Couldn't decode this file
77 */
78 public TagOggVorbis( RandomAccessFile in )
79 throws FormatDecodeException {
80 super( in );
81
82 try {
83 //--- Check for Ogg Signature ---
84 // I expected J-Ogg to do this check, but it has been commented
85 // out because very old ogg files do not seem to have this header.
86 // We will ignore those files.
87 if( !readStringLen(4).equals("OggS") )
88 throw new FormatDecodeException( "not an Ogg file" );
89 in.seek(0);
90
91 //--- Get the Comment Header ---
92 OggFastFileStream fs = new OggFastFileStream(in);
93 LogicalOggStream los = (LogicalOggStream) fs.getLogicalStreams().iterator().next();
94 if( los.getFormat() != LogicalOggStream.FORMAT_VORBIS )
95 throw new FormatDecodeException( "not a plain Ogg Vorbis file" );
96 VorbisStream vos = new VorbisStream( los );
97 cmt = vos.getCommentHeader();
98
99 }catch( OggFormatException e ) {
100 throw new FormatDecodeException( "not an Ogg file" );
101 }catch( VorbisFormatException e ) {
102 throw new FormatDecodeException( "not an Ogg Vorbis file" );
103 }catch( IOException e ) {
104 throw new FormatDecodeException( "could not decode file: " + e.toString() );
105 }catch( RuntimeException e ) {
106 throw new FormatDecodeException( "error decoding file: " + e.toString() );
107 }
108 }
109
110 /**
111 * Get the type of this file. This is usually the compression format
112 * itself (e.g. "OGG" or "MP3"). If there are different taggings for
113 * this format, the used tag format is appended after a slash (e.g.
114 * "MP3/id3v2").
115 *
116 * @return The type
117 */
118 public String getType() {
119 return "OGG";
120 }
121
122 /**
123 * Get the artist.
124 *
125 * @return The artist (never null)
126 */
127 public String getArtist() {
128 String val = cmt.getArtist();
129 if( val==null ) val="";
130 return val.trim();
131 }
132
133 /**
134 * Get the album.
135 *
136 * @return The album (never null)
137 */
138 public String getAlbum() {
139 String val = cmt.getAlbum();
140 if( val==null ) val="";
141 return val.trim();
142 }
143
144 /**
145 * Get the title.
146 *
147 * @return The title (never null)
148 */
149 public String getTitle() {
150 String val = cmt.getTitle();
151 if( val==null ) val="";
152 return val.trim();
153 }
154
155 /**
156 * Get the genre.
157 *
158 * @return The genre (never null)
159 */
160 public String getGenre() {
161 String val = cmt.getGenre();
162 if( val==null ) val="";
163 return val.trim();
164 }
165
166 /**
167 * Get the year.
168 *
169 * @return The year (never null)
170 */
171 public String getYear() {
172 String val = cmt.getDate();
173 if( val==null ) val="";
174 return val.trim();
175 }
176
177 /**
178 * Get the comment.
179 *
180 * @return The comment (never null)
181 */
182 public String getComment() {
183 String val = cmt.getDescription();
184 if( val==null ) {
185 // *sigh* The Ogg Vorbis documentation does not explicitely
186 // state the comment types. So there are some ogg writers
187 // around that use COMMENT instead of DESCRIPTION. We will
188 // use COMMENT if DESCRIPTION was empty.
189 val = cmt.getComment("COMMENT");
190 }
191 if( val==null )
192 val="";
193 return val.trim();
194 }
195
196 /**
197 * Get the track.
198 *
199 * @return The track (never null)
200 */
201 public String getTrack() {
202 String val = cmt.getTrackNumber();
203 if( val==null ) val="";
204 return val.trim();
205 }
206
207}
diff --git a/songdbj/org/tritonus/file/AiffAudioFileReader.java b/songdbj/org/tritonus/file/AiffAudioFileReader.java
new file mode 100644
index 0000000000..139ba05425
--- /dev/null
+++ b/songdbj/org/tritonus/file/AiffAudioFileReader.java
@@ -0,0 +1,244 @@
1/*
2 * AiffAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 1999 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file;
33
34import java.io.DataInputStream;
35import java.io.File;
36import java.io.InputStream;
37import java.io.IOException;
38
39import javax.sound.sampled.AudioFormat;
40import javax.sound.sampled.AudioFileFormat;
41import javax.sound.sampled.AudioInputStream;
42import javax.sound.sampled.AudioSystem;
43import javax.sound.sampled.UnsupportedAudioFileException;
44
45import org.tritonus.share.sampled.file.TAudioFileFormat;
46import org.tritonus.share.sampled.file.TAudioFileReader;
47import org.tritonus.share.TDebug;
48
49
50/** Class for reading AIFF and AIFF-C files.
51 *
52 * @author Florian Bomers
53 * @author Matthias Pfisterer
54 */
55public class AiffAudioFileReader extends TAudioFileReader
56{
57 private static final int READ_LIMIT = 1000;
58
59
60
61 public AiffAudioFileReader()
62 {
63 super(READ_LIMIT);
64 }
65
66
67
68 private void skipChunk(DataInputStream dataInputStream, int chunkLength, int chunkRead)
69 throws IOException {
70 chunkLength-=chunkRead;
71 if (chunkLength>0) {
72 dataInputStream.skip(chunkLength + (chunkLength % 2));
73 }
74 }
75
76 private AudioFormat readCommChunk(DataInputStream dataInputStream, int chunkLength)
77 throws IOException, UnsupportedAudioFileException {
78
79 int nNumChannels = dataInputStream.readShort();
80 if (nNumChannels <= 0) {
81 throw new UnsupportedAudioFileException(
82 "not an AIFF file: number of channels must be positive");
83 }
84 if (TDebug.TraceAudioFileReader) {
85 TDebug.out("Found "+nNumChannels+" channels.");
86 }
87 // ignored: frame count
88 dataInputStream.readInt();
89 int nSampleSize = dataInputStream.readShort();
90 float fSampleRate = (float) readIeeeExtended(dataInputStream);
91 if (fSampleRate <= 0.0) {
92 throw new UnsupportedAudioFileException(
93 "not an AIFF file: sample rate must be positive");
94 }
95 if (TDebug.TraceAudioFileReader) {
96 TDebug.out("Found framerate "+fSampleRate);
97 }
98 AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
99 int nRead=18;
100 if (chunkLength>nRead) {
101 int nEncoding=dataInputStream.readInt();
102 nRead+=4;
103 if (nEncoding==AiffTool.AIFF_COMM_PCM) {
104 // PCM - nothing to do
105 }
106 else if (nEncoding==AiffTool.AIFF_COMM_ULAW) {
107 // ULAW
108 encoding=AudioFormat.Encoding.ULAW;
109 nSampleSize=8;
110 }
111 else if (nEncoding==AiffTool.AIFF_COMM_IMA_ADPCM) {
112 encoding = new AudioFormat.Encoding("IMA_ADPCM");
113 nSampleSize=4;
114 }
115 else {
116 throw new UnsupportedAudioFileException(
117 "Encoding 0x"+Integer.toHexString(nEncoding)
118 +" of AIFF file not supported");
119 }
120 }
121 /* In case of IMA ADPCM, frame size is 0.5 bytes (since it is
122 always mono). A value of 1 as frame size would be wrong.
123 Handling of frame size 0 in defined nowhere. So the best
124 solution is to set the frame size to unspecified (-1).
125 */
126 int nFrameSize = (nSampleSize == 4) ?
127 AudioSystem.NOT_SPECIFIED :
128 calculateFrameSize(nSampleSize, nNumChannels);
129 if (TDebug.TraceAudioFileReader) { TDebug.out("calculated frame size: " + nFrameSize); }
130 skipChunk(dataInputStream, chunkLength, nRead);
131 AudioFormat format = new AudioFormat(encoding,
132 fSampleRate,
133 nSampleSize,
134 nNumChannels,
135 nFrameSize,
136 fSampleRate,
137 true);
138 return format;
139 }
140
141 private void readVerChunk(DataInputStream dataInputStream, int chunkLength)
142 throws IOException, UnsupportedAudioFileException {
143 if (chunkLength<4) {
144 throw new UnsupportedAudioFileException(
145 "Corrput AIFF file: FVER chunk too small.");
146 }
147 int nVer=dataInputStream.readInt();
148 if (nVer!=AiffTool.AIFF_FVER_TIME_STAMP) {
149 throw new UnsupportedAudioFileException(
150 "Unsupported AIFF file: version not known.");
151 }
152 skipChunk(dataInputStream, chunkLength, 4);
153 }
154
155
156
157 protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileSizeInBytes)
158 throws UnsupportedAudioFileException, IOException
159 {
160 if (TDebug.TraceAudioFileReader) {TDebug.out("AiffAudioFileReader.getAudioFileFormat(InputStream, long): begin"); }
161 DataInputStream dataInputStream = new DataInputStream(inputStream);
162 int nMagic = dataInputStream.readInt();
163 if (nMagic != AiffTool.AIFF_FORM_MAGIC) {
164 throw new UnsupportedAudioFileException(
165 "not an AIFF file: header magic is not FORM");
166 }
167 int nTotalLength = dataInputStream.readInt();
168 nMagic = dataInputStream.readInt();
169 boolean bIsAifc;
170 if (nMagic == AiffTool.AIFF_AIFF_MAGIC) {
171 bIsAifc = false;
172 } else if (nMagic == AiffTool.AIFF_AIFC_MAGIC) {
173 bIsAifc = true;
174 } else {
175 throw new UnsupportedAudioFileException(
176 "unsupported IFF file: header magic neither AIFF nor AIFC");
177 }
178 boolean bFVerFound=!bIsAifc;
179 boolean bCommFound=false;
180 boolean bSSndFound=false;
181 AudioFormat format=null;
182 int nDataChunkLength=0;
183
184 // walk through the chunks
185 // chunks may be in any order. However, in this implementation, SSND must be last
186 while (!bFVerFound || !bCommFound || !bSSndFound) {
187 nMagic = dataInputStream.readInt();
188 int nChunkLength = dataInputStream.readInt();
189 switch (nMagic) {
190 case AiffTool.AIFF_COMM_MAGIC:
191 format=readCommChunk(dataInputStream, nChunkLength);
192 if (TDebug.TraceAudioFileReader) {
193 TDebug.out("Read COMM chunk with length "+nChunkLength);
194 }
195 bCommFound=true;
196 break;
197 case AiffTool.AIFF_FVER_MAGIC:
198 if (!bFVerFound) {
199 readVerChunk(dataInputStream, nChunkLength);
200 if (TDebug.TraceAudioFileReader) {
201 TDebug.out("Read FVER chunk with length "+nChunkLength);
202 }
203 bFVerFound=true;
204 } else {
205 skipChunk(dataInputStream, nChunkLength, 0);
206 }
207 break;
208 case AiffTool.AIFF_SSND_MAGIC:
209 if (!bCommFound || !bFVerFound) {
210 throw new UnsupportedAudioFileException(
211 "cannot handle AIFF file: SSND not last chunk");
212 }
213 bSSndFound=true;
214 nDataChunkLength=nChunkLength-8;
215 // 8 information bytes of no interest
216 dataInputStream.skip(8);
217 if (TDebug.TraceAudioFileReader) {
218 TDebug.out("Found SSND chunk with length "+nChunkLength);
219 }
220 break;
221 default:
222 if (TDebug.TraceAudioFileReader) {
223 TDebug.out("Skipping unknown chunk: "
224 +Integer.toHexString(nMagic));
225 }
226 skipChunk(dataInputStream, nChunkLength, 0);
227 break;
228 }
229 }
230
231 // TODO: length argument has to be in frames
232 AudioFileFormat audioFileFormat = new TAudioFileFormat(
233 bIsAifc ? AudioFileFormat.Type.AIFC : AudioFileFormat.Type.AIFF,
234 format,
235 nDataChunkLength / format.getFrameSize(),
236 nTotalLength + 8);
237 if (TDebug.TraceAudioFileReader) {TDebug.out("AiffAudioFileReader.getAudioFileFormat(InputStream, long): end"); }
238 return audioFileFormat;
239 }
240}
241
242
243
244/*** AiffAudioFileReader.java ***/
diff --git a/songdbj/org/tritonus/file/AiffAudioFileWriter.java b/songdbj/org/tritonus/file/AiffAudioFileWriter.java
new file mode 100644
index 0000000000..cfd6996ae9
--- /dev/null
+++ b/songdbj/org/tritonus/file/AiffAudioFileWriter.java
@@ -0,0 +1,104 @@
1/*
2 * AiffAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import java.io.IOException;
34import java.util.Arrays;
35
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioInputStream;
39import javax.sound.sampled.AudioSystem;
40
41import org.tritonus.share.TDebug;
42import org.tritonus.share.sampled.file.AudioOutputStream;
43import org.tritonus.share.sampled.file.TAudioFileWriter;
44import org.tritonus.share.sampled.file.TDataOutputStream;
45
46
47/**
48 * Class for writing AIFF and AIFF-C files.
49 *
50 * @author Florian Bomers
51 */
52
53public class AiffAudioFileWriter extends TAudioFileWriter {
54
55 private static final AudioFileFormat.Type[] FILE_TYPES =
56 {
57 AudioFileFormat.Type.AIFF,
58 AudioFileFormat.Type.AIFC
59 };
60
61 private static final int ALL=AudioSystem.NOT_SPECIFIED;
62 private static final AudioFormat.Encoding PCM_SIGNED = AudioFormat.Encoding.PCM_SIGNED;
63 private static final AudioFormat.Encoding ULAW = AudioFormat.Encoding.ULAW;
64 private static final AudioFormat.Encoding IMA_ADPCM = new AudioFormat.Encoding("IMA_ADPCM");
65
66 // IMPORTANT: this array depends on the AudioFormat.match() algorithm which takes
67 // AudioSystem.NOT_SPECIFIED into account !
68 private static final AudioFormat[] AUDIO_FORMATS =
69 {
70 new AudioFormat(PCM_SIGNED, ALL, 8, ALL, ALL, ALL, true),
71 new AudioFormat(PCM_SIGNED, ALL, 8, ALL, ALL, ALL, false),
72 new AudioFormat(ULAW, ALL, 8, ALL, ALL, ALL, false),
73 new AudioFormat(ULAW, ALL, 8, ALL, ALL, ALL, true),
74 new AudioFormat(PCM_SIGNED, ALL, 16, ALL, ALL, ALL, true),
75 new AudioFormat(PCM_SIGNED, ALL, 24, ALL, ALL, ALL, true),
76 new AudioFormat(PCM_SIGNED, ALL, 32, ALL, ALL, ALL, true),
77 new AudioFormat(IMA_ADPCM, ALL, 4, ALL, ALL, ALL, true),
78 new AudioFormat(IMA_ADPCM, ALL, 4, ALL, ALL, ALL, false),
79 };
80
81 public AiffAudioFileWriter() {
82 super(Arrays.asList(FILE_TYPES),
83 Arrays.asList(AUDIO_FORMATS));
84 }
85
86
87 protected boolean isAudioFormatSupportedImpl(AudioFormat format,
88 AudioFileFormat.Type fileType) {
89 return AiffTool.getFormatCode(format)!=AiffTool.AIFF_COMM_UNSPECIFIED;
90 }
91
92
93 protected AudioOutputStream getAudioOutputStream(AudioFormat audioFormat,
94 long lLengthInBytes,
95 AudioFileFormat.Type fileType,
96 TDataOutputStream dataOutputStream) throws IOException {
97 return new AiffAudioOutputStream(audioFormat, fileType,
98 lLengthInBytes,
99 dataOutputStream);
100 }
101
102}
103
104/*** AiffAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/AiffAudioOutputStream.java b/songdbj/org/tritonus/file/AiffAudioOutputStream.java
new file mode 100644
index 0000000000..d0006ebfe0
--- /dev/null
+++ b/songdbj/org/tritonus/file/AiffAudioOutputStream.java
@@ -0,0 +1,205 @@
1/*
2 * AiffAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import java.io.IOException;
34import javax.sound.sampled.AudioFormat;
35import javax.sound.sampled.AudioFileFormat;
36import javax.sound.sampled.AudioSystem;
37import org.tritonus.share.TDebug;
38import org.tritonus.share.sampled.file.TAudioOutputStream;
39import org.tritonus.share.sampled.file.TDataOutputStream;
40
41
42/**
43 * AudioOutputStream for AIFF and AIFF-C files.
44 *
45 * @author Florian Bomers
46 */
47public class AiffAudioOutputStream extends TAudioOutputStream {
48
49 // this constant is used for chunk lengths when the length is not known yet
50 private static final int LENGTH_NOT_KNOWN=-1;
51
52 private AudioFileFormat.Type m_FileType;
53
54 public AiffAudioOutputStream(AudioFormat audioFormat,
55 AudioFileFormat.Type fileType,
56 long lLength,
57 TDataOutputStream dataOutputStream) {
58 super(audioFormat,
59 lLength,
60 dataOutputStream,
61 lLength == AudioSystem.NOT_SPECIFIED
62 && dataOutputStream.supportsSeek());
63 // AIFF files cannot exceed 2GB
64 if (lLength != AudioSystem.NOT_SPECIFIED && lLength>0x7FFFFFFFl) {
65 throw new IllegalArgumentException(
66 "AIFF files cannot be larger than 2GB.");
67 }
68 // IDEA: write AIFF file instead of AIFC when encoding=PCM ?
69 m_FileType=fileType;
70 if (!audioFormat.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED)
71 && !audioFormat.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED)) {
72 // only AIFC files can handle non-pcm data
73 m_FileType=AudioFileFormat.Type.AIFC;
74 }
75 }
76
77 protected void writeHeader()
78 throws IOException {
79 if (TDebug.TraceAudioOutputStream) {
80 TDebug.out("AiffAudioOutputStream.writeHeader(): called.");
81 }
82 AudioFormat format = getFormat();
83 boolean bIsAifc = m_FileType.equals(AudioFileFormat.Type.AIFC);
84 long lLength = getLength();
85 TDataOutputStream dos = getDataOutputStream();
86 int nCommChunkSize=18;
87 int nFormatCode=AiffTool.getFormatCode(format);
88 if (bIsAifc) {
89 // encoding takes 4 bytes
90 // encoding name takes at minimum 2 bytes
91 nCommChunkSize+=6;
92 }
93 int nHeaderSize=4 // magic
94 +8+nCommChunkSize // COMM chunk
95 +8; // header of SSND chunk
96 if (bIsAifc) {
97 // add length for FVER chunk
98 nHeaderSize+=12;
99 }
100 // if patching the header, and the length has not been known at first
101 // writing of the header, just truncate the size fields, don't throw an exception
102 if (lLength != AudioSystem.NOT_SPECIFIED && lLength+nHeaderSize>0x7FFFFFFFl) {
103 lLength=0x7FFFFFFFl-nHeaderSize;
104 }
105 // chunks must be on word-boundaries
106 long lSSndChunkSize=(lLength!=AudioSystem.NOT_SPECIFIED)?
107 (lLength+(lLength%2)+8):AudioSystem.NOT_SPECIFIED;
108
109 // write IFF container chunk
110 dos.writeInt(AiffTool.AIFF_FORM_MAGIC);
111 dos.writeInt((lLength!=AudioSystem.NOT_SPECIFIED)?
112 ((int) (lSSndChunkSize+nHeaderSize)):LENGTH_NOT_KNOWN);
113 if (bIsAifc) {
114 dos.writeInt(AiffTool.AIFF_AIFC_MAGIC);
115 // write FVER chunk
116 dos.writeInt(AiffTool.AIFF_FVER_MAGIC);
117 dos.writeInt(4);
118 dos.writeInt(AiffTool.AIFF_FVER_TIME_STAMP);
119 } else {
120 dos.writeInt(AiffTool.AIFF_AIFF_MAGIC);
121 }
122
123 // write COMM chunk
124 dos.writeInt(AiffTool.AIFF_COMM_MAGIC);
125 dos.writeInt(nCommChunkSize);
126 dos.writeShort((short) format.getChannels());
127 dos.writeInt((lLength!=AudioSystem.NOT_SPECIFIED)?
128 ((int) (lLength / format.getFrameSize())):LENGTH_NOT_KNOWN);
129 if (nFormatCode==AiffTool.AIFF_COMM_ULAW) {
130 // AIFF ulaw states 16 bits for ulaw data
131 dos.writeShort(16);
132 } else {
133 dos.writeShort((short) format.getSampleSizeInBits());
134 }
135 writeIeeeExtended(dos, format.getSampleRate());
136 if (bIsAifc) {
137 dos.writeInt(nFormatCode);
138 dos.writeShort(0); // no encoding name
139 // TODO: write encoding.toString() ??
140 }
141
142 // write header of SSND chunk
143
144
145
146 dos.writeInt(AiffTool.AIFF_SSND_MAGIC);
147 // don't use lSSndChunkSize here !
148 dos.writeInt((lLength!=AudioSystem.NOT_SPECIFIED)
149 ?((int) (lLength+8)):LENGTH_NOT_KNOWN);
150 // 8 information bytes of no interest
151 dos.writeInt(0); // offset
152 dos.writeInt(0); // blocksize
153 }
154
155
156
157
158 protected void patchHeader()
159 throws IOException {
160 TDataOutputStream tdos = getDataOutputStream();
161 tdos.seek(0);
162 setLengthFromCalculatedLength();
163 writeHeader();
164 }
165
166 public void close() throws IOException {
167 long nBytesWritten=getCalculatedLength();
168
169 if ((nBytesWritten % 2)==1) {
170 if (TDebug.TraceAudioOutputStream) {
171 TDebug.out("AiffOutputStream.close(): adding padding byte");
172 }
173 // extra byte for to align on word boundaries
174 TDataOutputStream tdos = getDataOutputStream();
175 tdos.writeByte(0);
176 // DON'T adjust calculated length !
177 }
178
179
180
181 super.close();
182 }
183
184 public void writeIeeeExtended(TDataOutputStream dos, float sampleRate) throws IOException {
185 // currently, only integer sample rates are written
186 // TODO: real conversion
187 // I don't know exactly how much I have to shift left the mantisse for normalisation
188 // now I do it so that there are any bits set in the first 5 bits
189 int nSampleRate=(int) sampleRate;
190 short ieeeExponent=0;
191 while ((nSampleRate!=0) && (nSampleRate & 0x80000000)==0) {
192 ieeeExponent++;
193 nSampleRate<<=1;
194 }
195 dos.writeShort(16414-ieeeExponent); // exponent
196 dos.writeInt(nSampleRate); // mantisse high double word
197 dos.writeInt(0); // mantisse low double word
198 }
199
200
201
202
203}
204
205/*** AiffAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/file/AiffTool.java b/songdbj/org/tritonus/file/AiffTool.java
new file mode 100644
index 0000000000..39cdbf0878
--- /dev/null
+++ b/songdbj/org/tritonus/file/AiffTool.java
@@ -0,0 +1,82 @@
1/*
2 * AiffTool.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import javax.sound.sampled.AudioFormat;
34import javax.sound.sampled.AudioFileFormat;
35import javax.sound.sampled.AudioSystem;
36
37
38/**
39 * Common constants and methods for handling aiff and aiff-c files.
40 *
41 * @author Florian Bomers
42 */
43
44public class AiffTool {
45
46 public static final int AIFF_FORM_MAGIC = 0x464F524D;
47 public static final int AIFF_AIFF_MAGIC = 0x41494646;
48 public static final int AIFF_AIFC_MAGIC = 0x41494643;
49 public static final int AIFF_COMM_MAGIC = 0x434F4D4D;
50 public static final int AIFF_SSND_MAGIC = 0x53534E44;
51 public static final int AIFF_FVER_MAGIC = 0x46564552;
52 public static final int AIFF_COMM_UNSPECIFIED = 0x00000000; // "0000"
53 public static final int AIFF_COMM_PCM = 0x4E4F4E45; // "NONE"
54 public static final int AIFF_COMM_ULAW = 0x756C6177; // "ulaw"
55 public static final int AIFF_COMM_IMA_ADPCM = 0x696D6134; // "ima4"
56 public static final int AIFF_FVER_TIME_STAMP = 0xA2805140; // May 23, 1990, 2:40pm
57
58 public static int getFormatCode(AudioFormat format) {
59 AudioFormat.Encoding encoding = format.getEncoding();
60 int nSampleSize = format.getSampleSizeInBits();
61 boolean bigEndian = format.isBigEndian();
62 // $$fb 2000-08-16: check the frame size, too.
63 boolean frameSizeOK=format.getFrameSize()==AudioSystem.NOT_SPECIFIED
64 || format.getChannels()!=AudioSystem.NOT_SPECIFIED
65 || format.getFrameSize()==nSampleSize/8*format.getChannels();
66
67 if ((encoding.equals(AudioFormat.Encoding.PCM_SIGNED))
68 && ((bigEndian && nSampleSize>=16 && nSampleSize<=32) || (nSampleSize==8))
69 && frameSizeOK) {
70 return AIFF_COMM_PCM;
71 } else if (encoding.equals(AudioFormat.Encoding.ULAW) && nSampleSize == 8 && frameSizeOK) {
72 return AIFF_COMM_ULAW;
73 } else if (encoding.equals(new AudioFormat.Encoding("IMA_ADPCM")) && nSampleSize == 4) {
74 return AIFF_COMM_IMA_ADPCM;
75 } else {
76 return AIFF_COMM_UNSPECIFIED;
77 }
78 }
79
80}
81
82/*** AiffTool.java ***/
diff --git a/songdbj/org/tritonus/file/AuAudioFileReader.java b/songdbj/org/tritonus/file/AuAudioFileReader.java
new file mode 100644
index 0000000000..b527920118
--- /dev/null
+++ b/songdbj/org/tritonus/file/AuAudioFileReader.java
@@ -0,0 +1,185 @@
1/*
2 * AuAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000,2001 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 1999 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file;
33
34import java.io.DataInputStream;
35import java.io.File;
36import java.io.InputStream;
37import java.io.IOException;
38
39import javax.sound.sampled.AudioFormat;
40import javax.sound.sampled.AudioFileFormat;
41import javax.sound.sampled.AudioInputStream;
42import javax.sound.sampled.AudioSystem;
43import javax.sound.sampled.UnsupportedAudioFileException;
44import javax.sound.sampled.spi.AudioFileReader;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.file.TAudioFileFormat;
48import org.tritonus.share.sampled.file.TAudioFileReader;
49
50
51/** Class for reading Sun/Next AU files.
52 *
53 * @author Florian Bomers
54 * @author Matthias Pfisterer
55 */
56public class AuAudioFileReader extends TAudioFileReader
57{
58 private static final int READ_LIMIT = 1000;
59
60
61
62 public AuAudioFileReader()
63 {
64 super(READ_LIMIT);
65 }
66
67
68
69 private static String readDescription(DataInputStream dis, int len) throws IOException {
70 byte c=-1;
71 String ret="";
72 while (len>0 && (c=dis.readByte())!=0) {
73 ret=ret+(char) c;
74 len--;
75 }
76 if (len>1 && c==0) {
77 dis.skip(len-1);
78 }
79 return ret;
80 }
81
82
83
84 protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileSizeInBytes)
85 throws UnsupportedAudioFileException, IOException
86 {
87 if (TDebug.TraceAudioFileReader) {TDebug.out("AuAudioFileReader.getAudioFileFormat(InputStream, long): begin"); }
88 DataInputStream dataInputStream = new DataInputStream(inputStream);
89 int nMagic = dataInputStream.readInt();
90 if (nMagic != AuTool.AU_HEADER_MAGIC) {
91 throw new UnsupportedAudioFileException(
92 "not an AU file: wrong header magic");
93 }
94 int nDataOffset = dataInputStream.readInt();
95 if (TDebug.TraceAudioFileReader) {
96 TDebug.out("AuAudioFileReader.getAudioFileFormat(): data offset: " + nDataOffset);
97 }
98 if (nDataOffset < AuTool.DATA_OFFSET) {
99 throw new UnsupportedAudioFileException(
100 "not an AU file: data offset must be 24 or greater");
101 }
102 int nDataLength = dataInputStream.readInt();
103 if (TDebug.TraceAudioFileReader) {
104 TDebug.out("AuAudioFileReader.getAudioFileFormat(): data length: " + nDataLength);
105 }
106 if (nDataLength < 0 && nDataLength!=AuTool.AUDIO_UNKNOWN_SIZE) {
107 throw new UnsupportedAudioFileException(
108 "not an AU file: data length must be positive, 0 or -1 for unknown");
109 }
110 AudioFormat.Encoding encoding = null;
111 int nSampleSize = 0;
112 int nEncoding = dataInputStream.readInt();
113 switch (nEncoding) {
114 case AuTool.SND_FORMAT_MULAW_8: // 8-bit uLaw G.711
115 encoding = AudioFormat.Encoding.ULAW;
116 nSampleSize = 8;
117 break;
118
119 case AuTool.SND_FORMAT_LINEAR_8:
120 encoding = AudioFormat.Encoding.PCM_SIGNED;
121 nSampleSize = 8;
122 break;
123
124 case AuTool.SND_FORMAT_LINEAR_16:
125 encoding = AudioFormat.Encoding.PCM_SIGNED;
126 nSampleSize = 16;
127 break;
128
129 case AuTool.SND_FORMAT_LINEAR_24:
130 encoding = AudioFormat.Encoding.PCM_SIGNED;
131 nSampleSize = 24;
132 break;
133
134 case AuTool.SND_FORMAT_LINEAR_32:
135 encoding = AudioFormat.Encoding.PCM_SIGNED;
136 nSampleSize = 32;
137 break;
138
139 case AuTool.SND_FORMAT_ALAW_8: // 8-bit aLaw G.711
140 encoding = AudioFormat.Encoding.ALAW;
141 nSampleSize = 8;
142 break;
143 }
144 if (nSampleSize == 0) {
145 throw new UnsupportedAudioFileException(
146 "unsupported AU file: unknown encoding " + nEncoding);
147 }
148 int nSampleRate = dataInputStream.readInt();
149 if (nSampleRate <= 0) {
150 throw new UnsupportedAudioFileException(
151 "corrupt AU file: sample rate must be positive");
152 }
153 int nNumChannels = dataInputStream.readInt();
154 if (nNumChannels <= 0) {
155 throw new UnsupportedAudioFileException(
156 "corrupt AU file: number of channels must be positive");
157 }
158 // skip header information field
159 inputStream.skip(nDataOffset - AuTool.DATA_OFFSET);
160 // read header info field
161 //String desc=readDescription(dataInputStream, nDataOffset - AuTool.DATA_OFFSET);
162
163 AudioFormat format = new AudioFormat(encoding,
164 (float) nSampleRate,
165 nSampleSize,
166 nNumChannels,
167 calculateFrameSize(nSampleSize, nNumChannels),
168 (float) nSampleRate,
169 true);
170 AudioFileFormat audioFileFormat = new TAudioFileFormat(
171 AudioFileFormat.Type.AU,
172 format,
173 (nDataLength==AuTool.AUDIO_UNKNOWN_SIZE)?
174 AudioSystem.NOT_SPECIFIED:(nDataLength / format.getFrameSize()),
175 (nDataLength==AuTool.AUDIO_UNKNOWN_SIZE)?
176 AudioSystem.NOT_SPECIFIED:(nDataLength + nDataOffset));
177 if (TDebug.TraceAudioFileReader) { TDebug.out("AuAudioFileReader.getAudioFileFormat(InputStream, long): begin"); }
178 return audioFileFormat;
179 }
180}
181
182
183
184/*** AuAudioFileReader.java ***/
185
diff --git a/songdbj/org/tritonus/file/AuAudioFileWriter.java b/songdbj/org/tritonus/file/AuAudioFileWriter.java
new file mode 100644
index 0000000000..5ac80a8c8a
--- /dev/null
+++ b/songdbj/org/tritonus/file/AuAudioFileWriter.java
@@ -0,0 +1,104 @@
1/*
2 * AuAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000,2001 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 1999 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file;
33
34import java.io.IOException;
35import java.util.Arrays;
36
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioFormat;
39import javax.sound.sampled.AudioInputStream;
40import javax.sound.sampled.AudioSystem;
41
42import org.tritonus.share.TDebug;
43import org.tritonus.share.sampled.file.AudioOutputStream;
44import org.tritonus.share.sampled.file.TAudioFileWriter;
45import org.tritonus.share.sampled.file.TDataOutputStream;
46
47
48/**
49 * AudioFileWriter for Sun/Next AU files.
50 *
51 * @author Florian Bomers
52 * @author Matthias Pfisterer
53 */
54public class AuAudioFileWriter extends TAudioFileWriter {
55
56 private static final AudioFileFormat.Type[] FILE_TYPES =
57 {
58 AudioFileFormat.Type.AU
59 };
60
61 private static final int ALL=AudioSystem.NOT_SPECIFIED;
62
63 // IMPORTANT: this array depends on the AudioFormat.match() algorithm which takes
64 // AudioSystem.NOT_SPECIFIED into account !
65 private static final AudioFormat[] AUDIO_FORMATS =
66 {
67 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 8, ALL, ALL, ALL, true),
68 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 8, ALL, ALL, ALL, false),
69
70 new AudioFormat(AudioFormat.Encoding.ULAW, ALL, 8, ALL, ALL, ALL, false),
71 new AudioFormat(AudioFormat.Encoding.ULAW, ALL, 8, ALL, ALL, ALL, true),
72
73 new AudioFormat(AudioFormat.Encoding.ALAW, ALL, 8, ALL, ALL, ALL, false),
74 new AudioFormat(AudioFormat.Encoding.ALAW, ALL, 8, ALL, ALL, ALL, true),
75
76 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 16, ALL, ALL, ALL, true),
77
78 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 24, ALL, ALL, ALL, true),
79
80 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 32, ALL, ALL, ALL, true),
81 };
82
83 public AuAudioFileWriter() {
84 super(Arrays.asList(FILE_TYPES),
85 Arrays.asList(AUDIO_FORMATS));
86 }
87
88
89 protected boolean isAudioFormatSupportedImpl(AudioFormat format,
90 AudioFileFormat.Type fileType) {
91 return AuTool.getFormatCode(format)!=AuTool.SND_FORMAT_UNSPECIFIED;
92 }
93 protected AudioOutputStream getAudioOutputStream(AudioFormat audioFormat,
94 long lLengthInBytes,
95 AudioFileFormat.Type fileType,
96 TDataOutputStream dataOutputStream) throws IOException {
97 return new AuAudioOutputStream(audioFormat,
98 lLengthInBytes,
99 dataOutputStream);
100 }
101
102}
103
104/*** AuAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/AuAudioOutputStream.java b/songdbj/org/tritonus/file/AuAudioOutputStream.java
new file mode 100644
index 0000000000..9f33e7a2aa
--- /dev/null
+++ b/songdbj/org/tritonus/file/AuAudioOutputStream.java
@@ -0,0 +1,121 @@
1/*
2 * AuAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2001 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 1999 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file;
33
34import java.io.IOException;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.AudioSystem;
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.file.TAudioOutputStream;
40import org.tritonus.share.sampled.file.TDataOutputStream;
41
42
43
44/**
45 * AudioOutputStream for AU files.
46 *
47 * @author Florian Bomers
48 * @author Matthias Pfisterer
49 */
50
51public class AuAudioOutputStream extends TAudioOutputStream {
52
53 private static String description="Created by Tritonus";
54
55 /**
56 * Writes a null-terminated ascii string s to f.
57 * The total number of bytes written is aligned on a 2byte boundary.
58 * @exception IOException Write error.
59 */
60 protected static void writeText(TDataOutputStream dos, String s) throws IOException {
61 if (s.length()>0) {
62 dos.writeBytes(s);
63 dos.writeByte(0); // pour terminer le texte
64 if ((s.length() % 2)==0) {
65 // ajout d'un zero pour faire la longeur pair
66 dos.writeByte(0);
67 }
68 }
69 }
70
71 /**
72 * Returns number of bytes that have to written for string s (with alignment)
73 */
74 protected static int getTextLength(String s) {
75 if (s.length()==0) {
76 return 0;
77 } else {
78 return (s.length()+2) & 0xFFFFFFFE;
79 }
80 }
81
82 public AuAudioOutputStream(AudioFormat audioFormat,
83 long lLength,
84 TDataOutputStream dataOutputStream) {
85 // if length exceeds 2GB, set the length field to NOT_SPECIFIED
86 super(audioFormat,
87 lLength>0x7FFFFFFFl?AudioSystem.NOT_SPECIFIED:lLength,
88 dataOutputStream,
89 lLength == AudioSystem.NOT_SPECIFIED && dataOutputStream.supportsSeek());
90 }
91
92 protected void writeHeader() throws IOException {
93 if (TDebug.TraceAudioOutputStream) {
94 TDebug.out("AuAudioOutputStream.writeHeader(): called.");
95 }
96 AudioFormat format = getFormat();
97 long lLength = getLength();
98 TDataOutputStream dos = getDataOutputStream();
99 if (TDebug.TraceAudioOutputStream) {
100 TDebug.out("AuAudioOutputStream.writeHeader(): AudioFormat: " + format);
101 TDebug.out("AuAudioOutputStream.writeHeader(): length: " + lLength);
102 }
103
104 dos.writeInt(AuTool.AU_HEADER_MAGIC);
105 dos.writeInt(AuTool.DATA_OFFSET+getTextLength(description));
106 dos.writeInt((lLength!=AudioSystem.NOT_SPECIFIED)?((int) lLength):AuTool.AUDIO_UNKNOWN_SIZE);
107 dos.writeInt(AuTool.getFormatCode(format));
108 dos.writeInt((int) format.getSampleRate());
109 dos.writeInt(format.getChannels());
110 writeText(dos, description);
111 }
112
113 protected void patchHeader() throws IOException {
114 TDataOutputStream tdos = getDataOutputStream();
115 tdos.seek(0);
116 setLengthFromCalculatedLength();
117 writeHeader();
118 }
119}
120
121/*** AuAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/file/AuTool.java b/songdbj/org/tritonus/file/AuTool.java
new file mode 100644
index 0000000000..bcdc62f86c
--- /dev/null
+++ b/songdbj/org/tritonus/file/AuTool.java
@@ -0,0 +1,95 @@
1/*
2 * AuTool.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2001 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import javax.sound.sampled.AudioFormat;
34import javax.sound.sampled.AudioFileFormat;
35import javax.sound.sampled.AudioSystem;
36
37
38/** Common constants and methods for handling au files.
39 *
40 * @author Florian Bomers
41 */
42
43public class AuTool {
44
45 public static final int AU_HEADER_MAGIC = 0x2e736e64;
46 public static final int AUDIO_UNKNOWN_SIZE = -1;
47
48 // length of header in bytes
49 public static final int DATA_OFFSET = 24;
50
51 public static final int SND_FORMAT_UNSPECIFIED = 0;
52 public static final int SND_FORMAT_MULAW_8 = 1;
53 public static final int SND_FORMAT_LINEAR_8 = 2;
54 public static final int SND_FORMAT_LINEAR_16 = 3;
55 public static final int SND_FORMAT_LINEAR_24 = 4;
56 public static final int SND_FORMAT_LINEAR_32 = 5;
57 public static final int SND_FORMAT_FLOAT = 6;
58 public static final int SND_FORMAT_DOUBLE = 7;
59 public static final int SND_FORMAT_ADPCM_G721 = 23;
60 public static final int SND_FORMAT_ADPCM_G722 = 24;
61 public static final int SND_FORMAT_ADPCM_G723_3 = 25;
62 public static final int SND_FORMAT_ADPCM_G723_5 = 26;
63 public static final int SND_FORMAT_ALAW_8 = 27;
64
65 public static int getFormatCode(AudioFormat format) {
66 AudioFormat.Encoding encoding = format.getEncoding();
67 int nSampleSize = format.getSampleSizeInBits();
68 // must be big endian for >8 bit formats
69 boolean bigEndian = format.isBigEndian();
70 // $$fb 2000-08-16: check the frame size, too.
71 boolean frameSizeOK=(
72 format.getFrameSize()==AudioSystem.NOT_SPECIFIED
73 || format.getChannels()!=AudioSystem.NOT_SPECIFIED
74 || format.getFrameSize()==nSampleSize/8*format.getChannels());
75
76 if (encoding.equals(AudioFormat.Encoding.ULAW) && nSampleSize == 8 && frameSizeOK) {
77 return SND_FORMAT_MULAW_8;
78 } else if (encoding.equals(AudioFormat.Encoding.PCM_SIGNED) && frameSizeOK) {
79 if (nSampleSize == 8) {
80 return SND_FORMAT_LINEAR_8;
81 } else if (nSampleSize == 16 && bigEndian) {
82 return SND_FORMAT_LINEAR_16;
83 } else if (nSampleSize == 24 && bigEndian) {
84 return SND_FORMAT_LINEAR_24;
85 } else if (nSampleSize == 32 && bigEndian) {
86 return SND_FORMAT_LINEAR_32;
87 }
88 } else if (encoding.equals(AudioFormat.Encoding.ALAW) && nSampleSize == 8 && frameSizeOK) {
89 return SND_FORMAT_ALAW_8;
90 }
91 return SND_FORMAT_UNSPECIFIED;
92 }
93}
94
95/*** AuTool.java ***/
diff --git a/songdbj/org/tritonus/file/WaveAudioFileReader.java b/songdbj/org/tritonus/file/WaveAudioFileReader.java
new file mode 100644
index 0000000000..62d3f1a9ea
--- /dev/null
+++ b/songdbj/org/tritonus/file/WaveAudioFileReader.java
@@ -0,0 +1,300 @@
1/*
2 * WaveAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 1999 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file;
33
34import java.io.DataInputStream;
35import java.io.File;
36import java.io.InputStream;
37import java.io.IOException;
38
39import javax.sound.sampled.AudioSystem;
40import javax.sound.sampled.AudioFormat;
41import javax.sound.sampled.AudioFileFormat;
42import javax.sound.sampled.AudioInputStream;
43import javax.sound.sampled.UnsupportedAudioFileException;
44import javax.sound.sampled.spi.AudioFileReader;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.file.TAudioFileFormat;
48import org.tritonus.share.sampled.file.TAudioFileReader;
49
50
51/**
52 * Class for reading wave files.
53 *
54 * @author Florian Bomers
55 * @author Matthias Pfisterer
56 */
57
58public class WaveAudioFileReader extends TAudioFileReader
59{
60 private static final int READ_LIMIT = 1000;
61
62
63
64 public WaveAudioFileReader()
65 {
66 super(READ_LIMIT);
67 }
68
69
70
71 protected void advanceChunk(DataInputStream dis, long prevLength, long prevRead)
72 throws IOException {
73 if (prevLength>0) {
74 dis.skip(((prevLength+1) & 0xFFFFFFFE)-prevRead);
75 }
76 }
77
78
79 protected long findChunk(DataInputStream dis, int key)
80 throws UnsupportedAudioFileException, IOException {
81 // $$fb 1999-12-18: we should take care that we don't exceed
82 // the mark of this stream. When we exceeded the mark and
83 // we notice that we don't support this wave file,
84 // other potential wave file readers have no chance.
85 int thisKey;
86 long chunkLength=0;
87 do {
88 advanceChunk(dis, chunkLength, 0);
89 try {
90 thisKey = dis.readInt();
91 } catch (IOException e)
92 {
93 if (TDebug.TraceAllExceptions)
94 {
95 TDebug.out(e);
96 }
97 // $$fb: when we come here, we skipped past the end of the wave file
98 // without finding the chunk.
99 // IMHO, this is not an IOException, as there are incarnations
100 // of WAVE files which store data in different chunks.
101 // maybe we can find a nice description of the "required chunk" ?
102 throw new UnsupportedAudioFileException(
103 "unsupported WAVE file: required chunk not found.");
104 }
105 chunkLength = readLittleEndianInt(dis) & 0xFFFFFFFF; // unsigned
106 }
107 while (thisKey != key);
108 return chunkLength;
109 }
110
111 protected AudioFormat readFormatChunk(DataInputStream dis,
112 long chunkLength) throws UnsupportedAudioFileException, IOException {
113 String debugAdd="";
114
115 int read=WaveTool.MIN_FMT_CHUNK_LENGTH;
116
117 if (chunkLength<WaveTool.MIN_FMT_CHUNK_LENGTH) {
118 throw new UnsupportedAudioFileException(
119 "corrupt WAVE file: format chunk is too small");
120 }
121
122 short formatCode=readLittleEndianShort(dis);
123 short channelCount = readLittleEndianShort(dis);
124 if (channelCount <= 0) {
125 throw new UnsupportedAudioFileException(
126 "corrupt WAVE file: number of channels must be positive");
127 }
128
129 int sampleRate = readLittleEndianInt(dis);
130 if (sampleRate <= 0) {
131 throw new UnsupportedAudioFileException(
132 "corrupt WAVE file: sample rate must be positive");
133 }
134
135 int avgBytesPerSecond=readLittleEndianInt(dis);
136 int blockAlign=readLittleEndianShort(dis);
137
138 AudioFormat.Encoding encoding;
139 int sampleSizeInBits;
140 int frameSize=0;
141 float frameRate=(float) sampleRate;
142
143 int cbSize = 0;
144 switch (formatCode) {
145 case WaveTool.WAVE_FORMAT_PCM:
146 if (chunkLength<WaveTool.MIN_FMT_CHUNK_LENGTH+2) {
147 throw new UnsupportedAudioFileException(
148 "corrupt WAVE file: format chunk is too small");
149 }
150 sampleSizeInBits = readLittleEndianShort(dis);
151 if (sampleSizeInBits <= 0) {
152 throw new UnsupportedAudioFileException(
153 "corrupt WAVE file: sample size must be positive");
154 }
155 encoding = (sampleSizeInBits <= 8) ?
156 AudioFormat.Encoding.PCM_UNSIGNED : AudioFormat.Encoding.PCM_SIGNED;
157 if (TDebug.TraceAudioFileReader) {
158 debugAdd+=", wBitsPerSample="+sampleSizeInBits;
159 }
160 read+=2;
161 break;
162 case WaveTool.WAVE_FORMAT_ALAW:
163 sampleSizeInBits = 8;
164 encoding = AudioFormat.Encoding.ALAW;
165 break;
166 case WaveTool.WAVE_FORMAT_ULAW:
167 sampleSizeInBits = 8;
168 encoding = AudioFormat.Encoding.ULAW;
169 break;
170 case WaveTool.WAVE_FORMAT_GSM610:
171 if (chunkLength<WaveTool.MIN_FMT_CHUNK_LENGTH+6) {
172 throw new UnsupportedAudioFileException(
173 "corrupt WAVE file: extra GSM bytes are missing");
174 }
175 sampleSizeInBits = readLittleEndianShort(dis); // sample Size (is 0 for GSM)
176 cbSize=readLittleEndianShort(dis);
177 if (cbSize < 2) {
178 throw new UnsupportedAudioFileException(
179 "corrupt WAVE file: extra GSM bytes are corrupt");
180 }
181 int decodedSamplesPerBlock=readLittleEndianShort(dis) & 0xFFFF; // unsigned
182 if (TDebug.TraceAudioFileReader) {
183 debugAdd+=", wBitsPerSample="+sampleSizeInBits
184 +", cbSize="+cbSize
185 +", wSamplesPerBlock="+decodedSamplesPerBlock;
186 }
187 sampleSizeInBits = AudioSystem.NOT_SPECIFIED;
188 encoding = WaveTool.GSM0610;
189 frameSize=blockAlign;
190 frameRate=((float) sampleRate)/((float) decodedSamplesPerBlock);
191 read+=6;
192 break;
193
194 case WaveTool.WAVE_FORMAT_IMA_ADPCM:
195 if (chunkLength < WaveTool.MIN_FMT_CHUNK_LENGTH + 2)
196 {
197 throw new UnsupportedAudioFileException(
198 "corrupt WAVE file: extra GSM bytes are missing");
199 }
200 sampleSizeInBits = readLittleEndianShort(dis);
201 cbSize = readLittleEndianShort(dis);
202 if (cbSize < 2)
203 {
204 throw new UnsupportedAudioFileException(
205 "corrupt WAVE file: extra IMA ADPCM bytes are corrupt");
206 }
207 int samplesPerBlock = readLittleEndianShort(dis) & 0xFFFF; // unsigned
208 if (TDebug.TraceAudioFileReader) {
209 debugAdd+=", wBitsPerSample="+sampleSizeInBits
210 +", cbSize="+cbSize
211 +", wSamplesPerBlock=" + samplesPerBlock;
212 }
213 sampleSizeInBits = AudioSystem.NOT_SPECIFIED;
214 encoding = WaveTool.GSM0610;
215 frameSize = blockAlign;
216 frameRate = ((float) sampleRate)/((float) samplesPerBlock);
217 read += 6;
218 break;
219
220 default:
221 throw new UnsupportedAudioFileException(
222 "unsupported WAVE file: unknown format code "+formatCode);
223 }
224 // if frameSize isn't set, calculate it (the default)
225 if (frameSize==0) {
226 frameSize = calculateFrameSize(sampleSizeInBits, channelCount);
227 }
228
229 if (TDebug.TraceAudioFileReader) {
230 TDebug.out("WaveAudioFileReader.readFormatChunk():");
231 TDebug.out(" read values: wFormatTag="+formatCode
232 +", nChannels="+channelCount
233 +", nSamplesPerSec="+sampleRate
234 +", nAvgBytesPerSec="+avgBytesPerSecond
235 +", nBlockAlign=="+blockAlign
236 +debugAdd);
237 TDebug.out(" constructed values: "
238 +"encoding="+encoding
239 +", sampleRate="+((float) sampleRate)
240 +", sampleSizeInBits="+sampleSizeInBits
241 +", channels="+channelCount
242 +", frameSize="+frameSize
243 +", frameRate="+frameRate);
244 }
245
246 // go to next chunk
247 advanceChunk(dis, chunkLength, read);
248 return new AudioFormat(
249 encoding,
250 (float) sampleRate,
251 sampleSizeInBits,
252 channelCount,
253 frameSize,
254 frameRate,
255 false);
256 }
257
258
259
260 protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileLengthInBytes)
261 throws UnsupportedAudioFileException, IOException {
262 DataInputStream dataInputStream = new DataInputStream(inputStream);
263 int magic = dataInputStream.readInt();
264 if (magic != WaveTool.WAVE_RIFF_MAGIC) {
265 throw new UnsupportedAudioFileException(
266 "not a WAVE file: wrong header magic");
267 }
268 long totalLength = readLittleEndianInt(dataInputStream) & 0xFFFFFFFF; // unsigned
269 magic = dataInputStream.readInt();
270 if (magic != WaveTool.WAVE_WAVE_MAGIC) {
271 throw new UnsupportedAudioFileException("not a WAVE file: wrong header magic");
272 }
273 // search for "fmt " chunk
274 long chunkLength = findChunk(dataInputStream, WaveTool.WAVE_FMT_MAGIC);
275 AudioFormat format = readFormatChunk(dataInputStream, chunkLength);
276
277 // search for "data" chunk
278 long dataChunkLength = findChunk(dataInputStream, WaveTool.WAVE_DATA_MAGIC);
279
280 long frameLength = dataChunkLength / format.getFrameSize();
281 if (format.getEncoding().equals(WaveTool.GSM0610)) {
282 // TODO: should not be necessary
283 frameLength = dataChunkLength;
284 }
285
286 if (TDebug.TraceAudioFileReader) {
287 TDebug.out("WaveAudioFileReader.getAudioFileFormat(): total length: "
288 +totalLength+", frame length = "+frameLength);
289 }
290 return new TAudioFileFormat(AudioFileFormat.Type.WAVE,
291 format,
292 (int) frameLength,
293 (int) (totalLength + WaveTool.CHUNK_HEADER_SIZE));
294 }
295}
296
297
298
299/*** WaveAudioFileReader.java ***/
300
diff --git a/songdbj/org/tritonus/file/WaveAudioFileWriter.java b/songdbj/org/tritonus/file/WaveAudioFileWriter.java
new file mode 100644
index 0000000000..d501b5b2b1
--- /dev/null
+++ b/songdbj/org/tritonus/file/WaveAudioFileWriter.java
@@ -0,0 +1,103 @@
1/*
2 * WaveAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import java.io.IOException;
34import java.util.Arrays;
35
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioInputStream;
39import javax.sound.sampled.AudioSystem;
40
41import org.tritonus.share.TDebug;
42import org.tritonus.share.sampled.file.AudioOutputStream;
43import org.tritonus.share.sampled.file.TAudioFileWriter;
44import org.tritonus.share.sampled.file.TDataOutputStream;
45
46
47/**
48 * Class for writing Microsoft(tm) WAVE files
49 *
50 * @author Florian Bomers
51 */
52public class WaveAudioFileWriter
53extends TAudioFileWriter {
54
55 private static final AudioFileFormat.Type[] FILE_TYPES =
56 {
57 AudioFileFormat.Type.WAVE
58 };
59
60 private static final int ALL=AudioSystem.NOT_SPECIFIED;
61
62 // IMPORTANT: this array depends on the AudioFormat.match() algorithm which takes
63 // AudioSystem.NOT_SPECIFIED into account !
64 private static final AudioFormat[] AUDIO_FORMATS =
65 {
66 // Encoding, SampleRate, sampleSizeInBits, channels, frameSize, frameRate, bigEndian
67 new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED, ALL, 8, ALL, ALL, ALL, true),
68 new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED, ALL, 8, ALL, ALL, ALL, false),
69 new AudioFormat(AudioFormat.Encoding.ULAW, ALL, 8, ALL, ALL, ALL, false),
70 new AudioFormat(AudioFormat.Encoding.ULAW, ALL, 8, ALL, ALL, ALL, true),
71 new AudioFormat(AudioFormat.Encoding.ALAW, ALL, 8, ALL, ALL, ALL, false),
72 new AudioFormat(AudioFormat.Encoding.ALAW, ALL, 8, ALL, ALL, ALL, true),
73 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 16, ALL, ALL, ALL, false),
74 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 24, ALL, ALL, ALL, false),
75 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 32, ALL, ALL, ALL, false),
76 new AudioFormat(WaveTool.GSM0610, ALL, ALL, ALL, ALL, ALL, false),
77 new AudioFormat(WaveTool.GSM0610, ALL, ALL, ALL, ALL, ALL, true),
78 };
79
80 public WaveAudioFileWriter() {
81 super(Arrays.asList(FILE_TYPES),
82 Arrays.asList(AUDIO_FORMATS));
83 }
84
85 // overwritten for quicker and more accurate check
86 protected boolean isAudioFormatSupportedImpl(AudioFormat format,
87 AudioFileFormat.Type fileType) {
88 return WaveTool.getFormatCode(format) != WaveTool.WAVE_FORMAT_UNSPECIFIED;
89 }
90
91
92 protected AudioOutputStream getAudioOutputStream(AudioFormat audioFormat,
93 long lLengthInBytes,
94 AudioFileFormat.Type fileType,
95 TDataOutputStream dataOutputStream) throws IOException {
96 return new WaveAudioOutputStream(audioFormat,
97 lLengthInBytes,
98 dataOutputStream);
99 }
100
101}
102
103/*** WaveAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/WaveAudioOutputStream.java b/songdbj/org/tritonus/file/WaveAudioOutputStream.java
new file mode 100644
index 0000000000..9054c3c4e1
--- /dev/null
+++ b/songdbj/org/tritonus/file/WaveAudioOutputStream.java
@@ -0,0 +1,201 @@
1/*
2 * WaveAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.AudioSystem;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.sampled.file.TAudioOutputStream;
41import org.tritonus.share.sampled.file.TDataOutputStream;
42
43
44/**
45 * AudioOutputStream for Wave files.
46 *
47 * @author Florian Bomers
48 */
49
50public class WaveAudioOutputStream extends TAudioOutputStream {
51
52 // this constant is used for chunk lengths when the length is not known yet
53 private static final int LENGTH_NOT_KNOWN=-1;
54 private int formatCode;
55
56 public WaveAudioOutputStream(AudioFormat audioFormat,
57 long lLength,
58 TDataOutputStream dataOutputStream) {
59 super(audioFormat,
60 lLength,
61 dataOutputStream,
62 lLength == AudioSystem.NOT_SPECIFIED && dataOutputStream.supportsSeek());
63 // wave cannot store more than 4GB
64 if (lLength != AudioSystem.NOT_SPECIFIED
65 && (lLength+WaveTool.DATA_OFFSET)>0xFFFFFFFFl) {
66 if (TDebug.TraceAudioOutputStream) {
67 TDebug.out("WaveAudioOutputStream: Length exceeds 4GB: "
68 +lLength+"=0x"+Long.toHexString(lLength)
69 +" with header="+(lLength+WaveTool.DATA_OFFSET)
70 +"=0x"+Long.toHexString(lLength+WaveTool.DATA_OFFSET));
71 }
72 throw new IllegalArgumentException("Wave files cannot be larger than 4GB.");
73 }
74 formatCode = WaveTool.getFormatCode(getFormat());
75 if (formatCode == WaveTool.WAVE_FORMAT_UNSPECIFIED) {
76 throw new IllegalArgumentException("Unknown encoding/format for this wave file.");
77 }
78
79 }
80
81 protected void writeHeader()
82 throws IOException {
83 if (TDebug.TraceAudioOutputStream) {
84 TDebug.out("WaveAudioOutputStream.writeHeader()");
85 }
86 AudioFormat format = getFormat();
87 long lLength = getLength();
88 int formatChunkAdd=0;
89 if (formatCode==WaveTool.WAVE_FORMAT_GSM610) {
90 // space for extra fields
91 formatChunkAdd+=2;
92 }
93 int dataOffset=WaveTool.DATA_OFFSET+formatChunkAdd;
94 if (formatCode!=WaveTool.WAVE_FORMAT_PCM) {
95 // space for fact chunk
96 dataOffset+=4+WaveTool.CHUNK_HEADER_SIZE;
97 }
98
99 // if patching the header, and the length has not been known at first
100 // writing of the header, just truncate the size fields, don't throw an exception
101 if (lLength != AudioSystem.NOT_SPECIFIED
102 && lLength+dataOffset>0xFFFFFFFFl) {
103 lLength=0xFFFFFFFFl-dataOffset;
104 }
105
106 // chunks must be on word-boundaries
107 long lDataChunkSize=lLength+(lLength%2);
108 TDataOutputStream dos = getDataOutputStream();
109
110 // write RIFF container chunk
111 dos.writeInt(WaveTool.WAVE_RIFF_MAGIC);
112 dos.writeLittleEndian32((int) ((lDataChunkSize+dataOffset-WaveTool.CHUNK_HEADER_SIZE)
113 & 0xFFFFFFFF));
114 dos.writeInt(WaveTool.WAVE_WAVE_MAGIC);
115
116 // write fmt_ chunk
117 int formatChunkSize=WaveTool.FMT_CHUNK_SIZE+formatChunkAdd;
118 short sampleSizeInBits=(short) format.getSampleSizeInBits();
119 int decodedSamplesPerBlock=1;
120
121 if (formatCode==WaveTool.WAVE_FORMAT_GSM610) {
122 if (format.getFrameSize()==33) {
123 decodedSamplesPerBlock=320;
124 } else if (format.getFrameSize()==65) {
125 decodedSamplesPerBlock=320;
126 } else {
127 // how to retrieve this value here ?
128 decodedSamplesPerBlock=(int) (format.getFrameSize()*(320.0f/65.0f));
129 }
130 sampleSizeInBits=0; // MS standard
131 }
132
133
134 int avgBytesPerSec=((int) format.getSampleRate())/decodedSamplesPerBlock*format.getFrameSize();
135 dos.writeInt(WaveTool.WAVE_FMT_MAGIC);
136 dos.writeLittleEndian32(formatChunkSize);
137 dos.writeLittleEndian16((short) formatCode); // wFormatTag
138 dos.writeLittleEndian16((short) format.getChannels()); // nChannels
139 dos.writeLittleEndian32((int) format.getSampleRate()); // nSamplesPerSec
140 dos.writeLittleEndian32(avgBytesPerSec); // nAvgBytesPerSec
141 dos.writeLittleEndian16((short) format.getFrameSize()); // nBlockalign
142 dos.writeLittleEndian16(sampleSizeInBits); // wBitsPerSample
143 dos.writeLittleEndian16((short) formatChunkAdd); // cbSize
144
145 if (formatCode==WaveTool.WAVE_FORMAT_GSM610) {
146 dos.writeLittleEndian16((short) decodedSamplesPerBlock); // wSamplesPerBlock
147 }
148
149 // write fact chunk
150
151
152 if (formatCode!=WaveTool.WAVE_FORMAT_PCM) {
153 // write "fact" chunk: number of samples
154 // todo: add this as an attribute or property
155 // in AudioOutputStream or AudioInputStream
156 long samples=0;
157 if (lLength!=AudioSystem.NOT_SPECIFIED) {
158 samples=lLength/format.getFrameSize()*decodedSamplesPerBlock;
159 }
160 // saturate sample count
161 if (samples>0xFFFFFFFFl) {
162 samples=(0xFFFFFFFFl/decodedSamplesPerBlock)*decodedSamplesPerBlock;
163 }
164 dos.writeInt(WaveTool.WAVE_FACT_MAGIC);
165 dos.writeLittleEndian32(4);
166 dos.writeLittleEndian32((int) (samples & 0xFFFFFFFF));
167 }
168
169 // write header of data chunk
170 dos.writeInt(WaveTool.WAVE_DATA_MAGIC);
171 dos.writeLittleEndian32((lLength!=AudioSystem.NOT_SPECIFIED)?((int) lLength):LENGTH_NOT_KNOWN);
172 }
173
174 protected void patchHeader()
175 throws IOException {
176 TDataOutputStream tdos = getDataOutputStream();
177 tdos.seek(0);
178 setLengthFromCalculatedLength();
179 writeHeader();
180 }
181
182 public void close() throws IOException {
183 long nBytesWritten=getCalculatedLength();
184
185 if ((nBytesWritten % 2)==1) {
186 if (TDebug.TraceAudioOutputStream) {
187 TDebug.out("WaveOutputStream.close(): adding padding byte");
188 }
189 // extra byte for to align on word boundaries
190 TDataOutputStream tdos = getDataOutputStream();
191 tdos.writeByte(0);
192 // DON'T adjust calculated length !
193 }
194
195
196 super.close();
197 }
198
199}
200
201/*** WaveAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/file/WaveTool.java b/songdbj/org/tritonus/file/WaveTool.java
new file mode 100644
index 0000000000..3487557088
--- /dev/null
+++ b/songdbj/org/tritonus/file/WaveTool.java
@@ -0,0 +1,115 @@
1/*
2 * WaveTool.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import javax.sound.sampled.AudioSystem;
34import javax.sound.sampled.AudioFormat;
35import javax.sound.sampled.AudioFileFormat;
36
37
38/**
39 * Common constants and methods for handling wave files.
40 *
41 * @author Florian Bomers
42 */
43
44public class WaveTool {
45
46 public static final int WAVE_RIFF_MAGIC = 0x52494646; // "RIFF"
47 public static final int WAVE_WAVE_MAGIC = 0x57415645; // "WAVE"
48 public static final int WAVE_FMT_MAGIC = 0x666D7420; // "fmt "
49 public static final int WAVE_DATA_MAGIC = 0x64617461; // "DATA"
50 public static final int WAVE_FACT_MAGIC = 0x66616374; // "fact"
51
52 public static final short WAVE_FORMAT_UNSPECIFIED = 0;
53 public static final short WAVE_FORMAT_PCM = 1;
54 public static final short WAVE_FORMAT_MS_ADPCM = 2;
55 public static final short WAVE_FORMAT_ALAW = 6;
56 public static final short WAVE_FORMAT_ULAW = 7;
57 public static final short WAVE_FORMAT_IMA_ADPCM = 17; // same as DVI_ADPCM
58 public static final short WAVE_FORMAT_G723_ADPCM = 20;
59 public static final short WAVE_FORMAT_GSM610 = 49;
60 public static final short WAVE_FORMAT_G721_ADPCM = 64;
61 public static final short WAVE_FORMAT_MPEG = 80;
62
63 public static final int MIN_FMT_CHUNK_LENGTH=14;
64 public static final int MIN_DATA_OFFSET=12+8+MIN_FMT_CHUNK_LENGTH+8;
65 public static final int MIN_FACT_CHUNK_LENGTH = 4;
66
67 // we always write the sample size in bits and the length of extra bytes.
68 // There are programs (CoolEdit) that rely on the
69 // additional entry for sample size in bits.
70 public static final int FMT_CHUNK_SIZE=18;
71 public static final int RIFF_CONTAINER_CHUNK_SIZE=12;
72 public static final int CHUNK_HEADER_SIZE=8;
73 public static final int DATA_OFFSET=RIFF_CONTAINER_CHUNK_SIZE
74 +CHUNK_HEADER_SIZE+FMT_CHUNK_SIZE+CHUNK_HEADER_SIZE;
75
76 public static AudioFormat.Encoding GSM0610 = new AudioFormat.Encoding("GSM0610");
77 public static AudioFormat.Encoding IMA_ADPCM = new AudioFormat.Encoding("IMA_ADPCM");
78
79 public static short getFormatCode(AudioFormat format) {
80 AudioFormat.Encoding encoding = format.getEncoding();
81 int nSampleSize = format.getSampleSizeInBits();
82 boolean littleEndian = !format.isBigEndian();
83 boolean frameSizeOK=format.getFrameSize()==AudioSystem.NOT_SPECIFIED
84 || format.getChannels()!=AudioSystem.NOT_SPECIFIED
85 || format.getFrameSize()==nSampleSize/8*format.getChannels();
86
87 if (nSampleSize==8 && frameSizeOK
88 && (encoding.equals(AudioFormat.Encoding.PCM_SIGNED)
89 || encoding.equals(AudioFormat.Encoding.PCM_UNSIGNED))) {
90 return WAVE_FORMAT_PCM;
91 } else if (nSampleSize>8 && frameSizeOK && littleEndian
92 && encoding.equals(AudioFormat.Encoding.PCM_SIGNED)) {
93 return WAVE_FORMAT_PCM;
94 } else if (encoding.equals(AudioFormat.Encoding.ULAW)
95 && (nSampleSize==AudioSystem.NOT_SPECIFIED || nSampleSize == 8)
96 && frameSizeOK) {
97 return WAVE_FORMAT_ULAW;
98 } else if (encoding.equals(AudioFormat.Encoding.ALAW)
99 && (nSampleSize==AudioSystem.NOT_SPECIFIED || nSampleSize == 8)
100 && frameSizeOK) {
101 return WAVE_FORMAT_ALAW;
102 } else if (encoding.equals(new AudioFormat.Encoding("IMA_ADPCM"))
103 && nSampleSize == 4)
104 {
105 return WAVE_FORMAT_IMA_ADPCM;
106 }
107 else if (encoding.equals(GSM0610)) {
108 return WAVE_FORMAT_GSM610;
109 }
110 return WAVE_FORMAT_UNSPECIFIED;
111 }
112
113}
114
115/*** WaveTool.java ***/
diff --git a/songdbj/org/tritonus/file/gsm/GSMAudioFileReader.java b/songdbj/org/tritonus/file/gsm/GSMAudioFileReader.java
new file mode 100644
index 0000000000..26859ddf24
--- /dev/null
+++ b/songdbj/org/tritonus/file/gsm/GSMAudioFileReader.java
@@ -0,0 +1,142 @@
1/*
2 * GSMAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 * Copyright (c) 2001 by Florian Bomers <http://www.bomers.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.sampled.file.gsm;
31
32import java.io.InputStream;
33import java.io.IOException;
34import java.io.EOFException;
35
36import java.util.HashMap;
37import java.util.Map;
38
39import javax.sound.sampled.AudioSystem;
40import javax.sound.sampled.AudioFormat;
41import javax.sound.sampled.AudioFileFormat;
42import javax.sound.sampled.AudioInputStream;
43import javax.sound.sampled.UnsupportedAudioFileException;
44import javax.sound.sampled.spi.AudioFileReader;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.file.TAudioFileFormat;
48import org.tritonus.share.sampled.file.TAudioFileReader;
49
50
51
52/** AudioFileReader class for GSM 06.10 data.
53 @author Matthias Pfisterer
54 */
55public class GSMAudioFileReader
56extends TAudioFileReader
57{
58 private static final int GSM_MAGIC = 0xD0;
59 private static final int GSM_MAGIC_MASK = 0xF0;
60
61 private static final int MARK_LIMIT = 1;
62
63
64
65 public GSMAudioFileReader()
66 {
67 super(MARK_LIMIT, true);
68 }
69
70
71
72 protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileSizeInBytes)
73 throws UnsupportedAudioFileException, IOException
74 {
75 if (TDebug.TraceAudioFileReader) { TDebug.out("GSMAudioFileReader.getAudioFileFormat(): begin"); }
76 int b0 = inputStream.read();
77 if (b0 < 0)
78 {
79 throw new EOFException();
80 }
81
82 /*
83 * Check for magic number.
84 */
85 if ((b0 & GSM_MAGIC_MASK) != GSM_MAGIC)
86 {
87 throw new UnsupportedAudioFileException("not a GSM stream: wrong magic number");
88 }
89
90
91 /*
92 If the file size is known, we derive the number of frames
93 ('frame size') from it.
94 If the values don't fit into integers, we leave them at
95 NOT_SPECIFIED. 'Unknown' is considered less incorrect than
96 a wrong value.
97 */
98 // [fb] not specifying it causes Sun's Wave file writer to write rubbish
99 int nByteSize = AudioSystem.NOT_SPECIFIED;
100 int nFrameSize = AudioSystem.NOT_SPECIFIED;
101 Map<String, Object> properties = new HashMap<String, Object>();
102 if (lFileSizeInBytes != AudioSystem.NOT_SPECIFIED)
103 {
104 // the number of GSM frames
105 long lFrameSize = lFileSizeInBytes / 33;
106 // duration in microseconds
107 long lDuration = lFrameSize * 20000;
108 properties.put("duration", lDuration);
109 if (lFileSizeInBytes <= Integer.MAX_VALUE)
110 {
111 nByteSize = (int) lFileSizeInBytes;
112 nFrameSize = (int) (lFileSizeInBytes / 33);
113 }
114 }
115
116 Map<String, Object> afProperties = new HashMap<String, Object>();
117 afProperties.put("bitrate", 13200L);
118 AudioFormat format = new AudioFormat(
119 new AudioFormat.Encoding("GSM0610"),
120 8000.0F,
121 AudioSystem.NOT_SPECIFIED /* ??? [sample size in bits] */,
122 1,
123 33,
124 50.0F,
125 true, // this value is chosen arbitrarily
126 afProperties);
127 AudioFileFormat audioFileFormat =
128 new TAudioFileFormat(
129 new AudioFileFormat.Type("GSM","gsm"),
130 format,
131 nFrameSize,
132 nByteSize,
133 properties);
134 if (TDebug.TraceAudioFileReader) { TDebug.out("GSMAudioFileReader.getAudioFileFormat(): end"); }
135 return audioFileFormat;
136 }
137}
138
139
140
141/*** GSMAudioFileReader.java ***/
142
diff --git a/songdbj/org/tritonus/file/gsm/GSMAudioFileWriter.java b/songdbj/org/tritonus/file/gsm/GSMAudioFileWriter.java
new file mode 100644
index 0000000000..eb3d1f3f16
--- /dev/null
+++ b/songdbj/org/tritonus/file/gsm/GSMAudioFileWriter.java
@@ -0,0 +1,77 @@
1/*
2 * GSMAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file.gsm;
33
34import java.util.Arrays;
35
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioSystem;
39
40import org.tritonus.share.TDebug;
41import org.tritonus.share.sampled.file.THeaderlessAudioFileWriter;
42
43
44
45/** Class for writing GSM streams
46 *
47 * @author Florian Bomers
48 * @author Matthias Pfisterer
49 */
50public class GSMAudioFileWriter
51extends THeaderlessAudioFileWriter
52{
53 private static final AudioFileFormat.Type[] FILE_TYPES =
54 {
55 new AudioFileFormat.Type("GSM", "gsm")
56 };
57
58 private static final AudioFormat[] AUDIO_FORMATS =
59 {
60 new AudioFormat(new AudioFormat.Encoding("GSM0610"), 8000.0F, ALL, 1, 33, 50.0F, false),
61 new AudioFormat(new AudioFormat.Encoding("GSM0610"), 8000.0F, ALL, 1, 33, 50.0F, true),
62 };
63
64
65
66 public GSMAudioFileWriter()
67 {
68 super(Arrays.asList(FILE_TYPES),
69 Arrays.asList(AUDIO_FORMATS));
70 if (TDebug.TraceAudioFileWriter) { TDebug.out("GSMAudioFileWriter.<init>(): begin"); }
71 if (TDebug.TraceAudioFileWriter) { TDebug.out("GSMAudioFileWriter.<init>(): end"); }
72 }
73}
74
75
76
77/*** GSMAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/gsm/package.html b/songdbj/org/tritonus/file/gsm/package.html
new file mode 100644
index 0000000000..763851dda0
--- /dev/null
+++ b/songdbj/org/tritonus/file/gsm/package.html
@@ -0,0 +1,10 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>GSM 06.10 audio file reader and writer.
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/file/jorbis/JorbisAudioFileReader.java b/songdbj/org/tritonus/file/jorbis/JorbisAudioFileReader.java
new file mode 100644
index 0000000000..5b33534b21
--- /dev/null
+++ b/songdbj/org/tritonus/file/jorbis/JorbisAudioFileReader.java
@@ -0,0 +1,231 @@
1/*
2 * JorbisAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.sampled.file.jorbis;
30
31import java.io.InputStream;
32import java.io.IOException;
33
34import javax.sound.sampled.AudioSystem;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.UnsupportedAudioFileException;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.sampled.file.TAudioFileFormat;
41import org.tritonus.share.sampled.file.TAudioFileReader;
42
43import com.jcraft.jogg.Buffer;
44import com.jcraft.jogg.SyncState;
45import com.jcraft.jogg.StreamState;
46import com.jcraft.jogg.Page;
47import com.jcraft.jogg.Packet;
48
49
50
51/**
52 * @author Matthias Pfisterer
53 */
54public class JorbisAudioFileReader
55extends TAudioFileReader
56{
57 private static final int INITAL_READ_LENGTH = 4096;
58 private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
59
60
61
62 public JorbisAudioFileReader()
63 {
64 super(MARK_LIMIT, true);
65 }
66
67
68
69 protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileSizeInBytes)
70 throws UnsupportedAudioFileException, IOException
71 {
72 // sync and verify incoming physical bitstream
73 SyncState oggSyncState = new SyncState();
74
75 // take physical pages, weld into a logical stream of packets
76 StreamState oggStreamState = new StreamState();
77
78 // one Ogg bitstream page. Vorbis packets are inside
79 Page oggPage = new Page();
80
81 // one raw packet of data for decode
82 Packet oggPacket = new Packet();
83
84 int bytes = 0;
85
86 // Decode setup
87
88 oggSyncState.init(); // Now we can read pages
89
90 // grab some data at the head of the stream. We want the first page
91 // (which is guaranteed to be small and only contain the Vorbis
92 // stream initial header) We need the first page to get the stream
93 // serialno.
94
95 // submit a 4k block to libvorbis' Ogg layer
96 int index = oggSyncState.buffer(INITAL_READ_LENGTH);
97 bytes = inputStream.read(oggSyncState.data, index, INITAL_READ_LENGTH);
98 oggSyncState.wrote(bytes);
99
100 // Get the first page.
101 if (oggSyncState.pageout(oggPage) != 1)
102 {
103 // have we simply run out of data? If so, we're done.
104 if (bytes < 4096)
105 {
106 // IDEA: throw EOFException?
107 throw new UnsupportedAudioFileException("not a Vorbis stream: ended prematurely");
108 }
109 throw new UnsupportedAudioFileException("not a Vorbis stream: not in Ogg bitstream format");
110 }
111
112 // Get the serial number and set up the rest of decode.
113 // serialno first; use it to set up a logical stream
114 oggStreamState.init(oggPage.serialno());
115
116 // extract the initial header from the first page and verify that the
117 // Ogg bitstream is in fact Vorbis data
118
119 // I handle the initial header first instead of just having the code
120 // read all three Vorbis headers at once because reading the initial
121 // header is an easy way to identify a Vorbis bitstream and it's
122 // useful to see that functionality seperated out.
123
124 if (oggStreamState.pagein(oggPage) < 0)
125 {
126 // error; stream version mismatch perhaps
127 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read first page of Ogg bitstream data");
128 }
129
130 if (oggStreamState.packetout(oggPacket) != 1)
131 {
132 // no page? must not be vorbis
133 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read initial header packet");
134 }
135
136 Buffer oggPacketBuffer = new Buffer();
137 oggPacketBuffer.readinit(oggPacket.packet_base, oggPacket.packet, oggPacket.bytes);
138
139 int nPacketType = oggPacketBuffer.read(8);
140 byte[] buf = new byte[6];
141 oggPacketBuffer.read(buf, 6);
142 if(buf[0]!='v' || buf[1]!='o' || buf[2]!='r' ||
143 buf[3]!='b' || buf[4]!='i' || buf[5]!='s')
144 {
145 throw new UnsupportedAudioFileException("not a Vorbis stream: not a vorbis header packet");
146 }
147 if (nPacketType != 1)
148 {
149 throw new UnsupportedAudioFileException("not a Vorbis stream: first packet is not the identification header");
150 }
151 if(oggPacket.b_o_s == 0)
152 {
153 throw new UnsupportedAudioFileException("not a Vorbis stream: initial packet not marked as beginning of stream");
154 }
155 int nVersion = oggPacketBuffer.read(32);
156 if (nVersion != 0)
157 {
158 throw new UnsupportedAudioFileException("not a Vorbis stream: wrong vorbis version");
159 }
160 int nChannels = oggPacketBuffer.read(8);
161 float fSampleRate = oggPacketBuffer.read(32);
162
163 // These are only used for error checking.
164 int bitrate_upper = oggPacketBuffer.read(32);
165 int bitrate_nominal = oggPacketBuffer.read(32);
166 int bitrate_lower = oggPacketBuffer.read(32);
167
168 int[] blocksizes = new int[2];
169 blocksizes[0] = 1 << oggPacketBuffer.read(4);
170 blocksizes[1] = 1 << oggPacketBuffer.read(4);
171
172 if (fSampleRate < 1.0F ||
173 nChannels < 1 ||
174 blocksizes[0] < 8||
175 blocksizes[1] < blocksizes[0] ||
176 oggPacketBuffer.read(1) != 1)
177 {
178 throw new UnsupportedAudioFileException("not a Vorbis stream: illegal values in initial header");
179 }
180
181
182 if (TDebug.TraceAudioFileReader) { TDebug.out("JorbisAudioFileReader.getAudioFileFormat(): channels: " + nChannels); }
183 if (TDebug.TraceAudioFileReader) { TDebug.out("JorbisAudioFileReader.getAudioFileFormat(): rate: " + fSampleRate); }
184
185 /*
186 If the file size is known, we derive the number of frames
187 ('frame size') from it.
188 If the values don't fit into integers, we leave them at
189 NOT_SPECIFIED. 'Unknown' is considered less incorrect than
190 a wrong value.
191 */
192 // [fb] not specifying it causes Sun's Wave file writer to write rubbish
193 int nByteSize = AudioSystem.NOT_SPECIFIED;
194 if (lFileSizeInBytes != AudioSystem.NOT_SPECIFIED
195 && lFileSizeInBytes <= Integer.MAX_VALUE)
196 {
197 nByteSize = (int) lFileSizeInBytes;
198 }
199 int nFrameSize = AudioSystem.NOT_SPECIFIED;
200 /* Can we calculate a useful size?
201 Peeking into ogginfo gives the insight that the only
202 way seems to be reading through the file. This is
203 something we do not want, at least not by default.
204 */
205 // nFrameSize = (int) (lFileSizeInBytes / ...;
206
207 AudioFormat format = new AudioFormat(
208 new AudioFormat.Encoding("VORBIS"),
209 fSampleRate,
210 AudioSystem.NOT_SPECIFIED,
211 nChannels,
212 AudioSystem.NOT_SPECIFIED,
213 AudioSystem.NOT_SPECIFIED,
214 true); // this value is chosen arbitrarily
215 if (TDebug.TraceAudioFileReader) { TDebug.out("JorbisAudioFileReader.getAudioFileFormat(): AudioFormat: " + format); }
216 AudioFileFormat.Type type = new AudioFileFormat.Type("Ogg","ogg");
217 AudioFileFormat audioFileFormat =
218 new TAudioFileFormat(
219 type,
220 format,
221 nFrameSize,
222 nByteSize);
223 if (TDebug.TraceAudioFileReader) { TDebug.out("JorbisAudioFileReader.getAudioFileFormat(): AudioFileFormat: " + audioFileFormat); }
224 return audioFileFormat;
225 }
226}
227
228
229
230/*** JorbisAudioFileReader.java ***/
231
diff --git a/songdbj/org/tritonus/file/jorbis/package.html b/songdbj/org/tritonus/file/jorbis/package.html
new file mode 100644
index 0000000000..e5b5599d8c
--- /dev/null
+++ b/songdbj/org/tritonus/file/jorbis/package.html
@@ -0,0 +1,10 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Ogg vorbis audio file reader based on the jorbis library.
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/file/mpeg/MpegAudioFileWriter.java b/songdbj/org/tritonus/file/mpeg/MpegAudioFileWriter.java
new file mode 100644
index 0000000000..d958fecf0d
--- /dev/null
+++ b/songdbj/org/tritonus/file/mpeg/MpegAudioFileWriter.java
@@ -0,0 +1,75 @@
1/*
2 * MpegAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file.mpeg;
32
33import java.util.Arrays;
34
35import javax.sound.sampled.AudioFileFormat;
36import javax.sound.sampled.AudioFormat;
37
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.file.THeaderlessAudioFileWriter;
40
41
42
43/** Class for writing mpeg files
44 *
45 * @author Florian Bomers
46 */
47public class MpegAudioFileWriter extends THeaderlessAudioFileWriter {
48
49 private static final AudioFileFormat.Type[] FILE_TYPES = {
50 //new AudioFileFormat.Type("MPEG", "mpeg"),
51 // workaround for the fixed extension problem in AudioFileFormat.Type
52 // see org.tritonus.share.sampled.AudioFileTypes.java
53 new AudioFileFormat.Type("MP3", "mp3")
54 };
55
56 public static AudioFormat.Encoding MPEG1L3=new AudioFormat.Encoding("MPEG1L3");
57
58 private static final AudioFormat[] AUDIO_FORMATS = {
59 new AudioFormat(MPEG1L3, ALL, ALL, 1, ALL, ALL, false),
60 new AudioFormat(MPEG1L3, ALL, ALL, 1, ALL, ALL, true),
61 new AudioFormat(MPEG1L3, ALL, ALL, 2, ALL, ALL, false),
62 new AudioFormat(MPEG1L3, ALL, ALL, 2, ALL, ALL, true),
63 };
64
65 public MpegAudioFileWriter()
66 {
67 super(Arrays.asList(FILE_TYPES),
68 Arrays.asList(AUDIO_FORMATS));
69 if (TDebug.TraceAudioFileWriter) { TDebug.out("MpegAudioFileWriter.<init>(): begin"); }
70 if (TDebug.TraceAudioFileWriter) { TDebug.out("MpegAudioFileWriter.<init>(): end"); }
71 }
72}
73
74
75/*** MpegAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/mpeg/package.html b/songdbj/org/tritonus/file/mpeg/package.html
new file mode 100644
index 0000000000..f24ded00ec
--- /dev/null
+++ b/songdbj/org/tritonus/file/mpeg/package.html
@@ -0,0 +1,10 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Mp3 audio file reader and writer.
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/file/package.html b/songdbj/org/tritonus/file/package.html
new file mode 100644
index 0000000000..a3ba1632a8
--- /dev/null
+++ b/songdbj/org/tritonus/file/package.html
@@ -0,0 +1,10 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Standard audio file readers and writers (.aiff, .au, .wav).
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileReader.java b/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileReader.java
new file mode 100644
index 0000000000..a882f11c3a
--- /dev/null
+++ b/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileReader.java
@@ -0,0 +1,302 @@
1/*
2 * VorbisAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.sampled.file.pvorbis;
30
31import java.io.InputStream;
32import java.io.IOException;
33
34import javax.sound.sampled.AudioSystem;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.UnsupportedAudioFileException;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.sampled.file.TAudioFileFormat;
41import org.tritonus.share.sampled.file.TAudioFileReader;
42
43import org.tritonus.lowlevel.pogg.Buffer;
44import org.tritonus.lowlevel.pogg.Page;
45import org.tritonus.lowlevel.pogg.Packet;
46import org.tritonus.lowlevel.pogg.SyncState;
47import org.tritonus.lowlevel.pogg.StreamState;
48
49
50
51/**
52 * @author Matthias Pfisterer
53 */
54public class VorbisAudioFileReader
55extends TAudioFileReader
56{
57 private static final int INITAL_READ_LENGTH = 4096;
58 private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
59
60
61
62 public VorbisAudioFileReader()
63 {
64 super(MARK_LIMIT, true);
65 }
66
67
68
69 protected AudioFileFormat getAudioFileFormat(InputStream inputStream,
70 long lFileSizeInBytes)
71 throws UnsupportedAudioFileException, IOException
72 {
73 if (TDebug.TraceAudioFileReader) { TDebug.out(">VorbisAudioFileReader.getAudioFileFormat(): begin"); }
74 SyncState oggSyncState = new SyncState();
75 StreamState oggStreamState = new StreamState();
76 Page oggPage = new Page();
77 Packet oggPacket = new Packet();
78
79 int bytes = 0;
80
81 // Decode setup
82
83 oggSyncState.init(); // Now we can read pages
84
85 // grab some data at the head of the stream. We want the first page
86 // (which is guaranteed to be small and only contain the Vorbis
87 // stream initial header) We need the first page to get the stream
88 // serialno.
89
90 // submit a 4k block to libvorbis' Ogg layer
91 byte[] abBuffer = new byte[INITAL_READ_LENGTH];
92 bytes = inputStream.read(abBuffer);
93 if (TDebug.TraceAudioFileReader) { TDebug.out("read bytes from input stream: " + bytes); }
94 int nResult = oggSyncState.write(abBuffer, bytes);
95 if (TDebug.TraceAudioFileReader) { TDebug.out("SyncState.write() returned " + nResult); }
96
97 // Get the first page.
98 if (oggSyncState.pageOut(oggPage) != 1)
99 {
100 // have we simply run out of data? If so, we're done.
101 if (bytes < INITAL_READ_LENGTH)
102 {
103 if (TDebug.TraceAudioFileReader) { TDebug.out("stream ended prematurely"); }
104 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
105 // IDEA: throw EOFException?
106 oggSyncState.free();
107 oggStreamState.free();
108 oggPage.free();
109 oggPacket.free();
110 throw new UnsupportedAudioFileException("not a Vorbis stream: ended prematurely");
111 }
112 if (TDebug.TraceAudioFileReader) { TDebug.out("not in Ogg bitstream format"); }
113 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
114 oggSyncState.free();
115 oggStreamState.free();
116 oggPage.free();
117 oggPacket.free();
118 throw new UnsupportedAudioFileException("not a Vorbis stream: not in Ogg bitstream format");
119 }
120
121 // Get the serial number and set up the rest of decode.
122 // serialno first; use it to set up a logical stream
123 int nSerialNo = oggPage.getSerialNo();
124 if (TDebug.TraceAudioFileReader) TDebug.out("serial no.: " + nSerialNo);
125 oggStreamState.init(nSerialNo);
126
127 // extract the initial header from the first page and verify that the
128 // Ogg bitstream is in fact Vorbis data
129
130 // I handle the initial header first instead of just having the code
131 // read all three Vorbis headers at once because reading the initial
132 // header is an easy way to identify a Vorbis bitstream and it's
133 // useful to see that functionality seperated out.
134
135 if (oggStreamState.pageIn(oggPage) < 0)
136 {
137 if (TDebug.TraceAudioFileReader) { TDebug.out("can't read first page of Ogg bitstream data"); }
138 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
139 // error; stream version mismatch perhaps
140 oggSyncState.free();
141 oggStreamState.free();
142 oggPage.free();
143 oggPacket.free();
144 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read first page of Ogg bitstream data");
145 }
146
147 if (oggStreamState.packetOut(oggPacket) != 1)
148 {
149 if (TDebug.TraceAudioFileReader) { TDebug.out("can't read initial header packet"); }
150 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
151 // no page? must not be vorbis
152 oggSyncState.free();
153 oggStreamState.free();
154 oggPage.free();
155 oggPacket.free();
156 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read initial header packet");
157 }
158
159 byte[] abData = oggPacket.getData();
160 if (TDebug.TraceAudioFileReader)
161 {
162 String strData = "";
163 for (int i = 0; i < abData.length; i++)
164 {
165 strData += " " + abData[i];
166 }
167 TDebug.out("packet data: " + strData);
168 }
169
170 int nPacketType = abData[0];
171 if (TDebug.TraceAudioFileReader) { TDebug.out("packet type: " + nPacketType); }
172 if (nPacketType != 1)
173 {
174 if (TDebug.TraceAudioFileReader) { TDebug.out("first packet is not the identification header"); }
175 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
176 oggSyncState.free();
177 oggStreamState.free();
178 oggPage.free();
179 oggPacket.free();
180 throw new UnsupportedAudioFileException("not a Vorbis stream: first packet is not the identification header");
181 }
182 if(abData[1] != 'v' ||
183 abData[2] != 'o' ||
184 abData[3] != 'r' ||
185 abData[4] != 'b' ||
186 abData[5] != 'i' ||
187 abData[6] != 's')
188 {
189 if (TDebug.TraceAudioFileReader) { TDebug.out("not a vorbis header packet"); }
190 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
191 oggSyncState.free();
192 oggStreamState.free();
193 oggPage.free();
194 oggPacket.free();
195 throw new UnsupportedAudioFileException("not a Vorbis stream: not a vorbis header packet");
196 }
197 if (! oggPacket.isBos())
198 {
199 if (TDebug.TraceAudioFileReader) { TDebug.out("initial packet not marked as beginning of stream"); }
200 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
201 oggSyncState.free();
202 oggStreamState.free();
203 oggPage.free();
204 oggPacket.free();
205 throw new UnsupportedAudioFileException("not a Vorbis stream: initial packet not marked as beginning of stream");
206 }
207 int nVersion = (abData[7] & 0xFF) + 256 * (abData[8] & 0xFF) + 65536 * (abData[9] & 0xFF) + 16777216 * (abData[10] & 0xFF);
208 if (TDebug.TraceAudioFileReader) { TDebug.out("version: " + nVersion); }
209 if (nVersion != 0)
210 {
211 if (TDebug.TraceAudioFileReader) { TDebug.out("wrong vorbis version"); }
212 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
213 oggSyncState.free();
214 oggStreamState.free();
215 oggPage.free();
216 oggPacket.free();
217 throw new UnsupportedAudioFileException("not a Vorbis stream: wrong vorbis version");
218 }
219 int nChannels = (abData[11] & 0xFF);
220 float fSampleRate = (abData[12] & 0xFF) + 256 * (abData[13] & 0xFF) + 65536 * (abData[14] & 0xFF) + 16777216 * (abData[15] & 0xFF);
221 if (TDebug.TraceAudioFileReader) { TDebug.out("channels: " + nChannels); }
222 if (TDebug.TraceAudioFileReader) { TDebug.out("rate: " + fSampleRate); }
223
224 // These are only used for error checking.
225 int bitrate_upper = abData[16] + 256 * abData[17] + 65536 * abData[18] + 16777216 * abData[19];
226 int bitrate_nominal = abData[20] + 256 * abData[21] + 65536 * abData[22] + 16777216 * abData[23];
227 int bitrate_lower = abData[24] + 256 * abData[25] + 65536 * abData[26] + 16777216 * abData[27];
228
229 int[] blocksizes = new int[2];
230 blocksizes[0] = 1 << (abData[28] & 0xF);
231 blocksizes[1] = 1 << ((abData[28] >>> 4) & 0xF);
232 if (TDebug.TraceAudioFileReader) { TDebug.out("blocksizes[0]: " + blocksizes[0]); }
233 if (TDebug.TraceAudioFileReader) { TDebug.out("blocksizes[1]: " + blocksizes[1]); }
234
235 if (fSampleRate < 1.0F ||
236 nChannels < 1 ||
237 blocksizes[0] < 8||
238 blocksizes[1] < blocksizes[0] ||
239 (abData[29] & 0x1) != 1)
240 {
241 if (TDebug.TraceAudioFileReader) { TDebug.out("illegal values in initial header"); }
242 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
243 oggSyncState.free();
244 oggStreamState.free();
245 oggPage.free();
246 oggPacket.free();
247 throw new UnsupportedAudioFileException("not a Vorbis stream: illegal values in initial header");
248 }
249
250 oggSyncState.free();
251 oggStreamState.free();
252 oggPage.free();
253 oggPacket.free();
254
255 /*
256 If the file size is known, we derive the number of frames
257 ('frame size') from it.
258 If the values don't fit into integers, we leave them at
259 NOT_SPECIFIED. 'Unknown' is considered less incorrect than
260 a wrong value.
261 */
262 // [fb] not specifying it causes Sun's Wave file writer to write rubbish
263 int nByteSize = AudioSystem.NOT_SPECIFIED;
264 if (lFileSizeInBytes != AudioSystem.NOT_SPECIFIED
265 && lFileSizeInBytes <= Integer.MAX_VALUE)
266 {
267 nByteSize = (int) lFileSizeInBytes;
268 }
269 int nFrameSize = AudioSystem.NOT_SPECIFIED;
270 /* Can we calculate a useful size?
271 Peeking into ogginfo gives the insight that the only
272 way seems to be reading through the file. This is
273 something we do not want, at least not by default.
274 */
275 // nFrameSize = (int) (lFileSizeInBytes / ...;
276
277 AudioFormat format = new AudioFormat(
278 new AudioFormat.Encoding("VORBIS"),
279 fSampleRate,
280 AudioSystem.NOT_SPECIFIED,
281 nChannels,
282 AudioSystem.NOT_SPECIFIED,
283 AudioSystem.NOT_SPECIFIED,
284 true); // this value is chosen arbitrarily
285 if (TDebug.TraceAudioFileReader) { TDebug.out("AudioFormat: " + format); }
286 AudioFileFormat.Type type = new AudioFileFormat.Type("Ogg","ogg");
287 AudioFileFormat audioFileFormat =
288 new TAudioFileFormat(
289 type,
290 format,
291 nFrameSize,
292 nByteSize);
293 if (TDebug.TraceAudioFileReader) { TDebug.out("AudioFileFormat: " + audioFileFormat); }
294 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): end"); }
295 return audioFileFormat;
296 }
297}
298
299
300
301/*** VorbisAudioFileReader.java ***/
302
diff --git a/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileWriter.java b/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileWriter.java
new file mode 100644
index 0000000000..5fc9c0663d
--- /dev/null
+++ b/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileWriter.java
@@ -0,0 +1,75 @@
1/*
2 * VorbisAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 -2004 by Matthias Pfisterer
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.sampled.file.pvorbis;
31
32import java.util.Arrays;
33
34import javax.sound.sampled.AudioFileFormat;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.file.THeaderlessAudioFileWriter;
40
41
42
43/** Class for writing Vorbis streams
44 *
45 * @author Florian Bomers
46 * @author Matthias Pfisterer
47 */
48public class VorbisAudioFileWriter
49extends THeaderlessAudioFileWriter
50{
51 private static final AudioFileFormat.Type[] FILE_TYPES =
52 {
53 new AudioFileFormat.Type("Vorbis", "ogg")
54 };
55
56 private static final AudioFormat[] AUDIO_FORMATS =
57 {
58 new AudioFormat(new AudioFormat.Encoding("VORBIS"), ALL, ALL, ALL, ALL, ALL, false),
59 new AudioFormat(new AudioFormat.Encoding("VORBIS"), ALL, ALL, ALL, ALL, ALL, true),
60 };
61
62
63
64 public VorbisAudioFileWriter()
65 {
66 super(Arrays.asList(FILE_TYPES),
67 Arrays.asList(AUDIO_FORMATS));
68 if (TDebug.TraceAudioFileWriter) { TDebug.out("VorbisAudioFileWriter.<init>(): begin"); }
69 if (TDebug.TraceAudioFileWriter) { TDebug.out("VorbisAudioFileWriter.<init>(): end"); }
70 }
71}
72
73
74
75/*** VorbisAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/pvorbis/package.html b/songdbj/org/tritonus/file/pvorbis/package.html
new file mode 100644
index 0000000000..a5238aaca0
--- /dev/null
+++ b/songdbj/org/tritonus/file/pvorbis/package.html
@@ -0,0 +1,12 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Ogg vorbis audio file reader and writer based on the pure java libraries.
8 The classes provided here .</p>
9
10 @see org.tritonus.lowlevel.ogg
11 </body>
12</html>
diff --git a/songdbj/org/tritonus/file/vorbis/VorbisAudioFileReader.java b/songdbj/org/tritonus/file/vorbis/VorbisAudioFileReader.java
new file mode 100644
index 0000000000..f8b34d5411
--- /dev/null
+++ b/songdbj/org/tritonus/file/vorbis/VorbisAudioFileReader.java
@@ -0,0 +1,302 @@
1/*
2 * VorbisAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.sampled.file.vorbis;
30
31import java.io.InputStream;
32import java.io.IOException;
33
34import javax.sound.sampled.AudioSystem;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.UnsupportedAudioFileException;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.sampled.file.TAudioFileFormat;
41import org.tritonus.share.sampled.file.TAudioFileReader;
42
43import org.tritonus.lowlevel.ogg.Buffer;
44import org.tritonus.lowlevel.ogg.Page;
45import org.tritonus.lowlevel.ogg.Packet;
46import org.tritonus.lowlevel.ogg.SyncState;
47import org.tritonus.lowlevel.ogg.StreamState;
48
49
50
51/**
52 * @author Matthias Pfisterer
53 */
54public class VorbisAudioFileReader
55extends TAudioFileReader
56{
57 private static final int INITAL_READ_LENGTH = 4096;
58 private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
59
60
61
62 public VorbisAudioFileReader()
63 {
64 super(MARK_LIMIT, true);
65 }
66
67
68
69 protected AudioFileFormat getAudioFileFormat(InputStream inputStream,
70 long lFileSizeInBytes)
71 throws UnsupportedAudioFileException, IOException
72 {
73 if (TDebug.TraceAudioFileReader) { TDebug.out(">VorbisAudioFileReader.getAudioFileFormat(): begin"); }
74 SyncState oggSyncState = new SyncState();
75 StreamState oggStreamState = new StreamState();
76 Page oggPage = new Page();
77 Packet oggPacket = new Packet();
78
79 int bytes = 0;
80
81 // Decode setup
82
83 oggSyncState.init(); // Now we can read pages
84
85 // grab some data at the head of the stream. We want the first page
86 // (which is guaranteed to be small and only contain the Vorbis
87 // stream initial header) We need the first page to get the stream
88 // serialno.
89
90 // submit a 4k block to libvorbis' Ogg layer
91 byte[] abBuffer = new byte[INITAL_READ_LENGTH];
92 bytes = inputStream.read(abBuffer);
93 if (TDebug.TraceAudioFileReader) { TDebug.out("read bytes from input stream: " + bytes); }
94 int nResult = oggSyncState.write(abBuffer, bytes);
95 if (TDebug.TraceAudioFileReader) { TDebug.out("SyncState.write() returned " + nResult); }
96
97 // Get the first page.
98 if (oggSyncState.pageOut(oggPage) != 1)
99 {
100 // have we simply run out of data? If so, we're done.
101 if (bytes < INITAL_READ_LENGTH)
102 {
103 if (TDebug.TraceAudioFileReader) { TDebug.out("stream ended prematurely"); }
104 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
105 // IDEA: throw EOFException?
106 oggSyncState.free();
107 oggStreamState.free();
108 oggPage.free();
109 oggPacket.free();
110 throw new UnsupportedAudioFileException("not a Vorbis stream: ended prematurely");
111 }
112 if (TDebug.TraceAudioFileReader) { TDebug.out("not in Ogg bitstream format"); }
113 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
114 oggSyncState.free();
115 oggStreamState.free();
116 oggPage.free();
117 oggPacket.free();
118 throw new UnsupportedAudioFileException("not a Vorbis stream: not in Ogg bitstream format");
119 }
120
121 // Get the serial number and set up the rest of decode.
122 // serialno first; use it to set up a logical stream
123 int nSerialNo = oggPage.getSerialNo();
124 TDebug.out("serial no.: " + nSerialNo);
125 oggStreamState.init(nSerialNo);
126
127 // extract the initial header from the first page and verify that the
128 // Ogg bitstream is in fact Vorbis data
129
130 // I handle the initial header first instead of just having the code
131 // read all three Vorbis headers at once because reading the initial
132 // header is an easy way to identify a Vorbis bitstream and it's
133 // useful to see that functionality seperated out.
134
135 if (oggStreamState.pageIn(oggPage) < 0)
136 {
137 if (TDebug.TraceAudioFileReader) { TDebug.out("can't read first page of Ogg bitstream data"); }
138 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
139 // error; stream version mismatch perhaps
140 oggSyncState.free();
141 oggStreamState.free();
142 oggPage.free();
143 oggPacket.free();
144 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read first page of Ogg bitstream data");
145 }
146
147 if (oggStreamState.packetOut(oggPacket) != 1)
148 {
149 if (TDebug.TraceAudioFileReader) { TDebug.out("can't read initial header packet"); }
150 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
151 // no page? must not be vorbis
152 oggSyncState.free();
153 oggStreamState.free();
154 oggPage.free();
155 oggPacket.free();
156 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read initial header packet");
157 }
158
159 byte[] abData = oggPacket.getData();
160 if (TDebug.TraceAudioFileReader)
161 {
162 String strData = "";
163 for (int i = 0; i < abData.length; i++)
164 {
165 strData += " " + abData[i];
166 }
167 TDebug.out("packet data: " + strData);
168 }
169
170 int nPacketType = abData[0];
171 if (TDebug.TraceAudioFileReader) { TDebug.out("packet type: " + nPacketType); }
172 if (nPacketType != 1)
173 {
174 if (TDebug.TraceAudioFileReader) { TDebug.out("first packet is not the identification header"); }
175 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
176 oggSyncState.free();
177 oggStreamState.free();
178 oggPage.free();
179 oggPacket.free();
180 throw new UnsupportedAudioFileException("not a Vorbis stream: first packet is not the identification header");
181 }
182 if(abData[1] != 'v' ||
183 abData[2] != 'o' ||
184 abData[3] != 'r' ||
185 abData[4] != 'b' ||
186 abData[5] != 'i' ||
187 abData[6] != 's')
188 {
189 if (TDebug.TraceAudioFileReader) { TDebug.out("not a vorbis header packet"); }
190 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
191 oggSyncState.free();
192 oggStreamState.free();
193 oggPage.free();
194 oggPacket.free();
195 throw new UnsupportedAudioFileException("not a Vorbis stream: not a vorbis header packet");
196 }
197 if (! oggPacket.isBos())
198 {
199 if (TDebug.TraceAudioFileReader) { TDebug.out("initial packet not marked as beginning of stream"); }
200 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
201 oggSyncState.free();
202 oggStreamState.free();
203 oggPage.free();
204 oggPacket.free();
205 throw new UnsupportedAudioFileException("not a Vorbis stream: initial packet not marked as beginning of stream");
206 }
207 int nVersion = (abData[7] & 0xFF) + 256 * (abData[8] & 0xFF) + 65536 * (abData[9] & 0xFF) + 16777216 * (abData[10] & 0xFF);
208 if (TDebug.TraceAudioFileReader) { TDebug.out("version: " + nVersion); }
209 if (nVersion != 0)
210 {
211 if (TDebug.TraceAudioFileReader) { TDebug.out("wrong vorbis version"); }
212 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
213 oggSyncState.free();
214 oggStreamState.free();
215 oggPage.free();
216 oggPacket.free();
217 throw new UnsupportedAudioFileException("not a Vorbis stream: wrong vorbis version");
218 }
219 int nChannels = (abData[11] & 0xFF);
220 float fSampleRate = (abData[12] & 0xFF) + 256 * (abData[13] & 0xFF) + 65536 * (abData[14] & 0xFF) + 16777216 * (abData[15] & 0xFF);
221 if (TDebug.TraceAudioFileReader) { TDebug.out("channels: " + nChannels); }
222 if (TDebug.TraceAudioFileReader) { TDebug.out("rate: " + fSampleRate); }
223
224 // These are only used for error checking.
225 int bitrate_upper = abData[16] + 256 * abData[17] + 65536 * abData[18] + 16777216 * abData[19];
226 int bitrate_nominal = abData[20] + 256 * abData[21] + 65536 * abData[22] + 16777216 * abData[23];
227 int bitrate_lower = abData[24] + 256 * abData[25] + 65536 * abData[26] + 16777216 * abData[27];
228
229 int[] blocksizes = new int[2];
230 blocksizes[0] = 1 << (abData[28] & 0xF);
231 blocksizes[1] = 1 << ((abData[28] >>> 4) & 0xF);
232 if (TDebug.TraceAudioFileReader) { TDebug.out("blocksizes[0]: " + blocksizes[0]); }
233 if (TDebug.TraceAudioFileReader) { TDebug.out("blocksizes[1]: " + blocksizes[1]); }
234
235 if (fSampleRate < 1.0F ||
236 nChannels < 1 ||
237 blocksizes[0] < 8||
238 blocksizes[1] < blocksizes[0] ||
239 (abData[29] & 0x1) != 1)
240 {
241 if (TDebug.TraceAudioFileReader) { TDebug.out("illegal values in initial header"); }
242 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
243 oggSyncState.free();
244 oggStreamState.free();
245 oggPage.free();
246 oggPacket.free();
247 throw new UnsupportedAudioFileException("not a Vorbis stream: illegal values in initial header");
248 }
249
250 oggSyncState.free();
251 oggStreamState.free();
252 oggPage.free();
253 oggPacket.free();
254
255 /*
256 If the file size is known, we derive the number of frames
257 ('frame size') from it.
258 If the values don't fit into integers, we leave them at
259 NOT_SPECIFIED. 'Unknown' is considered less incorrect than
260 a wrong value.
261 */
262 // [fb] not specifying it causes Sun's Wave file writer to write rubbish
263 int nByteSize = AudioSystem.NOT_SPECIFIED;
264 if (lFileSizeInBytes != AudioSystem.NOT_SPECIFIED
265 && lFileSizeInBytes <= Integer.MAX_VALUE)
266 {
267 nByteSize = (int) lFileSizeInBytes;
268 }
269 int nFrameSize = AudioSystem.NOT_SPECIFIED;
270 /* Can we calculate a useful size?
271 Peeking into ogginfo gives the insight that the only
272 way seems to be reading through the file. This is
273 something we do not want, at least not by default.
274 */
275 // nFrameSize = (int) (lFileSizeInBytes / ...;
276
277 AudioFormat format = new AudioFormat(
278 new AudioFormat.Encoding("VORBIS"),
279 fSampleRate,
280 AudioSystem.NOT_SPECIFIED,
281 nChannels,
282 AudioSystem.NOT_SPECIFIED,
283 AudioSystem.NOT_SPECIFIED,
284 true); // this value is chosen arbitrarily
285 if (TDebug.TraceAudioFileReader) { TDebug.out("AudioFormat: " + format); }
286 AudioFileFormat.Type type = new AudioFileFormat.Type("Ogg","ogg");
287 AudioFileFormat audioFileFormat =
288 new TAudioFileFormat(
289 type,
290 format,
291 nFrameSize,
292 nByteSize);
293 if (TDebug.TraceAudioFileReader) { TDebug.out("AudioFileFormat: " + audioFileFormat); }
294 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): end"); }
295 return audioFileFormat;
296 }
297}
298
299
300
301/*** VorbisAudioFileReader.java ***/
302
diff --git a/songdbj/org/tritonus/file/vorbis/VorbisAudioFileWriter.java b/songdbj/org/tritonus/file/vorbis/VorbisAudioFileWriter.java
new file mode 100644
index 0000000000..ee7e310e48
--- /dev/null
+++ b/songdbj/org/tritonus/file/vorbis/VorbisAudioFileWriter.java
@@ -0,0 +1,75 @@
1/*
2 * VorbisAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.sampled.file.vorbis;
31
32import java.util.Arrays;
33
34import javax.sound.sampled.AudioFileFormat;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.file.THeaderlessAudioFileWriter;
40
41
42
43/** Class for writing Vorbis streams
44 *
45 * @author Florian Bomers
46 * @author Matthias Pfisterer
47 */
48public class VorbisAudioFileWriter
49extends THeaderlessAudioFileWriter
50{
51 private static final AudioFileFormat.Type[] FILE_TYPES =
52 {
53 new AudioFileFormat.Type("Vorbis", "ogg")
54 };
55
56 private static final AudioFormat[] AUDIO_FORMATS =
57 {
58 new AudioFormat(new AudioFormat.Encoding("VORBIS"), ALL, ALL, ALL, ALL, ALL, false),
59 new AudioFormat(new AudioFormat.Encoding("VORBIS"), ALL, ALL, ALL, ALL, ALL, true),
60 };
61
62
63
64 public VorbisAudioFileWriter()
65 {
66 super(Arrays.asList(FILE_TYPES),
67 Arrays.asList(AUDIO_FORMATS));
68 if (TDebug.TraceAudioFileWriter) { TDebug.out("VorbisAudioFileWriter.<init>(): begin"); }
69 if (TDebug.TraceAudioFileWriter) { TDebug.out("VorbisAudioFileWriter.<init>(): end"); }
70 }
71}
72
73
74
75/*** VorbisAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/vorbis/package.html b/songdbj/org/tritonus/file/vorbis/package.html
new file mode 100644
index 0000000000..5d6c328b7d
--- /dev/null
+++ b/songdbj/org/tritonus/file/vorbis/package.html
@@ -0,0 +1,12 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Ogg vorbis audio file reader and writer based on native libraries.
8 The classes provided here .</p>
9
10 @see org.tritonus.lowlevel.ogg
11 </body>
12</html>
diff --git a/songdbj/org/tritonus/lowlevel/ogg/Buffer.java b/songdbj/org/tritonus/lowlevel/ogg/Buffer.java
new file mode 100644
index 0000000000..2903f0e17e
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/ogg/Buffer.java
@@ -0,0 +1,173 @@
1/*
2 * Buffer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.ogg;
30
31import org.tritonus.share.TDebug;
32
33
34/** Wrapper for oggpack_buffer.
35 */
36public class Buffer
37{
38 static
39 {
40 Ogg.loadNativeLibrary();
41 if (TDebug.TraceOggNative)
42 {
43 setTrace(true);
44 }
45 }
46
47
48 /**
49 * Holds the pointer to oggpack_buffer
50 * for the native code.
51 * This must be long to be 64bit-clean.
52 */
53 private long m_lNativeHandle;
54
55
56
57 public Buffer()
58 {
59 if (TDebug.TraceOggNative) { TDebug.out("Buffer.<init>(): begin"); }
60 int nReturn = malloc();
61 if (nReturn < 0)
62 {
63 throw new RuntimeException("malloc of ogg_page failed");
64 }
65 if (TDebug.TraceOggNative) { TDebug.out("Buffer.<init>(): end"); }
66 }
67
68
69
70 public void finalize()
71 {
72 // TODO: call free()
73 // call super.finalize() first or last?
74 // and introduce a flag if free() has already been called?
75 }
76
77
78
79 private native int malloc();
80 public native void free();
81
82
83 /** Calls oggpack_writeinit().
84 */
85 public native void writeInit();
86
87
88 /** Calls oggpack_writetrunc().
89 */
90 public native void writeTrunc(int nBits);
91
92
93 /** Calls oggpack_writealign().
94 */
95 public native void writeAlign();
96
97
98 /** Calls oggpack_writecopy().
99 */
100 public native void writeCopy(byte[] abSource, int nBits);
101
102
103 /** Calls oggpack_reset().
104 */
105 public native void reset();
106
107
108 /** Calls oggpack_writeclear().
109 */
110 public native void writeClear();
111
112
113 /** Calls oggpack_readinit().
114 */
115 public native void readInit(byte[] abBuffer, int nBytes);
116
117
118 /** Calls oggpack_write().
119 */
120 public native void write(int nValue, int nBits);
121
122
123 /** Calls oggpack_look().
124 */
125 public native int look(int nBits);
126
127
128 /** Calls oggpack_look1().
129 */
130 public native int look1();
131
132
133 /** Calls oggpack_adv().
134 */
135 public native void adv(int nBits);
136
137
138 /** Calls oggpack_adv1().
139 */
140 public native void adv1();
141
142
143 /** Calls oggpack_read().
144 */
145 public native int read(int nBits);
146
147
148 /** Calls oggpack_read1().
149 */
150 public native int read1();
151
152
153 /** Calls oggpack_bytes().
154 */
155 public native int bytes();
156
157
158 /** Calls oggpack_bits().
159 */
160 public native int bits();
161
162
163 /** Calls oggpack_get_buffer().
164 */
165 public native byte[] getBuffer();
166
167
168 private static native void setTrace(boolean bTrace);
169}
170
171
172
173/*** Buffer.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/Ogg.java b/songdbj/org/tritonus/lowlevel/ogg/Ogg.java
new file mode 100644
index 0000000000..1ad6bde789
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/ogg/Ogg.java
@@ -0,0 +1,104 @@
1/*
2 * Ogg.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.lowlevel.ogg;
32
33import org.tritonus.share.TDebug;
34
35
36/** libogg loading.
37 */
38public class Ogg
39{
40 private static boolean sm_bIsLibraryAvailable = false;
41
42
43
44 static
45 {
46 Ogg.loadNativeLibrary();
47 }
48
49
50
51 public static void loadNativeLibrary()
52 {
53 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibrary(): begin"); }
54
55 if (! isLibraryAvailable())
56 {
57 loadNativeLibraryImpl();
58 }
59 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibrary(): end"); }
60 }
61
62
63
64 /** Load the native library for ogg vorbis.
65
66 This method actually does the loading of the library. Unlike
67 {@link loadNativeLibrary() loadNativeLibrary()}, it does not
68 check if the library is already loaded.
69
70 */
71 private static void loadNativeLibraryImpl()
72 {
73 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibraryImpl(): loading native library tritonusvorbis"); }
74 try
75 {
76 System.loadLibrary("tritonusvorbis");
77 // only reached if no exception occures
78 sm_bIsLibraryAvailable = true;
79 }
80 catch (Error e)
81 {
82 if (TDebug.TraceOggNative ||
83 TDebug.TraceAllExceptions)
84 {
85 TDebug.out(e);
86 }
87 // throw e;
88 }
89 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibraryImpl(): loaded"); }
90 }
91
92
93
94 /** Returns whether the libraries are installed correctly.
95 */
96 public static boolean isLibraryAvailable()
97 {
98 return sm_bIsLibraryAvailable;
99 }
100}
101
102
103
104/*** Ogg.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/Packet.java b/songdbj/org/tritonus/lowlevel/ogg/Packet.java
new file mode 100644
index 0000000000..a5b3f6e7e2
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/ogg/Packet.java
@@ -0,0 +1,113 @@
1/*
2 * Packet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.ogg;
30
31import org.tritonus.share.TDebug;
32
33
34
35/** Wrapper for ogg_packet.
36 */
37public class Packet
38{
39 static
40 {
41 Ogg.loadNativeLibrary();
42 if (TDebug.TraceOggNative)
43 {
44 setTrace(true);
45 }
46 }
47
48
49 /**
50 * Holds the pointer to ogg_packet
51 * for the native code.
52 * This must be long to be 64bit-clean.
53 */
54 private long m_lNativeHandle;
55
56
57
58 public Packet()
59 {
60 if (TDebug.TraceOggNative) { TDebug.out("Packet.<init>(): begin"); }
61 int nReturn = malloc();
62 if (nReturn < 0)
63 {
64 throw new RuntimeException("malloc of ogg_packet failed");
65 }
66 if (TDebug.TraceOggNative) { TDebug.out("Packet.<init>(): end"); }
67 }
68
69
70
71 public void finalize()
72 {
73 // TODO: call free()
74 // call super.finalize() first or last?
75 // and introduce a flag if free() has already been called?
76 }
77
78
79
80 private native int malloc();
81 public native void free();
82
83
84
85 /** Calls ogg_packet_clear().
86 */
87 public native void clear();
88
89
90
91 /** Accesses packet and bytes.
92 */
93 public native byte[] getData();
94
95
96 /** Accesses b_o_s.
97 */
98 public native boolean isBos();
99
100
101 /** Accesses e_o_s.
102 */
103 public native boolean isEos();
104
105
106 private static native void setTrace(boolean bTrace);
107}
108
109
110
111
112
113/*** Packet.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/Page.java b/songdbj/org/tritonus/lowlevel/ogg/Page.java
new file mode 100644
index 0000000000..ae30f210d4
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/ogg/Page.java
@@ -0,0 +1,131 @@
1/*
2 * Page.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.ogg;
30
31import org.tritonus.share.TDebug;
32
33
34
35/** Wrapper for ogg_page.
36 */
37public class Page
38{
39 static
40 {
41 Ogg.loadNativeLibrary();
42 if (TDebug.TraceOggNative)
43 {
44 setTrace(true);
45 }
46 }
47 /**
48 * Holds the pointer to ogg_page
49 * for the native code.
50 * This must be long to be 64bit-clean.
51 */
52 private long m_lNativeHandle;
53
54
55
56 public Page()
57 {
58 if (TDebug.TraceOggNative) { TDebug.out("Page.<init>(): begin"); }
59 int nReturn = malloc();
60 if (nReturn < 0)
61 {
62 throw new RuntimeException("malloc of ogg_page failed");
63 }
64 if (TDebug.TraceOggNative) { TDebug.out("Page.<init>(): end"); }
65 }
66
67
68
69 public void finalize()
70 {
71 // TODO: call free()
72 // call super.finalize() first or last?
73 // and introduce a flag if free() has already been called?
74 }
75
76
77
78 private native int malloc();
79 public native void free();
80
81
82 /** Calls ogg_page_version().
83 */
84 public native int getVersion();
85
86 /** Calls ogg_page_continued().
87 */
88 public native boolean isContinued();
89
90 /** Calls ogg_page_packets().
91 */
92 public native int getPackets();
93
94 /** Calls ogg_page_bos().
95 */
96 public native boolean isBos();
97
98 /** Calls ogg_page_eos().
99 */
100 public native boolean isEos();
101
102 /** Calls ogg_page_granulepos().
103 */
104 public native long getGranulePos();
105
106 /** Calls ogg_page_serialno().
107 */
108 public native int getSerialNo();
109
110 /** Calls ogg_page_pageno().
111 */
112 public native int getPageNo();
113
114 /** Calls ogg_page_checksum_set().
115 */
116 public native void setChecksum();
117
118
119 public native byte[] getHeader();
120
121 public native byte[] getBody();
122
123
124 private static native void setTrace(boolean bTrace);
125}
126
127
128
129
130
131/*** Page.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/StreamState.java b/songdbj/org/tritonus/lowlevel/ogg/StreamState.java
new file mode 100644
index 0000000000..34b970c5e2
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/ogg/StreamState.java
@@ -0,0 +1,143 @@
1/*
2 * StreamState.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.ogg;
30
31import org.tritonus.share.TDebug;
32
33
34/** Wrapper for ogg_stream_state.
35 */
36public class StreamState
37{
38 static
39 {
40 Ogg.loadNativeLibrary();
41 if (TDebug.TraceOggNative)
42 {
43 setTrace(true);
44 }
45 }
46
47
48 /**
49 * Holds the pointer to ogg_stream_state
50 * for the native code.
51 * This must be long to be 64bit-clean.
52 */
53 private long m_lNativeHandle;
54
55
56
57 public StreamState()
58 {
59 if (TDebug.TraceOggNative) { TDebug.out("StreamState.<init>(): begin"); }
60 int nReturn = malloc();
61 if (nReturn < 0)
62 {
63 throw new RuntimeException("malloc of ogg_stream_state failed");
64 }
65 if (TDebug.TraceOggNative) { TDebug.out("StreamState.<init>(): end"); }
66 }
67
68
69
70 public void finalize()
71 {
72 // TODO: call free()
73 // call super.finalize() first or last?
74 // and introduce a flag if free() has already been called?
75 }
76
77
78
79 private native int malloc();
80 public native void free();
81
82
83
84 /** Calls ogg_stream_init().
85 */
86 public native int init(int nSerialNo);
87
88 /** Calls ogg_stream_clear().
89 */
90 public native int clear();
91
92 /** Calls ogg_stream_reset().
93 */
94 public native int reset();
95
96 /** Calls ogg_stream_destroy().
97 */
98 public native int destroy();
99
100 /** Calls ogg_stream_eos().
101 */
102 public native boolean isEOSReached();
103
104
105
106 /** Calls ogg_stream_packetin().
107 */
108 public native int packetIn(Packet packet);
109
110
111 /** Calls ogg_stream_pageout().
112 */
113 public native int pageOut(Page page);
114
115
116 /** Calls ogg_stream_flush().
117 */
118 public native int flush(Page page);
119
120
121 /** Calls ogg_stream_pagein().
122 */
123 public native int pageIn(Page page);
124
125
126 /** Calls ogg_stream_packetout().
127 */
128 public native int packetOut(Packet packet);
129
130
131 /** Calls ogg_stream_packetpeek().
132 */
133 public native int packetPeek(Packet packet);
134
135
136 private static native void setTrace(boolean bTrace);
137}
138
139
140
141
142
143/*** StreamState.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/SyncState.java b/songdbj/org/tritonus/lowlevel/ogg/SyncState.java
new file mode 100644
index 0000000000..3b3b535fbe
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/ogg/SyncState.java
@@ -0,0 +1,127 @@
1/*
2 * SyncState.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.ogg;
30
31import org.tritonus.share.TDebug;
32
33
34/** Wrapper for ogg_sync_state.
35 */
36public class SyncState
37{
38 static
39 {
40 Ogg.loadNativeLibrary();
41 if (TDebug.TraceOggNative)
42 {
43 setTrace(true);
44 }
45 }
46
47
48 /**
49 * Holds the pointer to ogg_sync_state
50 * for the native code.
51 * This must be long to be 64bit-clean.
52 */
53 private long m_lNativeHandle;
54
55
56
57 public SyncState()
58 {
59 if (TDebug.TraceOggNative) { TDebug.out("SyncState.<init>(): begin"); }
60 int nReturn = malloc();
61 if (nReturn < 0)
62 {
63 throw new RuntimeException("malloc of ogg_sync_state failed");
64 }
65 if (TDebug.TraceOggNative) { TDebug.out("SyncState.<init>(): end"); }
66 }
67
68
69
70 public void finalize()
71 {
72 // TODO: call free()
73 // call super.finalize() first or last?
74 // and introduce a flag if free() has already been called?
75 }
76
77
78
79 private native int malloc();
80 public native void free();
81
82
83
84 /** Calls ogg_sync_init().
85 */
86 public native void init();
87
88
89 /** Calls ogg_sync_clear().
90 */
91 public native void clear();
92
93
94 /** Calls ogg_sync_reset().
95 */
96 public native void reset();
97
98
99 /** Calls ogg_sync_destroy().
100 */
101 public native void destroy();
102
103
104 /** Calls ogg_sync_buffer()
105 and ogg_sync_wrote().
106 */
107 public native int write(byte[] abBuffer, int nBytes);
108
109
110 /** Calls ogg_sync_pageseek().
111 */
112 public native int pageseek(Page page);
113
114
115 /** Calls ogg_sync_pageout().
116 */
117 public native int pageOut(Page page);
118
119
120 private static native void setTrace(boolean bTrace);
121}
122
123
124
125
126
127/*** SyncState.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/package.html b/songdbj/org/tritonus/lowlevel/ogg/package.html
new file mode 100644
index 0000000000..4202aaebac
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/ogg/package.html
@@ -0,0 +1,12 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Access to the native ogg library.
8 The classes provided here .</p>
9
10 @see org.tritonus.sampled.convert.vorbis
11 </body>
12</html>
diff --git a/songdbj/org/tritonus/lowlevel/pogg/Buffer.java b/songdbj/org/tritonus/lowlevel/pogg/Buffer.java
new file mode 100644
index 0000000000..6d94c37740
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/pogg/Buffer.java
@@ -0,0 +1,284 @@
1/*
2 * Buffer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2005 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.pogg;
30
31import java.io.UnsupportedEncodingException;
32
33import org.tritonus.share.TDebug;
34
35
36/** Wrapper for oggpack_buffer.
37 */
38public class Buffer
39{
40 static
41 {
42 Ogg.loadNativeLibrary();
43 if (TDebug.TraceOggNative)
44 {
45 setTrace(true);
46 }
47 }
48
49
50 /**
51 * Holds the pointer to oggpack_buffer
52 * for the native code.
53 * This must be long to be 64bit-clean.
54 */
55 private long m_lNativeHandle;
56
57
58
59 public Buffer()
60 {
61 if (TDebug.TraceOggNative) { TDebug.out("Buffer.<init>(): begin"); }
62 int nReturn = malloc();
63 if (nReturn < 0)
64 {
65 throw new RuntimeException("malloc of ogg_page failed");
66 }
67 if (TDebug.TraceOggNative) { TDebug.out("Buffer.<init>(): end"); }
68 }
69
70
71
72 public void finalize()
73 {
74 // TODO: call free()
75 // call super.finalize() first or last?
76 // and introduce a flag if free() has already been called?
77 }
78
79
80
81 private native int malloc();
82 public native void free();
83
84
85 /** Calls oggpack_writeinit().
86 */
87 public native void writeInit();
88
89
90 /** Calls oggpack_writetrunc().
91 */
92 public native void writeTrunc(int nBits);
93
94
95 /** Calls oggpack_writealign().
96 */
97 public native void writeAlign();
98
99
100 /** Calls oggpack_writecopy().
101 */
102 public native void writeCopy(byte[] abSource, int nBits);
103
104
105 /** Calls oggpack_reset().
106 */
107 public native void reset();
108
109
110 /** Calls oggpack_writeclear().
111 */
112 public native void writeClear();
113
114
115 /** Calls oggpack_readinit().
116 */
117 public native void readInit(byte[] abBuffer, int nBytes);
118
119
120 /** Calls oggpack_write().
121 */
122 public native void write(int nValue, int nBits);
123
124
125 /** Calls oggpack_look().
126 */
127 public native int look(int nBits);
128
129
130 /** Calls oggpack_look1().
131 */
132 public native int look1();
133
134
135 /** Calls oggpack_adv().
136 */
137 public native void adv(int nBits);
138
139
140 /** Calls oggpack_adv1().
141 */
142 public native void adv1();
143
144
145 /** Calls oggpack_read().
146 */
147 public native int read(int nBits);
148
149
150 /** Calls oggpack_read1().
151 */
152 public native int read1();
153
154
155 /** Calls oggpack_bytes().
156 */
157 public native int bytes();
158
159
160 /** Calls oggpack_bits().
161 */
162 public native int bits();
163
164
165 /** Calls oggpack_get_buffer().
166 */
167 public native byte[] getBuffer();
168
169
170 /** Writes a string as UTF-8.
171 Note: no length coding and no end byte are written,
172 just the pure string!
173 */
174 public void write(String str)
175 {
176 write(str, false);
177 }
178
179
180 /** Writes a string as UTF-8, including a length coding.
181 In front of the string, the length in bytes is written
182 as a 32 bit integer. No end byte is written.
183 */
184 public void writeWithLength(String str)
185 {
186 write(str, true);
187 }
188
189
190 /** Writes a string as UTF-8, with or without a length coding.
191 If a length coding is requested, the length in (UTF8-)bytes is written
192 as a 32 bit integer in front of the string.
193 No end byte is written.
194 */
195 private void write(String str, boolean bWithLength)
196 {
197 byte[] aBytes = null;
198 try
199 {
200 aBytes = str.getBytes("UTF-8");
201 }
202 catch (UnsupportedEncodingException e)
203 {
204 if (TDebug.TraceAllExceptions) TDebug.out(e);
205 }
206 if (bWithLength)
207 {
208 write(aBytes.length, 32);
209 }
210 for (int i = 0; i < aBytes.length; i++)
211 {
212 write(aBytes[i], 8);
213 }
214 }
215
216
217 /** Reads a UTF-8 coded string with length coding.
218 It is expected that at the current read position,
219 there is a 32 bit integer containing the length in (UTF8-)bytes,
220 followed by the specified number of bytes in UTF-8 coding.
221
222 @return the string read from the buffer or null if an error occurs.
223 */
224 public String readString()
225 {
226 int length = read(32);
227 if (length < 0)
228 {
229 return null;
230 }
231 return readString(length);
232 }
233
234
235 /** Reads a UTF-8 coded string without length coding.
236 It is expected that at the current read position,
237 there is string in UTF-8 coding.
238
239 @return the string read from the buffer or null if an error occurs.
240 */
241 public String readString(int nLength)
242 {
243 byte[] aBytes = new byte[nLength];
244 for (int i = 0; i < nLength; i++)
245 {
246 aBytes[i] = (byte) read(8);
247 }
248 String s = null;
249 try
250 {
251 s = new String(aBytes, "UTF-8");
252 }
253 catch (UnsupportedEncodingException e)
254 {
255 if (TDebug.TraceAllExceptions) TDebug.out(e);
256 }
257 return s;
258 }
259
260
261 /** Reads a single bit.
262 */
263 public boolean readFlag()
264 {
265 return (read(1) != 0);
266 }
267
268 private static native void setTrace(boolean bTrace);
269
270 // for debugging
271 public static void outBuffer(byte[] buffer)
272 {
273 String s = "";
274 for (int i = 0; i < buffer.length; i++)
275 {
276 s += "" + buffer[i] + ", ";
277 }
278 TDebug.out("buffer: " + s);
279 }
280}
281
282
283
284/*** Buffer.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/Ogg.java b/songdbj/org/tritonus/lowlevel/pogg/Ogg.java
new file mode 100644
index 0000000000..086dd0f001
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/pogg/Ogg.java
@@ -0,0 +1,104 @@
1/*
2 * Ogg.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.lowlevel.pogg;
32
33import org.tritonus.share.TDebug;
34
35
36/** libogg loading.
37 */
38public class Ogg
39{
40 private static boolean sm_bIsLibraryAvailable = false;
41
42
43
44 static
45 {
46 Ogg.loadNativeLibrary();
47 }
48
49
50
51 public static void loadNativeLibrary()
52 {
53 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibrary(): begin"); }
54
55 if (! isLibraryAvailable())
56 {
57 loadNativeLibraryImpl();
58 }
59 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibrary(): end"); }
60 }
61
62
63
64 /** Load the native library for ogg vorbis.
65
66 This method actually does the loading of the library. Unlike
67 {@link loadNativeLibrary() loadNativeLibrary()}, it does not
68 check if the library is already loaded.
69
70 */
71 private static void loadNativeLibraryImpl()
72 {
73 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibraryImpl(): loading native library tritonuspvorbis"); }
74 try
75 {
76 System.loadLibrary("tritonuspvorbis");
77 // only reached if no exception occures
78 sm_bIsLibraryAvailable = true;
79 }
80 catch (Error e)
81 {
82 if (TDebug.TraceOggNative ||
83 TDebug.TraceAllExceptions)
84 {
85 TDebug.out(e);
86 }
87 // throw e;
88 }
89 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibraryImpl(): loaded"); }
90 }
91
92
93
94 /** Returns whether the libraries are installed correctly.
95 */
96 public static boolean isLibraryAvailable()
97 {
98 return sm_bIsLibraryAvailable;
99 }
100}
101
102
103
104/*** Ogg.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/Packet.java b/songdbj/org/tritonus/lowlevel/pogg/Packet.java
new file mode 100644
index 0000000000..15c5d9a66e
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/pogg/Packet.java
@@ -0,0 +1,133 @@
1/*
2 * Packet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.pogg;
30
31import org.tritonus.share.TDebug;
32
33
34
35/** Wrapper for ogg_packet.
36 */
37public class Packet
38{
39 static
40 {
41 Ogg.loadNativeLibrary();
42 if (TDebug.TraceOggNative)
43 {
44 setTrace(true);
45 }
46 }
47
48
49 /**
50 * Holds the pointer to ogg_packet
51 * for the native code.
52 * This must be long to be 64bit-clean.
53 */
54 private long m_lNativeHandle;
55
56
57
58 public Packet()
59 {
60 if (TDebug.TraceOggNative) { TDebug.out("Packet.<init>(): begin"); }
61 int nReturn = malloc();
62 if (nReturn < 0)
63 {
64 throw new RuntimeException("malloc of ogg_packet failed");
65 }
66 if (TDebug.TraceOggNative) { TDebug.out("Packet.<init>(): end"); }
67 }
68
69
70
71 public void finalize()
72 {
73 // TODO: call free()
74 // call super.finalize() first or last?
75 // and introduce a flag if free() has already been called?
76 }
77
78
79
80 private native int malloc();
81 public native void free();
82
83
84
85 /** Calls ogg_packet_clear().
86 */
87 public native void clear();
88
89
90
91 /** Accesses packet and bytes.
92 */
93 public native byte[] getData();
94
95
96 /** Accesses b_o_s.
97 */
98 public native boolean isBos();
99
100
101 /** Accesses e_o_s.
102 */
103 public native boolean isEos();
104
105
106 public native long getGranulePos();
107
108
109 public native long getPacketNo();
110
111
112 /** Sets the data in the packet.
113 */
114 public native void setData(byte[] abData, int nOffset, int nLength);
115
116
117 public native void setFlags(boolean bBos, boolean bEos, long lGranulePos,
118 long lPacketNo);
119
120 public void setFlags(boolean bBos, boolean bEos, long lGranulePos)
121 {
122 setFlags(bBos, bEos, lGranulePos, 0);
123 }
124
125
126 private static native void setTrace(boolean bTrace);
127}
128
129
130
131
132
133/*** Packet.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/Page.java b/songdbj/org/tritonus/lowlevel/pogg/Page.java
new file mode 100644
index 0000000000..3f89d7166e
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/pogg/Page.java
@@ -0,0 +1,298 @@
1/*
2 * Page.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.pogg;
30
31import org.tritonus.share.TDebug;
32
33
34
35/** Wrapper for ogg_page.
36 */
37public class Page
38{
39 private static final int[] crc_lookup =
40 {
41 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
42 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
43 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
44 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
45 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
46 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
47 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
48 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
49 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
50 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
51 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
52 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
53 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
54 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
55 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
56 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
57 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
58 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
59 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
60 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
61 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
62 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
63 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
64 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
65 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
66 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
67 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
68 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
69 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
70 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
71 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
72 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
73 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
74 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
75 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
76 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
77 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
78 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
79 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
80 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
81 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
82 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
83 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
84 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
85 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
86 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
87 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
88 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
89 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
90 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
91 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
92 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
93 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
94 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
95 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
96 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
97 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
98 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
99 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
100 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
101 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
102 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
103 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
104 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4
105 };
106
107
108 private byte[] m_abHeader;
109 private int m_nHeaderLength;
110 private byte[] m_abBody;
111 private int m_nBodyLength;
112
113
114 public Page()
115 {
116 if (TDebug.TraceOggNative) { TDebug.out("Page.<init>(): begin"); }
117 if (TDebug.TraceOggNative) { TDebug.out("Page.<init>(): end"); }
118 }
119
120
121
122 private native int malloc();
123
124 // TODO: remove calls to this method
125 public void free()
126 {
127 }
128
129
130 /** Calls ogg_page_version().
131 */
132 public int getVersion()
133 {
134 return m_abHeader[4] & 0xFF;
135 }
136
137
138 /** Calls ogg_page_continued().
139 */
140 public boolean isContinued()
141 {
142 return (m_abHeader[5] & 0x01) != 0;
143 }
144
145
146
147 /** Calls ogg_page_packets().
148 */
149/* returns the number of packets that are completed on this page (if
150 the leading packet is begun on a previous page, but ends on this
151 page, it's counted */
152
153/* NOTE:
154If a page consists of a packet begun on a previous page, and a new
155packet begun (but not completed) on this page, the return will be:
156 ogg_page_packets(page) ==1,
157 ogg_page_continued(page) !=0
158
159If a page happens to be a single packet that was begun on a
160previous page, and spans to the next page (in the case of a three or
161more page packet), the return will be:
162 ogg_page_packets(page) ==0,
163 ogg_page_continued(page) !=0
164*/
165 public int getPackets()
166 {
167 int n = m_abHeader[26] & 0xFF;
168 int count = 0;
169 for (int i = 0; i < n; i++)
170 if ((m_abHeader[27 + i] & 0xFF) < 255)
171 count++;
172 return count;
173 }
174
175
176
177 /** Calls ogg_page_bos().
178 */
179 public boolean isBos()
180 {
181 return (m_abHeader[5] & 0x02) != 0;
182 }
183
184
185
186 /** Calls ogg_page_eos().
187 */
188 public boolean isEos()
189 {
190 return (m_abHeader[5] & 0x04) != 0;
191 }
192
193
194
195 /** Calls ogg_page_granulepos().
196 */
197 public long getGranulePos()
198 {
199 long granulepos = m_abHeader[13]&(0xff);
200 granulepos = (granulepos<<8)|(m_abHeader[12] & 0xFF);
201 granulepos = (granulepos<<8)|(m_abHeader[11] & 0xFF);
202 granulepos = (granulepos<<8)|(m_abHeader[10] & 0xFF);
203 granulepos = (granulepos<<8)|(m_abHeader[9] & 0xFF);
204 granulepos = (granulepos<<8)|(m_abHeader[8] & 0xFF);
205 granulepos = (granulepos<<8)|(m_abHeader[7] & 0xFF);
206 granulepos = (granulepos<<8)|(m_abHeader[6] & 0xFF);
207 return granulepos;
208 }
209
210
211
212 /** Calls ogg_page_serialno().
213 */
214 public int getSerialNo()
215 {
216 return m_abHeader[14] |
217 (m_abHeader[15] << 8) |
218 (m_abHeader[16] << 16) |
219 (m_abHeader[17] << 24);
220 }
221
222
223
224 /** Calls ogg_page_pageno().
225 */
226 public int getPageNo()
227 {
228 return m_abHeader[18] |
229 (m_abHeader[19] << 8) |
230 (m_abHeader[20] << 16) |
231 (m_abHeader[21] << 24);
232 }
233
234
235
236 /** Calls ogg_page_checksum_set().
237 */
238 public void setChecksum()
239 {
240 int crc_reg = 0;
241
242 /* safety; needed for API behavior, but not framing code */
243 m_abHeader[22]=0;
244 m_abHeader[23]=0;
245 m_abHeader[24]=0;
246 m_abHeader[25]=0;
247
248 for(int i = 0; i < m_nHeaderLength; i++)
249 crc_reg = (crc_reg << 8) ^ crc_lookup[((crc_reg >>> 24) & 0xff) ^ (m_abHeader[i] & 0xFF)];
250 for(int i = 0; i < m_nBodyLength; i++)
251 crc_reg = (crc_reg << 8) ^ crc_lookup[((crc_reg >>> 24) & 0xff) ^ (m_abBody[i] & 0xFF)];
252
253 m_abHeader[22] = (byte) (crc_reg & 0xff);
254 m_abHeader[23] = (byte) ((crc_reg >> 8) & 0xff);
255 m_abHeader[24] = (byte) ((crc_reg >> 16) & 0xff);
256 m_abHeader[25] = (byte) ((crc_reg >> 24) & 0xff);
257 }
258
259
260
261
262 public byte[] getHeader()
263 {
264 byte[] abHeader = new byte[m_nHeaderLength];
265 System.arraycopy(m_abHeader, 0, abHeader, 0, m_nHeaderLength);
266 return abHeader;
267 }
268
269
270
271 public byte[] getBody()
272 {
273 byte[] abBody = new byte[m_nBodyLength];
274 System.arraycopy(m_abBody, 0, abBody, 0, m_nBodyLength);
275 return abBody;
276 }
277
278
279
280 public void setData(byte[] abHeader, int nHeaderOffset,
281 int nHeaderLength,
282 byte[] abBody, int nBodyOffset,
283 int nBodyLength)
284 {
285 m_abHeader = new byte[nHeaderLength];
286 System.arraycopy(abHeader, nHeaderOffset, m_abHeader, 0, nHeaderLength);
287 m_nHeaderLength = nHeaderLength;
288 m_abBody = new byte[nBodyLength];
289 System.arraycopy(abBody, nBodyOffset, m_abBody, 0, nBodyLength);
290 m_nBodyLength = nBodyLength;
291 }
292}
293
294
295
296
297
298/*** Page.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/StreamState.java b/songdbj/org/tritonus/lowlevel/pogg/StreamState.java
new file mode 100644
index 0000000000..3fde33de8f
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/pogg/StreamState.java
@@ -0,0 +1,703 @@
1/*
2 * StreamState.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2005 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.pogg;
30
31import org.tritonus.share.TDebug;
32
33
34/** Wrapper for ogg_stream_state.
35 */
36public class StreamState
37{
38 private static final int INITIAL_BODY_DATA_SIZE = 16 * 1024;
39 private static final int INITIAL_LACING_VALUES_SIZE = 1024;
40
41 /** The serial number of the stream.
42 This is set by init().
43 */
44 private int m_nSerialNo;
45
46 /** Storage for packet bodies.
47 */
48 private byte[] m_abBodyData;
49
50 /** Number of bytes used in te body storage.
51 */
52 private int m_nBodyFill;
53
54 /** Number of bytes aready returned (as pages) from the body storage.
55 */
56 private int m_nBodyReturned;
57
58 /** Lacing values. Bit 0 to 7 contain the lacing value (mask
59 0xFF). Bit 8 is set if the segment belongs to the first
60 packet of the stream (mask 0x100). Bit 9 is set ig the
61 segment belongs to the last packet of the stream (mask 0x200).
62 */
63 private int[] m_anLacingValues;
64
65 /** Granule values.
66 */
67 private long[] m_alGranuleValues;
68
69 /** Number of elements used in m_anLacingValues and m_alGranuleValues.
70 The elements with the index m_nLacingFill is the first free element.
71 */
72 private int m_nLacingFill;
73
74 /** Pointer to the index in m_anLacingValues where the lacing values
75 of the last decoded packet start (??)
76 */
77 private int m_nLacingPacket;
78
79 /**
80 */
81 private int m_nLacingReturned;
82
83 private byte[] m_abHeader;
84
85 private int m_nHeaderFill;
86
87 private boolean m_bBos;
88 private boolean m_bEos;
89 private int m_nPageNo;
90 private long m_lPacketNo;
91 private long m_lGranulePos;
92
93
94
95 public StreamState()
96 {
97 if (TDebug.TraceOggNative) { TDebug.out("StreamState.<init>(): begin"); }
98 if (TDebug.TraceOggNative) { TDebug.out("StreamState.<init>(): end"); }
99 }
100
101
102
103 public void free()
104 {
105 }
106
107
108
109 /** Calls ogg_stream_init().
110 */
111 public int init(int nSerialNo)
112 {
113 m_nSerialNo = nSerialNo;
114 m_abBodyData = new byte[INITIAL_BODY_DATA_SIZE];
115 m_nBodyFill = 0;
116 m_nBodyReturned = 0;
117 m_anLacingValues = new int[INITIAL_LACING_VALUES_SIZE];
118 m_alGranuleValues = new long[INITIAL_LACING_VALUES_SIZE];
119 m_nLacingFill = 0;
120 m_nLacingPacket = 0;
121 m_nLacingReturned = 0;
122
123 m_abHeader = new byte[282];
124 m_nHeaderFill = 0;
125
126 m_bBos = false;
127 m_bEos = false;
128 m_nPageNo = 0;
129 m_lPacketNo = 0;
130 m_lGranulePos = 0;
131
132 // TODO: necessary?
133 for (int i = 0; i < m_abBodyData.length; i++)
134 m_abBodyData[i] = 0;
135 for (int i = 0; i < m_anLacingValues.length; i++)
136 m_anLacingValues[i] = 0;
137 for (int i = 0; i < m_alGranuleValues.length; i++)
138 m_alGranuleValues[i] = 0;
139
140 // TODO: remove return value
141 return 0;
142 }
143
144 /** Calls ogg_stream_clear().
145 */
146 public int clear()
147 {
148 m_nSerialNo = 0;
149 m_abBodyData = null;
150 m_nBodyFill = 0;
151 m_nBodyReturned = 0;
152 m_anLacingValues = null;
153 m_alGranuleValues = null;
154 m_nLacingFill = 0;
155 m_nLacingPacket = 0;
156 m_nLacingReturned = 0;
157
158 m_abHeader = null;
159 m_nHeaderFill = 0;
160
161 m_bBos = false;
162 m_bEos = false;
163 m_nPageNo = 0;
164 m_lPacketNo = 0;
165 m_lGranulePos = 0;
166
167 // TODO: remove return value
168 return 0;
169 }
170
171 /** Calls ogg_stream_reset().
172 */
173 public int reset()
174 {
175 m_nBodyFill = 0;
176 m_nBodyReturned = 0;
177
178 m_nLacingFill = 0;
179 m_nLacingPacket = 0;
180 m_nLacingReturned = 0;
181
182 m_nHeaderFill = 0;
183
184 m_bBos = false;
185 m_bEos = false;
186 m_nPageNo = -1;
187 m_lPacketNo = 0;
188 m_lGranulePos = 0;
189
190 // TODO: remove return value
191 return 0;
192 }
193
194 /** Calls ogg_stream_eos().
195 */
196 public boolean isEOSReached()
197 {
198 return m_bEos;
199 }
200
201 /** Calls ogg_stream_packetin().
202 */
203 /* submit data to the internal buffer of the framing engine */
204 public int packetIn(Packet packet)
205 {
206 int i;
207 byte[] abPacketData = packet.getData();
208 int lacing_vals = abPacketData.length / 255 + 1;
209
210 if (m_nBodyReturned > 0)
211 {
212 /* advance packet data according to the body_returned pointer. We
213 had to keep it around to return a pointer into the buffer last
214 call */
215 m_nBodyFill -= m_nBodyReturned;
216 if (m_nBodyFill > 0)
217 {
218 System.arraycopy(m_abBodyData, m_nBodyReturned,
219 m_abBodyData, 0, m_nBodyFill);
220 }
221 m_nBodyReturned = 0;
222 }
223
224 /* make sure we have the buffer storage */
225 assureBodyDataCapacity(abPacketData.length);
226 assureLacingValuesCapacity(lacing_vals);
227
228 /* Copy in the submitted packet. Yes, the copy is a waste;
229 this is the liability of overly clean abstraction for the
230 time being. It will actually be fairly easy to eliminate
231 the extra copy in the future */
232 System.arraycopy(abPacketData, 0, m_abBodyData, m_nBodyFill,
233 abPacketData.length);
234 m_nBodyFill += abPacketData.length;
235
236 /* Store lacing vals for this packet */
237 for (i = 0; i < lacing_vals - 1; i++)
238 {
239 m_anLacingValues[m_nLacingFill + i] = 255;
240 m_alGranuleValues[m_nLacingFill + i] = m_lGranulePos;
241 }
242 m_anLacingValues[m_nLacingFill + i] = abPacketData.length % 255;
243 m_alGranuleValues[m_nLacingFill + i] = packet.getGranulePos();
244 m_lGranulePos = packet.getGranulePos();
245
246 /* flag the first segment as the beginning of the packet */
247 m_anLacingValues[m_nLacingFill] |= 0x100;
248
249 m_nLacingFill += lacing_vals;
250
251 /* for the sake of completeness */
252 m_lPacketNo++;
253
254 if (packet.isEos())
255 m_bEos = true;
256 return 0;
257 }
258
259
260
261 /** Calls ogg_stream_pageout().
262 */
263/* This constructs pages from buffered packet segments. The pointers
264 returned are to static buffers; do not free. The returned buffers are
265 good only until the next call (using the same ogg_stream_state) */
266 public int pageOut(Page page)
267 {
268 if ((m_bEos && m_nLacingFill > 0) || /* 'were done, now flush' */
269 m_nBodyFill - m_nBodyReturned > 4096 || /* 'page nominal size' */
270 m_nLacingFill >= 255 || /* 'segment table full' */
271 (m_nLacingFill > 0 && ! m_bBos)) /* 'initial header page' */
272 {
273 return flush(page);
274 }
275 /* not enough data to construct a page and not end of stream */
276 return 0;
277 }
278
279
280
281 /** Calls ogg_stream_flush().
282 */
283/* This will flush remaining packets into a page (returning nonzero),
284 even if there is not enough data to trigger a flush normally
285 (undersized page). If there are no packets or partial packets to
286 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
287 try to flush a normal sized page like ogg_stream_pageout; a call to
288 ogg_stream_flush does not guarantee that all packets have flushed.
289 Only a return value of 0 from ogg_stream_flush indicates all packet
290 data is flushed into pages.
291
292 since ogg_stream_flush will flush the last page in a stream even if
293 it's undersized, you almost certainly want to use ogg_stream_pageout
294 (and *not* ogg_stream_flush) unless you specifically need to flush
295 an page regardless of size in the middle of a stream.
296*/
297 public int flush(Page page)
298 {
299 int i;
300 int vals = 0;
301 int maxvals = Math.min(m_nLacingFill, 255);
302 int bytes = 0;
303 int acc = 0;
304 long granule_pos = m_alGranuleValues[0];
305
306 if (maxvals == 0)
307 {
308 return 0;
309 }
310
311 /* construct a page */
312 /* decide how many segments to include */
313
314 /* If this is the initial header case, the first page must
315 only include the initial header packet */
316 if (! m_bBos)
317 { /* 'initial header page' case */
318 granule_pos = 0;
319 for (vals = 0; vals < maxvals; vals++)
320 {
321 if ((m_anLacingValues[vals] & 0x0FF) < 255)
322 {
323 vals++;
324 break;
325 }
326 }
327 }
328 else
329 {
330 for (vals = 0; vals < maxvals; vals++)
331 {
332 if (acc > 4096)
333 break;
334 acc += (m_anLacingValues[vals] & 0x0FF);
335 granule_pos = m_alGranuleValues[vals];
336 }
337 }
338
339 /* construct the header in temp storage */
340 m_abHeader[0] = (byte) 'O';
341 m_abHeader[1] = (byte) 'g';
342 m_abHeader[2] = (byte) 'g';
343 m_abHeader[3] = (byte) 'S';
344
345 /* stream structure version */
346 m_abHeader[4] = 0;
347
348 m_abHeader[5] = 0x00;
349 /* continued packet flag? */
350 if ((m_anLacingValues[0] & 0x100) == 0)
351 m_abHeader[5] |= 0x01;
352 /* first page flag? */
353 if (! m_bBos)
354 m_abHeader[5] |= 0x02;
355 /* last page flag? */
356 if (m_bEos && m_nLacingFill == vals)
357 m_abHeader[5] |= 0x04;
358 m_bBos = true;
359
360 /* 64 bits of PCM position */
361 for (i = 6; i < 14; i++)
362 {
363 m_abHeader[i] = (byte) (granule_pos & 0xFF);
364 granule_pos >>>= 8;
365 }
366
367 /* 32 bits of stream serial number */
368 int serialno = m_nSerialNo;
369 for (i = 14; i < 18; i++)
370 {
371 m_abHeader[i] = (byte) (serialno & 0xFF);
372 serialno >>>= 8;
373 }
374
375 /* 32 bits of page counter (we have both counter and page header
376 because this val can roll over) */
377 if (m_nPageNo == -1)
378 {
379 m_nPageNo = 0; /* because someone called
380 stream_reset; this would be a
381 strange thing to do in an
382 encode stream, but it has
383 plausible uses */
384 }
385 int pageno = m_nPageNo++;
386 for (i = 18; i < 22; i++)
387 {
388 m_abHeader[i] = (byte) (pageno & 0xFF);
389 pageno >>>= 8;
390 }
391
392 /* zero for computation; filled in later */
393 m_abHeader[22] = 0;
394 m_abHeader[23] = 0;
395 m_abHeader[24] = 0;
396 m_abHeader[25] = 0;
397
398 /* segment table */
399 m_abHeader[26] = (byte) (vals & 0xFF);
400 for (i = 0; i < vals; i++)
401 {
402 m_abHeader[i + 27] = (byte) (m_anLacingValues[i] & 0xFF);
403 bytes += (m_anLacingValues[i] & 0xFF);
404 }
405
406 /* set pointers in the ogg_page struct */
407 page.setData(m_abHeader, 0, vals + 27,
408 m_abBodyData, m_nBodyReturned, bytes);
409 m_nHeaderFill = vals + 27;
410
411 /* advance the lacing data and set the body_returned pointer */
412
413 m_nLacingFill -= vals;
414 System.arraycopy(m_anLacingValues, vals, m_anLacingValues, 0,
415 m_nLacingFill);
416 System.arraycopy(m_alGranuleValues, vals, m_alGranuleValues, 0,
417 m_nLacingFill);
418 m_nBodyReturned += bytes;
419
420 /* calculate the checksum */
421
422 page.setChecksum();
423
424 /* done */
425 return 1;
426 }
427
428
429
430 /** add the incoming page to the stream state; we decompose the
431 page into packet segments here as well.
432
433 @return 0 on success, -1 if the stream serial number stored in
434 the page does not match the one stored in the stream state or
435 if the protocol version stored in the page is greater than 0.
436 */
437 public int pageIn(Page page)
438 {
439 byte[] header = page.getHeader();
440 byte[] body = page.getBody();
441 int nBodyOffset = 0;
442 int bodysize = body.length;
443 int segptr = 0;
444
445 int version = page.getVersion();
446 boolean continued = page.isContinued();
447 boolean bos = page.isBos();
448 boolean eos = page.isEos();
449 long granulepos = page.getGranulePos();
450 int serialno = page.getSerialNo();
451 int pageno = page.getPageNo();
452 int segments = header[26] & 0xFF;
453
454 /* clean up 'returned data' */
455 int lr = m_nLacingReturned;
456 int br = m_nBodyReturned;
457
458 /* body data */
459 if (br > 0)
460 {
461 m_nBodyFill -= br;
462 if (m_nBodyFill > 0)
463 {
464 System.arraycopy(m_abBodyData, br, m_abBodyData, 0,
465 m_nBodyFill);
466 }
467 m_nBodyReturned = 0;
468 }
469
470 if (lr > 0)
471 {
472 /* segment table */
473 if (m_nLacingFill - lr > 0)
474 {
475 System.arraycopy(m_anLacingValues, lr, m_anLacingValues, 0,
476 m_nLacingFill - lr);
477 System.arraycopy(m_alGranuleValues, lr, m_alGranuleValues, 0,
478 m_nLacingFill - lr);
479 }
480 m_nLacingFill -= lr;
481 m_nLacingPacket -= lr;
482 m_nLacingReturned = 0;
483 }
484
485 /* check the serial number */
486 if (serialno != m_nSerialNo)
487 return -1;
488 if (version > 0)
489 return -1;
490
491 assureLacingValuesCapacity(segments + 1);
492
493 /* are we in sequence? */
494 if (pageno != m_nPageNo)
495 {
496 int i;
497
498 /* unroll previous partial packet (if any) */
499 for (i = m_nLacingPacket; i < m_nLacingFill; i++)
500 m_nBodyFill -= (m_anLacingValues[i] & 0xFF);
501 m_nLacingFill = m_nLacingPacket;
502
503 /* make a note of dropped data in segment table */
504 if (m_nPageNo != -1)
505 {
506 m_anLacingValues[m_nLacingFill] = 0x400;
507 m_nLacingFill++;
508 m_nLacingPacket++;
509 }
510
511 /* are we a 'continued packet' page? If so, we'll need to skip
512 some segments */
513 if (continued)
514 {
515 bos = false;
516 for (; segptr < segments; segptr++)
517 {
518 int val = header[27 + segptr] & 0xFF;
519 nBodyOffset += val;
520 bodysize -= val;
521 if (val < 255)
522 {
523 segptr++;
524 break;
525 }
526 }
527 }
528 }
529
530 if (bodysize > 0)
531 {
532 assureBodyDataCapacity(bodysize);
533 System.arraycopy(body, nBodyOffset, m_abBodyData, m_nBodyFill,
534 bodysize);
535 m_nBodyFill += bodysize;
536 }
537
538 int saved = -1;
539 while (segptr < segments)
540 {
541 int val = header[27 + segptr] & 0xFF;
542 m_anLacingValues[m_nLacingFill] = val;
543 m_alGranuleValues[m_nLacingFill] = -1;
544
545 if (bos)
546 {
547 m_anLacingValues[m_nLacingFill] |= 0x100;
548 bos = false;
549 }
550
551 if (val < 255)
552 saved = m_nLacingFill;
553
554 m_nLacingFill++;
555 segptr++;
556
557 if (val < 255)
558 m_nLacingPacket = m_nLacingFill;
559 }
560
561 /* set the granulepos on the last granuleval of the last full packet */
562 if (saved != -1)
563 {
564 m_alGranuleValues[saved] = granulepos;
565 }
566
567 if (eos)
568 {
569 m_bEos = true;
570 if (m_nLacingFill > 0)
571 m_anLacingValues[m_nLacingFill - 1] |= 0x200;
572 }
573
574 m_nPageNo = pageno + 1;
575
576 return 0;
577 }
578
579
580 /** Calls ogg_stream_packetout().
581 */
582 public int packetOut(Packet packet)
583 {
584 return packetOutInternal(packet, true);
585 }
586
587
588 /** Calls ogg_stream_packetpeek().
589 */
590 public int packetPeek(Packet packet)
591 {
592 return packetOutInternal(packet, false);
593 }
594
595
596 /** Retrieves a packet from the internal storage for emission.
597 This method is called by packetOut and packetPeek.
598
599 @param packet the Packet object to store the retrieved packet
600 data in. May be null if bAdvance is false.
601
602 @param bAdvance should the internal pointers to the packet
603 data storage be advanced to the next packet after retrieving
604 this one? Called with a value of true for ordinary packet out
605 and with a value of false for packet peek.
606
607 @return
608 */
609 private int packetOutInternal(Packet packet, boolean bAdvance)
610 {
611 /* The last part of decode. We have the stream broken into
612 packet segments. Now we need to group them into packets
613 (or return the out of sync markers) */
614
615 int ptr = m_nLacingReturned;
616
617 if (m_nLacingPacket <= ptr)
618 return 0;
619
620 if ((m_anLacingValues[ptr] & 0x400) != 0)
621 {
622 /* we need to tell the codec there's a gap; it might need
623 to handle previous packet dependencies. */
624 m_nLacingReturned++;
625 m_lPacketNo++;
626 return -1;
627 }
628
629 if (packet == null && ! bAdvance)
630 return 1; /* just using peek as an inexpensive way
631 to ask if there's a whole packet
632 waiting */
633
634 /* Gather the whole packet. We'll have no holes or a partial
635 * packet */
636 int size = m_anLacingValues[ptr] & 0xFF;
637 int bytes = size;
638 /* last packet of the stream? */
639 boolean eos = (m_anLacingValues[ptr] & 0x200) != 0;
640 /* first packet of the stream? */
641 boolean bos = (m_anLacingValues[ptr] & 0x100) != 0;
642
643 while (size == 255)
644 {
645 int val = m_anLacingValues[++ptr];
646 size = val & 0xff;
647 if ((val & 0x200) != 0)
648 eos = true;
649 bytes += size;
650 }
651
652 if (packet != null)
653 {
654 packet.setData(m_abBodyData, m_nBodyReturned, bytes);
655 packet.setFlags(bos, eos, m_alGranuleValues[ptr], m_lPacketNo);
656 }
657
658 if (bAdvance)
659 {
660 m_nBodyReturned += bytes;
661 m_nLacingReturned = ptr + 1;
662 m_lPacketNo++;
663 }
664 return 1;
665 }
666
667
668 private void assureBodyDataCapacity(int needed)
669 {
670 if (m_abBodyData.length <= m_nBodyFill + needed)
671 {
672 int nNewSize = m_abBodyData.length + needed + 1024;
673 byte[] abNewBodyData = new byte[nNewSize];
674 System.arraycopy(m_abBodyData, 0, abNewBodyData, 0,
675 m_abBodyData.length);
676 m_abBodyData = abNewBodyData;
677 }
678 }
679
680
681
682 private void assureLacingValuesCapacity(int needed)
683 {
684 if (m_anLacingValues.length <= m_nLacingFill + needed)
685 {
686 int nNewSize = m_anLacingValues.length + needed + 32;
687 int[] anNewLacingValues = new int[nNewSize];
688 System.arraycopy(m_anLacingValues, 0, anNewLacingValues, 0,
689 m_anLacingValues.length);
690 m_anLacingValues = anNewLacingValues;
691 long[] alNewGranuleValues = new long[nNewSize];
692 System.arraycopy(m_alGranuleValues, 0, alNewGranuleValues, 0,
693 m_alGranuleValues.length);
694 m_alGranuleValues = alNewGranuleValues;
695 }
696 }
697}
698
699
700
701
702
703/*** StreamState.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/SyncState.java b/songdbj/org/tritonus/lowlevel/pogg/SyncState.java
new file mode 100644
index 0000000000..4246808bd3
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/pogg/SyncState.java
@@ -0,0 +1,339 @@
1/*
2 * SyncState.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2005 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.pogg;
30
31import org.tritonus.share.TDebug;
32
33
34/** Wrapper for ogg_sync_state.
35 */
36public class SyncState
37{
38 /** The stream buffer.
39 This points to a buffer that holds the incoming data from a stream
40 until the data is emitted in form of a page.
41 */
42 private byte[] m_abData;
43
44 /** The number of bytes in the stream buffer that are used. This
45 always counts from the beginning of the buffer. So
46 m_abData[m_nFill] is the first free byte in the buffer.
47 */
48 private int m_nFill;
49
50 /** Number of bytes that have been used to construct a returned
51 page. This is counted from the beginning of the
52 buffer. m_abData[m_nReturned] is the first valid byte in the
53 buffer.
54 */
55 private int m_nReturned;
56
57 /**
58 */
59 private boolean m_bUnsynced;
60
61 /**
62 */
63 private int m_nHeaderBytes;
64
65 /**
66 */
67 private int m_nBodyBytes;
68
69 /** Page object for re-calculating the checksum.
70 */
71 private Page m_tmpPage;
72
73 /** Storage for the checksum saved from the page.
74 */
75 private byte[] m_abChecksum;
76
77
78 public SyncState()
79 {
80 if (TDebug.TraceOggNative) { TDebug.out("SyncState.<init>(): begin"); }
81 m_tmpPage = new Page();
82 m_abChecksum = new byte[4];
83 if (TDebug.TraceOggNative) { TDebug.out("SyncState.<init>(): end"); }
84 }
85
86
87 // TODO: remove calls to this method
88 public void free()
89 {
90 }
91
92
93
94 /** Calls ogg_sync_init().
95 */
96 public void init()
97 {
98 m_abData = null;
99 m_nFill = 0;
100 m_nReturned = 0;
101 m_bUnsynced = false;
102 m_nHeaderBytes = 0;
103 m_nBodyBytes = 0;
104 }
105
106
107 /** Calls ogg_sync_clear().
108 */
109 public void clear()
110 {
111 init();
112 }
113
114
115 /** Calls ogg_sync_reset().
116 */
117 public void reset()
118 {
119 m_nFill = 0;
120 m_nReturned = 0;
121 m_bUnsynced = false;
122 m_nHeaderBytes = 0;
123 m_nBodyBytes = 0;
124 }
125
126
127 /** Writes to the stream buffer.
128 */
129 public int write(byte[] abBuffer, int nBytes)
130 {
131 /* Clear out space that has been previously returned. */
132 if (m_nReturned > 0)
133 {
134 m_nFill -= m_nReturned;
135 if (m_nFill > 0)
136 {
137 System.arraycopy(m_abData, m_nReturned,
138 m_abData, 0,
139 m_nFill);
140 }
141 m_nReturned = 0;
142 }
143
144 /* Check for enough space in the stream buffer and if it is
145 * allocated at all. If there isn't sufficient space, extend
146 * the buffer. */
147 if (m_abData == null || nBytes > m_abData.length - m_nFill)
148 {
149 int nNewSize = nBytes + m_nFill + 4096;
150 byte[] abOldBuffer = m_abData;
151 m_abData = new byte[nNewSize];
152 if (abOldBuffer != null)
153 {
154 System.arraycopy(abOldBuffer, 0, m_abData, 0, m_nFill);
155 }
156 }
157
158 /* Now finally fill with the new data. */
159 System.arraycopy(abBuffer, 0, m_abData, m_nFill, nBytes);
160 m_nFill += nBytes;
161 return 0;
162 }
163
164
165 /** Synchronizes the stream. This method looks if there is a
166 complete, valid page in the stream buffer. If a page is found,
167 it is returned in the passed Page object.
168
169 @param page The Page to store the result of the page search
170 in. The content is only changed if the return value is > 0.
171
172 @return if a page has been found at the current location, the
173 length of the page in bytes is returned. If not enough data
174 for a page is available in the stream buffer, 0 is
175 returned. If data in the stream buffer has been skipped
176 because there is no page at the current position, the skip
177 amount in bytes is returned as a negative number.
178 */
179 public int pageseek(Page page)
180 {
181 int nPage = m_nReturned;
182 int nBytes = m_nFill - m_nReturned;
183
184 if (m_nHeaderBytes == 0)
185 {
186 if (nBytes < 27)
187 {
188 /* Not enough data for a header. */
189 return 0;
190 }
191 /* Verify capture pattern. */
192 if (m_abData[nPage] != (byte) 'O' ||
193 m_abData[nPage + 1] != (byte) 'g' ||
194 m_abData[nPage + 2] != (byte) 'g' ||
195 m_abData[nPage + 3] != (byte) 'S')
196 {
197 TDebug.out("wrong capture pattern");
198 return syncFailure();
199 }
200 int nHeaderBytes = (m_abData[nPage + 26] & 0xFF) + 27;
201 if (nBytes < nHeaderBytes)
202 {
203 /* Not enough data for header + segment table. */
204 return 0;
205 }
206 /* Count up body length in the segment table. */
207 for (int i = 0; i < (m_abData[nPage + 26] & 0xFF); i++)
208 {
209 m_nBodyBytes += (m_abData[nPage + 27 + i] & 0xFF);
210 }
211 m_nHeaderBytes = nHeaderBytes;
212 }
213
214 if (m_nBodyBytes + m_nHeaderBytes > nBytes)
215 {
216 /* Not enough data for the whole packet. */
217 return 0;
218 }
219
220 /* Save the original checksum, set it to zero and recalculate it. */
221 System.arraycopy(m_abData, nPage + 22, m_abChecksum, 0, 4);
222 m_abData[nPage + 22] = 0;
223 m_abData[nPage + 23] = 0;
224 m_abData[nPage + 24] = 0;
225 m_abData[nPage + 25] = 0;
226
227 m_tmpPage.setData(m_abData, nPage, m_nHeaderBytes,
228 m_abData, nPage + m_nHeaderBytes, m_nBodyBytes);
229// TDebug.out("temporary page:");
230// byte[] abHeader = m_tmpPage.getHeader();
231// TDebug.out("H0:" + m_abData[nPage + 0] + " - " + abHeader[0]);
232// TDebug.out("H1:" + m_abData[nPage + 1] + " - " + abHeader[1]);
233// TDebug.out("H2:" + m_abData[nPage + 2] + " - " + abHeader[2]);
234// TDebug.out("H3:" + m_abData[nPage + 3] + " - " + abHeader[3]);
235// TDebug.out("" + m_abChecksum[0] + " - " + abHeader[22]);
236// TDebug.out("" + m_abChecksum[1] + " - " + abHeader[23]);
237// TDebug.out("" + m_abChecksum[2] + " - " + abHeader[24]);
238// TDebug.out("" + m_abChecksum[3] + " - " + abHeader[25]);
239 m_tmpPage.setChecksum();
240 byte[] abHeader = m_tmpPage.getHeader();
241 //m_tmpPage.free();
242 if (abHeader[22] != m_abChecksum[0] ||
243 abHeader[23] != m_abChecksum[1] ||
244 abHeader[24] != m_abChecksum[2] ||
245 abHeader[25] != m_abChecksum[3])
246 {
247 TDebug.out("wrong checksum");
248 TDebug.out("" + m_abChecksum[0] + " - " + abHeader[22]);
249 TDebug.out("" + m_abChecksum[1] + " - " + abHeader[23]);
250 TDebug.out("" + m_abChecksum[2] + " - " + abHeader[24]);
251 TDebug.out("" + m_abChecksum[3] + " - " + abHeader[25]);
252 /* Copy back the saved checksum. */
253 System.arraycopy(m_abChecksum, 0, m_abData, nPage + 22, 4);
254 return syncFailure();
255 }
256
257 /* Ok, we have a correct page to emit. */
258 page.setData(m_abData, nPage, m_nHeaderBytes,
259 m_abData, nPage + m_nHeaderBytes, m_nBodyBytes);
260 m_bUnsynced = false;
261 nBytes = m_nHeaderBytes + m_nBodyBytes;
262 m_nReturned += nBytes;
263 m_nHeaderBytes = 0;
264 m_nBodyBytes = 0;
265 return nBytes;
266 }
267
268
269 /** Auxiliary method for pageseek().
270 */
271 private int syncFailure()
272 {
273 int nPage = m_nReturned;
274 int nBytes = m_nFill - m_nReturned;
275 m_nHeaderBytes = 0;
276 m_nBodyBytes = 0;
277 int nNext = -1;
278 for (int i = 0; i < nBytes - 1; i++)
279 {
280 if (m_abData[nPage + 1 + i] == (byte) 'O')
281 {
282 nNext = nPage + 1 + i;
283 break;
284 }
285 }
286 if (nNext == -1)
287 {
288 nNext = m_nFill;
289 }
290 m_nReturned = nNext;
291 return -(nNext - nPage);
292 }
293
294
295
296
297 /** Returns a page from the stream buffer, if possible. This
298 method searches the current data in the stream buffer for the
299 beginning of a page. If there is one, it is returned in the
300 passed Page object. A synchronization error is signaled by a
301 return value of -1. However, only the first synchronization
302 error is reported. Consecutive sync errors are suppressed.
303
304 @param page The Page to store the result of the page search
305 in. The content is only changed if the return value is 1.
306
307 @return 1 if a page has been found, 0 if there is not enough
308 data, -1 if a synchronization error occured.
309 */
310 public int pageOut(Page page)
311 {
312 while (true)
313 {
314 int nReturn = pageseek(page);
315 if (nReturn > 0)
316 {
317 return 1;
318 }
319 else if (nReturn == 0)
320 {
321 return 0;
322 }
323 else // nReturn < 0
324 {
325 if (! m_bUnsynced)
326 {
327 m_bUnsynced = true;
328 return -1;
329 }
330 }
331 }
332 }
333}
334
335
336
337
338
339/*** SyncState.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/package.html b/songdbj/org/tritonus/lowlevel/pogg/package.html
new file mode 100644
index 0000000000..57b0e50763
--- /dev/null
+++ b/songdbj/org/tritonus/lowlevel/pogg/package.html
@@ -0,0 +1,12 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Alternative pure java implementation of the ogg library.
8 The classes provided here .</p>
9
10 @see org.tritonus.sampled.convert.pvorbis
11 </body>
12</html>
diff --git a/songdbj/org/tritonus/share/ArraySet.java b/songdbj/org/tritonus/share/ArraySet.java
new file mode 100644
index 0000000000..5aa677364f
--- /dev/null
+++ b/songdbj/org/tritonus/share/ArraySet.java
@@ -0,0 +1,87 @@
1/*
2 * ArraySet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 -2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Set;
36
37
38
39public class ArraySet<E>
40extends ArrayList<E>
41implements Set<E>
42{
43 public ArraySet()
44 {
45 super();
46 }
47
48
49
50 public ArraySet(Collection<E> c)
51 {
52 this();
53 addAll(c);
54 }
55
56
57
58 public boolean add(E element)
59 {
60 if (!contains(element))
61 {
62 super.add(element);
63 return true;
64 }
65 else
66 {
67 return false;
68 }
69 }
70
71
72
73 public void add(int index, E element)
74 {
75 throw new UnsupportedOperationException("ArraySet.add(int index, Object element) unsupported");
76 }
77
78 public E set(int index, E element)
79 {
80 throw new UnsupportedOperationException("ArraySet.set(int index, Object element) unsupported");
81 }
82
83}
84
85
86
87/*** ArraySet.java ***/
diff --git a/songdbj/org/tritonus/share/GlobalInfo.java b/songdbj/org/tritonus/share/GlobalInfo.java
new file mode 100644
index 0000000000..9a44c9c870
--- /dev/null
+++ b/songdbj/org/tritonus/share/GlobalInfo.java
@@ -0,0 +1,60 @@
1/*
2 * GlobalInfo.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import org.tritonus.share.TDebug;
34
35
36
37public class GlobalInfo
38{
39 private static final String VENDOR = "Tritonus is free software. See http://www.tritonus.org/";
40 private static final String VERSION = "0.3.1";
41
42
43
44 public static String getVendor()
45 {
46 return VENDOR;
47 }
48
49
50
51 public static String getVersion()
52 {
53 return VERSION;
54 }
55}
56
57
58
59/*** GlobalInfo.java ***/
60
diff --git a/songdbj/org/tritonus/share/StringHashedSet.java b/songdbj/org/tritonus/share/StringHashedSet.java
new file mode 100644
index 0000000000..8e244665fb
--- /dev/null
+++ b/songdbj/org/tritonus/share/StringHashedSet.java
@@ -0,0 +1,112 @@
1/*
2 * StringHashedSet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Iterator;
36
37import org.tritonus.share.ArraySet;
38
39
40/**
41 * A set where the elements are uniquely referenced by their
42 * string representation as given by the objects toString()
43 * method. No 2 objects with the same toString() can
44 * be in the set.
45 * <p>
46 * The <code>contains(Object elem)</code> and <code>get(Object elem)</code>
47 * methods can be called with Strings as <code>elem</code> parameter.
48 * For <code>get(Object elem)</code>, the object that has been added
49 * is returned, and not its String representation.
50 * <p>
51 * Though it's possible to store
52 * Strings as objects in this class, it doesn't make sense
53 * as you could use ArraySet for that equally well.
54 * <p>
55 * You shouldn't use the ArrayList specific functions
56 * like those that take index parameters.
57 * <p>
58 * It is not possible to add <code>null</code> elements.
59 */
60
61public class StringHashedSet<E> extends ArraySet<E>
62{
63 public StringHashedSet()
64 {
65 super();
66 }
67
68 public StringHashedSet(Collection<E> c)
69 {
70 super(c);
71 }
72
73 public boolean add(E elem)
74 {
75 if (elem==null) {
76 return false;
77 }
78 return super.add(elem);
79 }
80
81 public boolean contains(Object elem)
82 {
83 if (elem==null) {
84 return false;
85 }
86 String comp=elem.toString();
87 Iterator<E> it=iterator();
88 while (it.hasNext()) {
89 if (comp.equals(it.next().toString())) {
90 return true;
91 }
92 }
93 return false;
94 }
95
96 public E get(E elem) {
97 if (elem==null) {
98 return null;
99 }
100 String comp=elem.toString();
101 Iterator<E> it=iterator();
102 while (it.hasNext()) {
103 E thisElem=it.next();
104 if (comp.equals(thisElem.toString())) {
105 return thisElem;
106 }
107 }
108 return null;
109 }
110}
111
112/*** StringHashedSet.java ***/
diff --git a/songdbj/org/tritonus/share/TCircularBuffer.java b/songdbj/org/tritonus/share/TCircularBuffer.java
new file mode 100644
index 0000000000..11ebc0af01
--- /dev/null
+++ b/songdbj/org/tritonus/share/TCircularBuffer.java
@@ -0,0 +1,268 @@
1/*
2 * TCircularBuffer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import org.tritonus.share.TDebug;
34
35
36
37public class TCircularBuffer
38{
39 private boolean m_bBlockingRead;
40 private boolean m_bBlockingWrite;
41 private byte[] m_abData;
42 private int m_nSize;
43 private long m_lReadPos;
44 private long m_lWritePos;
45 private Trigger m_trigger;
46 private boolean m_bOpen;
47
48
49
50 public TCircularBuffer(int nSize, boolean bBlockingRead, boolean bBlockingWrite, Trigger trigger)
51 {
52 m_bBlockingRead = bBlockingRead;
53 m_bBlockingWrite = bBlockingWrite;
54 m_nSize = nSize;
55 m_abData = new byte[m_nSize];
56 m_lReadPos = 0;
57 m_lWritePos = 0;
58 m_trigger = trigger;
59 m_bOpen = true;
60 }
61
62
63
64 public void close()
65 {
66 m_bOpen = false;
67 // TODO: call notify() ?
68 }
69
70
71
72 private boolean isOpen()
73 {
74 return m_bOpen;
75 }
76
77
78 public int availableRead()
79 {
80 return (int) (m_lWritePos - m_lReadPos);
81 }
82
83
84
85 public int availableWrite()
86 {
87 return m_nSize - availableRead();
88 }
89
90
91
92 private int getReadPos()
93 {
94 return (int) (m_lReadPos % m_nSize);
95 }
96
97
98
99 private int getWritePos()
100 {
101 return (int) (m_lWritePos % m_nSize);
102 }
103
104
105
106 public int read(byte[] abData)
107 {
108 return read(abData, 0, abData.length);
109 }
110
111
112
113 public int read(byte[] abData, int nOffset, int nLength)
114 {
115 if (TDebug.TraceCircularBuffer)
116 {
117 TDebug.out(">TCircularBuffer.read(): called.");
118 dumpInternalState();
119 }
120 if (! isOpen())
121 {
122 if (availableRead() > 0)
123 {
124 nLength = Math.min(nLength, availableRead());
125 if (TDebug.TraceCircularBuffer) { TDebug.out("reading rest in closed buffer, length: " + nLength); }
126 }
127 else
128 {
129 if (TDebug.TraceCircularBuffer) { TDebug.out("< not open. returning -1."); }
130 return -1;
131 }
132 }
133 synchronized (this)
134 {
135 if (m_trigger != null && availableRead() < nLength)
136 {
137 if (TDebug.TraceCircularBuffer) { TDebug.out("executing trigger."); }
138 m_trigger.execute();
139 }
140 if (!m_bBlockingRead)
141 {
142 nLength = Math.min(availableRead(), nLength);
143 }
144 int nRemainingBytes = nLength;
145 while (nRemainingBytes > 0)
146 {
147 while (availableRead() == 0)
148 {
149 try
150 {
151 wait();
152 }
153 catch (InterruptedException e)
154 {
155 if (TDebug.TraceAllExceptions)
156 {
157 TDebug.out(e);
158 }
159 }
160 }
161 int nAvailable = Math.min(availableRead(), nRemainingBytes);
162 while (nAvailable > 0)
163 {
164 int nToRead = Math.min(nAvailable, m_nSize - getReadPos());
165 System.arraycopy(m_abData, getReadPos(), abData, nOffset, nToRead);
166 m_lReadPos += nToRead;
167 nOffset += nToRead;
168 nAvailable -= nToRead;
169 nRemainingBytes -= nToRead;
170 }
171 notifyAll();
172 }
173 if (TDebug.TraceCircularBuffer)
174 {
175 TDebug.out("After read:");
176 dumpInternalState();
177 TDebug.out("< completed. Read " + nLength + " bytes");
178 }
179 return nLength;
180 }
181 }
182
183
184 public int write(byte[] abData)
185 {
186 return write(abData, 0, abData.length);
187 }
188
189
190
191 public int write(byte[] abData, int nOffset, int nLength)
192 {
193 if (TDebug.TraceCircularBuffer)
194 {
195 TDebug.out(">TCircularBuffer.write(): called; nLength: " + nLength);
196 dumpInternalState();
197 }
198 synchronized (this)
199 {
200 if (TDebug.TraceCircularBuffer) { TDebug.out("entered synchronized block."); }
201 if (!m_bBlockingWrite)
202 {
203 nLength = Math.min(availableWrite(), nLength);
204 }
205 int nRemainingBytes = nLength;
206 while (nRemainingBytes > 0)
207 {
208 while (availableWrite() == 0)
209 {
210 try
211 {
212 wait();
213 }
214 catch (InterruptedException e)
215 {
216 if (TDebug.TraceAllExceptions)
217 {
218 TDebug.out(e);
219 }
220 }
221 }
222 int nAvailable = Math.min(availableWrite(), nRemainingBytes);
223 while (nAvailable > 0)
224 {
225 int nToWrite = Math.min(nAvailable, m_nSize - getWritePos());
226 //TDebug.out("src buf size= " + abData.length + ", offset = " + nOffset + ", dst buf size=" + m_abData.length + " write pos=" + getWritePos() + " len=" + nToWrite);
227 System.arraycopy(abData, nOffset, m_abData, getWritePos(), nToWrite);
228 m_lWritePos += nToWrite;
229 nOffset += nToWrite;
230 nAvailable -= nToWrite;
231 nRemainingBytes -= nToWrite;
232 }
233 notifyAll();
234 }
235 if (TDebug.TraceCircularBuffer)
236 {
237 TDebug.out("After write:");
238 dumpInternalState();
239 TDebug.out("< completed. Wrote "+nLength+" bytes");
240 }
241 return nLength;
242 }
243 }
244
245
246
247 private void dumpInternalState()
248 {
249 TDebug.out("m_lReadPos = " + m_lReadPos + " ^= "+getReadPos());
250 TDebug.out("m_lWritePos = " + m_lWritePos + " ^= "+getWritePos());
251 TDebug.out("availableRead() = " + availableRead());
252 TDebug.out("availableWrite() = " + availableWrite());
253 }
254
255
256
257 public static interface Trigger
258 {
259 public void execute();
260 }
261
262
263}
264
265
266
267/*** TCircularBuffer.java ***/
268
diff --git a/songdbj/org/tritonus/share/TDebug.java b/songdbj/org/tritonus/share/TDebug.java
new file mode 100644
index 0000000000..5969d91a72
--- /dev/null
+++ b/songdbj/org/tritonus/share/TDebug.java
@@ -0,0 +1,192 @@
1/*
2 * TDebug.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2002 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share;
30
31import java.io.PrintStream;
32import java.util.StringTokenizer;
33import java.security.AccessControlException;
34
35
36
37public class TDebug
38{
39 public static boolean SHOW_ACCESS_CONTROL_EXCEPTIONS = false;
40 private static final String PROPERTY_PREFIX = "tritonus.";
41 // The stream we output to
42 public static PrintStream m_printStream = System.out;
43
44 private static String indent="";
45
46 // meta-general
47 public static boolean TraceAllExceptions = getBooleanProperty("TraceAllExceptions");
48 public static boolean TraceAllWarnings = getBooleanProperty("TraceAllWarnings");
49
50 // general
51 public static boolean TraceInit = getBooleanProperty("TraceInit");
52 public static boolean TraceCircularBuffer = getBooleanProperty("TraceCircularBuffer");
53 public static boolean TraceService = getBooleanProperty("TraceService");
54
55 // sampled common implementation
56 public static boolean TraceAudioSystem = getBooleanProperty("TraceAudioSystem");
57 public static boolean TraceAudioConfig = getBooleanProperty("TraceAudioConfig");
58 public static boolean TraceAudioInputStream = getBooleanProperty("TraceAudioInputStream");
59 public static boolean TraceMixerProvider = getBooleanProperty("TraceMixerProvider");
60 public static boolean TraceControl = getBooleanProperty("TraceControl");
61 public static boolean TraceLine = getBooleanProperty("TraceLine");
62 public static boolean TraceDataLine = getBooleanProperty("TraceDataLine");
63 public static boolean TraceMixer = getBooleanProperty("TraceMixer");
64 public static boolean TraceSourceDataLine = getBooleanProperty("TraceSourceDataLine");
65 public static boolean TraceTargetDataLine = getBooleanProperty("TraceTargetDataLine");
66 public static boolean TraceClip = getBooleanProperty("TraceClip");
67 public static boolean TraceAudioFileReader = getBooleanProperty("TraceAudioFileReader");
68 public static boolean TraceAudioFileWriter = getBooleanProperty("TraceAudioFileWriter");
69 public static boolean TraceAudioConverter = getBooleanProperty("TraceAudioConverter");
70 public static boolean TraceAudioOutputStream = getBooleanProperty("TraceAudioOutputStream");
71
72 // sampled specific implementation
73 public static boolean TraceEsdNative = getBooleanProperty("TraceEsdNative");
74 public static boolean TraceEsdStreamNative = getBooleanProperty("TraceEsdStreamNative");
75 public static boolean TraceEsdRecordingStreamNative = getBooleanProperty("TraceEsdRecordingStreamNative");
76 public static boolean TraceAlsaNative = getBooleanProperty("TraceAlsaNative");
77 public static boolean TraceAlsaMixerNative = getBooleanProperty("TraceAlsaMixerNative");
78 public static boolean TraceAlsaPcmNative = getBooleanProperty("TraceAlsaPcmNative");
79 public static boolean TraceMixingAudioInputStream = getBooleanProperty("TraceMixingAudioInputStream");
80 public static boolean TraceOggNative = getBooleanProperty("TraceOggNative");
81 public static boolean TraceVorbisNative = getBooleanProperty("TraceVorbisNative");
82
83 // midi common implementation
84 public static boolean TraceMidiSystem = getBooleanProperty("TraceMidiSystem");
85 public static boolean TraceMidiConfig = getBooleanProperty("TraceMidiConfig");
86 public static boolean TraceMidiDeviceProvider = getBooleanProperty("TraceMidiDeviceProvider");
87 public static boolean TraceSequencer = getBooleanProperty("TraceSequencer");
88 public static boolean TraceMidiDevice = getBooleanProperty("TraceMidiDevice");
89
90 // midi specific implementation
91 public static boolean TraceAlsaSeq = getBooleanProperty("TraceAlsaSeq");
92 public static boolean TraceAlsaSeqDetails = getBooleanProperty("TraceAlsaSeqDetails");
93 public static boolean TraceAlsaSeqNative = getBooleanProperty("TraceAlsaSeqNative");
94 public static boolean TracePortScan = getBooleanProperty("TracePortScan");
95 public static boolean TraceAlsaMidiIn = getBooleanProperty("TraceAlsaMidiIn");
96 public static boolean TraceAlsaMidiOut = getBooleanProperty("TraceAlsaMidiOut");
97 public static boolean TraceAlsaMidiChannel = getBooleanProperty("TraceAlsaMidiChannel");
98
99 // misc
100 public static boolean TraceAlsaCtlNative = getBooleanProperty("TraceAlsaCtlNative");
101 public static boolean TraceCdda = getBooleanProperty("TraceCdda");
102 public static boolean TraceCddaNative = getBooleanProperty("TraceCddaNative");
103
104
105
106 // make this method configurable to write to file, write to stderr,...
107 public static void out(String strMessage)
108 {
109 if (strMessage.length()>0 && strMessage.charAt(0)=='<') {
110 if (indent.length()>2) {
111 indent=indent.substring(2);
112 } else {
113 indent="";
114 }
115 }
116 String newMsg=null;
117 if (indent!="" && strMessage.indexOf("\n")>=0) {
118 newMsg="";
119 StringTokenizer tokenizer=new StringTokenizer(strMessage, "\n");
120 while (tokenizer.hasMoreTokens()) {
121 newMsg+=indent+tokenizer.nextToken()+"\n";
122 }
123 } else {
124 newMsg=indent+strMessage;
125 }
126 m_printStream.println(newMsg);
127 if (strMessage.length()>0 && strMessage.charAt(0)=='>') {
128 indent+=" ";
129 }
130 }
131
132
133
134 public static void out(Throwable throwable)
135 {
136 throwable.printStackTrace(m_printStream);
137 }
138
139
140
141 public static void assertion(boolean bAssertion)
142 {
143 if (!bAssertion)
144 {
145 throw new AssertException();
146 }
147 }
148
149
150 public static class AssertException
151 extends RuntimeException
152 {
153 public AssertException()
154 {
155 }
156
157
158
159 public AssertException(String sMessage)
160 {
161 super(sMessage);
162 }
163 }
164
165
166
167 private static boolean getBooleanProperty(String strName)
168 {
169 String strPropertyName = PROPERTY_PREFIX + strName;
170 String strValue = "false";
171 try
172 {
173 strValue = System.getProperty(strPropertyName, "false");
174 }
175 catch (AccessControlException e)
176 {
177 if (SHOW_ACCESS_CONTROL_EXCEPTIONS)
178 {
179 out(e);
180 }
181 }
182 // TDebug.out("property: " + strPropertyName + "=" + strValue);
183 boolean bValue = strValue.toLowerCase().equals("true");
184 // TDebug.out("bValue: " + bValue);
185 return bValue;
186 }
187}
188
189
190
191/*** TDebug.java ***/
192
diff --git a/songdbj/org/tritonus/share/TNotifier.java b/songdbj/org/tritonus/share/TNotifier.java
new file mode 100644
index 0000000000..822b30c305
--- /dev/null
+++ b/songdbj/org/tritonus/share/TNotifier.java
@@ -0,0 +1,140 @@
1/*
2 * TNotifier.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.util.EventObject;
34import java.util.Collection;
35import java.util.ArrayList;
36import java.util.List;
37import java.util.Iterator;
38
39import javax.sound.sampled.LineListener;
40import javax.sound.sampled.LineEvent;
41
42
43
44public class TNotifier
45extends Thread
46{
47 public static class NotifyEntry
48 {
49 private EventObject m_event;
50 private List<LineListener> m_listeners;
51
52
53
54 public NotifyEntry(EventObject event, Collection<LineListener> listeners)
55 {
56 m_event = event;
57 m_listeners = new ArrayList<LineListener>(listeners);
58 }
59
60
61 public void deliver()
62 {
63 // TDebug.out("%% TNotifier.NotifyEntry.deliver(): called.");
64 Iterator<LineListener> iterator = m_listeners.iterator();
65 while (iterator.hasNext())
66 {
67 LineListener listener = iterator.next();
68 listener.update((LineEvent) m_event);
69 }
70 }
71 }
72
73
74 public static TNotifier notifier = null;
75
76 static
77 {
78 notifier = new TNotifier();
79 notifier.setDaemon(true);
80 notifier.start();
81 }
82
83
84
85 /** The queue of events to deliver.
86 * The entries are of class NotifyEntry.
87 */
88 private List<NotifyEntry> m_entries;
89
90
91 public TNotifier()
92 {
93 super("Tritonus Notifier");
94 m_entries = new ArrayList<NotifyEntry>();
95 }
96
97
98
99 public void addEntry(EventObject event, Collection<LineListener> listeners)
100 {
101 // TDebug.out("%% TNotifier.addEntry(): called.");
102 synchronized (m_entries)
103 {
104 m_entries.add(new NotifyEntry(event, listeners));
105 m_entries.notifyAll();
106 }
107 // TDebug.out("%% TNotifier.addEntry(): completed.");
108 }
109
110
111 public void run()
112 {
113 while (true)
114 {
115 NotifyEntry entry = null;
116 synchronized (m_entries)
117 {
118 while (m_entries.size() == 0)
119 {
120 try
121 {
122 m_entries.wait();
123 }
124 catch (InterruptedException e)
125 {
126 if (TDebug.TraceAllExceptions)
127 {
128 TDebug.out(e);
129 }
130 }
131 }
132 entry = m_entries.remove(0);
133 }
134 entry.deliver();
135 }
136 }
137}
138
139
140/*** TNotifier.java ***/
diff --git a/songdbj/org/tritonus/share/TSettings.java b/songdbj/org/tritonus/share/TSettings.java
new file mode 100644
index 0000000000..ae1a315e0e
--- /dev/null
+++ b/songdbj/org/tritonus/share/TSettings.java
@@ -0,0 +1,75 @@
1/*
2 * TSettings.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.io.PrintStream;
34import java.util.StringTokenizer;
35import java.security.AccessControlException;
36
37import org.tritonus.share.TDebug;
38
39
40public class TSettings
41{
42 public static boolean SHOW_ACCESS_CONTROL_EXCEPTIONS = false;
43 private static final String PROPERTY_PREFIX = "tritonus.";
44
45
46 public static boolean AlsaUsePlughw = getBooleanProperty("AlsaUsePlughw");
47
48
49
50 private static boolean getBooleanProperty(String strName)
51 {
52 String strPropertyName = PROPERTY_PREFIX + strName;
53 String strValue = "false";
54 try
55 {
56 strValue = System.getProperty(strPropertyName, "false");
57 }
58 catch (AccessControlException e)
59 {
60 if (SHOW_ACCESS_CONTROL_EXCEPTIONS)
61 {
62 TDebug.out(e);
63 }
64 }
65 // TDebug.out("property: " + strPropertyName + "=" + strValue);
66 boolean bValue = strValue.toLowerCase().equals("true");
67 // TDebug.out("bValue: " + bValue);
68 return bValue;
69 }
70}
71
72
73
74/*** TSettings.java ***/
75
diff --git a/songdbj/org/tritonus/share/package.html b/songdbj/org/tritonus/share/package.html
new file mode 100644
index 0000000000..200904dc60
--- /dev/null
+++ b/songdbj/org/tritonus/share/package.html
@@ -0,0 +1,10 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Misc helper classes.
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/share/sampled/AudioFileTypes.java b/songdbj/org/tritonus/share/sampled/AudioFileTypes.java
new file mode 100644
index 0000000000..45e4a0ffbc
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/AudioFileTypes.java
@@ -0,0 +1,155 @@
1/*
2 * AudioFileTypes.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27
28package org.tritonus.share.sampled;
29
30import javax.sound.sampled.AudioFileFormat;
31import org.tritonus.share.StringHashedSet;
32import org.tritonus.share.TDebug;
33
34/**
35 * This class is a proposal for generic handling of audio file format types.
36 * The main purpose is to provide a standardized way of
37 * implementing audio file format types. Like this, file types
38 * are only identified by their String name, and not, as currently,
39 * by their object instance.
40 * <p>
41 * A standard registry of file type names will
42 * be maintained by the Tritonus team.
43 * <p>
44 * In a specification request to JavaSoft, these static methods
45 * could be integrated into<code>AudioFileFormat.Type</code>. The static
46 * instances of AIFF, AIFC, AU, SND, and WAVE types in class
47 * <code>AudioFileFormat.Type</code> should be retrieved
48 * using this method, too (internally).<br>
49 * At best, the protected constructor of that class
50 * should also be replaced to be a private constructor.
51 * Like this it will be prevented that developers create
52 * instances of Type, which causes problems with the
53 * equals method. In fact, the equals method should be redefined anyway
54 * so that it compares the names and not the objects.
55 * <p>
56 * Also, the file name extension should be deprecated and moved
57 * to <code>AudioFileFormat</code>. There are some file formats
58 * which have varying extensions depending, e.g. on the encoding.
59 * An example for this is MPEG: the special encoding Mpeg 1, layer 3
60 * has the extension mp3, whereas other Mpeg files use mpeg or mpg.<br>
61 * This could be implemented with 2 methods in <code>AudioFileFormat</code>:
62 * <ol><li>String[] getFileExtensions(): returns all usable extensions
63 * for this file.
64 * <li>String getDefaultFileExtension(): returns the preferred extension.
65 * </ol>
66 *
67 * @author Florian Bomers
68 */
69public class AudioFileTypes extends AudioFileFormat.Type {
70
71 /** contains all known types */
72 private static StringHashedSet types = new StringHashedSet();
73
74 // initially add the standard types
75 static {
76 types.add(AudioFileFormat.Type.AIFF);
77 types.add(AudioFileFormat.Type.AIFC);
78 types.add(AudioFileFormat.Type.AU);
79 types.add(AudioFileFormat.Type.SND);
80 types.add(AudioFileFormat.Type.WAVE);
81 }
82
83 AudioFileTypes(String name, String ext) {
84 super(name, ext);
85 }
86
87 /**
88 * Use this method to retrieve an instance of
89 * <code>AudioFileFormat.Type</code> of the specified
90 * name. If no type of this name is in the internally
91 * maintained list, <code>null</code> is returned.
92 * <p>
93 * This method is supposed to be used by user programs.
94 * <p>
95 * In order to assure a well-filled internal list,
96 * call <code>AudioSystem.getAudioFileTypes()</code>
97 * at initialization time.
98 *
99 * @see #getType(String, String)
100 */
101 public static AudioFileFormat.Type getType(String name) {
102 return getType(name, null);
103 }
104
105 /**
106 * Use this method to retrieve an instance of
107 * <code>AudioFileFormat.Type</code> of the specified
108 * name. If it does not exist in the internal list
109 * of types, a new type is created and returned.
110 * If it a type of that name already exists (regardless
111 * of extension), it is returned. In this case it can
112 * not be guaranteed that the extension is the same as
113 * passed as parameter.<br>
114 * If <code>extension</code> is <code>null</code>,
115 * this method returns <code>null</code> if the
116 * type of the specified name does not exist in the
117 * internal list.
118 * <p>
119 * This method is supposed to be used by file providers.
120 * Every file reader and file writer provider should
121 * exclusively use this method for retrieving instances
122 * of <code>AudioFileFormat.Type</code>.
123 */
124 public static AudioFileFormat.Type getType(String name, String extension) {
125 AudioFileFormat.Type res=(AudioFileFormat.Type) types.get(name);
126 if (res==null) {
127 // it is not already in the string set.
128 if (extension==null) {
129 return null;
130 }
131 // Create a new type instance.
132 res=new AudioFileTypes(name, extension);
133 // and save it for the future
134 types.add(res);
135 }
136 return res;
137 }
138
139 /**
140 * Tests for equality of 2 file types. They are equal when their names match.
141 * <p>
142 * This function should be AudioFileFormat.Type.equals and must
143 * be considered as a temporary workaround until it flows into the
144 * JavaSound API.
145 */
146 // IDEA: create a special "NOT_SPECIFIED" file type
147 // and a AudioFileFormat.Type.matches method.
148 public static boolean equals(AudioFileFormat.Type t1, AudioFileFormat.Type t2) {
149 return t2.toString().equals(t1.toString());
150 }
151
152}
153
154/*** AudioFileTypes.java ***/
155
diff --git a/songdbj/org/tritonus/share/sampled/AudioFormatSet.java b/songdbj/org/tritonus/share/sampled/AudioFormatSet.java
new file mode 100644
index 0000000000..8d89541d77
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/AudioFormatSet.java
@@ -0,0 +1,155 @@
1/*
2 * AudioFormatSet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Iterator;
36
37import javax.sound.sampled.AudioFormat;
38
39import org.tritonus.share.ArraySet;
40import org.tritonus.share.sampled.AudioFormats;
41
42
43/**
44 * A set where the elements are uniquely referenced by
45 * AudioFormats.equals rather than their object reference.
46 * No 2 equal AudioFormats can exist in the set.
47 * <p>
48 * This class provide convenience methods like
49 * <code>getAudioFormat(AudioFormat)</code> and
50 * <code>matches(AudioFormat)</code>.
51 * <p>
52 * The <code>contains(Object elem)</code> and <code>get(Object elem)</code>
53 * fail, if elem is not an instance of AudioFormat.
54 * <p>
55 * You shouldn't use the ArrayList specific functions
56 * like those that take index parameters.
57 * <p>
58 * It is not possible to add <code>null</code> elements.
59 * <p>
60 * Currently, the methods equals(.,.) and matches(.,.) of
61 * class AudioFormats are used. Let's hope that they will
62 * be integrated into AudioFormat.
63 */
64
65public class AudioFormatSet extends ArraySet<AudioFormat>
66{
67 protected static final AudioFormat[] EMPTY_FORMAT_ARRAY = new AudioFormat[0];
68
69 public AudioFormatSet() {
70 super();
71 }
72
73 public AudioFormatSet(Collection<AudioFormat> c) {
74 super(c);
75 }
76
77 public boolean add(AudioFormat elem) {
78 if (elem==null || !(elem instanceof AudioFormat)) {
79 return false;
80 }
81 return super.add(elem);
82 }
83
84 public boolean contains(AudioFormat elem) {
85 if (elem==null || !(elem instanceof AudioFormat)) {
86 return false;
87 }
88 AudioFormat comp=(AudioFormat) elem;
89 Iterator it=iterator();
90 while (it.hasNext()) {
91 if (AudioFormats.equals(comp, (AudioFormat) it.next())) {
92 return true;
93 }
94 }
95 return false;
96 }
97
98 public AudioFormat get(AudioFormat elem) {
99 if (elem==null || !(elem instanceof AudioFormat)) {
100 return null;
101 }
102 AudioFormat comp=(AudioFormat) elem;
103 Iterator it=iterator();
104 while (it.hasNext()) {
105 AudioFormat thisElem=(AudioFormat) it.next();
106 if (AudioFormats.equals(comp, thisElem)) {
107 return thisElem;
108 }
109 }
110 return null;
111 }
112
113 public AudioFormat getAudioFormat(AudioFormat elem) {
114 return (AudioFormat) get(elem);
115 }
116
117 /**
118 * Checks whether this Set contains an AudioFormat
119 * that matches <code>elem</code>.
120 * The first matching format is returned. If no element
121 * matches <code>elem</code>, <code>null</code> is returned.
122 * <p>
123 * @see AudioFormats#matches(AudioFormat, AudioFormat)
124 */
125 public AudioFormat matches(AudioFormat elem) {
126 if (elem==null) {
127 return null;
128 }
129 Iterator it=iterator();
130 while (it.hasNext()) {
131 AudioFormat thisElem=(AudioFormat) it.next();
132 if (AudioFormats.matches(elem, thisElem)) {
133 return thisElem;
134 }
135 }
136 return null;
137 }
138
139
140 // $$mp: TODO: remove; should be obsolete
141 public AudioFormat[] toAudioFormatArray() {
142 return (AudioFormat[]) toArray(EMPTY_FORMAT_ARRAY);
143 }
144
145
146 public void add(int index, AudioFormat element) {
147 throw new UnsupportedOperationException("unsupported");
148 }
149
150 public AudioFormat set(int index, AudioFormat element) {
151 throw new UnsupportedOperationException("unsupported");
152 }
153}
154
155/*** AudioFormatSet.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/AudioFormats.java b/songdbj/org/tritonus/share/sampled/AudioFormats.java
new file mode 100644
index 0000000000..41ac3f37c7
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/AudioFormats.java
@@ -0,0 +1,131 @@
1/*
2 * AudioFormats.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Matthias Pfisterer
9 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled;
33
34import javax.sound.sampled.AudioFormat;
35import javax.sound.sampled.AudioSystem;
36
37
38
39public class AudioFormats
40{
41 private static boolean doMatch(int i1, int i2)
42 {
43 return i1 == AudioSystem.NOT_SPECIFIED
44 || i2 == AudioSystem.NOT_SPECIFIED
45 || i1 == i2;
46 }
47
48
49
50 private static boolean doMatch(float f1, float f2)
51 {
52 return f1 == AudioSystem.NOT_SPECIFIED
53 || f2 == AudioSystem.NOT_SPECIFIED
54 || Math.abs(f1 - f2) < 1.0e-9;
55 }
56
57
58
59 /**
60 * Tests whether 2 AudioFormats have matching formats.
61 * A field matches when it is AudioSystem.NOT_SPECIFIED in
62 * at least one of the formats or the field is the same
63 * in both formats.<br>
64 * Exceptions:
65 * <ul>
66 * <li>Encoding must always be equal for a match.
67 * <li> For a match, endianness must be equal if SampleSizeInBits is not
68 * AudioSystem.NOT_SPECIFIED and greater than 8bit in both formats.<br>
69 * In other words: If SampleSizeInBits is AudioSystem.NOT_SPECIFIED
70 * in either format or both formats have a SampleSizeInBits<8,
71 * endianness does not matter.
72 * </ul>
73 * This is a proposition to be used as AudioFormat.matches.
74 * It can therefore be considered as a temporary workaround.
75 */
76 // IDEA: create a special "NOT_SPECIFIED" encoding
77 // and a AudioFormat.Encoding.matches method.
78 public static boolean matches(AudioFormat format1,
79 AudioFormat format2)
80 {
81 //$$fb 19 Dec 99: endian must be checked, too.
82 //
83 // we do have a problem with redundant elements:
84 // e.g.
85 // encoding=ALAW || ULAW -> bigEndian and samplesizeinbits don't matter
86 // sample size in bits == 8 -> bigEndian doesn't matter
87 // sample size in bits > 8 -> PCM is always signed.
88 // This is an overall issue in JavaSound, I think.
89 // At present, it is not consistently implemented to support these
90 // redundancies and implicit definitions
91 //
92 // As a workaround of this issue I return in the converters
93 // all combinations, e.g. for ULAW I return bigEndian and !bigEndian formats.
94/* old version
95*/
96 // as proposed by florian
97 return format1.getEncoding().equals(format2.getEncoding())
98 && (format2.getSampleSizeInBits()<=8
99 || format1.getSampleSizeInBits()==AudioSystem.NOT_SPECIFIED
100 || format2.getSampleSizeInBits()==AudioSystem.NOT_SPECIFIED
101 || format1.isBigEndian()==format2.isBigEndian())
102 && doMatch(format1.getChannels(),format2.getChannels())
103 && doMatch(format1.getSampleSizeInBits(), format2.getSampleSizeInBits())
104 && doMatch(format1.getFrameSize(), format2.getFrameSize())
105 && doMatch(format1.getSampleRate(), format2.getSampleRate())
106 && doMatch(format1.getFrameRate(),format2.getFrameRate());
107 }
108
109 /**
110 * Tests for exact equality of 2 AudioFormats.
111 * This is the behaviour of AudioFormat.matches in JavaSound 1.0.
112 * <p>
113 * This is a proposition to be used as AudioFormat.equals.
114 * It can therefore be considered as a temporary workaround.
115 */
116 public static boolean equals(AudioFormat format1,
117 AudioFormat format2)
118 {
119 return format1.getEncoding().equals(format2.getEncoding())
120 && format1.getChannels() == format2.getChannels()
121 && format1.getSampleSizeInBits() == format2.getSampleSizeInBits()
122 && format1.getFrameSize() == format2.getFrameSize()
123 && (Math.abs(format1.getSampleRate() - format2.getSampleRate()) < 1.0e-9)
124 && (Math.abs(format1.getFrameRate() - format2.getFrameRate()) < 1.0e-9);
125 }
126
127}
128
129
130
131/*** AudioFormats.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/AudioSystemShadow.java b/songdbj/org/tritonus/share/sampled/AudioSystemShadow.java
new file mode 100644
index 0000000000..70b4e9ebd7
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/AudioSystemShadow.java
@@ -0,0 +1,115 @@
1/*
2 * AudioSystemShadow.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled;
32
33import java.io.File;
34import java.io.OutputStream;
35import java.io.IOException;
36
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioFormat;
39
40import org.tritonus.share.sampled.file.AudioOutputStream;
41import org.tritonus.share.sampled.file.TDataOutputStream;
42import org.tritonus.share.sampled.file.TSeekableDataOutputStream;
43import org.tritonus.share.sampled.file.TNonSeekableDataOutputStream;
44import org.tritonus.sampled.file.AiffAudioOutputStream;
45import org.tritonus.sampled.file.AuAudioOutputStream;
46import org.tritonus.sampled.file.WaveAudioOutputStream;
47
48
49
50/** Experminatal area for AudioSystem.
51 * This class is used to host features that may become part of the
52 * Java Sound API (In which case they will be moved to AudioSystem).
53 */
54public class AudioSystemShadow
55{
56 public static TDataOutputStream getDataOutputStream(File file)
57 throws IOException
58 {
59 return new TSeekableDataOutputStream(file);
60 }
61
62
63
64 public static TDataOutputStream getDataOutputStream(OutputStream stream)
65 throws IOException
66 {
67 return new TNonSeekableDataOutputStream(stream);
68 }
69
70
71
72 // TODO: lLengthInBytes actually should be lLengthInFrames (design problem of A.O.S.)
73 public static AudioOutputStream getAudioOutputStream(AudioFileFormat.Type type, AudioFormat audioFormat, long lLengthInBytes, TDataOutputStream dataOutputStream)
74 {
75 AudioOutputStream audioOutputStream = null;
76
77 if (type.equals(AudioFileFormat.Type.AIFF) ||
78 type.equals(AudioFileFormat.Type.AIFF))
79 {
80 audioOutputStream = new AiffAudioOutputStream(audioFormat, type, lLengthInBytes, dataOutputStream);
81 }
82 else if (type.equals(AudioFileFormat.Type.AU))
83 {
84 audioOutputStream = new AuAudioOutputStream(audioFormat, lLengthInBytes, dataOutputStream);
85 }
86 else if (type.equals(AudioFileFormat.Type.WAVE))
87 {
88 audioOutputStream = new WaveAudioOutputStream(audioFormat, lLengthInBytes, dataOutputStream);
89 }
90 return audioOutputStream;
91 }
92
93
94
95 public static AudioOutputStream getAudioOutputStream(AudioFileFormat.Type type, AudioFormat audioFormat, long lLengthInBytes, File file)
96 throws IOException
97 {
98 TDataOutputStream dataOutputStream = getDataOutputStream(file);
99 AudioOutputStream audioOutputStream = getAudioOutputStream(type, audioFormat, lLengthInBytes, dataOutputStream);
100 return audioOutputStream;
101 }
102
103
104
105 public static AudioOutputStream getAudioOutputStream(AudioFileFormat.Type type, AudioFormat audioFormat, long lLengthInBytes, OutputStream outputStream)
106 throws IOException
107 {
108 TDataOutputStream dataOutputStream = getDataOutputStream(outputStream);
109 AudioOutputStream audioOutputStream = getAudioOutputStream(type, audioFormat, lLengthInBytes, dataOutputStream);
110 return audioOutputStream;
111 }
112}
113
114
115/*** AudioSystemShadow.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/AudioUtils.java b/songdbj/org/tritonus/share/sampled/AudioUtils.java
new file mode 100644
index 0000000000..21c838b032
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/AudioUtils.java
@@ -0,0 +1,181 @@
1/*
2 * AudioUtils.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled;
31
32import java.io.File;
33import java.io.FileOutputStream;
34import java.io.InputStream;
35import java.io.IOException;
36import java.io.OutputStream;
37import java.util.Collection;
38import java.util.Iterator;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.AudioFormat;
42import javax.sound.sampled.AudioFileFormat;
43import javax.sound.sampled.AudioInputStream;
44import javax.sound.sampled.spi.AudioFileWriter;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.TConversionTool;
48
49
50
51public class AudioUtils
52{
53 public static long getLengthInBytes(AudioInputStream audioInputStream)
54 {
55 return getLengthInBytes(audioInputStream.getFormat(),
56 audioInputStream.getFrameLength());
57/*
58 long lLengthInFrames = audioInputStream.getFrameLength();
59 int nFrameSize = audioInputStream.getFormat().getFrameSize();
60 if (lLengthInFrames >= 0 && nFrameSize >= 1)
61 {
62 return lLengthInFrames * nFrameSize;
63 }
64 else
65 {
66 return AudioSystem.NOT_SPECIFIED;
67 }
68*/
69 }
70
71
72
73 /**
74 * if the passed value for lLength is
75 * AudioSystem.NOT_SPECIFIED (unknown
76 * length), the length in bytes becomes
77 * AudioSystem.NOT_SPECIFIED, too.
78 */
79 public static long getLengthInBytes(AudioFormat audioFormat,
80 long lLengthInFrames)
81 {
82 int nFrameSize = audioFormat.getFrameSize();
83 if (lLengthInFrames >= 0 && nFrameSize >= 1)
84 {
85 return lLengthInFrames * nFrameSize;
86 }
87 else
88 {
89 return AudioSystem.NOT_SPECIFIED;
90 }
91 }
92
93
94
95 public static boolean containsFormat(AudioFormat sourceFormat,
96 Iterator possibleFormats)
97 {
98 while (possibleFormats.hasNext())
99 {
100 AudioFormat format = (AudioFormat) possibleFormats.next();
101 if (AudioFormats.matches(format, sourceFormat))
102 {
103 return true;
104 }
105 }
106 return false;
107 }
108
109 /**
110 * Conversion milliseconds -> bytes
111 */
112
113 public static long millis2Bytes(long ms, AudioFormat format) {
114 return millis2Bytes(ms, format.getFrameRate(), format.getFrameSize());
115 }
116
117 public static long millis2Bytes(long ms, float frameRate, int frameSize) {
118 return (long) (ms*frameRate/1000*frameSize);
119 }
120
121 /**
122 * Conversion milliseconds -> bytes (bytes will be frame-aligned)
123 */
124 public static long millis2BytesFrameAligned(long ms, AudioFormat format) {
125 return millis2BytesFrameAligned(ms, format.getFrameRate(), format.getFrameSize());
126 }
127
128 public static long millis2BytesFrameAligned(long ms, float frameRate, int frameSize) {
129 return ((long) (ms*frameRate/1000))*frameSize;
130 }
131
132 /**
133 * Conversion milliseconds -> frames
134 */
135 public static long millis2Frames(long ms, AudioFormat format) {
136 return millis2Frames(ms, format.getFrameRate());
137 }
138
139 public static long millis2Frames(long ms, float frameRate) {
140 return (long) (ms*frameRate/1000);
141 }
142
143 /**
144 * Conversion bytes -> milliseconds
145 */
146 public static long bytes2Millis(long bytes, AudioFormat format) {
147 return (long) (bytes/format.getFrameRate()*1000/format.getFrameSize());
148 }
149
150 /**
151 * Conversion frames -> milliseconds
152 */
153 public static long frames2Millis(long frames, AudioFormat format) {
154 return (long) (frames/format.getFrameRate()*1000);
155 }
156
157
158 //$$fb 2000-07-18: added these debugging functions
159 public static String NS_or_number(int number) {
160 return (number==AudioSystem.NOT_SPECIFIED)?"NOT_SPECIFIED":String.valueOf(number);
161 }
162 public static String NS_or_number(float number) {
163 return (number==AudioSystem.NOT_SPECIFIED)?"NOT_SPECIFIED":String.valueOf(number);
164 }
165
166 /**
167 * For debugging purposes.
168 */
169 public static String format2ShortStr(AudioFormat format) {
170 return format.getEncoding() + "-" +
171 NS_or_number(format.getChannels()) + "ch-" +
172 NS_or_number(format.getSampleSizeInBits()) + "bit-" +
173 NS_or_number(((int)format.getSampleRate())) + "Hz-"+
174 (format.isBigEndian() ? "be" : "le");
175 }
176
177}
178
179
180
181/*** AudioUtils.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/Encodings.java b/songdbj/org/tritonus/share/sampled/Encodings.java
new file mode 100644
index 0000000000..6b880d24d9
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/Encodings.java
@@ -0,0 +1,183 @@
1/*
2 * Encodings.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27
28package org.tritonus.share.sampled;
29
30import java.util.Iterator;
31import javax.sound.sampled.AudioSystem;
32import javax.sound.sampled.AudioFormat;
33import org.tritonus.share.StringHashedSet;
34import org.tritonus.share.TDebug;
35
36/**
37 * This class is a proposal for generic handling of encodings.
38 * The main purpose is to provide a standardized way of
39 * implementing encoding types. Like this, encodings
40 * are only identified by their String name, and not, as currently,
41 * by their object instance.
42 * <p>
43 * A registry of standard encoding names will
44 * be maintained by the Tritonus team.
45 * <p>
46 * In a specification request to JavaSoft, the static method
47 * <code>getEncoding</code> should be integrated into
48 * <code>AudioFormat.Encoding(String name)</code> (possibly
49 * renamed to <code>getInstance(String name)</code>.<br>
50 * The static instances of ULAW, ALAW PCM_UNSIGNED and PCM_SIGNED
51 * encodings in that class should be retrieved using that function,
52 * too (internally).<br>
53 * At best, the protected constructor of that class
54 * should also be replaced to be a private constructor.
55 * Like this it will be prevented that developers create their own
56 * instances of Encoding, which causes problems with the
57 * equals method. In fact, the equals method should be redefined anyway
58 * so that it compares the names and not the objects.
59 * <p>
60 * Also, a specification request should be made to integrate
61 * <code>getEncodings()</code> into AudioSystem (this is
62 * especially annoying as the relevant methods already exist
63 * in the provider interfaces of file readers, file writers and
64 * converters).
65 *
66 * @author Florian Bomers
67 */
68public class Encodings extends AudioFormat.Encoding {
69
70 /** contains all known encodings */
71 private static StringHashedSet encodings = new StringHashedSet();
72
73 // initially add the standard encodings
74 static {
75 encodings.add(AudioFormat.Encoding.PCM_SIGNED);
76 encodings.add(AudioFormat.Encoding.PCM_UNSIGNED);
77 encodings.add(AudioFormat.Encoding.ULAW);
78 encodings.add(AudioFormat.Encoding.ALAW);
79 }
80
81 Encodings(String name) {
82 super(name);
83 }
84
85 /**
86 * Use this method for retrieving an instance of
87 * <code>AudioFormat.Encoding</code> of the specified
88 * name. A standard registry of encoding names will
89 * be maintained by the Tritonus team.
90 * <p>
91 * Every file reader, file writer, and format converter
92 * provider should exclusively use this method for
93 * retrieving instances of <code>AudioFormat.Encoding</code>.
94 */
95 /*
96 MP2000/09/11:
97 perhaps it is not a good idea to allow user programs the creation of new
98 encodings. The problem with it is that a plain typo will produce an encoding
99 object that is not supported. Instead, some indication of an error should be
100 signaled to the user program. And, there should be a second interface for
101 service providers allowing them to register encodings supported by themselves.
102
103 $$fb2000/09/26:
104 The problem is what you see as second issue: it can never be assured
105 that this class knows all available encodings. So at the moment, there
106 is no choice than to allow users to create any Encoding they wish.
107 The encodings database will simplify things.
108 A problem with an interface to retrieve supported encodings (or API
109 function in spi.FormatConversionProvider) is that this requires
110 loading of all providers very early. Hmmm, maybe this is necessary in any
111 case when the user issues something like AudioSystem.isConversionSupported.
112 */
113 public static AudioFormat.Encoding getEncoding(String name) {
114 AudioFormat.Encoding res=(AudioFormat.Encoding) encodings.get(name);
115 if (res==null) {
116 // it is not already in the string set. Create a new encoding instance.
117 res=new Encodings(name);
118 // and save it for the future
119 encodings.add(res);
120 }
121 return res;
122 }
123
124 /**
125 * Tests for equality of 2 encodings. They are equal when their strings match.
126 * <p>
127 * This function should be AudioFormat.Encoding.equals and must
128 * be considered as a temporary work around until it flows into the
129 * JavaSound API.
130 */
131 // IDEA: create a special "NOT_SPECIFIED" encoding
132 // and a AudioFormat.Encoding.matches method.
133 public static boolean equals(AudioFormat.Encoding e1, AudioFormat.Encoding e2) {
134 return e2.toString().equals(e1.toString());
135 }
136
137
138 /**
139 * Returns all &quot;supported&quot; encodings.
140 * Supported means that it is possible to read or
141 * write files with this encoding, or that a converter
142 * accepts this encoding as source or target format.
143 * <p>
144 * Currently, this method returns a best guess and
145 * the search algorithm is far from complete: with standard
146 * methods of AudioSystem, only the target encodings
147 * of the converters can be retrieved - neither
148 * the source encodings of converters nor the encodings
149 * of file readers and file writers cannot be retrieved.
150 */
151 public static AudioFormat.Encoding[] getEncodings() {
152 StringHashedSet iteratedSources=new StringHashedSet();
153 StringHashedSet retrievedTargets=new StringHashedSet();
154 Iterator sourceFormats=encodings.iterator();
155 while (sourceFormats.hasNext()) {
156 AudioFormat.Encoding source=(AudioFormat.Encoding) sourceFormats.next();
157 iterateEncodings(source, iteratedSources, retrievedTargets);
158 }
159 return (AudioFormat.Encoding[]) retrievedTargets.toArray(
160 new AudioFormat.Encoding[retrievedTargets.size()]);
161 }
162
163
164 private static void iterateEncodings(AudioFormat.Encoding source,
165 StringHashedSet iteratedSources,
166 StringHashedSet retrievedTargets) {
167 if (!iteratedSources.contains(source)) {
168 iteratedSources.add(source);
169 AudioFormat.Encoding[] targets=AudioSystem.getTargetEncodings(source);
170 for (int i=0; i<targets.length; i++) {
171 AudioFormat.Encoding target=targets[i];
172 if (retrievedTargets.add(target.toString())) {
173 iterateEncodings(target, iteratedSources,retrievedTargets);
174 }
175 }
176 }
177 }
178}
179
180
181
182/*** Encodings.java ***/
183
diff --git a/songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java b/songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java
new file mode 100644
index 0000000000..d1fe534613
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java
@@ -0,0 +1,734 @@
1/*
2 * FloatSampleBuffer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2004 by Florian Bomers <http://www.bomers.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31import java.util.ArrayList;
32import java.util.Iterator;
33import java.util.Random;
34
35import javax.sound.sampled.AudioSystem;
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioInputStream;
39import javax.sound.sampled.spi.AudioFileWriter;
40
41import org.tritonus.share.TDebug;
42
43/**
44 * A class for small buffers of samples in linear, 32-bit
45 * floating point format.
46 * <p>
47 * It is supposed to be a replacement of the byte[] stream
48 * architecture of JavaSound, especially for chains of
49 * AudioInputStreams. Ideally, all involved AudioInputStreams
50 * handle reading into a FloatSampleBuffer.
51 * <p>
52 * Specifications:
53 * <ol>
54 * <li>Channels are separated, i.e. for stereo there are 2 float arrays
55 * with the samples for the left and right channel
56 * <li>All data is handled in samples, where one sample means
57 * one float value in each channel
58 * <li>All samples are normalized to the interval [-1.0...1.0]
59 * </ol>
60 * <p>
61 * When a cascade of AudioInputStreams use FloatSampleBuffer for
62 * processing, they may implement the interface FloatSampleInput.
63 * This signals that this stream may provide float buffers
64 * for reading. The data is <i>not</i> converted back to bytes,
65 * but stays in a single buffer that is passed from stream to stream.
66 * For that serves the read(FloatSampleBuffer) method, which is
67 * then used as replacement for the byte-based read functions of
68 * AudioInputStream.<br>
69 * However, backwards compatibility must always be retained, so
70 * even when an AudioInputStream implements FloatSampleInput,
71 * it must work the same way when any of the byte-based read methods
72 * is called.<br>
73 * As an example, consider the following set-up:<br>
74 * <ul>
75 * <li>auAIS is an AudioInputStream (AIS) that reads from an AU file
76 * in 8bit pcm at 8000Hz. It does not implement FloatSampleInput.
77 * <li>pcmAIS1 is an AIS that reads from auAIS and converts the data
78 * to PCM 16bit. This stream implements FloatSampleInput, i.e. it
79 * can generate float audio data from the ulaw samples.
80 * <li>pcmAIS2 reads from pcmAIS1 and adds a reverb.
81 * It operates entirely on floating point samples.
82 * <li>The method that reads from pcmAIS2 (i.e. AudioSystem.write) does
83 * not handle floating point samples.
84 * </ul>
85 * So, what happens when a block of samples is read from pcmAIS2 ?
86 * <ol>
87 * <li>the read(byte[]) method of pcmAIS2 is called
88 * <li>pcmAIS2 always operates on floating point samples, so
89 * it uses an own instance of FloatSampleBuffer and initializes
90 * it with the number of samples requested in the read(byte[])
91 * method.
92 * <li>It queries pcmAIS1 for the FloatSampleInput interface. As it
93 * implements it, pcmAIS2 calls the read(FloatSampleBuffer) method
94 * of pcmAIS1.
95 * <li>pcmAIS1 notes that its underlying stream does not support floats,
96 * so it instantiates a byte buffer which can hold the number of
97 * samples of the FloatSampleBuffer passed to it. It calls the
98 * read(byte[]) method of auAIS.
99 * <li>auAIS fills the buffer with the bytes.
100 * <li>pcmAIS1 calls the <code>initFromByteArray</code> method of
101 * the float buffer to initialize it with the 8 bit data.
102 * <li>Then pcmAIS1 processes the data: as the float buffer is
103 * normalized, it does nothing with the buffer - and returns
104 * control to pcmAIS2. The SampleSizeInBits field of the
105 * AudioFormat of pcmAIS1 defines that it should be 16 bits.
106 * <li>pcmAIS2 receives the filled buffer from pcmAIS1 and does
107 * its processing on the buffer - it adds the reverb.
108 * <li>As pcmAIS2's read(byte[]) method had been called, pcmAIS2
109 * calls the <code>convertToByteArray</code> method of
110 * the float buffer to fill the byte buffer with the
111 * resulting samples.
112 * </ol>
113 * <p>
114 * To summarize, here are some advantages when using a FloatSampleBuffer
115 * for streaming:
116 * <ul>
117 * <li>no conversions from/to bytes need to be done during processing
118 * <li>the sample size in bits is irrelevant - normalized range
119 * <li>higher quality for processing
120 * <li>separated channels (easy process/remove/add channels)
121 * <li>potentially less copying of audio data, as processing
122 * the float samples is generally done in-place. The same
123 * instance of a FloatSampleBuffer may be used from the original data source
124 * to the final data sink.
125 * </ul>
126 * <p>
127 * Simple benchmarks showed that the processing requirements
128 * for the conversion to and from float is about the same as
129 * when converting it to shorts or ints without dithering,
130 * and significantly higher with dithering. An own implementation
131 * of a random number generator may improve this.
132 * <p>
133 * &quot;Lazy&quot; deletion of samples and channels:<br>
134 * <ul>
135 * <li>When the sample count is reduced, the arrays are not resized, but
136 * only the member variable <code>sampleCount</code> is reduced. A subsequent
137 * increase of the sample count (which will occur frequently), will check
138 * that and eventually reuse the existing array.
139 * <li>When a channel is deleted, it is not removed from memory but only
140 * hidden. Subsequent insertions of a channel will check whether a hidden channel
141 * can be reused.
142 * </ul>
143 * The lazy mechanism can save many array instantiation (and copy-) operations
144 * for the sake of performance. All relevant methods exist in a second
145 * version which allows explicitely to disable lazy deletion.
146 * <p>
147 * Use the <code>reset</code> functions to clear the memory and remove
148 * hidden samples and channels.
149 * <p>
150 * Note that the lazy mechanism implies that the arrays returned
151 * from <code>getChannel(int)</code> may have a greater size
152 * than getSampleCount(). Consequently, be sure to never rely on the
153 * length field of the sample arrays.
154 * <p>
155 * As an example, consider a chain of converters that all act
156 * on the same instance of FloatSampleBuffer. Some converters
157 * may decrease the sample count (e.g. sample rate converter) and
158 * delete channels (e.g. PCM2PCM converter). So, processing of one
159 * block will decrease both. For the next block, all starts
160 * from the beginning. With the lazy mechanism, all float arrays
161 * are only created once for processing all blocks.<br>
162 * Having lazy disabled would require for each chunk that is processed
163 * <ol>
164 * <li>new instantiation of all channel arrays
165 * at the converter chain beginning as they have been
166 * either deleted or decreased in size during processing of the
167 * previous chunk, and
168 * <li>re-instantiation of all channel arrays for
169 * the reduction of the sample count.
170 * </ol>
171 * <p>
172 * Dithering:<br>
173 * By default, this class uses dithering for reduction
174 * of sample width (e.g. original data was 16bit, target
175 * data is 8bit). As dithering may be needed in other cases
176 * (especially when the float samples are processed using DSP
177 * algorithms), or it is preferred to switch it off,
178 * dithering can be explicitely switched on or off with
179 * the method setDitherMode(int).<br>
180 * For a discussion about dithering, see
181 * <a href="http://www.iqsoft.com/IQSMagazine/BobsSoapbox/Dithering.htm">
182 * here</a> and
183 * <a href="http://www.iqsoft.com/IQSMagazine/BobsSoapbox/Dithering2.htm">
184 * here</a>.
185 *
186 * @author Florian Bomers
187 */
188
189public class FloatSampleBuffer {
190
191 /** Whether the functions without lazy parameter are lazy or not. */
192 private static final boolean LAZY_DEFAULT=true;
193
194 private ArrayList<float[]> channels = new ArrayList<float[]>(); // contains for each channel a float array
195 private int sampleCount=0;
196 private int channelCount=0;
197 private float sampleRate=0;
198 private int originalFormatType=0;
199
200 /** Constant for setDitherMode: dithering will be enabled if sample size is decreased */
201 public static final int DITHER_MODE_AUTOMATIC=0;
202 /** Constant for setDitherMode: dithering will be done */
203 public static final int DITHER_MODE_ON=1;
204 /** Constant for setDitherMode: dithering will not be done */
205 public static final int DITHER_MODE_OFF=2;
206
207 private float ditherBits = FloatSampleTools.DEFAULT_DITHER_BITS;
208
209 // e.g. the sample rate converter may want to force dithering
210 private int ditherMode = DITHER_MODE_AUTOMATIC;
211
212 //////////////////////////////// initialization /////////////////////////////////
213
214 /**
215 * Create an instance with initially no channels.
216 */
217 public FloatSampleBuffer() {
218 this(0,0,1);
219 }
220
221 /**
222 * Create an empty FloatSampleBuffer with the specified number of channels,
223 * samples, and the specified sample rate.
224 */
225 public FloatSampleBuffer(int channelCount, int sampleCount, float sampleRate) {
226 init(channelCount, sampleCount, sampleRate, LAZY_DEFAULT);
227 }
228
229 /**
230 * Creates a new instance of FloatSampleBuffer and initializes
231 * it with audio data given in the interleaved byte array <code>buffer</code>.
232 */
233 public FloatSampleBuffer(byte[] buffer, int offset, int byteCount,
234 AudioFormat format) {
235 this(format.getChannels(),
236 byteCount/(format.getSampleSizeInBits()/8*format.getChannels()),
237 format.getSampleRate());
238 initFromByteArray(buffer, offset, byteCount, format);
239 }
240
241 protected void init(int channelCount, int sampleCount, float sampleRate) {
242 init(channelCount, sampleCount, sampleRate, LAZY_DEFAULT);
243 }
244
245 protected void init(int channelCount, int sampleCount, float sampleRate, boolean lazy) {
246 if (channelCount<0 || sampleCount<0) {
247 throw new IllegalArgumentException(
248 "invalid parameters in initialization of FloatSampleBuffer.");
249 }
250 setSampleRate(sampleRate);
251 if (getSampleCount()!=sampleCount || getChannelCount()!=channelCount) {
252 createChannels(channelCount, sampleCount, lazy);
253 }
254 }
255
256 private void createChannels(int channelCount, int sampleCount, boolean lazy) {
257 this.sampleCount=sampleCount;
258 // lazy delete of all channels. Intentionally lazy !
259 this.channelCount=0;
260 for (int ch=0; ch<channelCount; ch++) {
261 insertChannel(ch, false, lazy);
262 }
263 if (!lazy) {
264 // remove hidden channels
265 while (channels.size()>channelCount) {
266 channels.remove(channels.size()-1);
267 }
268 }
269 }
270
271
272 /**
273 * Resets this buffer with the audio data specified
274 * in the arguments. This FloatSampleBuffer's sample count
275 * will be set to <code>byteCount / format.getFrameSize()</code>.
276 * If LAZY_DEFAULT is true, it will use lazy deletion.
277 *
278 * @throws IllegalArgumentException
279 */
280 public void initFromByteArray(byte[] buffer, int offset, int byteCount,
281 AudioFormat format) {
282 initFromByteArray(buffer, offset, byteCount, format, LAZY_DEFAULT);
283 }
284
285
286 /**
287 * Resets this buffer with the audio data specified
288 * in the arguments. This FloatSampleBuffer's sample count
289 * will be set to <code>byteCount / format.getFrameSize()</code>.
290 *
291 * @param lazy if true, then existing channels will be tried to be re-used
292 * to minimize garbage collection.
293 * @throws IllegalArgumentException
294 */
295 public void initFromByteArray(byte[] buffer, int offset, int byteCount,
296 AudioFormat format, boolean lazy) {
297 if (offset+byteCount>buffer.length) {
298 throw new IllegalArgumentException
299 ("FloatSampleBuffer.initFromByteArray: buffer too small.");
300 }
301
302 int thisSampleCount = byteCount/format.getFrameSize();
303 init(format.getChannels(), thisSampleCount, format.getSampleRate(), lazy);
304
305 // save format for automatic dithering mode
306 originalFormatType = FloatSampleTools.getFormatType(format);
307
308 FloatSampleTools.byte2float(buffer, offset,
309 channels, 0, sampleCount, format);
310 }
311
312 /**
313 * Resets this sample buffer with the data in <code>source</code>.
314 */
315 public void initFromFloatSampleBuffer(FloatSampleBuffer source) {
316 init(source.getChannelCount(), source.getSampleCount(), source.getSampleRate());
317 for (int ch=0; ch<getChannelCount(); ch++) {
318 System.arraycopy(source.getChannel(ch), 0, getChannel(ch), 0, sampleCount);
319 }
320 }
321
322 /**
323 * Deletes all channels, frees memory...
324 * This also removes hidden channels by lazy remove.
325 */
326 public void reset() {
327 init(0,0,1, false);
328 }
329
330 /**
331 * Destroys any existing data and creates new channels.
332 * It also destroys lazy removed channels and samples.
333 */
334 public void reset(int channels, int sampleCount, float sampleRate) {
335 init(channels, sampleCount, sampleRate, false);
336 }
337
338 //////////////////////////////// conversion back to bytes /////////////////////////////////
339
340 /**
341 * @return the required size of the buffer
342 * for calling convertToByteArray(..) is called
343 */
344 public int getByteArrayBufferSize(AudioFormat format) {
345 // make sure this format is supported
346 FloatSampleTools.getFormatType(format);
347 return format.getFrameSize() * getSampleCount();
348 }
349
350 /**
351 * Writes this sample buffer's audio data to <code>buffer</code>
352 * as an interleaved byte array.
353 * <code>buffer</code> must be large enough to hold all data.
354 *
355 * @throws IllegalArgumentException when buffer is too small or <code>format</code> doesn't match
356 * @return number of bytes written to <code>buffer</code>
357 */
358 public int convertToByteArray(byte[] buffer, int offset, AudioFormat format) {
359 int byteCount = getByteArrayBufferSize(format);
360 if (offset + byteCount > buffer.length) {
361 throw new IllegalArgumentException
362 ("FloatSampleBuffer.convertToByteArray: buffer too small.");
363 }
364 if (format.getSampleRate()!=getSampleRate()) {
365 throw new IllegalArgumentException
366 ("FloatSampleBuffer.convertToByteArray: different samplerates.");
367 }
368 if (format.getChannels()!=getChannelCount()) {
369 throw new IllegalArgumentException
370 ("FloatSampleBuffer.convertToByteArray: different channel count.");
371 }
372 FloatSampleTools.float2byte(channels, 0, buffer, offset, getSampleCount(),
373 format, getConvertDitherBits(FloatSampleTools.getFormatType(format)));
374
375 return byteCount;
376 }
377
378
379 /**
380 * Creates a new byte[] buffer, fills it with the audio data, and returns it.
381 * @throws IllegalArgumentException when sample rate or channels do not match
382 * @see #convertToByteArray(byte[], int, AudioFormat)
383 */
384 public byte[] convertToByteArray(AudioFormat format) {
385 // throws exception when sampleRate doesn't match
386 // creates a new byte[] buffer and returns it
387 byte[] res = new byte[getByteArrayBufferSize(format)];
388 convertToByteArray(res, 0, format);
389 return res;
390 }
391
392 //////////////////////////////// actions /////////////////////////////////
393
394 /**
395 * Resizes this buffer.
396 * <p>If <code>keepOldSamples</code> is true, as much as possible samples are
397 * retained. If the buffer is enlarged, silence is added at the end.
398 * If <code>keepOldSamples</code> is false, existing samples are discarded
399 * and the buffer contains random samples.
400 */
401 public void changeSampleCount(int newSampleCount, boolean keepOldSamples) {
402 int oldSampleCount=getSampleCount();
403 if (oldSampleCount==newSampleCount) {
404 return;
405 }
406 Object[] oldChannels=null;
407 if (keepOldSamples) {
408 oldChannels=getAllChannels();
409 }
410 init(getChannelCount(), newSampleCount, getSampleRate());
411 if (keepOldSamples) {
412 // copy old channels and eventually silence out new samples
413 int copyCount=newSampleCount<oldSampleCount?
414 newSampleCount:oldSampleCount;
415 for (int ch=0; ch<getChannelCount(); ch++) {
416 float[] oldSamples=(float[]) oldChannels[ch];
417 float[] newSamples=(float[]) getChannel(ch);
418 if (oldSamples!=newSamples) {
419 // if this sample array was not object of lazy delete
420 System.arraycopy(oldSamples, 0, newSamples, 0, copyCount);
421 }
422 if (oldSampleCount<newSampleCount) {
423 // silence out new samples
424 for (int i=oldSampleCount; i<newSampleCount; i++) {
425 newSamples[i]=0.0f;
426 }
427 }
428 }
429 }
430 }
431
432 public void makeSilence() {
433 // silence all channels
434 if (getChannelCount()>0) {
435 makeSilence(0);
436 for (int ch=1; ch<getChannelCount(); ch++) {
437 copyChannel(0, ch);
438 }
439 }
440 }
441
442 public void makeSilence(int channel) {
443 float[] samples=getChannel(channel);
444 for (int i=0; i<getSampleCount(); i++) {
445 samples[i]=0.0f;
446 }
447 }
448
449 public void addChannel(boolean silent) {
450 // creates new, silent channel
451 insertChannel(getChannelCount(), silent);
452 }
453
454 /**
455 * Insert a (silent) channel at position <code>index</code>.
456 * If LAZY_DEFAULT is true, this is done lazily.
457 */
458 public void insertChannel(int index, boolean silent) {
459 insertChannel(index, silent, LAZY_DEFAULT);
460 }
461
462 /**
463 * Inserts a channel at position <code>index</code>.
464 * <p>If <code>silent</code> is true, the new channel will be silent.
465 * Otherwise it will contain random data.
466 * <p>If <code>lazy</code> is true, hidden channels which have at least getSampleCount()
467 * elements will be examined for reusage as inserted channel.<br>
468 * If <code>lazy</code> is false, still hidden channels are reused,
469 * but it is assured that the inserted channel has exactly getSampleCount() elements,
470 * thus not wasting memory.
471 */
472 public void insertChannel(int index, boolean silent, boolean lazy) {
473 int physSize=channels.size();
474 int virtSize=getChannelCount();
475 float[] newChannel=null;
476 if (physSize>virtSize) {
477 // there are hidden channels. Try to use one.
478 for (int ch=virtSize; ch<physSize; ch++) {
479 float[] thisChannel=(float[]) channels.get(ch);
480 if ((lazy && thisChannel.length>=getSampleCount())
481 || (!lazy && thisChannel.length==getSampleCount())) {
482 // we found a matching channel. Use it !
483 newChannel=thisChannel;
484 channels.remove(ch);
485 break;
486 }
487 }
488 }
489 if (newChannel==null) {
490 newChannel=new float[getSampleCount()];
491 }
492 channels.add(index, newChannel);
493 this.channelCount++;
494 if (silent) {
495 makeSilence(index);
496 }
497 }
498
499 /** performs a lazy remove of the channel */
500 public void removeChannel(int channel) {
501 removeChannel(channel, LAZY_DEFAULT);
502 }
503
504
505 /**
506 * Removes a channel.
507 * If lazy is true, the channel is not physically removed, but only hidden.
508 * These hidden channels are reused by subsequent calls to addChannel
509 * or insertChannel.
510 */
511 public void removeChannel(int channel, boolean lazy) {
512 if (!lazy) {
513 channels.remove(channel);
514 } else if (channel<getChannelCount()-1) {
515 // if not already, move this channel at the end
516 channels.add(channels.remove(channel));
517 }
518 channelCount--;
519 }
520
521 /**
522 * both source and target channel have to exist. targetChannel
523 * will be overwritten
524 */
525 public void copyChannel(int sourceChannel, int targetChannel) {
526 float[] source=getChannel(sourceChannel);
527 float[] target=getChannel(targetChannel);
528 System.arraycopy(source, 0, target, 0, getSampleCount());
529 }
530
531 /**
532 * Copies data inside all channel. When the 2 regions
533 * overlap, the behavior is not specified.
534 */
535 public void copy(int sourceIndex, int destIndex, int length) {
536 for (int i=0; i<getChannelCount(); i++) {
537 copy(i, sourceIndex, destIndex, length);
538 }
539 }
540
541 /**
542 * Copies data inside a channel. When the 2 regions
543 * overlap, the behavior is not specified.
544 */
545 public void copy(int channel, int sourceIndex, int destIndex, int length) {
546 float[] data=getChannel(channel);
547 int bufferCount=getSampleCount();
548 if (sourceIndex+length>bufferCount || destIndex+length>bufferCount
549 || sourceIndex<0 || destIndex<0 || length<0) {
550 throw new IndexOutOfBoundsException("parameters exceed buffer size");
551 }
552 System.arraycopy(data, sourceIndex, data, destIndex, length);
553 }
554
555 /**
556 * Mix up of 1 channel to n channels.<br>
557 * It copies the first channel to all newly created channels.
558 * @param targetChannelCount the number of channels that this sample buffer
559 * will have after expanding. NOT the number of
560 * channels to add !
561 * @exception IllegalArgumentException if this buffer does not have one
562 * channel before calling this method.
563 */
564 public void expandChannel(int targetChannelCount) {
565 // even more sanity...
566 if (getChannelCount()!=1) {
567 throw new IllegalArgumentException(
568 "FloatSampleBuffer: can only expand channels for mono signals.");
569 }
570 for (int ch=1; ch<targetChannelCount; ch++) {
571 addChannel(false);
572 copyChannel(0, ch);
573 }
574 }
575
576 /**
577 * Mix down of n channels to one channel.<br>
578 * It uses a simple mixdown: all other channels are added to first channel.<br>
579 * The volume is NOT lowered !
580 * Be aware, this might cause clipping when converting back
581 * to integer samples.
582 */
583 public void mixDownChannels() {
584 float[] firstChannel=getChannel(0);
585 int sampleCount=getSampleCount();
586 int channelCount=getChannelCount();
587 for (int ch=channelCount-1; ch>0; ch--) {
588 float[] thisChannel=getChannel(ch);
589 for (int i=0; i<sampleCount; i++) {
590 firstChannel[i]+=thisChannel[i];
591 }
592 removeChannel(ch);
593 }
594 }
595
596 /**
597 * Initializes audio data from the provided byte array.
598 * The float samples are written at <code>destOffset</code>.
599 * This FloatSampleBuffer must be big enough to accomodate the samples.
600 * <p>
601 * <code>srcBuffer</code> is read from index <code>srcOffset</code>
602 * to <code>(srcOffset + (lengthInSamples * format.getFrameSize()))</code.
603 *
604 * @param input the input buffer in interleaved audio data
605 * @param inByteOffset the offset in <code>input</code>
606 * @param format input buffer's audio format
607 * @param floatOffset the offset where to write the float samples
608 * @param frameCount number of samples to write to this sample buffer
609 */
610 public void setSamplesFromBytes(byte[] input, int inByteOffset, AudioFormat format,
611 int floatOffset, int frameCount) {
612 if (floatOffset < 0 || frameCount < 0 || inByteOffset < 0) {
613 throw new IllegalArgumentException
614 ("FloatSampleBuffer.setSamplesFromBytes: negative inByteOffset, floatOffset, or frameCount");
615 }
616 if (inByteOffset + (frameCount * format.getFrameSize()) > input.length) {
617 throw new IllegalArgumentException
618 ("FloatSampleBuffer.setSamplesFromBytes: input buffer too small.");
619 }
620 if (floatOffset + frameCount > getSampleCount()) {
621 throw new IllegalArgumentException
622 ("FloatSampleBuffer.setSamplesFromBytes: frameCount too large");
623 }
624
625 FloatSampleTools.byte2float(input, inByteOffset, channels, floatOffset, frameCount, format);
626 }
627
628 //////////////////////////////// properties /////////////////////////////////
629
630 public int getChannelCount() {
631 return channelCount;
632 }
633
634 public int getSampleCount() {
635 return sampleCount;
636 }
637
638 public float getSampleRate() {
639 return sampleRate;
640 }
641
642 /**
643 * Sets the sample rate of this buffer.
644 * NOTE: no conversion is done. The samples are only re-interpreted.
645 */
646 public void setSampleRate(float sampleRate) {
647 if (sampleRate<=0) {
648 throw new IllegalArgumentException
649 ("Invalid samplerate for FloatSampleBuffer.");
650 }
651 this.sampleRate=sampleRate;
652 }
653
654 /**
655 * NOTE: the returned array may be larger than sampleCount. So in any case,
656 * sampleCount is to be respected.
657 */
658 public float[] getChannel(int channel) {
659 if (channel<0 || channel>=getChannelCount()) {
660 throw new IllegalArgumentException(
661 "FloatSampleBuffer: invalid channel number.");
662 }
663 return (float[]) channels.get(channel);
664 }
665
666 public Object[] getAllChannels() {
667 Object[] res=new Object[getChannelCount()];
668 for (int ch=0; ch<getChannelCount(); ch++) {
669 res[ch]=getChannel(ch);
670 }
671 return res;
672 }
673
674 /**
675 * Set the number of bits for dithering.
676 * Typically, a value between 0.2 and 0.9 gives best results.
677 * <p>Note: this value is only used, when dithering is actually performed.
678 */
679 public void setDitherBits(float ditherBits) {
680 if (ditherBits<=0) {
681 throw new IllegalArgumentException("DitherBits must be greater than 0");
682 }
683 this.ditherBits=ditherBits;
684 }
685
686 public float getDitherBits() {
687 return ditherBits;
688 }
689
690 /**
691 * Sets the mode for dithering.
692 * This can be one of:
693 * <ul><li>DITHER_MODE_AUTOMATIC: it is decided automatically,
694 * whether dithering is necessary - in general when sample size is
695 * decreased.
696 * <li>DITHER_MODE_ON: dithering will be forced
697 * <li>DITHER_MODE_OFF: dithering will not be done.
698 * </ul>
699 */
700 public void setDitherMode(int mode) {
701 if (mode!=DITHER_MODE_AUTOMATIC
702 && mode!=DITHER_MODE_ON
703 && mode!=DITHER_MODE_OFF) {
704 throw new IllegalArgumentException("Illegal DitherMode");
705 }
706 this.ditherMode=mode;
707 }
708
709 public int getDitherMode() {
710 return ditherMode;
711 }
712
713
714 /**
715 * @return the ditherBits parameter for the float2byte functions
716 */
717 protected float getConvertDitherBits(int newFormatType) {
718 // let's see whether dithering is necessary
719 boolean doDither = false;
720 switch (ditherMode) {
721 case DITHER_MODE_AUTOMATIC:
722 doDither=(originalFormatType & FloatSampleTools.F_SAMPLE_WIDTH_MASK)>
723 (newFormatType & FloatSampleTools.F_SAMPLE_WIDTH_MASK);
724 break;
725 case DITHER_MODE_ON:
726 doDither=true;
727 break;
728 case DITHER_MODE_OFF:
729 doDither=false;
730 break;
731 }
732 return doDither?ditherBits:0.0f;
733 }
734}
diff --git a/songdbj/org/tritonus/share/sampled/FloatSampleTools.java b/songdbj/org/tritonus/share/sampled/FloatSampleTools.java
new file mode 100644
index 0000000000..76913ba39e
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/FloatSampleTools.java
@@ -0,0 +1,696 @@
1/*
2 * FloatSampleTools.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2004 by Florian Bomers <http://www.bomers.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31import java.util.*;
32import javax.sound.sampled.*;
33import org.tritonus.share.TDebug;
34
35/**
36 * Utility functions for handling data in normalized float arrays.
37 * Each sample is linear in the range of [-1.0f, +1.0f].
38 * <p>
39 * Currently, the following bit sizes are supported:
40 * <ul>
41 * <li>8-bit
42 * <li>16-bit
43 * <li>packed 24-bit (stored in 3 bytes)
44 * <li>32-bit
45 * </ul>
46 * 8-bit data can be unsigned or signed. All other data is only
47 * supported in signed encoding.
48 *
49 * @see FloatSampleBuffer
50 * @author Florian Bomers
51 */
52
53public class FloatSampleTools {
54
55 /** default number of bits to be dithered: 0.7f */
56 public static final float DEFAULT_DITHER_BITS = 0.7f;
57
58 private static Random random = null;
59
60 // sample width (must be in order !)
61 static final int F_8=1;
62 static final int F_16=2;
63 static final int F_24=3;
64 static final int F_32=4;
65 static final int F_SAMPLE_WIDTH_MASK=F_8 | F_16 | F_24 | F_32;
66
67 // format bit-flags
68 static final int F_SIGNED=8;
69 static final int F_BIGENDIAN=16;
70
71 // supported formats
72 static final int CT_8S=F_8 | F_SIGNED;
73 static final int CT_8U=F_8;
74 static final int CT_16SB=F_16 | F_SIGNED | F_BIGENDIAN;
75 static final int CT_16SL=F_16 | F_SIGNED;
76 static final int CT_24SB=F_24 | F_SIGNED | F_BIGENDIAN;
77 static final int CT_24SL=F_24 | F_SIGNED;
78 static final int CT_32SB=F_32 | F_SIGNED | F_BIGENDIAN;
79 static final int CT_32SL=F_32 | F_SIGNED;
80
81 // ////////////////////////////// initialization /////////////////////////////// //
82
83 /** prevent instanciation */
84 private FloatSampleTools() {
85 }
86
87
88 // /////////////////// FORMAT / FORMAT TYPE /////////////////////////////////// //
89
90 /**
91 * only allow "packed" samples -- currently no support for 18, 20, 24_32 bits.
92 * @throws IllegalArgumentException
93 */
94 static void checkSupportedSampleSize(int ssib, int channels, int frameSize) {
95 if ((ssib*channels) != frameSize * 8) {
96 throw new IllegalArgumentException("unsupported sample size: "+ssib
97 +" stored in "+(frameSize/channels)+" bytes.");
98 }
99 }
100
101
102 /**
103 * Get the formatType code from the given format.
104 * @throws IllegalArgumentException
105 */
106 static int getFormatType(AudioFormat format) {
107 boolean signed = format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED);
108 if (!signed &&
109 !format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED)) {
110 throw new IllegalArgumentException
111 ("unsupported encoding: only PCM encoding supported.");
112 }
113 if (!signed && format.getSampleSizeInBits() != 8) {
114 throw new IllegalArgumentException
115 ("unsupported encoding: only 8-bit can be unsigned");
116 }
117 checkSupportedSampleSize(format.getSampleSizeInBits(),
118 format.getChannels(),
119 format.getFrameSize());
120
121 int formatType = getFormatType(format.getSampleSizeInBits(),
122 signed, format.isBigEndian());
123 return formatType;
124 }
125
126 /**
127 * @throws IllegalArgumentException
128 */
129 static int getFormatType(int ssib, boolean signed, boolean bigEndian) {
130 int bytesPerSample=ssib/8;
131 int res=0;
132 if (ssib==8) {
133 res=F_8;
134 } else if (ssib==16) {
135 res=F_16;
136 } else if (ssib==24) {
137 res=F_24;
138 } else if (ssib==32) {
139 res=F_32;
140 }
141 if (res==0) {
142 throw new IllegalArgumentException
143 ("FloatSampleBuffer: unsupported sample size of "
144 +ssib+" bits per sample.");
145 }
146 if (!signed && bytesPerSample>1) {
147 throw new IllegalArgumentException
148 ("FloatSampleBuffer: unsigned samples larger than "
149 +"8 bit are not supported");
150 }
151 if (signed) {
152 res|=F_SIGNED;
153 }
154 if (bigEndian && (ssib!=8)) {
155 res|=F_BIGENDIAN;
156 }
157 return res;
158 }
159
160 static int getSampleSize(int formatType) {
161 switch (formatType & F_SAMPLE_WIDTH_MASK) {
162 case F_8: return 1;
163 case F_16: return 2;
164 case F_24: return 3;
165 case F_32: return 4;
166 }
167 return 0;
168 }
169
170 /**
171 * Return a string representation of this format
172 */
173 static String formatType2Str(int formatType) {
174 String res=""+formatType+": ";
175 switch (formatType & F_SAMPLE_WIDTH_MASK) {
176 case F_8:
177 res+="8bit";
178 break;
179 case F_16:
180 res+="16bit";
181 break;
182 case F_24:
183 res+="24bit";
184 break;
185 case F_32:
186 res+="32bit";
187 break;
188 }
189 res+=((formatType & F_SIGNED)==F_SIGNED)?" signed":" unsigned";
190 if ((formatType & F_SAMPLE_WIDTH_MASK)!=F_8) {
191 res+=((formatType & F_BIGENDIAN)==F_BIGENDIAN)?
192 " big endian":" little endian";
193 }
194 return res;
195 }
196
197
198 // /////////////////// BYTE 2 FLOAT /////////////////////////////////// //
199
200 private static final float twoPower7=128.0f;
201 private static final float twoPower15=32768.0f;
202 private static final float twoPower23=8388608.0f;
203 private static final float twoPower31=2147483648.0f;
204
205 private static final float invTwoPower7=1/twoPower7;
206 private static final float invTwoPower15=1/twoPower15;
207 private static final float invTwoPower23=1/twoPower23;
208 private static final float invTwoPower31=1/twoPower31;
209
210
211 /**
212 * Conversion function to convert an interleaved byte array to
213 * a List of interleaved float arrays. The float arrays will contain normalized
214 * samples in the range [-1.0f, +1.0f]. The input array
215 * provides bytes in the format specified in <code>format</code>.
216 * <p>
217 * Only PCM formats are accepted. The method will convert all
218 * byte values from
219 * <code>input[inByteOffset]</code> to
220 * <code>input[inByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
221 * to floats from
222 * <code>output(n)[outOffset]</code> to
223 * <code>output(n)[outOffset + frameCount - 1]</code>
224 *
225 * @param input the audio data in an byte array
226 * @param inByteOffset index in input where to start the conversion
227 * @param output list of float[] arrays which receive the converted audio data.
228 * if the list does not contain enough elements, or individual float arrays
229 * are not large enough, they are created.
230 * @param outOffset the start offset in <code>output</code>
231 * @param frameCount number of frames to be converted
232 * @param format the input format. Only packed PCM is allowed
233 * @throws IllegalArgumentException if one of the parameters is out of bounds
234 *
235 * @see #byte2floatInterleaved(byte[],int,float[],int,int,AudioFormat)
236 */
237 public static void byte2float(byte[] input, int inByteOffset,
238 List<float[]> output, int outOffset, int frameCount,
239 //List output, int outOffset, int frameCount,
240 AudioFormat format) {
241 for (int channel = 0; channel < format.getChannels(); channel++) {
242 float[] data;
243 if (output.size() < channel) {
244 data = new float[frameCount + outOffset];
245 output.add(data);
246 } else {
247 data = output.get(channel);
248 if (data.length < frameCount + outOffset) {
249 data = new float[frameCount + outOffset];
250 output.set(channel, data);
251 }
252 }
253
254 byte2floatGeneric(input, inByteOffset, format.getFrameSize(),
255 data, outOffset,
256 frameCount, format);
257 inByteOffset += format.getFrameSize() / format.getChannels();
258 }
259 }
260
261
262 /**
263 * Conversion function to convert an interleaved byte array to
264 * an interleaved float array. The float array will contain normalized
265 * samples in the range [-1.0f, +1.0f]. The input array
266 * provides bytes in the format specified in <code>format</code>.
267 * <p>
268 * Only PCM formats are accepted. The method will convert all
269 * byte values from
270 * <code>input[inByteOffset]</code> to
271 * <code>input[inByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
272 * to floats from
273 * <code>output[outOffset]</code> to
274 * <code>output[outOffset + (frameCount * format.getChannels()) - 1]</code>
275 *
276 * @param input the audio data in an byte array
277 * @param inByteOffset index in input where to start the conversion
278 * @param output the float array that receives the converted audio data
279 * @param outOffset the start offset in <code>output</code>
280 * @param frameCount number of frames to be converted
281 * @param format the input format. Only packed PCM is allowed
282 * @throws IllegalArgumentException if one of the parameters is out of bounds
283 *
284 * @see #byte2float(byte[],int,List,int,int,AudioFormat)
285 */
286 public static void byte2floatInterleaved(byte[] input, int inByteOffset,
287 float[] output, int outOffset, int frameCount,
288 AudioFormat format) {
289
290 byte2floatGeneric(input, inByteOffset, format.getFrameSize() / format.getChannels(),
291 output, outOffset, frameCount * format.getChannels(),
292 format);
293 }
294
295
296
297 /**
298 * Generic conversion function to convert a byte array to
299 * a float array.
300 * <p>
301 * Only PCM formats are accepted. The method will convert all
302 * bytes from
303 * <code>input[inByteOffset]</code> to
304 * <code>input[inByteOffset + (sampleCount * (inByteStep - 1)]</code>
305 * to samples from
306 * <code>output[outOffset]</code> to
307 * <code>output[outOffset+sampleCount-1]</code>.
308 * <p>
309 * The <code>format</code>'s channel count is ignored.
310 * <p>
311 * For mono data, set <code>inByteOffset</code> to <code>format.getFrameSize()</code>.<br>
312 * For converting interleaved input data, multiply <code>sampleCount</code>
313 * by the number of channels and set inByteStep to
314 * <code>format.getFrameSize() / format.getChannels()</code>.
315 *
316 * @param sampleCount number of samples to be written to output
317 * @param inByteStep how many bytes advance for each output sample in <code>output</code>.
318 * @throws IllegalArgumentException if one of the parameters is out of bounds
319 *
320 * @see #byte2floatInterleaved(byte[],int,float[],int,int,AudioFormat)
321 * @see #byte2float(byte[],int,List,int,int,AudioFormat)
322 */
323 static void byte2floatGeneric(byte[] input, int inByteOffset, int inByteStep,
324 float[] output, int outOffset, int sampleCount,
325 AudioFormat format) {
326 int formatType = getFormatType(format);
327
328 byte2floatGeneric(input, inByteOffset, inByteStep,
329 output, outOffset, sampleCount,
330 formatType);
331 }
332
333
334 /**
335 * Central conversion function from
336 * a byte array to a normalized float array. In order to accomodate
337 * interleaved and non-interleaved
338 * samples, this method takes inByteStep as parameter which
339 * can be used to flexibly convert the data.
340 * <p>
341 * E.g.:<br>
342 * mono->mono: inByteStep=format.getFrameSize()<br>
343 * interleaved_stereo->interleaved_stereo: inByteStep=format.getFrameSize()/2,
344 * sampleCount*2<br>
345 * stereo->2 mono arrays:<br>
346 * ---inByteOffset=0, outOffset=0, inByteStep=format.getFrameSize()<br>
347 * ---inByteOffset=format.getFrameSize()/2, outOffset=1, inByteStep=format.getFrameSize()<br>
348 */
349 static void byte2floatGeneric(byte[] input, int inByteOffset, int inByteStep,
350 float[] output, int outOffset, int sampleCount,
351 int formatType) {
352 //if (TDebug.TraceAudioConverter) {
353 // TDebug.out("FloatSampleTools.byte2floatGeneric, formatType="
354 // +formatType2Str(formatType));
355 //}
356 int endCount = outOffset + sampleCount;
357 int inIndex = inByteOffset;
358 for (int outIndex = outOffset; outIndex < endCount; outIndex++, inIndex+=inByteStep) {
359 // do conversion
360 switch (formatType) {
361 case CT_8S:
362 output[outIndex]=
363 ((float) input[inIndex])*invTwoPower7;
364 break;
365 case CT_8U:
366 output[outIndex]=
367 ((float) ((input[inIndex] & 0xFF)-128))*invTwoPower7;
368 break;
369 case CT_16SB:
370 output[outIndex]=
371 ((float) ((input[inIndex]<<8)
372 | (input[inIndex+1] & 0xFF)))*invTwoPower15;
373 break;
374 case CT_16SL:
375 output[outIndex]=
376 ((float) ((input[inIndex+1]<<8)
377 | (input[inIndex] & 0xFF)))*invTwoPower15;
378 break;
379 case CT_24SB:
380 output[outIndex]=
381 ((float) ((input[inIndex]<<16)
382 | ((input[inIndex+1] & 0xFF)<<8)
383 | (input[inIndex+2] & 0xFF)))*invTwoPower23;
384 break;
385 case CT_24SL:
386 output[outIndex]=
387 ((float) ((input[inIndex+2]<<16)
388 | ((input[inIndex+1] & 0xFF)<<8)
389 | (input[inIndex] & 0xFF)))*invTwoPower23;
390 break;
391 case CT_32SB:
392 output[outIndex]=
393 ((float) ((input[inIndex]<<24)
394 | ((input[inIndex+1] & 0xFF)<<16)
395 | ((input[inIndex+2] & 0xFF)<<8)
396 | (input[inIndex+3] & 0xFF)))*invTwoPower31;
397 break;
398 case CT_32SL:
399 output[outIndex]=
400 ((float) ((input[inIndex+3]<<24)
401 | ((input[inIndex+2] & 0xFF)<<16)
402 | ((input[inIndex+1] & 0xFF)<<8)
403 | (input[inIndex] & 0xFF)))*invTwoPower31;
404 break;
405 default:
406 throw new IllegalArgumentException
407 ("unsupported format="+formatType2Str(formatType));
408 }
409 }
410 }
411
412 // /////////////////// FLOAT 2 BYTE /////////////////////////////////// //
413
414 private static byte quantize8(float sample, float ditherBits) {
415 if (ditherBits!=0) {
416 sample+=random.nextFloat()*ditherBits;
417 }
418 if (sample>=127.0f) {
419 return (byte) 127;
420 } else if (sample<=-128.0f) {
421 return (byte) -128;
422 } else {
423 return (byte) (sample<0?(sample-0.5f):(sample+0.5f));
424 }
425 }
426
427 private static int quantize16(float sample, float ditherBits) {
428 if (ditherBits!=0) {
429 sample+=random.nextFloat()*ditherBits;
430 }
431 if (sample>=32767.0f) {
432 return 32767;
433 } else if (sample<=-32768.0f) {
434 return -32768;
435 } else {
436 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
437 }
438 }
439
440 private static int quantize24(float sample, float ditherBits) {
441 if (ditherBits!=0) {
442 sample+=random.nextFloat()*ditherBits;
443 }
444 if (sample>=8388607.0f) {
445 return 8388607;
446 } else if (sample<=-8388608.0f) {
447 return -8388608;
448 } else {
449 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
450 }
451 }
452
453 private static int quantize32(float sample, float ditherBits) {
454 if (ditherBits!=0) {
455 sample+=random.nextFloat()*ditherBits;
456 }
457 if (sample>=2147483647.0f) {
458 return 2147483647;
459 } else if (sample<=-2147483648.0f) {
460 return -2147483648;
461 } else {
462 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
463 }
464 }
465
466
467 /**
468 * Conversion function to convert a non-interleaved float audio data to
469 * an interleaved byte array. The float arrays contains normalized
470 * samples in the range [-1.0f, +1.0f]. The output array
471 * will receive bytes in the format specified in <code>format</code>.
472 * Exactly <code>format.getChannels()</code> channels are converted
473 * regardless of the number of elements in <code>input</code>. If <code>input</code>
474 * does not provide enough channels, an </code>IllegalArgumentException<code> is thrown.
475 * <p>
476 * Only PCM formats are accepted. The method will convert all
477 * samples from <code>input(n)[inOffset]</code> to
478 * <code>input(n)[inOffset + frameCount - 1]</code>
479 * to byte values from <code>output[outByteOffset]</code> to
480 * <code>output[outByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
481 * <p>
482 * Dithering should be used when the output resolution is significantly
483 * lower than the original resolution. This includes if the original
484 * data was 16-bit and it is now converted to 8-bit, or if the
485 * data was generated in the float domain. No dithering need to be used
486 * if the original sample data was in e.g. 8-bit and the resulting output
487 * data has a higher resolution. If dithering is used, a sensitive value
488 * is DEFAULT_DITHER_BITS.
489 *
490 * @param input a List of float arrays with the input audio data
491 * @param inOffset index in the input arrays where to start the conversion
492 * @param output the byte array that receives the converted audio data
493 * @param outByteOffset the start offset in <code>output</code>
494 * @param frameCount number of frames to be converted.
495 * @param format the output format. Only packed PCM is allowed
496 * @param ditherBits if 0, do not dither. Otherwise the number of bits to be dithered
497 * @throws IllegalArgumentException if one of the parameters is out of bounds
498 *
499 * @see #DEFAULT_DITHER_BITS
500 * @see #float2byteInterleaved(float[],int,byte[],int,int,AudioFormat,float)
501 */
502 //public static void float2byte(List<float[]> input, int inOffset,
503 public static void float2byte(List input, int inOffset,
504 byte[] output, int outByteOffset,
505 int frameCount,
506 AudioFormat format, float ditherBits) {
507 for (int channel = 0; channel < format.getChannels(); channel++) {
508 float[] data = (float[]) input.get(channel);
509 float2byteGeneric(data, inOffset,
510 output, outByteOffset, format.getFrameSize(),
511 frameCount, format, ditherBits);
512 outByteOffset += format.getFrameSize() / format.getChannels();
513 }
514 }
515
516 /**
517 * Conversion function to convert an interleaved float array to
518 * an interleaved byte array. The float array contains normalized
519 * samples in the range [-1.0f, +1.0f]. The output array
520 * will receive bytes in the format specified in <code>format</code>.
521 * <p>
522 * Only PCM formats are accepted. The method will convert all
523 * samples from <code>input[inOffset]</code> to
524 * <code>input[inOffset + (frameCount * format.getChannels()) - 1]</code>
525 * to byte values from <code>output[outByteOffset]</code> to
526 * <code>output[outByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
527 * <p>
528 * Dithering should be used when the output resolution is significantly
529 * lower than the original resolution. This includes if the original
530 * data was 16-bit and it is now converted to 8-bit, or if the
531 * data was generated in the float domain. No dithering need to be used
532 * if the original sample data was in e.g. 8-bit and the resulting output
533 * data has a higher resolution. If dithering is used, a sensitive value
534 * is DEFAULT_DITHER_BITS.
535 *
536 * @param input the audio data in normalized samples
537 * @param inOffset index in input where to start the conversion
538 * @param output the byte array that receives the converted audio data
539 * @param outByteOffset the start offset in <code>output</code>
540 * @param frameCount number of frames to be converted.
541 * @param format the output format. Only packed PCM is allowed
542 * @param ditherBits if 0, do not dither. Otherwise the number of bits to be dithered
543 * @throws IllegalArgumentException if one of the parameters is out of bounds
544 *
545 * @see #DEFAULT_DITHER_BITS
546 * @see #float2byte(List,int,byte[],int,int,AudioFormat,float)
547 */
548 public static void float2byteInterleaved(float[] input, int inOffset,
549 byte[] output, int outByteOffset,
550 int frameCount,
551 AudioFormat format, float ditherBits) {
552 float2byteGeneric(input, inOffset,
553 output, outByteOffset, format.getFrameSize() / format.getChannels(),
554 frameCount * format.getChannels(),
555 format, ditherBits);
556 }
557
558
559
560 /**
561 * Generic conversion function to convert a float array to
562 * a byte array.
563 * <p>
564 * Only PCM formats are accepted. The method will convert all
565 * samples from <code>input[inOffset]</code> to
566 * <code>input[inOffset+sampleCount-1]</code>
567 * to byte values from <code>output[outByteOffset]</code> to
568 * <code>output[outByteOffset + (sampleCount * (outByteStep - 1)]</code>.
569 * <p>
570 * The <code>format</code>'s channel count is ignored.
571 * <p>
572 * For mono data, set <code>outByteOffset</code> to <code>format.getFrameSize()</code>.<br>
573 * For converting interleaved input data, multiply <code>sampleCount</code>
574 * by the number of channels and set outByteStep to
575 * <code>format.getFrameSize() / format.getChannels()</code>.
576 *
577 * @param sampleCount number of samples in input to be converted.
578 * @param outByteStep how many bytes advance for each input sample in <code>input</code>.
579 * @throws IllegalArgumentException if one of the parameters is out of bounds
580 *
581 * @see #float2byteInterleaved(float[],int,byte[],int,int,AudioFormat,float)
582 * @see #float2byte(List,int,byte[],int,int,AudioFormat,float)
583 */
584 static void float2byteGeneric(float[] input, int inOffset,
585 byte[] output, int outByteOffset, int outByteStep,
586 int sampleCount,
587 AudioFormat format, float ditherBits) {
588 int formatType = getFormatType(format);
589
590 float2byteGeneric(input, inOffset,
591 output, outByteOffset, outByteStep,
592 sampleCount,
593 formatType, ditherBits);
594 }
595
596
597 /**
598 * Central conversion function from normalized float array to
599 * a byte array. In order to accomodate interleaved and non-interleaved
600 * samples, this method takes outByteStep as parameter which
601 * can be used to flexibly convert the data.
602 * <p>
603 * E.g.:<br>
604 * mono->mono: outByteStep=format.getFrameSize()<br>
605 * interleaved stereo->interleaved stereo: outByteStep=format.getFrameSize()/2, sampleCount*2<br>
606 * 2 mono arrays->stereo:<br>
607 * ---inOffset=0, outByteOffset=0, outByteStep=format.getFrameSize()<br>
608 * ---inOffset=1, outByteOffset=format.getFrameSize()/2, outByteStep=format.getFrameSize()<br>
609 */
610 static void float2byteGeneric(float[] input, int inOffset,
611 byte[] output, int outByteOffset, int outByteStep,
612 int sampleCount, int formatType, float ditherBits) {
613 //if (TDebug.TraceAudioConverter) {
614 // TDebug.out("FloatSampleBuffer.float2byteGeneric, formatType="
615 // +"formatType2Str(formatType));
616 //}
617
618 if (inOffset < 0
619 || inOffset + sampleCount > input.length
620 || sampleCount < 0) {
621 throw new IllegalArgumentException("invalid input index: "
622 +"input.length="+input.length
623 +" inOffset="+inOffset
624 +" sampleCount="+sampleCount);
625 }
626 if (outByteOffset < 0
627 || outByteOffset + (sampleCount * outByteStep) > output.length
628 || outByteStep < getSampleSize(formatType)) {
629 throw new IllegalArgumentException("invalid output index: "
630 +"output.length="+output.length
631 +" outByteOffset="+outByteOffset
632 +" sampleCount="+sampleCount
633 +" format="+formatType2Str(formatType));
634 }
635
636 if (ditherBits!=0.0f && random==null) {
637 // create the random number generator for dithering
638 random=new Random();
639 }
640 int endSample = inOffset + sampleCount;
641 int iSample;
642 int outIndex = outByteOffset;
643 for (int inIndex = inOffset;
644 inIndex < endSample;
645 inIndex++, outIndex+=outByteStep) {
646 // do conversion
647 switch (formatType) {
648 case CT_8S:
649 output[outIndex]=quantize8(input[inIndex]*twoPower7, ditherBits);
650 break;
651 case CT_8U:
652 output[outIndex]=(byte) (quantize8((input[inIndex]*twoPower7), ditherBits)+128);
653 break;
654 case CT_16SB:
655 iSample=quantize16(input[inIndex]*twoPower15, ditherBits);
656 output[outIndex]=(byte) (iSample >> 8);
657 output[outIndex+1]=(byte) (iSample & 0xFF);
658 break;
659 case CT_16SL:
660 iSample=quantize16(input[inIndex]*twoPower15, ditherBits);
661 output[outIndex+1]=(byte) (iSample >> 8);
662 output[outIndex]=(byte) (iSample & 0xFF);
663 break;
664 case CT_24SB:
665 iSample=quantize24(input[inIndex]*twoPower23, ditherBits);
666 output[outIndex]=(byte) (iSample >> 16);
667 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
668 output[outIndex+2]=(byte) (iSample & 0xFF);
669 break;
670 case CT_24SL:
671 iSample=quantize24(input[inIndex]*twoPower23, ditherBits);
672 output[outIndex+2]=(byte) (iSample >> 16);
673 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
674 output[outIndex]=(byte) (iSample & 0xFF);
675 break;
676 case CT_32SB:
677 iSample=quantize32(input[inIndex]*twoPower31, ditherBits);
678 output[outIndex]=(byte) (iSample >> 24);
679 output[outIndex+1]=(byte) ((iSample >>> 16) & 0xFF);
680 output[outIndex+2]=(byte) ((iSample >>> 8) & 0xFF);
681 output[outIndex+3]=(byte) (iSample & 0xFF);
682 break;
683 case CT_32SL:
684 iSample=quantize32(input[inIndex]*twoPower31, ditherBits);
685 output[outIndex+3]=(byte) (iSample >> 24);
686 output[outIndex+2]=(byte) ((iSample >>> 16) & 0xFF);
687 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
688 output[outIndex]=(byte) (iSample & 0xFF);
689 break;
690 default:
691 throw new IllegalArgumentException
692 ("unsupported format="+formatType2Str(formatType));
693 }
694 }
695 }
696}
diff --git a/songdbj/org/tritonus/share/sampled/TAudioFormat.java b/songdbj/org/tritonus/share/sampled/TAudioFormat.java
new file mode 100644
index 0000000000..7911d5e005
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/TAudioFormat.java
@@ -0,0 +1,110 @@
1/*
2 * TAudioFormat.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2003 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31import java.util.Collections;
32import java.util.HashMap;
33import java.util.Map;
34
35import javax.sound.sampled.AudioFormat;
36
37
38
39public class TAudioFormat
40extends AudioFormat
41{
42 private Map<String, Object> m_properties;
43 private Map<String, Object> m_unmodifiableProperties;
44
45
46 public TAudioFormat(AudioFormat.Encoding encoding,
47 float sampleRate,
48 int sampleSizeInBits,
49 int channels,
50 int frameSize,
51 float frameRate,
52 boolean bigEndian,
53 Map<String, Object> properties)
54 {
55 super(encoding,
56 sampleRate,
57 sampleSizeInBits,
58 channels,
59 frameSize,
60 frameRate,
61 bigEndian);
62 initMaps(properties);
63 }
64
65
66 public TAudioFormat(float sampleRate,
67 int sampleSizeInBits,
68 int channels,
69 boolean signed,
70 boolean bigEndian,
71 Map<String, Object> properties)
72 {
73 super(sampleRate,
74 sampleSizeInBits,
75 channels,
76 signed,
77 bigEndian);
78 initMaps(properties);
79 }
80
81
82
83 private void initMaps(Map<String, Object> properties)
84 {
85 /* Here, we make a shallow copy of the map. It's unclear if this
86 is sufficient (or if a deep copy should be made).
87 */
88 m_properties = new HashMap<String, Object>();
89 m_properties.putAll(properties);
90 m_unmodifiableProperties = Collections.unmodifiableMap(m_properties);
91 }
92
93
94
95 public Map<String, Object> properties()
96 {
97 return m_unmodifiableProperties;
98 }
99
100
101
102 protected void setProperty(String key, Object value)
103 {
104 m_properties.put(key, value);
105 }
106}
107
108
109
110/*** TAudioFormat.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/TConversionTool.java b/songdbj/org/tritonus/share/sampled/TConversionTool.java
new file mode 100644
index 0000000000..18673edf31
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/TConversionTool.java
@@ -0,0 +1,1224 @@
1/*
2 * TConversionTool.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled;
33
34
35/**
36 * Useful methods for converting audio data.
37 *
38 * @author Florian Bomers
39 * @author Matthias Pfisterer
40 */
41
42/*
43For convenience, a list of available methods is maintained here.
44Some hints:
45- buffers: always byte arrays
46- offsets: always in bytes
47- sampleCount: number of SAMPLES to read/write, as opposed to FRAMES or BYTES!
48- when in buffer and out buffer are given, the data is copied,
49 otherwise it is replaced in the same buffer (buffer size is not checked!)
50- a number (except "2") gives the number of bits in which format
51 the samples have to be.
52- >8 bits per sample is always treated signed.
53- all functions are tried to be optimized - hints welcome !
54
55
56** "high level" methods **
57changeOrderOrSign(buffer, nOffset, nByteLength, nBytesPerSample)
58changeOrderOrSign(inBuffer, nInOffset, outBuffer, nOutOffset, nByteLength, nBytesPerSample)
59
60
61** PCM byte order and sign conversion **
62void convertSign8(buffer, byteOffset, sampleCount)
63void swapOrder16(buffer, byteOffset, sampleCount)
64void swapOrder24(buffer, byteOffset, sampleCount)
65void swapOrder32(buffer, byteOffset, sampleCount)
66void convertSign8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
67void swapOrder16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
68void swapOrder24(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
69void swapOrder32(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
70
71
72** conversion functions for byte arrays **
73** these are for reference to see how to implement these conversions **
74short bytesToShort16(highByte, lowByte)
75short bytesToShort16(buffer, byteOffset, bigEndian)
76short bytesToInt16(highByte, lowByte)
77short bytesToInt16(buffer, byteOffset, bigEndian)
78short bytesToInt24(buffer, byteOffset, bigEndian)
79short bytesToInt32(buffer, byteOffset, bigEndian)
80void shortToBytes16(sample, buffer, byteOffset, bigEndian)
81void intToBytes24(sample, buffer, byteOffset, bigEndian)
82void intToBytes32(sample, buffer, byteOffset, bigEndian)
83
84
85** ULAW <-> PCM **
86byte linear2ulaw(int sample)
87short ulaw2linear(int ulawbyte)
88void pcm162ulaw(buffer, byteOffset, sampleCount, bigEndian)
89void pcm162ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
90void pcm82ulaw(buffer, byteOffset, sampleCount, signed)
91void pcm82ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
92void ulaw2pcm16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
93void ulaw2pcm8(buffer, byteOffset, sampleCount, signed)
94void ulaw2pcm8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
95
96
97** ALAW <-> PCM **
98byte linear2alaw(short pcm_val)
99short alaw2linear(byte ulawbyte)
100void pcm162alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
101void pcm162alaw(buffer, byteOffset, sampleCount, bigEndian)
102void pcm82alaw(buffer, byteOffset, sampleCount, signed)
103void pcm82alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
104void alaw2pcm16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
105void alaw2pcm8(buffer, byteOffset, sampleCount, signed)
106void alaw2pcm8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
107
108
109** ULAW <-> ALAW **
110byte ulaw2alaw(byte sample)
111void ulaw2alaw(buffer, byteOffset, sampleCount)
112void ulaw2alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
113byte alaw2ulaw(byte sample)
114void alaw2ulaw(buffer, byteOffset, sampleCount)
115void alaw2ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
116
117*/
118
119public class TConversionTool {
120
121 ///////////////// sign/byte-order conversion ///////////////////////////////////
122
123 public static void convertSign8(byte[] buffer, int byteOffset, int sampleCount) {
124 sampleCount+=byteOffset;
125 for (int i=byteOffset; i<sampleCount; i++) {
126 buffer[i]+=128;
127 }
128 }
129
130 public static void swapOrder16(byte[] buffer, int byteOffset, int sampleCount) {
131 int byteMax=sampleCount*2+byteOffset-1;
132 int i=byteOffset;
133 while (i<byteMax) {
134 byte h=buffer[i];
135 buffer[i]=buffer[++i];
136 buffer[i++]=h;
137 }
138 }
139
140 public static void swapOrder24(byte[] buffer, int byteOffset, int sampleCount) {
141 int byteMax=sampleCount*3+byteOffset-2;
142 int i=byteOffset;
143 while (i<byteMax) {
144 byte h=buffer[i];
145 buffer[i]=buffer[++i+1];
146 buffer[++i]=h;
147 i++;
148 }
149 }
150
151 public static void swapOrder32(byte[] buffer, int byteOffset, int sampleCount) {
152 int byteMax=sampleCount*4+byteOffset-3;
153 int i=byteOffset;
154 while (i<byteMax) {
155 byte h=buffer[i];
156 buffer[i]=buffer[i+3];
157 buffer[i+3]=h;
158 i++;
159 h=buffer[i];
160 buffer[i]=buffer[++i];
161 buffer[i++]=h;
162 i++;
163 }
164 }
165
166 public static void convertSign8(byte[] inBuffer, int inByteOffset,
167 byte[] outBuffer, int outByteOffset, int sampleCount) {
168 while (sampleCount>0) {
169 outBuffer[outByteOffset++]=(byte)(inBuffer[inByteOffset++]+128);
170 sampleCount--;
171 }
172 }
173
174 public static void swapOrder16(byte[] inBuffer, int inByteOffset,
175 byte[] outBuffer, int outByteOffset, int sampleCount) {
176 while (sampleCount>0) {
177 outBuffer[outByteOffset++]=inBuffer[inByteOffset+1];
178 outBuffer[outByteOffset++]=inBuffer[inByteOffset++];
179 inByteOffset++;
180 sampleCount--;
181 }
182 }
183
184 public static void swapOrder24(byte[] inBuffer, int inByteOffset,
185 byte[] outBuffer, int outByteOffset, int sampleCount) {
186 while (sampleCount>0) {
187 outBuffer[outByteOffset++]=inBuffer[inByteOffset+2];
188 outByteOffset++;
189 outBuffer[outByteOffset++]=inBuffer[inByteOffset++];
190 inByteOffset++;
191 inByteOffset++;
192 sampleCount--;
193 }
194 }
195
196 public static void swapOrder32(byte[] inBuffer, int inByteOffset,
197 byte[] outBuffer, int outByteOffset, int sampleCount) {
198 while (sampleCount>0) {
199 outBuffer[outByteOffset++]=inBuffer[inByteOffset+3];
200 outBuffer[outByteOffset++]=inBuffer[inByteOffset+2];
201 outBuffer[outByteOffset++]=inBuffer[inByteOffset+1];
202 outBuffer[outByteOffset++]=inBuffer[inByteOffset++];
203 inByteOffset++;
204 inByteOffset++;
205 inByteOffset++;
206 sampleCount--;
207 }
208 }
209
210
211 ///////////////// conversion functions for byte arrays ////////////////////////////
212
213
214 /**
215 * Converts 2 bytes to a signed sample of type <code>short</code>.
216 * <p> This is a reference function.
217 */
218 public static short bytesToShort16(byte highByte, byte lowByte) {
219 return (short) ((highByte<<8) | (lowByte & 0xFF));
220 }
221
222 /**
223 * Converts 2 successive bytes starting at <code>byteOffset</code> in
224 * <code>buffer</code> to a signed sample of type <code>short</code>.
225 * <p>
226 * For little endian, buffer[byteOffset] is interpreted as low byte,
227 * whereas it is interpreted as high byte in big endian.
228 * <p> This is a reference function.
229 */
230 public static short bytesToShort16(byte[] buffer, int byteOffset, boolean bigEndian) {
231 return bigEndian?
232 ((short) ((buffer[byteOffset]<<8) | (buffer[byteOffset+1] & 0xFF))):
233 ((short) ((buffer[byteOffset+1]<<8) | (buffer[byteOffset] & 0xFF)));
234 }
235
236 /**
237 * Converts 2 bytes to a signed integer sample with 16bit range.
238 * <p> This is a reference function.
239 */
240 public static int bytesToInt16(byte highByte, byte lowByte) {
241 return (highByte<<8) | (lowByte & 0xFF);
242 }
243
244 /**
245 * Converts 2 successive bytes starting at <code>byteOffset</code> in
246 * <code>buffer</code> to a signed integer sample with 16bit range.
247 * <p>
248 * For little endian, buffer[byteOffset] is interpreted as low byte,
249 * whereas it is interpreted as high byte in big endian.
250 * <p> This is a reference function.
251 */
252 public static int bytesToInt16(byte[] buffer, int byteOffset, boolean bigEndian) {
253 return bigEndian?
254 ((buffer[byteOffset]<<8) | (buffer[byteOffset+1] & 0xFF)):
255 ((buffer[byteOffset+1]<<8) | (buffer[byteOffset] & 0xFF));
256 }
257
258 /**
259 * Converts 3 successive bytes starting at <code>byteOffset</code> in
260 * <code>buffer</code> to a signed integer sample with 24bit range.
261 * <p>
262 * For little endian, buffer[byteOffset] is interpreted as lowest byte,
263 * whereas it is interpreted as highest byte in big endian.
264 * <p> This is a reference function.
265 */
266 public static int bytesToInt24(byte[] buffer, int byteOffset, boolean bigEndian) {
267 return bigEndian?
268 ((buffer[byteOffset]<<16) // let Java handle sign-bit
269 | ((buffer[byteOffset+1] & 0xFF)<<8) // inhibit sign-bit handling
270 | (buffer[byteOffset+2] & 0xFF)):
271 ((buffer[byteOffset+2]<<16) // let Java handle sign-bit
272 | ((buffer[byteOffset+1] & 0xFF)<<8) // inhibit sign-bit handling
273 | (buffer[byteOffset] & 0xFF));
274 }
275
276 /**
277 * Converts a 4 successive bytes starting at <code>byteOffset</code> in
278 * <code>buffer</code> to a signed 32bit integer sample.
279 * <p>
280 * For little endian, buffer[byteOffset] is interpreted as lowest byte,
281 * whereas it is interpreted as highest byte in big endian.
282 * <p> This is a reference function.
283 */
284 public static int bytesToInt32(byte[] buffer, int byteOffset, boolean bigEndian) {
285 return bigEndian?
286 ((buffer[byteOffset]<<24) // let Java handle sign-bit
287 | ((buffer[byteOffset+1] & 0xFF)<<16) // inhibit sign-bit handling
288 | ((buffer[byteOffset+2] & 0xFF)<<8) // inhibit sign-bit handling
289 | (buffer[byteOffset+3] & 0xFF)):
290 ((buffer[byteOffset+3]<<24) // let Java handle sign-bit
291 | ((buffer[byteOffset+2] & 0xFF)<<16) // inhibit sign-bit handling
292 | ((buffer[byteOffset+1] & 0xFF)<<8) // inhibit sign-bit handling
293 | (buffer[byteOffset] & 0xFF));
294 }
295
296
297 /**
298 * Converts a sample of type <code>short</code> to 2 bytes in an array.
299 * <code>sample</code> is interpreted as signed (as Java does).
300 * <p>
301 * For little endian, buffer[byteOffset] is filled with low byte of sample,
302 * and buffer[byteOffset+1] is filled with high byte of sample.
303 * <p> For big endian, this is reversed.
304 * <p> This is a reference function.
305 */
306 public static void shortToBytes16(short sample, byte[] buffer, int byteOffset, boolean bigEndian) {
307 intToBytes16(sample, buffer, byteOffset, bigEndian);
308 }
309
310 /**
311 * Converts a 16 bit sample of type <code>int</code> to 2 bytes in an array.
312 * <code>sample</code> is interpreted as signed (as Java does).
313 * <p>
314 * For little endian, buffer[byteOffset] is filled with low byte of sample,
315 * and buffer[byteOffset+1] is filled with high byte of sample + sign bit.
316 * <p> For big endian, this is reversed.
317 * <p> Before calling this function, it should be assured that <code>sample</code>
318 * is in the 16bit range - it will not be clipped.
319 * <p> This is a reference function.
320 */
321 public static void intToBytes16(int sample, byte[] buffer, int byteOffset, boolean bigEndian) {
322 if (bigEndian) {
323 buffer[byteOffset++]=(byte) (sample >> 8);
324 buffer[byteOffset]=(byte) (sample & 0xFF);
325 } else {
326 buffer[byteOffset++]=(byte) (sample & 0xFF);
327 buffer[byteOffset]=(byte) (sample >> 8);
328 }
329 }
330
331 /**
332 * Converts a 24 bit sample of type <code>int</code> to 3 bytes in an array.
333 * <code>sample</code> is interpreted as signed (as Java does).
334 * <p>
335 * For little endian, buffer[byteOffset] is filled with low byte of sample,
336 * and buffer[byteOffset+2] is filled with the high byte of sample + sign bit.
337 * <p> For big endian, this is reversed.
338 * <p> Before calling this function, it should be assured that <code>sample</code>
339 * is in the 24bit range - it will not be clipped.
340 * <p> This is a reference function.
341 */
342 public static void intToBytes24(int sample, byte[] buffer, int byteOffset, boolean bigEndian) {
343 if (bigEndian) {
344 buffer[byteOffset++]=(byte) (sample >> 16);
345 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
346 buffer[byteOffset]=(byte) (sample & 0xFF);
347 } else {
348 buffer[byteOffset++]=(byte) (sample & 0xFF);
349 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
350 buffer[byteOffset]=(byte) (sample >> 16);
351 }
352 }
353
354
355 /**
356 * Converts a 32 bit sample of type <code>int</code> to 4 bytes in an array.
357 * <code>sample</code> is interpreted as signed (as Java does).
358 * <p>
359 * For little endian, buffer[byteOffset] is filled with lowest byte of sample,
360 * and buffer[byteOffset+3] is filled with the high byte of sample + sign bit.
361 * <p> For big endian, this is reversed.
362 * <p> This is a reference function.
363 */
364 public static void intToBytes32(int sample, byte[] buffer, int byteOffset, boolean bigEndian) {
365 if (bigEndian) {
366 buffer[byteOffset++]=(byte) (sample >> 24);
367 buffer[byteOffset++]=(byte) ((sample >>> 16) & 0xFF);
368 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
369 buffer[byteOffset]=(byte) (sample & 0xFF);
370 } else {
371 buffer[byteOffset++]=(byte) (sample & 0xFF);
372 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
373 buffer[byteOffset++]=(byte) ((sample >>> 16) & 0xFF);
374 buffer[byteOffset]=(byte) (sample >> 24);
375 }
376 }
377
378
379 /////////////////////// ULAW ///////////////////////////////////////////
380
381 private static final boolean ZEROTRAP=true;
382 private static final short BIAS=0x84;
383 private static final int CLIP=32635;
384 private static final int exp_lut1[] ={
385 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
386 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
387 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
388 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
389 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
390 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
391 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
392 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
393 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
394 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
395 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
396 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
397 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
398 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
399 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
400 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
401 };
402
403
404 /**
405 * Converts a linear signed 16bit sample to a uLaw byte.
406 * Ported to Java by fb.
407 * <BR>Originally by:<BR>
408 * Craig Reese: IDA/Supercomputing Research Center <BR>
409 * Joe Campbell: Department of Defense <BR>
410 * 29 September 1989 <BR>
411 */
412 public static byte linear2ulaw(int sample) {
413 int sign, exponent, mantissa, ulawbyte;
414
415 if (sample>32767) sample=32767;
416 else if (sample<-32768) sample=-32768;
417 /* Get the sample into sign-magnitude. */
418 sign = (sample >> 8) & 0x80; /* set aside the sign */
419 if (sign != 0) sample = -sample; /* get magnitude */
420 if (sample > CLIP) sample = CLIP; /* clip the magnitude */
421
422 /* Convert from 16 bit linear to ulaw. */
423 sample = sample + BIAS;
424 exponent = exp_lut1[(sample >> 7) & 0xFF];
425 mantissa = (sample >> (exponent + 3)) & 0x0F;
426 ulawbyte = ~(sign | (exponent << 4) | mantissa);
427 if (ZEROTRAP)
428 if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */
429 return((byte) ulawbyte);
430 }
431
432 /* u-law to linear conversion table */
433 private static short[] u2l = {
434 -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
435 -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
436 -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
437 -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
438 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
439 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
440 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
441 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
442 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
443 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
444 -876, -844, -812, -780, -748, -716, -684, -652,
445 -620, -588, -556, -524, -492, -460, -428, -396,
446 -372, -356, -340, -324, -308, -292, -276, -260,
447 -244, -228, -212, -196, -180, -164, -148, -132,
448 -120, -112, -104, -96, -88, -80, -72, -64,
449 -56, -48, -40, -32, -24, -16, -8, 0,
450 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
451 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
452 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
453 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
454 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
455 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
456 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
457 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
458 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
459 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
460 876, 844, 812, 780, 748, 716, 684, 652,
461 620, 588, 556, 524, 492, 460, 428, 396,
462 372, 356, 340, 324, 308, 292, 276, 260,
463 244, 228, 212, 196, 180, 164, 148, 132,
464 120, 112, 104, 96, 88, 80, 72, 64,
465 56, 48, 40, 32, 24, 16, 8, 0
466 };
467 public static short ulaw2linear(byte ulawbyte) {
468 return u2l[ulawbyte & 0xFF];
469 }
470
471
472
473 /**
474 * Converts a buffer of signed 16bit big endian samples to uLaw.
475 * The uLaw bytes overwrite the original 16 bit values.
476 * The first byte-offset of the uLaw bytes is byteOffset.
477 * It will be written sampleCount/2 bytes.
478 */
479 public static void pcm162ulaw(byte[] buffer, int byteOffset, int sampleCount, boolean bigEndian) {
480 int shortIndex=byteOffset;
481 int ulawIndex=shortIndex;
482 if (bigEndian) {
483 while (sampleCount>0) {
484 buffer[ulawIndex++]=linear2ulaw
485 (bytesToInt16(buffer[shortIndex], buffer[shortIndex+1]));
486 shortIndex++;
487 shortIndex++;
488 sampleCount--;
489 }
490 } else {
491 while (sampleCount>0) {
492 buffer[ulawIndex++]=linear2ulaw
493 (bytesToInt16(buffer[shortIndex+1], buffer[shortIndex]));
494 shortIndex++;
495 shortIndex++;
496 sampleCount--;
497 }
498 }
499 }
500
501 /**
502 * Fills outBuffer with ulaw samples.
503 * reading starts from inBuffer[inByteOffset].
504 * writing starts at outBuffer[outByteOffset].
505 * There will be sampleCount*2 bytes read from inBuffer;
506 * There will be sampleCount <B>bytes</B> written to outBuffer.
507 */
508 public static void pcm162ulaw(byte[] inBuffer, int inByteOffset,
509 byte[] outBuffer, int outByteOffset,
510 int sampleCount, boolean bigEndian) {
511 int shortIndex=inByteOffset;
512 int ulawIndex=outByteOffset;
513 if (bigEndian) {
514 while (sampleCount>0) {
515 outBuffer[ulawIndex++]=linear2ulaw
516 (bytesToInt16(inBuffer[shortIndex], inBuffer[shortIndex+1]));
517 shortIndex++;
518 shortIndex++;
519 sampleCount--;
520 }
521 } else {
522 while (sampleCount>0) {
523 outBuffer[ulawIndex++]=linear2ulaw
524 (bytesToInt16(inBuffer[shortIndex+1], inBuffer[shortIndex]));
525 shortIndex++;
526 shortIndex++;
527 sampleCount--;
528 }
529 }
530 }
531
532 // TODO: either direct 8bit pcm to ulaw, or better conversion from 8bit to 16bit
533 /**
534 * Converts a buffer of 8bit samples to uLaw.
535 * The uLaw bytes overwrite the original 8 bit values.
536 * The first byte-offset of the uLaw bytes is byteOffset.
537 * It will be written sampleCount bytes.
538 */
539 public static void pcm82ulaw(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
540 sampleCount+=byteOffset;
541 if (signed) {
542 for (int i=byteOffset; i<sampleCount; i++) {
543 buffer[i]=linear2ulaw(buffer[i] << 8);
544 }
545 } else {
546 for (int i=byteOffset; i<sampleCount; i++) {
547 buffer[i]=linear2ulaw(((byte) (buffer[i]+128)) << 8);
548 }
549 }
550 }
551
552 /**
553 * Fills outBuffer with ulaw samples.
554 * reading starts from inBuffer[inByteOffset].
555 * writing starts at outBuffer[outByteOffset].
556 * There will be sampleCount <B>bytes</B> written to outBuffer.
557 */
558 public static void pcm82ulaw(byte[] inBuffer, int inByteOffset,
559 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
560 int ulawIndex=outByteOffset;
561 int pcmIndex=inByteOffset;
562 if (signed) {
563 while (sampleCount>0) {
564 outBuffer[ulawIndex++]=linear2ulaw(inBuffer[pcmIndex++] << 8);
565 sampleCount--;
566 }
567 } else {
568 while (sampleCount>0) {
569 outBuffer[ulawIndex++]=linear2ulaw(((byte) (inBuffer[pcmIndex++]+128)) << 8);
570 sampleCount--;
571 }
572 }
573 }
574
575 /**
576 * Fills outBuffer with pcm signed 16 bit samples.
577 * reading starts from inBuffer[inByteOffset].
578 * writing starts at outBuffer[outByteOffset].
579 * There will be sampleCount bytes read from inBuffer;
580 * There will be sampleCount*2 bytes written to outBuffer.
581 */
582 public static void ulaw2pcm16(byte[] inBuffer, int inByteOffset,
583 byte[] outBuffer, int outByteOffset,
584 int sampleCount, boolean bigEndian) {
585 int shortIndex=outByteOffset;
586 int ulawIndex=inByteOffset;
587 while (sampleCount>0) {
588 intToBytes16
589 (u2l[inBuffer[ulawIndex++] & 0xFF], outBuffer, shortIndex++, bigEndian);
590 shortIndex++;
591 sampleCount--;
592 }
593 }
594
595
596 // TODO: either direct 8bit pcm to ulaw, or better conversion from 8bit to 16bit
597 /**
598 * Inplace-conversion of a ulaw buffer to 8bit samples.
599 * The 8bit bytes overwrite the original ulaw values.
600 * The first byte-offset of the uLaw bytes is byteOffset.
601 * It will be written sampleCount bytes.
602 */
603 public static void ulaw2pcm8(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
604 sampleCount+=byteOffset;
605 if (signed) {
606 for (int i=byteOffset; i<sampleCount; i++) {
607 buffer[i]=(byte) ((u2l[buffer[i] & 0xFF] >> 8) & 0xFF);
608 }
609 } else {
610 for (int i=byteOffset; i<sampleCount; i++) {
611 buffer[i]=(byte) ((u2l[buffer[i] & 0xFF]>>8)+128);
612 }
613 }
614 }
615
616 /**
617 * Fills outBuffer with ulaw samples.
618 * reading starts from inBuffer[inByteOffset].
619 * writing starts at outBuffer[outByteOffset].
620 * There will be sampleCount <B>bytes</B> written to outBuffer.
621 */
622 public static void ulaw2pcm8(byte[] inBuffer, int inByteOffset,
623 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
624 int ulawIndex=inByteOffset;
625 int pcmIndex=outByteOffset;
626 if (signed) {
627 while (sampleCount>0) {
628 outBuffer[pcmIndex++]=
629 (byte) ((u2l[inBuffer[ulawIndex++] & 0xFF] >> 8) & 0xFF);
630 sampleCount--;
631 }
632 } else {
633 while (sampleCount>0) {
634 outBuffer[pcmIndex++]=
635 (byte) ((u2l[inBuffer[ulawIndex++] & 0xFF]>>8)+128);
636 sampleCount--;
637 }
638 }
639 }
640
641
642 //////////////////// ALAW ////////////////////////////
643
644
645 /*
646 * This source code is a product of Sun Microsystems, Inc. and is provided
647 * for unrestricted use. Users may copy or modify this source code without
648 * charge.
649 *
650 * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
651 *
652 * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
653 *
654 * Linear Input Code Compressed Code
655 * ------------------------ ---------------
656 * 0000000wxyza 000wxyz
657 * 0000001wxyza 001wxyz
658 * 000001wxyzab 010wxyz
659 * 00001wxyzabc 011wxyz
660 * 0001wxyzabcd 100wxyz
661 * 001wxyzabcde 101wxyz
662 * 01wxyzabcdef 110wxyz
663 * 1wxyzabcdefg 111wxyz
664 *
665 * For further information see John C. Bellamy's Digital Telephony, 1982,
666 * John Wiley & Sons, pps 98-111 and 472-476.
667 */
668 private static final byte QUANT_MASK = 0xf; /* Quantization field mask. */
669 private static final byte SEG_SHIFT = 4; /* Left shift for segment number. */
670 private static final short[] seg_end = {
671 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
672 };
673
674 public static byte linear2alaw(short pcm_val) /* 2's complement (16-bit range) */
675 {
676 byte mask;
677 byte seg=8;
678 byte aval;
679
680 if (pcm_val >= 0) {
681 mask = (byte) 0xD5; /* sign (7th) bit = 1 */
682 } else {
683 mask = 0x55; /* sign bit = 0 */
684 pcm_val = (short) (-pcm_val - 8);
685 }
686
687 /* Convert the scaled magnitude to segment number. */
688 for (int i = 0; i < 8; i++) {
689 if (pcm_val <= seg_end[i]) {
690 seg=(byte) i;
691 break;
692 }
693 }
694
695 /* Combine the sign, segment, and quantization bits. */
696 if (seg >= 8) /* out of range, return maximum value. */
697 return (byte) ((0x7F ^ mask) & 0xFF);
698 else {
699 aval = (byte) (seg << SEG_SHIFT);
700 if (seg < 2)
701 aval |= (pcm_val >> 4) & QUANT_MASK;
702 else
703 aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
704 return (byte) ((aval ^ mask) & 0xFF);
705 }
706 }
707
708 private static short[] a2l = {
709 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
710 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
711 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
712 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
713 -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
714 -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
715 -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
716 -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
717 -344, -328, -376, -360, -280, -264, -312, -296,
718 -472, -456, -504, -488, -408, -392, -440, -424,
719 -88, -72, -120, -104, -24, -8, -56, -40,
720 -216, -200, -248, -232, -152, -136, -184, -168,
721 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
722 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
723 -688, -656, -752, -720, -560, -528, -624, -592,
724 -944, -912, -1008, -976, -816, -784, -880, -848,
725 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
726 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
727 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
728 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
729 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
730 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
731 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
732 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
733 344, 328, 376, 360, 280, 264, 312, 296,
734 472, 456, 504, 488, 408, 392, 440, 424,
735 88, 72, 120, 104, 24, 8, 56, 40,
736 216, 200, 248, 232, 152, 136, 184, 168,
737 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
738 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
739 688, 656, 752, 720, 560, 528, 624, 592,
740 944, 912, 1008, 976, 816, 784, 880, 848
741 };
742
743 public static short alaw2linear(byte ulawbyte) {
744 return a2l[ulawbyte & 0xFF];
745 }
746
747 /**
748 * Converts a buffer of signed 16bit big endian samples to uLaw.
749 * The uLaw bytes overwrite the original 16 bit values.
750 * The first byte-offset of the uLaw bytes is byteOffset.
751 * It will be written sampleCount/2 bytes.
752 */
753 public static void pcm162alaw(byte[] buffer, int byteOffset, int sampleCount, boolean bigEndian) {
754 int shortIndex=byteOffset;
755 int alawIndex=shortIndex;
756 if (bigEndian) {
757 while (sampleCount>0) {
758 buffer[alawIndex++]=
759 linear2alaw(bytesToShort16
760 (buffer[shortIndex], buffer[shortIndex+1]));
761 shortIndex++;
762 shortIndex++;
763 sampleCount--;
764 }
765 } else {
766 while (sampleCount>0) {
767 buffer[alawIndex++]=
768 linear2alaw(bytesToShort16
769 (buffer[shortIndex+1], buffer[shortIndex]));
770 shortIndex++;
771 shortIndex++;
772 sampleCount--;
773 }
774 }
775 }
776
777 /**
778 * Fills outBuffer with alaw samples.
779 * reading starts from inBuffer[inByteOffset].
780 * writing starts at outBuffer[outByteOffset].
781 * There will be sampleCount*2 bytes read from inBuffer;
782 * There will be sampleCount <B>bytes</B> written to outBuffer.
783 */
784 public static void pcm162alaw(byte[] inBuffer, int inByteOffset,
785 byte[] outBuffer, int outByteOffset, int sampleCount, boolean bigEndian) {
786 int shortIndex=inByteOffset;
787 int alawIndex=outByteOffset;
788 if (bigEndian) {
789 while (sampleCount>0) {
790 outBuffer[alawIndex++]=linear2alaw
791 (bytesToShort16(inBuffer[shortIndex], inBuffer[shortIndex+1]));
792 shortIndex++;
793 shortIndex++;
794 sampleCount--;
795 }
796 } else {
797 while (sampleCount>0) {
798 outBuffer[alawIndex++]=linear2alaw
799 (bytesToShort16(inBuffer[shortIndex+1], inBuffer[shortIndex]));
800 shortIndex++;
801 shortIndex++;
802 sampleCount--;
803 }
804 }
805 }
806
807 /**
808 * Converts a buffer of 8bit samples to alaw.
809 * The alaw bytes overwrite the original 8 bit values.
810 * The first byte-offset of the aLaw bytes is byteOffset.
811 * It will be written sampleCount bytes.
812 */
813 public static void pcm82alaw(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
814 sampleCount+=byteOffset;
815 if (signed) {
816 for (int i=byteOffset; i<sampleCount; i++) {
817 buffer[i]=linear2alaw((short) (buffer[i] << 8));
818 }
819 } else {
820 for (int i=byteOffset; i<sampleCount; i++) {
821 buffer[i]=linear2alaw((short) (((byte) (buffer[i]+128)) << 8));
822 }
823 }
824 }
825
826 /**
827 * Fills outBuffer with alaw samples.
828 * reading starts from inBuffer[inByteOffset].
829 * writing starts at outBuffer[outByteOffset].
830 * There will be sampleCount <B>bytes</B> written to outBuffer.
831 */
832 public static void pcm82alaw(byte[] inBuffer, int inByteOffset,
833 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
834 int alawIndex=outByteOffset;
835 int pcmIndex=inByteOffset;
836 if (signed) {
837 while (sampleCount>0) {
838 outBuffer[alawIndex++]=
839 linear2alaw((short) (inBuffer[pcmIndex++] << 8));
840 sampleCount--;
841 }
842 } else {
843 while (sampleCount>0) {
844 outBuffer[alawIndex++]=
845 linear2alaw((short) (((byte) (inBuffer[pcmIndex++]+128)) << 8));
846 sampleCount--;
847 }
848 }
849 }
850
851
852
853 /**
854 * Converts an alaw buffer to 8bit pcm samples
855 * The 8bit bytes overwrite the original alaw values.
856 * The first byte-offset of the aLaw bytes is byteOffset.
857 * It will be written sampleCount bytes.
858 */
859 public static void alaw2pcm8(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
860 sampleCount+=byteOffset;
861 if (signed) {
862 for (int i=byteOffset; i<sampleCount; i++) {
863 buffer[i]=(byte) ((a2l[buffer[i] & 0xFF] >> 8) & 0xFF);
864 }
865 } else {
866 for (int i=byteOffset; i<sampleCount; i++) {
867 buffer[i]=(byte) ((a2l[buffer[i] & 0xFF]>>8)+128);
868 }
869 }
870 }
871
872 /**
873 * Fills outBuffer with alaw samples.
874 * reading starts from inBuffer[inByteOffset].
875 * writing starts at outBuffer[outByteOffset].
876 * There will be sampleCount <B>bytes</B> written to outBuffer.
877 */
878 public static void alaw2pcm8(byte[] inBuffer, int inByteOffset,
879 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
880 int alawIndex=inByteOffset;
881 int pcmIndex=outByteOffset;
882 if (signed) {
883 while (sampleCount>0) {
884 outBuffer[pcmIndex++]=
885 (byte) ((a2l[inBuffer[alawIndex++] & 0xFF] >> 8) & 0xFF);
886 sampleCount--;
887 }
888 } else {
889 while (sampleCount>0) {
890 outBuffer[pcmIndex++]=
891 (byte) ((a2l[inBuffer[alawIndex++] & 0xFF]>>8)+128);
892 sampleCount--;
893 }
894 }
895 }
896
897 /**
898 * Fills outBuffer with pcm signed 16 bit samples.
899 * reading starts from inBuffer[inByteOffset].
900 * writing starts at outBuffer[outByteOffset].
901 * There will be sampleCount bytes read from inBuffer;
902 * There will be sampleCount*2 bytes written to outBuffer.
903 */
904 public static void alaw2pcm16(byte[] inBuffer, int inByteOffset,
905 byte[] outBuffer, int outByteOffset,
906 int sampleCount, boolean bigEndian) {
907 int shortIndex=outByteOffset;
908 int alawIndex=inByteOffset;
909 while (sampleCount>0) {
910 intToBytes16
911 (a2l[inBuffer[alawIndex++] & 0xFF], outBuffer, shortIndex++, bigEndian);
912 shortIndex++;
913 sampleCount--;
914 }
915 }
916
917 //////////////////////// cross conversion alaw <-> ulaw ////////////////////////////////////////
918
919 private static byte[] u2a = {
920 -86, -85, -88, -87, -82, -81, -84, -83, -94, -93, -96, -95, -90, -89, -92, -91,
921 -70, -69, -72, -71, -66, -65, -68, -67, -78, -77, -80, -79, -74, -73, -76, -75,
922 -118, -117, -120, -119, -114, -113, -116, -115, -126, -125, -128, -127, -122, -121, -124, -123,
923 -101, -104, -103, -98, -97, -100, -99, -110, -109, -112, -111, -106, -105, -108, -107, -22,
924 -24, -23, -18, -17, -20, -19, -30, -29, -32, -31, -26, -25, -28, -27, -6, -8,
925 -2, -1, -4, -3, -14, -13, -16, -15, -10, -9, -12, -11, -53, -55, -49, -51,
926 -62, -61, -64, -63, -58, -57, -60, -59, -38, -37, -40, -39, -34, -33, -36, -35,
927 -46, -46, -45, -45, -48, -48, -47, -47, -42, -42, -41, -41, -44, -44, -43, -43,
928 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37,
929 58, 59, 56, 57, 62, 63, 60, 61, 50, 51, 48, 49, 54, 55, 52, 53,
930 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5,
931 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21, 106,
932 104, 105, 110, 111, 108, 109, 98, 99, 96, 97, 102, 103, 100, 101, 122, 120,
933 126, 127, 124, 125, 114, 115, 112, 113, 118, 119, 116, 117, 75, 73, 79, 77,
934 66, 67, 64, 65, 70, 71, 68, 69, 90, 91, 88, 89, 94, 95, 92, 93,
935 82, 82, 83, 83, 80, 80, 81, 81, 86, 86, 87, 87, 84, 84, 85, 85,
936 };
937
938 public static byte ulaw2alaw(byte sample) {
939 return u2a[sample & 0xFF];
940 }
941
942 /**
943 * Converts a buffer of uLaw samples to aLaw.
944 */
945 public static void ulaw2alaw(byte[] buffer, int byteOffset, int sampleCount) {
946 sampleCount+=byteOffset;
947 for (int i=byteOffset; i<sampleCount; i++) {
948 buffer[i]=u2a[buffer[i] & 0xFF];
949 }
950 }
951
952 /**
953 * Fills outBuffer with alaw samples.
954 */
955 public static void ulaw2alaw(byte[] inBuffer, int inByteOffset,
956 byte[] outBuffer, int outByteOffset, int sampleCount) {
957 int ulawIndex=outByteOffset;
958 int alawIndex=inByteOffset;
959 while (sampleCount>0) {
960 outBuffer[alawIndex++]=u2a[inBuffer[ulawIndex++] & 0xFF];
961 sampleCount--;
962 }
963 }
964
965 private static byte[] a2u = {
966 -86, -85, -88, -87, -82, -81, -84, -83, -94, -93, -96, -95, -90, -89, -92, -91,
967 -71, -70, -73, -72, -67, -66, -69, -68, -79, -78, -80, -80, -75, -74, -77, -76,
968 -118, -117, -120, -119, -114, -113, -116, -115, -126, -125, -128, -127, -122, -121, -124, -123,
969 -102, -101, -104, -103, -98, -97, -100, -99, -110, -109, -112, -111, -106, -105, -108, -107,
970 -30, -29, -32, -31, -26, -25, -28, -27, -35, -35, -36, -36, -33, -33, -34, -34,
971 -12, -10, -16, -14, -4, -2, -8, -6, -22, -21, -24, -23, -18, -17, -20, -19,
972 -56, -55, -58, -57, -52, -51, -54, -53, -64, -63, -65, -65, -60, -59, -62, -61,
973 -42, -41, -44, -43, -38, -37, -40, -39, -49, -49, -50, -50, -46, -45, -48, -47,
974 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37,
975 57, 58, 55, 56, 61, 62, 59, 60, 49, 50, 48, 48, 53, 54, 51, 52,
976 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5,
977 26, 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21,
978 98, 99, 96, 97, 102, 103, 100, 101, 93, 93, 92, 92, 95, 95, 94, 94,
979 116, 118, 112, 114, 124, 126, 120, 122, 106, 107, 104, 105, 110, 111, 108, 109,
980 72, 73, 70, 71, 76, 77, 74, 75, 64, 65, 63, 63, 68, 69, 66, 67,
981 86, 87, 84, 85, 90, 91, 88, 89, 79, 79, 78, 78, 82, 83, 80, 81,
982 };
983
984 public static byte alaw2ulaw(byte sample) {
985 return a2u[sample & 0xFF];
986 }
987
988 /**
989 * Converts a buffer of aLaw samples to uLaw.
990 * The uLaw bytes overwrite the original aLaw values.
991 * The first byte-offset of the uLaw bytes is byteOffset.
992 * It will be written sampleCount bytes.
993 */
994 public static void alaw2ulaw(byte[] buffer, int byteOffset, int sampleCount) {
995 sampleCount+=byteOffset;
996 for (int i=byteOffset; i<sampleCount; i++) {
997 buffer[i]=a2u[buffer[i] & 0xFF];
998 }
999 }
1000
1001 /**
1002 * Fills outBuffer with ulaw samples.
1003 * reading starts from inBuffer[inByteOffset].
1004 * writing starts at outBuffer[outByteOffset].
1005 * There will be sampleCount <B>bytes</B> written to outBuffer.
1006 */
1007 public static void alaw2ulaw(byte[] inBuffer, int inByteOffset,
1008 byte[] outBuffer, int outByteOffset, int sampleCount) {
1009 int ulawIndex=outByteOffset;
1010 int alawIndex=inByteOffset;
1011 while (sampleCount>0) {
1012 outBuffer[ulawIndex++]=a2u[inBuffer[alawIndex++] & 0xFF];
1013 sampleCount--;
1014 }
1015 }
1016
1017
1018 //////////////////////// high level methods /////////////////////////////////////////////////
1019
1020 /*
1021 * !! Here, unlike other functions in this class, the length is
1022 * in bytes rather than samples !!
1023 */
1024 public static void changeOrderOrSign(byte[] buffer, int nOffset,
1025 int nByteLength, int nBytesPerSample) {
1026 switch (nBytesPerSample) {
1027 case 1:
1028 convertSign8(buffer, nOffset, nByteLength);
1029 break;
1030
1031 case 2:
1032 swapOrder16(buffer, nOffset, nByteLength / 2);
1033 break;
1034
1035 case 3:
1036 swapOrder24(buffer, nOffset, nByteLength / 3);
1037 break;
1038
1039 case 4:
1040 swapOrder32(buffer, nOffset, nByteLength / 4);
1041 break;
1042 }
1043 }
1044
1045
1046
1047 /*
1048 * !! Here, unlike other functions in this class, the length is
1049 * in bytes rather than samples !!
1050 */
1051 public static void changeOrderOrSign(
1052 byte[] inBuffer, int nInOffset,
1053 byte[] outBuffer, int nOutOffset,
1054 int nByteLength, int nBytesPerSample) {
1055 switch (nBytesPerSample) {
1056 case 1:
1057 convertSign8(
1058 inBuffer, nInOffset,
1059 outBuffer, nOutOffset,
1060 nByteLength);
1061 break;
1062
1063 case 2:
1064 swapOrder16(
1065 inBuffer, nInOffset,
1066 outBuffer, nOutOffset,
1067 nByteLength / 2);
1068 break;
1069
1070 case 3:
1071 swapOrder24(
1072 inBuffer, nInOffset,
1073 outBuffer, nOutOffset,
1074 nByteLength / 3);
1075 break;
1076
1077 case 4:
1078 swapOrder32(
1079 inBuffer, nInOffset,
1080 outBuffer, nOutOffset,
1081 nByteLength / 4);
1082 break;
1083 }
1084 }
1085
1086
1087 ///////////////// Annexe: how the arrays were created. //////////////////////////////////
1088
1089 /*
1090 * Converts a uLaw byte to a linear signed 16bit sample.
1091 * Ported to Java by fb.
1092 * <BR>Originally by:<BR>
1093 *
1094 * Craig Reese: IDA/Supercomputing Research Center <BR>
1095 * 29 September 1989 <BR>
1096 *
1097 * References: <BR>
1098 * <OL>
1099 * <LI>CCITT Recommendation G.711 (very difficult to follow)</LI>
1100 * <LI>MIL-STD-188-113,"Interoperability and Performance Standards
1101 * for Analog-to_Digital Conversion Techniques,"
1102 * 17 February 1987</LI>
1103 * </OL>
1104 */
1105 /*
1106 private static final int exp_lut2[] = {
1107 0,132,396,924,1980,4092,8316,16764
1108};
1109
1110 public static short _ulaw2linear(int ulawbyte) {
1111 int sign, exponent, mantissa, sample;
1112
1113 ulawbyte = ~ulawbyte;
1114 sign = (ulawbyte & 0x80);
1115 exponent = (ulawbyte >> 4) & 0x07;
1116 mantissa = ulawbyte & 0x0F;
1117 sample = exp_lut2[exponent] + (mantissa << (exponent + 3));
1118 if (sign != 0) sample = -sample;
1119 return((short) sample);
1120}*/
1121
1122
1123 /* u- to A-law conversions: copied from CCITT G.711 specifications */
1124 /*
1125 private static byte[] _u2a = {
1126 1, 1, 2, 2, 3, 3, 4, 4,
1127 5, 5, 6, 6, 7, 7, 8, 8,
1128 9, 10, 11, 12, 13, 14, 15, 16,
1129 17, 18, 19, 20, 21, 22, 23, 24,
1130 25, 27, 29, 31, 33, 34, 35, 36,
1131 37, 38, 39, 40, 41, 42, 43, 44,
1132 46, 48, 49, 50, 51, 52, 53, 54,
1133 55, 56, 57, 58, 59, 60, 61, 62,
1134 64, 65, 66, 67, 68, 69, 70, 71,
1135 72, 73, 74, 75, 76, 77, 78, 79,
1136 81, 82, 83, 84, 85, 86, 87, 88,
1137 89, 90, 91, 92, 93, 94, 95, 96,
1138 97, 98, 99, 100, 101, 102, 103, 104,
1139 105, 106, 107, 108, 109, 110, 111, 112,
1140 113, 114, 115, 116, 117, 118, 119, 120,
1141 121, 122, 123, 124, 125, 126, 127, (byte) 128};
1142 */
1143
1144 /* u-law to A-law conversion */
1145 /*
1146 * This source code is a product of Sun Microsystems, Inc. and is provided
1147 * for unrestricted use. Users may copy or modify this source code without
1148 * charge.
1149 */
1150 /*
1151 public static byte _ulaw2alaw(byte sample) {
1152 sample &= 0xff;
1153 return (byte) (((sample & 0x80)!=0) ? (0xD5 ^ (_u2a[(0x7F ^ sample) & 0x7F] - 1)) :
1154 (0x55 ^ (_u2a[(0x7F ^ sample) & 0x7F] - 1)));
1155}*/
1156
1157 /* A- to u-law conversions */
1158 /*
1159 private static byte[] _a2u = {
1160 1, 3, 5, 7, 9, 11, 13, 15,
1161 16, 17, 18, 19, 20, 21, 22, 23,
1162 24, 25, 26, 27, 28, 29, 30, 31,
1163 32, 32, 33, 33, 34, 34, 35, 35,
1164 36, 37, 38, 39, 40, 41, 42, 43,
1165 44, 45, 46, 47, 48, 48, 49, 49,
1166 50, 51, 52, 53, 54, 55, 56, 57,
1167 58, 59, 60, 61, 62, 63, 64, 64,
1168 65, 66, 67, 68, 69, 70, 71, 72,
1169 73, 74, 75, 76, 77, 78, 79, 79,
1170 80, 81, 82, 83, 84, 85, 86, 87,
1171 88, 89, 90, 91, 92, 93, 94, 95,
1172 96, 97, 98, 99, 100, 101, 102, 103,
1173 104, 105, 106, 107, 108, 109, 110, 111,
1174 112, 113, 114, 115, 116, 117, 118, 119,
1175 120, 121, 122, 123, 124, 125, 126, 127};
1176 */
1177
1178 /*
1179 * This source code is a product of Sun Microsystems, Inc. and is provided
1180 * for unrestricted use. Users may copy or modify this source code without
1181 * charge.
1182 */
1183 /*
1184 public static byte _alaw2ulaw(byte sample) {
1185 sample &= 0xff;
1186 return (byte) (((sample & 0x80)!=0) ? (0xFF ^ _a2u[(sample ^ 0xD5) & 0x7F]) :
1187 (0x7F ^ _a2u[(sample ^ 0x55) & 0x7F]));
1188}
1189
1190 public static void print_a2u() {
1191 System.out.println("\tprivate static byte[] a2u = {");
1192 for (int i=-128; i<128; i++) {
1193 if (((i+128) % 16)==0) {
1194 System.out.print("\t\t");
1195 }
1196 byte b=(byte) i;
1197 System.out.print(_alaw2ulaw(b)+", ");
1198 if (((i+128) % 16)==15) {
1199 System.out.println("");
1200 }
1201}
1202 System.out.println("\t};");
1203}
1204
1205 public static void print_u2a() {
1206 System.out.println("\tprivate static byte[] u2a = {");
1207 for (int i=-128; i<128; i++) {
1208 if (((i+128) % 16)==0) {
1209 System.out.print("\t\t");
1210 }
1211 byte b=(byte) i;
1212 System.out.print(_ulaw2alaw(b)+", ");
1213 if (((i+128) % 16)==15) {
1214 System.out.println("");
1215 }
1216}
1217 System.out.println("\t};");
1218}
1219 */
1220
1221}
1222
1223
1224/*** TConversionTool.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/TVolumeUtils.java b/songdbj/org/tritonus/share/sampled/TVolumeUtils.java
new file mode 100644
index 0000000000..0eaf1388da
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/TVolumeUtils.java
@@ -0,0 +1,55 @@
1/*
2 * TVolumeUtils.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31
32
33public class TVolumeUtils
34{
35 private static final double FACTOR1 = 20.0 / Math.log(10.0);
36 private static final double FACTOR2 = 1 / 20.0;
37
38
39
40 public static double lin2log(double dLinear)
41 {
42 return FACTOR1 * Math.log(dLinear);
43 }
44
45
46
47 public static double log2lin(double dLogarithmic)
48 {
49 return Math.pow(10.0, dLogarithmic * FACTOR2);
50 }
51}
52
53
54
55/*** TVolumeUtils.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java b/songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java
new file mode 100644
index 0000000000..83349439eb
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java
@@ -0,0 +1,256 @@
1/*
2 * TAsynchronousFilteredAudioInputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import java.io.ByteArrayInputStream;
34import java.io.IOException;
35
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioInputStream;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.TCircularBuffer;
41
42
43
44/** Base class for asynchronus converters.
45 This class serves as base class for
46 converters that do not have a fixed
47 ratio between the size of a block of input
48 data and the size of a block of output data.
49 These types of converters therefore need an
50 internal buffer, which is realized in this
51 class.
52
53 @author Matthias Pfisterer
54*/
55public abstract class TAsynchronousFilteredAudioInputStream
56extends TAudioInputStream
57implements TCircularBuffer.Trigger
58{
59 private static final int DEFAULT_BUFFER_SIZE = 327670;
60 private static final int DEFAULT_MIN_AVAILABLE = 4096;
61 private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
62
63
64 private TCircularBuffer m_circularBuffer;
65 private int m_nMinAvailable;
66 private byte[] m_abSingleByte;
67
68
69
70 /** Constructor.
71 This constructor uses the default buffer size and the default
72 min available amount.
73
74 @param lLength length of this stream in frames. May be
75 AudioSystem.NOT_SPECIFIED.
76 */
77 public TAsynchronousFilteredAudioInputStream(AudioFormat outputFormat, long lLength)
78 {
79 this(outputFormat, lLength,
80 DEFAULT_BUFFER_SIZE,
81 DEFAULT_MIN_AVAILABLE);
82 }
83
84
85
86 /** Constructor.
87 With this constructor, the buffer size and the minimum
88 available amount can be specified as parameters.
89
90 @param lLength length of this stream in frames. May be
91 AudioSystem.NOT_SPECIFIED.
92
93 @param nBufferSize size of the circular buffer in bytes.
94 */
95 public TAsynchronousFilteredAudioInputStream(
96 AudioFormat outputFormat, long lLength,
97 int nBufferSize,
98 int nMinAvailable)
99 {
100 /* The usage of a ByteArrayInputStream is a hack.
101 * (the infamous "JavaOne hack", because I did it on June
102 * 6th 2000 in San Francisco, only hours before a
103 * JavaOne session where I wanted to show mp3 playback
104 * with Java Sound.) It is necessary because in the FCS
105 * version of the Sun jdk1.3, the constructor of
106 * AudioInputStream throws an exception if its first
107 * argument is null. So we have to pass a dummy non-null
108 * value.
109 */
110 super(new ByteArrayInputStream(EMPTY_BYTE_ARRAY),
111 outputFormat,
112 lLength);
113 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.<init>(): begin"); }
114 m_circularBuffer = new TCircularBuffer(
115 nBufferSize,
116 false, // blocking read
117 true, // blocking write
118 this); // trigger
119 m_nMinAvailable = nMinAvailable;
120 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.<init>(): end"); }
121 }
122
123
124 /** Returns the circular buffer.
125 */
126 protected TCircularBuffer getCircularBuffer()
127 {
128 return m_circularBuffer;
129 }
130
131
132
133 /** Check if writing more data to the circular buffer is recommanded.
134 This checks the available write space in the circular buffer
135 against the minimum available property. If the available write
136 space is greater than th minimum available property, more
137 writing is encouraged, so this method returns true.
138 Note that this is only a hint to subclasses. However,
139 it is an important hint.
140
141 @return true if more writing to the circular buffer is
142 recommanden. Otherwise, false is returned.
143 */
144 protected boolean writeMore()
145 {
146 return getCircularBuffer().availableWrite() > m_nMinAvailable;
147 }
148
149
150
151 public int read()
152 throws IOException
153 {
154 // if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(): begin"); }
155 int nByte = -1;
156 if (m_abSingleByte == null)
157 {
158 m_abSingleByte = new byte[1];
159 }
160 int nReturn = read(m_abSingleByte);
161 if (nReturn == -1)
162 {
163 nByte = -1;
164 }
165 else
166 {
167 //$$fb 2001-04-14 nobody really knows that...
168 nByte = m_abSingleByte[0] & 0xFF;
169 }
170 // if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(): end"); }
171 return nByte;
172 }
173
174
175
176 public int read(byte[] abData)
177 throws IOException
178 {
179 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[]): begin"); }
180 int nRead = read(abData, 0, abData.length);
181 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[]): end"); }
182 return nRead;
183 }
184
185
186
187 public int read(byte[] abData, int nOffset, int nLength)
188 throws IOException
189 {
190 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[], int, int): begin"); }
191 //$$fb 2001-04-22: this returns at maximum circular buffer
192 // length. This is not very efficient...
193 //$$fb 2001-04-25: we should check that we do not exceed getFrameLength() !
194 int nRead = m_circularBuffer.read(abData, nOffset, nLength);
195 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[], int, int): end"); }
196 return nRead;
197 }
198
199
200
201 public long skip(long lSkip)
202 throws IOException
203 {
204 // TODO: this is quite inefficient
205 for (long lSkipped = 0; lSkipped < lSkip; lSkipped++)
206 {
207 int nReturn = read();
208 if (nReturn == -1)
209 {
210 return lSkipped;
211 }
212 }
213 return lSkip;
214 }
215
216
217
218 public int available()
219 throws IOException
220 {
221 return m_circularBuffer.availableRead();
222 }
223
224
225
226 public void close()
227 throws IOException
228 {
229 m_circularBuffer.close();
230 }
231
232
233
234 public boolean markSupported()
235 {
236 return false;
237 }
238
239
240
241 public void mark(int nReadLimit)
242 {
243 }
244
245
246
247 public void reset()
248 throws IOException
249 {
250 throw new IOException("mark not supported");
251 }
252}
253
254
255
256/*** TAsynchronousFilteredAudioInputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java b/songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java
new file mode 100644
index 0000000000..d84530e115
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java
@@ -0,0 +1,120 @@
1/*
2 * TAudioInputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2003 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.convert;
30
31import java.io.InputStream;
32
33import java.util.Collections;
34import java.util.HashMap;
35import java.util.Map;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioInputStream;
39
40
41/** AudioInputStream base class. This class implements "dynamic"
42 properties. "Dynamic" properties are properties that may change
43 during the life time of the objects. This is typically used to
44 pass information like the current frame number, volume of subbands
45 and similar values. "Dynamic" properties are different from
46 properties in AudioFormat and AudioFileFormat, which are
47 considered "static", as they aren't allowed to change after
48 creating of the object, thereby maintaining the immutable
49 character of these classes.
50*/
51
52public class TAudioInputStream
53extends AudioInputStream
54{
55 private Map<String, Object> m_properties;
56 private Map<String, Object> m_unmodifiableProperties;
57
58
59 /** Constructor without properties.
60 Creates an empty properties map.
61 */
62 public TAudioInputStream(InputStream inputStream,
63 AudioFormat audioFormat,
64 long lLengthInFrames)
65 {
66 super(inputStream, audioFormat, lLengthInFrames);
67 initMaps(new HashMap<String, Object>());
68 }
69
70
71 /** Constructor with properties.
72 The passed properties map is not copied. This allows subclasses
73 to change values in the map after creation, and the changes are
74 reflected in the map the application program can obtain.
75 */
76 public TAudioInputStream(InputStream inputStream,
77 AudioFormat audioFormat,
78 long lLengthInFrames,
79 Map<String, Object> properties)
80 {
81 super(inputStream, audioFormat, lLengthInFrames);
82 initMaps(properties);
83 }
84
85
86 private void initMaps(Map<String, Object> properties)
87 {
88 /* Here, we make a shallow copy of the map. It's unclear if this
89 is sufficient (of if a deep copy should be made).
90 */
91 m_properties = properties;
92 m_unmodifiableProperties = Collections.unmodifiableMap(m_properties);
93 }
94
95
96 /** Obtain a Map containing the properties. This method returns a
97 Map that cannot be modified by the application program, but
98 reflects changes to the map made by the implementation.
99
100 @return a map containing the properties.
101 */
102 public Map<String, Object> properties()
103 {
104 return m_unmodifiableProperties;
105 }
106
107
108 /** Set a property. Unlike in AudioFormat and AudioFileFormat,
109 this method may be used anywhere by subclasses - it is not
110 restricted to be used in the constructor.
111 */
112 protected void setProperty(String key, Object value)
113 {
114 m_properties.put(key, value);
115 }
116}
117
118
119
120/*** TAudioInputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java
new file mode 100644
index 0000000000..6b83403c43
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java
@@ -0,0 +1,129 @@
1/*
2 * TEncodingFormatConversionProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import java.util.Collection;
34import java.util.Iterator;
35
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioSystem;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.ArraySet;
41
42
43// this class depends on handling of AudioSystem.NOT_SPECIFIED in AudioFormat.matches()
44
45/**
46 * This is a base class for FormatConversionProviders that only
47 * change the encoding, i.e. they never
48 * <ul>
49 * <li> change the sample size in bits without changing the encoding
50 * <li> change the sample rate
51 * <li> change the number of channels
52 * </ul>
53 * <p>It is assumed that each source format can be encoded to all
54 * target formats.
55 * <p>In the sourceFormats and targetFormats collections that are passed to
56 * the constructor of this class, fields may be set to AudioSystem.NOT_SPECIFIED.
57 * This means that it handles all values of that field, but cannot change it.
58 * <p>This class prevents that a conversion is done (e.g. for sample rates),
59 * because the overriding class specified AudioSystem.NOT_SPECIFIED as sample rate,
60 * meaning it handles all sample rates.
61 * <p>Overriding classes must implement at least
62 * <code>AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream)</code>
63 * and provide a constructor that calls the protected constructor of this class.
64 *
65 * @author Florian Bomers
66 */
67public abstract class TEncodingFormatConversionProvider
68extends TSimpleFormatConversionProvider
69{
70 protected TEncodingFormatConversionProvider(
71 Collection<AudioFormat> sourceFormats,
72 Collection<AudioFormat> targetFormats)
73 {
74 super(sourceFormats, targetFormats);
75 }
76
77
78
79 /**
80 * This implementation assumes that the converter can convert
81 * from each of its source formats to each of its target
82 * formats. If this is not the case, the converter has to
83 * override this method.
84 * <p>When conversion is supported, for every target encoding,
85 * the fields sample size in bits, channels and sample rate are checked:
86 * <ul>
87 * <li>When a field in both the source and target format is AudioSystem.NOT_SPECIFIED,
88 * one instance of that targetFormat is returned with this field set to AudioSystem.NOT_SPECIFIED.
89 * <li>When a field in sourceFormat is set and it is AudioSystem.NOT_SPECIFIED in the target format,
90 * the value of the field of source format is set in the returned format.
91 * <li>The same applies for the other way round.
92 * </ul>
93 * For this, <code>replaceNotSpecified(sourceFormat, targetFormat)</code> in the base
94 * class TSimpleFormatConversionProvider is used - and accordingly, the frameSize
95 * is recalculated with <code>getFrameSize(...)</code> if a field with AudioSystem.NOT_SPECIFIED
96 * is replaced. Inheriting classes may wish to override this method if the
97 * default mode of calculating the frame size is not appropriate.
98 */
99 public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
100 if (TDebug.TraceAudioConverter) {
101 TDebug.out(">TEncodingFormatConversionProvider.getTargetFormats(AudioFormat.Encoding, AudioFormat):");
102 TDebug.out("checking if conversion possible");
103 TDebug.out("from: " + sourceFormat);
104 TDebug.out("to: " + targetEncoding);
105 }
106 if (isConversionSupported(targetEncoding, sourceFormat)) {
107 // TODO: check that no duplicates may occur...
108 ArraySet<AudioFormat> result=new ArraySet<AudioFormat>();
109 Iterator<AudioFormat> iterator = getCollectionTargetFormats().iterator();
110 while (iterator.hasNext()) {
111 AudioFormat targetFormat = iterator.next();
112 targetFormat=replaceNotSpecified(sourceFormat, targetFormat);
113 result.add(targetFormat);
114 }
115 if (TDebug.TraceAudioConverter) {
116 TDebug.out("< returning "+result.size()+" elements.");
117 }
118 return result.toArray(EMPTY_FORMAT_ARRAY);
119 } else {
120 if (TDebug.TraceAudioConverter) {
121 TDebug.out("< returning empty array.");
122 }
123 return EMPTY_FORMAT_ARRAY;
124 }
125 }
126
127}
128
129/*** TEncodingFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java
new file mode 100644
index 0000000000..eaec65bb06
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java
@@ -0,0 +1,170 @@
1/*
2 * TFormatConversionProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import javax.sound.sampled.AudioSystem;
34import javax.sound.sampled.AudioFormat;
35import javax.sound.sampled.AudioInputStream;
36import javax.sound.sampled.spi.FormatConversionProvider;
37
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.AudioFormats;
40
41
42
43/** Base class for all conversion providers of Tritonus.
44 *
45 * @author Matthias Pfisterer
46 */
47public abstract class TFormatConversionProvider
48extends FormatConversionProvider
49{
50 protected static final AudioFormat.Encoding[] EMPTY_ENCODING_ARRAY = new AudioFormat.Encoding[0];
51 protected static final AudioFormat[] EMPTY_FORMAT_ARRAY = new AudioFormat[0];
52
53
54
55 // $$fb2000-10-04: use AudioSystem.NOT_SPECIFIED for all fields.
56 public AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding, AudioInputStream audioInputStream)
57 {
58 AudioFormat sourceFormat = audioInputStream.getFormat();
59 AudioFormat targetFormat = new AudioFormat(
60 targetEncoding,
61 AudioSystem.NOT_SPECIFIED, // sample rate
62 AudioSystem.NOT_SPECIFIED, // sample size in bits
63 AudioSystem.NOT_SPECIFIED, // channels
64 AudioSystem.NOT_SPECIFIED, // frame size
65 AudioSystem.NOT_SPECIFIED, // frame rate
66 sourceFormat.isBigEndian()); // big endian
67 if (TDebug.TraceAudioConverter)
68 {
69 TDebug.out("TFormatConversionProvider.getAudioInputStream(AudioFormat.Encoding, AudioInputStream):");
70 TDebug.out("trying to convert to " + targetFormat);
71 }
72 return getAudioInputStream(targetFormat, audioInputStream);
73 }
74
75
76
77 /**
78 * WARNING: this method uses <code>getTargetFormats(AudioFormat.Encoding, AudioFormat)</code>
79 * which may create infinite loops if the latter is overwritten.
80 * <p>
81 * This method is overwritten here to make use of org.tritonus.share.sampled.AudioFormats.matches
82 * and is considered temporary until AudioFormat.matches is corrected in the JavaSound API.
83 */
84 /* $$mp: if we decide to use getMatchingFormat(), this method should be
85 implemented by simply calling getMatchingFormat() and comparing the
86 result against null.
87 */
88 public boolean isConversionSupported(
89 AudioFormat targetFormat,
90 AudioFormat sourceFormat)
91 {
92 if (TDebug.TraceAudioConverter)
93 {
94 TDebug.out(">TFormatConversionProvider.isConversionSupported(AudioFormat, AudioFormat):");
95 TDebug.out("class: "+getClass().getName());
96 TDebug.out("checking if conversion possible");
97 TDebug.out("from: " + sourceFormat);
98 TDebug.out("to: " + targetFormat);
99 }
100 AudioFormat[] aTargetFormats = getTargetFormats(targetFormat.getEncoding(), sourceFormat);
101 for (int i = 0; i < aTargetFormats.length; i++)
102 {
103 if (TDebug.TraceAudioConverter)
104 {
105 TDebug.out("checking against possible target format: " + aTargetFormats[i]);
106 }
107 if (aTargetFormats[i] != null
108 && AudioFormats.matches(aTargetFormats[i], targetFormat))
109 {
110 if (TDebug.TraceAudioConverter)
111 {
112 TDebug.out("<result=true");
113 }
114 return true;
115 }
116 }
117 if (TDebug.TraceAudioConverter) {
118 TDebug.out("<result=false");
119 }
120 return false;
121 }
122
123
124 /**
125 * WARNING: this method uses <code>getTargetFormats(AudioFormat.Encoding, AudioFormat)</code>
126 * which may create infinite loops if the latter is overwritten.
127 * <p>
128 * This method is overwritten here to make use of org.tritonus.share.sampled.AudioFormats.matches
129 * and is considered temporary until AudioFormat.matches is corrected in the JavaSound API.
130 */
131 public AudioFormat getMatchingFormat(
132 AudioFormat targetFormat,
133 AudioFormat sourceFormat)
134 {
135 if (TDebug.TraceAudioConverter)
136 {
137 TDebug.out(">TFormatConversionProvider.isConversionSupported(AudioFormat, AudioFormat):");
138 TDebug.out("class: "+getClass().getName());
139 TDebug.out("checking if conversion possible");
140 TDebug.out("from: " + sourceFormat);
141 TDebug.out("to: " + targetFormat);
142 }
143 AudioFormat[] aTargetFormats = getTargetFormats(targetFormat.getEncoding(), sourceFormat);
144 for (int i = 0; i < aTargetFormats.length; i++)
145 {
146 if (TDebug.TraceAudioConverter)
147 {
148 TDebug.out("checking against possible target format: " + aTargetFormats[i]);
149 }
150 if (aTargetFormats[i] != null
151 && AudioFormats.matches(aTargetFormats[i], targetFormat))
152 {
153 if (TDebug.TraceAudioConverter)
154 {
155 TDebug.out("<result=true");
156 }
157 return aTargetFormats[i];
158 }
159 }
160 if (TDebug.TraceAudioConverter) {
161 TDebug.out("<result=false");
162 }
163 return null;
164 }
165
166}
167
168
169
170/*** TFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java
new file mode 100644
index 0000000000..05dca90309
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java
@@ -0,0 +1,182 @@
1/*
2 * TMatrixFormatConversionProvider.java
3 */
4
5/*
6 * Copyright (c) 1999, 2000 by Matthias Pfisterer <Matthias.Pfisterer@gmx.de>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Library General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25
26package org.tritonus.share.sampled.convert;
27
28
29import java.util.Collection;
30import java.util.List;
31import java.util.Map;
32import java.util.Set;
33import java.util.HashMap;
34import java.util.ArrayList;
35import java.util.Iterator;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioInputStream;
39import javax.sound.sampled.spi.FormatConversionProvider;
40
41import org.tritonus.share.sampled.AudioFormats;
42import org.tritonus.share.ArraySet;
43
44/**
45 * Base class for arbitrary formatConversionProviders.
46 *
47 * @author Matthias Pfisterer
48 */
49
50
51public abstract class TMatrixFormatConversionProvider
52 extends TSimpleFormatConversionProvider
53{
54 /*
55 * keys: source AudioFormat
56 * values: collection of possible target encodings
57 *
58 * Note that accessing values with get() is not appropriate,
59 * since the equals() method in AudioFormat is not overloaded.
60 * The hashtable is just used as a convenient storage
61 * organization.
62 */
63 private Map m_targetEncodingsFromSourceFormat;
64
65
66 /*
67 * keys: source AudioFormat
68 * values: a Map that contains a mapping from target encodings
69 * (keys) to a collection of target formats (values).
70 *
71 * Note that accessing values with get() is not appropriate,
72 * since the equals() method in AudioFormat is not overloaded.
73 * The hashtable is just used as a convenient storage
74 * organization.
75 */
76 private Map m_targetFormatsFromSourceFormat;
77
78
79
80 protected TMatrixFormatConversionProvider(
81 List sourceFormats,
82 List targetFormats,
83 boolean[][] abConversionPossible)
84 {
85 super(sourceFormats,
86 targetFormats);
87 m_targetEncodingsFromSourceFormat = new HashMap();
88 m_targetFormatsFromSourceFormat = new HashMap();
89
90 for (int nSourceFormat = 0;
91 nSourceFormat < sourceFormats.size();
92 nSourceFormat++)
93 {
94 AudioFormat sourceFormat = (AudioFormat) sourceFormats.get(nSourceFormat);
95 List supportedTargetEncodings = new ArraySet();
96 m_targetEncodingsFromSourceFormat.put(sourceFormat, supportedTargetEncodings);
97 Map targetFormatsFromTargetEncodings = new HashMap();
98 m_targetFormatsFromSourceFormat.put(sourceFormat, targetFormatsFromTargetEncodings);
99 for (int nTargetFormat = 0;
100 nTargetFormat < targetFormats.size();
101 nTargetFormat++)
102 {
103 AudioFormat targetFormat = (AudioFormat) targetFormats.get(nTargetFormat);
104 if (abConversionPossible[nSourceFormat][nTargetFormat])
105 {
106 AudioFormat.Encoding targetEncoding = targetFormat.getEncoding();
107 supportedTargetEncodings.add(targetEncoding);
108 Collection supportedTargetFormats = (Collection) targetFormatsFromTargetEncodings.get(targetEncoding);
109 if (supportedTargetFormats == null)
110 {
111 supportedTargetFormats = new ArraySet();
112 targetFormatsFromTargetEncodings.put(targetEncoding, supportedTargetFormats);
113 }
114 supportedTargetFormats.add(targetFormat);
115 }
116 }
117 }
118 }
119
120
121
122 public AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat)
123 {
124 Iterator iterator = m_targetEncodingsFromSourceFormat.entrySet().iterator();
125 while (iterator.hasNext())
126 {
127 Map.Entry entry = (Map.Entry) iterator.next();
128 AudioFormat format = (AudioFormat) entry.getKey();
129 if (AudioFormats.matches(format, sourceFormat))
130 {
131 Collection targetEncodings = (Collection) entry.getValue();
132 return (AudioFormat.Encoding[]) targetEncodings.toArray(EMPTY_ENCODING_ARRAY);
133 }
134
135 }
136 return EMPTY_ENCODING_ARRAY;
137 }
138
139
140
141 // TODO: this should work on the array returned by getTargetEncodings(AudioFormat)
142/*
143 public boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat)
144 {
145 return isAllowedSourceFormat(sourceFormat) &&
146 isTargetEncodingSupported(targetEncoding);
147 }
148*/
149
150
151
152 public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat)
153 {
154 Iterator iterator = m_targetFormatsFromSourceFormat.entrySet().iterator();
155 while (iterator.hasNext())
156 {
157 Map.Entry entry = (Map.Entry) iterator.next();
158 AudioFormat format = (AudioFormat) entry.getKey();
159 if (AudioFormats.matches(format, sourceFormat))
160 {
161 Map targetEncodings = (Map) entry.getValue();
162 Collection targetFormats = (Collection) targetEncodings.get(targetEncoding);
163 if (targetFormats != null)
164 {
165 return (AudioFormat[]) targetFormats.toArray(EMPTY_FORMAT_ARRAY);
166 }
167 else
168 {
169 return EMPTY_FORMAT_ARRAY;
170 }
171 }
172
173 }
174 return EMPTY_FORMAT_ARRAY;
175 }
176
177
178}
179
180
181
182/*** TMatrixFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java
new file mode 100644
index 0000000000..71b055ff79
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java
@@ -0,0 +1,367 @@
1/*
2 * TSimpleFormatConversionProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.convert;
31
32import java.util.Collection;
33import java.util.Iterator;
34
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.sampled.AudioFormats;
39import org.tritonus.share.ArraySet;
40import org.tritonus.share.TDebug;
41
42
43/**
44 * This is a base class for FormatConversionProviders that can convert
45 * from each source encoding/format to each target encoding/format.
46 * If this is not the case, use TEncodingFormatConversionProvider.
47 *
48 * <p>Overriding classes must
49 * provide a constructor that calls the protected constructor of this class and override
50 * <code>AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream)</code>.
51 * The latter method should be able to handle the case that all fields are NOT_SPECIFIED
52 * and provide appropriate default values.
53 *
54 * @author Matthias Pfisterer
55 */
56
57// todo:
58// - declare a constant ALL_BUT_SAME_VALUE (==-2) or so that can be used in format lists
59// - consistent implementation of replacing NOT_SPECIFIED when not given in conversion
60
61public abstract class TSimpleFormatConversionProvider
62extends TFormatConversionProvider
63{
64 private Collection<AudioFormat.Encoding> m_sourceEncodings;
65 private Collection<AudioFormat.Encoding> m_targetEncodings;
66 private Collection<AudioFormat> m_sourceFormats;
67 private Collection<AudioFormat> m_targetFormats;
68
69
70
71 protected TSimpleFormatConversionProvider(
72 Collection<AudioFormat> sourceFormats,
73 Collection<AudioFormat> targetFormats)
74 {
75 m_sourceEncodings = new ArraySet<AudioFormat.Encoding>();
76 m_targetEncodings = new ArraySet<AudioFormat.Encoding>();
77 m_sourceFormats = sourceFormats;
78 m_targetFormats = targetFormats;
79 collectEncodings(m_sourceFormats, m_sourceEncodings);
80 collectEncodings(m_targetFormats, m_targetEncodings);
81 }
82
83
84
85 /** Disables this FormatConversionProvider.
86 This may be useful when e.g. native libraries are not present.
87 TODO: enable method, better implementation
88 */
89 protected void disable()
90 {
91 if (TDebug.TraceAudioConverter) { TDebug.out("TSimpleFormatConversionProvider.disable(): disabling " + getClass().getName()); }
92 m_sourceEncodings = new ArraySet<AudioFormat.Encoding>();
93 m_targetEncodings = new ArraySet<AudioFormat.Encoding>();
94 m_sourceFormats = new ArraySet<AudioFormat>();
95 m_targetFormats = new ArraySet<AudioFormat>();
96 }
97
98
99
100 private static void collectEncodings(Collection<AudioFormat> formats,
101 Collection<AudioFormat.Encoding> encodings)
102 {
103 Iterator<AudioFormat> iterator = formats.iterator();
104 while (iterator.hasNext())
105 {
106 AudioFormat format = iterator.next();
107 encodings.add(format.getEncoding());
108 }
109 }
110
111
112
113 public AudioFormat.Encoding[] getSourceEncodings()
114 {
115 return m_sourceEncodings.toArray(EMPTY_ENCODING_ARRAY);
116 }
117
118
119
120 public AudioFormat.Encoding[] getTargetEncodings()
121 {
122 return m_targetEncodings.toArray(EMPTY_ENCODING_ARRAY);
123 }
124
125
126
127 // overwritten of FormatConversionProvider
128 public boolean isSourceEncodingSupported(AudioFormat.Encoding sourceEncoding)
129 {
130 return m_sourceEncodings.contains(sourceEncoding);
131 }
132
133
134
135 // overwritten of FormatConversionProvider
136 public boolean isTargetEncodingSupported(AudioFormat.Encoding targetEncoding)
137 {
138 return m_targetEncodings.contains(targetEncoding);
139 }
140
141
142
143 /**
144 * This implementation assumes that the converter can convert
145 * from each of its source encodings to each of its target
146 * encodings. If this is not the case, the converter has to
147 * override this method.
148 */
149 public AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat)
150 {
151 if (isAllowedSourceFormat(sourceFormat))
152 {
153 return getTargetEncodings();
154 }
155 else
156 {
157 return EMPTY_ENCODING_ARRAY;
158 }
159 }
160
161
162
163 /**
164 * This implementation assumes that the converter can convert
165 * from each of its source formats to each of its target
166 * formats. If this is not the case, the converter has to
167 * override this method.
168 */
169 public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat)
170 {
171 if (isConversionSupported(targetEncoding, sourceFormat))
172 {
173 return m_targetFormats.toArray(EMPTY_FORMAT_ARRAY);
174 }
175 else
176 {
177 return EMPTY_FORMAT_ARRAY;
178 }
179 }
180
181
182 // TODO: check if necessary
183 protected boolean isAllowedSourceEncoding(AudioFormat.Encoding sourceEncoding)
184 {
185 return m_sourceEncodings.contains(sourceEncoding);
186 }
187
188
189
190 protected boolean isAllowedTargetEncoding(AudioFormat.Encoding targetEncoding)
191 {
192 return m_targetEncodings.contains(targetEncoding);
193 }
194
195
196
197 protected boolean isAllowedSourceFormat(AudioFormat sourceFormat)
198 {
199 Iterator<AudioFormat> iterator = m_sourceFormats.iterator();
200 while (iterator.hasNext())
201 {
202 AudioFormat format = iterator.next();
203 if (AudioFormats.matches(format, sourceFormat))
204 {
205 return true;
206 }
207 }
208 return false;
209 }
210
211
212
213 protected boolean isAllowedTargetFormat(AudioFormat targetFormat)
214 {
215 Iterator<AudioFormat> iterator = m_targetFormats.iterator();
216 while (iterator.hasNext())
217 {
218 AudioFormat format = iterator.next();
219 if (AudioFormats.matches(format, targetFormat))
220 {
221 return true;
222 }
223 }
224 return false;
225 }
226
227 // $$fb 2000-04-02 added some convenience methods for overriding classes
228 protected Collection<AudioFormat.Encoding> getCollectionSourceEncodings()
229 {
230 return m_sourceEncodings;
231 }
232
233 protected Collection<AudioFormat.Encoding> getCollectionTargetEncodings()
234 {
235 return m_targetEncodings;
236 }
237
238 protected Collection<AudioFormat> getCollectionSourceFormats() {
239 return m_sourceFormats;
240 }
241
242 protected Collection<AudioFormat> getCollectionTargetFormats() {
243 return m_targetFormats;
244 }
245
246 /**
247 * Utility method to check whether these values match,
248 * taking into account AudioSystem.NOT_SPECIFIED.
249 * @return true if any of the values is AudioSystem.NOT_SPECIFIED
250 * or both values have the same value.
251 */
252 //$$fb 2000-08-16: moved from TEncodingFormatConversionProvider
253 protected static boolean doMatch(int i1, int i2) {
254 return i1==AudioSystem.NOT_SPECIFIED
255 || i2==AudioSystem.NOT_SPECIFIED
256 || i1==i2;
257 }
258
259 /**
260 * @see #doMatch(int,int)
261 */
262 //$$fb 2000-08-16: moved from TEncodingFormatConversionProvider
263 protected static boolean doMatch(float f1, float f2) {
264 return f1==AudioSystem.NOT_SPECIFIED
265 || f2==AudioSystem.NOT_SPECIFIED
266 || Math.abs(f1 - f2) < 1.0e-9;
267 }
268
269 /**
270 * Utility method, replaces all occurences of AudioSystem.NOT_SPECIFIED
271 * in <code>targetFormat</code> with the corresponding value in <code>sourceFormat</code>.
272 * If <code>targetFormat</code> does not contain any fields with AudioSystem.NOT_SPECIFIED,
273 * it is returned unmodified. The endian-ness and encoding remain the same in all cases.
274 * <p>
275 * If any of the fields is AudioSystem.NOT_SPECIFIED in both <code>sourceFormat</code> and
276 * <code>targetFormat</code>, it will remain not specified.
277 * <p>
278 * This method uses <code>getFrameSize(...)</code> (see below) to set the new frameSize,
279 * if a new AudioFormat instance is created.
280 * <p>
281 * This method isn't used in TSimpleFormatConversionProvider - it is solely there
282 * for inheriting classes.
283 */
284 //$$fb 2000-08-16: moved from TEncodingFormatConversionProvider
285 protected AudioFormat replaceNotSpecified(AudioFormat sourceFormat, AudioFormat targetFormat) {
286 boolean bSetSampleSize=false;
287 boolean bSetChannels=false;
288 boolean bSetSampleRate=false;
289 boolean bSetFrameRate=false;
290 if (targetFormat.getSampleSizeInBits()==AudioSystem.NOT_SPECIFIED
291 && sourceFormat.getSampleSizeInBits()!=AudioSystem.NOT_SPECIFIED) {
292 bSetSampleSize=true;
293 }
294 if (targetFormat.getChannels()==AudioSystem.NOT_SPECIFIED
295 && sourceFormat.getChannels()!=AudioSystem.NOT_SPECIFIED) {
296 bSetChannels=true;
297 }
298 if (targetFormat.getSampleRate()==AudioSystem.NOT_SPECIFIED
299 && sourceFormat.getSampleRate()!=AudioSystem.NOT_SPECIFIED) {
300 bSetSampleRate=true;
301 }
302 if (targetFormat.getFrameRate()==AudioSystem.NOT_SPECIFIED
303 && sourceFormat.getFrameRate()!=AudioSystem.NOT_SPECIFIED) {
304 bSetFrameRate=true;
305 }
306 if (bSetSampleSize || bSetChannels || bSetSampleRate || bSetFrameRate
307 || (targetFormat.getFrameSize()==AudioSystem.NOT_SPECIFIED
308 && sourceFormat.getFrameSize()!=AudioSystem.NOT_SPECIFIED)) {
309 // create new format in place of the original target format
310 float sampleRate=bSetSampleRate?
311 sourceFormat.getSampleRate():targetFormat.getSampleRate();
312 float frameRate=bSetFrameRate?
313 sourceFormat.getFrameRate():targetFormat.getFrameRate();
314 int sampleSize=bSetSampleSize?
315 sourceFormat.getSampleSizeInBits():targetFormat.getSampleSizeInBits();
316 int channels=bSetChannels?
317 sourceFormat.getChannels():targetFormat.getChannels();
318 int frameSize=getFrameSize(
319 targetFormat.getEncoding(),
320 sampleRate,
321 sampleSize,
322 channels,
323 frameRate,
324 targetFormat.isBigEndian(),
325 targetFormat.getFrameSize());
326 targetFormat= new AudioFormat(
327 targetFormat.getEncoding(),
328 sampleRate,
329 sampleSize,
330 channels,
331 frameSize,
332 frameRate,
333 targetFormat.isBigEndian());
334 }
335 return targetFormat;
336 }
337
338 /**
339 * Calculates the frame size for the given format description.
340 * The default implementation returns AudioSystem.NOT_SPECIFIED
341 * if either <code>sampleSize</code> or <code>channels</code> is AudioSystem.NOT_SPECIFIED,
342 * otherwise <code>sampleSize*channels/8</code> is returned.
343 * <p>
344 * If this does not reflect the way to calculate the right frame size,
345 * inheriting classes should overwrite this method if they use
346 * replaceNotSpecified(...). It is not used elsewhere in this class.
347 */
348 //$$fb 2000-08-16: added
349 protected int getFrameSize(
350 AudioFormat.Encoding encoding,
351 float sampleRate,
352 int sampleSize,
353 int channels,
354 float frameRate,
355 boolean bigEndian,
356 int oldFrameSize) {
357 if (sampleSize==AudioSystem.NOT_SPECIFIED || channels==AudioSystem.NOT_SPECIFIED) {
358 return AudioSystem.NOT_SPECIFIED;
359 }
360 return sampleSize*channels/8;
361 }
362
363
364
365}
366
367/*** TSimpleFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java b/songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java
new file mode 100644
index 0000000000..8a588e5c3e
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java
@@ -0,0 +1,271 @@
1/*
2 * TSynchronousFilteredAudioInputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioSystem;
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioInputStream;
38import javax.sound.sampled.spi.FormatConversionProvider;
39
40import org.tritonus.share.TDebug;
41import org.tritonus.share.sampled.AudioUtils;
42
43
44
45/**
46 * Base class for types of audio filter/converter that translate one frame to another frame.<br>
47 * It provides all the transformation of frame sizes.<br>
48 * It does NOT handle different sample rates of original stream and this stream !
49 *
50 * @author Florian Bomers
51 */
52public abstract class TSynchronousFilteredAudioInputStream
53extends TAudioInputStream {
54
55 private AudioInputStream originalStream;
56 private AudioFormat originalFormat;
57 /** 1 if original format's frame size is NOT_SPECIFIED */
58 private int originalFrameSize;
59 /** 1 if original format's frame size is NOT_SPECIFIED */
60 private int newFrameSize;
61
62 /**
63 * The intermediate buffer used during convert actions
64 * (if not convertInPlace is used).
65 * It remains until this audioStream is closed or destroyed
66 * and grows with the time - it always has the size of the
67 * largest intermediate buffer ever needed.
68 */
69 protected byte[] buffer=null;
70
71 /**
72 * For use of the more efficient method convertInPlace.
73 * it will be set to true when (frameSizeFactor==1)
74 */
75 private boolean m_bConvertInPlace = false;
76
77 public TSynchronousFilteredAudioInputStream(AudioInputStream audioInputStream, AudioFormat newFormat) {
78 // the super class will do nothing... we override everything
79 super(audioInputStream, newFormat, audioInputStream.getFrameLength());
80 originalStream=audioInputStream;
81 originalFormat=audioInputStream.getFormat();
82 originalFrameSize=(originalFormat.getFrameSize()<=0) ?
83 1 : originalFormat.getFrameSize();
84 newFrameSize=(getFormat().getFrameSize()<=0) ?
85 1 : getFormat().getFrameSize();
86 if (TDebug.TraceAudioConverter) {
87 TDebug.out("TSynchronousFilteredAudioInputStream: original format ="
88 +AudioUtils.format2ShortStr(originalFormat));
89 TDebug.out("TSynchronousFilteredAudioInputStream: converted format="
90 +AudioUtils.format2ShortStr(getFormat()));
91 }
92 //$$fb 2000-07-17: convert in place has to be enabled explicitly with "enableConvertInPlace"
93 //if (getFormat().getFrameSize() == originalFormat.getFrameSize()) {
94 // m_bConvertInPlace = true;
95 //}
96 m_bConvertInPlace = false;
97 }
98
99 protected boolean enableConvertInPlace() {
100 if (newFrameSize >= originalFrameSize) {
101 m_bConvertInPlace = true;
102 }
103 return m_bConvertInPlace;
104 }
105
106
107 /**
108 * Override this method to do the actual conversion.
109 * inBuffer starts always at index 0 (it is an internal buffer)
110 * You should always override this.
111 * inFrameCount is the number of frames in inBuffer. These
112 * frames are of the format originalFormat.
113 * @return the resulting number of <B>frames</B> converted and put into
114 * outBuffer. The return value is in the format of this stream.
115 */
116 protected abstract int convert(byte[] inBuffer, byte[] outBuffer, int outByteOffset, int inFrameCount);
117
118
119
120 /**
121 * Override this method to provide in-place conversion of samples.
122 * To use it, call "enableConvertInPlace()". It will only be used when
123 * input bytes per frame >= output bytes per frame.
124 * This method must always convert frameCount frames, so no return value is necessary.
125 */
126 protected void convertInPlace(byte[] buffer, int byteOffset, int frameCount) {
127 throw new RuntimeException("Illegal call to convertInPlace");
128 }
129
130 public int read()
131 throws IOException {
132 if (newFrameSize != 1) {
133 throw new IOException("frame size must be 1 to read a single byte");
134 }
135 // very ugly, but efficient. Who uses this method anyway ?
136 // TODO: use an instance variable
137 byte[] temp = new byte[1];
138 int result = read(temp);
139 if (result == -1) {
140 return -1;
141 }
142 if (result == 0) {
143 // what in this case ??? Let's hope it never occurs.
144 return -1;
145 }
146 return temp[0] & 0xFF;
147 }
148
149
150
151 private void clearBuffer() {
152 buffer = null;
153 }
154
155 public AudioInputStream getOriginalStream() {
156 return originalStream;
157 }
158
159 public AudioFormat getOriginalFormat() {
160 return originalFormat;
161 }
162
163 /**
164 * Read nLength bytes that will be the converted samples
165 * of the original InputStream.
166 * When nLength is not an integral number of frames,
167 * this method may read less than nLength bytes.
168 */
169 public int read(byte[] abData, int nOffset, int nLength)
170 throws IOException {
171 // number of frames that we have to read from the underlying stream.
172 int nFrameLength = nLength/newFrameSize;
173
174 // number of bytes that we need to read from underlying stream.
175 int originalBytes = nFrameLength * originalFrameSize;
176
177 if (TDebug.TraceAudioConverter) {
178 TDebug.out("> TSynchronousFilteredAIS.read(buffer["+abData.length+"], "
179 +nOffset+" ,"+nLength+" bytes ^="+nFrameLength+" frames)");
180 }
181 int nFramesConverted = 0;
182
183 // set up buffer to read
184 byte readBuffer[];
185 int readOffset;
186 if (m_bConvertInPlace) {
187 readBuffer=abData;
188 readOffset=nOffset;
189 } else {
190 // assert that the buffer fits
191 if (buffer == null || buffer.length < originalBytes) {
192 buffer = new byte[originalBytes];
193 }
194 readBuffer=buffer;
195 readOffset=0;
196 }
197 int nBytesRead = originalStream.read(readBuffer, readOffset, originalBytes);
198 if (nBytesRead == -1) {
199 // end of stream
200 clearBuffer();
201 return -1;
202 }
203 int nFramesRead = nBytesRead / originalFrameSize;
204 if (TDebug.TraceAudioConverter) {
205 TDebug.out("original.read returned "
206 +nBytesRead+" bytes ^="+nFramesRead+" frames");
207 }
208 if (m_bConvertInPlace) {
209 convertInPlace(abData, nOffset, nFramesRead);
210 nFramesConverted=nFramesRead;
211 } else {
212 nFramesConverted = convert(buffer, abData, nOffset, nFramesRead);
213 }
214 if (TDebug.TraceAudioConverter) {
215 TDebug.out("< converted "+nFramesConverted+" frames");
216 }
217 return nFramesConverted*newFrameSize;
218 }
219
220
221 public long skip(long nSkip)
222 throws IOException {
223 // only returns integral frames
224 long skipFrames = nSkip / newFrameSize;
225 long originalSkippedBytes = originalStream.skip(skipFrames*originalFrameSize);
226 long skippedFrames = originalSkippedBytes/originalFrameSize;
227 return skippedFrames * newFrameSize;
228 }
229
230
231 public int available()
232 throws IOException {
233 int origAvailFrames = originalStream.available()/originalFrameSize;
234 return origAvailFrames*newFrameSize;
235 }
236
237
238 public void close()
239 throws IOException {
240 originalStream.close();
241 clearBuffer();
242 }
243
244
245
246 public void mark(int readlimit) {
247 int readLimitFrames=readlimit/newFrameSize;
248 originalStream.mark(readLimitFrames*originalFrameSize);
249 }
250
251
252
253 public void reset()
254 throws IOException {
255 originalStream.reset();
256 }
257
258
259 public boolean markSupported() {
260 return originalStream.markSupported();
261 }
262
263
264 private int getFrameSize() {
265 return getFormat().getFrameSize();
266 }
267
268}
269
270
271/*** TSynchronousFilteredAudioInputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/package.html b/songdbj/org/tritonus/share/sampled/convert/package.html
new file mode 100644
index 0000000000..d0cc35c408
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/convert/package.html
@@ -0,0 +1,17 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Base classes for the implementation of FormatConversionProviders.
8 The classes provided here .</p>
9
10 @see javax.sound.sampled.spi.FormatConversionProvider
11 @see org.tritonus.sampled.convert
12 @see org.tritonus.sampled.convert.gsm
13 @see org.tritonus.sampled.convert.jorbis
14 @see org.tritonus.sampled.convert.lame
15 @see org.tritonus.sampled.convert.vorbis
16 </body>
17</html>
diff --git a/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java
new file mode 100644
index 0000000000..d76296cd2d
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java
@@ -0,0 +1,113 @@
1/*
2 * AudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioFormat;
36
37
38
39/** Represents a one-time writing of audio data to a destination (file or output stream).
40 *
41 * This interface is the lowest abstraction level of writing audio data.
42 * Implementations of this interface should, when write() is called, never
43 * do buffering and they should never do format conversions. However,
44 * this interface is intended to abstract the file format (how the
45 * headers and data chunks look like) and the way of writing to the
46 * destination object. (implementation note [non-normative]: the last
47 * should be done by using TDataOutputStream implementing classes).
48 *
49 * One reasoning behind this interface was to allow direct, unbuffered
50 * writing of recorded data.
51 * In JS API 0.90, there was no obvious way for this.
52 * Data have had to be recorded to a buffer, then written to a file
53 * from that buffer.
54 * This gave problems with long recordings, where the main
55 * memory of the machine is not big enough to hold all data. There are
56 * two ways so solve this:
57 *
58 * a) Having a special AudioInputStream that fetches its data from a
59 * TargetDataLine. This way, the loop inside the AudioFileWriters reads
60 * directely from the recording line via the special AudioInputStream.
61 * This is the solution Sun adopted for JS 1.0.
62 *
63 * b) The other way is to expose a direct interface to the writing of the
64 * audio file with no loop inside it. This is to enable the application
65 * programmer to write the main loop itself, possibly doing some
66 * additional processing inside it. This is the more flexible way.
67 * The drawback is that it requires a new architecture for writing files.
68 *
69 * This interface is the central part of a proposal for the second
70 * solution.
71 * The idea is now to use the new structure inside the old one to gain
72 * experience with it before proposing to make it a public interface
73 * (public in the sense that it is part of the javax.sound.sampled
74 * package).
75 *
76 * @author Matthias Pfisterer
77 */
78public interface AudioOutputStream
79{
80 /**
81 * Retrieves the AufioFormat of this AudioOutputStream.
82 */
83 public AudioFormat getFormat();
84
85
86 /** Gives length of the stream.
87 * This value is in bytes. It may be AudioSystem.NOT_SPECIFIED
88 * to express that the length is unknown.
89 */
90 public long getLength();
91
92
93
94 /**
95 * Writes a chunk of audio data to the destination (file or output stream).
96 */
97 // IDEA: use long?
98 public int write(byte[] abData, int nOffset, int nLength)
99 throws IOException;
100
101
102
103 /** Closes the stream.
104 * This does write remaining buffered data to the destination,
105 * backpatch the header, if necessary, and closes the destination.
106 */
107 public void close()
108 throws IOException;
109}
110
111
112
113/*** AudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java
new file mode 100644
index 0000000000..3083fd5b8f
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java
@@ -0,0 +1,58 @@
1/*
2 * HeaderlessAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34import javax.sound.sampled.AudioFormat;
35
36
37/**
38 * AudioOutputStream for files without a header; the input is written as it is.
39 *
40 * @author Florian Bomers
41 */
42
43// todo: implement directly AudioOutputStream without using TAudioOutputStream
44
45public class HeaderlessAudioOutputStream extends TAudioOutputStream {
46
47 public HeaderlessAudioOutputStream(AudioFormat audioFormat,
48 long lLength,
49 TDataOutputStream dataOutputStream) {
50 super(audioFormat, lLength, dataOutputStream, false);
51 }
52
53 protected void writeHeader() throws IOException
54 {
55 }
56}
57
58/*** HeaderlessAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java
new file mode 100644
index 0000000000..fd9831e291
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java
@@ -0,0 +1,113 @@
1/*
2 * TAudioFileFormat.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.util.Collections;
34import java.util.HashMap;
35import java.util.Map;
36
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioFormat;
39
40
41
42/**
43 * This class is just to have a public constructor taking the
44 * number of bytes of the whole file. The public constructor of
45 * AudioFileFormat doesn't take this parameter, the one who takes
46 * it is protected.
47 *
48 * @author Matthias Pfisterer
49 */
50public class TAudioFileFormat
51extends AudioFileFormat
52{
53 private Map<String, Object> m_properties;
54 private Map<String, Object> m_unmodifiableProperties;
55
56
57 /*
58 * Note that the order of the arguments is different from
59 * the one in AudioFileFormat.
60 */
61 public TAudioFileFormat(Type type,
62 AudioFormat audioFormat,
63 int nLengthInFrames,
64 int nLengthInBytes)
65 {
66 super(type,
67 nLengthInBytes,
68 audioFormat,
69 nLengthInFrames);
70 }
71
72
73 public TAudioFileFormat(Type type,
74 AudioFormat audioFormat,
75 int nLengthInFrames,
76 int nLengthInBytes,
77 Map<String, Object> properties)
78 {
79 super(type,
80 nLengthInBytes,
81 audioFormat,
82 nLengthInFrames);
83 initMaps(properties);
84 }
85
86
87 private void initMaps(Map<String, Object> properties)
88 {
89 /* Here, we make a shallow copy of the map. It's unclear if this
90 is sufficient (of if a deep copy should be made).
91 */
92 m_properties = new HashMap<String, Object>();
93 m_properties.putAll(properties);
94 m_unmodifiableProperties = Collections.unmodifiableMap(m_properties);
95 }
96
97
98 public Map<String, Object> properties()
99 {
100 return m_unmodifiableProperties;
101 }
102
103
104
105 protected void setProperty(String key, Object value)
106 {
107 m_properties.put(key, value);
108 }
109}
110
111
112
113/*** TAudioFileFormat.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java
new file mode 100644
index 0000000000..ee79becf20
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java
@@ -0,0 +1,510 @@
1/*
2 * TAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 * Copyright (c) 2001 by Florian Bomers <http://www.bomers.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.file;
31
32import java.io.BufferedInputStream;
33import java.io.File;
34import java.io.FileInputStream;
35import java.io.DataInputStream;
36import java.io.InputStream;
37import java.io.IOException;
38import java.io.EOFException;
39
40import java.net.URL;
41import java.net.URLConnection;
42
43import javax.sound.sampled.AudioFormat;
44import javax.sound.sampled.AudioInputStream;
45import javax.sound.sampled.AudioFileFormat;
46import javax.sound.sampled.AudioSystem;
47import javax.sound.sampled.UnsupportedAudioFileException;
48import javax.sound.sampled.spi.AudioFileReader;
49
50import org.tritonus.share.TDebug;
51
52
53
54/** Base class for audio file readers.
55 This is Tritonus' base class for classes that provide the facility
56 of detecting an audio file type and reading its header.
57 Classes should be derived from this class or one of its subclasses
58 rather than from javax.sound.sampled.spi.AudioFileReader.
59
60 @author Matthias Pfisterer
61 @author Florian Bomers
62*/
63public abstract class TAudioFileReader
64extends AudioFileReader
65{
66 private int m_nMarkLimit = -1;
67 private boolean m_bRereading;
68
69
70 protected TAudioFileReader(int nMarkLimit)
71 {
72 this(nMarkLimit, false);
73 }
74
75
76
77 protected TAudioFileReader(int nMarkLimit, boolean bRereading)
78 {
79 m_nMarkLimit = nMarkLimit;
80 m_bRereading = bRereading;
81 }
82
83
84
85 private int getMarkLimit()
86 {
87 return m_nMarkLimit;
88 }
89
90
91
92 private boolean isRereading()
93 {
94 return m_bRereading;
95 }
96
97
98
99 /** Get an AudioFileFormat object for a File.
100 This method calls getAudioFileFormat(InputStream, long).
101 Subclasses should not override this method unless there are
102 really severe reasons. Normally, it is sufficient to
103 implement getAudioFileFormat(InputStream, long).
104
105 @param file the file to read from.
106 @return an AudioFileFormat instance containing
107 information from the header of the file passed in.
108 */
109 public AudioFileFormat getAudioFileFormat(File file)
110 throws UnsupportedAudioFileException, IOException
111 {
112 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(File): begin"); }
113 long lFileLengthInBytes = file.length();
114 InputStream inputStream = new FileInputStream(file);
115 AudioFileFormat audioFileFormat = null;
116 try
117 {
118 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
119 }
120 finally
121 {
122 inputStream.close();
123 }
124 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(File): end"); }
125 return audioFileFormat;
126 }
127
128
129
130 /** Get an AudioFileFormat object for a URL.
131 This method calls getAudioFileFormat(InputStream, long).
132 Subclasses should not override this method unless there are
133 really severe reasons. Normally, it is sufficient to
134 implement getAudioFileFormat(InputStream, long).
135
136 @param url the URL to read from.
137 @return an AudioFileFormat instance containing
138 information from the header of the URL passed in.
139 */
140 public AudioFileFormat getAudioFileFormat(URL url)
141 throws UnsupportedAudioFileException, IOException
142
143 {
144 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(URL): begin"); }
145 long lFileLengthInBytes = getDataLength(url);
146 InputStream inputStream = url.openStream();
147 AudioFileFormat audioFileFormat = null;
148 try
149 {
150 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
151 }
152 finally
153 {
154 inputStream.close();
155 }
156 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(URL): end"); }
157 return audioFileFormat;
158 }
159
160
161
162 /** Get an AudioFileFormat object for an InputStream.
163 This method calls getAudioFileFormat(InputStream, long).
164 Subclasses should not override this method unless there are
165 really severe reasons. Normally, it is sufficient to
166 implement getAudioFileFormat(InputStream, long).
167
168 @param inputStream the stream to read from.
169 @return an AudioFileFormat instance containing
170 information from the header of the stream passed in.
171 */
172 public AudioFileFormat getAudioFileFormat(InputStream inputStream)
173 throws UnsupportedAudioFileException, IOException
174
175 {
176 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): begin"); }
177 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
178 inputStream.mark(getMarkLimit());
179 AudioFileFormat audioFileFormat = null;
180 try
181 {
182 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
183 }
184 finally
185 {
186 /* TODO: required semantics is unclear: should reset()
187 be executed only when there is an exception or
188 should it be done always?
189 */
190 inputStream.reset();
191 }
192 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): end"); }
193 return audioFileFormat;
194 }
195
196
197
198 /** Get an AudioFileFormat (internal implementation).
199 Subclasses must implement this method in a way specific
200 to the file format they handle.
201
202 Note that depending on the implementation of this method,
203 you should or should not override
204 getAudioInputStream(InputStream, long), too (see comment
205 there).
206
207 @param inputStream The InputStream to read from.
208 @param lFileLengthInBytes The size of the originating
209 file, if known. If it isn't known, AudioSystem.NOT_SPECIFIED
210 should be passed. This value may be used for byteLength in
211 AudioFileFormat, if this value can't be derived from the
212 informmation in the file header.
213
214 @return an AudioFileFormat instance containing
215 information from the header of the stream passed in as
216 inputStream.
217 */
218 protected abstract AudioFileFormat getAudioFileFormat(
219 InputStream inputStream,
220 long lFileLengthInBytes)
221 throws UnsupportedAudioFileException, IOException;
222
223
224
225 /** Get an AudioInputStream object for a file.
226 This method calls getAudioInputStream(InputStream, long).
227 Subclasses should not override this method unless there are
228 really severe reasons. Normally, it is sufficient to
229 implement getAudioFileFormat(InputStream, long) and perhaps
230 override getAudioInputStream(InputStream, long).
231
232 @param file the File object to read from.
233 @return an AudioInputStream instance containing
234 the audio data from this file.
235 */
236 public AudioInputStream getAudioInputStream(File file)
237 throws UnsupportedAudioFileException, IOException
238 {
239 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(File): begin"); }
240 long lFileLengthInBytes = file.length();
241 InputStream inputStream = new FileInputStream(file);
242 AudioInputStream audioInputStream = null;
243 try
244 {
245 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
246 }
247 catch (UnsupportedAudioFileException e)
248 {
249 inputStream.close();
250 throw e;
251 }
252 catch (IOException e)
253 {
254 inputStream.close();
255 throw e;
256 }
257 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(File): end"); }
258 return audioInputStream;
259 }
260
261
262
263 /** Get an AudioInputStream object for a URL.
264 This method calls getAudioInputStream(InputStream, long).
265 Subclasses should not override this method unless there are
266 really severe reasons. Normally, it is sufficient to
267 implement getAudioFileFormat(InputStream, long) and perhaps
268 override getAudioInputStream(InputStream, long).
269
270 @param url the URL to read from.
271 @return an AudioInputStream instance containing
272 the audio data from this URL.
273 */
274 public AudioInputStream getAudioInputStream(URL url)
275 throws UnsupportedAudioFileException, IOException
276 {
277 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(URL): begin"); }
278 long lFileLengthInBytes = getDataLength(url);
279 InputStream inputStream = url.openStream();
280 AudioInputStream audioInputStream = null;
281 try
282 {
283 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
284 }
285 catch (UnsupportedAudioFileException e)
286 {
287 inputStream.close();
288 throw e;
289 }
290 catch (IOException e)
291 {
292 inputStream.close();
293 throw e;
294 }
295 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(URL): end"); }
296 return audioInputStream;
297 }
298
299
300
301 /** Get an AudioInputStream object for an InputStream.
302 This method calls getAudioInputStream(InputStream, long).
303 Subclasses should not override this method unless there are
304 really severe reasons. Normally, it is sufficient to
305 implement getAudioFileFormat(InputStream, long) and perhaps
306 override getAudioInputStream(InputStream, long).
307
308 @param inputStream the stream to read from.
309 @return an AudioInputStream instance containing
310 the audio data from this stream.
311 */
312 public AudioInputStream getAudioInputStream(InputStream inputStream)
313 throws UnsupportedAudioFileException, IOException
314 {
315 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): begin"); }
316 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
317 AudioInputStream audioInputStream = null;
318 inputStream.mark(getMarkLimit());
319 try
320 {
321 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
322 }
323 catch (UnsupportedAudioFileException e)
324 {
325 inputStream.reset();
326 throw e;
327 }
328 catch (IOException e)
329 {
330 inputStream.reset();
331 throw e;
332 }
333 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): end"); }
334 return audioInputStream;
335 }
336
337
338
339 /** Get an AudioInputStream (internal implementation).
340 This implementation calls getAudioFileFormat() with the
341 same arguments as passed in here. Then, it constructs
342 an AudioInputStream instance. This instance takes the passed
343 inputStream in the state it is left after getAudioFileFormat()
344 did its work. In other words, the implementation here
345 assumes that getAudioFileFormat() reads the entire header
346 up to a position exactely where the audio data starts.
347 If this can't be realized for a certain format, this method
348 should be overridden.
349
350 @param inputStream The InputStream to read from.
351 @param lFileLengthInBytes The size of the originating
352 file, if known. If it isn't known, AudioSystem.NOT_SPECIFIED
353 should be passed. This value may be used for byteLength in
354 AudioFileFormat, if this value can't be derived from the
355 informmation in the file header.
356 */
357 protected AudioInputStream getAudioInputStream(InputStream inputStream, long lFileLengthInBytes)
358 throws UnsupportedAudioFileException, IOException
359 {
360 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): begin"); }
361 if (isRereading())
362 {
363 inputStream = new BufferedInputStream(inputStream, getMarkLimit());
364 inputStream.mark(getMarkLimit());
365 }
366 AudioFileFormat audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
367 if (isRereading())
368 {
369 inputStream.reset();
370 }
371 AudioInputStream audioInputStream =
372 new AudioInputStream(inputStream,
373 audioFileFormat.getFormat(),
374 audioFileFormat.getFrameLength());
375 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): end"); }
376 return audioInputStream;
377 }
378
379
380
381 protected static int calculateFrameSize(int nSampleSize, int nNumChannels)
382 {
383 return ((nSampleSize + 7) / 8) * nNumChannels;
384 }
385
386
387
388 private static long getDataLength(URL url)
389 throws IOException
390 {
391 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
392 URLConnection connection = url.openConnection();
393 connection.connect();
394 int nLength = connection.getContentLength();
395 if (nLength > 0)
396 {
397 lFileLengthInBytes = nLength;
398 }
399 return lFileLengthInBytes;
400 }
401
402
403
404 public static int readLittleEndianInt(InputStream is)
405 throws IOException
406 {
407 int b0 = is.read();
408 int b1 = is.read();
409 int b2 = is.read();
410 int b3 = is.read();
411 if ((b0 | b1 | b2 | b3) < 0)
412 {
413 throw new EOFException();
414 }
415 return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
416 }
417
418
419
420 public static short readLittleEndianShort(InputStream is)
421 throws IOException
422 {
423 int b0 = is.read();
424 int b1 = is.read();
425 if ((b0 | b1) < 0)
426 {
427 throw new EOFException();
428 }
429 return (short) ((b1 << 8) + (b0 << 0));
430 }
431
432
433/*
434 * C O N V E R T F R O M I E E E E X T E N D E D
435 */
436
437/*
438 * Copyright (C) 1988-1991 Apple Computer, Inc.
439 * All rights reserved.
440 *
441 * Machine-independent I/O routines for IEEE floating-point numbers.
442 *
443 * NaN's and infinities are converted to HUGE_VAL or HUGE, which
444 * happens to be infinity on IEEE machines. Unfortunately, it is
445 * impossible to preserve NaN's in a machine-independent way.
446 * Infinities are, however, preserved on IEEE machines.
447 *
448 * These routines have been tested on the following machines:
449 * Apple Macintosh, MPW 3.1 C compiler
450 * Apple Macintosh, THINK C compiler
451 * Silicon Graphics IRIS, MIPS compiler
452 * Cray X/MP and Y/MP
453 * Digital Equipment VAX
454 *
455 *
456 * Implemented by Malcolm Slaney and Ken Turkowski.
457 *
458 * Malcolm Slaney contributions during 1988-1990 include big- and little-
459 * endian file I/O, conversion to and from Motorola's extended 80-bit
460 * floating-point format, and conversions to and from IEEE single-
461 * precision floating-point format.
462 *
463 * In 1991, Ken Turkowski implemented the conversions to and from
464 * IEEE double-precision format, added more precision to the extended
465 * conversions, and accommodated conversions involving +/- infinity,
466 * NaN's, and denormalized numbers.
467 */
468
469 public static double readIeeeExtended(DataInputStream dis)
470 throws IOException
471 {
472 double f = 0.0D;
473 int expon = 0;
474 long hiMant = 0L;
475 long loMant = 0L;
476 double HUGE = 3.4028234663852886E+038D;
477 expon = dis.readUnsignedShort();
478 long t1 = dis.readUnsignedShort();
479 long t2 = dis.readUnsignedShort();
480 hiMant = t1 << 16 | t2;
481 t1 = dis.readUnsignedShort();
482 t2 = dis.readUnsignedShort();
483 loMant = t1 << 16 | t2;
484 if(expon == 0 && hiMant == 0L && loMant == 0L)
485 {
486 f = 0.0D;
487 }
488 else
489 {
490 if(expon == 32767)
491 {
492 f = HUGE;
493 }
494 else
495 {
496 expon -= 16383;
497 expon -= 31;
498 f = hiMant * Math.pow(2D, expon);
499 expon -= 32;
500 f += loMant * Math.pow(2D, expon);
501 }
502 }
503 return f;
504 }
505}
506
507
508
509/*** TAudioFileReader.java ***/
510
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java
new file mode 100644
index 0000000000..d9d6ee86ec
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java
@@ -0,0 +1,484 @@
1/*
2 * TAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 * Copyright (c) 1999, 2000 by Florian Bomers <http://www.bomers.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.File;
34import java.io.FileOutputStream;
35import java.io.InputStream;
36import java.io.IOException;
37import java.io.OutputStream;
38import java.util.Collection;
39import java.util.Iterator;
40
41import javax.sound.sampled.AudioFormat;
42import javax.sound.sampled.AudioFileFormat;
43import javax.sound.sampled.AudioInputStream;
44import javax.sound.sampled.AudioSystem;
45import javax.sound.sampled.spi.AudioFileWriter;
46
47import org.tritonus.share.TDebug;
48import org.tritonus.share.sampled.AudioFormats;
49import org.tritonus.share.sampled.AudioUtils;
50import org.tritonus.share.sampled.TConversionTool;
51import org.tritonus.share.ArraySet;
52
53/**
54 * Common base class for implementing classes of AudioFileWriter.
55 * <p>It provides often-used functionality and the new architecture using
56 * an AudioOutputStream.
57 * <p>There should be only one set of audio formats supported by any given
58 * class of TAudioFileWriter. This class assumes implicitely that all
59 * supported file types have a common set of audio formats they can handle.
60 *
61 * @author Matthias Pfisterer
62 * @author Florian Bomers
63 */
64
65public abstract class TAudioFileWriter
66extends AudioFileWriter
67{
68 protected static final int ALL = AudioSystem.NOT_SPECIFIED;
69
70 public static AudioFormat.Encoding PCM_SIGNED=new AudioFormat.Encoding("PCM_SIGNED");
71 public static AudioFormat.Encoding PCM_UNSIGNED=new AudioFormat.Encoding("PCM_UNSIGNED");
72
73 /** Buffer length for the loop in the write() method.
74 * This is in bytes. Perhaps it should be in frames to give an
75 * equal amount of latency.
76 */
77 private static final int BUFFER_LENGTH = 16384;
78
79 // only needed for Collection.toArray()
80 protected static final AudioFileFormat.Type[] NULL_TYPE_ARRAY = new AudioFileFormat.Type[0];
81
82
83 /** The audio file types (AudioFileFormat.Type) that can be
84 * handled by the AudioFileWriter.
85 */
86 private Collection<AudioFileFormat.Type> m_audioFileTypes;
87
88
89
90 /** The AudioFormats that can be handled by the
91 * AudioFileWriter.
92 */
93 // IDEA: implement a special collection that uses matches() to test whether an element is already in
94 private Collection<AudioFormat> m_audioFormats;
95
96
97 /**
98 * Inheriting classes should call this constructor
99 * in order to make use of the functionality of TAudioFileWriter.
100 */
101 protected TAudioFileWriter(Collection<AudioFileFormat.Type> fileTypes,
102 Collection<AudioFormat> audioFormats)
103 {
104 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.<init>(): begin"); }
105 m_audioFileTypes = fileTypes;
106 m_audioFormats = audioFormats;
107 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.<init>(): end"); }
108 }
109
110 // implementing the interface
111 public AudioFileFormat.Type[] getAudioFileTypes()
112 {
113 return m_audioFileTypes.toArray(NULL_TYPE_ARRAY);
114 }
115
116
117 // implementing the interface
118 public boolean isFileTypeSupported(AudioFileFormat.Type fileType)
119 {
120 return m_audioFileTypes.contains(fileType);
121 }
122
123
124
125 // implementing the interface
126 public AudioFileFormat.Type[] getAudioFileTypes(
127 AudioInputStream audioInputStream)
128 {
129 //$$fb 2000-08-16: rewrote this method. We need to check for *each*
130 // file type, whether the format is supported !
131 AudioFormat format = audioInputStream.getFormat();
132 ArraySet<AudioFileFormat.Type> res=new ArraySet<AudioFileFormat.Type>();
133 Iterator<AudioFileFormat.Type> it=m_audioFileTypes.iterator();
134 while (it.hasNext()) {
135 AudioFileFormat.Type thisType = it.next();
136 if (isAudioFormatSupportedImpl(format, thisType)) {
137 res.add(thisType);
138 }
139 }
140 return res.toArray(NULL_TYPE_ARRAY);
141 }
142
143
144
145 // implementing the interface
146 public boolean isFileTypeSupported(AudioFileFormat.Type fileType, AudioInputStream audioInputStream)
147 {
148 // $$fb 2000-08-16: finally this method works reliably !
149 return isFileTypeSupported(fileType)
150 && (isAudioFormatSupportedImpl(audioInputStream.getFormat(), fileType)
151 || findConvertableFormat(audioInputStream.getFormat(), fileType)!=null);
152 // we may soft it up by including the possibility of endian/sign
153 // changing for PCM formats.
154 // I prefer to return false if the format is not exactly supported
155 // but still exectute the write, if only sign/endian changing is necessary.
156 }
157
158
159
160 // implementing the interface
161 public int write(AudioInputStream audioInputStream,
162 AudioFileFormat.Type fileType,
163 File file)
164 throws IOException
165 {
166 if (TDebug.TraceAudioFileWriter)
167 {
168 TDebug.out(">TAudioFileWriter.write(.., File): called");
169 TDebug.out("class: "+getClass().getName());
170 }
171 //$$fb added this check
172 if (!isFileTypeSupported(fileType)) {
173 if (TDebug.TraceAudioFileWriter)
174 {
175 TDebug.out("< file type is not supported");
176 }
177 throw new IllegalArgumentException("file type is not supported.");
178 }
179
180 AudioFormat inputFormat = audioInputStream.getFormat();
181 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format: " + inputFormat); }
182 AudioFormat outputFormat = null;
183 boolean bNeedsConversion = false;
184 if (isAudioFormatSupportedImpl(inputFormat, fileType))
185 {
186 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is supported directely"); }
187 outputFormat = inputFormat;
188 bNeedsConversion = false;
189 }
190 else
191 {
192 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is not supported directely; trying to find a convertable format"); }
193 outputFormat = findConvertableFormat(inputFormat, fileType);
194 if (outputFormat != null)
195 {
196 bNeedsConversion = true;
197 // $$fb 2000-08-16 made consistent with new conversion trials
198 // if 8 bit and only endianness changed, don't convert !
199 if (outputFormat.getSampleSizeInBits()==8
200 && outputFormat.getEncoding().equals(inputFormat.getEncoding())) {
201 bNeedsConversion = false;
202 }
203 }
204 else
205 {
206 if (TDebug.TraceAudioFileWriter) { TDebug.out("< input format is not supported and not convertable."); }
207 throw new IllegalArgumentException("format not supported and not convertable");
208 }
209 }
210 long lLengthInBytes = AudioUtils.getLengthInBytes(audioInputStream);
211 TDataOutputStream dataOutputStream = new TSeekableDataOutputStream(file);
212 AudioOutputStream audioOutputStream =
213 getAudioOutputStream(
214 outputFormat,
215 lLengthInBytes,
216 fileType,
217 dataOutputStream);
218 int written=writeImpl(audioInputStream,
219 audioOutputStream,
220 bNeedsConversion);
221 if (TDebug.TraceAudioFileWriter)
222 {
223 TDebug.out("< wrote "+written+" bytes.");
224 }
225 return written;
226 }
227
228
229
230 // implementing the interface
231 public int write(AudioInputStream audioInputStream,
232 AudioFileFormat.Type fileType,
233 OutputStream outputStream)
234 throws IOException
235 {
236 //$$fb added this check
237 if (!isFileTypeSupported(fileType)) {
238 throw new IllegalArgumentException("file type is not supported.");
239 }
240 if (TDebug.TraceAudioFileWriter)
241 {
242 TDebug.out(">TAudioFileWriter.write(.., OutputStream): called");
243 TDebug.out("class: "+getClass().getName());
244 }
245 AudioFormat inputFormat = audioInputStream.getFormat();
246 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format: " + inputFormat); }
247 AudioFormat outputFormat = null;
248 boolean bNeedsConversion = false;
249 if (isAudioFormatSupportedImpl(inputFormat, fileType))
250 {
251 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is supported directely"); }
252 outputFormat = inputFormat;
253 bNeedsConversion = false;
254 }
255 else
256 {
257 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is not supported directely; trying to find a convertable format"); }
258 outputFormat = findConvertableFormat(inputFormat, fileType);
259 if (outputFormat != null)
260 {
261 bNeedsConversion = true;
262 // $$fb 2000-08-16 made consistent with new conversion trials
263 // if 8 bit and only endianness changed, don't convert !
264 if (outputFormat.getSampleSizeInBits()==8
265 && outputFormat.getEncoding().equals(inputFormat.getEncoding())) {
266 bNeedsConversion = false;
267 }
268 }
269 else
270 {
271 if (TDebug.TraceAudioFileWriter) { TDebug.out("< format is not supported"); }
272 throw new IllegalArgumentException("format not supported and not convertable");
273 }
274 }
275 long lLengthInBytes = AudioUtils.getLengthInBytes(audioInputStream);
276 TDataOutputStream dataOutputStream = new TNonSeekableDataOutputStream(outputStream);
277 AudioOutputStream audioOutputStream =
278 getAudioOutputStream(
279 outputFormat,
280 lLengthInBytes,
281 fileType,
282 dataOutputStream);
283 int written=writeImpl(audioInputStream,
284 audioOutputStream,
285 bNeedsConversion);
286 if (TDebug.TraceAudioFileWriter) { TDebug.out("< wrote "+written+" bytes."); }
287 return written;
288 }
289
290
291
292 protected int writeImpl(
293 AudioInputStream audioInputStream,
294 AudioOutputStream audioOutputStream,
295 boolean bNeedsConversion)
296 throws IOException
297 {
298 if (TDebug.TraceAudioFileWriter)
299 {
300 TDebug.out(">TAudioFileWriter.writeImpl(): called");
301 TDebug.out("class: "+getClass().getName());
302 }
303 int nTotalWritten = 0;
304 AudioFormat inputFormat = audioInputStream.getFormat();
305 AudioFormat outputFormat = audioOutputStream.getFormat();
306
307 // TODO: handle case when frame size is unknown ?
308 int nBytesPerSample = outputFormat.getFrameSize() / outputFormat.getChannels();
309
310 //$$fb 2000-07-18: BUFFER_LENGTH must be a multiple of frame size...
311 int nBufferSize=((int)BUFFER_LENGTH/outputFormat.getFrameSize())*outputFormat.getFrameSize();
312 byte[] abBuffer = new byte[nBufferSize];
313 while (true)
314 {
315 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying to read (bytes): " + abBuffer.length); }
316 int nBytesRead = audioInputStream.read(abBuffer);
317 if (TDebug.TraceAudioFileWriter) { TDebug.out("read (bytes): " + nBytesRead); }
318 if (nBytesRead == -1)
319 {
320 break;
321 }
322 if (bNeedsConversion)
323 {
324 TConversionTool.changeOrderOrSign(abBuffer, 0,
325 nBytesRead, nBytesPerSample);
326 }
327 int nWritten = audioOutputStream.write(abBuffer, 0, nBytesRead);
328 nTotalWritten += nWritten;
329 }
330 if (TDebug.TraceAudioFileWriter) { TDebug.out("<TAudioFileWriter.writeImpl(): after main loop. Wrote "+nTotalWritten+" bytes"); }
331 audioOutputStream.close();
332 // TODO: get bytes written for header etc. from AudioOutputStrem and add to nTotalWrittenBytes
333 return nTotalWritten;
334 }
335
336
337 /** Returns the AudioFormat that can be handled for the given file type.
338 * In this simple implementation, all handled AudioFormats are
339 * returned (i.e. the fileType argument is ignored). If the
340 * handled AudioFormats depend on the file type, this method
341 * has to be overwritten by subclasses.
342 */
343 protected Iterator<AudioFormat> getSupportedAudioFormats(AudioFileFormat.Type fileType)
344 {
345 return m_audioFormats.iterator();
346 }
347
348
349 /** Checks whether the passed <b>AudioFormat</b> can be handled.
350 * In this simple implementation, it is only checked if the
351 * passed AudioFormat matches one of the generally handled
352 * formats (i.e. the fileType argument is ignored). If the
353 * handled AudioFormats depend on the file type, this method
354 * or getSupportedAudioFormats() (on which this method relies)
355 * has to be overwritten by subclasses.
356 * <p>
357 * This is the central method for checking if a FORMAT is supported.
358 * Inheriting classes can overwrite this for performance
359 * or to exclude/include special type/format combinations.
360 * <p>
361 * This method is only called when the <code>fileType</code>
362 * is in the list of supported file types ! Overriding
363 * classes <b>need not</b> check this.
364 */
365 //$$fb 2000-08-16 changed name, changed documentation. Semantics !
366 protected boolean isAudioFormatSupportedImpl(
367 AudioFormat audioFormat,
368 AudioFileFormat.Type fileType)
369 {
370 if (TDebug.TraceAudioFileWriter)
371 {
372 TDebug.out("> TAudioFileWriter.isAudioFormatSupportedImpl(): format to test: " + audioFormat);
373 TDebug.out("class: "+getClass().getName());
374 }
375 Iterator audioFormats = getSupportedAudioFormats(fileType);
376 while (audioFormats.hasNext())
377 {
378 AudioFormat handledFormat = (AudioFormat) audioFormats.next();
379 if (TDebug.TraceAudioFileWriter) { TDebug.out("matching against format : " + handledFormat); }
380 if (AudioFormats.matches(handledFormat, audioFormat))
381 {
382 if (TDebug.TraceAudioFileWriter) { TDebug.out("<...succeeded."); }
383 return true;
384 }
385 }
386 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
387 return false;
388 }
389
390
391
392 protected abstract AudioOutputStream getAudioOutputStream(
393 AudioFormat audioFormat,
394 long lLengthInBytes,
395 AudioFileFormat.Type fileType,
396 TDataOutputStream dataOutputStream)
397 throws IOException;
398
399 private AudioFormat findConvertableFormat(
400 AudioFormat inputFormat,
401 AudioFileFormat.Type fileType)
402 {
403 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.findConvertableFormat(): input format: " + inputFormat); }
404 if (!isFileTypeSupported(fileType)) {
405 if (TDebug.TraceAudioFileWriter) { TDebug.out("< input file type is not supported."); }
406 return null;
407 }
408 AudioFormat.Encoding inputEncoding = inputFormat.getEncoding();
409 if ((inputEncoding.equals(PCM_SIGNED) || inputEncoding.equals(PCM_UNSIGNED))
410 && inputFormat.getSampleSizeInBits() == 8)
411 {
412 AudioFormat outputFormat = convertFormat(inputFormat, true, false);
413 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
414 if (isAudioFormatSupportedImpl(outputFormat, fileType))
415 {
416 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
417 return outputFormat;
418 }
419 //$$fb 2000-08-16: added trial of other endianness for 8bit. We try harder !
420 outputFormat = convertFormat(inputFormat, false, true);
421 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
422 if (isAudioFormatSupportedImpl(outputFormat, fileType))
423 {
424 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
425 return outputFormat;
426 }
427 outputFormat = convertFormat(inputFormat, true, true);
428 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
429 if (isAudioFormatSupportedImpl(outputFormat, fileType))
430 {
431 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
432 return outputFormat;
433 }
434 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
435 return null;
436 }
437 else if (inputEncoding.equals(PCM_SIGNED) &&
438 (inputFormat.getSampleSizeInBits() == 16 ||
439 inputFormat.getSampleSizeInBits() == 24 ||
440 inputFormat.getSampleSizeInBits() == 32) )
441 {
442 // TODO: possible to allow all sample sized > 8 bit?
443 // $$ fb: don't think that this is necessary. Well, let's talk about that in 5 years :)
444 AudioFormat outputFormat = convertFormat(inputFormat, false, true);
445 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
446 if (isAudioFormatSupportedImpl(outputFormat, fileType))
447 {
448 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
449 return outputFormat;
450 }
451 else
452 {
453 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
454 return null;
455 }
456 }
457 else
458 {
459 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
460 return null;
461 }
462 }
463
464 // $$fb 2000-08-16: added convenience method
465 private AudioFormat convertFormat(AudioFormat format, boolean changeSign, boolean changeEndian) {
466 AudioFormat.Encoding enc=PCM_SIGNED;
467 if (format.getEncoding().equals(PCM_UNSIGNED)!=changeSign) {
468 enc=PCM_UNSIGNED;
469 }
470 return new AudioFormat(
471 enc,
472 format.getSampleRate(),
473 format.getSampleSizeInBits(),
474 format.getChannels(),
475 format.getFrameSize(),
476 format.getFrameRate(),
477 format.isBigEndian() ^ changeEndian);
478 }
479
480}
481
482
483
484/*** TAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java
new file mode 100644
index 0000000000..e54316c0a6
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java
@@ -0,0 +1,197 @@
1/*
2 * TAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.TDebug;
39
40
41/**
42 * Base class for classes implementing AudioOutputStream.
43 *
44 * @author Matthias Pfisterer
45 */
46
47public abstract class TAudioOutputStream
48implements AudioOutputStream
49{
50 private AudioFormat m_audioFormat;
51 private long m_lLength; // in bytes
52 private long m_lCalculatedLength;
53 private TDataOutputStream m_dataOutputStream;
54 private boolean m_bDoBackPatching;
55 private boolean m_bHeaderWritten;
56
57
58
59 protected TAudioOutputStream(AudioFormat audioFormat,
60 long lLength,
61 TDataOutputStream dataOutputStream,
62 boolean bDoBackPatching)
63 {
64 m_audioFormat = audioFormat;
65 m_lLength = lLength;
66 m_lCalculatedLength = 0;
67 m_dataOutputStream = dataOutputStream;
68 m_bDoBackPatching = bDoBackPatching;
69 m_bHeaderWritten = false;
70 }
71
72
73
74 public AudioFormat getFormat()
75 {
76 return m_audioFormat;
77 }
78
79
80
81 /** Gives length of the stream.
82 * This value is in bytes. It may be AudioSystem.NOT_SPECIFIED
83 * to express that the length is unknown.
84 */
85 public long getLength()
86 {
87 return m_lLength;
88 }
89
90
91
92 /** Gives number of bytes already written.
93 */
94 // IDEA: rename this to BytesWritten or something like that ?
95 public long getCalculatedLength()
96 {
97 return m_lCalculatedLength;
98 }
99
100 protected TDataOutputStream getDataOutputStream()
101 {
102 return m_dataOutputStream;
103 }
104
105
106 /** Writes audio data to the destination (file or output stream).
107 */
108 // IDEA: use long?
109 public int write(byte[] abData, int nOffset, int nLength)
110 throws IOException
111 {
112 if (TDebug.TraceAudioOutputStream)
113 {
114 TDebug.out("TAudioOutputStream.write(): wanted length: " + nLength);
115 }
116 if (! m_bHeaderWritten)
117 {
118 writeHeader();
119 m_bHeaderWritten = true;
120 }
121 // $$fb added
122 // check that total writes do not exceed specified length
123 long lTotalLength=getLength();
124 if (lTotalLength!=AudioSystem.NOT_SPECIFIED && (m_lCalculatedLength+nLength)>lTotalLength) {
125 if (TDebug.TraceAudioOutputStream) {
126 TDebug.out("TAudioOutputStream.write(): requested more bytes to write than possible.");
127 }
128 nLength=(int) (lTotalLength-m_lCalculatedLength);
129 // sanity
130 if (nLength<0) {
131 nLength=0;
132 }
133 }
134 // TODO: throw an exception if nLength==0 ? (to indicate end of file ?)
135 if (nLength>0) {
136 m_dataOutputStream.write(abData, nOffset, nLength);
137 m_lCalculatedLength += nLength;
138 }
139 if (TDebug.TraceAudioOutputStream)
140 {
141 TDebug.out("TAudioOutputStream.write(): calculated (total) length: " + m_lCalculatedLength+" bytes = "+(m_lCalculatedLength/getFormat().getFrameSize())+" frames");
142 }
143 return nLength;
144 }
145
146
147
148 /** Writes the header of the audio file.
149 */
150 protected abstract void writeHeader()
151 throws IOException;
152
153
154
155 /** Closes the stream.
156 * This does write remaining buffered data to the destination,
157 * backpatch the header, if necessary, and closes the destination.
158 */
159 public void close()
160 throws IOException
161 {
162 if (TDebug.TraceAudioOutputStream)
163 {
164 TDebug.out("TAudioOutputStream.close(): called");
165 }
166 // flush?
167 if (m_bDoBackPatching)
168 {
169 if (TDebug.TraceAudioOutputStream)
170 {
171 TDebug.out("TAudioOutputStream.close(): patching header");
172 }
173 patchHeader();
174 }
175 m_dataOutputStream.close();
176 }
177
178
179
180 protected void patchHeader()
181 throws IOException
182 {
183 TDebug.out("TAudioOutputStream.patchHeader(): called");
184 // DO NOTHING
185 }
186
187
188
189 protected void setLengthFromCalculatedLength()
190 {
191 m_lLength = m_lCalculatedLength;
192 }
193}
194
195
196
197/*** TAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java
new file mode 100644
index 0000000000..eacc00a2e2
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java
@@ -0,0 +1,79 @@
1/*
2 * TDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.DataOutput;
34import java.io.IOException;
35import java.io.InputStream;
36
37
38/**
39 * Interface for the file writing classes.
40 * <p>Like that it is possible to write to a file without knowing
41 * the length before.
42 *
43 * @author Florian Bomers
44 */
45public interface TDataOutputStream
46extends DataOutput
47{
48 public boolean supportsSeek();
49
50
51
52 public void seek(long position)
53 throws IOException;
54
55
56
57 public long getFilePointer()
58 throws IOException;
59
60
61
62 public long length()
63 throws IOException;
64
65
66 public void writeLittleEndian32(int value)
67 throws IOException;
68
69
70 public void writeLittleEndian16(short value)
71 throws IOException;
72
73 public void close()
74 throws IOException;
75}
76
77
78
79/*** TDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java b/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java
new file mode 100644
index 0000000000..a9d76de505
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java
@@ -0,0 +1,84 @@
1/*
2 * THeaderlessAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 - 2002 by Matthias Pfisterer
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.file;
31
32import java.io.IOException;
33import java.util.Collection;
34
35import javax.sound.sampled.AudioFileFormat;
36import javax.sound.sampled.AudioFormat;
37
38import org.tritonus.share.TDebug;
39
40
41
42/** Base class for formats without extra header.
43 This AudioFileWriter is typically used for compressed formats
44 where the encoder puts a header into the encoded stream. In this
45 case, the AudioFileWriter needs not to add a header. This is why
46 THeaderlessAudioOutputStream is used here.
47
48 @author Florian Bomers
49 @author Matthias Pfisterer
50*/
51public class THeaderlessAudioFileWriter
52extends TAudioFileWriter
53{
54 protected THeaderlessAudioFileWriter(Collection<AudioFileFormat.Type> fileTypes,
55 Collection<AudioFormat> audioFormats)
56 {
57 super(fileTypes, audioFormats);
58 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.<init>(): begin"); }
59 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.<init>(): end"); }
60 }
61
62
63
64 protected AudioOutputStream getAudioOutputStream(
65 AudioFormat audioFormat,
66 long lLengthInBytes,
67 AudioFileFormat.Type fileType,
68 TDataOutputStream dataOutputStream)
69 throws IOException
70 {
71 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.getAudioOutputStream(): begin"); }
72 AudioOutputStream aos = new HeaderlessAudioOutputStream(
73 audioFormat,
74 lLengthInBytes,
75 dataOutputStream);
76 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.getAudioOutputStream(): end"); }
77 return aos;
78 }
79
80}
81
82
83
84/*** THeaderlessAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java
new file mode 100644
index 0000000000..2e9704ed10
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java
@@ -0,0 +1,109 @@
1/*
2 * TNonSeekableDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled.file;
33
34import java.io.IOException;
35import java.io.OutputStream;
36import java.io.DataOutputStream;
37
38
39
40/**
41 * A TDataOutputStream that does not allow seeking.
42 *
43 * @author Florian Bomers
44 * @author Matthias Pfisterer
45 */
46public class TNonSeekableDataOutputStream
47extends DataOutputStream
48implements TDataOutputStream
49{
50 public TNonSeekableDataOutputStream(OutputStream outputStream)
51 {
52 super(outputStream);
53 }
54
55
56
57 public boolean supportsSeek()
58 {
59 return false;
60 }
61
62
63
64 public void seek(long position)
65 throws IOException
66 {
67 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to seek not allowed.");
68 }
69
70
71
72 public long getFilePointer()
73 throws IOException
74 {
75 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to getFilePointer not allowed.");
76 }
77
78
79
80 public long length()
81 throws IOException
82 {
83 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to length not allowed.");
84 }
85
86
87
88 public void writeLittleEndian32(int value)
89 throws IOException
90 {
91 writeByte(value & 0xFF);
92 writeByte((value >> 8) & 0xFF);
93 writeByte((value >> 16) & 0xFF);
94 writeByte((value >> 24) & 0xFF);
95 }
96
97
98
99 public void writeLittleEndian16(short value)
100 throws IOException
101 {
102 writeByte(value & 0xFF);
103 writeByte((value >> 8) & 0xFF);
104 }
105}
106
107
108
109/*** TNonSeekableDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java
new file mode 100644
index 0000000000..6f688c5b2e
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java
@@ -0,0 +1,86 @@
1/*
2 * TSeekableDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled.file;
33
34import java.io.File;
35import java.io.RandomAccessFile;
36import java.io.IOException;
37
38
39
40/**
41 * A TDataOutputStream that allows seeking.
42 *
43 * @author Florian Bomers
44 * @author Matthias Pfisterer
45 */
46public class TSeekableDataOutputStream
47extends RandomAccessFile
48implements TDataOutputStream
49{
50 public TSeekableDataOutputStream(File file)
51 throws IOException
52 {
53 super(file, "rw");
54 }
55
56
57
58 public boolean supportsSeek()
59 {
60 return true;
61 }
62
63
64
65 public void writeLittleEndian32(int value)
66 throws IOException
67 {
68 writeByte(value & 0xFF);
69 writeByte((value >> 8) & 0xFF);
70 writeByte((value >> 16) & 0xFF);
71 writeByte((value >> 24) & 0xFF);
72 }
73
74
75
76 public void writeLittleEndian16(short value)
77 throws IOException
78 {
79 writeByte(value & 0xFF);
80 writeByte((value >> 8) & 0xFF);
81 }
82}
83
84
85
86/*** TSeekableDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/package.html b/songdbj/org/tritonus/share/sampled/file/package.html
new file mode 100644
index 0000000000..a79274048c
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/file/package.html
@@ -0,0 +1,18 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Base classes for the implementation of AudioFileReaders and AudioFileWriters.
8 The classes provided here .</p>
9
10 @see javax.sound.sampled.spi.AudioFileReader
11 @see javax.sound.sampled.spi.AudioFileWriter
12 @see org.tritonus.sampled.file
13 @see org.tritonus.sampled.file.gsm
14 @see org.tritonus.sampled.file.jorbis
15 @see org.tritonus.sampled.file.mpeg
16 @see org.tritonus.sampled.file.vorbis
17 </body>
18</html>
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java b/songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java
new file mode 100644
index 0000000000..e589439838
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java
@@ -0,0 +1,107 @@
1/*
2 * TBaseDataLine.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.mixer;
30
31import java.util.Collection;
32import java.util.EventListener;
33import java.util.EventObject;
34import java.util.HashSet;
35import java.util.Set;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioSystem;
39import javax.sound.sampled.Control;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.LineEvent;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineUnavailableException;
44
45import org.tritonus.share.TDebug;
46
47
48
49/** Base class for implementing SourceDataLine or TargetDataLine.
50 */
51public abstract class TBaseDataLine
52extends TDataLine
53{
54 public TBaseDataLine(TMixer mixer,
55 DataLine.Info info)
56 {
57 super(mixer,
58 info);
59 }
60
61
62
63 public TBaseDataLine(TMixer mixer,
64 DataLine.Info info,
65 Collection<Control> controls)
66 {
67 super(mixer,
68 info,
69 controls);
70 }
71
72
73
74 public void open(AudioFormat format, int nBufferSize)
75 throws LineUnavailableException
76 {
77 if (TDebug.TraceDataLine) { TDebug.out("TBaseDataLine.open(AudioFormat, int): called with buffer size: " + nBufferSize); }
78 setBufferSize(nBufferSize);
79 open(format);
80 }
81
82
83
84 public void open(AudioFormat format)
85 throws LineUnavailableException
86 {
87 if (TDebug.TraceDataLine) { TDebug.out("TBaseDataLine.open(AudioFormat): called"); }
88 setFormat(format);
89 open();
90 }
91
92
93 // IDEA: move to TDataLine or TLine?
94 // necessary and wise at all?
95 protected void finalize()
96 {
97 if (isOpen())
98 {
99 close();
100 }
101 }
102}
103
104
105
106/*** TBaseDataLine.java ***/
107
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java b/songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java
new file mode 100644
index 0000000000..a722edbf31
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java
@@ -0,0 +1,128 @@
1/*
2 * TBooleanControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.BooleanControl;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/** Base class for classes implementing BooleanControl.
41 */
42public class TBooleanControl
43extends BooleanControl
44implements TControllable
45{
46 private TControlController m_controller;
47
48
49
50 public TBooleanControl(BooleanControl.Type type,
51 boolean bInitialValue)
52 {
53 this(type, bInitialValue, null);
54 }
55
56
57
58 public TBooleanControl(BooleanControl.Type type,
59 boolean bInitialValue,
60 TCompoundControl parentControl)
61 {
62 super(type, bInitialValue);
63 if (TDebug.TraceControl)
64 {
65 TDebug.out("TBooleanControl.<init>: begin");
66 }
67 m_controller = new TControlController();
68 if (TDebug.TraceControl)
69 {
70 TDebug.out("TBooleanControl.<init>: end");
71 }
72 }
73
74
75
76 public TBooleanControl(BooleanControl.Type type,
77 boolean bInitialValue,
78 String strTrueStateLabel,
79 String strFalseStateLabel)
80 {
81 this(type, bInitialValue, strTrueStateLabel, strFalseStateLabel, null);
82 }
83
84
85
86 public TBooleanControl(BooleanControl.Type type,
87 boolean bInitialValue,
88 String strTrueStateLabel,
89 String strFalseStateLabel,
90 TCompoundControl parentControl)
91 {
92 super(type, bInitialValue, strTrueStateLabel, strFalseStateLabel);
93 if (TDebug.TraceControl)
94 {
95 TDebug.out("TBooleanControl.<init>: begin");
96 }
97 m_controller = new TControlController();
98 if (TDebug.TraceControl)
99 {
100 TDebug.out("TBooleanControl.<init>: end");
101 }
102 }
103
104
105
106 public void setParentControl(TCompoundControl compoundControl)
107 {
108 m_controller.setParentControl(compoundControl);
109 }
110
111
112
113 public TCompoundControl getParentControl()
114 {
115 return m_controller.getParentControl();
116 }
117
118
119
120 public void commit()
121 {
122 m_controller.commit();
123 }
124}
125
126
127
128/*** TBooleanControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TClip.java b/songdbj/org/tritonus/share/sampled/mixer/TClip.java
new file mode 100644
index 0000000000..e0a8140c37
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TClip.java
@@ -0,0 +1,340 @@
1/*
2 * TClip.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.mixer;
31
32import java.io.IOException;
33import java.io.ByteArrayInputStream;
34import java.util.Collection;
35
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioSystem;
38import javax.sound.sampled.Clip;
39import javax.sound.sampled.Control;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.SourceDataLine;
42import javax.sound.sampled.AudioInputStream;
43import javax.sound.sampled.LineUnavailableException;
44import javax.sound.sampled.Mixer;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.mixer.TDataLine;
48
49
50
51public class TClip
52extends TDataLine
53implements Clip
54{
55 private static final Class[] CONTROL_CLASSES = {/*GainControl.class*/};
56 private static final int BUFFER_FRAMES = 16384;
57
58
59 public TClip(DataLine.Info info)
60 {
61 super(null, // TMixer
62 info);
63 }
64
65
66
67 public TClip(DataLine.Info info,
68 Collection<Control> controls)
69 {
70 super(null, // TMixer
71 info,
72 controls);
73 }
74
75
76
77 public void open(AudioFormat audioFormat,
78 byte[] abData,
79 int nOffset,
80 int nLength)
81 throws LineUnavailableException
82 {
83 // int nBufferLength = nNumFrames * audioFormat.getFrameSize();
84 // TODO: check if nOffset + nBufferLength <= abData.length
85 // perhaps truncate automatically
86 ByteArrayInputStream bais = new ByteArrayInputStream(abData, nOffset, nLength);
87 AudioInputStream audioInputStream = new AudioInputStream(bais, audioFormat, AudioSystem.NOT_SPECIFIED);
88 try
89 {
90 open(audioInputStream);
91 }
92 catch (IOException e)
93 {
94 if (TDebug.TraceAllExceptions)
95 {
96 TDebug.out(e);
97 }
98 throw new LineUnavailableException("IOException occured");
99 }
100 }
101
102
103
104 public void open(AudioInputStream audioInputStream)
105 throws LineUnavailableException, IOException
106 {
107 AudioFormat audioFormat = audioInputStream.getFormat();
108 // TOOD:
109 DataLine.Info info = new DataLine.Info(Clip.class,
110 audioFormat, -1/*nBufferSize*/);
111/*
112 setLineInfo(info);
113 int nFrameSize = audioFormat.getFrameSize();
114 long lTotalLength = audioInputStream.getFrameLength() * nFrameSize;
115 int nFormat = Esd.ESD_STREAM | Esd.ESD_PLAY | EsdUtils.getEsdFormat(audioFormat);
116 if (TDebug.TraceClip)
117 {
118 TDebug.out("format: " + nFormat);
119 TDebug.out("sample rate: " + audioFormat.getSampleRate());
120 }
121 // m_esdSample.open(nFormat, (int) audioFormat.getSampleRate(), (int) lTotalLength);
122 if (TDebug.TraceClip)
123 {
124 TDebug.out("size in esd: " + audioInputStream.getFrameLength() * nFrameSize);
125 }
126 int nBufferLength = BUFFER_FRAMES * nFrameSize;
127 byte[] abData = new byte[nBufferLength];
128 int nBytesRead = 0;
129 int nTotalBytes = 0;
130 while (nBytesRead != -1)
131 {
132 try
133 {
134 nBytesRead = audioInputStream.read(abData, 0, abData.length);
135 }
136 catch (IOException e)
137 {
138 if (TDebug.TraceClip || TDebug.TraceAllExceptions)
139 {
140 TDebug.out(e);
141 }
142 }
143 if (nBytesRead >= 0)
144 {
145 nTotalBytes += nBytesRead;
146 if (TDebug.TraceClip)
147 {
148 TDebug.out("TClip.open(): total bytes: " + nTotalBytes);
149 TDebug.out("TClip.open(): Trying to write: " + nBytesRead);
150 }
151 int nBytesWritten = 0; //m_esdSample.write(abData, 0, nBytesRead);
152 if (TDebug.TraceClip)
153 {
154 TDebug.out("TClip.open(): Written: " + nBytesWritten);
155 }
156 }
157 }
158 // to trigger the events
159 // open();
160 */
161 }
162
163
164
165 public int getFrameLength()
166 {
167 // TODO:
168 return -1;
169 }
170
171
172
173 public long getMicrosecondLength()
174 {
175 // TODO:
176 return -1;
177 }
178
179
180
181 public void setFramePosition(int nPosition)
182 {
183 // TOOD:
184 }
185
186
187
188 public void setMicrosecondPosition(long lPosition)
189 {
190 // TOOD:
191 }
192
193
194
195 public int getFramePosition()
196 {
197 // TOOD:
198 return -1;
199 }
200
201
202
203 public long getMicrosecondPosition()
204 {
205 // TOOD:
206 return -1;
207 }
208
209
210
211 public void setLoopPoints(int nStart, int nEnd)
212 {
213 // TOOD:
214 }
215
216
217
218 public void loop(int nCount)
219 {
220 if (TDebug.TraceClip)
221 {
222 TDebug.out("TClip.loop(int): called; count = " + nCount);
223 }
224 if (false/*isStarted()*/)
225 {
226 /*
227 * only allow zero count to stop the looping
228 * at the end of an iteration.
229 */
230 if (nCount == 0)
231 {
232 if (TDebug.TraceClip)
233 {
234 TDebug.out("TClip.loop(int): stopping sample");
235 }
236 // m_esdSample.stop();
237 }
238 }
239 else
240 {
241 if (nCount == 0)
242 {
243 if (TDebug.TraceClip)
244 {
245 TDebug.out("TClip.loop(int): starting sample (once)");
246 }
247 // m_esdSample.play();
248 }
249 else
250 {
251 /*
252 * we're ignoring the count, because esd
253 * cannot loop for a fixed number of
254 * times.
255 */
256 // TDebug.out("hallo");
257 if (TDebug.TraceClip)
258 {
259 TDebug.out("TClip.loop(int): starting sample (forever)");
260 }
261 // m_esdSample.loop();
262 }
263 }
264 // TOOD:
265 }
266
267
268
269 public void flush()
270 {
271 // TOOD:
272 }
273
274
275
276 public void drain()
277 {
278 // TOOD:
279 }
280
281
282
283 public void close()
284 {
285 // m_esdSample.free();
286 // m_esdSample.close();
287 // TOOD:
288 }
289
290
291
292
293 public void open()
294 {
295 // TODO:
296 }
297
298
299
300 public void start()
301 {
302 if (TDebug.TraceClip)
303 {
304 TDebug.out("TClip.start(): called");
305 }
306 /*
307 * This is a hack. What start() really should do is
308 * start playing at the position playback was stopped.
309 */
310 if (TDebug.TraceClip)
311 {
312 TDebug.out("TClip.start(): calling 'loop(0)' [hack]");
313 }
314 loop(0);
315 }
316
317
318
319 public void stop()
320 {
321 // TODO:
322 // m_esdSample.kill();
323 }
324
325
326
327 /*
328 * This method is enforced by DataLine, but doesn't make any
329 * sense for Clips.
330 */
331 public int available()
332 {
333 return -1;
334 }
335}
336
337
338
339/*** TClip.java ***/
340
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java b/songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java
new file mode 100644
index 0000000000..4a370eb86c
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java
@@ -0,0 +1,90 @@
1/*
2 * TCompoundControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.CompoundControl;
34import javax.sound.sampled.Control;
35
36import org.tritonus.share.TDebug;
37
38
39
40
41/** Base class for classes implementing Line.
42 */
43public class TCompoundControl
44extends CompoundControl
45implements TControllable
46{
47 private TControlController m_controller;
48
49
50
51 public TCompoundControl(CompoundControl.Type type,
52 Control[] aMemberControls)
53 {
54 super(type, aMemberControls);
55 if (TDebug.TraceControl)
56 {
57 TDebug.out("TCompoundControl.<init>: begin");
58 }
59 m_controller = new TControlController();
60 if (TDebug.TraceControl)
61 {
62 TDebug.out("TCompoundControl.<init>: end");
63 }
64 }
65
66
67
68 public void setParentControl(TCompoundControl compoundControl)
69 {
70 m_controller.setParentControl(compoundControl);
71 }
72
73
74
75 public TCompoundControl getParentControl()
76 {
77 return m_controller.getParentControl();
78 }
79
80
81
82 public void commit()
83 {
84 m_controller.commit();
85 }
86}
87
88
89
90/*** TCompoundControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java b/songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java
new file mode 100644
index 0000000000..1b90b1a673
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java
@@ -0,0 +1,55 @@
1/*
2 * TCompoundControlType.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.mixer;
30
31import javax.sound.sampled.CompoundControl;
32
33
34
35/** CompoundControl.Type class.
36 This class is only needed to provide a public constructor.
37 */
38public class TCompoundControlType
39extends CompoundControl.Type
40{
41 /** Constructor.
42 Constructs a CompoundControl.Type with the
43 name given.
44
45 @param strName The name of the control.
46 */
47 public TCompoundControlType(String strName)
48 {
49 super(strName);
50 }
51}
52
53
54
55/*** TCompoundControlType.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TControlController.java b/songdbj/org/tritonus/share/sampled/mixer/TControlController.java
new file mode 100644
index 0000000000..ec17c45b59
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TControlController.java
@@ -0,0 +1,98 @@
1/*
2 * TControlController.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46import javax.sound.sampled.Port;
47
48import org.tritonus.share.TDebug;
49
50
51
52
53/** Base class for classes implementing Line.
54 */
55public class TControlController
56implements TControllable
57{
58 /** The parent (compound) control.
59 In case this control is part of a compound control, the parentControl
60 property is set to a value other than null.
61 */
62 private TCompoundControl m_parentControl;
63
64
65 public TControlController()
66 {
67 }
68
69
70
71 public void setParentControl(TCompoundControl compoundControl)
72 {
73 m_parentControl = compoundControl;
74 }
75
76
77 public TCompoundControl getParentControl()
78 {
79 return m_parentControl;
80 }
81
82
83 public void commit()
84 {
85 if (TDebug.TraceControl)
86 {
87 TDebug.out("TControlController.commit(): called [" + this.getClass().getName() + "]");
88 }
89 if (getParentControl() != null)
90 {
91 getParentControl().commit();
92 }
93 }
94}
95
96
97
98/*** TControlController.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TControllable.java b/songdbj/org/tritonus/share/sampled/mixer/TControllable.java
new file mode 100644
index 0000000000..b89d34a2b3
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TControllable.java
@@ -0,0 +1,62 @@
1/*
2 * TControllable.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46import javax.sound.sampled.Port;
47
48import org.tritonus.share.TDebug;
49
50
51
52
53public interface TControllable
54{
55 public void setParentControl(TCompoundControl compoundControl);
56 public TCompoundControl getParentControl();
57 public void commit();
58}
59
60
61
62/*** TControllable.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TDataLine.java b/songdbj/org/tritonus/share/sampled/mixer/TDataLine.java
new file mode 100644
index 0000000000..a493bac6c5
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TDataLine.java
@@ -0,0 +1,304 @@
1/*
2 * TDataLine.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.EventListener;
35import java.util.EventObject;
36import java.util.HashSet;
37import java.util.Set;
38
39import javax.sound.sampled.AudioFormat;
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.DataLine;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.Line;
45
46import org.tritonus.share.TDebug;
47
48
49
50/** Base class for classes implementing DataLine.
51 */
52public abstract class TDataLine
53extends TLine
54implements DataLine
55{
56 private static final int DEFAULT_BUFFER_SIZE = 128000;
57
58 private AudioFormat m_format;
59 private int m_nBufferSize;
60 private boolean m_bRunning;
61 // private boolean m_bActive;
62
63
64
65
66 public TDataLine(TMixer mixer,
67 DataLine.Info info)
68 {
69 super(mixer,
70 info);
71 init(info);
72 }
73
74
75
76 public TDataLine(TMixer mixer,
77 DataLine.Info info,
78 Collection<Control> controls)
79 {
80 super(mixer,
81 info,
82 controls);
83 init(info);
84 }
85
86
87
88 // IDEA: extract format and bufsize from info?
89 private void init(DataLine.Info info)
90 {
91 m_format = null;
92 m_nBufferSize = AudioSystem.NOT_SPECIFIED;
93 setRunning(false);
94 // setActive(false);
95 }
96
97
98
99 // not defined here:
100 // public void drain()
101 // public void flush()
102
103
104
105 public void start()
106 {
107 if (TDebug.TraceSourceDataLine)
108 {
109 TDebug.out("TDataLine.start(): called");
110 }
111 setRunning(true);
112 }
113
114
115
116 public void stop()
117 {
118 if (TDebug.TraceSourceDataLine)
119 {
120 TDebug.out("TDataLine.stop(): called");
121 }
122 setRunning(false);
123 }
124
125
126
127 public boolean isRunning()
128 {
129 return m_bRunning;
130 }
131
132
133
134 // TODO: recheck
135 protected void setRunning(boolean bRunning)
136 {
137 boolean bOldValue = isRunning();
138 m_bRunning = bRunning;
139 if (bOldValue != isRunning())
140 {
141 if (isRunning())
142 {
143 startImpl();
144 notifyLineEvent(LineEvent.Type.START);
145 }
146 else
147 {
148 stopImpl();
149 notifyLineEvent(LineEvent.Type.STOP);
150 }
151 }
152 }
153
154
155
156 protected void startImpl()
157 {
158 }
159
160
161
162 protected void stopImpl()
163 {
164 }
165
166
167
168 /**
169 * This implementation returns the status of isRunning().
170 * Subclasses should overwrite this method if there is more
171 * precise information about the status of the line available.
172 */
173 public boolean isActive()
174 {
175 return isRunning();
176 }
177
178
179/*
180 public boolean isStarted()
181 {
182 return m_bStarted;
183 }
184*/
185
186 // TODO: should only ALLOW engaging in data I/O.
187 // actual START event should only be sent when line really becomes active
188/*
189 protected void setStarted(boolean bStarted)
190 {
191 m_bStarted = bStarted;
192 if (!isRunning())
193 {
194 setActive(false);
195 }
196 }
197*/
198
199
200 public AudioFormat getFormat()
201 {
202 return m_format;
203 }
204
205
206
207 protected void setFormat(AudioFormat format)
208 {
209 if (TDebug.TraceDataLine)
210 {
211 TDebug.out("TDataLine.setFormat(): setting: " + format);
212 }
213 m_format = format;
214 }
215
216
217
218 public int getBufferSize()
219 {
220 return m_nBufferSize;
221 }
222
223
224
225 protected void setBufferSize(int nBufferSize)
226 {
227 if (TDebug.TraceDataLine)
228 {
229 TDebug.out("TDataLine.setBufferSize(): setting: " + nBufferSize);
230 }
231 m_nBufferSize = nBufferSize;
232 }
233
234
235
236 // not defined here:
237 // public int available()
238
239
240
241 public int getFramePosition()
242 {
243 // TODO:
244 return -1;
245 }
246
247
248
249 public long getLongFramePosition()
250 {
251 // TODO:
252 return -1;
253 }
254
255
256
257 public long getMicrosecondPosition()
258 {
259 return (long) (getFramePosition() * getFormat().getFrameRate() * 1000000);
260 }
261
262
263
264 /*
265 * Has to be overridden to be useful.
266 */
267 public float getLevel()
268 {
269 return AudioSystem.NOT_SPECIFIED;
270 }
271
272
273
274 protected void checkOpen()
275 {
276 if (getFormat() == null)
277 {
278 throw new IllegalStateException("format must be specified");
279 }
280 if (getBufferSize() == AudioSystem.NOT_SPECIFIED)
281 {
282 setBufferSize(getDefaultBufferSize());
283 }
284 }
285
286
287
288 protected int getDefaultBufferSize()
289 {
290 return DEFAULT_BUFFER_SIZE;
291 }
292
293
294
295 protected void notifyLineEvent(LineEvent.Type type)
296 {
297 notifyLineEvent(new LineEvent(this, type, getFramePosition()));
298 }
299}
300
301
302
303/*** TDataLine.java ***/
304
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java b/songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java
new file mode 100644
index 0000000000..2c9132401f
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java
@@ -0,0 +1,92 @@
1/*
2 * TEnumControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.EnumControl;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/** Base class for classes implementing Line.
41 */
42public class TEnumControl
43extends EnumControl
44implements TControllable
45{
46 private TControlController m_controller;
47
48
49
50 public TEnumControl(EnumControl.Type type,
51 Object[] aValues,
52 Object value)
53 {
54 super(type,
55 aValues,
56 value);
57 if (TDebug.TraceControl)
58 {
59 TDebug.out("TEnumControl.<init>: begin");
60 }
61 m_controller = new TControlController();
62 if (TDebug.TraceControl)
63 {
64 TDebug.out("TEnumControl.<init>: end");
65 }
66 }
67
68
69
70 public void setParentControl(TCompoundControl compoundControl)
71 {
72 m_controller.setParentControl(compoundControl);
73 }
74
75
76
77 public TCompoundControl getParentControl()
78 {
79 return m_controller.getParentControl();
80 }
81
82
83
84 public void commit()
85 {
86 m_controller.commit();
87 }
88}
89
90
91
92/*** TEnumControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java b/songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java
new file mode 100644
index 0000000000..8a80016865
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java
@@ -0,0 +1,134 @@
1/*
2 * TFloatControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.FloatControl;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/** Base class for classes implementing Line.
41 */
42public class TFloatControl
43extends FloatControl
44implements TControllable
45{
46 private TControlController m_controller;
47
48
49
50 public TFloatControl(FloatControl.Type type,
51 float fMinimum,
52 float fMaximum,
53 float fPrecision,
54 int nUpdatePeriod,
55 float fInitialValue,
56 String strUnits)
57 {
58 super(type,
59 fMinimum,
60 fMaximum,
61 fPrecision,
62 nUpdatePeriod,
63 fInitialValue,
64 strUnits);
65 if (TDebug.TraceControl)
66 {
67 TDebug.out("TFloatControl.<init>: begin");
68 }
69 m_controller = new TControlController();
70 if (TDebug.TraceControl)
71 {
72 TDebug.out("TFloatControl.<init>: end");
73 }
74 }
75
76
77
78 public TFloatControl(FloatControl.Type type,
79 float fMinimum,
80 float fMaximum,
81 float fPrecision,
82 int nUpdatePeriod,
83 float fInitialValue,
84 String strUnits,
85 String strMinLabel,
86 String strMidLabel,
87 String strMaxLabel)
88 {
89 super(type,
90 fMinimum,
91 fMaximum,
92 fPrecision,
93 nUpdatePeriod,
94 fInitialValue,
95 strUnits,
96 strMinLabel,
97 strMidLabel,
98 strMaxLabel);
99 if (TDebug.TraceControl)
100 {
101 TDebug.out("TFloatControl.<init>: begin");
102 }
103 m_controller = new TControlController();
104 if (TDebug.TraceControl)
105 {
106 TDebug.out("TFloatControl.<init>: end");
107 }
108 }
109
110
111
112 public void setParentControl(TCompoundControl compoundControl)
113 {
114 m_controller.setParentControl(compoundControl);
115 }
116
117
118
119 public TCompoundControl getParentControl()
120 {
121 return m_controller.getParentControl();
122 }
123
124
125
126 public void commit()
127 {
128 m_controller.commit();
129 }
130}
131
132
133
134/*** TFloatControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TLine.java b/songdbj/org/tritonus/share/sampled/mixer/TLine.java
new file mode 100644
index 0000000000..89b38099ed
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TLine.java
@@ -0,0 +1,362 @@
1/*
2 * TLine.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46
47import org.tritonus.share.TDebug;
48import org.tritonus.share.TNotifier;
49
50
51
52
53/** Base class for classes implementing Line.
54 */
55public abstract class TLine
56implements Line
57{
58 private static final Control[] EMPTY_CONTROL_ARRAY = new Control[0];
59
60 private Line.Info m_info;
61 private boolean m_bOpen;
62 private List<Control> m_controls;
63 private Set<LineListener> m_lineListeners;
64 private TMixer m_mixer;
65
66
67
68 protected TLine(TMixer mixer,
69 Line.Info info)
70 {
71 setLineInfo(info);
72 setOpen(false);
73 m_controls = new ArrayList<Control>();
74 m_lineListeners = new HashSet<LineListener>();
75 m_mixer = mixer;
76 }
77
78
79
80 protected TLine(TMixer mixer,
81 Line.Info info,
82 Collection<Control> controls)
83 {
84 this (mixer, info);
85 m_controls.addAll(controls);
86 }
87
88
89 protected TMixer getMixer()
90 {
91 return m_mixer;
92 }
93
94
95 public Line.Info getLineInfo()
96 {
97 return m_info;
98 }
99
100
101
102 protected void setLineInfo(Line.Info info)
103 {
104 if (TDebug.TraceLine)
105 {
106 TDebug.out("TLine.setLineInfo(): setting: " + info);
107 }
108 synchronized (this)
109 {
110 m_info = info;
111 }
112 }
113
114
115
116 public void open()
117 throws LineUnavailableException
118 {
119 if (TDebug.TraceLine)
120 {
121 TDebug.out("TLine.open(): called");
122 }
123 if (! isOpen())
124 {
125 if (TDebug.TraceLine)
126 {
127 TDebug.out("TLine.open(): opening");
128 }
129 openImpl();
130 if (getMixer() != null)
131 {
132 getMixer().registerOpenLine(this);
133 }
134 setOpen(true);
135 }
136 else
137 {
138 if (TDebug.TraceLine)
139 {
140 TDebug.out("TLine.open(): already open");
141 }
142 }
143 }
144
145
146
147 /**
148 * Subclasses should override this method.
149 */
150 protected void openImpl()
151 throws LineUnavailableException
152 {
153 if (TDebug.TraceLine)
154 {
155 TDebug.out("TLine.openImpl(): called");
156 }
157 }
158
159
160
161 public void close()
162 {
163 if (TDebug.TraceLine)
164 {
165 TDebug.out("TLine.close(): called");
166 }
167 if (isOpen())
168 {
169 if (TDebug.TraceLine)
170 {
171 TDebug.out("TLine.close(): closing");
172 }
173 if (getMixer() != null)
174 {
175 getMixer().unregisterOpenLine(this);
176 }
177 closeImpl();
178 setOpen(false);
179 }
180 else
181 {
182 if (TDebug.TraceLine)
183 {
184 TDebug.out("TLine.close(): not open");
185 }
186 }
187 }
188
189
190
191 /**
192 * Subclasses should override this method.
193 */
194 protected void closeImpl()
195 {
196 if (TDebug.TraceLine)
197 {
198 TDebug.out("TLine.closeImpl(): called");
199 }
200 }
201
202
203
204
205
206 public boolean isOpen()
207 {
208 return m_bOpen;
209 }
210
211
212
213
214 protected void setOpen(boolean bOpen)
215 {
216 if (TDebug.TraceLine)
217 {
218 TDebug.out("TLine.setOpen(): called, value: " + bOpen);
219 }
220 boolean bOldValue = isOpen();
221 m_bOpen = bOpen;
222 if (bOldValue != isOpen())
223 {
224 if (isOpen())
225 {
226 if (TDebug.TraceLine)
227 {
228 TDebug.out("TLine.setOpen(): opened");
229 }
230 notifyLineEvent(LineEvent.Type.OPEN);
231 }
232 else
233 {
234 if (TDebug.TraceLine)
235 {
236 TDebug.out("TLine.setOpen(): closed");
237 }
238 notifyLineEvent(LineEvent.Type.CLOSE);
239 }
240 }
241 }
242
243
244
245 protected void addControl(Control control)
246 {
247 synchronized (m_controls)
248 {
249 m_controls.add(control);
250 }
251 }
252
253
254
255 protected void removeControl(Control control)
256 {
257 synchronized (m_controls)
258 {
259 m_controls.remove(control);
260 }
261 }
262
263
264
265 public Control[] getControls()
266 {
267 synchronized (m_controls)
268 {
269 return m_controls.toArray(EMPTY_CONTROL_ARRAY);
270 }
271 }
272
273
274
275 public Control getControl(Control.Type controlType)
276 {
277 synchronized (m_controls)
278 {
279 Iterator<Control> it = m_controls.iterator();
280 while (it.hasNext())
281 {
282 Control control = it.next();
283 if (control.getType().equals(controlType))
284 {
285 return control;
286 }
287 }
288 throw new IllegalArgumentException("no control of type " + controlType);
289 }
290 }
291
292
293
294 public boolean isControlSupported(Control.Type controlType)
295 {
296 // TDebug.out("TLine.isSupportedControl(): called");
297 try
298 {
299 return getControl(controlType) != null;
300 }
301 catch (IllegalArgumentException e)
302 {
303 if (TDebug.TraceAllExceptions)
304 {
305 TDebug.out(e);
306 }
307 // TDebug.out("TLine.isSupportedControl(): returning false");
308 return false;
309 }
310 }
311
312
313
314 public void addLineListener(LineListener listener)
315 {
316 // TDebug.out("%% TChannel.addListener(): called");
317 synchronized (m_lineListeners)
318 {
319 m_lineListeners.add(listener);
320 }
321 }
322
323
324
325 public void removeLineListener(LineListener listener)
326 {
327 synchronized (m_lineListeners)
328 {
329 m_lineListeners.remove(listener);
330 }
331 }
332
333
334
335 private Set<LineListener> getLineListeners()
336 {
337 synchronized (m_lineListeners)
338 {
339 return new HashSet<LineListener>(m_lineListeners);
340 }
341 }
342
343
344 // is overridden in TDataLine to provide a position
345 protected void notifyLineEvent(LineEvent.Type type)
346 {
347 notifyLineEvent(new LineEvent(this, type, AudioSystem.NOT_SPECIFIED));
348 }
349
350
351
352 protected void notifyLineEvent(LineEvent event)
353 {
354 // TDebug.out("%% TChannel.notifyChannelEvent(): called");
355 // Channel.Event event = new Channel.Event(this, type, getPosition());
356 TNotifier.notifier.addEntry(event, getLineListeners());
357 }
358}
359
360
361
362/*** TLine.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TMixer.java b/songdbj/org/tritonus/share/sampled/mixer/TMixer.java
new file mode 100644
index 0000000000..6a5dc4db72
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TMixer.java
@@ -0,0 +1,506 @@
1/*
2 * TMixer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Iterator;
36import java.util.Set;
37
38import javax.sound.sampled.AudioFormat;
39import javax.sound.sampled.Clip;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.Line;
42import javax.sound.sampled.LineUnavailableException;
43import javax.sound.sampled.Mixer;
44import javax.sound.sampled.Port;
45import javax.sound.sampled.SourceDataLine;
46import javax.sound.sampled.TargetDataLine;
47
48import org.tritonus.share.TDebug;
49import org.tritonus.share.sampled.AudioFormats;
50import org.tritonus.share.ArraySet;
51
52
53
54// TODO: global controls (that use the system mixer)
55public abstract class TMixer
56extends TLine
57implements Mixer
58{
59 private static Line.Info[] EMPTY_LINE_INFO_ARRAY = new Line.Info[0];
60 private static Line[] EMPTY_LINE_ARRAY = new Line[0];
61
62 private Mixer.Info m_mixerInfo;
63 private Collection<AudioFormat> m_supportedSourceFormats;
64 private Collection<AudioFormat> m_supportedTargetFormats;
65 private Collection<Line.Info> m_supportedSourceLineInfos;
66 private Collection<Line.Info> m_supportedTargetLineInfos;
67 private Set<SourceDataLine> m_openSourceDataLines;
68 private Set<TargetDataLine> m_openTargetDataLines;
69
70
71 /** Constructor for mixers that use setSupportInformation().
72 */
73 protected TMixer(Mixer.Info mixerInfo,
74 Line.Info lineInfo)
75 {
76 this(mixerInfo,
77 lineInfo,
78 new ArrayList<AudioFormat>(),
79 new ArrayList<AudioFormat>(),
80 new ArrayList<Line.Info>(),
81 new ArrayList<Line.Info>());
82 }
83
84
85
86 /** Constructor for mixers.
87 */
88 protected TMixer(Mixer.Info mixerInfo,
89 Line.Info lineInfo,
90 Collection<AudioFormat> supportedSourceFormats,
91 Collection<AudioFormat> supportedTargetFormats,
92 Collection<Line.Info> supportedSourceLineInfos,
93 Collection<Line.Info> supportedTargetLineInfos)
94 {
95 super(null, // TMixer
96 lineInfo);
97 if (TDebug.TraceMixer) { TDebug.out("TMixer.<init>(): begin"); }
98 m_mixerInfo = mixerInfo;
99 setSupportInformation(
100 supportedSourceFormats,
101 supportedTargetFormats,
102 supportedSourceLineInfos,
103 supportedTargetLineInfos);
104 m_openSourceDataLines = new ArraySet<SourceDataLine>();
105 m_openTargetDataLines = new ArraySet<TargetDataLine>();
106 if (TDebug.TraceMixer) { TDebug.out("TMixer.<init>(): end"); }
107 }
108
109
110
111 protected void setSupportInformation(
112 Collection<AudioFormat> supportedSourceFormats,
113 Collection<AudioFormat> supportedTargetFormats,
114 Collection<Line.Info> supportedSourceLineInfos,
115 Collection<Line.Info> supportedTargetLineInfos)
116 {
117 if (TDebug.TraceMixer) { TDebug.out("TMixer.setSupportInformation(): begin"); }
118 m_supportedSourceFormats = supportedSourceFormats;
119 m_supportedTargetFormats = supportedTargetFormats;
120 m_supportedSourceLineInfos = supportedSourceLineInfos;
121 m_supportedTargetLineInfos = supportedTargetLineInfos;
122 if (TDebug.TraceMixer) { TDebug.out("TMixer.setSupportInformation(): end"); }
123 }
124
125
126
127 public Mixer.Info getMixerInfo()
128 {
129 if (TDebug.TraceMixer) { TDebug.out("TMixer.getMixerInfo(): begin"); }
130 if (TDebug.TraceMixer) { TDebug.out("TMixer.getMixerInfo(): end"); }
131 return m_mixerInfo;
132 }
133
134
135
136 public Line.Info[] getSourceLineInfo()
137 {
138 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLineInfo(): begin"); }
139 Line.Info[] infos = (Line.Info[]) m_supportedSourceLineInfos.toArray(EMPTY_LINE_INFO_ARRAY);
140 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLineInfo(): end"); }
141 return infos;
142 }
143
144
145
146 public Line.Info[] getTargetLineInfo()
147 {
148 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLineInfo(): begin"); }
149 Line.Info[] infos = (Line.Info[]) m_supportedTargetLineInfos.toArray(EMPTY_LINE_INFO_ARRAY);
150 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLineInfo(): end"); }
151 return infos;
152 }
153
154
155
156 public Line.Info[] getSourceLineInfo(Line.Info info)
157 {
158 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLineInfo(Line.Info): info to test: " + info); }
159 // TODO:
160 return EMPTY_LINE_INFO_ARRAY;
161 }
162
163
164
165 public Line.Info[] getTargetLineInfo(Line.Info info)
166 {
167 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLineInfo(Line.Info): info to test: " + info); }
168 // TODO:
169 return EMPTY_LINE_INFO_ARRAY;
170 }
171
172
173
174 public boolean isLineSupported(Line.Info info)
175 {
176 if (TDebug.TraceMixer) { TDebug.out("TMixer.isLineSupported(): info to test: " + info); }
177 Class lineClass = info.getLineClass();
178 if (lineClass.equals(SourceDataLine.class))
179 {
180 return isLineSupportedImpl(info, m_supportedSourceLineInfos);
181 }
182 else if (lineClass.equals(TargetDataLine.class))
183 {
184 return isLineSupportedImpl(info, m_supportedTargetLineInfos);
185 }
186 else if (lineClass.equals(Port.class))
187 {
188 return isLineSupportedImpl(info, m_supportedSourceLineInfos) || isLineSupportedImpl(info, m_supportedTargetLineInfos);
189 }
190 else
191 {
192 return false;
193 }
194 }
195
196
197
198 private static boolean isLineSupportedImpl(Line.Info info, Collection supportedLineInfos)
199 {
200 Iterator iterator = supportedLineInfos.iterator();
201 while (iterator.hasNext())
202 {
203 Line.Info info2 = (Line.Info) iterator.next();
204 if (info2.matches(info))
205 {
206 return true;
207 }
208 }
209 return false;
210 }
211
212
213
214 public Line getLine(Line.Info info)
215 throws LineUnavailableException
216 {
217 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): begin"); }
218 Class lineClass = info.getLineClass();
219 DataLine.Info dataLineInfo = null;
220 Port.Info portInfo = null;
221 AudioFormat[] aFormats = null;
222 if (info instanceof DataLine.Info)
223 {
224 dataLineInfo = (DataLine.Info) info;
225 aFormats = dataLineInfo.getFormats();
226 }
227 else if (info instanceof Port.Info)
228 {
229 portInfo = (Port.Info) info;
230 }
231 AudioFormat format = null;
232 Line line = null;
233 if (lineClass == SourceDataLine.class)
234 {
235 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: SourceDataLine"); }
236 if (dataLineInfo == null)
237 {
238 throw new IllegalArgumentException("need DataLine.Info for SourceDataLine");
239 }
240 format = getSupportedSourceFormat(aFormats);
241 line = getSourceDataLine(format, dataLineInfo.getMaxBufferSize());
242 }
243 else if (lineClass == Clip.class)
244 {
245 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: Clip"); }
246 if (dataLineInfo == null)
247 {
248 throw new IllegalArgumentException("need DataLine.Info for Clip");
249 }
250 format = getSupportedSourceFormat(aFormats);
251 line = getClip(format);
252 }
253 else if (lineClass == TargetDataLine.class)
254 {
255 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: TargetDataLine"); }
256 if (dataLineInfo == null)
257 {
258 throw new IllegalArgumentException("need DataLine.Info for TargetDataLine");
259 }
260 format = getSupportedTargetFormat(aFormats);
261 line = getTargetDataLine(format, dataLineInfo.getMaxBufferSize());
262 }
263 else if (lineClass == Port.class)
264 {
265 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: TargetDataLine"); }
266 if (portInfo == null)
267 {
268 throw new IllegalArgumentException("need Port.Info for Port");
269 }
270 line = getPort(portInfo);
271 }
272 else
273 {
274 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): unknown line type, will throw exception"); }
275 throw new LineUnavailableException("unknown line class: " + lineClass);
276 }
277 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): end"); }
278 return line;
279 }
280
281
282
283 protected SourceDataLine getSourceDataLine(AudioFormat format, int nBufferSize)
284 throws LineUnavailableException
285 {
286 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceDataLine(): begin"); }
287 throw new IllegalArgumentException("this mixer does not support SourceDataLines");
288 }
289
290
291
292 protected Clip getClip(AudioFormat format)
293 throws LineUnavailableException
294 {
295 if (TDebug.TraceMixer) { TDebug.out("TMixer.getClip(): begin"); }
296 throw new IllegalArgumentException("this mixer does not support Clips");
297 }
298
299
300
301 protected TargetDataLine getTargetDataLine(AudioFormat format, int nBufferSize)
302 throws LineUnavailableException
303 {
304 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetDataLine(): begin"); }
305 throw new IllegalArgumentException("this mixer does not support TargetDataLines");
306 }
307
308
309
310 protected Port getPort(Port.Info info)
311 throws LineUnavailableException
312 {
313 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetDataLine(): begin"); }
314 throw new IllegalArgumentException("this mixer does not support Ports");
315 }
316
317
318
319 private AudioFormat getSupportedSourceFormat(AudioFormat[] aFormats)
320 {
321 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): begin"); }
322 AudioFormat format = null;
323 for (int i = 0; i < aFormats.length; i++)
324 {
325 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): checking " + aFormats[i] + "..."); }
326 if (isSourceFormatSupported(aFormats[i]))
327 {
328 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): ...supported"); }
329 format = aFormats[i];
330 break;
331 }
332 else
333 {
334 if (TDebug.TraceMixer)
335 {
336 TDebug.out("TMixer.getSupportedSourceFormat(): ...no luck");
337 }
338 }
339 }
340 if (format == null)
341 {
342 throw new IllegalArgumentException("no line matchine one of the passed formats");
343 }
344 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): end"); }
345 return format;
346 }
347
348
349
350 private AudioFormat getSupportedTargetFormat(AudioFormat[] aFormats)
351 {
352 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): begin"); }
353 AudioFormat format = null;
354 for (int i = 0; i < aFormats.length; i++)
355 {
356 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): checking " + aFormats[i] + " ..."); }
357 if (isTargetFormatSupported(aFormats[i]))
358 {
359 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): ...supported"); }
360 format = aFormats[i];
361 break;
362 }
363 else
364 {
365 if (TDebug.TraceMixer)
366 {
367 TDebug.out("TMixer.getSupportedTargetFormat(): ...no luck");
368 }
369 }
370 }
371 if (format == null)
372 {
373 throw new IllegalArgumentException("no line matchine one of the passed formats");
374 }
375 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): end"); }
376 return format;
377 }
378
379
380
381/*
382 not implemented here:
383 getMaxLines(Line.Info)
384*/
385
386
387
388 public Line[] getSourceLines()
389 {
390 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLines(): called"); }
391 return (Line[]) m_openSourceDataLines.toArray(EMPTY_LINE_ARRAY);
392 }
393
394
395
396 public Line[] getTargetLines()
397 {
398 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLines(): called"); }
399 return (Line[]) m_openTargetDataLines.toArray(EMPTY_LINE_ARRAY);
400 }
401
402
403
404 public void synchronize(Line[] aLines,
405 boolean bMaintainSync)
406 {
407 throw new IllegalArgumentException("synchronization not supported");
408 }
409
410
411
412 public void unsynchronize(Line[] aLines)
413 {
414 throw new IllegalArgumentException("synchronization not supported");
415 }
416
417
418
419 public boolean isSynchronizationSupported(Line[] aLines,
420 boolean bMaintainSync)
421 {
422 return false;
423 }
424
425
426
427 protected boolean isSourceFormatSupported(AudioFormat format)
428 {
429 if (TDebug.TraceMixer) { TDebug.out("TMixer.isSourceFormatSupported(): format to test: " + format); }
430 Iterator<AudioFormat> iterator = m_supportedSourceFormats.iterator();
431 while (iterator.hasNext())
432 {
433 AudioFormat supportedFormat = iterator.next();
434 if (AudioFormats.matches(supportedFormat, format))
435 {
436 return true;
437 }
438 }
439 return false;
440 }
441
442
443
444 protected boolean isTargetFormatSupported(AudioFormat format)
445 {
446 if (TDebug.TraceMixer) { TDebug.out("TMixer.isTargetFormatSupported(): format to test: " + format); }
447 Iterator<AudioFormat> iterator = m_supportedTargetFormats.iterator();
448 while (iterator.hasNext())
449 {
450 AudioFormat supportedFormat = iterator.next();
451 if (AudioFormats.matches(supportedFormat, format))
452 {
453 return true;
454 }
455 }
456 return false;
457 }
458
459
460
461 /*package*/ void registerOpenLine(Line line)
462 {
463 if (TDebug.TraceMixer) { TDebug.out("TMixer.registerOpenLine(): line to register: " + line);
464 }
465 if (line instanceof SourceDataLine)
466 {
467 synchronized (m_openSourceDataLines)
468 {
469 m_openSourceDataLines.add((SourceDataLine) line);
470 }
471 }
472 else if (line instanceof TargetDataLine)
473 {
474 synchronized (m_openSourceDataLines)
475 {
476 m_openTargetDataLines.add((TargetDataLine) line);
477 }
478 }
479 }
480
481
482
483 /*package*/ void unregisterOpenLine(Line line)
484 {
485 if (TDebug.TraceMixer) { TDebug.out("TMixer.unregisterOpenLine(): line to unregister: " + line); }
486 if (line instanceof SourceDataLine)
487 {
488 synchronized (m_openSourceDataLines)
489 {
490 m_openSourceDataLines.remove((SourceDataLine) line);
491 }
492 }
493 else if (line instanceof TargetDataLine)
494 {
495 synchronized (m_openTargetDataLines)
496 {
497 m_openTargetDataLines.remove((TargetDataLine) line);
498 }
499 }
500 }
501}
502
503
504
505/*** TMixer.java ***/
506
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java b/songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java
new file mode 100644
index 0000000000..cb4b7cc860
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java
@@ -0,0 +1,56 @@
1/*
2 * TMixerInfo.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.Mixer;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/*
41 * This is needed only because Mixer.Info's constructor
42 * is protected (in the Sun jdk1.3).
43 */
44public class TMixerInfo
45extends Mixer.Info
46{
47 public TMixerInfo(String a, String b, String c, String d)
48 {
49 super(a, b, c, d);
50 }
51}
52
53
54
55/*** TMixerInfo.java ***/
56
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java b/songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java
new file mode 100644
index 0000000000..3116d74dc3
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java
@@ -0,0 +1,240 @@
1/*
2 * TMixerProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.mixer;
30
31import java.util.ArrayList;
32import java.util.HashMap;
33import java.util.HashSet;
34import java.util.Iterator;
35import java.util.List;
36import java.util.Map;
37import java.util.Set;
38
39import javax.sound.sampled.Mixer;
40import javax.sound.sampled.spi.MixerProvider;
41
42import org.tritonus.share.TDebug;
43
44
45
46public abstract class TMixerProvider
47extends MixerProvider
48{
49 private static final Mixer.Info[] EMPTY_MIXER_INFO_ARRAY = new Mixer.Info[0];
50
51 private static Map<Class, MixerProviderStruct> sm_mixerProviderStructs = new HashMap<Class, MixerProviderStruct>();
52
53 private boolean m_bDisabled = false;
54
55
56
57
58 public TMixerProvider()
59 {
60 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.<init>(): begin"); }
61 // currently does nothing
62 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.<init>(): end"); }
63 }
64
65
66
67 /*
68 Override this method if you want a thread-safe static initializaiton.
69 */
70 protected void staticInit()
71 {
72 }
73
74
75
76 private MixerProviderStruct getMixerProviderStruct()
77 {
78 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): begin"); }
79 Class cls = this.getClass();
80 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): called from " + cls); }
81 // Thread.dumpStack();
82 synchronized (TMixerProvider.class)
83 {
84 MixerProviderStruct struct = sm_mixerProviderStructs.get(cls);
85 if (struct == null)
86 {
87 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): creating new MixerProviderStruct for " + cls); }
88 struct = new MixerProviderStruct();
89 sm_mixerProviderStructs.put(cls, struct);
90 }
91 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): end"); }
92 return struct;
93 }
94 }
95
96
97
98 protected void disable()
99 {
100 if (TDebug.TraceMixerProvider) { TDebug.out("disabling " + getClass().getName()); }
101 m_bDisabled = true;
102 }
103
104
105 protected boolean isDisabled()
106 {
107 return m_bDisabled;
108 }
109
110
111
112 protected void addMixer(Mixer mixer)
113 {
114 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.addMixer(): begin"); }
115 MixerProviderStruct struct = getMixerProviderStruct();
116 synchronized (struct)
117 {
118 struct.m_mixers.add(mixer);
119 if (struct.m_defaultMixer == null)
120 {
121 struct.m_defaultMixer = mixer;
122 }
123 }
124 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.addMixer(): end"); }
125 }
126
127
128
129 protected void removeMixer(Mixer mixer)
130 {
131 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.removeMixer(): begin"); }
132 MixerProviderStruct struct = getMixerProviderStruct();
133 synchronized (struct)
134 {
135 struct.m_mixers.remove(mixer);
136 // TODO: should search for another mixer
137 if (struct.m_defaultMixer == mixer)
138 {
139 struct.m_defaultMixer = null;
140 }
141 }
142 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.removeMixer(): end"); }
143 }
144
145
146 // $$mp 2003/01/11: TODO: this implementation may become obsolete once the overridden method in spi.MixerProvider is implemented in a way documented officially.
147 public boolean isMixerSupported(Mixer.Info info)
148 {
149 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.isMixerSupported(): begin"); }
150 boolean bIsSupported = false;
151 Mixer.Info[] infos = getMixerInfo();
152 for (int i = 0; i < infos.length; i++)
153 {
154 if (infos[i].equals(info))
155 {
156 bIsSupported = true;
157 break;
158 }
159 }
160 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.isMixerSupported(): end"); }
161 return bIsSupported;
162 }
163
164
165
166 /**
167 */
168 public Mixer getMixer(Mixer.Info info)
169 {
170 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixer(): begin"); }
171 MixerProviderStruct struct = getMixerProviderStruct();
172 Mixer mixerResult = null;
173 synchronized (struct)
174 {
175 if (info == null)
176 {
177 mixerResult = struct.m_defaultMixer;
178 }
179 else
180 {
181 Iterator mixers = struct.m_mixers.iterator();
182 while (mixers.hasNext())
183 {
184 Mixer mixer = (Mixer) mixers.next();
185 if (mixer.getMixerInfo().equals(info))
186 {
187 mixerResult = mixer;
188 break;
189 }
190 }
191 }
192 }
193 if (mixerResult == null)
194 {
195 throw new IllegalArgumentException("no mixer available for " + info);
196 }
197 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixer(): end"); }
198 return mixerResult;
199 }
200
201
202
203 public Mixer.Info[] getMixerInfo()
204 {
205 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerInfo(): begin"); }
206 Set<Mixer.Info> mixerInfos = new HashSet<Mixer.Info>();
207 MixerProviderStruct struct = getMixerProviderStruct();
208 synchronized (struct)
209 {
210 Iterator<Mixer> mixers = struct.m_mixers.iterator();
211 while (mixers.hasNext())
212 {
213 Mixer mixer = mixers.next();
214 mixerInfos.add(mixer.getMixerInfo());
215 }
216 }
217 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerInfo(): end"); }
218 return mixerInfos.toArray(EMPTY_MIXER_INFO_ARRAY);
219 }
220
221
222
223 private class MixerProviderStruct
224 {
225 public List<Mixer> m_mixers;
226 public Mixer m_defaultMixer;
227
228
229
230 public MixerProviderStruct()
231 {
232 m_mixers = new ArrayList<Mixer>();
233 m_defaultMixer = null;
234 }
235 }
236}
237
238
239
240/*** TMixerProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TPort.java b/songdbj/org/tritonus/share/sampled/mixer/TPort.java
new file mode 100644
index 0000000000..18d5abae00
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TPort.java
@@ -0,0 +1,77 @@
1/*
2 * TPort.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46import javax.sound.sampled.Port;
47
48import org.tritonus.share.TDebug;
49
50
51
52
53/** Base class for Ports.
54 */
55public class TPort
56extends TLine
57implements Port
58{
59 public TPort(TMixer mixer,
60 Line.Info info)
61 {
62 super(mixer, info);
63 }
64
65
66
67 public TPort(TMixer mixer,
68 Line.Info info,
69 Collection<Control> controls)
70 {
71 super(mixer, info, controls);
72 }
73}
74
75
76
77/*** TPort.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java b/songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java
new file mode 100644
index 0000000000..b5a8aea2c1
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java
@@ -0,0 +1,318 @@
1/*
2 * TSoftClip.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.io.IOException;
34import java.io.ByteArrayInputStream;
35import java.io.ByteArrayOutputStream;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioSystem;
39import javax.sound.sampled.Clip;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.SourceDataLine;
42import javax.sound.sampled.AudioInputStream;
43import javax.sound.sampled.LineUnavailableException;
44import javax.sound.sampled.Mixer;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.mixer.TDataLine;
48
49
50
51public class TSoftClip
52extends TClip
53implements Runnable
54{
55 private static final Class[] CONTROL_CLASSES = {/*GainControl.class*/};
56 private static final int BUFFER_SIZE = 16384;
57
58
59 private Mixer m_mixer;
60 private SourceDataLine m_line;
61 private byte[] m_abClip;
62 private int m_nRepeatCount;
63 private Thread m_thread;
64
65 public TSoftClip(Mixer mixer, AudioFormat format)
66 throws LineUnavailableException
67 {
68 // TODO: info object
69/*
70 DataLine.Info info = new DataLine.Info(Clip.class,
71 audioFormat, -1);
72*/
73 super(null);
74 m_mixer = mixer;
75 DataLine.Info info = new DataLine.Info(
76 SourceDataLine.class,
77 // TODO: should pass a real AudioFormat object that isn't too restrictive
78 format);
79 m_line = (SourceDataLine) AudioSystem.getLine(info);
80 }
81
82
83
84 public void open(AudioInputStream audioInputStream)
85 throws LineUnavailableException, IOException
86 {
87 AudioFormat audioFormat = audioInputStream.getFormat();
88 setFormat(audioFormat);
89 int nFrameSize = audioFormat.getFrameSize();
90 if (nFrameSize < 1)
91 {
92 throw new IllegalArgumentException("frame size must be positive");
93 }
94 if (TDebug.TraceClip)
95 {
96 TDebug.out("TSoftClip.open(): format: " + audioFormat);
97 // TDebug.out("sample rate: " + audioFormat.getSampleRate());
98 }
99 byte[] abData = new byte[BUFFER_SIZE];
100 ByteArrayOutputStream baos = new ByteArrayOutputStream();
101 int nBytesRead = 0;
102 while (nBytesRead != -1)
103 {
104 try
105 {
106 nBytesRead = audioInputStream.read(abData, 0, abData.length);
107 }
108 catch (IOException e)
109 {
110 if (TDebug.TraceClip || TDebug.TraceAllExceptions)
111 {
112 TDebug.out(e);
113 }
114 }
115 if (nBytesRead >= 0)
116 {
117 if (TDebug.TraceClip)
118 {
119 TDebug.out("TSoftClip.open(): Trying to write: " + nBytesRead);
120 }
121 baos.write(abData, 0, nBytesRead);
122 if (TDebug.TraceClip)
123 {
124 TDebug.out("TSoftClip.open(): Written: " + nBytesRead);
125 }
126 }
127 }
128 m_abClip = baos.toByteArray();
129 setBufferSize(m_abClip.length);
130 // open the line
131 m_line.open(getFormat());
132 // to trigger the events
133 // open();
134 }
135
136
137
138 public int getFrameLength()
139 {
140 if (isOpen())
141 {
142 return getBufferSize() / getFormat().getFrameSize();
143 }
144 else
145 {
146 return AudioSystem.NOT_SPECIFIED;
147 }
148 }
149
150
151
152 public long getMicrosecondLength()
153 {
154 if (isOpen())
155 {
156 return (long) (getFrameLength() * getFormat().getFrameRate() * 1000000);
157 }
158 else
159 {
160 return AudioSystem.NOT_SPECIFIED;
161 }
162 }
163
164
165
166 public void setFramePosition(int nPosition)
167 {
168 // TOOD:
169 }
170
171
172
173 public void setMicrosecondPosition(long lPosition)
174 {
175 // TOOD:
176 }
177
178
179
180 public int getFramePosition()
181 {
182 // TOOD:
183 return -1;
184 }
185
186
187
188 public long getMicrosecondPosition()
189 {
190 // TOOD:
191 return -1;
192 }
193
194
195
196 public void setLoopPoints(int nStart, int nEnd)
197 {
198 // TOOD:
199 }
200
201
202
203 public void loop(int nCount)
204 {
205 if (TDebug.TraceClip)
206 {
207 TDebug.out("TSoftClip.loop(int): called; count = " + nCount);
208 }
209 if (false/*isStarted()*/)
210 {
211 /*
212 * only allow zero count to stop the looping
213 * at the end of an iteration.
214 */
215 if (nCount == 0)
216 {
217 if (TDebug.TraceClip)
218 {
219 TDebug.out("TSoftClip.loop(int): stopping sample");
220 }
221 // m_esdSample.stop();
222 }
223 }
224 else
225 {
226 m_nRepeatCount = nCount;
227 m_thread = new Thread(this);
228 m_thread.start();
229 }
230 // TOOD:
231 }
232
233
234
235 public void flush()
236 {
237 // TOOD:
238 }
239
240
241
242 public void drain()
243 {
244 // TOOD:
245 }
246
247
248
249 public void close()
250 {
251 // m_esdSample.free();
252 // m_esdSample.close();
253 // TOOD:
254 }
255
256
257
258
259 public void open()
260 {
261 // TODO:
262 }
263
264
265
266 public void start()
267 {
268 if (TDebug.TraceClip)
269 {
270 TDebug.out("TSoftClip.start(): called");
271 }
272 /*
273 * This is a hack. What start() really should do is
274 * start playing at the position playback was stopped.
275 */
276 if (TDebug.TraceClip)
277 {
278 TDebug.out("TSoftClip.start(): calling 'loop(0)' [hack]");
279 }
280 loop(0);
281 }
282
283
284
285 public void stop()
286 {
287 // TODO:
288 // m_esdSample.kill();
289 }
290
291
292
293 /*
294 * This method is enforced by DataLine, but doesn't make any
295 * sense for Clips.
296 */
297 public int available()
298 {
299 return -1;
300 }
301
302
303
304 public void run()
305 {
306 while (m_nRepeatCount >= 0)
307 {
308 m_line.write(m_abClip, 0, m_abClip.length);
309 m_nRepeatCount--;
310 }
311 }
312
313}
314
315
316
317/*** TSoftClip.java ***/
318
diff --git a/songdbj/org/tritonus/share/sampled/mixer/package.html b/songdbj/org/tritonus/share/sampled/mixer/package.html
new file mode 100644
index 0000000000..681024bc9d
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/mixer/package.html
@@ -0,0 +1,14 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Base classes for the implementation of MixerProviders.
8 The classes provided here .</p>
9
10 @see javax.sound.sampled.spi.MixerProvider
11 @see org.tritonus.sampled.mixer.alsa
12 @see org.tritonus.sampled.mixer.esd
13 </body>
14</html>
diff --git a/songdbj/org/tritonus/share/sampled/package.html b/songdbj/org/tritonus/share/sampled/package.html
new file mode 100644
index 0000000000..f7a6b56099
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/package.html
@@ -0,0 +1,10 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Helper classes for the implementation of sampled audio stuff.
8 The classes provided here .</p>
9 </body>
10</html>