From b4ef1af8e81c10f4b7164e3038f130a496ec8fda Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Fri, 11 May 2012 14:46:14 -0700 Subject: [PATCH 01/34] Squashed 'android-aac-enc/' content from commit 9d0f2aa git-subtree-dir: android-aac-enc git-subtree-split: 9d0f2aae9690301a72bd7ca5cb16027b2eeec670 --- .classpath | 9 + .gitignore | 3 + .project | 33 + AndroidManifest.xml | 28 + README.md | 32 + build.xml | 85 + jni/Android.mk | 85 + jni/Config.mk | 24 + jni/aac-enc.c | 154 ++ jni/basic_op/basicop2.c | 1624 +++++++++++ jni/basic_op/oper_32b.c | 361 +++ jni/doc/voAACEncoderSDK.pdf | Bin 0 -> 160899 bytes jni/inc/aac_rom.h | 117 + jni/inc/aacenc_core.h | 117 + jni/inc/adj_thr.h | 57 + jni/inc/adj_thr_data.h | 69 + jni/inc/band_nrg.h | 46 + jni/inc/basic_op.h | 1171 ++++++++ jni/inc/bit_cnt.h | 106 + jni/inc/bitbuffer.h | 89 + jni/inc/bitenc.h | 50 + jni/inc/block_switch.h | 72 + jni/inc/channel_map.h | 37 + jni/inc/cmnMemory.h | 106 + jni/inc/config.h | 36 + jni/inc/dyn_bits.h | 82 + jni/inc/grp_data.h | 44 + jni/inc/interface.h | 106 + jni/inc/line_pe.h | 75 + jni/inc/memalign.h | 35 + jni/inc/ms_stereo.h | 45 + jni/inc/oper_32b.h | 89 + jni/inc/pre_echo_control.h | 42 + jni/inc/psy_configuration.h | 107 + jni/inc/psy_const.h | 80 + jni/inc/psy_data.h | 66 + jni/inc/psy_main.h | 69 + jni/inc/qc_data.h | 143 + jni/inc/qc_main.h | 64 + jni/inc/quantize.h | 42 + jni/inc/sf_estim.h | 46 + jni/inc/spreading.h | 33 + jni/inc/stat_bits.h | 34 + jni/inc/tns.h | 108 + jni/inc/tns_func.h | 75 + jni/inc/tns_param.h | 52 + jni/inc/transform.h | 36 + jni/inc/typedef.h | 63 + jni/inc/typedefs.h | 187 ++ jni/inc/voAAC.h | 74 + jni/inc/voAMRWB.h | 87 + jni/inc/voAudio.h | 173 ++ jni/inc/voIndex.h | 193 ++ jni/inc/voMem.h | 65 + jni/inc/voType.h | 221 ++ jni/patent_disclaimer.txt | 9 + jni/src/aac_rom.c | 2363 +++++++++++++++++ jni/src/aacenc.c | 495 ++++ jni/src/aacenc_core.c | 239 ++ jni/src/adj_thr.c | 1225 +++++++++ jni/src/asm/ARMV5E/AutoCorrelation_v5.s | 167 ++ jni/src/asm/ARMV5E/CalcWindowEnergy_v5.s | 112 + jni/src/asm/ARMV5E/PrePostMDCT_v5.s | 131 + jni/src/asm/ARMV5E/R4R8First_v5.s | 252 ++ jni/src/asm/ARMV5E/Radix4FFT_v5.s | 169 ++ jni/src/asm/ARMV5E/band_nrg_v5.s | 204 ++ jni/src/asm/ARMV7/PrePostMDCT_v7.s | 135 + jni/src/asm/ARMV7/R4R8First_v7.s | 146 + jni/src/asm/ARMV7/Radix4FFT_v7.s | 143 + jni/src/band_nrg.c | 102 + jni/src/bit_cnt.c | 885 ++++++ jni/src/bitbuffer.c | 173 ++ jni/src/bitenc.c | 690 +++++ jni/src/block_switch.c | 431 +++ jni/src/channel_map.c | 123 + jni/src/cmnMemory.c | 71 + jni/src/dyn_bits.c | 545 ++++ jni/src/grp_data.c | 188 ++ jni/src/interface.c | 112 + jni/src/line_pe.c | 145 + jni/src/memalign.c | 112 + jni/src/ms_stereo.c | 139 + jni/src/pre_echo_control.c | 113 + jni/src/psy_configuration.c | 505 ++++ jni/src/psy_main.c | 811 ++++++ jni/src/qc_main.c | 580 ++++ jni/src/quantize.c | 445 ++++ jni/src/sf_estim.c | 882 ++++++ jni/src/spreading.c | 52 + jni/src/stat_bits.c | 237 ++ jni/src/tns.c | 932 +++++++ jni/src/transform.c | 678 +++++ libs/armeabi/libaac-encoder.so | Bin 0 -> 109064 bytes libs/xom-1.2.7.jar | Bin 0 -> 312996 bytes local.properties | 10 + proguard.cfg | 40 + project.properties | 11 + res/drawable-hdpi/ic_launcher.png | Bin 0 -> 4147 bytes res/drawable-ldpi/ic_launcher.png | Bin 0 -> 1723 bytes res/drawable-mdpi/ic_launcher.png | Bin 0 -> 2574 bytes res/layout/main.xml | 23 + res/raw/isoparser.properties | 227 ++ res/values/strings.xml | 7 + src/com/coremedia/iso/AbstractBoxParser.java | 130 + src/com/coremedia/iso/Ascii.java | 47 + src/com/coremedia/iso/BoxParser.java | 31 + src/com/coremedia/iso/ChannelHelper.java | 90 + src/com/coremedia/iso/Hex.java | 50 + src/com/coremedia/iso/IsoFile.java | 186 ++ .../iso/IsoFileConvenienceHelper.java | 89 + src/com/coremedia/iso/IsoTypeReader.java | 148 ++ .../coremedia/iso/IsoTypeReaderVariable.java | 39 + src/com/coremedia/iso/IsoTypeWriter.java | 103 + .../coremedia/iso/IsoTypeWriterVariable.java | 45 + .../coremedia/iso/PropertyBoxParserImpl.java | 207 ++ src/com/coremedia/iso/Utf8.java | 59 + .../iso/boxes/AbstractMediaHeaderBox.java | 29 + src/com/coremedia/iso/boxes/AlbumBox.java | 112 + src/com/coremedia/iso/boxes/AuthorBox.java | 94 + src/com/coremedia/iso/boxes/BitRateBox.java | 91 + src/com/coremedia/iso/boxes/Box.java | 51 + .../iso/boxes/ChunkOffset64BitBox.java | 51 + .../coremedia/iso/boxes/ChunkOffsetBox.java | 21 + .../iso/boxes/ClassificationBox.java | 110 + .../CompositionShiftLeastGreatestAtom.java | 101 + .../iso/boxes/CompositionTimeToSample.java | 150 ++ src/com/coremedia/iso/boxes/ContainerBox.java | 74 + src/com/coremedia/iso/boxes/CopyrightBox.java | 86 + .../coremedia/iso/boxes/DataEntryUrlBox.java | 53 + .../coremedia/iso/boxes/DataEntryUrnBox.java | 69 + .../iso/boxes/DataInformationBox.java | 36 + .../coremedia/iso/boxes/DataReferenceBox.java | 65 + .../coremedia/iso/boxes/DescriptionBox.java | 77 + src/com/coremedia/iso/boxes/EditBox.java | 34 + src/com/coremedia/iso/boxes/EditListBox.java | 248 ++ src/com/coremedia/iso/boxes/FileTypeBox.java | 144 + src/com/coremedia/iso/boxes/FreeBox.java | 64 + src/com/coremedia/iso/boxes/FreeSpaceBox.java | 63 + src/com/coremedia/iso/boxes/FullBox.java | 17 + .../iso/boxes/GenericMediaHeaderBoxImpl.java | 39 + src/com/coremedia/iso/boxes/GenreBox.java | 80 + src/com/coremedia/iso/boxes/HandlerBox.java | 151 ++ .../iso/boxes/HintMediaHeaderBox.java | 91 + src/com/coremedia/iso/boxes/ItemDataBox.java | 43 + .../coremedia/iso/boxes/ItemLocationBox.java | 360 +++ .../iso/boxes/ItemProtectionBox.java | 61 + src/com/coremedia/iso/boxes/KeywordsBox.java | 95 + src/com/coremedia/iso/boxes/MediaBox.java | 61 + .../coremedia/iso/boxes/MediaHeaderBox.java | 147 + .../iso/boxes/MediaInformationBox.java | 49 + src/com/coremedia/iso/boxes/MetaBox.java | 113 + src/com/coremedia/iso/boxes/MovieBox.java | 67 + .../coremedia/iso/boxes/MovieHeaderBox.java | 210 ++ .../iso/boxes/NullMediaHeaderBox.java | 43 + .../iso/boxes/ObjectDescriptorBox.java | 0 .../iso/boxes/OmaDrmAccessUnitFormatBox.java | 87 + .../iso/boxes/OriginalFormatBox.java | 69 + src/com/coremedia/iso/boxes/PerformerBox.java | 78 + .../ProgressiveDownloadInformationBox.java | 95 + .../boxes/ProtectionSchemeInformationBox.java | 42 + src/com/coremedia/iso/boxes/RatingBox.java | 124 + .../coremedia/iso/boxes/RecordingYearBox.java | 63 + .../SampleAuxiliaryInformationOffsetsBox.java | 127 + .../SampleAuxiliaryInformationSizesBox.java | 134 + .../iso/boxes/SampleDependencyTypeBox.java | 136 + .../iso/boxes/SampleDescriptionBox.java | 81 + .../coremedia/iso/boxes/SampleSizeBox.java | 121 + .../coremedia/iso/boxes/SampleTableBox.java | 124 + .../coremedia/iso/boxes/SampleToChunkBox.java | 156 ++ .../coremedia/iso/boxes/SampleToGroupBox.java | 122 + .../iso/boxes/SchemeInformationBox.java | 33 + .../coremedia/iso/boxes/SchemeTypeBox.java | 101 + .../iso/boxes/SoundMediaHeaderBox.java | 58 + .../iso/boxes/StaticChunkOffsetBox.java | 71 + .../iso/boxes/SubSampleInformationBox.java | 208 ++ .../iso/boxes/SubtitleMediaHeaderBox.java | 30 + .../coremedia/iso/boxes/SyncSampleBox.java | 83 + .../coremedia/iso/boxes/TimeToSampleBox.java | 152 ++ src/com/coremedia/iso/boxes/TitleBox.java | 89 + src/com/coremedia/iso/boxes/TrackBox.java | 71 + .../coremedia/iso/boxes/TrackHeaderBox.java | 249 ++ .../iso/boxes/TrackReferenceBox.java | 41 + .../iso/boxes/TrackReferenceTypeBox.java | 76 + src/com/coremedia/iso/boxes/UnknownBox.java | 59 + src/com/coremedia/iso/boxes/UserBox.java | 64 + src/com/coremedia/iso/boxes/UserDataBox.java | 59 + .../iso/boxes/VideoMediaHeaderBox.java | 81 + .../coremedia/iso/boxes/WriteListener.java | 10 + src/com/coremedia/iso/boxes/XmlBox.java | 44 + .../boxes/apple/AbstractAppleMetaDataBox.java | 164 ++ .../iso/boxes/apple/AppleAlbumArtistBox.java | 16 + .../iso/boxes/apple/AppleAlbumBox.java | 15 + .../iso/boxes/apple/AppleArtistBox.java | 16 + .../iso/boxes/apple/AppleCommentBox.java | 16 + .../iso/boxes/apple/AppleCompilationBox.java | 15 + .../iso/boxes/apple/AppleCopyrightBox.java | 15 + .../iso/boxes/apple/AppleCoverBox.java | 44 + .../iso/boxes/apple/AppleCustomGenreBox.java | 28 + .../iso/boxes/apple/AppleDataBox.java | 92 + .../iso/boxes/apple/AppleDataRateBox.java | 53 + .../boxes/apple/AppleDataReferenceBox.java | 71 + .../iso/boxes/apple/AppleDescriptionBox.java | 15 + .../iso/boxes/apple/AppleEncoderBox.java | 15 + .../boxes/apple/AppleGaplessPlaybackBox.java | 15 + .../iso/boxes/apple/AppleGenericBox.java | 15 + .../iso/boxes/apple/AppleGroupingBox.java | 15 + .../coremedia/iso/boxes/apple/AppleIdBox.java | 15 + .../iso/boxes/apple/AppleItemListBox.java | 15 + .../boxes/apple/AppleLosslessSpecificBox.java | 163 ++ .../iso/boxes/apple/AppleMeanBox.java | 47 + .../iso/boxes/apple/AppleMediaTypeBox.java | 39 + .../iso/boxes/apple/AppleNameBox.java | 45 + .../iso/boxes/apple/AppleNetworkBox.java | 16 + .../iso/boxes/apple/ApplePurchaseDateBox.java | 15 + .../iso/boxes/apple/AppleRatingBox.java | 16 + .../boxes/apple/AppleRecordingYearBox.java | 16 + .../boxes/apple/AppleReferenceMovieBox.java | 28 + .../AppleReferenceMovieDescriptorBox.java | 27 + .../iso/boxes/apple/AppleShowBox.java | 15 + .../iso/boxes/apple/AppleSortAlbumBox.java | 14 + .../boxes/apple/AppleStandardGenreBox.java | 14 + .../boxes/apple/AppleStoreAccountTypeBox.java | 27 + .../boxes/apple/AppleStoreCountryCodeBox.java | 54 + .../iso/boxes/apple/AppleSynopsisBox.java | 16 + .../iso/boxes/apple/AppleTempBox.java | 28 + .../iso/boxes/apple/AppleTrackAuthorBox.java | 16 + .../iso/boxes/apple/AppleTrackNumberBox.java | 48 + .../iso/boxes/apple/AppleTrackTitleBox.java | 15 + .../iso/boxes/apple/AppleTvEpisodeBox.java | 15 + .../boxes/apple/AppleTvEpisodeNumberBox.java | 15 + .../iso/boxes/apple/AppleTvSeasonBox.java | 15 + .../iso/boxes/apple/AppleWaveBox.java | 16 + .../iso/boxes/dece/TrickPlayBox.java | 108 + .../iso/boxes/fragment/MovieExtendsBox.java | 31 + .../boxes/fragment/MovieExtendsHeaderBox.java | 67 + .../iso/boxes/fragment/MovieFragmentBox.java | 96 + .../fragment/MovieFragmentHeaderBox.java | 72 + .../MovieFragmentRandomAccessBox.java | 34 + .../MovieFragmentRandomAccessOffsetBox.java | 62 + .../iso/boxes/fragment/SampleFlags.java | 207 ++ .../iso/boxes/fragment/TrackExtendsBox.java | 115 + .../TrackFragmentBaseMediaDecodeTimeBox.java | 76 + .../iso/boxes/fragment/TrackFragmentBox.java | 43 + .../fragment/TrackFragmentHeaderBox.java | 208 ++ .../TrackFragmentRandomAccessBox.java | 287 ++ .../iso/boxes/fragment/TrackRunBox.java | 381 +++ .../iso/boxes/h264/AvcConfigurationBox.java | 285 ++ .../coremedia/iso/boxes/mdat/DummyMap.java | 84 + .../iso/boxes/mdat/MediaDataBox.java | 94 + .../coremedia/iso/boxes/mdat/SampleList.java | 194 ++ src/com/coremedia/iso/boxes/mdat/Segment.java | 12 + src/com/coremedia/iso/boxes/odf-boxes.zip | Bin 0 -> 37706 bytes src/com/coremedia/iso/boxes/rtp-boxes.zip | Bin 0 -> 31772 bytes .../iso/boxes/sampleentry/AmrSpecificBox.java | 101 + .../boxes/sampleentry/AudioSampleEntry.java | 251 ++ .../boxes/sampleentry/MpegSampleEntry.java | 43 + .../Ovc1VisualSampleEntryImpl.java | 45 + .../iso/boxes/sampleentry/SampleEntry.java | 157 ++ .../sampleentry/SubtitleSampleEntry.java | 76 + .../boxes/sampleentry/TextSampleEntry.java | 305 +++ .../boxes/sampleentry/VisualSampleEntry.java | 213 ++ .../threegpp26244/LocationInformationBox.java | 126 + .../iso/boxes/vodafone/AlbumArtistBox.java | 78 + .../vodafone/ContentDistributorIdBox.java | 70 + .../iso/boxes/vodafone/CoverUriBox.java | 66 + .../iso/boxes/vodafone/LyricsUriBox.java | 66 + src/com/googlecode/mp4parser/AbstractBox.java | 271 ++ .../mp4parser/AbstractContainerBox.java | 170 ++ .../googlecode/mp4parser/AbstractFullBox.java | 74 + .../mp4parser/FullContainerBox.java | 157 ++ .../annotations/DoNotParseDetail.java | 43 + .../mp4parser/annotations/ParseDetail.java | 33 + .../mp4parser/authoring/AbstractTrack.java | 60 + .../mp4parser/authoring/DateHelper.java | 44 + .../googlecode/mp4parser/authoring/Movie.java | 91 + .../mp4parser/authoring/Mp4TrackImpl.java | 178 ++ .../googlecode/mp4parser/authoring/Track.java | 60 + .../mp4parser/authoring/TrackMetaData.java | 139 + .../authoring/builder/ByteBufferHelper.java | 50 + .../authoring/builder/DefaultMp4Builder.java | 547 ++++ .../builder/FragmentIntersectionFinder.java | 34 + .../builder/FragmentedMp4Builder.java | 654 +++++ .../authoring/builder/Mp4Builder.java | 37 + .../SyncSampleIntersectFinderImpl.java | 205 ++ .../builder/TwoSecondIntersectionFinder.java | 81 + .../builder/smoothstreaming/AudioQuality.java | 28 + .../FlatManifestWriterImpl.java | 330 +++ .../FlatPackageWriterImpl.java | 177 ++ .../smoothstreaming/ManifestWriter.java | 31 + .../smoothstreaming/PackageWriter.java | 27 + .../builder/smoothstreaming/VideoQuality.java | 25 + .../authoring/container/mp4/MovieCreator.java | 40 + .../authoring/tracks/AACTrackImpl.java | 273 ++ .../authoring/tracks/AC3TrackImpl.java | 501 ++++ .../mp4parser/authoring/tracks/Amf0Track.java | 116 + .../authoring/tracks/AppendTrack.java | 166 ++ .../tracks/ChangeTimeScaleTrack.java | 176 ++ .../authoring/tracks/CroppedTrack.java | 150 ++ .../tracks/DivideTimeScaleTrack.java | 131 + .../authoring/tracks/EC3TrackImpl.java | 403 +++ .../authoring/tracks/H264TrackImpl.java | 678 +++++ .../tracks/MultiplyTimeScaleTrack.java | 135 + .../authoring/tracks/TextTrackImpl.java | 164 ++ .../mp4parser/boxes/AC3SpecificBox.java | 119 + .../boxes/AbstractSampleEncryptionBox.java | 303 +++ .../boxes/AbstractTrackEncryptionBox.java | 93 + .../mp4parser/boxes/DTSSpecificBox.java | 217 ++ .../mp4parser/boxes/EC3SpecificBox.java | 139 + .../mp4parser/boxes/MLPSpecificBox.java | 76 + .../ActionMessageFormat0SampleEntryBox.java | 38 + .../mp4parser/boxes/apple/TimeCodeBox.java | 39 + .../basemediaformat/AvcNalUnitStorageBox.java | 75 + .../basemediaformat/SampleEncryptionBox.java | 24 + .../basemediaformat/TrackEncryptionBox.java | 12 + .../googlecode/mp4parser/boxes/mp4-boxes.zip | Bin 0 -> 62700 bytes .../boxes/mp4/AbstractDescriptorBox.java | 84 + .../mp4parser/boxes/mp4/ESDescriptorBox.java | 36 + .../boxes/mp4/ObjectDescriptorBox.java | 46 + .../AudioSpecificConfig.java | 979 +++++++ .../mp4/objectdescriptors/BaseDescriptor.java | 99 + .../objectdescriptors/BitReaderBuffer.java | 51 + .../objectdescriptors/BitWriterBuffer.java | 33 + .../DecoderConfigDescriptor.java | 262 ++ .../DecoderSpecificInfo.java | 61 + .../mp4/objectdescriptors/Descriptor.java | 39 + .../mp4/objectdescriptors/ESDescriptor.java | 333 +++ .../ExtensionDescriptor.java | 73 + .../ExtensionProfileLevelDescriptor.java | 51 + .../InitialObjectDescriptor.java | 136 + .../ObjectDescriptor.java_bak | 104 + .../ObjectDescriptorBase.java | 27 + .../ObjectDescriptorFactory.java | 189 ++ .../ProfileLevelIndicationDescriptor.java | 47 + .../objectdescriptors/SLConfigDescriptor.java | 96 + .../objectdescriptors/UnknownDescriptor.java | 42 + .../boxes/piff/PiffSampleEncryptionBox.java | 45 + .../boxes/piff/PiffTrackEncryptionBox.java | 34 + .../mp4parser/boxes/piff/PlayReadyHeader.java | 253 ++ .../boxes/piff/ProtectionSpecificHeader.java | 79 + .../mp4parser/boxes/piff/TfrfBox.java | 129 + .../mp4parser/boxes/piff/TfxdBox.java | 85 + ...asedProtectionSystemSpecificHeaderBox.java | 112 + .../boxes/threegpp26245/FontTableBox.java | 95 + .../ultraviolet/AssetInformationBox.java | 75 + .../boxes/ultraviolet/BaseLocationBox.java | 103 + src/com/googlecode/mp4parser/h264/BTree.java | 69 + .../googlecode/mp4parser/h264/CharCache.java | 57 + src/com/googlecode/mp4parser/h264/Debug.java | 88 + .../mp4parser/h264/model/AspectRatio.java | 50 + .../h264/model/BitstreamElement.java | 29 + .../mp4parser/h264/model/ChromaFormat.java | 77 + .../mp4parser/h264/model/HRDParameters.java | 53 + .../h264/model/PictureParameterSet.java | 406 +++ .../mp4parser/h264/model/ScalingList.java | 83 + .../mp4parser/h264/model/ScalingMatrix.java | 37 + .../mp4parser/h264/model/SeqParameterSet.java | 556 ++++ .../mp4parser/h264/model/VUIParameters.java | 94 + .../mp4parser/h264/read/BitstreamReader.java | 194 ++ .../mp4parser/h264/read/CAVLCReader.java | 185 ++ .../mp4parser/h264/write/BitstreamWriter.java | 108 + .../mp4parser/h264/write/CAVLCWriter.java | 100 + .../googlecode/mp4parser/srt/SrtParser.java | 59 + .../mp4parser/util/ByteBufferByteChannel.java | 56 + .../googlecode/mp4parser/util/CastUtils.java | 34 + src/com/googlecode/mp4parser/util/Math.java | 30 + src/com/googlecode/mp4parser/util/Path.java | 113 + .../mp4parser/util/UUIDConverter.java | 48 + src/com/todoroo/aacenc/AACEncoder.java | 28 + src/com/todoroo/aacenc/AACToM4A.java | 44 + src/com/todoroo/aacenc/ContextManager.java | 63 + src/com/todoroo/aacenc/Main.java | 195 ++ 371 files changed, 49609 insertions(+) create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100644 AndroidManifest.xml create mode 100644 README.md create mode 100644 build.xml create mode 100644 jni/Android.mk create mode 100644 jni/Config.mk create mode 100644 jni/aac-enc.c create mode 100644 jni/basic_op/basicop2.c create mode 100644 jni/basic_op/oper_32b.c create mode 100644 jni/doc/voAACEncoderSDK.pdf create mode 100644 jni/inc/aac_rom.h create mode 100644 jni/inc/aacenc_core.h create mode 100644 jni/inc/adj_thr.h create mode 100644 jni/inc/adj_thr_data.h create mode 100644 jni/inc/band_nrg.h create mode 100644 jni/inc/basic_op.h create mode 100644 jni/inc/bit_cnt.h create mode 100644 jni/inc/bitbuffer.h create mode 100644 jni/inc/bitenc.h create mode 100644 jni/inc/block_switch.h create mode 100644 jni/inc/channel_map.h create mode 100644 jni/inc/cmnMemory.h create mode 100644 jni/inc/config.h create mode 100644 jni/inc/dyn_bits.h create mode 100644 jni/inc/grp_data.h create mode 100644 jni/inc/interface.h create mode 100644 jni/inc/line_pe.h create mode 100644 jni/inc/memalign.h create mode 100644 jni/inc/ms_stereo.h create mode 100644 jni/inc/oper_32b.h create mode 100644 jni/inc/pre_echo_control.h create mode 100644 jni/inc/psy_configuration.h create mode 100644 jni/inc/psy_const.h create mode 100644 jni/inc/psy_data.h create mode 100644 jni/inc/psy_main.h create mode 100644 jni/inc/qc_data.h create mode 100644 jni/inc/qc_main.h create mode 100644 jni/inc/quantize.h create mode 100644 jni/inc/sf_estim.h create mode 100644 jni/inc/spreading.h create mode 100644 jni/inc/stat_bits.h create mode 100644 jni/inc/tns.h create mode 100644 jni/inc/tns_func.h create mode 100644 jni/inc/tns_param.h create mode 100644 jni/inc/transform.h create mode 100644 jni/inc/typedef.h create mode 100644 jni/inc/typedefs.h create mode 100644 jni/inc/voAAC.h create mode 100644 jni/inc/voAMRWB.h create mode 100644 jni/inc/voAudio.h create mode 100644 jni/inc/voIndex.h create mode 100644 jni/inc/voMem.h create mode 100644 jni/inc/voType.h create mode 100644 jni/patent_disclaimer.txt create mode 100644 jni/src/aac_rom.c create mode 100644 jni/src/aacenc.c create mode 100644 jni/src/aacenc_core.c create mode 100644 jni/src/adj_thr.c create mode 100644 jni/src/asm/ARMV5E/AutoCorrelation_v5.s create mode 100644 jni/src/asm/ARMV5E/CalcWindowEnergy_v5.s create mode 100644 jni/src/asm/ARMV5E/PrePostMDCT_v5.s create mode 100644 jni/src/asm/ARMV5E/R4R8First_v5.s create mode 100644 jni/src/asm/ARMV5E/Radix4FFT_v5.s create mode 100644 jni/src/asm/ARMV5E/band_nrg_v5.s create mode 100644 jni/src/asm/ARMV7/PrePostMDCT_v7.s create mode 100644 jni/src/asm/ARMV7/R4R8First_v7.s create mode 100644 jni/src/asm/ARMV7/Radix4FFT_v7.s create mode 100644 jni/src/band_nrg.c create mode 100644 jni/src/bit_cnt.c create mode 100644 jni/src/bitbuffer.c create mode 100644 jni/src/bitenc.c create mode 100644 jni/src/block_switch.c create mode 100644 jni/src/channel_map.c create mode 100644 jni/src/cmnMemory.c create mode 100644 jni/src/dyn_bits.c create mode 100644 jni/src/grp_data.c create mode 100644 jni/src/interface.c create mode 100644 jni/src/line_pe.c create mode 100644 jni/src/memalign.c create mode 100644 jni/src/ms_stereo.c create mode 100644 jni/src/pre_echo_control.c create mode 100644 jni/src/psy_configuration.c create mode 100644 jni/src/psy_main.c create mode 100644 jni/src/qc_main.c create mode 100644 jni/src/quantize.c create mode 100644 jni/src/sf_estim.c create mode 100644 jni/src/spreading.c create mode 100644 jni/src/stat_bits.c create mode 100644 jni/src/tns.c create mode 100644 jni/src/transform.c create mode 100755 libs/armeabi/libaac-encoder.so create mode 100644 libs/xom-1.2.7.jar create mode 100644 local.properties create mode 100644 proguard.cfg create mode 100644 project.properties create mode 100644 res/drawable-hdpi/ic_launcher.png create mode 100644 res/drawable-ldpi/ic_launcher.png create mode 100644 res/drawable-mdpi/ic_launcher.png create mode 100644 res/layout/main.xml create mode 100644 res/raw/isoparser.properties create mode 100644 res/values/strings.xml create mode 100644 src/com/coremedia/iso/AbstractBoxParser.java create mode 100644 src/com/coremedia/iso/Ascii.java create mode 100644 src/com/coremedia/iso/BoxParser.java create mode 100644 src/com/coremedia/iso/ChannelHelper.java create mode 100644 src/com/coremedia/iso/Hex.java create mode 100644 src/com/coremedia/iso/IsoFile.java create mode 100644 src/com/coremedia/iso/IsoFileConvenienceHelper.java create mode 100644 src/com/coremedia/iso/IsoTypeReader.java create mode 100644 src/com/coremedia/iso/IsoTypeReaderVariable.java create mode 100644 src/com/coremedia/iso/IsoTypeWriter.java create mode 100644 src/com/coremedia/iso/IsoTypeWriterVariable.java create mode 100644 src/com/coremedia/iso/PropertyBoxParserImpl.java create mode 100644 src/com/coremedia/iso/Utf8.java create mode 100644 src/com/coremedia/iso/boxes/AbstractMediaHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/AlbumBox.java create mode 100644 src/com/coremedia/iso/boxes/AuthorBox.java create mode 100644 src/com/coremedia/iso/boxes/BitRateBox.java create mode 100644 src/com/coremedia/iso/boxes/Box.java create mode 100755 src/com/coremedia/iso/boxes/ChunkOffset64BitBox.java create mode 100755 src/com/coremedia/iso/boxes/ChunkOffsetBox.java create mode 100644 src/com/coremedia/iso/boxes/ClassificationBox.java create mode 100644 src/com/coremedia/iso/boxes/CompositionShiftLeastGreatestAtom.java create mode 100644 src/com/coremedia/iso/boxes/CompositionTimeToSample.java create mode 100644 src/com/coremedia/iso/boxes/ContainerBox.java create mode 100644 src/com/coremedia/iso/boxes/CopyrightBox.java create mode 100644 src/com/coremedia/iso/boxes/DataEntryUrlBox.java create mode 100644 src/com/coremedia/iso/boxes/DataEntryUrnBox.java create mode 100644 src/com/coremedia/iso/boxes/DataInformationBox.java create mode 100644 src/com/coremedia/iso/boxes/DataReferenceBox.java create mode 100644 src/com/coremedia/iso/boxes/DescriptionBox.java create mode 100644 src/com/coremedia/iso/boxes/EditBox.java create mode 100644 src/com/coremedia/iso/boxes/EditListBox.java create mode 100644 src/com/coremedia/iso/boxes/FileTypeBox.java create mode 100644 src/com/coremedia/iso/boxes/FreeBox.java create mode 100644 src/com/coremedia/iso/boxes/FreeSpaceBox.java create mode 100644 src/com/coremedia/iso/boxes/FullBox.java create mode 100644 src/com/coremedia/iso/boxes/GenericMediaHeaderBoxImpl.java create mode 100644 src/com/coremedia/iso/boxes/GenreBox.java create mode 100644 src/com/coremedia/iso/boxes/HandlerBox.java create mode 100644 src/com/coremedia/iso/boxes/HintMediaHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/ItemDataBox.java create mode 100644 src/com/coremedia/iso/boxes/ItemLocationBox.java create mode 100644 src/com/coremedia/iso/boxes/ItemProtectionBox.java create mode 100644 src/com/coremedia/iso/boxes/KeywordsBox.java create mode 100644 src/com/coremedia/iso/boxes/MediaBox.java create mode 100644 src/com/coremedia/iso/boxes/MediaHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/MediaInformationBox.java create mode 100644 src/com/coremedia/iso/boxes/MetaBox.java create mode 100644 src/com/coremedia/iso/boxes/MovieBox.java create mode 100644 src/com/coremedia/iso/boxes/MovieHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/NullMediaHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/ObjectDescriptorBox.java create mode 100644 src/com/coremedia/iso/boxes/OmaDrmAccessUnitFormatBox.java create mode 100644 src/com/coremedia/iso/boxes/OriginalFormatBox.java create mode 100644 src/com/coremedia/iso/boxes/PerformerBox.java create mode 100644 src/com/coremedia/iso/boxes/ProgressiveDownloadInformationBox.java create mode 100644 src/com/coremedia/iso/boxes/ProtectionSchemeInformationBox.java create mode 100644 src/com/coremedia/iso/boxes/RatingBox.java create mode 100644 src/com/coremedia/iso/boxes/RecordingYearBox.java create mode 100644 src/com/coremedia/iso/boxes/SampleAuxiliaryInformationOffsetsBox.java create mode 100644 src/com/coremedia/iso/boxes/SampleAuxiliaryInformationSizesBox.java create mode 100644 src/com/coremedia/iso/boxes/SampleDependencyTypeBox.java create mode 100644 src/com/coremedia/iso/boxes/SampleDescriptionBox.java create mode 100644 src/com/coremedia/iso/boxes/SampleSizeBox.java create mode 100644 src/com/coremedia/iso/boxes/SampleTableBox.java create mode 100644 src/com/coremedia/iso/boxes/SampleToChunkBox.java create mode 100644 src/com/coremedia/iso/boxes/SampleToGroupBox.java create mode 100644 src/com/coremedia/iso/boxes/SchemeInformationBox.java create mode 100644 src/com/coremedia/iso/boxes/SchemeTypeBox.java create mode 100644 src/com/coremedia/iso/boxes/SoundMediaHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/StaticChunkOffsetBox.java create mode 100644 src/com/coremedia/iso/boxes/SubSampleInformationBox.java create mode 100644 src/com/coremedia/iso/boxes/SubtitleMediaHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/SyncSampleBox.java create mode 100644 src/com/coremedia/iso/boxes/TimeToSampleBox.java create mode 100644 src/com/coremedia/iso/boxes/TitleBox.java create mode 100644 src/com/coremedia/iso/boxes/TrackBox.java create mode 100644 src/com/coremedia/iso/boxes/TrackHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/TrackReferenceBox.java create mode 100644 src/com/coremedia/iso/boxes/TrackReferenceTypeBox.java create mode 100644 src/com/coremedia/iso/boxes/UnknownBox.java create mode 100644 src/com/coremedia/iso/boxes/UserBox.java create mode 100644 src/com/coremedia/iso/boxes/UserDataBox.java create mode 100644 src/com/coremedia/iso/boxes/VideoMediaHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/WriteListener.java create mode 100644 src/com/coremedia/iso/boxes/XmlBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AbstractAppleMetaDataBox.java create mode 100755 src/com/coremedia/iso/boxes/apple/AppleAlbumArtistBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleAlbumBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleArtistBox.java create mode 100755 src/com/coremedia/iso/boxes/apple/AppleCommentBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleCompilationBox.java create mode 100755 src/com/coremedia/iso/boxes/apple/AppleCopyrightBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleCoverBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleCustomGenreBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleDataBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleDataRateBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleDataReferenceBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleDescriptionBox.java create mode 100755 src/com/coremedia/iso/boxes/apple/AppleEncoderBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleGaplessPlaybackBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleGenericBox.java create mode 100755 src/com/coremedia/iso/boxes/apple/AppleGroupingBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleIdBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleItemListBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleLosslessSpecificBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleMeanBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleMediaTypeBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleNameBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleNetworkBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/ApplePurchaseDateBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleRatingBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleRecordingYearBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleReferenceMovieBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleReferenceMovieDescriptorBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleShowBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleSortAlbumBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleStandardGenreBox.java create mode 100755 src/com/coremedia/iso/boxes/apple/AppleStoreAccountTypeBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleStoreCountryCodeBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleSynopsisBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleTempBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleTrackAuthorBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleTrackNumberBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleTrackTitleBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleTvEpisodeBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleTvEpisodeNumberBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleTvSeasonBox.java create mode 100644 src/com/coremedia/iso/boxes/apple/AppleWaveBox.java create mode 100644 src/com/coremedia/iso/boxes/dece/TrickPlayBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/MovieExtendsBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/MovieExtendsHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/MovieFragmentBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/MovieFragmentHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/MovieFragmentRandomAccessBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/MovieFragmentRandomAccessOffsetBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/SampleFlags.java create mode 100644 src/com/coremedia/iso/boxes/fragment/TrackExtendsBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/TrackFragmentBaseMediaDecodeTimeBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/TrackFragmentBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/TrackFragmentHeaderBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/TrackFragmentRandomAccessBox.java create mode 100644 src/com/coremedia/iso/boxes/fragment/TrackRunBox.java create mode 100644 src/com/coremedia/iso/boxes/h264/AvcConfigurationBox.java create mode 100644 src/com/coremedia/iso/boxes/mdat/DummyMap.java create mode 100644 src/com/coremedia/iso/boxes/mdat/MediaDataBox.java create mode 100644 src/com/coremedia/iso/boxes/mdat/SampleList.java create mode 100644 src/com/coremedia/iso/boxes/mdat/Segment.java create mode 100644 src/com/coremedia/iso/boxes/odf-boxes.zip create mode 100644 src/com/coremedia/iso/boxes/rtp-boxes.zip create mode 100644 src/com/coremedia/iso/boxes/sampleentry/AmrSpecificBox.java create mode 100644 src/com/coremedia/iso/boxes/sampleentry/AudioSampleEntry.java create mode 100644 src/com/coremedia/iso/boxes/sampleentry/MpegSampleEntry.java create mode 100644 src/com/coremedia/iso/boxes/sampleentry/Ovc1VisualSampleEntryImpl.java create mode 100644 src/com/coremedia/iso/boxes/sampleentry/SampleEntry.java create mode 100644 src/com/coremedia/iso/boxes/sampleentry/SubtitleSampleEntry.java create mode 100644 src/com/coremedia/iso/boxes/sampleentry/TextSampleEntry.java create mode 100644 src/com/coremedia/iso/boxes/sampleentry/VisualSampleEntry.java create mode 100644 src/com/coremedia/iso/boxes/threegpp26244/LocationInformationBox.java create mode 100644 src/com/coremedia/iso/boxes/vodafone/AlbumArtistBox.java create mode 100644 src/com/coremedia/iso/boxes/vodafone/ContentDistributorIdBox.java create mode 100644 src/com/coremedia/iso/boxes/vodafone/CoverUriBox.java create mode 100644 src/com/coremedia/iso/boxes/vodafone/LyricsUriBox.java create mode 100644 src/com/googlecode/mp4parser/AbstractBox.java create mode 100644 src/com/googlecode/mp4parser/AbstractContainerBox.java create mode 100644 src/com/googlecode/mp4parser/AbstractFullBox.java create mode 100644 src/com/googlecode/mp4parser/FullContainerBox.java create mode 100644 src/com/googlecode/mp4parser/annotations/DoNotParseDetail.java create mode 100644 src/com/googlecode/mp4parser/annotations/ParseDetail.java create mode 100644 src/com/googlecode/mp4parser/authoring/AbstractTrack.java create mode 100644 src/com/googlecode/mp4parser/authoring/DateHelper.java create mode 100644 src/com/googlecode/mp4parser/authoring/Movie.java create mode 100644 src/com/googlecode/mp4parser/authoring/Mp4TrackImpl.java create mode 100644 src/com/googlecode/mp4parser/authoring/Track.java create mode 100644 src/com/googlecode/mp4parser/authoring/TrackMetaData.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/ByteBufferHelper.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/DefaultMp4Builder.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/FragmentIntersectionFinder.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/FragmentedMp4Builder.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/Mp4Builder.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/SyncSampleIntersectFinderImpl.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/TwoSecondIntersectionFinder.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/smoothstreaming/AudioQuality.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/smoothstreaming/FlatManifestWriterImpl.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/smoothstreaming/FlatPackageWriterImpl.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/smoothstreaming/ManifestWriter.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/smoothstreaming/PackageWriter.java create mode 100644 src/com/googlecode/mp4parser/authoring/builder/smoothstreaming/VideoQuality.java create mode 100644 src/com/googlecode/mp4parser/authoring/container/mp4/MovieCreator.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/AACTrackImpl.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/AC3TrackImpl.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/Amf0Track.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/AppendTrack.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/ChangeTimeScaleTrack.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/CroppedTrack.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/DivideTimeScaleTrack.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/EC3TrackImpl.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/H264TrackImpl.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/MultiplyTimeScaleTrack.java create mode 100644 src/com/googlecode/mp4parser/authoring/tracks/TextTrackImpl.java create mode 100644 src/com/googlecode/mp4parser/boxes/AC3SpecificBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/AbstractSampleEncryptionBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/AbstractTrackEncryptionBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/DTSSpecificBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/EC3SpecificBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/MLPSpecificBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/adobe/ActionMessageFormat0SampleEntryBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/apple/TimeCodeBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/basemediaformat/AvcNalUnitStorageBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/basemediaformat/SampleEncryptionBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/basemediaformat/TrackEncryptionBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4-boxes.zip create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/AbstractDescriptorBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/ESDescriptorBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/ObjectDescriptorBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/AudioSpecificConfig.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BaseDescriptor.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitReaderBuffer.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitWriterBuffer.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderConfigDescriptor.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderSpecificInfo.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/Descriptor.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ESDescriptor.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionDescriptor.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionProfileLevelDescriptor.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/InitialObjectDescriptor.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptor.java_bak create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorBase.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorFactory.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ProfileLevelIndicationDescriptor.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/SLConfigDescriptor.java create mode 100644 src/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/UnknownDescriptor.java create mode 100644 src/com/googlecode/mp4parser/boxes/piff/PiffSampleEncryptionBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/piff/PiffTrackEncryptionBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/piff/PlayReadyHeader.java create mode 100644 src/com/googlecode/mp4parser/boxes/piff/ProtectionSpecificHeader.java create mode 100644 src/com/googlecode/mp4parser/boxes/piff/TfrfBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/piff/TfxdBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/piff/UuidBasedProtectionSystemSpecificHeaderBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/threegpp26245/FontTableBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/ultraviolet/AssetInformationBox.java create mode 100644 src/com/googlecode/mp4parser/boxes/ultraviolet/BaseLocationBox.java create mode 100644 src/com/googlecode/mp4parser/h264/BTree.java create mode 100644 src/com/googlecode/mp4parser/h264/CharCache.java create mode 100644 src/com/googlecode/mp4parser/h264/Debug.java create mode 100644 src/com/googlecode/mp4parser/h264/model/AspectRatio.java create mode 100644 src/com/googlecode/mp4parser/h264/model/BitstreamElement.java create mode 100644 src/com/googlecode/mp4parser/h264/model/ChromaFormat.java create mode 100644 src/com/googlecode/mp4parser/h264/model/HRDParameters.java create mode 100644 src/com/googlecode/mp4parser/h264/model/PictureParameterSet.java create mode 100644 src/com/googlecode/mp4parser/h264/model/ScalingList.java create mode 100644 src/com/googlecode/mp4parser/h264/model/ScalingMatrix.java create mode 100644 src/com/googlecode/mp4parser/h264/model/SeqParameterSet.java create mode 100644 src/com/googlecode/mp4parser/h264/model/VUIParameters.java create mode 100644 src/com/googlecode/mp4parser/h264/read/BitstreamReader.java create mode 100644 src/com/googlecode/mp4parser/h264/read/CAVLCReader.java create mode 100644 src/com/googlecode/mp4parser/h264/write/BitstreamWriter.java create mode 100644 src/com/googlecode/mp4parser/h264/write/CAVLCWriter.java create mode 100644 src/com/googlecode/mp4parser/srt/SrtParser.java create mode 100644 src/com/googlecode/mp4parser/util/ByteBufferByteChannel.java create mode 100644 src/com/googlecode/mp4parser/util/CastUtils.java create mode 100644 src/com/googlecode/mp4parser/util/Math.java create mode 100644 src/com/googlecode/mp4parser/util/Path.java create mode 100644 src/com/googlecode/mp4parser/util/UUIDConverter.java create mode 100644 src/com/todoroo/aacenc/AACEncoder.java create mode 100644 src/com/todoroo/aacenc/AACToM4A.java create mode 100644 src/com/todoroo/aacenc/ContextManager.java create mode 100644 src/com/todoroo/aacenc/Main.java diff --git a/.classpath b/.classpath new file mode 100644 index 000000000..46fb3389c --- /dev/null +++ b/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..83a05088f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +gen +bin +obj diff --git a/.project b/.project new file mode 100644 index 000000000..c0e662584 --- /dev/null +++ b/.project @@ -0,0 +1,33 @@ + + + aac-enc + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 000000000..46ada8375 --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..2e93ef936 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +Android AAC Encoder project +============================ + +Extraction of Android Stagefright VO AAC encoder with a nice Java API. + +In addition, includes a patched [MP4Parser](http://code.google.com/p/mp4parser) Java library for wrapping AAC files in an MP4 container to produce M4A audio files playable by Google Chrome and Apple QuickTime. + +This project is set up as a single Eclipse project with a Main.java example activity. AAC encoding logic is found in jni/aac-enc.c, which needs to be built with the [Android NDK](http://developer.android.com/sdk/ndk/index.html). I used NDK r7c, but any version should work. + +Why? +---- + +- smaller code footprint than FFmpeg (< 500k compared to > 2M) +- less native code to compile = less work to support new architectures +- easiest way to make an M4A file + + +License +------- + +This project is released under the [Apache License, version 2](http://www.apache.org/licenses/LICENSE-2.0) + +Patents +------- + +This project grants you no rights to any of the patents this technology may require. However, since Android version 4.0 and up ship with the Stagefright VO AAC encoder, it is my understanding that you can release code that depends on these libraries for any version of Android. Please note that I am not a lawyer. + + +Have changes? +------------- + +Pull requests are accepted! \ No newline at end of file diff --git a/build.xml b/build.xml new file mode 100644 index 000000000..3bf2ba2f4 --- /dev/null +++ b/build.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jni/Android.mk b/jni/Android.mk new file mode 100644 index 000000000..46e25c4c4 --- /dev/null +++ b/jni/Android.mk @@ -0,0 +1,85 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +include $(LOCAL_PATH)/Config.mk + +LOCAL_MODULE := aac-encoder + +ENC_SRC := src + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/inc + +LOCAL_SRC_FILES = \ + aac-enc.c \ + $(ENC_SRC)/cmnMemory.c \ + basic_op/basicop2.c \ + basic_op/oper_32b.c \ + $(ENC_SRC)/aac_rom.c \ + $(ENC_SRC)/aacenc.c \ + $(ENC_SRC)/aacenc_core.c \ + $(ENC_SRC)/adj_thr.c \ + $(ENC_SRC)/band_nrg.c \ + $(ENC_SRC)/bit_cnt.c \ + $(ENC_SRC)/bitbuffer.c \ + $(ENC_SRC)/bitenc.c \ + $(ENC_SRC)/block_switch.c \ + $(ENC_SRC)/channel_map.c \ + $(ENC_SRC)/dyn_bits.c \ + $(ENC_SRC)/grp_data.c \ + $(ENC_SRC)/interface.c \ + $(ENC_SRC)/line_pe.c \ + $(ENC_SRC)/memalign.c \ + $(ENC_SRC)/ms_stereo.c \ + $(ENC_SRC)/pre_echo_control.c \ + $(ENC_SRC)/psy_configuration.c \ + $(ENC_SRC)/psy_main.c \ + $(ENC_SRC)/qc_main.c \ + $(ENC_SRC)/quantize.c \ + $(ENC_SRC)/sf_estim.c \ + $(ENC_SRC)/spreading.c \ + $(ENC_SRC)/stat_bits.c \ + $(ENC_SRC)/tns.c \ + $(ENC_SRC)/transform.c + +ifeq ($(VOTT), v5) +LOCAL_SRC_FILES += \ + $(ENC_SRC)/asm/ARMV5E/AutoCorrelation_v5.s \ + $(ENC_SRC)/asm/ARMV5E/band_nrg_v5.s \ + $(ENC_SRC)/asm/ARMV5E/CalcWindowEnergy_v5.s \ + $(ENC_SRC)/asm/ARMV5E/PrePostMDCT_v5.s \ + $(ENC_SRC)/asm/ARMV5E/R4R8First_v5.s \ + $(ENC_SRC)/asm/ARMV5E/Radix4FFT_v5.s +endif + +ifeq ($(VOTT), v7) +LOCAL_SRC_FILES += \ + $(ENC_SRC)/asm/ARMV5E/AutoCorrelation_v5.s \ + $(ENC_SRC)/asm/ARMV5E/band_nrg_v5.s \ + $(ENC_SRC)/asm/ARMV5E/CalcWindowEnergy_v5.s \ + $(ENC_SRC)/asm/ARMV7/PrePostMDCT_v7.s \ + $(ENC_SRC)/asm/ARMV7/R4R8First_v7.s \ + $(ENC_SRC)/asm/ARMV7/Radix4FFT_v7.s +endif + +LOCAL_ARM_MODE := arm + +LOCAL_LDLIBS := -llog + +LOCAL_STATIC_LIBRARIES := +LOCAL_SHARED_LIBRARIES := + +LOCAL_CFLAGS := $(VO_CFLAGS) + +ifeq ($(VOTT), v5) +LOCAL_CFLAGS += -DARMV5E -DARM_INASM -DARMV5_INASM +LOCAL_C_INCLUDES += $(ENC_SRC)/asm/ARMV5E +endif + +ifeq ($(VOTT), v7) +LOCAL_CFLAGS += -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM -DARMV6_INASM +LOCAL_C_INCLUDES += $(ENC_SRC)/asm/ARMV5E +LOCAL_C_INCLUDES += $(ENC_SRC)/asm/ARMV7 +endif + +include $(BUILD_SHARED_LIBRARY) + diff --git a/jni/Config.mk b/jni/Config.mk new file mode 100644 index 000000000..187f25cc1 --- /dev/null +++ b/jni/Config.mk @@ -0,0 +1,24 @@ +# +# This configure file is just for Linux projects against Android +# + +VOPRJ := +VONJ := + +# WARNING: +# Using v7 breaks generic build +ifeq ($(TARGET_ARCH),arm) +VOTT := v5 +else +VOTT := pc +endif + +# Do we also need to check on ARCH_ARM_HAVE_ARMV7A? - probably not +ifeq ($(ARCH_ARM_HAVE_NEON),true) +VOTT := v7 +endif + +VOTEST := 0 + +VO_CFLAGS:=-DLINUX + diff --git a/jni/aac-enc.c b/jni/aac-enc.c new file mode 100644 index 000000000..c2322b72f --- /dev/null +++ b/jni/aac-enc.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include +#include + +#define DEBUG 0 + +#if DEBUG +#define LOG(msg, args...) __android_log_print(ANDROID_LOG_ERROR, "aac-enc", msg, ## args) +#else +#define LOG(msg, args...) +#endif + +/* utility functions */ + +void throwException(JNIEnv* env, const char *name, const char *msg) +{ + jclass cls = (*env)->FindClass(env, name); + /* if cls is NULL, an exception has already been thrown */ + if (cls != NULL) { + (*env)->ThrowNew(env, cls, msg); + } + /* free the local ref */ + (*env)->DeleteLocalRef(env, cls); +} + +/* internal storage */ + +FILE* outfile; + +VO_AUDIO_CODECAPI codec_api; +VO_HANDLE handle = 0; +VO_AUDIO_CODECAPI codec_api = { 0 }; +VO_MEM_OPERATOR mem_operator = { 0 }; +VO_CODEC_INIT_USERDATA user_data; +AACENC_PARAM params = { 0 }; + +/* java native functions */ + +void +Java_com_todoroo_aacenc_AACEncoder_init( JNIEnv* env, + jobject thiz, + int bitrate, + int channels, + int sampleRate, + int bitsPerSample, + jstring outputFile) +{ + + if (bitsPerSample != 16) { + throwException(env, "java/lang/IllegalArgumentException", + "Unsupported sample depth. Only 16 bits per sample is supported"); + return; + } + + voGetAACEncAPI(&codec_api); + + mem_operator.Alloc = cmnMemAlloc; + mem_operator.Copy = cmnMemCopy; + mem_operator.Free = cmnMemFree; + mem_operator.Set = cmnMemSet; + mem_operator.Check = cmnMemCheck; + user_data.memflag = VO_IMF_USERMEMOPERATOR; + user_data.memData = &mem_operator; + codec_api.Init(&handle, VO_AUDIO_CodingAAC, &user_data); + + params.sampleRate = sampleRate; + params.bitRate = bitrate; + params.nChannels = channels; + params.adtsUsed = 1; + + if (codec_api.SetParam(handle, VO_PID_AAC_ENCPARAM, ¶ms) != VO_ERR_NONE) { + throwException(env, "java/lang/IllegalArgumentException", + "Unable to set encoding parameters"); + return; + } + + const char* output_file = (*env)->GetStringUTFChars(env, outputFile, (jboolean) 0); + outfile = fopen(output_file, "wb"); + LOG("writing to %s", output_file); + (*env)->ReleaseStringUTFChars(env, outputFile, output_file); + + LOG("initialized handle: %x", handle); + +} + +void +Java_com_todoroo_aacenc_AACEncoder_encode( JNIEnv* env, + jobject thiz, + jbyteArray inputArray) +{ + + LOG("writing to handle: %x", handle); + + jbyte* buffer = (*env)->GetByteArrayElements(env, inputArray, (jboolean) 0); + int inputSize = (*env)->GetArrayLength(env, inputArray); + + VO_CODECBUFFER input = { 0 }, output = { 0 }; + VO_AUDIO_OUTPUTINFO output_info = { 0 }; + + int readSize = params.nChannels * 2 * 1024; + uint16_t* outbuf = (uint16_t*) malloc(readSize * 2); + + LOG("input buffer: %d", inputSize); + + /* GET OUTPUT DATA */ + int i; + for(i = 0; i < inputSize; i += readSize) { + + input.Buffer = buffer + i; + input.Length = readSize; + codec_api.SetInputData(handle, &input); + + output.Buffer = outbuf; + output.Length = readSize * 2; + + int status = codec_api.GetOutputData(handle, &output, &output_info); + if (status == VO_ERR_INPUT_BUFFER_SMALL) + break; + + if (status == VO_ERR_OUTPUT_BUFFER_SMALL) { + LOG("output buffer was too small, read %d", output_info.InputUsed); + } else if (status != VO_ERR_NONE) { + char message[100]; + sprintf(message, "Unable to encode frame: %x", status); + throwException(env, "java/lang/RuntimeException", message); + return; + } + + fwrite(outbuf, 1, output.Length, outfile); + } + + LOG("finished output"); + (*env)->ReleaseByteArrayElements(env, inputArray, buffer, JNI_ABORT); + free(outbuf); +} + +void +Java_com_todoroo_aacenc_AACEncoder_uninit( JNIEnv* env, + jobject thiz) +{ + + fclose(outfile); + codec_api.Uninit(handle); + +} + +JNIEXPORT jint JNICALL +JNI_OnLoad (JavaVM * vm, void * reserved) +{ + return JNI_VERSION_1_6; +} diff --git a/jni/basic_op/basicop2.c b/jni/basic_op/basicop2.c new file mode 100644 index 000000000..d43bbd99e --- /dev/null +++ b/jni/basic_op/basicop2.c @@ -0,0 +1,1624 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: basicop2.c + + Content: Basic arithmetic operators. + +*******************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" + + +/*___________________________________________________________________________ + | | + | Functions | + |___________________________________________________________________________| +*/ + +/*___________________________________________________________________________ + | | + | Function Name : saturate | + | | + | Purpose : | + | | + | Limit the 32 bit input to the range of a 16 bit word. | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +#if (!SATRUATE_IS_INLINE) +Word16 saturate(Word32 L_var1) +{ + Word16 var_out; + + if (L_var1 > 0X00007fffL) + { + var_out = MAX_16; + } + else if (L_var1 < (Word32) 0xffff8000L) + { + var_out = MIN_16; + } + else + { + var_out = extract_l(L_var1); + } + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : add | + | | + | Purpose : | + | | + | Performs the addition (var1+var2) with overflow control and saturation;| + | the 16 bit result is set at +32767 when overflow occurs or at -32768 | + | when underflow occurs. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +#if (!ADD_IS_INLINE) +Word16 add (Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_sum; + + L_sum = (Word32)var1 + (Word32)var2; + var_out = saturate(L_sum); + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : sub | + | | + | Purpose : | + | | + | Performs the subtraction (var1+var2) with overflow control and satu- | + | ration; the 16 bit result is set at +32767 when overflow occurs or at | + | -32768 when underflow occurs. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +#if (!SUB_IS_INLINE) +Word16 sub(Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_diff; + + L_diff = (Word32) var1 - var2; + var_out = saturate(L_diff); + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : abs_s | + | | + | Purpose : | + | | + | Absolute value of var1; abs_s(-32768) = 32767. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +//Word16 abs_s (Word16 var1) +//{ +// Word16 var_out; +// +// if (var1 == MIN_16) +// { +// var_out = MAX_16; +// } +// else +// { +// if (var1 < 0) +// { +// var_out = (Word16)-var1; +// } +// else +// { +// var_out = var1; +// } +// } +// +// return (var_out); +//} + + +/*___________________________________________________________________________ + | | + | Function Name : shl | + | | + | Purpose : | + | | + | Arithmetically shift the 16 bit input var1 left var2 positions.Zero fill| + | the var2 LSB of the result. If var2 is negative, arithmetically shift | + | var1 right by -var2 with sign extension. Saturate the result in case of | + | underflows or overflows. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +#if (!SHL_IS_INLINE) +Word16 shl (Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 result; + + if (var2 < 0) + { + if (var2 < -16) + var2 = -16; + var_out = shr (var1, (Word16)-var2); + } + else + { + result = (Word32) var1 *((Word32) 1 << var2); + + if ((var2 > 15 && var1 != 0) || (result != (Word32) ((Word16) result))) + { + //Overflow = 1; + var_out = (Word16)((var1 > 0) ? MAX_16 : MIN_16); + } + else + { + var_out = extract_l(result); + } + } + + return (var_out); +} +#endif +// end + +/*___________________________________________________________________________ + | | + | Function Name : shr | + | | + | Purpose : | + | | + | Arithmetically shift the 16 bit input var1 right var2 positions with | + | sign extension. If var2 is negative, arithmetically shift var1 left by | + | -var2 with sign extension. Saturate the result in case of underflows or | + | overflows. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +#if (!SHR_IS_INLINE) +Word16 shr (Word16 var1, Word16 var2) +{ + Word16 var_out; + + if (var2 < 0) + { + if (var2 < -16) + var2 = -16; + var_out = shl (var1, (Word16)-var2); + } + else + { + if (var2 >= 15) + { + var_out = (Word16)((var1 < 0) ? -1 : 0); + } + else + { + if (var1 < 0) + { + var_out = (Word16)(~((~var1) >> var2)); + } + else + { + var_out = (Word16)(var1 >> var2); + } + } + } + + return (var_out); +} +#endif + + +/*___________________________________________________________________________ + | | + | Function Name : mult | + | | + | Purpose : | + | | + | Performs the multiplication of var1 by var2 and gives a 16 bit result | + | which is scaled i.e.: | + | mult(var1,var2) = extract_l(L_shr((var1 times var2),15)) and | + | mult(-32768,-32768) = 32767. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +#if (!MULT_IS_INLINE) +Word16 mult (Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_product; + + L_product = (Word32) var1 *(Word32) var2; + + L_product = (L_product & (Word32) 0xffff8000L) >> 15; + + if (L_product & (Word32) 0x00010000L) + L_product = L_product | (Word32) 0xffff0000L; + + var_out = saturate(L_product); + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : L_mult | + | | + | Purpose : | + | | + | L_mult is the 32 bit result of the multiplication of var1 times var2 | + | with one shift left i.e.: | + | L_mult(var1,var2) = L_shl((var1 times var2),1) and | + | L_mult(-32768,-32768) = 2147483647. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +#if (!L_MULT_IS_INLINE) +Word32 L_mult(Word16 var1, Word16 var2) +{ + Word32 L_var_out; + + L_var_out = (Word32) var1 *(Word32) var2; + + if (L_var_out != (Word32) 0x40000000L) + { + L_var_out <<= 1; + } + else + { + L_var_out = MAX_32; + } + + return (L_var_out); +} +#endif +// end + +/*___________________________________________________________________________ + | | + | Function Name : negate | + | | + | Purpose : | + | | + | Negate var1 with saturation, saturate in the case where input is -32768:| + | negate(var1) = sub(0,var1). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +//Word16 negate (Word16 var1) +//{ +// Word16 var_out; +// +// var_out = (Word16)((var1 == MIN_16) ? MAX_16 : -var1); +// +// return (var_out); +//} + + +/*___________________________________________________________________________ + | | + | Function Name : extract_h | + | | + | Purpose : | + | | + | Return the 16 MSB of L_var1. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32 ) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +#if (!EXTRACT_H_IS_INLINE) +Word16 extract_h (Word32 L_var1) +{ + Word16 var_out; + + var_out = (Word16) (L_var1 >> 16); + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : extract_l | + | | + | Purpose : | + | | + | Return the 16 LSB of L_var1. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32 ) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +#if (!EXTRACT_L_IS_INLINE) +Word16 extract_l(Word32 L_var1) +{ + Word16 var_out; + + var_out = (Word16) L_var1; + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : round | + | | + | Purpose : | + | | + | Round the lower 16 bits of the 32 bit input number into the MS 16 bits | + | with saturation. Shift the resulting bits right by 16 and return the 16 | + | bit number: | + | round(L_var1) = extract_h(L_add(L_var1,32768)) | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32 ) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +#if (!ROUND_IS_INLINE) +Word16 round16(Word32 L_var1) +{ + Word16 var_out; + Word32 L_rounded; + + L_rounded = L_add (L_var1, (Word32) 0x00008000L); + var_out = extract_h (L_rounded); + + return (var_out); +} +#endif +// end + +/*___________________________________________________________________________ + | | + | Function Name : L_mac | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Add the 32 bit | + | result to L_var3 with saturation, return a 32 bit result: | + | L_mac(L_var3,var1,var2) = L_add(L_var3,L_mult(var1,var2)). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +#if (!L_MSU_IS_INLINE) +Word32 L_mac (Word32 L_var3, Word16 var1, Word16 var2) +{ + Word32 L_var_out; + Word32 L_product; + + L_product = L_mult(var1, var2); + L_var_out = L_add (L_var3, L_product); + + return (L_var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : L_msu | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Subtract the 32 | + | bit result to L_var3 with saturation, return a 32 bit result: | + | L_msu(L_var3,var1,var2) = L_sub(L_var3,L_mult(var1,var2)). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +#if (!L_MSU_IS_INLINE) +Word32 L_msu (Word32 L_var3, Word16 var1, Word16 var2) +{ + Word32 L_var_out; + Word32 L_product; + + L_product = L_mult(var1, var2); + L_var_out = L_sub (L_var3, L_product); + + return (L_var_out); +} +#endif + + +/*___________________________________________________________________________ + | | + | Function Name : L_add | + | | + | Purpose : | + | | + | 32 bits addition of the two 32 bits variables (L_var1+L_var2) with | + | overflow control and saturation; the result is set at +2147483647 when | + | overflow occurs or at -2147483648 when underflow occurs. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | L_var2 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +#if (!L_ADD_IS_INLINE) +Word32 L_add (Word32 L_var1, Word32 L_var2) +{ + Word32 L_var_out; + + L_var_out = L_var1 + L_var2; + + if (((L_var1 ^ L_var2) & MIN_32) == 0) + { + if ((L_var_out ^ L_var1) & MIN_32) + { + L_var_out = (L_var1 < 0) ? MIN_32 : MAX_32; + //Overflow = 1; + } + } + + return (L_var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : L_sub | + | | + | Purpose : | + | | + | 32 bits subtraction of the two 32 bits variables (L_var1-L_var2) with | + | overflow control and saturation; the result is set at +2147483647 when | + | overflow occurs or at -2147483648 when underflow occurs. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | L_var2 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +#if (!L_SUB_IS_INLINE) +Word32 L_sub(Word32 L_var1, Word32 L_var2) +{ + Word32 L_var_out; + + L_var_out = L_var1 - L_var2; + + if (((L_var1 ^ L_var2) & MIN_32) != 0) + { + if ((L_var_out ^ L_var1) & MIN_32) + { + L_var_out = (L_var1 < 0L) ? MIN_32 : MAX_32; + //Overflow = 1; + } + } + + return (L_var_out); +} +#endif + + +/*___________________________________________________________________________ + | | + | Function Name : L_negate | + | | + | Purpose : | + | | + | Negate the 32 bit variable L_var1 with saturation; saturate in the case | + | where input is -2147483648 (0x8000 0000). | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +//Word32 L_negate (Word32 L_var1) +//{ +// Word32 L_var_out; +// +// L_var_out = (L_var1 == MIN_32) ? MAX_32 : -L_var1; +// +// return (L_var_out); +//} + + +/*___________________________________________________________________________ + | | + | Function Name : mult_r | + | | + | Purpose : | + | | + | Same as mult with rounding, i.e.: | + | mult_r(var1,var2) = extract_l(L_shr(((var1 * var2) + 16384),15)) and | + | mult_r(-32768,-32768) = 32767. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +#if (!MULT_R_IS_INLINE) +Word16 mult_r (Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_product_arr; + + L_product_arr = (Word32) var1 *(Word32) var2; /* product */ + L_product_arr += (Word32) 0x00004000L; /* round */ + L_product_arr &= (Word32) 0xffff8000L; + L_product_arr >>= 15; /* shift */ + + if (L_product_arr & (Word32) 0x00010000L) /* sign extend when necessary */ + { + L_product_arr |= (Word32) 0xffff0000L; + } + var_out = saturate(L_product_arr); + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : L_shl | + | | + | Purpose : | + | | + | Arithmetically shift the 32 bit input L_var1 left var2 positions. Zero | + | fill the var2 LSB of the result. If var2 is negative, arithmetically | + | shift L_var1 right by -var2 with sign extension. Saturate the result in | + | case of underflows or overflows. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +#if (!L_SHL_IS_INLINE) +Word32 L_shl (Word32 L_var1, Word16 var2) +{ + Word32 L_var_out = 0L; + + if (var2 <= 0) + { + L_var1 = L_shr(L_var1, (Word16)-var2); + } + else + { + for (; var2 > 0; var2--) + { + if (L_var1 > (Word32) 0X3fffffffL) + { + return MAX_32; + } + else + { + if (L_var1 < (Word32) 0xc0000000L) + { + return MIN_32; + } + } + L_var1 <<= 1; + } + } + return (L_var1); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : L_shr | + | | + | Purpose : | + | | + | Arithmetically shift the 32 bit input L_var1 right var2 positions with | + | sign extension. If var2 is negative, arithmetically shift L_var1 left | + | by -var2 and zero fill the -var2 LSB of the result. Saturate the result | + | in case of underflows or overflows. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +#if (!L_SHR_IS_INLINE) +Word32 L_shr (Word32 L_var1, Word16 var2) +{ + Word32 L_var_out; + + if (var2 < 0) + { + L_var_out = L_shl (L_var1, (Word16)-var2); + } + else + { + if (var2 >= 31) + { + L_var_out = (L_var1 < 0L) ? -1 : 0; + } + else + { + if (L_var1 < 0) + { + L_var_out = ~((~L_var1) >> var2); + } + else + { + L_var_out = L_var1 >> var2; + } + } + } + return (L_var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : shr_r | + | | + | Purpose : | + | | + | Same as shr(var1,var2) but with rounding. Saturate the result in case of| + | underflows or overflows : | + | - If var2 is greater than zero : | + | if (sub(shl(shr(var1,var2),1),shr(var1,sub(var2,1)))) | + | is equal to zero | + | then | + | shr_r(var1,var2) = shr(var1,var2) | + | else | + | shr_r(var1,var2) = add(shr(var1,var2),1) | + | - If var2 is less than or equal to zero : | + | shr_r(var1,var2) = shr(var1,var2). | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +#if (!SHR_R_IS_INLINE) +Word16 shr_r (Word16 var1, Word16 var2) +{ + Word16 var_out; + + if (var2 > 15) + { + var_out = 0; + } + else + { + var_out = shr (var1, var2); + + if (var2 > 0) + { + if ((var1 & ((Word16) 1 << (var2 - 1))) != 0) + { + var_out++; + } + } + } + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : mac_r | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Add the 32 bit | + | result to L_var3 with saturation. Round the LS 16 bits of the result | + | into the MS 16 bits with saturation and shift the result right by 16. | + | Return a 16 bit result. | + | mac_r(L_var3,var1,var2) = round(L_mac(L_var3,var1,var2)) | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 8000 <= L_var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +#if (!MAC_R_IS_INLINE) +Word16 mac_r (Word32 L_var3, Word16 var1, Word16 var2) +{ + Word16 var_out; + + L_var3 = L_mac (L_var3, var1, var2); + L_var3 = L_add (L_var3, (Word32) 0x00008000L); + var_out = extract_h (L_var3); + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : msu_r | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Subtract the 32 | + | bit result to L_var3 with saturation. Round the LS 16 bits of the res- | + | ult into the MS 16 bits with saturation and shift the result right by | + | 16. Return a 16 bit result. | + | msu_r(L_var3,var1,var2) = round(L_msu(L_var3,var1,var2)) | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 8000 <= L_var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +#if (!MSU_R_IS_INLINE) +Word16 msu_r (Word32 L_var3, Word16 var1, Word16 var2) +{ + Word16 var_out; + + L_var3 = L_msu (L_var3, var1, var2); + L_var3 = L_add (L_var3, (Word32) 0x00008000L); + var_out = extract_h (L_var3); + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : L_deposit_h | + | | + | Purpose : | + | | + | Deposit the 16 bit var1 into the 16 MS bits of the 32 bit output. The | + | 16 LS bits of the output are zeroed. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var_out <= 0x7fff 0000. | + |___________________________________________________________________________| +*/ +//Word32 L_deposit_h (Word16 var1) +//{ +// Word32 L_var_out; +// +// L_var_out = (Word32) var1 << 16; +// +// return (L_var_out); +//} + + +/*___________________________________________________________________________ + | | + | Function Name : L_deposit_l | + | | + | Purpose : | + | | + | Deposit the 16 bit var1 into the 16 LS bits of the 32 bit output. The | + | 16 MS bits of the output are sign extended. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0xFFFF 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +//Word32 L_deposit_l (Word16 var1) +//{ +// Word32 L_var_out; +// +// L_var_out = (Word32) var1; +// +// return (L_var_out); +//} + + +/*___________________________________________________________________________ + | | + | Function Name : L_shr_r | + | | + | Purpose : | + | | + | Same as L_shr(L_var1,var2) but with rounding. Saturate the result in | + | case of underflows or overflows : | + | - If var2 is greater than zero : | + | if (L_sub(L_shl(L_shr(L_var1,var2),1),L_shr(L_var1,sub(var2,1))))| + | is equal to zero | + | then | + | L_shr_r(L_var1,var2) = L_shr(L_var1,var2) | + | else | + | L_shr_r(L_var1,var2) = L_add(L_shr(L_var1,var2),1) | + | - If var2 is less than or equal to zero : | + | L_shr_r(L_var1,var2) = L_shr(L_var1,var2). | + | | + | Complexity weight : 3 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +#if (!L_SHR_R_IS_INLINE) +Word32 L_shr_r (Word32 L_var1, Word16 var2) +{ + Word32 L_var_out; + + if (var2 > 31) + { + L_var_out = 0; + } + else + { + L_var_out = L_shr (L_var1, var2); + + if (var2 > 0) + { + if ((L_var1 & ((Word32) 1 << (var2 - 1))) != 0) + { + L_var_out++; + } + } + } + + return (L_var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : L_abs | + | | + | Purpose : | + | | + | Absolute value of L_var1; Saturate in case where the input is | + | -214783648 | + | | + | Complexity weight : 3 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +//Word32 L_abs (Word32 L_var1) +//{ +// Word32 L_var_out; +// +// if (L_var1 == MIN_32) +// { +// L_var_out = MAX_32; +// } +// else +// { +// if (L_var1 < 0) +// { +// L_var_out = -L_var1; +// } +// else +// { +// L_var_out = L_var1; +// } +// } +// +// return (L_var_out); +//} + +/*___________________________________________________________________________ + | | + | Function Name : norm_s | + | | + | Purpose : | + | | + | Produces the number of left shift needed to normalize the 16 bit varia- | + | ble var1 for positive values on the interval with minimum of 16384 and | + | maximum of 32767, and for negative values on the interval with minimum | + | of -32768 and maximum of -16384; in order to normalize the result, the | + | following operation must be done : | + | norm_var1 = shl(var1,norm_s(var1)). | + | | + | Complexity weight : 15 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 000f. | + |___________________________________________________________________________| +*/ + +#if (!NORM_S_IS_INLINE) +Word16 norm_s (Word16 var1) +{ + Word16 var_out; + + if (var1 == 0) + { + var_out = 0; + } + else + { + if (var1 == -1) + { + var_out = 15; + } + else + { + if (var1 < 0) + { + var1 = (Word16)~var1; + } + for (var_out = 0; var1 < 0x4000; var_out++) + { + var1 <<= 1; + } + } + } + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : div_s | + | | + | Purpose : | + | | + | Produces a result which is the fractional integer division of var1 by | + | var2; var1 and var2 must be positive and var2 must be greater or equal | + | to var1; the result is positive (leading bit equal to 0) and truncated | + | to 16 bits. | + | If var1 = var2 then div(var1,var2) = 32767. | + | | + | Complexity weight : 18 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var1 <= var2 and var2 != 0. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : var1 <= var2 <= 0x0000 7fff and var2 != 0. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 7fff. | + | It's a Q15 value (point between b15 and b14). | + |___________________________________________________________________________| +*/ + +#if (!DIV_S_IS_INLINE) +Word16 div_s (Word16 var1, Word16 var2) +{ + Word16 var_out = 0; + Word16 iteration; + Word32 L_num; + Word32 L_denom; + + if (var1 == 0) + { + var_out = 0; + } + else + { + if (var1 == var2) + { + var_out = MAX_16; + } + else + { + L_num = L_deposit_l (var1); + L_denom = L_deposit_l (var2); + + for (iteration = 0; iteration < 15; iteration++) + { + var_out <<= 1; + L_num <<= 1; + + if (L_num >= L_denom) + { + L_num = L_sub(L_num, L_denom); + var_out = add (var_out, 1); + } + } + } + } + + return (var_out); +} +#endif + +/*___________________________________________________________________________ + | | + | Function Name : norm_l | + | | + | Purpose : | + | | + | Produces the number of left shifts needed to normalize the 32 bit varia-| + | ble L_var1 for positive values on the interval with minimum of | + | 1073741824 and maximum of 2147483647, and for negative values on the in-| + | terval with minimum of -2147483648 and maximum of -1073741824; in order | + | to normalize the result, the following operation must be done : | + | norm_L_var1 = L_shl(L_var1,norm_l(L_var1)). | + | | + | Complexity weight : 30 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 001f. | + |___________________________________________________________________________| +*/ + +#if (!NORM_L_IS_INLINE) +Word16 norm_l (Word32 L_var1) +{ + Word16 var_out; + + if (L_var1 == 0) + { + var_out = 0; + } + else + { + if (L_var1 == (Word32) 0xffffffffL) + { + var_out = 31; + } + else + { + if (L_var1 < 0) + { + L_var1 = ~L_var1; + } + for (var_out = 0; L_var1 < (Word32) 0x40000000L; var_out++) + { + L_var1 <<= 1; + } + } + } + + return (var_out); +} +#endif + diff --git a/jni/basic_op/oper_32b.c b/jni/basic_op/oper_32b.c new file mode 100644 index 000000000..982f4fd44 --- /dev/null +++ b/jni/basic_op/oper_32b.c @@ -0,0 +1,361 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: oper_32b.c + + Content: This file contains operations in double precision. + +*******************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" + +/***************************************************************************** + * * + * Function L_Extract() * + * * + * Extract from a 32 bit integer two 16 bit DPF. * + * * + * Arguments: * + * * + * L_32 : 32 bit integer. * + * 0x8000 0000 <= L_32 <= 0x7fff ffff. * + * hi : b16 to b31 of L_32 * + * lo : (L_32 - hi<<16)>>1 * + ***************************************************************************** +*/ + +void L_Extract (Word32 L_32, Word16 *hi, Word16 *lo) +{ + *hi = extract_h (L_32); + *lo = extract_l (L_msu (L_shr (L_32, 1), *hi, 16384)); + return; +} + +/***************************************************************************** + * * + * Function L_Comp() * + * * + * Compose from two 16 bit DPF a 32 bit integer. * + * * + * L_32 = hi<<16 + lo<<1 * + * * + * Arguments: * + * * + * hi msb * + * lo lsf (with sign) * + * * + * Return Value : * + * * + * 32 bit long signed integer (Word32) whose value falls in the * + * range : 0x8000 0000 <= L_32 <= 0x7fff fff0. * + * * + ***************************************************************************** +*/ + +Word32 L_Comp (Word16 hi, Word16 lo) +{ + Word32 L_32; + + L_32 = L_deposit_h (hi); + return (L_mac (L_32, lo, 1)); /* = hi<<16 + lo<<1 */ +} + +/***************************************************************************** + * Function Mpy_32() * + * * + * Multiply two 32 bit integers (DPF). The result is divided by 2**31 * + * * + * L_32 = (hi1*hi2)<<1 + ( (hi1*lo2)>>15 + (lo1*hi2)>>15 )<<1 * + * * + * This operation can also be viewed as the multiplication of two Q31 * + * number and the result is also in Q31. * + * * + * Arguments: * + * * + * hi1 hi part of first number * + * lo1 lo part of first number * + * hi2 hi part of second number * + * lo2 lo part of second number * + * * + ***************************************************************************** +*/ + +Word32 Mpy_32 (Word16 hi1, Word16 lo1, Word16 hi2, Word16 lo2) +{ + Word32 L_32; + + L_32 = L_mult (hi1, hi2); + L_32 = L_mac (L_32, mult (hi1, lo2), 1); + L_32 = L_mac (L_32, mult (lo1, hi2), 1); + + return (L_32); +} + +/***************************************************************************** + * Function Mpy_32_16() * + * * + * Multiply a 16 bit integer by a 32 bit (DPF). The result is divided * + * by 2**15 * + * * + * * + * L_32 = (hi1*lo2)<<1 + ((lo1*lo2)>>15)<<1 * + * * + * Arguments: * + * * + * hi hi part of 32 bit number. * + * lo lo part of 32 bit number. * + * n 16 bit number. * + * * + ***************************************************************************** +*/ + +Word32 Mpy_32_16 (Word16 hi, Word16 lo, Word16 n) +{ + Word32 L_32; + + L_32 = L_mult (hi, n); + L_32 = L_mac (L_32, mult (lo, n), 1); + + return (L_32); +} + +/***************************************************************************** + * * + * Function Name : Div_32 * + * * + * Purpose : * + * Fractional integer division of two 32 bit numbers. * + * L_num / L_denom. * + * L_num and L_denom must be positive and L_num < L_denom. * + * L_denom = denom_hi<<16 + denom_lo<<1 * + * denom_hi is a normalize number. * + * * + * Inputs : * + * * + * L_num * + * 32 bit long signed integer (Word32) whose value falls in the * + * range : 0x0000 0000 < L_num < L_denom * + * * + * L_denom = denom_hi<<16 + denom_lo<<1 (DPF) * + * * + * denom_hi * + * 16 bit positive normalized integer whose value falls in the * + * range : 0x4000 < hi < 0x7fff * + * denom_lo * + * 16 bit positive integer whose value falls in the * + * range : 0 < lo < 0x7fff * + * * + * Return Value : * + * * + * L_div * + * 32 bit long signed integer (Word32) whose value falls in the * + * range : 0x0000 0000 <= L_div <= 0x7fff ffff. * + * * + * Algorithm: * + * * + * - find = 1/L_denom. * + * First approximation: approx = 1 / denom_hi * + * 1/L_denom = approx * (2.0 - L_denom * approx ) * + * * + * - result = L_num * (1/L_denom) * + ***************************************************************************** +*/ + +Word32 Div_32 (Word32 L_num, Word32 denom) +{ + Word16 approx; + Word32 L_32; + /* First approximation: 1 / L_denom = 1/denom_hi */ + + approx = div_s ((Word16) 0x3fff, denom >> 16); + + /* 1/L_denom = approx * (2.0 - L_denom * approx) */ + + L_32 = L_mpy_ls (denom, approx); + + L_32 = L_sub ((Word32) 0x7fffffffL, L_32); + + L_32 = L_mpy_ls (L_32, approx); + /* L_num * (1/L_denom) */ + + L_32 = MULHIGH(L_32, L_num); + L_32 = L_shl (L_32, 3); + + return (L_32); +} + +/*! + + \brief calculates the log dualis times 4 of argument + iLog4(x) = (Word32)(4 * log(value)/log(2.0)) + + \return ilog4 value + +*/ +Word16 iLog4(Word32 value) +{ + Word16 iLog4; + + if(value != 0){ + Word32 tmp; + Word16 tmp16; + iLog4 = norm_l(value); + tmp = (value << iLog4); + tmp16 = round16(tmp); + tmp = L_mult(tmp16, tmp16); + tmp16 = round16(tmp); + tmp = L_mult(tmp16, tmp16); + tmp16 = round16(tmp); + + iLog4 = (-(iLog4 << 2) - norm_s(tmp16)) - 1; + } + else { + iLog4 = -128; /* -(INT_BITS*4); */ + } + + return iLog4; +} + +#define step(shift) \ + if ((0x40000000l >> shift) + root <= value) \ + { \ + value -= (0x40000000l >> shift) + root; \ + root = (root >> 1) | (0x40000000l >> shift); \ + } else { \ + root = root >> 1; \ + } + +Word32 rsqrt(Word32 value, /*!< Operand to square root (0.0 ... 1) */ + Word32 accuracy) /*!< Number of valid bits that will be calculated */ +{ + Word32 root = 0; + Word32 scale; + + if(value < 0) + return 0; + + scale = norm_l(value); + if(scale & 1) scale--; + + value <<= scale; + + step( 0); step( 2); step( 4); step( 6); + step( 8); step(10); step(12); step(14); + step(16); step(18); step(20); step(22); + step(24); step(26); step(28); step(30); + + scale >>= 1; + if (root < value) + ++root; + + root >>= scale; + return root* 46334; +} + +static const Word32 pow2Table[POW2_TABLE_SIZE] = { +0x7fffffff, 0x7fa765ad, 0x7f4f08ae, 0x7ef6e8da, +0x7e9f0606, 0x7e476009, 0x7deff6b6, 0x7d98c9e6, +0x7d41d96e, 0x7ceb2523, 0x7c94acde, 0x7c3e7073, +0x7be86fb9, 0x7b92aa88, 0x7b3d20b6, 0x7ae7d21a, +0x7a92be8b, 0x7a3de5df, 0x79e947ef, 0x7994e492, +0x7940bb9e, 0x78ecccec, 0x78991854, 0x78459dac, +0x77f25cce, 0x779f5591, 0x774c87cc, 0x76f9f359, +0x76a7980f, 0x765575c8, 0x76038c5b, 0x75b1dba2, +0x75606374, 0x750f23ab, 0x74be1c20, 0x746d4cac, +0x741cb528, 0x73cc556d, 0x737c2d55, 0x732c3cba, +0x72dc8374, 0x728d015d, 0x723db650, 0x71eea226, +0x719fc4b9, 0x71511de4, 0x7102ad80, 0x70b47368, +0x70666f76, 0x7018a185, 0x6fcb096f, 0x6f7da710, +0x6f307a41, 0x6ee382de, 0x6e96c0c3, 0x6e4a33c9, +0x6dfddbcc, 0x6db1b8a8, 0x6d65ca38, 0x6d1a1057, +0x6cce8ae1, 0x6c8339b2, 0x6c381ca6, 0x6bed3398, +0x6ba27e66, 0x6b57fce9, 0x6b0daeff, 0x6ac39485, +0x6a79ad56, 0x6a2ff94f, 0x69e6784d, 0x699d2a2c, +0x69540ec9, 0x690b2601, 0x68c26fb1, 0x6879ebb6, +0x683199ed, 0x67e97a34, 0x67a18c68, 0x6759d065, +0x6712460b, 0x66caed35, 0x6683c5c3, 0x663ccf92, +0x65f60a80, 0x65af766a, 0x6569132f, 0x6522e0ad, +0x64dcdec3, 0x64970d4f, 0x64516c2e, 0x640bfb41, +0x63c6ba64, 0x6381a978, 0x633cc85b, 0x62f816eb, +0x62b39509, 0x626f4292, 0x622b1f66, 0x61e72b65, +0x61a3666d, 0x615fd05f, 0x611c6919, 0x60d9307b, +0x60962665, 0x60534ab7, 0x60109d51, 0x5fce1e12, +0x5f8bccdb, 0x5f49a98c, 0x5f07b405, 0x5ec5ec26, +0x5e8451d0, 0x5e42e4e3, 0x5e01a540, 0x5dc092c7, +0x5d7fad59, 0x5d3ef4d7, 0x5cfe6923, 0x5cbe0a1c, +0x5c7dd7a4, 0x5c3dd19c, 0x5bfdf7e5, 0x5bbe4a61, +0x5b7ec8f2, 0x5b3f7377, 0x5b0049d4, 0x5ac14bea, +0x5a82799a, 0x5a43d2c6, 0x5a055751, 0x59c7071c, +0x5988e209, 0x594ae7fb, 0x590d18d3, 0x58cf7474, +0x5891fac1, 0x5854ab9b, 0x581786e6, 0x57da8c83, +0x579dbc57, 0x57611642, 0x57249a29, 0x56e847ef, +0x56ac1f75, 0x567020a0, 0x56344b52, 0x55f89f70, +0x55bd1cdb, 0x5581c378, 0x55469329, 0x550b8bd4, +0x54d0ad5b, 0x5495f7a1, 0x545b6a8b, 0x542105fd, +0x53e6c9db, 0x53acb607, 0x5372ca68, 0x533906e0, +0x52ff6b55, 0x52c5f7aa, 0x528cabc3, 0x52538786, +0x521a8ad7, 0x51e1b59a, 0x51a907b4, 0x5170810b, +0x51382182, 0x50ffe8fe, 0x50c7d765, 0x508fec9c, +0x50582888, 0x50208b0e, 0x4fe91413, 0x4fb1c37c, +0x4f7a9930, 0x4f439514, 0x4f0cb70c, 0x4ed5ff00, +0x4e9f6cd4, 0x4e69006e, 0x4e32b9b4, 0x4dfc988c, +0x4dc69cdd, 0x4d90c68b, 0x4d5b157e, 0x4d25899c, +0x4cf022ca, 0x4cbae0ef, 0x4c85c3f1, 0x4c50cbb8, +0x4c1bf829, 0x4be7492b, 0x4bb2bea5, 0x4b7e587d, +0x4b4a169c, 0x4b15f8e6, 0x4ae1ff43, 0x4aae299b, +0x4a7a77d5, 0x4a46e9d6, 0x4a137f88, 0x49e038d0, +0x49ad1598, 0x497a15c4, 0x4947393f, 0x49147fee, +0x48e1e9ba, 0x48af768a, 0x487d2646, 0x484af8d6, +0x4818ee22, 0x47e70611, 0x47b5408c, 0x47839d7b, +0x47521cc6, 0x4720be55, 0x46ef8210, 0x46be67e0, +0x468d6fae, 0x465c9961, 0x462be4e2, 0x45fb521a, +0x45cae0f2, 0x459a9152, 0x456a6323, 0x453a564d, +0x450a6abb, 0x44daa054, 0x44aaf702, 0x447b6ead, +0x444c0740, 0x441cc0a3, 0x43ed9ac0, 0x43be9580, +0x438fb0cb, 0x4360ec8d, 0x433248ae, 0x4303c517, +0x42d561b4, 0x42a71e6c, 0x4278fb2b, 0x424af7da, +0x421d1462, 0x41ef50ae, 0x41c1aca8, 0x41942839, +0x4166c34c, 0x41397dcc, 0x410c57a2, 0x40df50b8, +0x40b268fa, 0x4085a051, 0x4058f6a8, 0x402c6be9 +}; + +/*! + + \brief calculates 2 ^ (x/y) for x<=0, y > 0, x <= 32768 * y + + avoids integer division + + \return +*/ +Word32 pow2_xy(Word32 x, Word32 y) +{ + Word32 iPart; + Word32 fPart; + Word32 res; + Word32 tmp, tmp2; + Word32 shift, shift2; + + tmp2 = -x; + iPart = tmp2 / y; + fPart = tmp2 - iPart*y; + iPart = min(iPart,INT_BITS-1); + + res = pow2Table[(POW2_TABLE_SIZE*fPart)/y] >> iPart; + + return(res); +} diff --git a/jni/doc/voAACEncoderSDK.pdf b/jni/doc/voAACEncoderSDK.pdf new file mode 100644 index 0000000000000000000000000000000000000000..874d0f7fc267bf8b0536dab24e366089c54ecbbd GIT binary patch literal 160899 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%0DIC~C|m*3 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 WBUSCKp^x}>J6v(-@J9Tp`2PYxNa^$d literal 0 HcmV?d00001 diff --git a/jni/inc/aac_rom.h b/jni/inc/aac_rom.h new file mode 100644 index 000000000..8e206b7fb --- /dev/null +++ b/jni/inc/aac_rom.h @@ -0,0 +1,117 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: aac_rom.h + + Content: constant tables + +*******************************************************************************/ + +#ifndef ROM_H +#define ROM_H + +#include "config.h" +#include "psy_const.h" +#include "tns_param.h" + +/* + mdct +*/ +extern const int ShortWindowSine[FRAME_LEN_SHORT/2]; +extern const int LongWindowKBD[FRAME_LEN_LONG/2]; + +extern const unsigned char bitrevTab[17 + 129]; +extern const int cossintab[128 + 1024]; + +#if defined (ARMV5E) && !defined (ARMV7Neon) +extern const int twidTab64[(4*6 + 16*6)/2]; +extern const int twidTab512[(8*6 + 32*6 + 128*6)/2]; +#else +extern const int twidTab64[4*6 + 16*6]; +extern const int twidTab512[8*6 + 32*6 + 128*6]; +#endif + +/* + form factor +*/ +extern const Word32 formfac_sqrttable[96]; + +/* + quantizer +*/ +extern const Word32 mTab_3_4[512]; +extern const Word32 mTab_4_3[512]; +/*! $2^{-\frac{n}{16}}$ table */ +extern const Word16 pow2tominusNover16[17] ; + +extern Word32 specExpMantTableComb_enc[4][14]; +extern const UWord8 specExpTableComb_enc[4][14]; + +extern const Word16 quantBorders[4][4]; +//extern const Word16 quantRecon[3][4]; +extern const Word16 quantRecon[4][3]; + +/* + huffman +*/ +extern const UWord16 huff_ltab1_2[3][3][3][3]; +extern const UWord16 huff_ltab3_4[3][3][3][3]; +extern const UWord16 huff_ltab5_6[9][9]; +extern const UWord16 huff_ltab7_8[8][8]; +extern const UWord16 huff_ltab9_10[13][13]; +extern const UWord16 huff_ltab11[17][17]; +extern const UWord16 huff_ltabscf[121]; +extern const UWord16 huff_ctab1[3][3][3][3]; +extern const UWord16 huff_ctab2[3][3][3][3]; +extern const UWord16 huff_ctab3[3][3][3][3]; +extern const UWord16 huff_ctab4[3][3][3][3]; +extern const UWord16 huff_ctab5[9][9]; +extern const UWord16 huff_ctab6[9][9]; +extern const UWord16 huff_ctab7[8][8]; +extern const UWord16 huff_ctab8[8][8]; +extern const UWord16 huff_ctab9[13][13]; +extern const UWord16 huff_ctab10[13][13]; +extern const UWord16 huff_ctab11[17][17]; +extern const UWord32 huff_ctabscf[121]; + + + +/* + misc +*/ +extern const int sampRateTab[NUM_SAMPLE_RATES]; +extern const int BandwithCoefTab[8][NUM_SAMPLE_RATES]; +extern const int rates[8]; +extern const UWord8 sfBandTotalShort[NUM_SAMPLE_RATES]; +extern const UWord8 sfBandTotalLong[NUM_SAMPLE_RATES]; +extern const int sfBandTabShortOffset[NUM_SAMPLE_RATES]; +extern const short sfBandTabShort[76]; +extern const int sfBandTabLongOffset[NUM_SAMPLE_RATES]; +extern const short sfBandTabLong[325]; + +extern const Word32 m_log2_table[INT_BITS]; + +/* + TNS +*/ +extern const Word32 tnsCoeff3[8]; +extern const Word32 tnsCoeff3Borders[8]; +extern const Word32 tnsCoeff4[16]; +extern const Word32 tnsCoeff4Borders[16]; +extern const Word32 invSBF[24]; +extern const Word16 sideInfoTabLong[MAX_SFB_LONG + 1]; +extern const Word16 sideInfoTabShort[MAX_SFB_SHORT + 1]; +#endif diff --git a/jni/inc/aacenc_core.h b/jni/inc/aacenc_core.h new file mode 100644 index 000000000..bb75b6dc4 --- /dev/null +++ b/jni/inc/aacenc_core.h @@ -0,0 +1,117 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: aacenc_core.h + + Content: aac encoder interface functions + +*******************************************************************************/ + +#ifndef _aacenc_core_h_ +#define _aacenc_core_h_ + + +#include "typedef.h" +#include "config.h" +#include "bitenc.h" + +#include "psy_configuration.h" +#include "psy_main.h" +#include "qc_main.h" +#include "psy_main.h" +/*-------------------------- defines --------------------------------------*/ + + +/*-------------------- structure definitions ------------------------------*/ +typedef struct { + Word32 sampleRate; /* audio file sample rate */ + Word32 bitRate; /* encoder bit rate in bits/sec */ + Word16 nChannelsIn; /* number of channels on input (1,2) */ + Word16 nChannelsOut; /* number of channels on output (1,2) */ + Word16 bandWidth; /* targeted audio bandwidth in Hz */ + Word16 adtsUsed; /* whether write adts header */ +} AACENC_CONFIG; + + +typedef struct { + + AACENC_CONFIG config; /* Word16 size: 8 */ + + ELEMENT_INFO elInfo; /* Word16 size: 4 */ + + QC_STATE qcKernel; /* Word16 size: 6 + 5(PADDING) + 7(ELEMENT_BITS) + 54(ADJ_THR_STATE) = 72 */ + QC_OUT qcOut; /* Word16 size: MAX_CHANNELS*920(QC_OUT_CHANNEL) + 5(QC_OUT_ELEMENT) + 7 = 932 / 1852 */ + + PSY_OUT psyOut; /* Word16 size: MAX_CHANNELS*186 + 2 = 188 / 374 */ + PSY_KERNEL psyKernel; /* Word16 size: 2587 / 4491 */ + + struct BITSTREAMENCODER_INIT bseInit; /* Word16 size: 6 */ + struct BIT_BUF bitStream; /* Word16 size: 8 */ + HANDLE_BIT_BUF hBitStream; + int initOK; + + short *intbuf; + short *encbuf; + short *inbuf; + int enclen; + int inlen; + int intlen; + int uselength; + + void *hCheck; + VO_MEM_OPERATOR *voMemop; + VO_MEM_OPERATOR voMemoprator; + +}AAC_ENCODER; /* Word16 size: 3809 / 6851 */ + +/*----------------------------------------------------------------------------- + +functionname: AacInitDefaultConfig +description: gives reasonable default configuration +returns: --- + +------------------------------------------------------------------------------*/ +void AacInitDefaultConfig(AACENC_CONFIG *config); + +/*--------------------------------------------------------------------------- + +functionname:AacEncOpen +description: allocate and initialize a new encoder instance +returns: AACENC_OK if success + +---------------------------------------------------------------------------*/ + +Word16 AacEncOpen (AAC_ENCODER *hAacEnc, /* pointer to an encoder handle, initialized on return */ + const AACENC_CONFIG config); /* pre-initialized config struct */ + +Word16 AacEncEncode(AAC_ENCODER *hAacEnc, + Word16 *timeSignal, + const UWord8 *ancBytes, /*!< pointer to ancillary data bytes */ + Word16 *numAncBytes, /*!< number of ancillary Data Bytes, send as fill element */ + UWord8 *outBytes, /*!< pointer to output buffer */ + VO_U32 *numOutBytes /*!< number of bytes in output buffer */ + ); + +/*--------------------------------------------------------------------------- + +functionname:AacEncClose +description: deallocate an encoder instance + +---------------------------------------------------------------------------*/ + +void AacEncClose (AAC_ENCODER* hAacEnc, VO_MEM_OPERATOR *pMemOP); /* an encoder handle */ + +#endif /* _aacenc_h_ */ diff --git a/jni/inc/adj_thr.h b/jni/inc/adj_thr.h new file mode 100644 index 000000000..0f4bb5e6c --- /dev/null +++ b/jni/inc/adj_thr.h @@ -0,0 +1,57 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: adj_thr.h + + Content: Threshold compensation function + +*******************************************************************************/ + +#ifndef __ADJ_THR_H +#define __ADJ_THR_H + +#include "adj_thr_data.h" +#include "qc_data.h" +#include "interface.h" + +Word16 bits2pe(const Word16 bits); + +Word32 AdjThrNew(ADJ_THR_STATE** phAdjThr, + Word32 nElements); + +void AdjThrDelete(ADJ_THR_STATE *hAdjThr); + +void AdjThrInit(ADJ_THR_STATE *hAdjThr, + const Word32 peMean, + Word32 chBitrate); + +void AdjustThresholds(ADJ_THR_STATE *adjThrState, + ATS_ELEMENT* AdjThrStateElement, + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + PSY_OUT_ELEMENT *psyOutElement, + Word16 *chBitDistribution, + Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], + Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB], + QC_OUT_ELEMENT* qcOE, + ELEMENT_BITS* elBits, + const Word16 nChannels, + const Word16 maxBitFac); + +void AdjThrUpdate(ATS_ELEMENT *AdjThrStateElement, + const Word16 dynBitsUsed); + + +#endif diff --git a/jni/inc/adj_thr_data.h b/jni/inc/adj_thr_data.h new file mode 100644 index 000000000..30132d854 --- /dev/null +++ b/jni/inc/adj_thr_data.h @@ -0,0 +1,69 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: adj_thr_data.h + + Content: Threshold compensation parameter + +*******************************************************************************/ + +#ifndef __ADJ_THR_DATA_H +#define __ADJ_THR_DATA_H + +#include "typedef.h" +#include "psy_const.h" +#include "line_pe.h" + +typedef struct { + Word16 clipSaveLow, clipSaveHigh; + Word16 minBitSave, maxBitSave; + Word16 clipSpendLow, clipSpendHigh; + Word16 minBitSpend, maxBitSpend; +} BRES_PARAM; + +typedef struct { + UWord8 modifyMinSnr; + Word16 startSfbL, startSfbS; +} AH_PARAM; + +typedef struct { + Word32 maxRed; + Word32 startRatio, maxRatio; + Word32 redRatioFac; + Word32 redOffs; +} MINSNR_ADAPT_PARAM; + +typedef struct { + /* parameters for bitreservoir control */ + Word16 peMin, peMax; + /* constant offset to pe */ + Word16 peOffset; + /* avoid hole parameters */ + AH_PARAM ahParam; + /* paramters for adaptation of minSnr */ + MINSNR_ADAPT_PARAM minSnrAdaptParam; + /* values for correction of pe */ + Word16 peLast; + Word16 dynBitsLast; + Word16 peCorrectionFactor; +} ATS_ELEMENT; + +typedef struct { + BRES_PARAM bresParamLong, bresParamShort; /* Word16 size: 2*8 */ + ATS_ELEMENT adjThrStateElem; /* Word16 size: 19 */ +} ADJ_THR_STATE; + +#endif diff --git a/jni/inc/band_nrg.h b/jni/inc/band_nrg.h new file mode 100644 index 000000000..65453c0a3 --- /dev/null +++ b/jni/inc/band_nrg.h @@ -0,0 +1,46 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: band_nrg.h + + Content: Band/Line energy calculations functions + +*******************************************************************************/ + + +#ifndef _BAND_NRG_H +#define _BAND_NRG_H + +#include "typedef.h" + + +void CalcBandEnergy(const Word32 *mdctSpectrum, + const Word16 *bandOffset, + const Word16 numBands, + Word32 *bandEnergy, + Word32 *bandEnergySum); + + +void CalcBandEnergyMS(const Word32 *mdctSpectrumLeft, + const Word32 *mdctSpectrumRight, + const Word16 *bandOffset, + const Word16 numBands, + Word32 *bandEnergyMid, + Word32 *bandEnergyMidSum, + Word32 *bandEnergySide, + Word32 *bandEnergySideSum); + +#endif diff --git a/jni/inc/basic_op.h b/jni/inc/basic_op.h new file mode 100644 index 000000000..0755eb7a7 --- /dev/null +++ b/jni/inc/basic_op.h @@ -0,0 +1,1171 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: basicop2.h + + Content: Constants , Globals and Basic arithmetic operators. + +*******************************************************************************/ + +#ifndef __BASIC_OP_H +#define __BASIC_OP_H + +#include "typedef.h" + +#define MAX_32 (Word32)0x7fffffffL +#define MIN_32 (Word32)0x80000000L + +#define MAX_16 (Word16)0x7fff +#define MIN_16 (Word16)0x8000 +#define ABS(a) ((a) >= 0) ? (a) : (-(a)) + +/* Short abs, 1 */ +#define abs_s(x) (((x) != MIN_16) ? (((x) >= 0) ? (x) : (-(x))) : MAX_16) + +/* 16 bit var1 -> MSB, 2 */ +#define L_deposit_h(x) (((Word32)(x)) << 16) + + +/* 16 bit var1 -> LSB, 2 */ +#define L_deposit_l(x) ((Word32)(x)) + + +/* Long abs, 3 */ +#define L_abs(x) (((x) != MIN_32) ? (((x) >= 0) ? (x) : (-(x))) : MAX_32) + + +/* Short negate, 1 */ +#define negate(var1) (((var1) == MIN_16) ? MAX_16 : (-(var1))) + + +/* Long negate, 2 */ +#define L_negate(L_var1) (((L_var1) == (MIN_32)) ? (MAX_32) : (-(L_var1))) + + +#define MULHIGH(A,B) (int)(((Word64)(A)*(Word64)(B)) >> 32) +#define fixmul(a, b) (int)((((Word64)(a)*(Word64)(b)) >> 32) << 1) + + +#if (SATRUATE_IS_INLINE) +__inline Word32 saturate(Word32 L_var1); +#else +Word16 saturate(Word32 L_var1); +#endif + +/* Short shift left, 1 */ +#if (SHL_IS_INLINE) +__inline Word32 shl (Word32 var1, Word32 var2); +#else +Word16 shl (Word16 var1, Word16 var2); +#endif + +/* Short shift right, 1 */ +#if (SHR_IS_INLINE) +__inline Word32 shr (Word32 var1, Word32 var2); +#else +Word16 shr (Word16 var1, Word16 var2); +#endif + +#if (L_MULT_IS_INLINE) +__inline Word32 L_mult(Word32 var1, Word32 var2); +#else +Word32 L_mult(Word16 var1, Word16 var2); +#endif + +/* Msu, 1 */ +#if (L_MSU_IS_INLINE) +__inline Word32 L_msu (Word32 L_var3, Word32 var1, Word32 var2); +#else +Word32 L_msu (Word32 L_var3, Word16 var1, Word16 var2); +#endif + +/* Long sub, 2 */ +#if (L_SUB_IS_INLINE) +__inline Word32 L_sub(Word32 L_var1, Word32 L_var2); +#else +Word32 L_sub(Word32 L_var1, Word32 L_var2); +#endif + +/* Long shift left, 2 */ +#if (L_SHL_IS_INLINE) +__inline Word32 L_shl (Word32 L_var1, Word32 var2); +#else +Word32 L_shl (Word32 L_var1, Word16 var2); +#endif + +/* Long shift right, 2*/ +#if (L_SHR_IS_INLINE) +__inline Word32 L_shr (Word32 L_var1, Word32 var2); +#else +Word32 L_shr (Word32 L_var1, Word16 var2); +#endif + +/* Short add, 1 */ +#if (ADD_IS_INLINE) +__inline Word32 add (Word32 var1, Word32 var2); +#else +Word16 add (Word16 var1, Word16 var2); +#endif + +/* Short sub, 1 */ +#if (SUB_IS_INLINE) +__inline Word32 sub(Word32 var1, Word32 var2); +#else +Word16 sub(Word16 var1, Word16 var2); +#endif + +/* Short division, 18 */ +#if (DIV_S_IS_INLINE) +__inline Word32 div_s (Word32 var1, Word32 var2); +#else +Word16 div_s (Word16 var1, Word16 var2); +#endif + +/* Short mult, 1 */ +#if (MULT_IS_INLINE) +__inline Word32 mult (Word32 var1, Word32 var2); +#else +Word16 mult (Word16 var1, Word16 var2); +#endif + +/* Short norm, 15 */ +#if (NORM_S_IS_INLINE) +__inline Word32 norm_s (Word32 var1); +#else +Word16 norm_s (Word16 var1); +#endif + +/* Long norm, 30 */ +#if (NORM_L_IS_INLINE) +__inline Word32 norm_l (Word32 L_var1); +#else +Word16 norm_l (Word32 L_var1); +#endif + +/* Round, 1 */ +#if (ROUND_IS_INLINE) +__inline Word32 round16(Word32 L_var1); +#else +Word16 round16(Word32 L_var1); +#endif + +/* Mac, 1 */ +#if (L_MAC_IS_INLINE) +__inline Word32 L_mac (Word32 L_var3, Word32 var1, Word32 var2); +#else +Word32 L_mac (Word32 L_var3, Word16 var1, Word16 var2); +#endif + +#if (L_ADD_IS_INLINE) +__inline Word32 L_add (Word32 L_var1, Word32 L_var2); +#else +Word32 L_add (Word32 L_var1, Word32 L_var2); +#endif + +/* Extract high, 1 */ +#if (EXTRACT_H_IS_INLINE) +__inline Word32 extract_h (Word32 L_var1); +#else +Word16 extract_h (Word32 L_var1); +#endif + +/* Extract low, 1 */ +#if (EXTRACT_L_IS_INLINE) +__inline Word32 extract_l(Word32 L_var1); +#else +Word16 extract_l(Word32 L_var1); +#endif + +/* Mult with round, 2 */ +#if (MULT_R_IS_INLINE) +__inline Word32 mult_r(Word32 var1, Word32 var2); +#else +Word16 mult_r(Word16 var1, Word16 var2); +#endif + +/* Shift right with round, 2 */ +#if (SHR_R_IS_INLINE) +__inline Word32 shr_r (Word32 var1, Word32 var2); +#else +Word16 shr_r (Word16 var1, Word16 var2); +#endif + +/* Mac with rounding,2 */ +#if (MAC_R_IS_INLINE) +__inline Word32 mac_r (Word32 L_var3, Word32 var1, Word32 var2); +#else +Word16 mac_r (Word32 L_var3, Word16 var1, Word16 var2); +#endif + +/* Msu with rounding,2 */ +#if (MSU_R_IS_INLINE) +__inline Word32 msu_r (Word32 L_var3, Word32 var1, Word32 var2); +#else +Word16 msu_r (Word32 L_var3, Word16 var1, Word16 var2); +#endif + +/* Long shift right with round, 3 */ +#if (L_SHR_R_IS_INLINE) +__inline Word32 L_shr_r (Word32 L_var1, Word32 var2); +#else +Word32 L_shr_r (Word32 L_var1, Word16 var2); +#endif + +#if ARMV4_INASM +__inline Word32 ASM_L_shr(Word32 L_var1, Word32 var2) +{ + return L_var1 >> var2; +} + +__inline Word32 ASM_L_shl(Word32 L_var1, Word32 var2) +{ + Word32 result; + asm ( + "MOV %[result], %[L_var1], ASL %[var2] \n" + "TEQ %[L_var1], %[result], ASR %[var2]\n" + "EORNE %[result], %[mask], %[L_var1], ASR #31\n" + :[result]"=&r"(result) + :[L_var1]"r"(L_var1), [var2]"r"(var2), [mask]"r"(0x7fffffff) + ); + return result; +} + +__inline Word32 ASM_shr(Word32 L_var1, Word32 var2) +{ + Word32 result; + asm ( + "CMP %[var2], #15\n" + "MOVLT %[result], %[L_var1], ASR %[var2]\n" + "MOVGE %[result], %[L_var1], ASR #15\n" + :[result]"=r"(result) + :[L_var1]"r"(L_var1), [var2]"r"(var2) + ); + return result; +} + +__inline Word32 ASM_shl(Word32 L_var1, Word32 var2) +{ +#if ARMV6_SAT + Word32 result; + asm ( + "CMP %[var2], #16\n" + "MOVLT %[result], %[L_var1], ASL %[var2]\n" + "MOVGE %[result], %[L_var1], ASL #16\n" + "SSAT %[result], #16, %[result]\n" + :[result]"=r"(result) + :[L_var1]"r"(L_var1), [var2]"r"(var2) + ); + return result; +#else + Word32 result; + Word32 tmp; + asm ( + "CMP %[var2], #16\n" + "MOVLT %[result], %[L_var1], ASL %[var2]\n" + "MOVGE %[result], %[L_var1], ASL #16\n" + "MOV %[tmp], %[result], ASR #15\n" + "TEQ %[tmp], %[result], ASR #31 \n" + "EORNE %[result], %[mask], %[result],ASR #31" + :[result]"=&r"(result), [tmp]"=&r"(tmp) + :[L_var1]"r"(L_var1), [var2]"r"(var2), [mask]"r"(0x7fff) + ); + return result; +#endif +} +#endif + +/*___________________________________________________________________________ + | | + | definitions for inline basic arithmetic operators | + |___________________________________________________________________________| +*/ +#if (SATRUATE_IS_INLINE) +__inline Word32 saturate(Word32 L_var1) +{ +#if ARMV6_SAT + Word32 result; + asm ( + "SSAT %[result], #16, %[L_var1]" + : [result]"=r"(result) + : [L_var1]"r"(L_var1) + ); + return result; +#elif ARMV5TE_SAT + Word32 result; + Word32 tmp; + asm volatile ( + "MOV %[tmp], %[L_var1],ASR#15\n" + "TEQ %[tmp], %[L_var1],ASR#31\n" + "EORNE %[result], %[mask],%[L_var1],ASR#31\n" + "MOVEQ %[result], %[L_var1]\n" + :[result]"=&r"(result), [tmp]"=&r"(tmp) + :[L_var1]"r"(L_var1), [mask]"r"(0x7fff) + ); + + return result; +#else + Word32 var_out; + + //var_out = (L_var1 > (Word32)0X00007fffL) ? (MAX_16) : ((L_var1 < (Word32)0xffff8000L) ? (MIN_16) : ((Word16)L_var1)); + + if (L_var1 > 0X00007fffL) + { + var_out = MAX_16; + } + else if (L_var1 < (Word32) 0xffff8000L) + { + var_out = MIN_16; + } + else + { + var_out = extract_l(L_var1); + } + + return (var_out); +#endif +} +#endif + +/* Short shift left, 1 */ +#if (SHL_IS_INLINE) +__inline Word32 shl (Word32 var1, Word32 var2) +{ +#if ARMV5TE_SHL + if(var2>=0) + { + return ASM_shl( var1, var2); + } + else + { + return ASM_shr( var1, -var2); + } +#else + Word32 var_out; + Word32 result; + + if (var2 < 0) + { + var_out = shr (var1, (Word16)-var2); + } + else + { + result = (Word32) var1 *((Word32) 1 << var2); + + if ((var2 > 15 && var1 != 0) || (result != (Word32) ((Word16) result))) + { + var_out = (Word16)((var1 > 0) ? MAX_16 : MIN_16); + } + else + { + var_out = extract_l(result); + } + } + return (var_out); +#endif +} +#endif + +/* Short shift right, 1 */ +#if (SHR_IS_INLINE) +__inline Word32 shr (Word32 var1, Word32 var2) +{ +#if ARMV5TE_SHR + if(var2>=0) + { + return ASM_shr( var1, var2); + } + else + { + return ASM_shl( var1, -var2); + } +#else + Word32 var_out; + + if (var2 < 0) + { + var_out = shl (var1, (Word16)-var2); + } + else + { + if (var2 >= 15) + { + var_out = (Word16)((var1 < 0) ? -1 : 0); + } + else + { + if (var1 < 0) + { + var_out = (Word16)(~((~var1) >> var2)); + } + else + { + var_out = (Word16)(var1 >> var2); + } + } + } + + return (var_out); +#endif +} +#endif + + +#if (L_MULT_IS_INLINE) +__inline Word32 L_mult(Word32 var1, Word32 var2) +{ +#if ARMV5TE_L_MULT + Word32 result; + asm ( + "SMULBB %[result], %[var1], %[var2] \n" + "QADD %[result], %[result], %[result] \n" + :[result]"=r"(result) + :[var1]"r"(var1), [var2]"r"(var2) + ); + return result; +#else + Word32 L_var_out; + + L_var_out = (Word32) var1 *(Word32) var2; + + if (L_var_out != (Word32) 0x40000000L) + { + L_var_out <<= 1; + } + else + { + L_var_out = MAX_32; + } + return (L_var_out); +#endif +} +#endif + +#if (L_MSU_IS_INLINE) +__inline Word32 L_msu (Word32 L_var3, Word32 var1, Word32 var2) +{ +#if ARMV5TE_L_MSU + Word32 result; + asm ( + "SMULBB %[result], %[var1], %[var2] \n" + "QDSUB %[result], %[L_var3], %[result]\n" + :[result]"=&r"(result) + :[L_var3]"r"(L_var3), [var1]"r"(var1), [var2]"r"(var2) + ); + return result; +#else + Word32 L_var_out; + Word32 L_product; + + L_product = L_mult(var1, var2); + L_var_out = L_sub(L_var3, L_product); + return (L_var_out); +#endif +} +#endif + +#if (L_SUB_IS_INLINE) +__inline Word32 L_sub(Word32 L_var1, Word32 L_var2) +{ +#if ARMV5TE_L_SUB + Word32 result; + asm ( + "QSUB %[result], %[L_var1], %[L_var2]\n" + :[result]"=r"(result) + :[L_var1]"r"(L_var1), [L_var2]"r"(L_var2) + ); + return result; +#else + Word32 L_var_out; + + L_var_out = L_var1 - L_var2; + + if (((L_var1 ^ L_var2) & MIN_32) != 0) + { + if ((L_var_out ^ L_var1) & MIN_32) + { + L_var_out = (L_var1 < 0L) ? MIN_32 : MAX_32; + } + } + + return (L_var_out); +#endif +} +#endif + +#if (L_SHL_IS_INLINE) +__inline Word32 L_shl(Word32 L_var1, Word32 var2) +{ +#if ARMV5TE_L_SHL + if(var2>=0) + { + return ASM_L_shl( L_var1, var2); + } + else + { + return ASM_L_shr( L_var1, -var2); + } +#else + Word32 L_var_out = 0L; + + if (var2 <= 0) + { + L_var1 = L_shr(L_var1, (Word16)-var2); + } + else + { + for (; var2 > 0; var2--) + { + if (L_var1 > (Word32) 0X3fffffffL) + { + return MAX_32; + } + else + { + if (L_var1 < (Word32) 0xc0000000L) + { + return MIN_32; + } + } + L_var1 <<= 1; + L_var_out = L_var1; + } + } + return (L_var1); +#endif +} +#endif + +#if (L_SHR_IS_INLINE) +__inline Word32 L_shr (Word32 L_var1, Word32 var2) +{ +#if ARMV5TE_L_SHR + if(var2>=0) + { + return ASM_L_shr( L_var1, var2); + } + else + { + return ASM_L_shl( L_var1, -var2); + } +#else + Word32 L_var_out; + + if (var2 < 0) + { + L_var_out = L_shl (L_var1, (Word16)-var2); + } + else + { + if (var2 >= 31) + { + L_var_out = (L_var1 < 0L) ? -1 : 0; + } + else + { + if (L_var1 < 0) + { + L_var_out = ~((~L_var1) >> var2); + } + else + { + L_var_out = L_var1 >> var2; + } + } + } + return (L_var_out); +#endif +} +#endif + +/* Short add, 1 */ +#if (ADD_IS_INLINE) +__inline Word32 add (Word32 var1, Word32 var2) +{ +#if ARMV5TE_ADD + Word32 result; + Word32 tmp; + asm ( + "ADD %[result], %[var1], %[var2] \n" + "MOV %[tmp], %[result], ASR #15 \n" + "TEQ %[tmp], %[result], ASR #31 \n" + "EORNE %[result], %[mask], %[result], ASR #31" + :[result]"=&r"(result), [tmp]"=&r"(tmp) + :[var1]"r"(var1), [var2]"r"(var2), [mask]"r"(0x7fff) + ); + return result; +#else + Word32 var_out; + Word32 L_sum; + + L_sum = (Word32) var1 + var2; + var_out = saturate(L_sum); + + return (var_out); +#endif +} +#endif + +/* Short sub, 1 */ +#if (SUB_IS_INLINE) +__inline Word32 sub(Word32 var1, Word32 var2) +{ +#if ARMV5TE_SUB + Word32 result; + Word32 tmp; + asm ( + "SUB %[result], %[var1], %[var2] \n" + "MOV %[tmp], %[var1], ASR #15 \n" + "TEQ %[tmp], %[var1], ASR #31 \n" + "EORNE %[result], %[mask], %[result], ASR #31 \n" + :[result]"=&r"(result), [tmp]"=&r"(tmp) + :[var1]"r"(var1), [var2]"r"(var2), [mask]"r"(0x7fff) + ); + return result; +#else + Word32 var_out; + Word32 L_diff; + + L_diff = (Word32) var1 - var2; + var_out = saturate(L_diff); + + return (var_out); +#endif +} +#endif + +/* Short division, 18 */ +#if (DIV_S_IS_INLINE) +__inline Word32 div_s (Word32 var1, Word32 var2) +{ + Word32 var_out = 0; + Word32 iteration; + Word32 L_num; + Word32 L_denom; + + var_out = MAX_16; + if (var1!= var2)//var1!= var2 + { + var_out = 0; + L_num = (Word32) var1; + + L_denom = (Word32) var2; + + //return (L_num<<15)/var2; + + for (iteration = 0; iteration < 15; iteration++) + { + var_out <<= 1; + L_num <<= 1; + + if (L_num >= L_denom) + { + L_num -= L_denom; + var_out++; + } + } + } + return (var_out); +} +#endif + +/* Short mult, 1 */ +#if (MULT_IS_INLINE) +__inline Word32 mult (Word32 var1, Word32 var2) +{ +#if ARMV5TE_MULT && ARMV6_SAT + Word32 result; + asm ( + "SMULBB %[result], %[var1], %[var2] \n" + "SSAT %[result], #16, %[result], ASR #15 \n" + :[result]"=r"(result) + :[var1]"r"(var1), [var2]"r"(var2) + ); + return result; +#elif ARMV5TE_MULT + Word32 result, tmp; + asm ( + "SMULBB %[tmp], %[var1], %[var2] \n" + "MOV %[result], %[tmp], ASR #15\n" + "MOV %[tmp], %[result], ASR #15\n" + "TEQ %[tmp], %[result], ASR #31\n" + "EORNE %[result], %[mask], %[result], ASR #31 \n" + :[result]"=&r"(result), [tmp]"=&r"(tmp) + :[var1]"r"(var1), [var2]"r"(var2), [mask]"r"(0x7fff) + ); + return result; +#else + Word32 var_out; + Word32 L_product; + + L_product = (Word32) var1 *(Word32) var2; + L_product = (L_product & (Word32) 0xffff8000L) >> 15; + if (L_product & (Word32) 0x00010000L) + L_product = L_product | (Word32) 0xffff0000L; + var_out = saturate(L_product); + + return (var_out); +#endif +} +#endif + + +/* Short norm, 15 */ +#if (NORM_S_IS_INLINE) +__inline Word32 norm_s (Word32 var1) +{ +#if ARMV5TE_NORM_S + Word32 result; + Word32 tmp; + asm ( + "RSBS %[tmp], %[var1], #0 \n" + "CLZLT %[result], %[var1]\n" + "CLZGT %[result], %[tmp]\n" + "SUBNE %[result], %[result], #17\n" + "MOVEQ %[result], #0\n" + "CMP %[var1], #-1\n" + "MOVEQ %[result], #15\n" + :[result]"=&r"(result), [tmp]"=&r"(tmp) + :[var1]"r"(var1) + ); + return result; +#else + Word32 var_out; + + if (var1 == 0) + { + var_out = 0; + } + else + { + if (var1 == -1) + { + var_out = 15; + } + else + { + if (var1 < 0) + { + var1 = (Word16)~var1; + } + for (var_out = 0; var1 < 0x4000; var_out++) + { + var1 <<= 1; + } + } + } + return (var_out); +#endif +} +#endif + +/* Long norm, 30 */ +#if (NORM_L_IS_INLINE) +__inline Word32 norm_l (Word32 L_var1) +{ +#if ARMV5TE_NORM_L + Word32 result; + asm volatile( + "CMP %[L_var1], #0\n" + "CLZNE %[result], %[L_var1]\n" + "SUBNE %[result], %[result], #1\n" + "MOVEQ %[result], #0\n" + :[result]"=r"(result) + :[L_var1]"r"(L_var1) + ); + return result; +#else + //Word16 var_out; + + //if (L_var1 == 0) + //{ + // var_out = 0; + //} + //else + //{ + // if (L_var1 == (Word32) 0xffffffffL) + // { + // var_out = 31; + // } + // else + // { + // if (L_var1 < 0) + // { + // L_var1 = ~L_var1; + // } + // for (var_out = 0; L_var1 < (Word32) 0x40000000L; var_out++) + // { + // L_var1 <<= 1; + // } + // } + //} + //return (var_out); + Word16 a16; + Word16 r = 0 ; + + + if ( L_var1 < 0 ) { + L_var1 = ~L_var1; + } + + if (0 == (L_var1 & 0x7fff8000)) { + a16 = extract_l(L_var1); + r += 16; + + if (0 == (a16 & 0x7f80)) { + r += 8; + + if (0 == (a16 & 0x0078)) { + r += 4; + + if (0 == (a16 & 0x0006)) { + r += 2; + + if (0 == (a16 & 0x0001)) { + r += 1; + } + } + else { + + if (0 == (a16 & 0x0004)) { + r += 1; + } + } + } + else { + + if (0 == (a16 & 0x0060)) { + r += 2; + + if (0 == (a16 & 0x0010)) { + r += 1; + } + } + else { + + if (0 == (a16 & 0x0040)) { + r += 1; + } + } + } + } + else { + + if (0 == (a16 & 0x7800)) { + r += 4; + + if (0 == (a16 & 0x0600)) { + r += 2; + + if (0 == (a16 & 0x0100)) { + r += 1; + } + } + else { + + if (0 == (a16 & 0x0400)) { + r += 1; + } + } + } + else { + + if (0 == (a16 & 0x6000)) { + r += 2; + + if (0 == (a16 & 0x1000)) { + r += 1; + } + } + else { + + if (0 == (a16 & 0x4000)) { + r += 1; + } + } + } + } + } + else { + a16 = extract_h(L_var1); + + if (0 == (a16 & 0x7f80)) { + r += 8; + + if (0 == (a16 & 0x0078)) { + r += 4 ; + + if (0 == (a16 & 0x0006)) { + r += 2; + + if (0 == (a16 & 0x0001)) { + r += 1; + } + } + else { + + if (0 == (a16 & 0x0004)) { + r += 1; + } + } + } + else { + + if (0 == (a16 & 0x0060)) { + r += 2; + + if (0 == (a16 & 0x0010)) { + r += 1; + } + } + else { + + if (0 == (a16 & 0x0040)) { + r += 1; + } + } + } + } + else { + + if (0 == (a16 & 0x7800)) { + r += 4; + + if (0 == (a16 & 0x0600)) { + r += 2; + + if (0 == (a16 & 0x0100)) { + r += 1; + } + } + else { + + if (0 == (a16 & 0x0400)) { + r += 1; + } + } + } + else { + + if (0 == (a16 & 0x6000)) { + r += 2; + + if (0 == (a16 & 0x1000)) { + r += 1; + } + } + else { + + if (0 == (a16 & 0x4000)) { + return 1; + } + } + } + } + } + + return r ; +#endif +} +#endif + +/* Round, 1 */ +#if (ROUND_IS_INLINE) +__inline Word32 round16(Word32 L_var1) +{ +#if ARMV5TE_ROUND + Word32 result; + asm ( + "QADD %[result], %[L_var1], %[bias]\n" + "MOV %[result], %[result], ASR #16 \n" + :[result]"=r"(result) + :[L_var1]"r"(L_var1), [bias]"r"(0x8000) + ); + return result; +#else + Word32 var_out; + Word32 L_rounded; + + L_rounded = L_add (L_var1, (Word32) 0x00008000L); + var_out = extract_h (L_rounded); + return (var_out); +#endif +} +#endif + +/* Mac, 1 */ +#if (L_MAC_IS_INLINE) +__inline Word32 L_mac (Word32 L_var3, Word32 var1, Word32 var2) +{ +#if ARMV5TE_L_MAC + Word32 result; + asm ( + "SMULBB %[result], %[var1], %[var2]\n" + "QDADD %[result], %[L_var3], %[result]\n" + :[result]"=&r"(result) + : [L_var3]"r"(L_var3), [var1]"r"(var1), [var2]"r"(var2) + ); + return result; +#else + Word32 L_var_out; + Word32 L_product; + + L_product = L_mult(var1, var2); + L_var_out = L_add (L_var3, L_product); + return (L_var_out); +#endif +} +#endif + +#if (L_ADD_IS_INLINE) +__inline Word32 L_add (Word32 L_var1, Word32 L_var2) +{ +#if ARMV5TE_L_ADD + Word32 result; + asm ( + "QADD %[result], %[L_var1], %[L_var2]\n" + :[result]"=r"(result) + :[L_var1]"r"(L_var1), [L_var2]"r"(L_var2) + ); + return result; +#else + Word32 L_var_out; + + L_var_out = L_var1 + L_var2; + if (((L_var1 ^ L_var2) & MIN_32) == 0) + { + if ((L_var_out ^ L_var1) & MIN_32) + { + L_var_out = (L_var1 < 0) ? MIN_32 : MAX_32; + } + } + return (L_var_out); +#endif +} +#endif + + + +#if (MULT_R_IS_INLINE) +__inline Word32 mult_r (Word32 var1, Word32 var2) +{ + Word32 var_out; + Word32 L_product_arr; + + L_product_arr = (Word32)var1 *(Word32)var2; /* product */ + L_product_arr += (Word32)0x00004000L; /* round */ + L_product_arr >>= 15; /* shift */ + + var_out = saturate(L_product_arr); + + return (var_out); +} +#endif + +#if (SHR_R_IS_INLINE) +__inline Word32 shr_r (Word32 var1, Word32 var2) +{ + Word32 var_out; + + if (var2 > 15) + { + var_out = 0; + } + else + { + var_out = shr(var1, var2); + + if (var2 > 0) + { + if ((var1 & ((Word16) 1 << (var2 - 1))) != 0) + { + var_out++; + } + } + } + + return (var_out); +} +#endif + +#if (MAC_R_IS_INLINE) +__inline Word32 mac_r (Word32 L_var3, Word32 var1, Word32 var2) +{ + Word32 var_out; + + L_var3 = L_mac (L_var3, var1, var2); + var_out = (Word16)((L_var3 + 0x8000L) >> 16); + + return (var_out); +} +#endif + +#if (MSU_R_IS_INLINE) +__inline Word32 msu_r (Word32 L_var3, Word32 var1, Word32 var2) +{ + Word32 var_out; + + L_var3 = L_msu (L_var3, var1, var2); + var_out = (Word16)((L_var3 + 0x8000L) >> 16); + + return (var_out); +} +#endif + +#if (L_SHR_R_IS_INLINE) +__inline Word32 L_shr_r (Word32 L_var1, Word32 var2) +{ + Word32 L_var_out; + + if (var2 > 31) + { + L_var_out = 0; + } + else + { + L_var_out = L_shr(L_var1, var2); + + if (var2 > 0) + { + if ((L_var1 & ((Word32) 1 << (var2 - 1))) != 0) + { + L_var_out++; + } + } + } + + return (L_var_out); +} +#endif + +#if (EXTRACT_H_IS_INLINE) +__inline Word32 extract_h (Word32 L_var1) +{ + Word32 var_out; + + var_out = (L_var1 >> 16); + + return (var_out); +} +#endif + +#if (EXTRACT_L_IS_INLINE) +__inline Word32 extract_l(Word32 L_var1) +{ + return (Word16) L_var1; +} +#endif + +#endif diff --git a/jni/inc/bit_cnt.h b/jni/inc/bit_cnt.h new file mode 100644 index 000000000..266a21944 --- /dev/null +++ b/jni/inc/bit_cnt.h @@ -0,0 +1,106 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: bit_cnt.h + + Content: Huffman Bitcounter & coder structure and functions + +*******************************************************************************/ + +#ifndef __BITCOUNT_H +#define __BITCOUNT_H + +#include "bitbuffer.h" +#include "basic_op.h" +#define INVALID_BITCOUNT (MAX_16/4) + +/* + code book number table +*/ + +enum codeBookNo{ + CODE_BOOK_ZERO_NO= 0, + CODE_BOOK_1_NO= 1, + CODE_BOOK_2_NO= 2, + CODE_BOOK_3_NO= 3, + CODE_BOOK_4_NO= 4, + CODE_BOOK_5_NO= 5, + CODE_BOOK_6_NO= 6, + CODE_BOOK_7_NO= 7, + CODE_BOOK_8_NO= 8, + CODE_BOOK_9_NO= 9, + CODE_BOOK_10_NO= 10, + CODE_BOOK_ESC_NO= 11, + CODE_BOOK_RES_NO= 12, + CODE_BOOK_PNS_NO= 13 +}; + +/* + code book index table +*/ + +enum codeBookNdx{ + CODE_BOOK_ZERO_NDX=0, + CODE_BOOK_1_NDX, + CODE_BOOK_2_NDX, + CODE_BOOK_3_NDX, + CODE_BOOK_4_NDX, + CODE_BOOK_5_NDX, + CODE_BOOK_6_NDX, + CODE_BOOK_7_NDX, + CODE_BOOK_8_NDX, + CODE_BOOK_9_NDX, + CODE_BOOK_10_NDX, + CODE_BOOK_ESC_NDX, + CODE_BOOK_RES_NDX, + CODE_BOOK_PNS_NDX, + NUMBER_OF_CODE_BOOKS +}; + +/* + code book lav table +*/ + +enum codeBookLav{ + CODE_BOOK_ZERO_LAV=0, + CODE_BOOK_1_LAV=1, + CODE_BOOK_2_LAV=1, + CODE_BOOK_3_LAV=2, + CODE_BOOK_4_LAV=2, + CODE_BOOK_5_LAV=4, + CODE_BOOK_6_LAV=4, + CODE_BOOK_7_LAV=7, + CODE_BOOK_8_LAV=7, + CODE_BOOK_9_LAV=12, + CODE_BOOK_10_LAV=12, + CODE_BOOK_ESC_LAV=16, + CODE_BOOK_SCF_LAV=60, + CODE_BOOK_PNS_LAV=60 +}; + +Word16 bitCount(const Word16 *aQuantSpectrum, + const Word16 noOfSpecLines, + Word16 maxVal, + Word16 *bitCountLut); + +Word16 codeValues(Word16 *values, Word16 width, Word16 codeBook, HANDLE_BIT_BUF hBitstream); + +Word16 bitCountScalefactorDelta(Word16 delta); +Word16 codeScalefactorDelta(Word16 scalefactor, HANDLE_BIT_BUF hBitstream); + + + +#endif diff --git a/jni/inc/bitbuffer.h b/jni/inc/bitbuffer.h new file mode 100644 index 000000000..7c79f07ec --- /dev/null +++ b/jni/inc/bitbuffer.h @@ -0,0 +1,89 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: bitbuffer.h + + Content: Bit Buffer Management structure and functions + +*******************************************************************************/ + +#ifndef BITBUFFER_H +#define BITBUFFER_H + +#include "typedef.h" + + +enum direction +{ + forwardDirection, + backwardDirection +}; + + +/*! + The pointer 'pReadNext' points to the next available word, where bits can be read from. The pointer + 'pWriteNext' points to the next available word, where bits can be written to. The pointer pBitBufBase + points to the start of the bitstream buffer and the pointer pBitBufEnd points to the end of the bitstream + buffer. The two pointers are used as lower-bound respectively upper-bound address for the modulo addressing + mode. + + The element cntBits contains the currently available bits in the bit buffer. It will be incremented when + bits are written to the bitstream buffer and decremented when bits are read from the bitstream buffer. +*/ +struct BIT_BUF +{ + UWord8 *pBitBufBase; /*!< pointer points to first position in bitstream buffer */ + UWord8 *pBitBufEnd; /*!< pointer points to last position in bitstream buffer */ + + UWord8 *pWriteNext; /*!< pointer points to next available word in bitstream buffer to write */ + + UWord32 cache; + + Word16 wBitPos; /*!< 31<=wBitPos<=0*/ + Word16 cntBits; /*!< number of available bits in the bitstream buffer + write bits to bitstream buffer => increment cntBits + read bits from bitstream buffer => decrement cntBits */ + Word16 size; /*!< size of bitbuffer in bits */ + Word16 isValid; /*!< indicates whether the instance has been initialized */ +}; /* size Word16: 8 */ + +/*! Define pointer to bit buffer structure */ +typedef struct BIT_BUF *HANDLE_BIT_BUF; + + +HANDLE_BIT_BUF CreateBitBuffer(HANDLE_BIT_BUF hBitBuf, + UWord8 *pBitBufBase, + Word16 bitBufSize); + + +void DeleteBitBuffer(HANDLE_BIT_BUF *hBitBuf); + + +Word16 GetBitsAvail(HANDLE_BIT_BUF hBitBuf); + + +Word16 WriteBits(HANDLE_BIT_BUF hBitBuf, + UWord32 writeValue, + Word16 noBitsToWrite); + +void ResetBitBuf(HANDLE_BIT_BUF hBitBuf, + UWord8 *pBitBufBase, + Word16 bitBufSize); + +#define GetNrBitsAvailable(hBitBuf) ( (hBitBuf)->cntBits) +#define GetNrBitsRead(hBitBuf) ((hBitBuf)->size-(hBitBuf)->cntBits) + +#endif /* BITBUFFER_H */ diff --git a/jni/inc/bitenc.h b/jni/inc/bitenc.h new file mode 100644 index 000000000..6a58aebe9 --- /dev/null +++ b/jni/inc/bitenc.h @@ -0,0 +1,50 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: bitenc.h + + Content: Bitstream encoder structure and functions + +*******************************************************************************/ + +#ifndef _BITENC_H +#define _BITENC_H + +#include "qc_data.h" +#include "tns.h" +#include "channel_map.h" +#include "interface.h" + +struct BITSTREAMENCODER_INIT +{ + Word16 nChannels; + Word32 bitrate; + Word32 sampleRate; + Word16 profile; +}; + + + +Word16 WriteBitstream (HANDLE_BIT_BUF hBitstream, + ELEMENT_INFO elInfo, + QC_OUT *qcOut, + PSY_OUT *psyOut, + Word16 *globUsedBits, + const UWord8 *ancBytes, + Word16 samplerate + ); + +#endif /* _BITENC_H */ diff --git a/jni/inc/block_switch.h b/jni/inc/block_switch.h new file mode 100644 index 000000000..a4d3e8fd4 --- /dev/null +++ b/jni/inc/block_switch.h @@ -0,0 +1,72 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: block_switch.h + + Content: Block switching structure and functions + +*******************************************************************************/ + +#ifndef _BLOCK_SWITCH_H +#define _BLOCK_SWITCH_H + +#include "typedef.h" + + +/****************** Defines ******************************/ +#define BLOCK_SWITCHING_IIR_LEN 2 /* Length of HighPass-FIR-Filter for Attack-Detection */ +#define BLOCK_SWITCH_WINDOWS TRANS_FAC /* number of windows for energy calculation */ +#define BLOCK_SWITCH_WINDOW_LEN FRAME_LEN_SHORT /* minimal granularity of energy calculation */ + + + +/****************** Structures ***************************/ +typedef struct{ + Word32 invAttackRatio; + Word16 windowSequence; + Word16 nextwindowSequence; + Flag attack; + Flag lastattack; + Word16 attackIndex; + Word16 lastAttackIndex; + Word16 noOfGroups; + Word16 groupLen[TRANS_FAC]; + Word32 windowNrg[2][BLOCK_SWITCH_WINDOWS]; /* time signal energy in Subwindows (last and current) */ + Word32 windowNrgF[2][BLOCK_SWITCH_WINDOWS]; /* filtered time signal energy in segments (last and current) */ + Word32 iirStates[BLOCK_SWITCHING_IIR_LEN]; /* filter delay-line */ + Word32 maxWindowNrg; /* max energy in subwindows */ + Word32 accWindowNrg; /* recursively accumulated windowNrgF */ +}BLOCK_SWITCHING_CONTROL; + + + + + +Word16 InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, + const Word32 bitRate, const Word16 nChannels); + +Word16 BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, + Word16 *timeSignal, + Word32 sampleRate, + Word16 chIncrement); + +Word16 SyncBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft, + BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight, + const Word16 noOfChannels); + + + +#endif /* #ifndef _BLOCK_SWITCH_H */ diff --git a/jni/inc/channel_map.h b/jni/inc/channel_map.h new file mode 100644 index 000000000..c361feb89 --- /dev/null +++ b/jni/inc/channel_map.h @@ -0,0 +1,37 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: channel_map.h + + Content: channel mapping functions + +*******************************************************************************/ + +#ifndef _CHANNEL_MAP_H +#define _CHANNEL_MAP_H + +#include "psy_const.h" +#include "qc_data.h" + +Word16 InitElementInfo (Word16 nChannels, ELEMENT_INFO* elInfo); + +Word16 InitElementBits(ELEMENT_BITS *elementBits, + ELEMENT_INFO elInfo, + Word32 bitrateTot, + Word16 averageBitsTot, + Word16 staticBitsTot); + +#endif /* CHANNEL_MAP_H */ diff --git a/jni/inc/cmnMemory.h b/jni/inc/cmnMemory.h new file mode 100644 index 000000000..e1751033e --- /dev/null +++ b/jni/inc/cmnMemory.h @@ -0,0 +1,106 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: cmnMemory.h + + Content: memory operator implementation header file + +*******************************************************************************/ + +#ifndef __cmnMemory_H__ +#define __cmnMemory_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "voMem.h" + +//extern VO_MEM_OPERATOR g_memOP; + +/** + * Allocate memory + * \param uID [in] module ID + * \param uSize [in] size of memory + * \return value is the allocated memory address. NULL is failed. + */ +VO_U32 cmnMemAlloc (VO_S32 uID, VO_MEM_INFO * pMemInfo); + +/** + * Free up memory + * \param uID [in] module ID + * \param pMem [in] address of memory + * \return value 0, if succeeded. + */ +VO_U32 cmnMemFree (VO_S32 uID, VO_PTR pBuffer); + +/** + * memory set function + * \param uID [in] module ID + * \param pBuff [in/out] address of memory + * \param uValue [in] the value to be set + * \param uSize [in] the size to be set + * \return value 0, if succeeded. + */ +VO_U32 cmnMemSet (VO_S32 uID, VO_PTR pBuff, VO_U8 uValue, VO_U32 uSize); + +/** + * memory copy function + * \param uID [in] module ID + * \param pDest [in/out] address of destination memory + * \param pSource [in] address of source memory + * \param uSize [in] the size to be copied + * \return value 0, if succeeded. + */ +VO_U32 cmnMemCopy (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize); + +/** + * memory check function + * \param uID [in] module ID + * \param pBuff [in] address of buffer to be checked + * \param uSize [in] the size to be checked + * \return value 0, if succeeded. + */ +VO_U32 cmnMemCheck (VO_S32 uID, VO_PTR pBuffer, VO_U32 uSize); + +/** + * memory compare function + * \param uID [in] module ID + * \param pBuffer1 [in] address of buffer 1 to be compared + * \param pBuffer2 [in] address of buffer 2 to be compared + * \param uSize [in] the size to be compared + * \return value: same as standard C run-time memcmp() function. + */ +VO_S32 cmnMemCompare (VO_S32 uID, VO_PTR pBuffer1, VO_PTR pBuffer2, VO_U32 uSize); + +/** + * memory move function + * \param uID [in] module ID + * \param pDest [in/out] address of destination memory + * \param pSource [in] address of source memory + * \param uSize [in] the size to be moved + * \return value 0, if succeeded. + */ +VO_U32 cmnMemMove (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // __cmnMemory_H__ + + diff --git a/jni/inc/config.h b/jni/inc/config.h new file mode 100644 index 000000000..b0b4c26f8 --- /dev/null +++ b/jni/inc/config.h @@ -0,0 +1,36 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: config.h + + Content: aac encoder parameter + +*******************************************************************************/ + +#ifndef _AACENC_CONFIG_H_ +#define _AACENC_CONFIG_H_ + +#define MAX_CHANNELS 2 + +#define AACENC_BLOCKSIZE 1024 /*! encoder only takes BLOCKSIZE samples at a time */ +#define AACENC_TRANS_FAC 8 /*! encoder short long ratio */ + + +#define MAXBITS_COEF 6144 +#define MINBITS_COEF 744 + + +#endif diff --git a/jni/inc/dyn_bits.h b/jni/inc/dyn_bits.h new file mode 100644 index 000000000..d3a8a6714 --- /dev/null +++ b/jni/inc/dyn_bits.h @@ -0,0 +1,82 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: dyn_bits.h + + Content: Noiseless coder module structure and functions + +*******************************************************************************/ + +#ifndef __DYN_BITS_H +#define __DYN_BITS_H + +#include "psy_const.h" +#include "tns.h" +#include "bit_cnt.h" + + + +#define MAX_SECTIONS MAX_GROUPED_SFB +#define SECT_ESC_VAL_LONG 31 +#define SECT_ESC_VAL_SHORT 7 +#define CODE_BOOK_BITS 4 +#define SECT_BITS_LONG 5 +#define SECT_BITS_SHORT 3 + +typedef struct +{ + Word16 codeBook; + Word16 sfbStart; + Word16 sfbCnt; + Word16 sectionBits; +} +SECTION_INFO; + + + + +typedef struct +{ + Word16 blockType; + Word16 noOfGroups; + Word16 sfbCnt; + Word16 maxSfbPerGroup; + Word16 sfbPerGroup; + Word16 noOfSections; + SECTION_INFO sectionInfo[MAX_SECTIONS]; + Word16 sideInfoBits; /* sectioning bits */ + Word16 huffmanBits; /* huffman coded bits */ + Word16 scalefacBits; /* scalefac coded bits */ + Word16 firstScf; /* first scf to be coded */ + Word16 bitLookUp[MAX_SFB_LONG*(CODE_BOOK_ESC_NDX+1)]; + Word16 mergeGainLookUp[MAX_SFB_LONG]; +} +SECTION_DATA; /* Word16 size: 10 + 60(MAX_SECTIONS)*4(SECTION_INFO) + 51(MAX_SFB_LONG)*12(CODE_BOOK_ESC_NDX+1) + 51(MAX_SFB_LONG) = 913 */ + + +Word16 BCInit(void); + +Word16 dynBitCount(const Word16 *quantSpectrum, + const UWord16 *maxValueInSfb, + const Word16 *scalefac, + const Word16 blockType, + const Word16 sfbCnt, + const Word16 maxSfbPerGroup, + const Word16 sfbPerGroup, + const Word16 *sfbOffset, + SECTION_DATA *sectionData); + +#endif diff --git a/jni/inc/grp_data.h b/jni/inc/grp_data.h new file mode 100644 index 000000000..4c1b2cbab --- /dev/null +++ b/jni/inc/grp_data.h @@ -0,0 +1,44 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: grp_data.h + + Content: Short block grouping function + +*******************************************************************************/ + +#ifndef __GRP_DATA_H__ +#define __GRP_DATA_H__ +#include "psy_data.h" +#include "typedefs.h" + +void +groupShortData(Word32 *mdctSpectrum, + Word32 *tmpSpectrum, + SFB_THRESHOLD *sfbThreshold, + SFB_ENERGY *sfbEnergy, + SFB_ENERGY *sfbEnergyMS, + SFB_ENERGY *sfbSpreadedEnergy, + const Word16 sfbCnt, + const Word16 *sfbOffset, + const Word16 *sfbMinSnr, + Word16 *groupedSfbOffset, + Word16 *maxSfbPerGroup, + Word16 *groupedSfbMinSnr, + const Word16 noOfGroups, + const Word16 *groupLen); + +#endif /* _INTERFACE_H */ diff --git a/jni/inc/interface.h b/jni/inc/interface.h new file mode 100644 index 000000000..a42e6a9cd --- /dev/null +++ b/jni/inc/interface.h @@ -0,0 +1,106 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: interface.h + + Content: psychoaccoustic/quantizer structures and interface + +*******************************************************************************/ + +#ifndef _INTERFACE_H +#define _INTERFACE_H + +#include "config.h" +#include "psy_const.h" +#include "psy_data.h" +#include "typedefs.h" + + +enum +{ + MS_NONE = 0, + MS_SOME = 1, + MS_ALL = 2 +}; + +enum +{ + MS_ON = 1 +}; + +struct TOOLSINFO { + Word16 msDigest; + Word16 msMask[MAX_GROUPED_SFB]; +}; + + +typedef struct { + Word16 sfbCnt; + Word16 sfbPerGroup; + Word16 maxSfbPerGroup; + Word16 windowSequence; + Word16 windowShape; + Word16 groupingMask; + Word16 sfbOffsets[MAX_GROUPED_SFB+1]; + Word16 mdctScale; + Word32 *sfbEnergy; + Word32 *sfbSpreadedEnergy; + Word32 *sfbThreshold; + Word32 *mdctSpectrum; + Word32 sfbEnSumLR; + Word32 sfbEnSumMS; + Word32 sfbDist[MAX_GROUPED_SFB]; + Word32 sfbDistNew[MAX_GROUPED_SFB]; + Word16 sfbMinSnr[MAX_GROUPED_SFB]; + Word16 minSfMaxQuant[MAX_GROUPED_SFB]; + Word16 minScfCalculated[MAX_GROUPED_SFB]; + Word16 prevScfLast[MAX_GROUPED_SFB]; + Word16 prevScfNext[MAX_GROUPED_SFB]; + Word16 deltaPeLast[MAX_GROUPED_SFB]; + TNS_INFO tnsInfo; +} PSY_OUT_CHANNEL; /* Word16 size: 14 + 60(MAX_GROUPED_SFB) + 112(TNS_INFO) = 186 */ + +typedef struct { + struct TOOLSINFO toolsInfo; + Word16 groupedSfbOffset[MAX_CHANNELS][MAX_GROUPED_SFB+1]; /* plus one for last dummy offset ! */ + Word16 groupedSfbMinSnr[MAX_CHANNELS][MAX_GROUPED_SFB]; +} PSY_OUT_ELEMENT; + +typedef struct { + /* information shared by both channels */ + PSY_OUT_ELEMENT psyOutElement; + /* information specific to each channel */ + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS]; +}PSY_OUT; + +void BuildInterface(Word32 *mdctSpectrum, + const Word16 mdctScale, + SFB_THRESHOLD *sfbThreshold, + SFB_ENERGY *sfbEnergy, + SFB_ENERGY *sfbSpreadedEnergy, + const SFB_ENERGY_SUM sfbEnergySumLR, + const SFB_ENERGY_SUM sfbEnergySumMS, + const Word16 windowSequence, + const Word16 windowShape, + const Word16 sfbCnt, + const Word16 *sfbOffset, + const Word16 maxSfbPerGroup, + const Word16 *groupedSfbMinSnr, + const Word16 noOfGroups, + const Word16 *groupLen, + PSY_OUT_CHANNEL *psyOutCh); + +#endif /* _INTERFACE_H */ diff --git a/jni/inc/line_pe.h b/jni/inc/line_pe.h new file mode 100644 index 000000000..116d5a8c4 --- /dev/null +++ b/jni/inc/line_pe.h @@ -0,0 +1,75 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: line_pe.h + + Content: Perceptual entropie module structure and functions + +*******************************************************************************/ + +#ifndef __LINE_PE_H +#define __LINE_PE_H + + +#include "psy_const.h" +#include "interface.h" + + +typedef struct { + Word16 sfbLdEnergy[MAX_GROUPED_SFB]; /* 4*log(sfbEnergy)/log(2) */ + Word16 sfbNLines4[MAX_GROUPED_SFB]; /* 4*number of relevant lines in sfb */ + Word16 sfbPe[MAX_GROUPED_SFB]; /* pe for each sfb */ + Word16 sfbConstPart[MAX_GROUPED_SFB]; /* constant part for each sfb */ + Word16 sfbNActiveLines[MAX_GROUPED_SFB]; /* number of active lines in sfb */ + Word16 pe; /* sum of sfbPe */ + Word16 constPart; /* sum of sfbConstPart */ + Word16 nActiveLines; /* sum of sfbNActiveLines */ +} PE_CHANNEL_DATA; /* size Word16: 303 */ + + +typedef struct { + PE_CHANNEL_DATA peChannelData[MAX_CHANNELS]; + Word16 pe; + Word16 constPart; + Word16 nActiveLines; + Word16 offset; + Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB]; + Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB]; + Word32 sfbPeFactors[MAX_CHANNELS][MAX_GROUPED_SFB]; +} PE_DATA; /* size Word16: 303 + 4 + 120 + 240 = 667 */ + + + + +void prepareSfbPe(PE_DATA *peData, + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], + Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB], + const Word16 nChannels, + const Word16 peOffset); + + + + + +void calcSfbPe(PE_DATA *peData, + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + const Word16 nChannels); + + + + +#endif diff --git a/jni/inc/memalign.h b/jni/inc/memalign.h new file mode 100644 index 000000000..30bbf4501 --- /dev/null +++ b/jni/inc/memalign.h @@ -0,0 +1,35 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: memalign.h + + Content: Memory alloc alignments functions + +*******************************************************************************/ + +#ifndef __VO_AACENC_MEM_ALIGN_H__ +#define __VO_AACENC_MEM_ALIGN_H__ + +#include "voMem.h" +#include "typedef.h" + +extern void *mem_malloc(VO_MEM_OPERATOR *pMemop, unsigned int size, unsigned char alignment, unsigned int CodecID); +extern void mem_free(VO_MEM_OPERATOR *pMemop, void *mem_ptr, unsigned int CodecID); + +#endif /* __VO_MEM_ALIGN_H__ */ + + + diff --git a/jni/inc/ms_stereo.h b/jni/inc/ms_stereo.h new file mode 100644 index 000000000..3c03dea44 --- /dev/null +++ b/jni/inc/ms_stereo.h @@ -0,0 +1,45 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: ms_stereo.h + + Content: Declaration MS stereo processing structure and functions + +*******************************************************************************/ + +#ifndef __MS_STEREO_H__ +#define __MS_STEREO_H__ +#include "typedef.h" + +void MsStereoProcessing(Word32 *sfbEnergyLeft, + Word32 *sfbEnergyRight, + const Word32 *sfbEnergyMid, + const Word32 *sfbEnergySide, + Word32 *mdctSpectrumLeft, + Word32 *mdctSpectrumRight, + Word32 *sfbThresholdLeft, + Word32 *sfbThresholdRight, + Word32 *sfbSpreadedEnLeft, + Word32 *sfbSpreadedEnRight, + Word16 *msDigest, + Word16 *msMask, + const Word16 sfbCnt, + const Word16 sfbPerGroup, + const Word16 maxSfbPerGroup, + const Word16 *sfbOffset); + + +#endif diff --git a/jni/inc/oper_32b.h b/jni/inc/oper_32b.h new file mode 100644 index 000000000..6e5844faa --- /dev/null +++ b/jni/inc/oper_32b.h @@ -0,0 +1,89 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: oper_32b.h + + Content: Double precision operations + +*******************************************************************************/ + +#ifndef __OPER_32b_H +#define __OPER_32b_H + +#include "typedef.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define POW2_TABLE_BITS 8 +#define POW2_TABLE_SIZE (1<> 16); + + l_var_out = (long)swLow1 * (long)var1 >> 15; + + l_var_out += swHigh1 * var1 << 1; + + return(l_var_out); +} + +__inline Word32 L_mpy_wx(Word32 L_var2, Word16 var1) +{ +#if ARMV5TE_L_MPY_LS + Word32 result; + asm volatile( + "SMULWB %[result], %[L_var2], %[var1] \n" + :[result]"=r"(result) + :[L_var2]"r"(L_var2), [var1]"r"(var1) + ); + return result; +#else + unsigned short swLow1; + Word16 swHigh1; + Word32 l_var_out; + + swLow1 = (unsigned short)(L_var2); + swHigh1 = (Word16)(L_var2 >> 16); + + l_var_out = (long)swLow1 * (long)var1 >> 16; + l_var_out += swHigh1 * var1; + + return(l_var_out); +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/jni/inc/pre_echo_control.h b/jni/inc/pre_echo_control.h new file mode 100644 index 000000000..e719ba72a --- /dev/null +++ b/jni/inc/pre_echo_control.h @@ -0,0 +1,42 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: pre_echo_control.h + + Content: Pre echo control functions + +*******************************************************************************/ + +#ifndef __PRE_ECHO_CONTROL_H +#define __PRE_ECHO_CONTROL_H + +#include "typedefs.h" + +void InitPreEchoControl(Word32 *pbThresholdnm1, + Word16 numPb, + Word32 *pbThresholdQuiet); + + +void PreEchoControl(Word32 *pbThresholdNm1, + Word16 numPb, + Word32 maxAllowedIncreaseFactor, + Word16 minRemainingThresholdFactor, + Word32 *pbThreshold, + Word16 mdctScale, + Word16 mdctScalenm1); + +#endif + diff --git a/jni/inc/psy_configuration.h b/jni/inc/psy_configuration.h new file mode 100644 index 000000000..f6981faff --- /dev/null +++ b/jni/inc/psy_configuration.h @@ -0,0 +1,107 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: psy_configuration.h + + Content: Psychoaccoustic configuration structure and functions + +*******************************************************************************/ + +#ifndef _PSY_CONFIGURATION_H +#define _PSY_CONFIGURATION_H + +#include "typedefs.h" +#include "psy_const.h" +#include "tns.h" + +typedef struct{ + + Word16 sfbCnt; + Word16 sfbActive; /* number of sf bands containing energy after lowpass */ + const Word16 *sfbOffset; + + Word32 sfbThresholdQuiet[MAX_SFB_LONG]; + + Word16 maxAllowedIncreaseFactor; /* preecho control */ + Word16 minRemainingThresholdFactor; + + Word16 lowpassLine; + Word16 sampRateIdx; + Word32 clipEnergy; /* for level dependend tmn */ + + Word16 ratio; + Word16 sfbMaskLowFactor[MAX_SFB_LONG]; + Word16 sfbMaskHighFactor[MAX_SFB_LONG]; + + Word16 sfbMaskLowFactorSprEn[MAX_SFB_LONG]; + Word16 sfbMaskHighFactorSprEn[MAX_SFB_LONG]; + + + Word16 sfbMinSnr[MAX_SFB_LONG]; /* minimum snr (formerly known as bmax) */ + + TNS_CONFIG tnsConf; + +}PSY_CONFIGURATION_LONG; /*Word16 size: 8 + 52 + 102 + 51 + 51 + 51 + 51 + 47 = 515 */ + + +typedef struct{ + + Word16 sfbCnt; + Word16 sfbActive; /* number of sf bands containing energy after lowpass */ + const Word16 *sfbOffset; + + Word32 sfbThresholdQuiet[MAX_SFB_SHORT]; + + Word16 maxAllowedIncreaseFactor; /* preecho control */ + Word16 minRemainingThresholdFactor; + + Word16 lowpassLine; + Word16 sampRateIdx; + Word32 clipEnergy; /* for level dependend tmn */ + + Word16 ratio; + Word16 sfbMaskLowFactor[MAX_SFB_SHORT]; + Word16 sfbMaskHighFactor[MAX_SFB_SHORT]; + + Word16 sfbMaskLowFactorSprEn[MAX_SFB_SHORT]; + Word16 sfbMaskHighFactorSprEn[MAX_SFB_SHORT]; + + + Word16 sfbMinSnr[MAX_SFB_SHORT]; /* minimum snr (formerly known as bmax) */ + + TNS_CONFIG tnsConf; + +}PSY_CONFIGURATION_SHORT; /*Word16 size: 8 + 16 + 16 + 16 + 16 + 16 + 16 + 16 + 47 = 167 */ + + +/* Returns the sample rate index */ +Word32 GetSRIndex(Word32 sampleRate); + + +Word16 InitPsyConfigurationLong(Word32 bitrate, + Word32 samplerate, + Word16 bandwidth, + PSY_CONFIGURATION_LONG *psyConf); + +Word16 InitPsyConfigurationShort(Word32 bitrate, + Word32 samplerate, + Word16 bandwidth, + PSY_CONFIGURATION_SHORT *psyConf); + +#endif /* _PSY_CONFIGURATION_H */ + + + diff --git a/jni/inc/psy_const.h b/jni/inc/psy_const.h new file mode 100644 index 000000000..19fb9b2e1 --- /dev/null +++ b/jni/inc/psy_const.h @@ -0,0 +1,80 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: psy_const.h + + Content: Global psychoacoustic constants structures + +*******************************************************************************/ + +#ifndef _PSYCONST_H +#define _PSYCONST_H + +#include "config.h" + +#define TRUE 1 +#define FALSE 0 + +#define FRAME_LEN_LONG AACENC_BLOCKSIZE +#define TRANS_FAC 8 +#define FRAME_LEN_SHORT (FRAME_LEN_LONG/TRANS_FAC) + + + +/* Block types */ +enum +{ + LONG_WINDOW = 0, + START_WINDOW, + SHORT_WINDOW, + STOP_WINDOW +}; + +/* Window shapes */ +enum +{ + SINE_WINDOW = 0, + KBD_WINDOW = 1 +}; + +/* + MS stuff +*/ +enum +{ + SI_MS_MASK_NONE = 0, + SI_MS_MASK_SOME = 1, + SI_MS_MASK_ALL = 2 +}; + +#define MAX_NO_OF_GROUPS 4 +#define MAX_SFB_SHORT 15 /* 15 for a memory optimized implementation, maybe 16 for convenient debugging */ +#define MAX_SFB_LONG 51 /* 51 for a memory optimized implementation, maybe 64 for convenient debugging */ +#define MAX_SFB (MAX_SFB_SHORT > MAX_SFB_LONG ? MAX_SFB_SHORT : MAX_SFB_LONG) /* = MAX_SFB_LONG */ +#define MAX_GROUPED_SFB (MAX_NO_OF_GROUPS*MAX_SFB_SHORT > MAX_SFB_LONG ? \ + MAX_NO_OF_GROUPS*MAX_SFB_SHORT : MAX_SFB_LONG) + +#define BLOCK_SWITCHING_OFFSET (1*1024+3*128+64+128) +#define BLOCK_SWITCHING_DATA_SIZE FRAME_LEN_LONG + +#define TRANSFORM_OFFSET_LONG 0 +#define TRANSFORM_OFFSET_SHORT 448 + +#define LOG_NORM_PCM -15 + +#define NUM_SAMPLE_RATES 12 + +#endif /* _PSYCONST_H */ diff --git a/jni/inc/psy_data.h b/jni/inc/psy_data.h new file mode 100644 index 000000000..3ea6a84d4 --- /dev/null +++ b/jni/inc/psy_data.h @@ -0,0 +1,66 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: psy_data.h + + Content: Psychoacoustic data and structures + +*******************************************************************************/ + +#ifndef _PSY_DATA_H +#define _PSY_DATA_H + +#include "block_switch.h" +#include "tns.h" + +/* + the structs can be implemented as unions +*/ + +typedef struct{ + Word32 sfbLong[MAX_GROUPED_SFB]; + Word32 sfbShort[TRANS_FAC][MAX_SFB_SHORT]; +}SFB_THRESHOLD; /* Word16 size: 260 */ + +typedef struct{ + Word32 sfbLong[MAX_GROUPED_SFB]; + Word32 sfbShort[TRANS_FAC][MAX_SFB_SHORT]; +}SFB_ENERGY; /* Word16 size: 260 */ + +typedef struct{ + Word32 sfbLong; + Word32 sfbShort[TRANS_FAC]; +}SFB_ENERGY_SUM; /* Word16 size: 18 */ + + +typedef struct{ + BLOCK_SWITCHING_CONTROL blockSwitchingControl; /* block switching */ + Word16 *mdctDelayBuffer; /* mdct delay buffer [BLOCK_SWITCHING_OFFSET]*/ + Word32 sfbThresholdnm1[MAX_SFB]; /* PreEchoControl */ + Word16 mdctScalenm1; /* scale of last block's mdct (PreEchoControl) */ + + SFB_THRESHOLD sfbThreshold; /* adapt */ + SFB_ENERGY sfbEnergy; /* sfb Energy */ + SFB_ENERGY sfbEnergyMS; + SFB_ENERGY_SUM sfbEnergySum; + SFB_ENERGY_SUM sfbEnergySumMS; + SFB_ENERGY sfbSpreadedEnergy; + + Word32 *mdctSpectrum; /* mdct spectrum [FRAME_LEN_LONG] */ + Word16 mdctScale; /* scale of mdct */ +}PSY_DATA; /* Word16 size: 4 + 87 + 102 + 360 + 360 + 360 + 18 + 18 + 360 = 1669 */ + +#endif /* _PSY_DATA_H */ diff --git a/jni/inc/psy_main.h b/jni/inc/psy_main.h new file mode 100644 index 000000000..2ccac60b3 --- /dev/null +++ b/jni/inc/psy_main.h @@ -0,0 +1,69 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: psy_main.h + + Content: Psychoacoustic major function block + +*******************************************************************************/ + +#ifndef _PSYMAIN_H +#define _PSYMAIN_H + +#include "psy_configuration.h" +#include "qc_data.h" +#include "memalign.h" + +/* + psy kernel +*/ +typedef struct { + PSY_CONFIGURATION_LONG psyConfLong; /* Word16 size: 515 */ + PSY_CONFIGURATION_SHORT psyConfShort; /* Word16 size: 167 */ + PSY_DATA psyData[MAX_CHANNELS]; /* Word16 size: MAX_CHANNELS*1669*/ + TNS_DATA tnsData[MAX_CHANNELS]; /* Word16 size: MAX_CHANNELS*235 */ + Word32* pScratchTns; + Word16 sampleRateIdx; +}PSY_KERNEL; /* Word16 size: 2587 / 4491 */ + + +Word16 PsyNew( PSY_KERNEL *hPsy, Word32 nChan, VO_MEM_OPERATOR *pMemOP); +Word16 PsyDelete( PSY_KERNEL *hPsy, VO_MEM_OPERATOR *pMemOP); + +Word16 PsyOutNew( PSY_OUT *hPsyOut, VO_MEM_OPERATOR *pMemOP); +Word16 PsyOutDelete( PSY_OUT *hPsyOut, VO_MEM_OPERATOR *pMemOP); + +Word16 psyMainInit( PSY_KERNEL *hPsy, + Word32 sampleRate, + Word32 bitRate, + Word16 channels, + Word16 tnsMask, + Word16 bandwidth); + + +Word16 psyMain(Word16 nChannels, /*!< total number of channels */ + ELEMENT_INFO *elemInfo, + Word16 *timeSignal, /*!< interleaved time signal */ + PSY_DATA psyData[MAX_CHANNELS], + TNS_DATA tnsData[MAX_CHANNELS], + PSY_CONFIGURATION_LONG* psyConfLong, + PSY_CONFIGURATION_SHORT* psyConfShort, + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + PSY_OUT_ELEMENT *psyOutElement, + Word32 *pScratchTns, + Word32 sampleRate); + +#endif /* _PSYMAIN_H */ diff --git a/jni/inc/qc_data.h b/jni/inc/qc_data.h new file mode 100644 index 000000000..109922df0 --- /dev/null +++ b/jni/inc/qc_data.h @@ -0,0 +1,143 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: qc_data.h + + Content: Quantizing & coding structures + +*******************************************************************************/ + +#ifndef _QC_DATA_H +#define _QC_DATA_H + +#include "psy_const.h" +#include "dyn_bits.h" +#include "adj_thr_data.h" + + +#define MAX_MODES 10 + +typedef enum { + MODE_INVALID = 0, + MODE_1, /* mono */ + MODE_1_1, /* dual mono */ + MODE_2 /* stereo */ +} ENCODER_MODE; + +typedef enum { + ID_SCE=0, /* Single Channel Element */ + ID_CPE=1, /* Channel Pair Element */ + ID_CCE=2, /* Coupling Channel Element */ + ID_LFE=3, /* LFE Channel Element */ + ID_DSE=4, /* current one DSE element for ancillary is supported */ + ID_PCE=5, + ID_FIL=6, + ID_END=7 +}ELEMENT_TYPE; + +typedef struct { + ELEMENT_TYPE elType; + Word16 instanceTag; + Word16 nChannelsInEl; + Word16 ChannelIndex[MAX_CHANNELS]; +} ELEMENT_INFO; + +typedef struct { + Word32 paddingRest; +} PADDING; + + +/* Quantizing & coding stage */ + +struct QC_INIT{ + ELEMENT_INFO *elInfo; + Word16 maxBits; /* maximum number of bits in reservoir */ + Word16 averageBits; /* average number of bits we should use */ + Word16 bitRes; + Word16 meanPe; + Word32 chBitrate; + Word16 maxBitFac; + Word32 bitrate; + + PADDING padding; +}; + +typedef struct +{ + Word16 *quantSpec; /* [FRAME_LEN_LONG]; */ + UWord16 *maxValueInSfb; /* [MAX_GROUPED_SFB]; */ + Word16 *scf; /* [MAX_GROUPED_SFB]; */ + Word16 globalGain; + Word16 mdctScale; + Word16 groupingMask; + SECTION_DATA sectionData; + Word16 windowShape; +} QC_OUT_CHANNEL; + +typedef struct +{ + Word16 adtsUsed; + Word16 staticBitsUsed; /* for verification purposes */ + Word16 dynBitsUsed; /* for verification purposes */ + Word16 pe; + Word16 ancBitsUsed; + Word16 fillBits; +} QC_OUT_ELEMENT; + +typedef struct +{ + QC_OUT_CHANNEL qcChannel[MAX_CHANNELS]; + QC_OUT_ELEMENT qcElement; + Word16 totStaticBitsUsed; /* for verification purposes */ + Word16 totDynBitsUsed; /* for verification purposes */ + Word16 totAncBitsUsed; /* for verification purposes */ + Word16 totFillBits; + Word16 alignBits; + Word16 bitResTot; + Word16 averageBitsTot; +} QC_OUT; + +typedef struct { + Word32 chBitrate; + Word16 averageBits; /* brutto -> look ancillary.h */ + Word16 maxBits; + Word16 bitResLevel; + Word16 maxBitResBits; + Word16 relativeBits; /* Bits relative to total Bits scaled down by 2 */ +} ELEMENT_BITS; + +typedef struct +{ + /* this is basically struct QC_INIT */ + Word16 averageBitsTot; + Word16 maxBitsTot; + Word16 globStatBits; + Word16 nChannels; + Word16 bitResTot; + + Word16 maxBitFac; + + PADDING padding; + + ELEMENT_BITS elementBits; + ADJ_THR_STATE adjThr; + + Word16 logSfbFormFactor[MAX_CHANNELS][MAX_GROUPED_SFB]; + Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB]; + Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB]; +} QC_STATE; + +#endif /* _QC_DATA_H */ diff --git a/jni/inc/qc_main.h b/jni/inc/qc_main.h new file mode 100644 index 000000000..8f8397304 --- /dev/null +++ b/jni/inc/qc_main.h @@ -0,0 +1,64 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: qc_main.h + + Content: Quantizing & coding functions + +*******************************************************************************/ + +#ifndef _QC_MAIN_H +#define _QC_MAIN_H + +#include "qc_data.h" +#include "interface.h" +#include "memalign.h" + +/* Quantizing & coding stage */ + +Word16 QCOutNew(QC_OUT *hQC, Word16 nChannels, VO_MEM_OPERATOR *pMemOP); + +void QCOutDelete(QC_OUT *hQC, VO_MEM_OPERATOR *pMemOP); + +Word16 QCNew(QC_STATE *hQC, VO_MEM_OPERATOR *pMemOP); + +Word16 QCInit(QC_STATE *hQC, + struct QC_INIT *init); + +void QCDelete(QC_STATE *hQC, VO_MEM_OPERATOR *pMemOP); + + +Word16 QCMain(QC_STATE *hQC, + ELEMENT_BITS* elBits, + ATS_ELEMENT* adjThrStateElement, + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], /* may be modified in-place */ + PSY_OUT_ELEMENT* psyOutElement, + QC_OUT_CHANNEL qcOutChannel[MAX_CHANNELS], /* out */ + QC_OUT_ELEMENT* qcOutElement, + Word16 nChannels, + Word16 ancillaryDataBytes); /* returns error code */ + +void updateBitres(QC_STATE* qcKernel, + QC_OUT* qcOut); + +Word16 FinalizeBitConsumption(QC_STATE *hQC, + QC_OUT* qcOut); + +Word16 AdjustBitrate(QC_STATE *hQC, + Word32 bitRate, + Word32 sampleRate); + +#endif /* _QC_MAIN_H */ diff --git a/jni/inc/quantize.h b/jni/inc/quantize.h new file mode 100644 index 000000000..1cafef69c --- /dev/null +++ b/jni/inc/quantize.h @@ -0,0 +1,42 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: quantize.h + + Content: Quantization functions + +*******************************************************************************/ + +#ifndef _QUANTIZE_H_ +#define _QUANTIZE_H_ +#include "typedefs.h" + +/* quantizing */ + +#define MAX_QUANT 8191 + +void QuantizeSpectrum(Word16 sfbCnt, + Word16 maxSfbPerGroup, + Word16 sfbPerGroup, + Word16 *sfbOffset, Word32 *mdctSpectrum, + Word16 globalGain, Word16 *scalefactors, + Word16 *quantizedSpectrum); + +Word32 calcSfbDist(const Word32 *spec, + Word16 sfbWidth, + Word16 gain); + +#endif /* _QUANTIZE_H_ */ diff --git a/jni/inc/sf_estim.h b/jni/inc/sf_estim.h new file mode 100644 index 000000000..997eba5b8 --- /dev/null +++ b/jni/inc/sf_estim.h @@ -0,0 +1,46 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: sf_estim.h + + Content: Scale factor estimation functions + +*******************************************************************************/ + +#ifndef __SF_ESTIM_H__ +#define __SF_ESTIM_H__ +/* + Scale factor estimation + */ +#include "psy_const.h" +#include "interface.h" +#include "qc_data.h" + +void +CalcFormFactor(Word16 logSfbFormFactor[MAX_CHANNELS][MAX_GROUPED_SFB], + Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB], + Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + const Word16 nChannels); + +void +EstimateScaleFactors(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + QC_OUT_CHANNEL qcOutChannel[MAX_CHANNELS], + Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], + Word16 logSfbFormFactor[MAX_CHANNELS][MAX_GROUPED_SFB], + Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB], + const Word16 nChannels); +#endif diff --git a/jni/inc/spreading.h b/jni/inc/spreading.h new file mode 100644 index 000000000..0c96fc750 --- /dev/null +++ b/jni/inc/spreading.h @@ -0,0 +1,33 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: spreading.h + + Content: Spreading of energy functions + +*******************************************************************************/ + +#ifndef _SPREADING_H +#define _SPREADING_H +#include "typedefs.h" + + +void SpreadingMax(const Word16 pbCnt, + const Word16 *maskLowFactor, + const Word16 *maskHighFactor, + Word32 *pbSpreadedEnergy); + +#endif /* #ifndef _SPREADING_H */ diff --git a/jni/inc/stat_bits.h b/jni/inc/stat_bits.h new file mode 100644 index 000000000..9cddc1d54 --- /dev/null +++ b/jni/inc/stat_bits.h @@ -0,0 +1,34 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: stat_bits.h + + Content: Static bit counter functions + +*******************************************************************************/ + +#ifndef __STAT_BITS_H +#define __STAT_BITS_H + +#include "psy_const.h" +#include "interface.h" + +Word16 countStaticBitdemand(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + PSY_OUT_ELEMENT *psyOutElement, + Word16 nChannels, + Word16 adtsUsed); + +#endif /* __STAT_BITS_H */ diff --git a/jni/inc/tns.h b/jni/inc/tns.h new file mode 100644 index 000000000..40cfaee79 --- /dev/null +++ b/jni/inc/tns.h @@ -0,0 +1,108 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: tns.h + + Content: TNS structures + +*******************************************************************************/ + +#ifndef _TNS_H +#define _TNS_H + +#include "typedef.h" +#include "psy_const.h" + + + +#define TNS_MAX_ORDER 12 +#define TNS_MAX_ORDER_SHORT 5 + +#define FILTER_DIRECTION 0 + +typedef struct{ /*stuff that is tabulated dependent on bitrate etc. */ + Word16 threshOn; /* min. prediction gain for using tns TABUL * 100*/ + Word32 lpcStartFreq; /* lowest freq for lpc TABUL*/ + Word32 lpcStopFreq; /* TABUL */ + Word32 tnsTimeResolution; +}TNS_CONFIG_TABULATED; + + +typedef struct { /*assigned at InitTime*/ + Word16 tnsActive; + Word16 tnsMaxSfb; + + Word16 maxOrder; /* max. order of tns filter */ + Word16 tnsStartFreq; /* lowest freq. for tns filtering */ + Word16 coefRes; + + TNS_CONFIG_TABULATED confTab; + + Word32 acfWindow[TNS_MAX_ORDER+1]; + + Word16 tnsStartBand; + Word16 tnsStartLine; + + Word16 tnsStopBand; + Word16 tnsStopLine; + + Word16 lpcStartBand; + Word16 lpcStartLine; + + Word16 lpcStopBand; + Word16 lpcStopLine; + + Word16 tnsRatioPatchLowestCb; + Word16 tnsModifyBeginCb; + + Word16 threshold; /* min. prediction gain for using tns TABUL * 100 */ + +}TNS_CONFIG; + + +typedef struct { + Word16 tnsActive; + Word32 parcor[TNS_MAX_ORDER]; + Word16 predictionGain; +} TNS_SUBBLOCK_INFO; /* Word16 size: 26 */ + +typedef struct{ + TNS_SUBBLOCK_INFO subBlockInfo[TRANS_FAC]; +} TNS_DATA_SHORT; + +typedef struct{ + TNS_SUBBLOCK_INFO subBlockInfo; +} TNS_DATA_LONG; + +typedef struct{ + TNS_DATA_LONG tnsLong; + TNS_DATA_SHORT tnsShort; +}TNS_DATA_RAW; + +typedef struct{ + Word16 numOfSubblocks; + TNS_DATA_RAW dataRaw; +}TNS_DATA; /* Word16 size: 1 + 8*26 + 26 = 235 */ + +typedef struct{ + Word16 tnsActive[TRANS_FAC]; + Word16 coefRes[TRANS_FAC]; + Word16 length[TRANS_FAC]; + Word16 order[TRANS_FAC]; + Word16 coef[TRANS_FAC*TNS_MAX_ORDER_SHORT]; +}TNS_INFO; /* Word16 size: 72 */ + +#endif /* _TNS_H */ diff --git a/jni/inc/tns_func.h b/jni/inc/tns_func.h new file mode 100644 index 000000000..02df24de5 --- /dev/null +++ b/jni/inc/tns_func.h @@ -0,0 +1,75 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: tns_func.h + + Content: TNS functions + +*******************************************************************************/ + +/* + Temporal noise shaping + */ +#ifndef _TNS_FUNC_H +#define _TNS_FUNC_H +#include "typedef.h" +#include "psy_configuration.h" + +Word16 InitTnsConfigurationLong(Word32 bitrate, + Word32 samplerate, + Word16 channels, + TNS_CONFIG *tnsConfig, + PSY_CONFIGURATION_LONG *psyConfig, + Word16 active); + +Word16 InitTnsConfigurationShort(Word32 bitrate, + Word32 samplerate, + Word16 channels, + TNS_CONFIG *tnsConfig, + PSY_CONFIGURATION_SHORT *psyConfig, + Word16 active); + +Word32 TnsDetect(TNS_DATA* tnsData, + TNS_CONFIG tC, + Word32* pScratchTns, + const Word16 sfbOffset[], + Word32* spectrum, + Word16 subBlockNumber, + Word16 blockType, + Word32 * sfbEnergy); + +void TnsSync(TNS_DATA *tnsDataDest, + const TNS_DATA *tnsDataSrc, + const TNS_CONFIG tC, + const Word16 subBlockNumber, + const Word16 blockType); + +Word16 TnsEncode(TNS_INFO* tnsInfo, + TNS_DATA* tnsData, + Word16 numOfSfb, + TNS_CONFIG tC, + Word16 lowPassLine, + Word32* spectrum, + Word16 subBlockNumber, + Word16 blockType); + +void ApplyTnsMultTableToRatios(Word16 startCb, + Word16 stopCb, + TNS_SUBBLOCK_INFO subInfo, + Word32 *thresholds); + + +#endif /* _TNS_FUNC_H */ diff --git a/jni/inc/tns_param.h b/jni/inc/tns_param.h new file mode 100644 index 000000000..0aa33c353 --- /dev/null +++ b/jni/inc/tns_param.h @@ -0,0 +1,52 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: tns_param.h + + Content: TNS parameters + +*******************************************************************************/ + +/* + TNS parameters + */ +#ifndef _TNS_PARAM_H +#define _TNS_PARAM_H + +#include "tns.h" + +typedef struct{ + Word32 samplingRate; + Word16 maxBandLong; + Word16 maxBandShort; +}TNS_MAX_TAB_ENTRY; + +typedef struct{ + Word32 bitRateFrom; + Word32 bitRateTo; + const TNS_CONFIG_TABULATED *paramMono_Long; /* contains TNS parameters */ + const TNS_CONFIG_TABULATED *paramMono_Short; + const TNS_CONFIG_TABULATED *paramStereo_Long; + const TNS_CONFIG_TABULATED *paramStereo_Short; +}TNS_INFO_TAB; + + +void GetTnsParam(TNS_CONFIG_TABULATED *tnsConfigTab, + Word32 bitRate, Word16 channels, Word16 blockType); + +void GetTnsMaxBands(Word32 samplingRate, Word16 blockType, Word16* tnsMaxSfb); + +#endif /* _TNS_PARAM_H */ diff --git a/jni/inc/transform.h b/jni/inc/transform.h new file mode 100644 index 000000000..311cef5e1 --- /dev/null +++ b/jni/inc/transform.h @@ -0,0 +1,36 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: transform.h + + Content: MDCT Transform functions + +*******************************************************************************/ + +#ifndef __TRANSFORM_H__ +#define __TRANSFORM_H__ + +#include "typedef.h" + +void Transform_Real(Word16 *mdctDelayBuffer, + Word16 *timeSignal, + Word16 chIncrement, /*! channel increment */ + Word32 *realOut, + Word16 *mdctScale, + Word16 windowSequence + ); + +#endif diff --git a/jni/inc/typedef.h b/jni/inc/typedef.h new file mode 100644 index 000000000..b1f8225e4 --- /dev/null +++ b/jni/inc/typedef.h @@ -0,0 +1,63 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: typedef.h + + Content: type defined for defferent paltform + +*******************************************************************************/ + +#ifndef typedef_h +#define typedef_h "$Id $" + +#undef ORIGINAL_TYPEDEF_H /* define to get "original" ETSI version + of typedef.h */ + +#ifdef ORIGINAL_TYPEDEF_H +/* + * this is the original code from the ETSI file typedef.h + */ + +#if defined(__BORLANDC__) || defined(__WATCOMC__) || defined(_MSC_VER) || defined(__ZTC__) +typedef signed char Word8; +typedef short Word16; +typedef long Word32; +typedef int Flag; + +#elif defined(__sun) +typedef signed char Word8; +typedef short Word16; +typedef long Word32; +typedef int Flag; + +#elif defined(__unix__) || defined(__unix) +typedef signed char Word8; +typedef short Word16; +typedef int Word32; +typedef int Flag; + +#endif +#else /* not original typedef.h */ + +/* + * use (improved) type definition file typdefs.h and add a "Flag" type + */ +#include "typedefs.h" +typedef int Flag; + +#endif + +#endif diff --git a/jni/inc/typedefs.h b/jni/inc/typedefs.h new file mode 100644 index 000000000..29ff1e98f --- /dev/null +++ b/jni/inc/typedefs.h @@ -0,0 +1,187 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: typedefs.h + + Content: type defined or const defined + +*******************************************************************************/ + +#ifndef typedefs_h +#define typedefs_h "$Id $" + +#ifndef CHAR_BIT +#define CHAR_BIT 8 /* number of bits in a char */ +#endif + +#ifndef VOAAC_SHRT_MAX +#define VOAAC_SHRT_MAX (32767) /* maximum (signed) short value */ +#endif + +#ifndef VOAAC_SHRT_MIN +#define VOAAC_SHRT_MIN (-32768) /* minimum (signed) short value */ +#endif + +/* Define NULL pointer value */ +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef assert +#define assert(_Expression) ((void)0) +#endif + +#define __inline static __inline + +#define INT_BITS 32 +/* +******************************************************************************** +* DEFINITION OF CONSTANTS +******************************************************************************** +*/ +/* + ********* define char type + */ +typedef char Char; + +/* + ********* define 8 bit signed/unsigned types & constants + */ +typedef signed char Word8; +typedef unsigned char UWord8; +/* + ********* define 16 bit signed/unsigned types & constants + */ +typedef short Word16; +typedef unsigned short UWord16; + +/* + ********* define 32 bit signed/unsigned types & constants + */ +typedef int Word32; +typedef unsigned int UWord32; + + + +#ifndef _MSC_VER +typedef long long Word64; +typedef unsigned long long UWord64; +#else +typedef __int64 Word64; +typedef unsigned __int64 UWord64; +#endif + +#ifndef min +#define min(a,b) ( a < b ? a : b) +#endif + +#ifndef max +#define max(a,b) ( a > b ? a : b) +#endif + +#ifdef ARM_INASM +#ifdef ARMV5_INASM +#define ARMV5E_INASM 1 +#endif +#define ARMV4_INASM 1 +#endif + +#if ARMV4_INASM + #define ARMV5TE_SAT 1 + #define ARMV5TE_ADD 1 + #define ARMV5TE_SUB 1 + #define ARMV5TE_SHL 1 + #define ARMV5TE_SHR 1 + #define ARMV5TE_L_SHL 1 + #define ARMV5TE_L_SHR 1 +#endif//ARMV4 +#if ARMV5E_INASM + #define ARMV5TE_L_ADD 1 + #define ARMV5TE_L_SUB 1 + #define ARMV5TE_L_MULT 1 + #define ARMV5TE_L_MAC 1 + #define ARMV5TE_L_MSU 1 + + + #define ARMV5TE_DIV_S 1 + #define ARMV5TE_ROUND 1 + #define ARMV5TE_MULT 1 + + #define ARMV5TE_NORM_S 1 + #define ARMV5TE_NORM_L 1 + #define ARMV5TE_L_MPY_LS 1 +#endif +#if ARMV6_INASM + #undef ARMV5TE_ADD + #define ARMV5TE_ADD 0 + #undef ARMV5TE_SUB + #define ARMV5TE_SUB 0 + #define ARMV6_SAT 1 +#endif + +//basic operation functions optimization flags +#define SATRUATE_IS_INLINE 1 //define saturate as inline function +#define SHL_IS_INLINE 1 //define shl as inline function +#define SHR_IS_INLINE 1 //define shr as inline function +#define L_MULT_IS_INLINE 1 //define L_mult as inline function +#define L_MSU_IS_INLINE 1 //define L_msu as inline function +#define L_SUB_IS_INLINE 1 //define L_sub as inline function +#define L_SHL_IS_INLINE 1 //define L_shl as inline function +#define L_SHR_IS_INLINE 1 //define L_shr as inline function +#define ADD_IS_INLINE 1 //define add as inline function //add, inline is the best +#define SUB_IS_INLINE 1 //define sub as inline function //sub, inline is the best +#define DIV_S_IS_INLINE 1 //define div_s as inline function +#define MULT_IS_INLINE 1 //define mult as inline function +#define NORM_S_IS_INLINE 1 //define norm_s as inline function +#define NORM_L_IS_INLINE 1 //define norm_l as inline function +#define ROUND_IS_INLINE 1 //define round as inline function +#define L_MAC_IS_INLINE 1 //define L_mac as inline function +#define L_ADD_IS_INLINE 1 //define L_add as inline function +#define EXTRACT_H_IS_INLINE 1 //define extract_h as inline function +#define EXTRACT_L_IS_INLINE 1 //define extract_l as inline function //??? +#define MULT_R_IS_INLINE 1 //define mult_r as inline function +#define SHR_R_IS_INLINE 1 //define shr_r as inline function +#define MAC_R_IS_INLINE 1 //define mac_r as inline function +#define MSU_R_IS_INLINE 1 //define msu_r as inline function +#define L_SHR_R_IS_INLINE 1 //define L_shr_r as inline function + +#define PREFIX voAACEnc +#define LINK0(x, y, z) LINK1(x,y,z) +#define LINK1(x,y,z) x##y##z +#define ADD_PREFIX(func) LINK0(PREFIX, _, func) + +#define L_Extract ADD_PREFIX(L_Extract) +#define L_Comp ADD_PREFIX(L_Comp) +#define Mpy_32 ADD_PREFIX(Mpy_32) +#define Mpy_32_16 ADD_PREFIX(Mpy_32_16) +#define Div_32 ADD_PREFIX(Div_32) +#define iLog4 ADD_PREFIX(iLog4) +#define rsqrt ADD_PREFIX(rsqrt) +#define pow2_xy ADD_PREFIX(pow2_xy) +#define L_mpy_ls ADD_PREFIX(L_mpy_ls) +#define L_mpy_wx ADD_PREFIX(L_mpy_wx) +#define TnsEncode ADD_PREFIX(TnsEncode) +#define GetSRIndex ADD_PREFIX(GetSRIndex) +#define WriteBitstream ADD_PREFIX(WriteBitstream) + +#define mem_malloc ADD_PREFIX(mem_malloc) +#define mem_free ADD_PREFIX(mem_free) + +#endif diff --git a/jni/inc/voAAC.h b/jni/inc/voAAC.h new file mode 100644 index 000000000..9ecb14246 --- /dev/null +++ b/jni/inc/voAAC.h @@ -0,0 +1,74 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: voAAC.h + + Content: AAC codec APIs & data types + +*******************************************************************************/ + +#ifndef __voAAC_H__ +#define __voAAC_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "voAudio.h" + +/*! + * the frame type that the decoder supports + */ +typedef enum { + VOAAC_RAWDATA = 0, /*! */ + VOAMRWB_N_MODES = 9, /*!< Invalid mode */ + VOAMRWB_MODE_MAX = VO_MAX_ENUM_VALUE + +}VOAMRWBMODE; + +/*!* the frame format the codec supports*/ +typedef enum { + VOAMRWB_DEFAULT = 0, /*!< the frame type is the header (defined in RFC3267) + rawdata*/ + /*One word (2-byte) for sync word (0x6b21)*/ + /*One word (2-byte) for frame length N.*/ + /*N words (2-byte) containing N bits (bit 0 = 0x007f, bit 1 = 0x0081).*/ + VOAMRWB_ITU = 1, + /*One word (2-byte) for sync word (0x6b21).*/ + /*One word (2-byte) to indicate the frame type.*/ + /*One word (2-byte) to indicate the mode.*/ + /*N words (2-byte) containing N bits (bit 0 = 0xff81, bit 1 = 0x007f).*/ + VOAMRWB_RFC3267 = 2, /* see RFC 3267 */ + VOAMRWB_TMAX = VO_MAX_ENUM_VALUE +}VOAMRWBFRAMETYPE; + + +#define VO_PID_AMRWB_Module 0x42261000 +#define VO_PID_AMRWB_FORMAT (VO_PID_AMRWB_Module | 0x0002) +#define VO_PID_AMRWB_CHANNELS (VO_PID_AMRWB_Module | 0x0003) +#define VO_PID_AMRWB_SAMPLERATE (VO_PID_AMRWB_Module | 0x0004) +#define VO_PID_AMRWB_FRAMETYPE (VO_PID_AMRWB_Module | 0x0005) +#define VO_PID_AMRWB_MODE (VO_PID_AMRWB_Module | 0x0006) +#define VO_PID_AMRWB_DTX (VO_PID_AMRWB_Module | 0x0007) + +/** + * Get audio codec API interface + * \param pEncHandle [out] Return the AMRWB Encoder handle. + * \retval VO_ERR_OK Succeeded. + */ +VO_S32 VO_API voGetAMRWBEncAPI(VO_AUDIO_CODECAPI *pEncHandle); + + +#pragma pack(pop) +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif //__VOAMRWB_H__ + diff --git a/jni/inc/voAudio.h b/jni/inc/voAudio.h new file mode 100644 index 000000000..d8628eeae --- /dev/null +++ b/jni/inc/voAudio.h @@ -0,0 +1,173 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: voAudio.h + + Content: Audio types and functions + +*******************************************************************************/ + +#ifndef __voAudio_H__ +#define __voAudio_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "voIndex.h" +#include "voMem.h" + +#define VO_PID_AUDIO_BASE 0x42000000 /*!< The base param ID for AUDIO codec */ +#define VO_PID_AUDIO_FORMAT (VO_PID_AUDIO_BASE | 0X0001) /*!< The format data of audio in track */ +#define VO_PID_AUDIO_SAMPLEREATE (VO_PID_AUDIO_BASE | 0X0002) /*!< The sample rate of audio */ +#define VO_PID_AUDIO_CHANNELS (VO_PID_AUDIO_BASE | 0X0003) /*!< The channel of audio */ +#define VO_PID_AUDIO_BITRATE (VO_PID_AUDIO_BASE | 0X0004) /*!< The bit rate of audio */ +#define VO_PID_AUDIO_CHANNELMODE (VO_PID_AUDIO_BASE | 0X0005) /*!< The channel mode of audio */ + +#define VO_ERR_AUDIO_BASE 0x82000000 +#define VO_ERR_AUDIO_UNSCHANNEL VO_ERR_AUDIO_BASE | 0x0001 +#define VO_ERR_AUDIO_UNSSAMPLERATE VO_ERR_AUDIO_BASE | 0x0002 +#define VO_ERR_AUDIO_UNSFEATURE VO_ERR_AUDIO_BASE | 0x0003 + + +/** + *Enumeration used to define the possible audio coding formats. + */ +typedef enum VO_AUDIO_CODINGTYPE { + VO_AUDIO_CodingUnused = 0, /**< Placeholder value when coding is N/A */ + VO_AUDIO_CodingPCM, /**< Any variant of PCM coding */ + VO_AUDIO_CodingADPCM, /**< Any variant of ADPCM encoded data */ + VO_AUDIO_CodingAMRNB, /**< Any variant of AMR encoded data */ + VO_AUDIO_CodingAMRWB, /**< Any variant of AMR encoded data */ + VO_AUDIO_CodingAMRWBP, /**< Any variant of AMR encoded data */ + VO_AUDIO_CodingQCELP13, /**< Any variant of QCELP 13kbps encoded data */ + VO_AUDIO_CodingEVRC, /**< Any variant of EVRC encoded data */ + VO_AUDIO_CodingAAC, /**< Any variant of AAC encoded data, 0xA106 - ISO/MPEG-4 AAC, 0xFF - AAC */ + VO_AUDIO_CodingAC3, /**< Any variant of AC3 encoded data */ + VO_AUDIO_CodingFLAC, /**< Any variant of FLAC encoded data */ + VO_AUDIO_CodingMP1, /**< Any variant of MP1 encoded data */ + VO_AUDIO_CodingMP3, /**< Any variant of MP3 encoded data */ + VO_AUDIO_CodingOGG, /**< Any variant of OGG encoded data */ + VO_AUDIO_CodingWMA, /**< Any variant of WMA encoded data */ + VO_AUDIO_CodingRA, /**< Any variant of RA encoded data */ + VO_AUDIO_CodingMIDI, /**< Any variant of MIDI encoded data */ + VO_AUDIO_CodingDRA, /**< Any variant of dra encoded data */ + VO_AUDIO_CodingG729, /**< Any variant of dra encoded data */ + VO_AUDIO_Coding_MAX = VO_MAX_ENUM_VALUE +} VO_AUDIO_CODINGTYPE; + +/*! +* the channel type value +*/ +typedef enum { + VO_CHANNEL_CENTER = 1, /*!
InputUsed is total used input data size in byte. + * \retval VO_ERR_NONE Succeeded. + * VO_ERR_INPUT_BUFFER_SMALL. The input was finished or the input data was not enought. Continue to input + * data before next call. + */ + VO_U32 (VO_API * GetOutputData) (VO_HANDLE hCodec, VO_CODECBUFFER * pOutBuffer, VO_AUDIO_OUTPUTINFO * pOutInfo); + + /** + * Set the parameter for the specified param ID. + * \param hCodec [IN]] The codec handle which was created by Init function. + * \param uParamID [IN] The param ID. + * \param pData [IN] The param value. + * \retval VO_ERR_NONE Succeeded. + */ + VO_U32 (VO_API * SetParam) (VO_HANDLE hCodec, VO_S32 uParamID, VO_PTR pData); + + /** + * Get the parameter for the specified param ID. + * \param hCodec [IN]] The codec handle which was created by Init function. + * \param uParamID [IN] The param ID. + * \param pData [IN] The param value. + * \retval VO_ERR_NONE Succeeded. + */ + VO_U32 (VO_API * GetParam) (VO_HANDLE hCodec, VO_S32 uParamID, VO_PTR pData); + + /** + * Uninit the Codec. + * \param hCodec [IN]] The codec handle which was created by Init function. + * \retval VO_ERR_NONE Succeeded. + */ + VO_U32 (VO_API * Uninit) (VO_HANDLE hCodec); +} VO_AUDIO_CODECAPI; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // __voAudio_H__ diff --git a/jni/inc/voIndex.h b/jni/inc/voIndex.h new file mode 100644 index 000000000..320a2f82f --- /dev/null +++ b/jni/inc/voIndex.h @@ -0,0 +1,193 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: voIndex.h + + Content: module and ID definition + +*******************************************************************************/ + +#ifndef __voIndex_H__ +#define __voIndex_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "voType.h" + +/* Define the module ID */ +#define _MAKE_SOURCE_ID(id, name) \ +VO_INDEX_SRC_##name = _VO_INDEX_SOURCE | id, + +#define _MAKE_CODEC_ID(id, name) \ +VO_INDEX_DEC_##name = _VO_INDEX_DEC | id, \ +VO_INDEX_ENC_##name = _VO_INDEX_ENC | id, + +#define _MAKE_EFFECT_ID(id, name) \ +VO_INDEX_EFT_##name = _VO_INDEX_EFFECT | id, + +#define _MAKE_SINK_ID(id, name) \ +VO_INDEX_SNK_##name = _VO_INDEX_SINK | id, + +#define _MAKE_FILTER_ID(id, name) \ +VO_INDEX_FLT_##name = _VO_INDEX_FILTER | id, + +#define _MAKE_OMX_ID(id, name) \ +VO_INDEX_OMX_##name = _VO_INDEX_OMX | id, + +#define _MAKE_MFW_ID(id, name) \ +VO_INDEX_MFW_##name = _VO_INDEX_MFW | id, + +enum +{ + _VO_INDEX_SOURCE = 0x01000000, + _VO_INDEX_DEC = 0x02000000, + _VO_INDEX_ENC = 0x03000000, + _VO_INDEX_EFFECT = 0x04000000, + _VO_INDEX_SINK = 0x05000000, + _VO_INDEX_FILTER = 0x06000000, + _VO_INDEX_OMX = 0x07000000, + _VO_INDEX_MFW = 0x08000000, + + // define file parser modules + _MAKE_SOURCE_ID (0x010000, MP4) + _MAKE_SOURCE_ID (0x020000, AVI) + _MAKE_SOURCE_ID (0x030000, ASF) + _MAKE_SOURCE_ID (0x040000, REAL) + _MAKE_SOURCE_ID (0x050000, AUDIO) + _MAKE_SOURCE_ID (0x060000, FLASH) + _MAKE_SOURCE_ID (0x070000, OGG) + _MAKE_SOURCE_ID (0x080000, MKV) + + // define network source modules + _MAKE_SOURCE_ID (0x110000, RTSP) + _MAKE_SOURCE_ID (0x120000, HTTP) + + // define CMMB source modules + _MAKE_SOURCE_ID (0x200000, CMMB) + _MAKE_SOURCE_ID (0x210000, CMMB_INNO) + _MAKE_SOURCE_ID (0x220000, CMMB_TELE) + _MAKE_SOURCE_ID (0x230000, CMMB_SIANO) + + // define DVBT source modules + _MAKE_SOURCE_ID (0x300000, DVBT) + _MAKE_SOURCE_ID (0x310000, DVBT_DIBCOM) + + // define other source modules + _MAKE_SOURCE_ID (0x400000, ID3) + + // define video codec modules + _MAKE_CODEC_ID (0x010000, H264) + _MAKE_CODEC_ID (0x020000, MPEG4) + _MAKE_CODEC_ID (0x030000, H263) + _MAKE_CODEC_ID (0x040000, S263) + _MAKE_CODEC_ID (0x050000, RV) + _MAKE_CODEC_ID (0x060000, WMV) + _MAKE_CODEC_ID (0x070000, DIVX3) + _MAKE_CODEC_ID (0x080000, MJPEG) + _MAKE_CODEC_ID (0x090000, MPEG2) + _MAKE_CODEC_ID (0x0A0000, VP6) + + // define audio codec modules + _MAKE_CODEC_ID (0x210000, AAC) + _MAKE_CODEC_ID (0x220000, MP3) + _MAKE_CODEC_ID (0x230000, WMA) + _MAKE_CODEC_ID (0x240000, RA) + _MAKE_CODEC_ID (0x250000, AMRNB) + _MAKE_CODEC_ID (0x260000, AMRWB) + _MAKE_CODEC_ID (0x270000, AMRWBP) + _MAKE_CODEC_ID (0x280000, QCELP) + _MAKE_CODEC_ID (0x290000, EVRC) + _MAKE_CODEC_ID (0x2A0000, ADPCM) + _MAKE_CODEC_ID (0x2B0000, MIDI) + _MAKE_CODEC_ID (0x2C0000, AC3) + _MAKE_CODEC_ID (0x2D0000, FLAC) + _MAKE_CODEC_ID (0x2E0000, DRA) + _MAKE_CODEC_ID (0x2F0000, OGG) + _MAKE_CODEC_ID (0x300000, G729) + + // define image codec modules + _MAKE_CODEC_ID (0x410000, JPEG) + _MAKE_CODEC_ID (0x420000, GIF) + _MAKE_CODEC_ID (0x430000, PNG) + _MAKE_CODEC_ID (0x440000, TIF) + + // define effect modules + _MAKE_EFFECT_ID (0x010000, EQ) + + // define sink modules + _MAKE_SINK_ID (0x010000, VIDEO) + _MAKE_SINK_ID (0x020000, AUDIO) + _MAKE_SINK_ID (0x030000, CCRRR) + _MAKE_SINK_ID (0x040000, CCRRV) + + _MAKE_SINK_ID (0x110000, MP4) + _MAKE_SINK_ID (0x120000, AVI) + _MAKE_SINK_ID (0x130000, AFW) + + // define media frame module ID + _MAKE_MFW_ID (0x010000, VOMMPLAY) + _MAKE_MFW_ID (0x020000, VOMMREC) + _MAKE_MFW_ID (0x030000, VOME) +}; + + +/* define the error ID */ +#define VO_ERR_NONE 0x00000000 +#define VO_ERR_FINISH 0x00000001 +#define VO_ERR_BASE 0X80000000 +#define VO_ERR_FAILED 0x80000001 +#define VO_ERR_OUTOF_MEMORY 0x80000002 +#define VO_ERR_NOT_IMPLEMENT 0x80000003 +#define VO_ERR_INVALID_ARG 0x80000004 +#define VO_ERR_INPUT_BUFFER_SMALL 0x80000005 +#define VO_ERR_OUTPUT_BUFFER_SMALL 0x80000006 +#define VO_ERR_WRONG_STATUS 0x80000007 +#define VO_ERR_WRONG_PARAM_ID 0x80000008 +#define VO_ERR_LICENSE_ERROR 0x80000009 + +/* xxx is the module ID +#define VO_ERR_FAILED 0x8xxx0001 +#define VO_ERR_OUTOF_MEMORY 0x8xxx0002 +#define VO_ERR_NOT_IMPLEMENT 0x8xxx0003 +#define VO_ERR_INVALID_ARG 0x8xxx0004 +#define VO_ERR_INPUT_BUFFER_SMALL 0x8xxx0005 +#define VO_ERR_OUTPUT_BUFFER_SMALL 0x8xxx0006 +#define VO_ERR_WRONG_STATUS 0x8xxx0007 +#define VO_ERR_WRONG_PARAM_ID 0x8xxx0008 +#define VO_ERR_LICENSE_ERROR 0x8xxx0009 +// Module own error ID +#define VO_ERR_Module 0x8xxx0X00 +*/ + +#define VO_PID_COMMON_BASE 0x40000000 /*!< The base of common param ID */ +#define VO_PID_COMMON_QUERYMEM (VO_PID_COMMON_BASE | 0X0001) /*!< Query the memory needed; Reserved. */ +#define VO_PID_COMMON_INPUTTYPE (VO_PID_COMMON_BASE | 0X0002) /*!< Set or get the input buffer type. VO_INPUT_TYPE */ +#define VO_PID_COMMON_HASRESOURCE (VO_PID_COMMON_BASE | 0X0003) /*!< Query it has resource to be used. VO_U32 *, 1 have, 0 No */ +#define VO_PID_COMMON_HEADDATA (VO_PID_COMMON_BASE | 0X0004) /*!< Decoder track header data. VO_CODECBUFFER * */ +#define VO_PID_COMMON_FLUSH (VO_PID_COMMON_BASE | 0X0005) /*!< Flush the codec buffer. VO_U32 *, 1 Flush, 0 No * */ + +/* +// Module Param ID +#define VO_ID_Mdoule 0x0xxx1000 +*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // __voIndex_H__ diff --git a/jni/inc/voMem.h b/jni/inc/voMem.h new file mode 100644 index 000000000..8dfb634d5 --- /dev/null +++ b/jni/inc/voMem.h @@ -0,0 +1,65 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: voMem.h + + Content: memory functions & data structures + +*******************************************************************************/ + +#ifndef __voMem_H__ +#define __voMem_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "voIndex.h" + +typedef struct +{ + VO_S32 Size; /*!< Buffer stride */ + VO_S32 Flag; + VO_PTR VBuffer; /*!< user data pointer */ + VO_PTR PBuffer; /*!< user data pointer */ +} +VO_MEM_INFO; + +typedef struct VO_MEM_OPERATOR +{ + VO_U32 (VO_API * Alloc) (VO_S32 uID, VO_MEM_INFO * pMemInfo); + VO_U32 (VO_API * Free) (VO_S32 uID, VO_PTR pBuff); + VO_U32 (VO_API * Set) (VO_S32 uID, VO_PTR pBuff, VO_U8 uValue, VO_U32 uSize); + VO_U32 (VO_API * Copy) (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize); + VO_U32 (VO_API * Check) (VO_S32 uID, VO_PTR pBuffer, VO_U32 uSize); + VO_S32 (VO_API * Compare) (VO_S32 uID, VO_PTR pBuffer1, VO_PTR pBuffer2, VO_U32 uSize); + VO_U32 (VO_API * Move) (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize); +} VO_MEM_OPERATOR; + +#define voMemAlloc(pBuff, pMemOP, ID, nSize) \ +{ \ + VO_MEM_INFO voMemInfo; \ + voMemInfo.Size=nSize; \ + pMemOP->Alloc(ID, &voMemInfo); \ + pBuff=(VO_PBYTE)voMemInfo.VBuffer; \ +} + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // __voMem_H__ diff --git a/jni/inc/voType.h b/jni/inc/voType.h new file mode 100644 index 000000000..5f659ab05 --- /dev/null +++ b/jni/inc/voType.h @@ -0,0 +1,221 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: voType.h + + Content: data type definition + +*******************************************************************************/ +#ifndef __voType_H__ +#define __voType_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef _WIN32 +# define VO_API __cdecl +# define VO_CBI __stdcall +#else +# define VO_API +# define VO_CBI +#endif //_WIN32 + +/** VO_IN is used to identify inputs to an VO function. This designation + will also be used in the case of a pointer that points to a parameter + that is used as an output. */ +#ifndef VO_IN +#define VO_IN +#endif + +/** VO_OUT is used to identify outputs from an VO function. This + designation will also be used in the case of a pointer that points + to a parameter that is used as an input. */ +#ifndef VO_OUT +#define VO_OUT +#endif + +/** VO_INOUT is used to identify parameters that may be either inputs or + outputs from an VO function at the same time. This designation will + also be used in the case of a pointer that points to a parameter that + is used both as an input and an output. */ +#ifndef VO_INOUT +#define VO_INOUT +#endif + +#define VO_MAX_ENUM_VALUE 0X7FFFFFFF + +/** VO_VOID */ +typedef void VO_VOID; + +/** VO_U8 is an 8 bit unsigned quantity that is byte aligned */ +typedef unsigned char VO_U8; + +/** VO_BYTE is an 8 bit unsigned quantity that is byte aligned */ +typedef unsigned char VO_BYTE; + +/** VO_S8 is an 8 bit signed quantity that is byte aligned */ +typedef signed char VO_S8; + +/** VO_CHAR is an 8 bit signed quantity that is byte aligned */ +typedef char VO_CHAR; + +/** VO_U16 is a 16 bit unsigned quantity that is 16 bit word aligned */ +typedef unsigned short VO_U16; + +/** VO_WCHAR is a 16 bit unsigned quantity that is 16 bit word aligned */ +#if defined _WIN32 +typedef unsigned short VO_WCHAR; +typedef unsigned short* VO_PWCHAR; +#elif defined LINUX +typedef unsigned char VO_WCHAR; +typedef unsigned char* VO_PWCHAR; +#endif + +/** VO_S16 is a 16 bit signed quantity that is 16 bit word aligned */ +typedef signed short VO_S16; + +/** VO_U32 is a 32 bit unsigned quantity that is 32 bit word aligned */ +typedef unsigned long VO_U32; + +/** VO_S32 is a 32 bit signed quantity that is 32 bit word aligned */ +typedef signed long VO_S32; + +/* Users with compilers that cannot accept the "long long" designation should + define the VO_SKIP64BIT macro. It should be noted that this may cause + some components to fail to compile if the component was written to require + 64 bit integral types. However, these components would NOT compile anyway + since the compiler does not support the way the component was written. +*/ +#ifndef VO_SKIP64BIT +#ifdef _MSC_VER +/** VO_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */ +typedef unsigned __int64 VO_U64; +/** VO_S64 is a 64 bit signed quantity that is 64 bit word aligned */ +typedef signed __int64 VO_S64; +#else // WIN32 +/** VO_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */ +typedef unsigned long long VO_U64; +/** VO_S64 is a 64 bit signed quantity that is 64 bit word aligned */ +typedef signed long long VO_S64; +#endif // WIN32 +#endif // VO_SKIP64BIT + +/** The VO_BOOL type is intended to be used to represent a true or a false + value when passing parameters to and from the VO core and components. The + VO_BOOL is a 32 bit quantity and is aligned on a 32 bit word boundary. + */ +typedef enum VO_BOOL { + VO_FALSE = 0, + VO_TRUE = !VO_FALSE, + VO_BOOL_MAX = VO_MAX_ENUM_VALUE +} VO_BOOL; + +/** The VO_PTR type is intended to be used to pass pointers between the VO + applications and the VO Core and components. This is a 32 bit pointer and + is aligned on a 32 bit boundary. + */ +typedef void* VO_PTR; + +/** The VO_HANDLE type is intended to be used to pass pointers between the VO + applications and the VO Core and components. This is a 32 bit pointer and + is aligned on a 32 bit boundary. + */ +typedef void* VO_HANDLE; + +/** The VO_STRING type is intended to be used to pass "C" type strings between + the application and the core and component. The VO_STRING type is a 32 + bit pointer to a zero terminated string. The pointer is word aligned and + the string is byte aligned. + */ +typedef char* VO_PCHAR; + +/** The VO_PBYTE type is intended to be used to pass arrays of bytes such as + buffers between the application and the component and core. The VO_PBYTE + type is a 32 bit pointer to a zero terminated string. The pointer is word + aligned and the string is byte aligned. + */ +typedef unsigned char* VO_PBYTE; + +/** The VO_PTCHAR type is intended to be used to pass arrays of wchar such as + unicode char between the application and the component and core. The VO_PTCHAR + type is a 32 bit pointer to a zero terminated string. The pointer is word + aligned and the string is byte aligned. + */ +/* +#if !defined LINUX +typedef unsigned short* VO_PTCHAR; +typedef unsigned short* VO_TCHAR; +#else +typedef char* VO_PTCHAR; +typedef char VO_TCHAR; +#endif +*/ + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +/** + * Input stream format, Frame or Stream.. + */ +typedef enum { + VO_INPUT_FRAME = 1, /*!< Input contains completely frame(s) data. */ + VO_INPUT_STREAM, /*!< Input is stream data. */ + VO_INPUT_STREAM_MAX = VO_MAX_ENUM_VALUE +} VO_INPUT_TYPE; + + +/** + * General data buffer, used as input or output. + */ +typedef struct { + VO_PBYTE Buffer; /*!< Buffer pointer */ + VO_U32 Length; /*!< Buffer size in byte */ + VO_S64 Time; /*!< The time of the buffer */ +} VO_CODECBUFFER; + + +/** + * The init memdata flag. + */ +typedef enum{ + VO_IMF_USERMEMOPERATOR =0, /*!< memData is the pointer of memoperator function*/ + VO_IMF_PREALLOCATEDBUFFER =1, /*!< memData is preallocated memory*/ + VO_IMF_MAX = VO_MAX_ENUM_VALUE +}VO_INIT_MEM_FlAG; + + +/** + * The init memory structure.. + */ +typedef struct{ + VO_INIT_MEM_FlAG memflag; /*!memflag != VO_IMF_USERMEMOPERATOR || pUserData->memData == NULL ) + { +#ifdef USE_DEAULT_MEM + voMemoprator.Alloc = cmnMemAlloc; + voMemoprator.Copy = cmnMemCopy; + voMemoprator.Free = cmnMemFree; + voMemoprator.Set = cmnMemSet; + voMemoprator.Check = cmnMemCheck; + + interMem = 1; + + pMemOP = &voMemoprator; +#else + *phCodec = NULL; + return VO_ERR_INVALID_ARG; +#endif + } + else + { + pMemOP = (VO_MEM_OPERATOR *)pUserData->memData; + } + + /* init the aac encoder handle */ + hAacEnc = (AAC_ENCODER*)mem_malloc(pMemOP, sizeof(AAC_ENCODER), 32, VO_INDEX_ENC_AAC); + if(NULL == hAacEnc) + { + error = 1; + } + + if(!error) + { + /* init the aac encoder intra memory */ + hAacEnc->intbuf = (short *)mem_malloc(pMemOP, AACENC_BLOCKSIZE*MAX_CHANNELS*sizeof(short), 32, VO_INDEX_ENC_AAC); + if(NULL == hAacEnc->intbuf) + { + error = 1; + } + } + + if (!error) { + /* init the aac encoder psychoacoustic */ + error = (PsyNew(&hAacEnc->psyKernel, MAX_CHANNELS, pMemOP) || + PsyOutNew(&hAacEnc->psyOut, pMemOP)); + } + + if (!error) { + /* init the aac encoder quantization elements */ + error = QCOutNew(&hAacEnc->qcOut,MAX_CHANNELS, pMemOP); + } + + if (!error) { + /* init the aac encoder quantization state */ + error = QCNew(&hAacEnc->qcKernel, pMemOP); + } + + /* uninit the aac encoder if error is nozero */ + if(error) + { + AacEncClose(hAacEnc, pMemOP); + if(hAacEnc) + { + mem_free(pMemOP, hAacEnc, VO_INDEX_ENC_AAC); + hAacEnc = NULL; + } + *phCodec = NULL; + return VO_ERR_OUTOF_MEMORY; + } + + /* init the aac encoder memory operator */ +#ifdef USE_DEAULT_MEM + if(interMem) + { + hAacEnc->voMemoprator.Alloc = cmnMemAlloc; + hAacEnc->voMemoprator.Copy = cmnMemCopy; + hAacEnc->voMemoprator.Free = cmnMemFree; + hAacEnc->voMemoprator.Set = cmnMemSet; + hAacEnc->voMemoprator.Check = cmnMemCheck; + + pMemOP = &hAacEnc->voMemoprator; + } +#endif + /* init the aac encoder default parameter */ + if(hAacEnc->initOK == 0) + { + AACENC_CONFIG config; + config.adtsUsed = 1; + config.bitRate = 128000; + config.nChannelsIn = 2; + config.nChannelsOut = 2; + config.sampleRate = 44100; + config.bandWidth = 20000; + + AacEncOpen(hAacEnc, config); + } + + hAacEnc->voMemop = pMemOP; + + *phCodec = hAacEnc; + + return VO_ERR_NONE; +} + +/** +* Set input audio data. +* \param hCodec [IN]] The Codec Handle which was created by Init function. +* \param pInput [IN] The input buffer param. +* \param pOutBuffer [OUT] The output buffer info. +* \retval VO_ERR_NONE Succeeded. +*/ +VO_U32 VO_API voAACEncSetInputData(VO_HANDLE hCodec, VO_CODECBUFFER * pInput) +{ + AAC_ENCODER *hAacEnc; + int length; + + if(NULL == hCodec || NULL == pInput || NULL == pInput->Buffer) + { + return VO_ERR_INVALID_ARG; + } + + hAacEnc = (AAC_ENCODER *)hCodec; + + /* init input pcm buffer and length*/ + hAacEnc->inbuf = (short *)pInput->Buffer; + hAacEnc->inlen = pInput->Length / sizeof(short); + hAacEnc->uselength = 0; + + hAacEnc->encbuf = hAacEnc->inbuf; + hAacEnc->enclen = hAacEnc->inlen; + + /* rebuild intra pcm buffer and length*/ + if(hAacEnc->intlen) + { + length = min(hAacEnc->config.nChannelsIn*AACENC_BLOCKSIZE - hAacEnc->intlen, hAacEnc->inlen); + hAacEnc->voMemop->Copy(VO_INDEX_ENC_AAC, hAacEnc->intbuf + hAacEnc->intlen, + hAacEnc->inbuf, length*sizeof(short)); + + hAacEnc->encbuf = hAacEnc->intbuf; + hAacEnc->enclen = hAacEnc->intlen + length; + + hAacEnc->inbuf += length; + hAacEnc->inlen -= length; + } + + return VO_ERR_NONE; +} + +/** +* Get the outut audio data +* \param hCodec [IN]] The Codec Handle which was created by Init function. +* \param pOutBuffer [OUT] The output audio data +* \param pOutInfo [OUT] The dec module filled audio format and used the input size. +* pOutInfo->InputUsed is total used the input size. +* \retval VO_ERR_NONE Succeeded. +* VO_ERR_INPUT_BUFFER_SMALL. The input was finished or the input data was not enought. +*/ +VO_U32 VO_API voAACEncGetOutputData(VO_HANDLE hCodec, VO_CODECBUFFER * pOutput, VO_AUDIO_OUTPUTINFO * pOutInfo) +{ + AAC_ENCODER* hAacEnc = (AAC_ENCODER*)hCodec; + Word16 numAncDataBytes=0; + Word32 inbuflen; + int ret, length; + if(NULL == hAacEnc) + return VO_ERR_INVALID_ARG; + + inbuflen = AACENC_BLOCKSIZE*hAacEnc->config.nChannelsIn; + + /* check the input pcm buffer and length*/ + if(NULL == hAacEnc->encbuf || hAacEnc->enclen < inbuflen) + { + length = hAacEnc->enclen; + if(hAacEnc->intlen == 0) + { + hAacEnc->voMemop->Copy(VO_INDEX_ENC_AAC, hAacEnc->intbuf, + hAacEnc->encbuf, length*sizeof(short)); + hAacEnc->uselength += length*sizeof(short); + } + else + { + hAacEnc->uselength += (length - hAacEnc->intlen)*sizeof(short); + } + + hAacEnc->intlen = length; + + pOutput->Length = 0; + if(pOutInfo) + pOutInfo->InputUsed = hAacEnc->uselength; + return VO_ERR_INPUT_BUFFER_SMALL; + } + + /* check the output aac buffer and length*/ + if(NULL == pOutput || NULL == pOutput->Buffer || pOutput->Length < (6144/8)*hAacEnc->config.nChannelsOut/(sizeof(Word32))) + return VO_ERR_OUTPUT_BUFFER_SMALL; + + /* aac encoder core function */ + AacEncEncode( hAacEnc, + (Word16*)hAacEnc->encbuf, + NULL, + &numAncDataBytes, + pOutput->Buffer, + &pOutput->Length); + + /* update the input pcm buffer and length*/ + if(hAacEnc->intlen) + { + length = inbuflen - hAacEnc->intlen; + hAacEnc->encbuf = hAacEnc->inbuf; + hAacEnc->enclen = hAacEnc->inlen; + hAacEnc->uselength += length*sizeof(short); + hAacEnc->intlen = 0; + } + else + { + hAacEnc->encbuf = hAacEnc->encbuf + inbuflen; + hAacEnc->enclen = hAacEnc->enclen - inbuflen; + hAacEnc->uselength += inbuflen*sizeof(short); + } + + /* update the output aac information */ + if(pOutInfo) + { + pOutInfo->Format.Channels = hAacEnc->config.nChannelsOut; + pOutInfo->Format.SampleRate = hAacEnc->config.sampleRate; + pOutInfo->Format.SampleBits = 16; + pOutInfo->InputUsed = hAacEnc->uselength; + } + + return VO_ERR_NONE; +} + +/** +* Uninit the Codec. +* \param hCodec [IN]] The Codec Handle which was created by Init function. +* \retval VO_ERR_NONE Succeeded. +*/ +VO_U32 VO_API voAACEncUninit(VO_HANDLE hCodec) +{ + AAC_ENCODER* hAacEnc = (AAC_ENCODER*)hCodec; + + if(NULL != hAacEnc) + { + /* close the aac encoder */ + AacEncClose(hAacEnc, hAacEnc->voMemop); + + /* free the aac encoder handle*/ + mem_free(hAacEnc->voMemop, hAacEnc, VO_INDEX_ENC_AAC); + hAacEnc = NULL; + } + + return VO_ERR_NONE; +} + +/** +* Set the param for special target. +* \param hCodec [IN]] The Codec Handle which was created by Init function. +* \param uParamID [IN] The param ID. +* \param pData [IN] The param value depend on the ID> +* \retval VO_ERR_NONE Succeeded. +*/ +VO_U32 VO_API voAACEncSetParam(VO_HANDLE hCodec, VO_S32 uParamID, VO_PTR pData) +{ + AACENC_CONFIG config; + AACENC_PARAM* pAAC_param; + VO_AUDIO_FORMAT *pWAV_Format; + AAC_ENCODER* hAacEnc = (AAC_ENCODER*)hCodec; + int ret, i, bitrate, tmp; + int SampleRateIdx; + + if(NULL == hAacEnc) + return VO_ERR_INVALID_ARG; + + switch(uParamID) + { + case VO_PID_AAC_ENCPARAM: /* init aac encoder parameter*/ + AacInitDefaultConfig(&config); + if(pData == NULL) + return VO_ERR_INVALID_ARG; + pAAC_param = (AACENC_PARAM*)pData; + config.adtsUsed = pAAC_param->adtsUsed; + config.bitRate = pAAC_param->bitRate; + config.nChannelsIn = pAAC_param->nChannels; + config.nChannelsOut = pAAC_param->nChannels; + config.sampleRate = pAAC_param->sampleRate; + + /* check the channel */ + if(config.nChannelsIn< 1 || config.nChannelsIn > MAX_CHANNELS || + config.nChannelsOut < 1 || config.nChannelsOut > MAX_CHANNELS || config.nChannelsIn < config.nChannelsOut) + return VO_ERR_AUDIO_UNSCHANNEL; + + /* check the samplerate */ + ret = -1; + for(i = 0; i < NUM_SAMPLE_RATES; i++) + { + if(config.sampleRate == sampRateTab[i]) + { + ret = 0; + break; + } + } + if(ret < 0) + return VO_ERR_AUDIO_UNSSAMPLERATE; + + SampleRateIdx = i; + + tmp = 441; + if(config.sampleRate%8000 == 0) + tmp =480; + /* check the bitrate */ + if(config.bitRate!=0 && (config.bitRate/config.nChannelsOut < 4000) || + (config.bitRate/config.nChannelsOut > 160000) || + (config.bitRate > config.sampleRate*6*config.nChannelsOut)) + { + config.bitRate = 640*config.sampleRate/tmp*config.nChannelsOut; + + if(config.bitRate/config.nChannelsOut < 4000) + config.bitRate = 4000 * config.nChannelsOut; + else if(config.bitRate > config.sampleRate*6*config.nChannelsOut) + config.bitRate = config.sampleRate*6*config.nChannelsOut; + else if(config.bitRate/config.nChannelsOut > 160000) + config.bitRate = config.nChannelsOut*160000; + } + + /* check the bandwidth */ + bitrate = config.bitRate / config.nChannelsOut; + bitrate = bitrate * tmp / config.sampleRate; + + for (i = 0; rates[i]; i++) + { + if (rates[i] >= bitrate) + break; + } + + config.bandWidth = BandwithCoefTab[i][SampleRateIdx]; + + /* init aac encoder core */ + ret = AacEncOpen(hAacEnc, config); + if(ret) + return VO_ERR_AUDIO_UNSFEATURE; + break; + case VO_PID_AUDIO_FORMAT: /* init pcm channel and samplerate*/ + AacInitDefaultConfig(&config); + if(pData == NULL) + return VO_ERR_INVALID_ARG; + pWAV_Format = (VO_AUDIO_FORMAT*)pData; + config.adtsUsed = 1; + config.nChannelsIn = pWAV_Format->Channels; + config.nChannelsOut = pWAV_Format->Channels; + config.sampleRate = pWAV_Format->SampleRate; + + /* check the channel */ + if(config.nChannelsIn< 1 || config.nChannelsIn > MAX_CHANNELS || + config.nChannelsOut < 1 || config.nChannelsOut > MAX_CHANNELS || config.nChannelsIn < config.nChannelsOut) + return VO_ERR_AUDIO_UNSCHANNEL; + + /* check the samplebits */ + if(pWAV_Format->SampleBits != 16) + { + return VO_ERR_AUDIO_UNSFEATURE; + } + + /* check the samplerate */ + ret = -1; + for(i = 0; i < NUM_SAMPLE_RATES; i++) + { + if(config.sampleRate == sampRateTab[i]) + { + ret = 0; + break; + } + } + if(ret < 0) + return VO_ERR_AUDIO_UNSSAMPLERATE; + + SampleRateIdx = i; + + /* update the bitrates */ + tmp = 441; + if(config.sampleRate%8000 == 0) + tmp =480; + + config.bitRate = 640*config.sampleRate/tmp*config.nChannelsOut; + + if(config.bitRate/config.nChannelsOut < 4000) + config.bitRate = 4000 * config.nChannelsOut; + else if(config.bitRate > config.sampleRate*6*config.nChannelsOut) + config.bitRate = config.sampleRate*6*config.nChannelsOut; + else if(config.bitRate/config.nChannelsOut > 160000) + config.bitRate = config.nChannelsOut*160000; + + /* check the bandwidth */ + bitrate = config.bitRate / config.nChannelsOut; + bitrate = bitrate * tmp / config.sampleRate; + + for (i = 0; rates[i]; i++) + { + if (rates[i] >= bitrate) + break; + } + + config.bandWidth = BandwithCoefTab[i][SampleRateIdx]; + + /* init aac encoder core */ + ret = AacEncOpen(hAacEnc, config); + if(ret) + return VO_ERR_AUDIO_UNSFEATURE; + break; + default: + return VO_ERR_WRONG_PARAM_ID; + } + + return VO_ERR_NONE; +} + +/** +* Get the param for special target. +* \param hCodec [IN]] The Codec Handle which was created by Init function. +* \param uParamID [IN] The param ID. +* \param pData [IN] The param value depend on the ID> +* \retval VO_ERR_NONE Succeeded. +*/ +VO_U32 VO_API voAACEncGetParam(VO_HANDLE hCodec, VO_S32 uParamID, VO_PTR pData) +{ + return VO_ERR_NONE; +} + +/** + * Get audio codec API interface + * \param pEncHandle [out] Return the AAC Encoder handle. + * \retval VO_ERR_OK Succeeded. + */ +VO_S32 VO_API voGetAACEncAPI(VO_AUDIO_CODECAPI * pDecHandle) +{ + if(pDecHandle == NULL) + return VO_ERR_INVALID_ARG; + + pDecHandle->Init = voAACEncInit; + pDecHandle->SetInputData = voAACEncSetInputData; + pDecHandle->GetOutputData = voAACEncGetOutputData; + pDecHandle->SetParam = voAACEncSetParam; + pDecHandle->GetParam = voAACEncGetParam; + pDecHandle->Uninit = voAACEncUninit; + + return VO_ERR_NONE; +} diff --git a/jni/src/aacenc_core.c b/jni/src/aacenc_core.c new file mode 100644 index 000000000..cecbc8f10 --- /dev/null +++ b/jni/src/aacenc_core.c @@ -0,0 +1,239 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: aacenc_core.c + + Content: aac encoder core functions + +*******************************************************************************/ + +#include "typedef.h" +#include "aacenc_core.h" +#include "bitenc.h" + +#include "psy_configuration.h" +#include "psy_main.h" +#include "qc_main.h" +#include "psy_main.h" +#include "channel_map.h" +#include "aac_rom.h" + +/******************************************************************************** +* +* function name: AacInitDefaultConfig +* description: gives reasonable default configuration +* +**********************************************************************************/ +void AacInitDefaultConfig(AACENC_CONFIG *config) +{ + /* default configurations */ + config->adtsUsed = 1; + config->nChannelsIn = 2; + config->nChannelsOut = 2; + config->bitRate = 128000; + config->bandWidth = 0; +} + +/******************************************************************************** +* +* function name: AacEncOpen +* description: allocate and initialize a new encoder instance +* returns: 0 if success +* +**********************************************************************************/ +Word16 AacEncOpen( AAC_ENCODER* hAacEnc, /* pointer to an encoder handle, initialized on return */ + const AACENC_CONFIG config /* pre-initialized config struct */ + ) +{ + Word32 i; + Word32 error = 0; + Word16 profile = 1; + + ELEMENT_INFO *elInfo = NULL; + + if (hAacEnc==0) { + error=1; + } + + if (!error) { + hAacEnc->config = config; + } + + if (!error) { + error = InitElementInfo (config.nChannelsOut, + &hAacEnc->elInfo); + } + + if (!error) { + elInfo = &hAacEnc->elInfo; + } + + if (!error) { + /* use or not tns tool for long and short block */ + Word16 tnsMask=3; + + /* init encoder psychoacoustic */ + error = psyMainInit(&hAacEnc->psyKernel, + config.sampleRate, + config.bitRate, + elInfo->nChannelsInEl, + tnsMask, + hAacEnc->config.bandWidth); + } + + /* use or not adts header */ + if(!error) { + hAacEnc->qcOut.qcElement.adtsUsed = config.adtsUsed; + } + + /* init encoder quantization */ + if (!error) { + struct QC_INIT qcInit; + + /*qcInit.channelMapping = &hAacEnc->channelMapping;*/ + qcInit.elInfo = &hAacEnc->elInfo; + + qcInit.maxBits = (Word16) (MAXBITS_COEF*elInfo->nChannelsInEl); + qcInit.bitRes = qcInit.maxBits; + qcInit.averageBits = (Word16) ((config.bitRate * FRAME_LEN_LONG) / config.sampleRate); + + qcInit.padding.paddingRest = config.sampleRate; + + qcInit.meanPe = (Word16) ((10 * FRAME_LEN_LONG * hAacEnc->config.bandWidth) / + (config.sampleRate>>1)); + + qcInit.maxBitFac = (Word16) ((100 * (MAXBITS_COEF-MINBITS_COEF)* elInfo->nChannelsInEl)/ + (qcInit.averageBits?qcInit.averageBits:1)); + + qcInit.bitrate = config.bitRate; + + error = QCInit(&hAacEnc->qcKernel, &qcInit); + } + + /* init bitstream encoder */ + if (!error) { + hAacEnc->bseInit.nChannels = elInfo->nChannelsInEl; + hAacEnc->bseInit.bitrate = config.bitRate; + hAacEnc->bseInit.sampleRate = config.sampleRate; + hAacEnc->bseInit.profile = profile; + } + + return error; +} + +/******************************************************************************** +* +* function name: AacEncEncode +* description: encode pcm to aac data core function +* returns: 0 if success +* +**********************************************************************************/ +Word16 AacEncEncode(AAC_ENCODER *aacEnc, /*!< an encoder handle */ + Word16 *timeSignal, /*!< BLOCKSIZE*nChannels audio samples, interleaved */ + const UWord8 *ancBytes, /*!< pointer to ancillary data bytes */ + Word16 *numAncBytes, /*!< number of ancillary Data Bytes */ + UWord8 *outBytes, /*!< pointer to output buffer (must be large MINBITS_COEF/8*MAX_CHANNELS bytes) */ + VO_U32 *numOutBytes /*!< number of bytes in output buffer after processing */ + ) +{ + ELEMENT_INFO *elInfo = &aacEnc->elInfo; + Word16 globUsedBits; + Word16 ancDataBytes, ancDataBytesLeft; + + ancDataBytes = ancDataBytesLeft = *numAncBytes; + + /* init output aac data buffer and length */ + aacEnc->hBitStream = CreateBitBuffer(&aacEnc->bitStream, outBytes, *numOutBytes); + + /* psychoacoustic process */ + psyMain(aacEnc->config.nChannelsOut, + elInfo, + timeSignal, + &aacEnc->psyKernel.psyData[elInfo->ChannelIndex[0]], + &aacEnc->psyKernel.tnsData[elInfo->ChannelIndex[0]], + &aacEnc->psyKernel.psyConfLong, + &aacEnc->psyKernel.psyConfShort, + &aacEnc->psyOut.psyOutChannel[elInfo->ChannelIndex[0]], + &aacEnc->psyOut.psyOutElement, + aacEnc->psyKernel.pScratchTns, + aacEnc->config.sampleRate); + + /* adjust bitrate and frame length */ + AdjustBitrate(&aacEnc->qcKernel, + aacEnc->config.bitRate, + aacEnc->config.sampleRate); + + /* quantization and coding process */ + QCMain(&aacEnc->qcKernel, + &aacEnc->qcKernel.elementBits, + &aacEnc->qcKernel.adjThr.adjThrStateElem, + &aacEnc->psyOut.psyOutChannel[elInfo->ChannelIndex[0]], + &aacEnc->psyOut.psyOutElement, + &aacEnc->qcOut.qcChannel[elInfo->ChannelIndex[0]], + &aacEnc->qcOut.qcElement, + elInfo->nChannelsInEl, + min(ancDataBytesLeft,ancDataBytes)); + + ancDataBytesLeft = ancDataBytesLeft - ancDataBytes; + + globUsedBits = FinalizeBitConsumption(&aacEnc->qcKernel, + &aacEnc->qcOut); + + /* write bitstream process */ + WriteBitstream(aacEnc->hBitStream, + *elInfo, + &aacEnc->qcOut, + &aacEnc->psyOut, + &globUsedBits, + ancBytes, + aacEnc->psyKernel.sampleRateIdx); + + updateBitres(&aacEnc->qcKernel, + &aacEnc->qcOut); + + /* write out the bitstream */ + *numOutBytes = GetBitsAvail(aacEnc->hBitStream) >> 3; + + return 0; +} + + +/******************************************************************************** +* +* function name:AacEncClose +* description: deallocate an encoder instance +* +**********************************************************************************/ +void AacEncClose (AAC_ENCODER* hAacEnc, VO_MEM_OPERATOR *pMemOP) +{ + if (hAacEnc) { + QCDelete(&hAacEnc->qcKernel, pMemOP); + + QCOutDelete(&hAacEnc->qcOut, pMemOP); + + PsyDelete(&hAacEnc->psyKernel, pMemOP); + + PsyOutDelete(&hAacEnc->psyOut, pMemOP); + + DeleteBitBuffer(&hAacEnc->hBitStream); + + if(hAacEnc->intbuf) + { + mem_free(pMemOP, hAacEnc->intbuf, VO_INDEX_ENC_AAC); + hAacEnc->intbuf = NULL; + } + } +} diff --git a/jni/src/adj_thr.c b/jni/src/adj_thr.c new file mode 100644 index 000000000..07b33b7ff --- /dev/null +++ b/jni/src/adj_thr.c @@ -0,0 +1,1225 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: adj_thr.c + + Content: Threshold compensation functions + +*******************************************************************************/ + +#include "basic_op.h" +#include "oper_32b.h" +#include "adj_thr_data.h" +#include "adj_thr.h" +#include "qc_data.h" +#include "line_pe.h" +#include + + +#define minSnrLimit 0x6666 /* 1 dB */ +#define PEBITS_COEF 0x170a /* 0.18*(1 << 15)*/ + +#define HOLE_THR_LONG 0x2873 /* 0.316*(1 << 15) */ +#define HOLE_THR_SHORT 0x4000 /* 0.5 *(1 << 15) */ + +#define MS_THRSPREAD_COEF 0x7333 /* 0.9 * (1 << 15) */ + +#define MIN_SNR_COEF 0x651f /* 3.16* (1 << (15 - 2)) */ + +/* values for avoid hole flag */ +enum _avoid_hole_state { + NO_AH =0, + AH_INACTIVE =1, + AH_ACTIVE =2 +}; + +/******************************************************************************** +* +* function name:bits2pe +* description: convert from bits to pe +* pe = 1.18*desiredBits +* +**********************************************************************************/ +Word16 bits2pe(const Word16 bits) { + return (bits + ((PEBITS_COEF * bits) >> 15)); +} + +/******************************************************************************** +* +* function name:calcThreshExp +* description: loudness calculation (threshold to the power of redExp) +* thr(n)^0.25 +* +**********************************************************************************/ +static void calcThreshExp(Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB], + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + const Word16 nChannels) +{ + Word16 ch, sfb, sfbGrp; + Word32 *pthrExp, *psfbThre; + for (ch=0; chsfbCnt; sfbGrp+= psyOutChan->sfbPerGroup) + pthrExp = &(thrExp[ch][sfbGrp]); + psfbThre = psyOutChan->sfbThreshold + sfbGrp; + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + *pthrExp = rsqrt(rsqrt(*psfbThre,INT_BITS),INT_BITS); + pthrExp++; psfbThre++; + } + } +} + +/******************************************************************************** +* +* function name:adaptMinSnr +* description: reduce minSnr requirements for bands with relative low energies +* +**********************************************************************************/ +static void adaptMinSnr(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], + MINSNR_ADAPT_PARAM *msaParam, + const Word16 nChannels) +{ + Word16 ch, sfb, sfbOffs, shift; + Word32 nSfb, avgEn; + Word16 log_avgEn = 0; + Word32 startRatio_x_avgEn = 0; + + + for (ch=0; chsfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) { + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfbOffs+sfb]); + nSfb = nSfb + 1; + } + } + + if (nSfb > 0) { + avgEn = avgEn / nSfb; + + log_avgEn = iLog4(avgEn); + startRatio_x_avgEn = fixmul(msaParam->startRatio, avgEn); + } + + + /* reduce minSnr requirement by minSnr^minSnrRed dependent on avgEn/sfbEn */ + for (sfbOffs=0; sfbOffssfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) { + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + if (psyOutChan->sfbEnergy[sfbOffs+sfb] < startRatio_x_avgEn) { + Word16 dbRatio, minSnrRed; + Word32 snrRed; + Word16 newMinSnr; + + dbRatio = log_avgEn - logSfbEnergy[ch][sfbOffs+sfb]; + dbRatio = dbRatio + (dbRatio << 1); + + minSnrRed = 110 - ((dbRatio + (dbRatio << 1)) >> 2); + minSnrRed = max(minSnrRed, 20); /* 110: (0.375(redOffs)+1)*80, + 3: 0.00375(redRatioFac)*80 + 20: 0.25(maxRed) * 80 */ + + snrRed = minSnrRed * iLog4((psyOutChan->sfbMinSnr[sfbOffs+sfb] << 16)); + /* + snrRedI si now scaled by 80 (minSnrRed) and 4 (ffr_iLog4) + */ + + newMinSnr = round16(pow2_xy(snrRed,80*4)); + + psyOutChan->sfbMinSnr[sfbOffs+sfb] = min(newMinSnr, minSnrLimit); + } + } + } + } + +} + + +/******************************************************************************** +* +* function name:initAvoidHoleFlag +* description: determine bands where avoid hole is not necessary resp. possible +* +**********************************************************************************/ +static void initAvoidHoleFlag(Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB], + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + PSY_OUT_ELEMENT* psyOutElement, + const Word16 nChannels, + AH_PARAM *ahParam) +{ + Word16 ch, sfb, sfbGrp, shift; + Word32 threshold; + Word32* psfbSpreadEn; + + for (ch=0; chwindowSequence != SHORT_WINDOW) { + for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){ + psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp; + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + *psfbSpreadEn = *psfbSpreadEn >> 1; /* 0.5 */ + ++psfbSpreadEn; + } + } + } + else { + for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){ + psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp; + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + *psfbSpreadEn = (*psfbSpreadEn >> 1) + (*psfbSpreadEn >> 3); /* 0.63 */ + ++psfbSpreadEn; + } + } + } + } + + /* increase minSnr for local peaks, decrease it for valleys */ + if (ahParam->modifyMinSnr) { + for(ch=0; chwindowSequence != SHORT_WINDOW) + threshold = HOLE_THR_LONG; + else + threshold = HOLE_THR_SHORT; + + for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){ + Word16 *psfbMinSnr = psyOutChan->sfbMinSnr + sfbGrp; + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + Word32 sfbEn, sfbEnm1, sfbEnp1, avgEn; + + if (sfb > 0) + sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp+sfb-1]; + else + sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp]; + + if (sfb < (psyOutChan->maxSfbPerGroup-1)) + sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb+1]; + else + sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb]; + avgEn = (sfbEnm1 + sfbEnp1) >> 1; + sfbEn = psyOutChan->sfbEnergy[sfbGrp+sfb]; + + if (sfbEn > avgEn && avgEn > 0) { + Word32 tmpMinSnr; + shift = norm_l(sfbEn); + tmpMinSnr = Div_32(L_mpy_ls(avgEn, minSnrLimit) << shift, sfbEn << shift ); + tmpMinSnr = max(tmpMinSnr, HOLE_THR_LONG); + tmpMinSnr = max(tmpMinSnr, threshold); + *psfbMinSnr = min(*psfbMinSnr, tmpMinSnr); + } + /* valley ? */ + + if ((sfbEn < (avgEn >> 1)) && (sfbEn > 0)) { + Word32 tmpMinSnr; + Word32 minSnrEn = L_mpy_wx(avgEn, *psfbMinSnr); + + if(minSnrEn < sfbEn) { + shift = norm_l(sfbEn); + tmpMinSnr = Div_32( minSnrEn << shift, sfbEn<> 2), mult(*psfbMinSnr, MIN_SNR_COEF)) << 2); + } + psfbMinSnr++; + } + } + } + } + + /* stereo: adapt the minimum requirements sfbMinSnr of mid and + side channels */ + + if (nChannels == 2) { + PSY_OUT_CHANNEL *psyOutChanM = &psyOutChannel[0]; + PSY_OUT_CHANNEL *psyOutChanS = &psyOutChannel[1]; + for (sfb=0; sfbsfbCnt; sfb++) { + if (psyOutElement->toolsInfo.msMask[sfb]) { + Word32 sfbEnM = psyOutChanM->sfbEnergy[sfb]; + Word32 sfbEnS = psyOutChanS->sfbEnergy[sfb]; + Word32 maxSfbEn = max(sfbEnM, sfbEnS); + Word32 maxThr = L_mpy_wx(maxSfbEn, psyOutChanM->sfbMinSnr[sfb]) >> 1; + + if(maxThr >= sfbEnM) { + psyOutChanM->sfbMinSnr[sfb] = MAX_16; + } + else { + shift = norm_l(sfbEnM); + psyOutChanM->sfbMinSnr[sfb] = min(max(psyOutChanM->sfbMinSnr[sfb], + round16(Div_32(maxThr<= sfbEnS) { + psyOutChanS->sfbMinSnr[sfb] = MAX_16; + } + else { + shift = norm_l(sfbEnS); + psyOutChanS->sfbMinSnr[sfb] = min(max(psyOutChanS->sfbMinSnr[sfb], + round16(Div_32(maxThr << shift, sfbEnS << shift))), minSnrLimit); + } + + + if (sfbEnM > psyOutChanM->sfbSpreadedEnergy[sfb]) + psyOutChanS->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnS, MS_THRSPREAD_COEF); + + if (sfbEnS > psyOutChanS->sfbSpreadedEnergy[sfb]) + psyOutChanM->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnM, MS_THRSPREAD_COEF); + } + } + } + + + /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */ + for(ch=0; chsfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){ + Word16 *pahFlag = ahFlag[ch] + sfbGrp; + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + + if ((psyOutChan->sfbSpreadedEnergy[sfbGrp+sfb] > psyOutChan->sfbEnergy[sfbGrp+sfb]) || + (psyOutChan->sfbEnergy[sfbGrp+sfb] <= psyOutChan->sfbThreshold[sfbGrp+sfb]) || + (psyOutChan->sfbMinSnr[sfbGrp+sfb] == MAX_16)) { + *pahFlag++ = NO_AH; + } + else { + *pahFlag++ = AH_INACTIVE; + } + } + for (sfb=psyOutChan->maxSfbPerGroup; sfbsfbPerGroup; sfb++) { + *pahFlag++ = NO_AH; + } + } + } +} + +/******************************************************************************** +* +* function name:calcPeNoAH +* description: sum the pe data only for bands where avoid hole is inactive +* +**********************************************************************************/ +static void calcPeNoAH(Word16 *pe, + Word16 *constPart, + Word16 *nActiveLines, + PE_DATA *peData, + Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB], + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + const Word16 nChannels) +{ + Word16 ch, sfb, sfbGrp; + int ipe, iconstPart, inActiveLines; + + ipe = 0; + iconstPart = 0; + inActiveLines = 0; + for(ch=0; chpeChannelData[ch]; + for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){ + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + + if (ahFlag[ch][sfbGrp+sfb] < AH_ACTIVE) { + ipe = ipe + peChanData->sfbPe[sfbGrp+sfb]; + iconstPart = iconstPart + peChanData->sfbConstPart[sfbGrp+sfb]; + inActiveLines = inActiveLines + peChanData->sfbNActiveLines[sfbGrp+sfb]; + } + } + } + } + + *pe = saturate(ipe); + *constPart = saturate(iconstPart); + *nActiveLines = saturate(inActiveLines); +} + +/******************************************************************************** +* +* function name:reduceThresholds +* description: apply reduction formula +* +**********************************************************************************/ +static void reduceThresholds(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB], + Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB], + const Word16 nChannels, + const Word32 redVal) +{ + Word32 sfbThrReduced; + Word32 *psfbEn, *psfbThr; + Word16 ch, sfb, sfbGrp; + + for(ch=0; chsfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) { + psfbEn = psyOutChan->sfbEnergy + sfbGrp; + psfbThr = psyOutChan->sfbThreshold + sfbGrp; + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + + if (*psfbEn > *psfbThr) { + /* threshold reduction formula */ + Word32 tmp = thrExp[ch][sfbGrp+sfb] + redVal; + tmp = fixmul(tmp, tmp); + sfbThrReduced = fixmul(tmp, tmp); + /* avoid holes */ + tmp = L_mpy_ls(*psfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]); + + if ((sfbThrReduced > tmp) && + (ahFlag[ch][sfbGrp+sfb] != NO_AH)){ + sfbThrReduced = max(tmp, *psfbThr); + ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE; + } + *psfbThr = sfbThrReduced; + } + + psfbEn++; psfbThr++; + } + } + } +} + + +/******************************************************************************** +* +* function name:correctThresh +* description: if pe difference deltaPe between desired pe and real pe is small enough, +* the difference can be distributed among the scale factor bands. +* +**********************************************************************************/ +static void correctThresh(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB], + PE_DATA *peData, + Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB], + const Word32 redVal, + const Word16 nChannels, + const Word32 deltaPe) +{ + Word16 ch, sfb, sfbGrp,shift; + PSY_OUT_CHANNEL *psyOutChan; + PE_CHANNEL_DATA *peChanData; + Word32 deltaSfbPe; + Word32 normFactor; + Word32 *psfbPeFactors; + Word16 *psfbNActiveLines, *pahFlag; + Word32 sfbEn, sfbThr; + Word32 sfbThrReduced; + + /* for each sfb calc relative factors for pe changes */ + normFactor = 1; + for(ch=0; chpeChannelData[ch]; + for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){ + psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp; + psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp; + pahFlag = ahFlag[ch] + sfbGrp; + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + Word32 redThrExp = thrExp[ch][sfbGrp+sfb] + redVal; + + if (((*pahFlag < AH_ACTIVE) || (deltaPe > 0)) && (redThrExp > 0) && (redThrExp >= *psfbNActiveLines)) { + + *psfbPeFactors = (*psfbNActiveLines) * (0x7fffffff / redThrExp); + normFactor = L_add(normFactor, *psfbPeFactors); + } + else { + *psfbPeFactors = 0; + } + psfbPeFactors++; + pahFlag++; psfbNActiveLines++; + } + } + } + + + /* calculate new thresholds */ + for(ch=0; chpeChannelData[ch]; + for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){ + psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp; + psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp; + pahFlag = ahFlag[ch] + sfbGrp; + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + /* pe difference for this sfb */ + deltaSfbPe = *psfbPeFactors * deltaPe; + + /* thr3(n) = thr2(n)*2^deltaSfbPe/b(n) */ + if (*psfbNActiveLines > 0 && (normFactor* (*psfbNActiveLines)) != 0) { + /* new threshold */ + Word32 thrFactor; + sfbEn = psyOutChan->sfbEnergy[sfbGrp+sfb]; + sfbThr = psyOutChan->sfbThreshold[sfbGrp+sfb]; + + if(deltaSfbPe >= 0){ + /* + reduce threshold + */ + thrFactor = pow2_xy(L_negate(deltaSfbPe), (normFactor* (*psfbNActiveLines))); + + sfbThrReduced = L_mpy_ls(sfbThr, round16(thrFactor)); + } + else { + /* + increase threshold + */ + thrFactor = pow2_xy(deltaSfbPe, (normFactor * (*psfbNActiveLines))); + + + if(thrFactor > sfbThr) { + shift = norm_l(thrFactor); + sfbThrReduced = Div_32( sfbThr << shift, thrFactor<sfbMinSnr[sfbGrp+sfb]); + + if ((sfbThrReduced > sfbEn) && + (*pahFlag == AH_INACTIVE)) { + sfbThrReduced = max(sfbEn, sfbThr); + *pahFlag = AH_ACTIVE; + } + + psyOutChan->sfbThreshold[sfbGrp+sfb] = sfbThrReduced; + } + + pahFlag++; psfbNActiveLines++; psfbPeFactors++; + } + } + } +} + + +/******************************************************************************** +* +* function name:reduceMinSnr +* description: if the desired pe can not be reached, reduce pe by reducing minSnr +* +**********************************************************************************/ +static void reduceMinSnr(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + PE_DATA *peData, + Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB], + const Word16 nChannels, + const Word16 desiredPe) +{ + Word16 ch, sfb, sfbSubWin; + Word16 deltaPe; + + /* start at highest freq down to 0 */ + sfbSubWin = psyOutChannel[0].maxSfbPerGroup; + while (peData->pe > desiredPe && sfbSubWin > 0) { + + sfbSubWin = sfbSubWin - 1; + /* loop over all subwindows */ + for (sfb=sfbSubWin; sfbpeChannelData; + PSY_OUT_CHANNEL* psyOutCh = psyOutChannel; + for (ch=0; chsfbMinSnr[sfb] < minSnrLimit) { + psyOutCh->sfbMinSnr[sfb] = minSnrLimit; + psyOutCh->sfbThreshold[sfb] = + L_mpy_ls(psyOutCh->sfbEnergy[sfb], psyOutCh->sfbMinSnr[sfb]); + + /* calc new pe */ + deltaPe = ((peChan->sfbNLines4[sfb] + (peChan->sfbNLines4[sfb] >> 1)) >> 2) - + peChan->sfbPe[sfb]; + peData->pe = peData->pe + deltaPe; + peChan->pe = peChan->pe + deltaPe; + } + peChan += 1; psyOutCh += 1; + } + /* stop if enough has been saved */ + + if (peData->pe <= desiredPe) + break; + } + } +} + +/******************************************************************************** +* +* function name:allowMoreHoles +* description: if the desired pe can not be reached, some more scalefactor bands +* have to be quantized to zero +* +**********************************************************************************/ +static void allowMoreHoles(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + PSY_OUT_ELEMENT *psyOutElement, + PE_DATA *peData, + Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB], + const AH_PARAM *ahParam, + const Word16 nChannels, + const Word16 desiredPe) +{ + Word16 ch, sfb; + Word16 actPe, shift; + + actPe = peData->pe; + + /* for MS allow hole in the channel with less energy */ + + if (nChannels==2 && + psyOutChannel[0].windowSequence==psyOutChannel[1].windowSequence) { + PSY_OUT_CHANNEL *psyOutChanL = &psyOutChannel[0]; + PSY_OUT_CHANNEL *psyOutChanR = &psyOutChannel[1]; + for (sfb=0; sfbsfbCnt; sfb++) { + Word32 minEn; + + if (psyOutElement->toolsInfo.msMask[sfb]) { + /* allow hole in side channel ? */ + minEn = L_mpy_ls(psyOutChanL->sfbEnergy[sfb], (minSnrLimit * psyOutChanL->sfbMinSnr[sfb]) >> 16); + + if (ahFlag[1][sfb] != NO_AH && + minEn > psyOutChanR->sfbEnergy[sfb]) { + ahFlag[1][sfb] = NO_AH; + psyOutChanR->sfbThreshold[sfb] = L_add(psyOutChanR->sfbEnergy[sfb], psyOutChanR->sfbEnergy[sfb]); + actPe = actPe - peData->peChannelData[1].sfbPe[sfb]; + } + /* allow hole in mid channel ? */ + else { + minEn = L_mpy_ls(psyOutChanR->sfbEnergy[sfb], (minSnrLimit * psyOutChanR->sfbMinSnr[sfb]) >> 16); + + if (ahFlag[0][sfb]!= NO_AH && + minEn > psyOutChanL->sfbEnergy[sfb]) { + ahFlag[0][sfb] = NO_AH; + psyOutChanL->sfbThreshold[sfb] = L_add(psyOutChanL->sfbEnergy[sfb], psyOutChanL->sfbEnergy[sfb]); + actPe = actPe - peData->peChannelData[0].sfbPe[sfb]; + } + } + + if (actPe < desiredPe) + break; + } + } + } + + /* subsequently erase bands */ + if (actPe > desiredPe) { + Word16 startSfb[2]; + Word32 avgEn, minEn; + Word16 ahCnt; + Word16 enIdx; + Word16 enDiff; + Word32 en[4]; + Word16 minSfb, maxSfb; + Flag done; + + /* do not go below startSfb */ + for (ch=0; chstartSfbL; + else + startSfb[ch] = ahParam->startSfbS; + } + + avgEn = 0; + minEn = MAX_32; + ahCnt = 0; + for (ch=0; chsfbCnt; sfb++) { + + if ((ahFlag[ch][sfb] != NO_AH) && + (psyOutChan->sfbEnergy[sfb] > psyOutChan->sfbThreshold[sfb])) { + minEn = min(minEn, psyOutChan->sfbEnergy[sfb]); + avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfb]); + ahCnt++; + } + } + } + + if(ahCnt) { + Word32 iahCnt; + shift = norm_l(ahCnt); + iahCnt = Div_32( 1 << shift, ahCnt << shift ); + avgEn = fixmul(avgEn, iahCnt); + } + + enDiff = iLog4(avgEn) - iLog4(minEn); + /* calc some energy borders between minEn and avgEn */ + for (enIdx=0; enIdx<4; enIdx++) { + Word32 enFac; + enFac = ((6-(enIdx << 1)) * enDiff); + en[enIdx] = fixmul(avgEn, pow2_xy(L_negate(enFac),7*4)); + } + + /* start with lowest energy border at highest sfb */ + maxSfb = psyOutChannel[0].sfbCnt - 1; + minSfb = startSfb[0]; + + if (nChannels == 2) { + maxSfb = max(maxSfb, (psyOutChannel[1].sfbCnt - 1)); + minSfb = min(minSfb, startSfb[1]); + } + + sfb = maxSfb; + enIdx = 0; + done = 0; + while (!done) { + + for (ch=0; ch=startSfb[ch] && sfbsfbCnt) { + /* sfb energy below border ? */ + + if (ahFlag[ch][sfb] != NO_AH && psyOutChan->sfbEnergy[sfb] < en[enIdx]){ + /* allow hole */ + ahFlag[ch][sfb] = NO_AH; + psyOutChan->sfbThreshold[sfb] = L_add(psyOutChan->sfbEnergy[sfb], psyOutChan->sfbEnergy[sfb]); + actPe = actPe - peData->peChannelData[ch].sfbPe[sfb]; + } + + if (actPe < desiredPe) { + done = 1; + break; + } + } + } + sfb = sfb - 1; + + if (sfb < minSfb) { + /* restart with next energy border */ + sfb = maxSfb; + enIdx = enIdx + 1; + + if (enIdx - 4 >= 0) + done = 1; + } + } + } +} + +/******************************************************************************** +* +* function name:adaptThresholdsToPe +* description: two guesses for the reduction value and one final correction of the +* thresholds +* +**********************************************************************************/ +static void adaptThresholdsToPe(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + PSY_OUT_ELEMENT *psyOutElement, + Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], + PE_DATA *peData, + const Word16 nChannels, + const Word16 desiredPe, + AH_PARAM *ahParam, + MINSNR_ADAPT_PARAM *msaParam) +{ + Word16 noRedPe, redPe, redPeNoAH; + Word16 constPart, constPartNoAH; + Word16 nActiveLines, nActiveLinesNoAH; + Word16 desiredPeNoAH; + Word32 redVal, avgThrExp; + Word32 iter; + + calcThreshExp(peData->thrExp, psyOutChannel, nChannels); + + adaptMinSnr(psyOutChannel, logSfbEnergy, msaParam, nChannels); + + initAvoidHoleFlag(peData->ahFlag, psyOutChannel, psyOutElement, nChannels, ahParam); + + noRedPe = peData->pe; + constPart = peData->constPart; + nActiveLines = peData->nActiveLines; + + /* first guess of reduction value t^0.25 = 2^((a-pen)/4*b) */ + avgThrExp = pow2_xy((constPart - noRedPe), (nActiveLines << 2)); + + /* r1 = 2^((a-per)/4*b) - t^0.25 */ + redVal = pow2_xy((constPart - desiredPe), (nActiveLines << 2)) - avgThrExp; + + /* reduce thresholds */ + reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal); + + /* pe after first guess */ + calcSfbPe(peData, psyOutChannel, nChannels); + redPe = peData->pe; + + iter = 0; + do { + /* pe for bands where avoid hole is inactive */ + calcPeNoAH(&redPeNoAH, &constPartNoAH, &nActiveLinesNoAH, + peData, peData->ahFlag, psyOutChannel, nChannels); + + desiredPeNoAH = desiredPe -(redPe - redPeNoAH); + + if (desiredPeNoAH < 0) { + desiredPeNoAH = 0; + } + + /* second guess */ + + if (nActiveLinesNoAH > 0) { + + avgThrExp = pow2_xy((constPartNoAH - redPeNoAH), (nActiveLinesNoAH << 2)); + + redVal = (redVal + pow2_xy((constPartNoAH - desiredPeNoAH), (nActiveLinesNoAH << 2))) - avgThrExp; + + /* reduce thresholds */ + reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal); + } + + calcSfbPe(peData, psyOutChannel, nChannels); + redPe = peData->pe; + + iter = iter+1; + + } while ((20 * abs_s(redPe - desiredPe) > desiredPe) && (iter < 2)); + + + if ((100 * redPe < 115 * desiredPe)) { + correctThresh(psyOutChannel, peData->ahFlag, peData, peData->thrExp, redVal, + nChannels, desiredPe - redPe); + } + else { + Word16 desiredPe105 = (105 * desiredPe) / 100; + reduceMinSnr(psyOutChannel, peData, peData->ahFlag, + nChannels, desiredPe105); + allowMoreHoles(psyOutChannel, psyOutElement, peData, peData->ahFlag, + ahParam, nChannels, desiredPe105); + } +} + + +/***************************************************************************** +* +* function name: calcBitSave +* description: Calculates percentage of bit save, see figure below +* returns: +* input: parameters and bitres-fullness +* output: percentage of bit save +* +*****************************************************************************/ +static Word16 calcBitSave(Word16 fillLevel, + const Word16 clipLow, + const Word16 clipHigh, + const Word16 minBitSave, + const Word16 maxBitSave) +{ + Word16 bitsave = 0; + + fillLevel = max(fillLevel, clipLow); + fillLevel = min(fillLevel, clipHigh); + + if(clipHigh-clipLow) + bitsave = (maxBitSave - (((maxBitSave-minBitSave)*(fillLevel-clipLow))/ + (clipHigh-clipLow))); + + return (bitsave); +} + + + +/***************************************************************************** +* +* function name: calcBitSpend +* description: Calculates percentage of bit spend, see figure below +* returns: +* input: parameters and bitres-fullness +* output: percentage of bit spend +* +*****************************************************************************/ +static Word16 calcBitSpend(Word16 fillLevel, + const Word16 clipLow, + const Word16 clipHigh, + const Word16 minBitSpend, + const Word16 maxBitSpend) +{ + Word16 bitspend = 1; + + fillLevel = max(fillLevel, clipLow); + fillLevel = min(fillLevel, clipHigh); + + if(clipHigh-clipLow) + bitspend = (minBitSpend + ((maxBitSpend - minBitSpend)*(fillLevel - clipLow) / + (clipHigh-clipLow))); + + return (bitspend); +} + + +/***************************************************************************** +* +* function name: adjustPeMinMax() +* description: adjusts peMin and peMax parameters over time +* returns: +* input: current pe, peMin, peMax +* output: adjusted peMin/peMax +* +*****************************************************************************/ +static void adjustPeMinMax(const Word16 currPe, + Word16 *peMin, + Word16 *peMax) +{ + Word16 minFacHi, maxFacHi, minFacLo, maxFacLo; + Word16 diff; + Word16 minDiff = extract_l(currPe / 6); + minFacHi = 30; + maxFacHi = 100; + minFacLo = 14; + maxFacLo = 7; + + diff = currPe - *peMax ; + + if (diff > 0) { + *peMin = *peMin + ((diff * minFacHi) / 100); + *peMax = *peMax + ((diff * maxFacHi) / 100); + } else { + diff = *peMin - currPe; + + if (diff > 0) { + *peMin = *peMin - ((diff * minFacLo) / 100); + *peMax = *peMax - ((diff * maxFacLo) / 100); + } else { + *peMin = *peMin + ((currPe - *peMin) * minFacHi / 100); + *peMax = *peMax - ((*peMax - currPe) * maxFacLo / 100); + } + } + + + if ((*peMax - *peMin) < minDiff) { + Word16 partLo, partHi; + + partLo = max(0, (currPe - *peMin)); + partHi = max(0, (*peMax - currPe)); + + *peMax = currPe + ((partHi * minDiff) / (partLo + partHi)); + *peMin = currPe - ((partLo * minDiff) / (partLo + partHi)); + *peMin = max(0, *peMin); + } +} + + +/***************************************************************************** +* +* function name: BitresCalcBitFac +* description: calculates factor of spending bits for one frame +* 1.0 : take all frame dynpart bits +* >1.0 : take all frame dynpart bits + bitres +* <1.0 : put bits in bitreservoir +* returns: BitFac*100 +* input: bitres-fullness, pe, blockType, parameter-settings +* output: +* +*****************************************************************************/ +static Word16 bitresCalcBitFac( const Word16 bitresBits, + const Word16 maxBitresBits, + const Word16 pe, + const Word16 windowSequence, + const Word16 avgBits, + const Word16 maxBitFac, + ADJ_THR_STATE *AdjThr, + ATS_ELEMENT *adjThrChan) +{ + BRES_PARAM *bresParam; + Word16 pex; + Word16 fillLevel; + Word16 bitSave, bitSpend, bitresFac; + + fillLevel = extract_l((100* bitresBits) / maxBitresBits); + + if (windowSequence != SHORT_WINDOW) + bresParam = &(AdjThr->bresParamLong); + else + bresParam = &(AdjThr->bresParamShort); + + pex = max(pe, adjThrChan->peMin); + pex = min(pex,adjThrChan->peMax); + + bitSave = calcBitSave(fillLevel, + bresParam->clipSaveLow, bresParam->clipSaveHigh, + bresParam->minBitSave, bresParam->maxBitSave); + + bitSpend = calcBitSpend(fillLevel, + bresParam->clipSpendLow, bresParam->clipSpendHigh, + bresParam->minBitSpend, bresParam->maxBitSpend); + + if(adjThrChan->peMax != adjThrChan->peMin) + bitresFac = (100 - bitSave) + extract_l(((bitSpend + bitSave) * (pex - adjThrChan->peMin)) / + (adjThrChan->peMax - adjThrChan->peMin)); + else + bitresFac = 0x7fff; + + bitresFac = min(bitresFac, + (100-30 + extract_l((100 * bitresBits) / avgBits))); + + bitresFac = min(bitresFac, maxBitFac); + + adjustPeMinMax(pe, &adjThrChan->peMin, &adjThrChan->peMax); + + return bitresFac; +} + +/***************************************************************************** +* +* function name: AdjThrInit +* description: init thresholds parameter +* +*****************************************************************************/ +void AdjThrInit(ADJ_THR_STATE *hAdjThr, + const Word32 meanPe, + Word32 chBitrate) +{ + ATS_ELEMENT* atsElem = &hAdjThr->adjThrStateElem; + MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam; + + /* common for all elements: */ + /* parameters for bitres control */ + hAdjThr->bresParamLong.clipSaveLow = 20; + hAdjThr->bresParamLong.clipSaveHigh = 95; + hAdjThr->bresParamLong.minBitSave = -5; + hAdjThr->bresParamLong.maxBitSave = 30; + hAdjThr->bresParamLong.clipSpendLow = 20; + hAdjThr->bresParamLong.clipSpendHigh = 95; + hAdjThr->bresParamLong.minBitSpend = -10; + hAdjThr->bresParamLong.maxBitSpend = 40; + + hAdjThr->bresParamShort.clipSaveLow = 20; + hAdjThr->bresParamShort.clipSaveHigh = 75; + hAdjThr->bresParamShort.minBitSave = 0; + hAdjThr->bresParamShort.maxBitSave = 20; + hAdjThr->bresParamShort.clipSpendLow = 20; + hAdjThr->bresParamShort.clipSpendHigh = 75; + hAdjThr->bresParamShort.minBitSpend = -5; + hAdjThr->bresParamShort.maxBitSpend = 50; + + /* specific for each element: */ + + /* parameters for bitres control */ + atsElem->peMin = extract_l(((80*meanPe) / 100)); + atsElem->peMax = extract_l(((120*meanPe) / 100)); + + /* additional pe offset to correct pe2bits for low bitrates */ + atsElem->peOffset = 0; + if (chBitrate < 32000) { + atsElem->peOffset = max(50, (100 - extract_l((100 * chBitrate) / 32000))); + } + + /* avoid hole parameters */ + if (chBitrate > 20000) { + atsElem->ahParam.modifyMinSnr = TRUE; + atsElem->ahParam.startSfbL = 15; + atsElem->ahParam.startSfbS = 3; + } + else { + atsElem->ahParam.modifyMinSnr = FALSE; + atsElem->ahParam.startSfbL = 0; + atsElem->ahParam.startSfbS = 0; + } + + /* minSnr adaptation */ + /* maximum reduction of minSnr goes down to minSnr^maxRed */ + msaParam->maxRed = 0x20000000; /* *0.25f */ + /* start adaptation of minSnr for avgEn/sfbEn > startRatio */ + msaParam->startRatio = 0x0ccccccd; /* 10 */ + /* maximum minSnr reduction to minSnr^maxRed is reached for + avgEn/sfbEn >= maxRatio */ + msaParam->maxRatio = 0x0020c49c; /* 1000 */ + /* helper variables to interpolate minSnr reduction for + avgEn/sfbEn between startRatio and maxRatio */ + + msaParam->redRatioFac = 0xfb333333; /* -0.75/20 */ + + msaParam->redOffs = 0x30000000; /* msaParam->redRatioFac * 10*log10(msaParam->startRatio) */ + + + /* pe correction */ + atsElem->peLast = 0; + atsElem->dynBitsLast = 0; + atsElem->peCorrectionFactor = 100; /* 1.0 */ + +} + +/***************************************************************************** +* +* function name: calcPeCorrection +* description: calculates the desired perceptual entropy factor +* It is between 0.85 and 1.15 +* +*****************************************************************************/ +static void calcPeCorrection(Word16 *correctionFac, + const Word16 peAct, + const Word16 peLast, + const Word16 bitsLast) +{ + Word32 peAct100 = 100 * peAct; + Word32 peLast100 = 100 * peLast; + Word16 peBitsLast = bits2pe(bitsLast); + + if ((bitsLast > 0) && + (peAct100 < (150 * peLast)) && (peAct100 > (70 * peLast)) && + ((120 * peBitsLast) > peLast100 ) && (( 65 * peBitsLast) < peLast100)) + { + Word16 newFac = (100 * peLast) / peBitsLast; + /* dead zone */ + + if (newFac < 100) { + newFac = min(((110 * newFac) / 100), 100); + newFac = max(newFac, 85); + } + else { + newFac = max(((90 * newFac) / 100), 100); + newFac = min(newFac, 115); + } + + if ((newFac > 100 && *correctionFac < 100) || + (newFac < 100 && *correctionFac > 100)) { + *correctionFac = 100; + } + /* faster adaptation towards 1.0, slower in the other direction */ + + if ((*correctionFac < 100 && newFac < *correctionFac) || + (*correctionFac > 100 && newFac > *correctionFac)) + *correctionFac = (85 * *correctionFac + 15 * newFac) / 100; + else + *correctionFac = (70 * *correctionFac + 30 * newFac) / 100; + *correctionFac = min(*correctionFac, 115); + *correctionFac = max(*correctionFac, 85); + } + else { + *correctionFac = 100; + } +} + +/******************************************************************************** +* +* function name: AdjustThresholds +* description: Adjust thresholds to the desired bitrate +* +**********************************************************************************/ +void AdjustThresholds(ADJ_THR_STATE *adjThrState, + ATS_ELEMENT *AdjThrStateElement, + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + PSY_OUT_ELEMENT *psyOutElement, + Word16 *chBitDistribution, + Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], + Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB], + QC_OUT_ELEMENT *qcOE, + ELEMENT_BITS *elBits, + const Word16 nChannels, + const Word16 maxBitFac) +{ + PE_DATA peData; + Word16 noRedPe, grantedPe, grantedPeCorr; + Word16 curWindowSequence; + Word16 bitFactor; + Word16 avgBits = (elBits->averageBits - (qcOE->staticBitsUsed + qcOE->ancBitsUsed)); + Word16 bitresBits = elBits->bitResLevel; + Word16 maxBitresBits = elBits->maxBits; + Word16 sideInfoBits = (qcOE->staticBitsUsed + qcOE->ancBitsUsed); + Word16 ch; + memset(&peData, 0, sizeof(peData)); + + prepareSfbPe(&peData, psyOutChannel, logSfbEnergy, sfbNRelevantLines, nChannels, AdjThrStateElement->peOffset); + + /* pe without reduction */ + calcSfbPe(&peData, psyOutChannel, nChannels); + noRedPe = peData.pe; + + + curWindowSequence = LONG_WINDOW; + + if (nChannels == 2) { + + if ((psyOutChannel[0].windowSequence == SHORT_WINDOW) || + (psyOutChannel[1].windowSequence == SHORT_WINDOW)) { + curWindowSequence = SHORT_WINDOW; + } + } + else { + curWindowSequence = psyOutChannel[0].windowSequence; + } + + + /* bit factor */ + bitFactor = bitresCalcBitFac(bitresBits, maxBitresBits, noRedPe+5*sideInfoBits, + curWindowSequence, avgBits, maxBitFac, + adjThrState, + AdjThrStateElement); + + /* desired pe */ + grantedPe = ((bitFactor * bits2pe(avgBits)) / 100); + + /* correction of pe value */ + calcPeCorrection(&(AdjThrStateElement->peCorrectionFactor), + min(grantedPe, noRedPe), + AdjThrStateElement->peLast, + AdjThrStateElement->dynBitsLast); + grantedPeCorr = (grantedPe * AdjThrStateElement->peCorrectionFactor) / 100; + + + if (grantedPeCorr < noRedPe && noRedPe > peData.offset) { + /* calc threshold necessary for desired pe */ + adaptThresholdsToPe(psyOutChannel, + psyOutElement, + logSfbEnergy, + &peData, + nChannels, + grantedPeCorr, + &AdjThrStateElement->ahParam, + &AdjThrStateElement->minSnrAdaptParam); + } + + /* calculate relative distribution */ + for (ch=0; ch 0) { + Word32 temp = 1000 - (nChannels * 200); + chBitDistribution[ch] = chBitDistribution[ch] + + (temp * peData.peChannelData[ch].pe) / peOffsDiff; + } + } + + /* store pe */ + qcOE->pe = noRedPe; + + /* update last pe */ + AdjThrStateElement->peLast = grantedPe; +} + +/******************************************************************************** +* +* function name: AdjThrUpdate +* description: save dynBitsUsed for correction of bits2pe relation +* +**********************************************************************************/ +void AdjThrUpdate(ATS_ELEMENT *AdjThrStateElement, + const Word16 dynBitsUsed) +{ + AdjThrStateElement->dynBitsLast = dynBitsUsed; +} + + diff --git a/jni/src/asm/ARMV5E/AutoCorrelation_v5.s b/jni/src/asm/ARMV5E/AutoCorrelation_v5.s new file mode 100644 index 000000000..e7051975f --- /dev/null +++ b/jni/src/asm/ARMV5E/AutoCorrelation_v5.s @@ -0,0 +1,167 @@ +@/* +@ ** Copyright 2003-2010, VisualOn, Inc. +@ ** +@ ** Licensed under the Apache License, Version 2.0 (the "License"); +@ ** you may not use this file except in compliance with the License. +@ ** You may obtain a copy of the License at +@ ** +@ ** http://www.apache.org/licenses/LICENSE-2.0 +@ ** +@ ** Unless required by applicable law or agreed to in writing, software +@ ** distributed under the License is distributed on an "AS IS" BASIS, +@ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@ ** See the License for the specific language governing permissions and +@ ** limitations under the License. +@ */ + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ File: AutoCorrelation_v5.s +@ +@ Content: AutoCorrelation function armv5 assemble +@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + + .section .text + .global AutoCorrelation + +AutoCorrelation: + stmdb sp!, {r4 - r11, lr} + + sub r13, r13, #20 + + mov r5, r0 + mov r7, r1 + mov r9, r3 + mov r2, r2, lsl #16 + mov r0, #0 + mov r4, r2, asr #16 + mov r8, #0 + cmp r4, #0 + ble L136 + + cmp r4, #8 + mov r2, #0 + blt L133 + + sub r12, r4, #8 +L132: + ldr r6, [r5, r2] + add r2, r2, #4 + smulbb r3, r6, r6 + ldr r1, [r5, r2] + smultt r10, r6, r6 + mov r3, r3, asr #9 + smulbb r6, r1, r1 + mov r10, r10, asr #9 + qadd r0, r0, r3 + smultt r11, r1, r1 + add r2, r2, #4 + qadd r0, r0, r10 + mov r6, r6, asr #9 + mov r11, r11, asr #9 + ldr r1, [r5, r2] + qadd r0, r0, r6 + smulbb r10, r1, r1 + smultt r6, r1, r1 + qadd r0, r0, r11 + mov r10, r10, asr #9 + mov r6, r6, asr #9 + qadd r0, r0, r10 + add r2, r2, #4 + add r8, r8, #6 + + qadd r0, r0, r6 + cmp r8, r12 + blt L132 +L133: + ldrsh r6, [r5, r2] + mul r10, r6, r6 + add r2, r2, #2 + mov r1, r10, asr #9 + qadd r0, r0, r1 +L134: + add r8, r8, #1 + cmp r8, r4 + blt L133 +L135: +L136: + str r0, [r7, #0] + cmp r0, #0 + beq L1320 +L137: + mov r2, r9, lsl #16 + mov r8, #1 + mov r2, r2, asr #16 + cmp r2, #1 + ble L1319 +L138: +L139: + sub r4, r4, #1 + mov r14, #0 + mov r3, #0 + cmp r4, #0 + ble L1317 +L1310: + cmp r4, #6 + addlt r6, r5, r8, lsl #1 + blt L1314 +L1311: + add r6, r5, r8, lsl #1 + sub r12, r4, #6 + str r8, [r13, #8] + str r7, [r13, #4] +L1312: + mov r1, r3, lsl #1 + ldrsh r7, [r6, r1] + ldrsh r10, [r5, r1] + add r8, r1, r6 + add r9, r5, r1 + mul r7, r10, r7 + ldrsh r1, [r8, #2] + ldrsh r10, [r8, #4] + add r7, r14, r7, asr #9 + ldrsh r0, [r9, #2] + ldrsh r11, [r9, #4] + mul r1, r0, r1 + ldrsh r14, [r8, #6] + mul r10, r11, r10 + add r7, r7, r1, asr #9 + ldrsh r8, [r8, #8] + add r3, r3, #5 + ldrsh r11, [r9, #6] + ldrsh r1, [r9, #8] + mul r14, r11, r14 + add r7, r7, r10, asr #9 + mul r1, r1, r8 + add r14, r7, r14, asr #9 + cmp r3, r12 + add r14, r14, r1, asr #9 + ble L1312 +L1313: + ldr r8, [r13, #8] + ldr r7, [r13, #4] +L1314: +L1315: + mov r12, r3, lsl #1 + ldrsh r9, [r6, r12] + ldrsh r12, [r5, r12] + add r3, r3, #1 + cmp r3, r4 + mul r12, r12, r9 + add r14, r14, r12, asr #9 + blt L1315 +L1316: +L1317: + str r14, [r7, +r8, lsl #2] + add r8, r8, #1 + cmp r8, r2 + blt L139 + +L1319: +L1320: + add r13, r13, #20 + ldmia sp!, {r4 - r11, pc} + + @ENDP @ |AutoCorrelation| + .end diff --git a/jni/src/asm/ARMV5E/CalcWindowEnergy_v5.s b/jni/src/asm/ARMV5E/CalcWindowEnergy_v5.s new file mode 100644 index 000000000..b30e8cb81 --- /dev/null +++ b/jni/src/asm/ARMV5E/CalcWindowEnergy_v5.s @@ -0,0 +1,112 @@ +@/* +@ ** Copyright 2003-2010, VisualOn, Inc. +@ ** +@ ** Licensed under the Apache License, Version 2.0 (the "License"); +@ ** you may not use this file except in compliance with the License. +@ ** You may obtain a copy of the License at +@ ** +@ ** http://www.apache.org/licenses/LICENSE-2.0 +@ ** +@ ** Unless required by applicable law or agreed to in writing, software +@ ** distributed under the License is distributed on an "AS IS" BASIS, +@ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@ ** See the License for the specific language governing permissions and +@ ** limitations under the License. +@ */ + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ File: CalcWindowEnergy_v5.s +@ +@ Content: CalcWindowEnergy function armv5 assemble +@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + .section .text + + .global CalcWindowEnergy + +CalcWindowEnergy: + stmdb sp!, {r4 - r11, lr} + sub r13, r13, #20 + + mov r3, r3, lsl #16 + ldr r10, [r0, #168] @ states0 = blockSwitchingControl->iirStates[0]; + mov r3, r3, asr #16 + ldr r11, [r0, #172] @ states1 = blockSwitchingControl->iirStates[1]; + + mov r2, r2, lsl #16 + ldr r12, hiPassCoeff @ Coeff0 = hiPassCoeff[0]; + mov r2, r2, asr #16 + ldr r14, hiPassCoeff + 4 @ Coeff1 = hiPassCoeff[1]; + + mov r8, #0 @ w=0 + mov r5, #0 @ wOffset = 0; + +BLOCK_BEGIN: + mov r6, #0 @ accuUE = 0; + mov r7, #0 @ accuFE = 0; + mov r4, #0 @ i=0 + + str r8, [r13, #4] + str r0, [r13, #8] + str r3, [r13, #12] + +ENERGY_BEG: + mov r9, r5, lsl #1 + ldrsh r9, [r1, r9] @ tempUnfiltered = timeSignal[tidx]; + + add r5, r5, r2 @ tidx = tidx + chIncrement; + + smulwb r3, r14, r9 @ accu1 = L_mpy_ls(Coeff1, tempUnfiltered); + smull r0, r8, r12, r11 @ accu2 = fixmul( Coeff0, states1 ); + + mov r3, r3, lsl #1 + mov r8, r8, lsl #1 + + sub r0, r3, r10 @ accu3 = accu1 - states0; + sub r8, r0, r8 @ out = accu3 - accu2; + + mov r10, r3 @ states0 = accu1; + mov r11, r8 @ states1 = out; + + mul r3, r9, r9 + mov r8, r8, asr #16 + + add r4, r4, #1 + add r6, r6, r3, asr #7 + + mul r9, r8, r8 + ldr r3, [r13, #12] + + add r7, r7, r9, asr #7 + + cmp r4, r3 + blt ENERGY_BEG + + ldr r0, [r13, #8] + ldr r8, [r13, #4] + +ENERGY_END: + add r4, r0, r8, lsl #2 + + str r6, [r4, #72] + add r8, r8, #1 + str r7, [r4, #136] + + cmp r8, #8 + blt BLOCK_BEGIN + +BLOCK_END: + str r10, [r0, #168] + str r11, [r0, #172] + mov r0, #1 + + add r13, r13, #20 + ldmia sp!, {r4 - r11, pc} + +hiPassCoeff: + .word 0xbec8b439 + .word 0x609d4952 + + @ENDP + .end diff --git a/jni/src/asm/ARMV5E/PrePostMDCT_v5.s b/jni/src/asm/ARMV5E/PrePostMDCT_v5.s new file mode 100644 index 000000000..da21d5faf --- /dev/null +++ b/jni/src/asm/ARMV5E/PrePostMDCT_v5.s @@ -0,0 +1,131 @@ +@/* +@ ** Copyright 2003-2010, VisualOn, Inc. +@ ** +@ ** Licensed under the Apache License, Version 2.0 (the "License"); +@ ** you may not use this file except in compliance with the License. +@ ** You may obtain a copy of the License at +@ ** +@ ** http://www.apache.org/licenses/LICENSE-2.0 +@ ** +@ ** Unless required by applicable law or agreed to in writing, software +@ ** distributed under the License is distributed on an "AS IS" BASIS, +@ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@ ** See the License for the specific language governing permissions and +@ ** limitations under the License. +@ */ + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ File: PrePostMDCT_v5.s +@ +@ Content: premdct and postmdct function armv5 assemble +@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + .section .text + .global PreMDCT + +PreMDCT: + stmdb sp!, {r4 - r11, lr} + + add r9, r0, r1, lsl #2 + sub r3, r9, #8 + + movs r1, r1, asr #2 + beq PreMDCT_END + +PreMDCT_LOOP: + ldr r8, [r2], #4 + ldr r9, [r2], #4 + + ldrd r4, [r0] + ldrd r6, [r3] + + smull r14, r11, r4, r8 @ MULHIGH(tr1, cosa) + smull r10, r12, r7, r8 @ MULHIGH(ti1, cosa) + + smull r14, r8, r7, r9 @ MULHIGH(ti1, sina) + smull r7, r10, r4, r9 @ MULHIGH(tr1, sina) + + add r11, r11, r8 @ MULHIGH(cosa, tr1) + MULHIGH(sina, ti1)@ + sub r7, r12, r10 @ MULHIGH(ti1, cosa) - MULHIGH(tr1, sina) + + ldr r8, [r2], #4 + ldr r9, [r2], #4 + + smull r14, r4, r6, r8 @ MULHIGH(tr2, cosa) + smull r10, r12, r5, r8 @ MULHIGH(ti2, cosa) + + smull r14, r8, r5, r9 @ MULHIGH(ti2, sina) + smull r5, r10, r6, r9 @ MULHIGH(tr2, sina) + + add r8, r8, r4 + sub r9, r12, r10 + + mov r6, r11 + + strd r6, [r0] + strd r8, [r3] + + subs r1, r1, #1 + sub r3, r3, #8 + add r0, r0, #8 + bne PreMDCT_LOOP + +PreMDCT_END: + ldmia sp!, {r4 - r11, pc} + @ENDP @ |PreMDCT| + + .section .text + .global PostMDCT + +PostMDCT: + stmdb sp!, {r4 - r11, lr} + + add r9, r0, r1, lsl #2 + sub r3, r9, #8 + + movs r1, r1, asr #2 + beq PostMDCT_END + +PostMDCT_LOOP: + ldr r8, [r2], #4 + ldr r9, [r2], #4 + + ldrd r4, [r0] + ldrd r6, [r3] + + smull r14, r11, r4, r8 @ MULHIGH(tr1, cosa) + smull r10, r12, r5, r8 @ MULHIGH(ti1, cosa) + + smull r14, r8, r5, r9 @ MULHIGH(ti1, sina) + smull r5, r10, r4, r9 @ MULHIGH(tr1, sina) + + add r4, r11, r8 @ MULHIGH(cosa, tr1) + MULHIGH(sina, ti1)@ + sub r11, r10, r12 @ MULHIGH(ti1, cosa) - MULHIGH(tr1, sina)@ + + ldr r8, [r2], #4 @ + ldr r9, [r2], #4 + + smull r14, r5, r6, r8 @ MULHIGH(tr2, cosa) + smull r10, r12, r7, r8 @ MULHIGH(ti2, cosa) + + smull r14, r8, r7, r9 @ MULHIGH(ti2, sina) + smull r7, r10, r6, r9 @ MULHIGH(tr2, sina) + + add r6, r8, r5 @ MULHIGH(cosb, tr2) + MULHIGH(sinb, ti2)@ + sub r5, r10, r12 @ MULHIGH(sinb, tr2) - MULHIGH(cosb, ti2)@ + + mov r7, r11 + + strd r4, [r0] + strd r6, [r3] + + subs r1, r1, #1 + sub r3, r3, #8 + add r0, r0, #8 + bne PostMDCT_LOOP + +PostMDCT_END: + ldmia sp!, {r4 - r11, pc} + @ENDP @ |PostMDCT| + .end diff --git a/jni/src/asm/ARMV5E/R4R8First_v5.s b/jni/src/asm/ARMV5E/R4R8First_v5.s new file mode 100644 index 000000000..4ca4f3110 --- /dev/null +++ b/jni/src/asm/ARMV5E/R4R8First_v5.s @@ -0,0 +1,252 @@ +@/* +@ ** Copyright 2003-2010, VisualOn, Inc. +@ ** +@ ** Licensed under the Apache License, Version 2.0 (the "License"); +@ ** you may not use this file except in compliance with the License. +@ ** You may obtain a copy of the License at +@ ** +@ ** http://www.apache.org/licenses/LICENSE-2.0 +@ ** +@ ** Unless required by applicable law or agreed to in writing, software +@ ** distributed under the License is distributed on an "AS IS" BASIS, +@ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@ ** See the License for the specific language governing permissions and +@ ** limitations under the License. +@ */ + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ File: R4R8First_v5.s +@ +@ Content: Radix8First and Radix4First function armv5 assemble +@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + .section .text + .global Radix4First + +Radix4First: + stmdb sp!, {r4 - r11, lr} + + movs r10, r1 + mov r11, r0 + beq Radix4First_END + +Radix4First_LOOP: + ldrd r0, [r11] + ldrd r2, [r11, #8] + ldrd r4, [r11, #16] + ldrd r6, [r11, #24] + + add r8, r0, r2 + add r9, r1, r3 + + sub r0, r0, r2 + sub r1, r1, r3 + + add r2, r4, r6 + add r3, r5, r7 + + sub r4, r4, r6 + sub r5, r5, r7 + + add r6, r8, r2 + add r7, r9, r3 + + sub r8, r8, r2 + sub r9, r9, r3 + + add r2, r0, r5 + sub r3, r1, r4 + + sub r0, r0, r5 + add r1, r1, r4 + + strd r6, [r11] + strd r2, [r11, #8] + strd r8, [r11, #16] + strd r0, [r11, #24] + + subs r10, r10, #1 + add r11, r11, #32 + bne Radix4First_LOOP + +Radix4First_END: + ldmia sp!, {r4 - r11, pc} + @ENDP @ |Radix4First| + + .section .text + .global Radix8First + +Radix8First: + stmdb sp!, {r4 - r11, lr} + sub sp, sp, #0x24 + + mov r12, r1 + mov r14, r0 + cmp r12, #0 + beq Radix8First_END + +Radix8First_LOOP: + ldrd r0, [r14] + ldrd r2, [r14, #8] + ldrd r4, [r14, #16] + ldrd r6, [r14, #24] + + add r8, r0, r2 @ r0 = buf[0] + buf[2]@ + add r9, r1, r3 @ i0 = buf[1] + buf[3]@ + + sub r0, r0, r2 @ r1 = buf[0] - buf[2]@ + sub r1, r1, r3 @ i1 = buf[1] - buf[3]@ + + add r2, r4, r6 @ r2 = buf[4] + buf[6]@ + add r3, r5, r7 @ i2 = buf[5] + buf[7]@ + + sub r4, r4, r6 @ r3 = buf[4] - buf[6]@ + sub r5, r5, r7 @ i3 = buf[5] - buf[7]@ + + add r6, r8, r2 @ r4 = (r0 + r2) >> 1@ + add r7, r9, r3 @ i4 = (i0 + i2) >> 1@ + + sub r8, r8, r2 @ r5 = (r0 - r2) >> 1@ + sub r9, r9, r3 @ i5 = (i0 - i2) >> 1@ + + sub r2, r0, r5 @ r6 = (r1 - i3) >> 1@ + add r3, r1, r4 @ i6 = (i1 + r3) >> 1@ + + add r0, r0, r5 @ r7 = (r1 + i3) >> 1@ + sub r1, r1, r4 @ i7 = (i1 - r3) >> 1@ + + mov r6, r6, asr #1 @ + mov r7, r7, asr #1 @ + + mov r8, r8, asr #1 + mov r9, r9, asr #1 + + mov r2, r2, asr #1 + mov r3, r3, asr #1 + + mov r0, r0, asr #1 + mov r1, r1, asr #1 + + str r6, [sp] + str r7, [sp, #4] + + str r8, [sp, #8] + str r9, [sp, #12] + + str r2, [sp, #16] + str r3, [sp, #20] + + str r0, [sp, #24] + str r1, [sp, #28] + + ldrd r2, [r14, #32] + ldrd r4, [r14, #40] + ldrd r6, [r14, #48] + ldrd r8, [r14, #56] + + add r0, r2, r4 @ r0 = buf[ 8] + buf[10]@ + add r1, r3, r5 @ i0 = buf[ 9] + buf[11]@ + + sub r2, r2, r4 @ r1 = buf[ 8] - buf[10]@ + sub r3, r3, r5 @ i1 = buf[ 9] - buf[11]@ + + add r4, r6, r8 @ r2 = buf[12] + buf[14]@ + add r5, r7, r9 @ i2 = buf[13] + buf[15]@ + + sub r6, r6, r8 @ r3 = buf[12] - buf[14]@ + sub r7, r7, r9 @ i3 = buf[13] - buf[15]@ + + add r8, r0, r4 @ t0 = (r0 + r2) + add r9, r1, r5 @ t1 = (i0 + i2) + + sub r0, r0, r4 @ t2 = (r0 - r2) + sub r1, r1, r5 @ t3 = (i0 - i2) + + mov r8, r8, asr #1 + ldr r4, [sp] + + mov r9, r9, asr #1 + ldr r5, [sp, #4] + + mov r0, r0, asr #1 + mov r1, r1, asr #1 + + add r10, r4, r8 @ buf[ 0] = r4 + t0@ + add r11, r5, r9 @ buf[ 1] = i4 + t1@ + + sub r4, r4, r8 @ buf[ 8] = r4 - t0@ + sub r5, r5, r9 @ buf[ 9] = i4 - t1@ + + strd r10, [r14] + strd r4, [r14, #32] + + ldr r10, [sp, #8] + ldr r11, [sp, #12] + + add r4, r10, r1 @ buf[ 4] = r5 + t3@ + sub r5, r11, r0 @ buf[ 5] = i5 - t2@ + + sub r10, r10, r1 @ buf[12] = r5 - t3@ + add r11, r11, r0 @ buf[13] = i5 + t2@ + + strd r4, [r14, #16] + strd r10, [r14, #48] + + sub r0, r2, r7 @ r0 = r1 - i3@ + add r1, r3, r6 @ i0 = i1 + r3@ + + ldr r11, DATATab + + add r2, r2, r7 @ r2 = r1 + i3@ + sub r3, r3, r6 @ i2 = i1 - r3@ + + sub r4, r0, r1 @ r0 - i0 + add r5, r0, r1 @ r0 + i0 + + sub r0, r2, r3 @ r2 - i2 + add r1, r2, r3 @ r2 + i2 + + smull r8, r6, r4, r11 + smull r9, r7, r5, r11 + + ldr r2, [sp, #16] + ldr r3, [sp, #20] + + smull r8, r4, r0, r11 + smull r9, r5, r1, r11 + + ldr r10, [sp, #24] + ldr r11, [sp, #28] + + sub r8, r2, r6 + sub r9, r3, r7 + + add r2, r2, r6 + add r3, r3, r7 + + add r6, r10, r5 + sub r7, r11, r4 + + sub r0, r10, r5 + add r1, r11, r4 + + strd r6, [r14, #8] + strd r8, [r14, #24] + strd r0, [r14, #40] + strd r2, [r14, #56] + + subs r12, r12, #1 + add r14, r14, #64 + + bne Radix8First_LOOP + +Radix8First_END: + add sp, sp, #0x24 + ldmia sp!, {r4 - r11, pc} + +DATATab: + .word 0x5a82799a + + @ENDP @ |Radix8First| + .end diff --git a/jni/src/asm/ARMV5E/Radix4FFT_v5.s b/jni/src/asm/ARMV5E/Radix4FFT_v5.s new file mode 100644 index 000000000..b59b967ad --- /dev/null +++ b/jni/src/asm/ARMV5E/Radix4FFT_v5.s @@ -0,0 +1,169 @@ +@/* +@ ** Copyright 2003-2010, VisualOn, Inc. +@ ** +@ ** Licensed under the Apache License, Version 2.0 (the "License"); +@ ** you may not use this file except in compliance with the License. +@ ** You may obtain a copy of the License at +@ ** +@ ** http://www.apache.org/licenses/LICENSE-2.0 +@ ** +@ ** Unless required by applicable law or agreed to in writing, software +@ ** distributed under the License is distributed on an "AS IS" BASIS, +@ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@ ** See the License for the specific language governing permissions and +@ ** limitations under the License. +@ */ + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ File: Radix4FFT_v5.s +@ +@ Content: Radix4FFT armv5 assemble +@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + .section .text + .global Radix4FFT + +Radix4FFT: + stmdb sp!, {r4 - r11, lr} + sub sp, sp, #32 + + mov r1, r1, asr #2 + cmp r1, #0 + beq Radix4FFT_END + +Radix4FFT_LOOP1: + mov r14, r0 @ xptr = buf@ + mov r10, r1 @ i = num@ + mov r9, r2, lsl #3 @ step = 2*bgn@ + cmp r10, #0 + str r0, [sp] + str r1, [sp, #4] + str r2, [sp, #8] + str r3, [sp, #12] + beq Radix4FFT_LOOP1_END + +Radix4FFT_LOOP2: + mov r12, r3 @ csptr = twidTab@ + mov r11, r2 @ j = bgn + cmp r11, #0 + str r10, [sp, #16] + beq Radix4FFT_LOOP2_END + +Radix4FFT_LOOP3: + str r11, [sp, #20] + + ldrd r0, [r14, #0] @ r0 = xptr[0]@ r1 = xptr[1]@ + add r14, r14, r9 @ xptr += step@ + + ldrd r10, [r14, #0] @ r2 = xptr[0]@ r3 = xptr[1]@ + ldr r8, [r12], #4 @ cosxsinx = csptr[0]@ + + smulwt r4, r10, r8 @ L_mpy_wx(cosx, t0) + smulwt r3, r11, r8 @ L_mpy_wx(cosx, t1) + + smlawb r2, r11, r8, r4 @ r2 = L_mpy_wx(cosx, t0) + L_mpy_wx(sinx, t1)@ + smulwb r5, r10, r8 @ L_mpy_wx(sinx, t0) + + mov r10, r0, asr #2 @ t0 = r0 >> 2@ + mov r11, r1, asr #2 @ t1 = r1 >> 2@ + + sub r3, r3, r5 @ r3 = L_mpy_wx(cosx, t1) - L_mpy_wx(sinx, t0)@ + add r14, r14, r9 @ xptr += step@ + + sub r0, r10, r2 @ r0 = t0 - r2@ + sub r1, r11, r3 @ r1 = t1 - r3@ + + add r2, r10, r2 @ r2 = t0 + r2@ + add r3, r11, r3 @ r3 = t1 + r3@ + + str r2, [sp, #24] + str r3, [sp, #28] + + ldrd r10, [r14, #0] @ r4 = xptr[0]@ r5 = xptr[1]@ + ldr r8, [r12], #4 @ cosxsinx = csptr[1]@ + + smulwt r6, r10, r8 @ L_mpy_wx(cosx, t0) + smulwt r5, r11, r8 @ L_mpy_wx(cosx, t1) + + smlawb r4, r11, r8, r6 @ r4 = L_mpy_wx(cosx, t0) + L_mpy_wx(sinx, t1)@ + smulwb r7, r10, r8 @ L_mpy_wx(sinx, t0) + + add r14, r14, r9 @ xptr += step@ + sub r5, r5, r7 @ r5 = L_mpy_wx(cosx, t1) - L_mpy_wx(sinx, t0)@ + + ldrd r10, [r14] @ r6 = xptr[0]@ r7 = xptr[1]@ + ldr r8, [r12], #4 @ cosxsinx = csptr[1]@ + + smulwt r2, r10, r8 @ L_mpy_wx(cosx, t0) + smulwt r7, r11, r8 @ L_mpy_wx(cosx, t1) + + smlawb r6, r11, r8, r2 @ r4 = L_mpy_wx(cosx, t0) + L_mpy_wx(sinx, t1)@ + smulwb r3, r10, r8 @ L_mpy_wx(sinx, t0) + + mov r10, r4 @ t0 = r4@ + mov r11, r5 @ t1 = r5@ + + sub r7, r7, r3 @ r5 = L_mpy_wx(cosx, t1) - L_mpy_wx(sinx, t0)@ + + + add r4, r10, r6 @ r4 = t0 + r6@ + sub r5, r7, r11 @ r5 = r7 - t1@ + + sub r6, r10, r6 @ r6 = t0 - r6@ + add r7, r7, r11 @ r7 = r7 + t1@ + + ldr r2, [sp, #24] + ldr r3, [sp, #28] + + add r10, r0, r5 @ xptr[0] = r0 + r5@ + add r11, r1, r6 @ xptr[0] = r1 + r6 + + strd r10, [r14] + sub r14, r14, r9 @ xptr -= step@ + + sub r10, r2, r4 @ xptr[0] = r2 - r4@ + sub r11, r3, r7 @ xptr[1] = r3 - r7@ + + strd r10, [r14] + sub r14, r14, r9 @ xptr -= step@ + + sub r10, r0, r5 @ xptr[0] = r0 - r5@ + sub r11, r1, r6 @ xptr[0] = r1 - r6 + + strd r10, [r14] + sub r14, r14, r9 @ xptr -= step@ + + add r10, r2, r4 @ xptr[0] = r2 - r4@ + add r11, r3, r7 @ xptr[1] = r3 - r7@ + + strd r10, [r14] + add r14, r14, #8 @ xptr += 2@ + + ldr r11, [sp, #20] + subs r11, r11, #1 + bne Radix4FFT_LOOP3 + +Radix4FFT_LOOP2_END: + ldr r10, [sp, #16] + ldr r3, [sp, #12] + ldr r2, [sp, #8] + rsb r8, r9, r9, lsl #2 + sub r10, r10, #1 + add r14, r14, r8 + cmp r10, #0 + bhi Radix4FFT_LOOP2 + +Radix4FFT_LOOP1_END: + ldr r0, [sp] + ldr r1, [sp, #4] + add r3, r3, r8, asr #1 + mov r2, r2, lsl #2 + movs r1, r1, asr #2 + bne Radix4FFT_LOOP1 + +Radix4FFT_END: + add sp, sp, #32 + ldmia sp!, {r4 - r11, pc} + + @ENDP @ |Radix4FFT| + .end diff --git a/jni/src/asm/ARMV5E/band_nrg_v5.s b/jni/src/asm/ARMV5E/band_nrg_v5.s new file mode 100644 index 000000000..4789f6d1d --- /dev/null +++ b/jni/src/asm/ARMV5E/band_nrg_v5.s @@ -0,0 +1,204 @@ +@/* +@ ** Copyright 2003-2010, VisualOn, Inc. +@ ** +@ ** Licensed under the Apache License, Version 2.0 (the "License"); +@ ** you may not use this file except in compliance with the License. +@ ** You may obtain a copy of the License at +@ ** +@ ** http://www.apache.org/licenses/LICENSE-2.0 +@ ** +@ ** Unless required by applicable law or agreed to in writing, software +@ ** distributed under the License is distributed on an "AS IS" BASIS, +@ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@ ** See the License for the specific language governing permissions and +@ ** limitations under the License. +@ */ + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ File: band_nrg_v5.s +@ +@ Content: CalcBandEnergy and CalcBandEnergyMS function armv5 assemble +@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + .section .text + + .global CalcBandEnergy + +CalcBandEnergy: + stmdb sp!, {r4 - r11, lr} + + mov r2, r2, lsl #16 + ldr r12, [r13, #36] + mov r9, #0 + mov r5, r2, asr #16 + mov r4, #0 + cmp r5, #0 + ble L212 + +L22: + mov r2, r4, lsl #1 + ldrsh r10, [r1, r2] + add r11, r1, r2 + ldrsh r2, [r11, #2] + mov r14, #0 + cmp r10, r2 + bge L28 + +L23: + ldr r11, [r0, +r10, lsl #2] + add r10, r10, #1 + ldr r6, [r0, +r10, lsl #2] + smull r11, r7, r11, r11 + add r10, r10, #1 + smull r6, r8, r6, r6 + ldr r11, [r0, +r10, lsl #2] + qadd r14, r14, r7 + add r10, r10, #1 + smull r11, r7, r11, r11 + ldr r6, [r0, +r10, lsl #2] + qadd r14, r14, r8 + smull r6, r8, r6, r6 + add r10, r10, #1 + qadd r14, r14, r7 + cmp r10, r2 + qadd r14, r14, r8 + blt L23 + +L28: + qadd r14, r14, r14 + str r14, [r3, +r4, lsl #2] + add r4, r4, #1 + qadd r9, r9, r14 + cmp r4, r5 + + blt L22 + +L212: + str r9, [r12, #0] + ldmia sp!, {r4 - r11, pc} + + @ENDP ; |CalcBandEnergy| + + .global CalcBandEnergyMS + +CalcBandEnergyMS: + stmdb sp!, {r4 - r11, lr} + sub r13, r13, #24 + + mov r12, #0 + mov r3, r3, lsl #16 + mov r14, #0 + mov r3, r3, asr #16 + cmp r3, #0 + mov r4, #0 + ble L315 + +L32: + mov r5, r4, lsl #1 + mov r6, #0 + ldrsh r10, [r2, r5] + add r5, r2, r5 + mov r7, #0 + ldrsh r11, [r5, #2] + cmp r10, r11 + bge L39 + + str r3, [r13, #4] + str r4, [r13, #8] + str r12, [r13, #12] + str r14, [r13, #16] + +L33: + ldr r8, [r0, +r10, lsl #2] + ldr r9, [r1, +r10, lsl #2] + mov r8, r8, asr #1 + add r10, r10, #1 + mov r9, r9, asr #1 + + ldr r12, [r0, +r10, lsl #2] + add r5, r8, r9 + ldr r14, [r1, +r10, lsl #2] + sub r8, r8, r9 + + smull r5, r3, r5, r5 + mov r12, r12, asr #1 + smull r8, r4, r8, r8 + mov r14, r14, asr #1 + + qadd r6, r6, r3 + add r5, r12, r14 + qadd r7, r7, r4 + sub r8, r12, r14 + + smull r5, r3, r5, r5 + add r10, r10, #1 + smull r8, r4, r8, r8 + + qadd r6, r6, r3 + qadd r7, r7, r4 + + ldr r8, [r0, +r10, lsl #2] + ldr r9, [r1, +r10, lsl #2] + mov r8, r8, asr #1 + add r10, r10, #1 + mov r9, r9, asr #1 + + ldr r12, [r0, +r10, lsl #2] + add r5, r8, r9 + ldr r14, [r1, +r10, lsl #2] + sub r8, r8, r9 + + smull r5, r3, r5, r5 + mov r12, r12, asr #1 + smull r8, r4, r8, r8 + mov r14, r14, asr #1 + + qadd r6, r6, r3 + add r5, r12, r14 + qadd r7, r7, r4 + sub r8, r12, r14 + + smull r5, r3, r5, r5 + add r10, r10, #1 + smull r8, r4, r8, r8 + + qadd r6, r6, r3 + qadd r7, r7, r4 + + cmp r10, r11 + + blt L33 + + ldr r3, [r13, #4] + ldr r4, [r13, #8] + ldr r12, [r13, #12] + ldr r14, [r13, #16] +L39: + qadd r6, r6, r6 + qadd r7, r7, r7 + + ldr r8, [r13, #60] + ldr r9, [r13, #68] + + qadd r12, r12, r6 + qadd r14, r14, r7 + + str r6, [r8, +r4, lsl #2] + str r7, [r9, +r4, lsl #2] + + add r4, r4, #1 + cmp r4, r3 + blt L32 + +L315: + ldr r8, [r13, #64] + ldr r9, [r13, #72] + str r12, [r8, #0] + str r14, [r9, #0] + + add r13, r13, #24 + ldmia sp!, {r4 - r11, pc} + @ENDP ; |CalcBandEnergyMS| + + .end diff --git a/jni/src/asm/ARMV7/PrePostMDCT_v7.s b/jni/src/asm/ARMV7/PrePostMDCT_v7.s new file mode 100644 index 000000000..b2bc9d9b7 --- /dev/null +++ b/jni/src/asm/ARMV7/PrePostMDCT_v7.s @@ -0,0 +1,135 @@ +@/* +@ ** Copyright 2003-2010, VisualOn, Inc. +@ ** +@ ** Licensed under the Apache License, Version 2.0 (the "License"); +@ ** you may not use this file except in compliance with the License. +@ ** You may obtain a copy of the License at +@ ** +@ ** http://www.apache.org/licenses/LICENSE-2.0 +@ ** +@ ** Unless required by applicable law or agreed to in writing, software +@ ** distributed under the License is distributed on an "AS IS" BASIS, +@ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@ ** See the License for the specific language governing permissions and +@ ** limitations under the License. +@ */ + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ File: PrePostMDCT_v7.s +@ +@ Content: premdct and postmdct function armv7 assemble +@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + .section .text + .global PreMDCT + +PreMDCT: + stmdb sp!, {r4 - r11, lr} + + add r9, r0, r1, lsl #2 + sub r3, r9, #32 + + movs r1, r1, asr #2 + beq PreMDCT_END + +PreMDCT_LOOP: + VLD4.I32 {d0, d2, d4, d6}, [r2]! @ cosa = *csptr++@ sina = *csptr++@ + VLD4.I32 {d1, d3, d5, d7}, [r2]! @ cosb = *csptr++@ sinb = *csptr++@ + VLD2.I32 {d8, d9, d10, d11}, [r0] @ tr1 = *(buf0 + 0)@ ti2 = *(buf0 + 1)@ + VLD2.I32 {d13, d15}, [r3]! @ tr2 = *(buf1 - 1)@ ti1 = *(buf1 + 0)@ + VLD2.I32 {d12, d14}, [r3]! @ tr2 = *(buf1 - 1)@ ti1 = *(buf1 + 0)@ + + VREV64.32 Q8, Q7 + VREV64.32 Q9, Q6 + + + VQDMULH.S32 Q10, Q0, Q4 @ MULHIGH(cosa, tr1) + VQDMULH.S32 Q11, Q1, Q8 @ MULHIGH(sina, ti1) + VQDMULH.S32 Q12, Q0, Q8 @ MULHIGH(cosa, ti1) + VQDMULH.S32 Q13, Q1, Q4 @ MULHIGH(sina, tr1) + + VADD.S32 Q0, Q10, Q11 @ *buf0++ = MULHIGH(cosa, tr1) + MULHIGH(sina, ti1)@ + VSUB.S32 Q1, Q12, Q13 @ *buf0++ = MULHIGH(cosa, ti1) - MULHIGH(sina, tr1)@ + + VST2.I32 {d0, d1, d2, d3}, [r0]! + sub r3, r3, #32 + + VQDMULH.S32 Q10, Q2, Q9 @ MULHIGH(cosb, tr2) + VQDMULH.S32 Q11, Q3, Q5 @ MULHIGH(sinb, ti2) + VQDMULH.S32 Q12, Q2, Q5 @ MULHIGH(cosb, ti2) + VQDMULH.S32 Q13, Q3, Q9 @ MULHIGH(sinb, tr2) + + VADD.S32 Q0, Q10, Q11 @ MULHIGH(cosa, tr2) + MULHIGH(sina, ti2)@ + VSUB.S32 Q1, Q12, Q13 @ MULHIGH(cosa, ti2) - MULHIGH(sina, tr2)@ + + VREV64.32 Q3, Q1 + VREV64.32 Q2, Q0 + + VST2.I32 {d5, d7}, [r3]! + VST2.I32 {d4, d6}, [r3]! + + subs r1, r1, #4 + sub r3, r3, #64 + bne PreMDCT_LOOP + +PreMDCT_END: + ldmia sp!, {r4 - r11, pc} + @ENDP @ |PreMDCT| + + .section .text + .global PostMDCT + +PostMDCT: + stmdb sp!, {r4 - r11, lr} + + add r9, r0, r1, lsl #2 + sub r3, r9, #32 + + movs r1, r1, asr #2 + beq PostMDCT_END + +PostMDCT_LOOP: + VLD4.I32 {d0, d2, d4, d6}, [r2]! @ cosa = *csptr++@ sina = *csptr++@ + VLD4.I32 {d1, d3, d5, d7}, [r2]! @ cosb = *csptr++@ sinb = *csptr++@ + VLD2.I32 {d8, d9, d10, d11}, [r0] @ tr1 = *(zbuf1 + 0)@ ti1 = *(zbuf1 + 1)@ + VLD2.I32 {d13, d15}, [r3]! @ tr2 = *(zbuf2 - 1)@ ti2 = *(zbuf2 + 0)@ + VLD2.I32 {d12, d14}, [r3]! @ tr2 = *(zbuf2 - 1)@ ti2 = *(zbuf2 + 0)@ + + VREV64.32 Q8, Q6 + VREV64.32 Q9, Q7 + + VQDMULH.S32 Q10, Q0, Q4 @ MULHIGH(cosa, tr1) + VQDMULH.S32 Q11, Q1, Q5 @ MULHIGH(sina, ti1) + VQDMULH.S32 Q12, Q0, Q5 @ MULHIGH(cosa, ti1) + VQDMULH.S32 Q13, Q1, Q4 @ MULHIGH(sina, tr1) + + VADD.S32 Q0, Q10, Q11 @ *buf0++ = MULHIGH(cosa, tr1) + MULHIGH(sina, ti1)@ + VSUB.S32 Q5, Q13, Q12 @ *buf1-- = MULHIGH(sina, tr1) - MULHIGH(cosa, ti1)@ + + VQDMULH.S32 Q10, Q2, Q8 @ MULHIGH(cosb, tr2) + VQDMULH.S32 Q11, Q3, Q9 @ MULHIGH(sinb, ti2) + VQDMULH.S32 Q12, Q2, Q9 @ MULHIGH(cosb, ti2) + VQDMULH.S32 Q13, Q3, Q8 @ MULHIGH(sinb, tr2) + + VADD.S32 Q4, Q10, Q11 @ *buf1-- = MULHIGH(cosa, tr2) + MULHIGH(sina, ti2)@ + VSUB.S32 Q1, Q13, Q12 @ *buf0++ = MULHIGH(sina, tr2) - MULHIGH(cosa, ti2)@ + + VREV64.32 Q2, Q4 + VREV64.32 Q3, Q5 + + sub r3, r3, #32 + VST2.I32 {d0, d1, d2, d3}, [r0]! + + VST2.I32 {d5, d7}, [r3]! + VST2.I32 {d4, d6}, [r3]! + + subs r1, r1, #4 + sub r3, r3, #64 + bne PostMDCT_LOOP + +PostMDCT_END: + ldmia sp!, {r4 - r11, pc} + + @ENDP @ |PostMDCT| + .end diff --git a/jni/src/asm/ARMV7/R4R8First_v7.s b/jni/src/asm/ARMV7/R4R8First_v7.s new file mode 100644 index 000000000..3033156a5 --- /dev/null +++ b/jni/src/asm/ARMV7/R4R8First_v7.s @@ -0,0 +1,146 @@ +@/* +@ ** Copyright 2003-2010, VisualOn, Inc. +@ ** +@ ** Licensed under the Apache License, Version 2.0 (the "License"); +@ ** you may not use this file except in compliance with the License. +@ ** You may obtain a copy of the License at +@ ** +@ ** http://www.apache.org/licenses/LICENSE-2.0 +@ ** +@ ** Unless required by applicable law or agreed to in writing, software +@ ** distributed under the License is distributed on an "AS IS" BASIS, +@ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@ ** See the License for the specific language governing permissions and +@ ** limitations under the License. +@ */ + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ File: R4R8First_v7.s +@ +@ Content: Radix8First and Radix4First function armv7 assemble +@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + .section .text + .global Radix8First + +Radix8First: + stmdb sp!, {r4 - r11, lr} + + ldr r3, SQRT1_2 + cmp r1, #0 + + VDUP.I32 Q15, r3 + beq Radix8First_END + +Radix8First_LOOP: + VLD1.I32 {d0, d1, d2, d3}, [r0]! + VLD1.I32 {d8, d9, d10, d11}, [r0]! + + VADD.S32 d4, d0, d1 @ r0 = buf[0] + buf[2]@i0 = buf[1] + buf[3]@ + VSUB.S32 d5, d0, d1 @ r1 = buf[0] - buf[2]@i1 = buf[1] - buf[3]@ + VSUB.S32 d7, d2, d3 @ r2 = buf[4] - buf[6]@i2 = buf[5] - buf[7]@ + VADD.S32 d6, d2, d3 @ r3 = buf[4] + buf[6]@i3 = buf[5] + buf[7]@ + VREV64.I32 d7, d7 + + VADD.S32 Q0, Q2, Q3 @ r4 = (r0 + r2)@i4 = (i0 + i2)@i6 = (i1 + r3)@r7 = (r1 + i3) + VSUB.S32 Q1, Q2, Q3 @ r5 = (r0 - r2)@i5 = (i0 - i2)@r6 = (r1 - i3)@i7 = (i1 - r3)@ + + VREV64.I32 d3, d3 + + VADD.S32 d4, d8, d9 @ r0 = buf[ 8] + buf[10]@i0 = buf[ 9] + buf[11]@ + VSUB.S32 d7, d10, d11 @ r1 = buf[12] - buf[14]@i1 = buf[13] - buf[15]@ + VADD.S32 d6, d10, d11 @ r2 = buf[12] + buf[14]@i2 = buf[13] + buf[15]@ + VREV64.I32 d7, d7 + VSUB.S32 d5, d8, d9 @ r3 = buf[ 8] - buf[10]@i3 = buf[ 9] - buf[11]@ + + VTRN.32 d1, d3 + + VADD.S32 Q4, Q2, Q3 @ t0 = (r0 + r2) >> 1@t1 = (i0 + i2) >> 1@i0 = i1 + r3@r2 = r1 + i3@ + VSUB.S32 Q5, Q2, Q3 @ t2 = (r0 - r2) >> 1@t3 = (i0 - i2) >> 1@r0 = r1 - i3@i2 = i1 - r3@ + + VREV64.I32 d3, d3 + + VSHR.S32 d8, d8, #1 + VSHR.S32 Q0, Q0, #1 + VREV64.I32 d10, d10 + VTRN.32 d11, d9 + VSHR.S32 Q1, Q1, #1 + VSHR.S32 d10, d10, #1 + VREV64.I32 d9, d9 + + sub r0, r0, #0x40 + + VADD.S32 d12, d0, d8 + VSUB.S32 d16, d0, d8 + VADD.S32 d14, d2, d10 + VSUB.S32 d18, d2, d10 + + VSUB.S32 d4, d11, d9 + VADD.S32 d5, d11, d9 + + VREV64.I32 d18, d18 + + VQDMULH.S32 Q3, Q2, Q15 + VTRN.32 d14, d18 + VTRN.32 d6, d7 + VREV64.I32 d18, d18 + + VSUB.S32 d15, d3, d6 + VREV64.I32 d7, d7 + VADD.S32 d19, d3, d6 + VADD.S32 d13, d1, d7 + VSUB.S32 d17, d1, d7 + + VREV64.I32 d17, d17 + VTRN.32 d13, d17 + VREV64.I32 d17, d17 + + subs r1, r1, #1 + + VST1.I32 {d12, d13, d14, d15}, [r0]! + VST1.I32 {d16, d17, d18, d19}, [r0]! + bne Radix8First_LOOP + +Radix8First_END: + ldmia sp!, {r4 - r11, pc} +SQRT1_2: + .word 0x2d413ccd + + @ENDP @ |Radix8First| + + .section .text + .global Radix4First + +Radix4First: + stmdb sp!, {r4 - r11, lr} + + cmp r1, #0 + beq Radix4First_END + +Radix4First_LOOP: + VLD1.I32 {d0, d1, d2, d3}, [r0] + + VADD.S32 d4, d0, d1 @ r0 = buf[0] + buf[2]@ r1 = buf[1] + buf[3]@ + VSUB.S32 d5, d0, d1 @ r2 = buf[0] - buf[2]@ r3 = buf[1] - buf[3]@ + VSUB.S32 d7, d2, d3 @ r4 = buf[4] + buf[6]@ r5 = buf[5] + buf[7]@ + VADD.S32 d6, d2, d3 @ r6 = buf[4] - buf[6]@ r7 = buf[5] - buf[7]@ + + VREV64.I32 d7, d7 @ + + VADD.S32 Q4, Q2, Q3 + VSUB.S32 Q5, Q2, Q3 + + VREV64.I32 d11, d11 + VTRN.32 d9, d11 + subs r1, r1, #1 + VREV64.I32 d11, d11 + VST1.I32 {d8, d9, d10, d11}, [r0]! + + bne Radix4First_LOOP + +Radix4First_END: + ldmia sp!, {r4 - r11, pc} + + @ENDP @ |Radix4First| + .end diff --git a/jni/src/asm/ARMV7/Radix4FFT_v7.s b/jni/src/asm/ARMV7/Radix4FFT_v7.s new file mode 100644 index 000000000..f8748256b --- /dev/null +++ b/jni/src/asm/ARMV7/Radix4FFT_v7.s @@ -0,0 +1,143 @@ +@/* +@ ** Copyright 2003-2010, VisualOn, Inc. +@ ** +@ ** Licensed under the Apache License, Version 2.0 (the "License"); +@ ** you may not use this file except in compliance with the License. +@ ** You may obtain a copy of the License at +@ ** +@ ** http://www.apache.org/licenses/LICENSE-2.0 +@ ** +@ ** Unless required by applicable law or agreed to in writing, software +@ ** distributed under the License is distributed on an "AS IS" BASIS, +@ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@ ** See the License for the specific language governing permissions and +@ ** limitations under the License. +@ */ + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ File: Radix4FFT_v7.s +@ +@ Content: Radix4FFT armv7 assemble +@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + .section .text + .global Radix4FFT + +Radix4FFT: + stmdb sp!, {r4 - r11, lr} + + mov r1, r1, asr #2 + cmp r1, #0 + beq Radix4FFT_END + +Radix4FFT_LOOP1: + mov r5, r2, lsl #1 + mov r8, r0 + mov r7, r1 + mov r5, r5, lsl #2 + cmp r1, #0 + rsbeq r12, r5, r5, lsl #2 + beq Radix4FFT_LOOP1_END + + rsb r12, r5, r5, lsl #2 + +Radix4FFT_LOOP2: + mov r6, r3 + mov r4, r2 + cmp r2, #0 + beq Radix4FFT_LOOP2_END + +Radix4FFT_LOOP3: + @r0 = xptr[0]@ + @r1 = xptr[1]@ + VLD2.I32 {D0, D1, D2, D3}, [r8] + VLD2.I32 {D28, D29, D30, D31}, [r6]! @ cosx = csptr[0]@ sinx = csptr[1]@ + + add r8, r8, r5 @ xptr += step@ + VLD2.I32 {D4, D5, D6,D7}, [r8] @ r2 = xptr[0]@ r3 = xptr[1]@ + + VQDMULH.S32 Q10, Q2, Q14 @ MULHIGH(cosx, t0) + VQDMULH.S32 Q11, Q3, Q15 @ MULHIGH(sinx, t1) + VQDMULH.S32 Q12, Q3, Q14 @ MULHIGH(cosx, t1) + VQDMULH.S32 Q13, Q2, Q15 @ MULHIGH(sinx, t0) + + VADD.S32 Q2, Q10, Q11 @ MULHIGH(cosx, t0) + MULHIGH(sinx, t1) + VSUB.S32 Q3, Q12, Q13 @ MULHIGH(cosx, t1) - MULHIGH(sinx, t0) + + add r8, r8, r5 @ xptr += step@ + VSHR.S32 Q10, Q0, #2 @ t0 = r0 >> 2@ + VSHR.S32 Q11, Q1, #2 @ t1 = r1 >> 2@ + + VSUB.S32 Q0, Q10, Q2 @ r0 = t0 - r2@ + VSUB.S32 Q1, Q11, Q3 @ r1 = t1 - r3@ + VADD.S32 Q2, Q10, Q2 @ r2 = t0 + r2@ + VADD.S32 Q3, Q11, Q3 @ r3 = t1 + r3@ + + VLD2.I32 {D8, D9, D10, D11}, [r8] + VLD2.I32 {D28, D29, D30, D31}, [r6]! + add r8, r8, r5 + + VQDMULH.S32 Q10, Q4, Q14 @ MULHIGH(cosx, t0) + VQDMULH.S32 Q11, Q5, Q15 @ MULHIGH(sinx, t1) + VQDMULH.S32 Q12, Q5, Q14 @ MULHIGH(cosx, t1) + VQDMULH.S32 Q13, Q4, Q15 @ MULHIGH(sinx, t0) + + VADD.S32 Q8, Q10, Q11 @ MULHIGH(cosx, t0) + MULHIGH(sinx, t1) + VSUB.S32 Q9, Q12, Q13 @ MULHIGH(cosx, t1) - MULHIGH(sinx, t0) + + VLD2.I32 {D12, D13, D14, D15}, [r8] + VLD2.I32 {D28, D29, D30, D31}, [r6]! + + VQDMULH.S32 Q10, Q6, Q14 @ MULHIGH(cosx, t0) + VQDMULH.S32 Q11, Q7, Q15 @ MULHIGH(sinx, t1) + VQDMULH.S32 Q12, Q7, Q14 @ MULHIGH(cosx, t1) + VQDMULH.S32 Q13, Q6, Q15 @ MULHIGH(sinx, t0) + + VADD.S32 Q6, Q10, Q11 @ MULHIGH(cosx, t0) + MULHIGH(sinx, t1) + VSUB.S32 Q7, Q12, Q13 @ MULHIGH(cosx, t1) - MULHIGH(sinx, t0) + + VADD.S32 Q4, Q8, Q6 @ r4 = t0 + r6@ + VSUB.S32 Q5, Q7, Q9 @ r5 = r7 - t1@ + VSUB.S32 Q6, Q8, Q6 @ r6 = t0 - r6@ + VADD.S32 Q7, Q7, Q9 @ r7 = r7 + t1@ + + VADD.S32 Q8, Q0, Q5 @ xptr[0] = r0 + r5@ + VADD.S32 Q9, Q1, Q6 @ xptr[1] = r1 + r6@ + VST2.I32 {D16, D17, D18, D19}, [r8] + + VSUB.S32 Q10, Q2, Q4 @ xptr[0] = r2 - r4@ + sub r8, r8, r5 @ xptr -= step@ + VSUB.S32 Q11, Q3, Q7 @ xptr[1] = r3 - r7@ + VST2.I32 {D20, D21, D22, D23}, [r8] + + VSUB.S32 Q8, Q0, Q5 @ xptr[0] = r0 - r5@ + sub r8, r8, r5 @ xptr -= step@ + VSUB.S32 Q9, Q1, Q6 @ xptr[1] = r1 - r6@ + VST2.I32 {D16, D17, D18, D19}, [r8] + + VADD.S32 Q10, Q2, Q4 @ xptr[0] = r2 + r4@ + sub r8, r8, r5 @ xptr -= step@ + VADD.S32 Q11, Q3, Q7 @ xptr[1] = r3 + r7@ + VST2.I32 {D20, D21, D22, D23}, [r8]! + + subs r4, r4, #4 + bne Radix4FFT_LOOP3 + +Radix4FFT_LOOP2_END: + add r8, r8, r12 + sub r7, r7, #1 + cmp r7, #0 + bhi Radix4FFT_LOOP2 + +Radix4FFT_LOOP1_END: + add r3, r12, r3 + mov r2, r2, lsl #2 + movs r1, r1, asr #2 + bne Radix4FFT_LOOP1 + +Radix4FFT_END: + ldmia sp!, {r4 - r11, pc} + + @ENDP @ |Radix4FFT| + .end diff --git a/jni/src/band_nrg.c b/jni/src/band_nrg.c new file mode 100644 index 000000000..e4034b8a4 --- /dev/null +++ b/jni/src/band_nrg.c @@ -0,0 +1,102 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: band_nrg.c + + Content: Band/Line energy calculations functions + +*******************************************************************************/ + +#include "basic_op.h" +#include "band_nrg.h" + +#ifndef ARMV5E +/******************************************************************************** +* +* function name: CalcBandEnergy +* description: Calc sfb-bandwise mdct-energies for left and right channel +* +**********************************************************************************/ +void CalcBandEnergy(const Word32 *mdctSpectrum, + const Word16 *bandOffset, + const Word16 numBands, + Word32 *bandEnergy, + Word32 *bandEnergySum) +{ + Word32 i, j; + Word32 accuSum = 0; + + for (i=0; i> 1; + r = mdctSpectrumRight[j] >> 1; + specm = l + r; + specs = l - r; + accuMid = L_add(accuMid, MULHIGH(specm, specm)); + accuSide = L_add(accuSide, MULHIGH(specs, specs)); + } + + accuMid = L_add(accuMid, accuMid); + accuSide = L_add(accuSide, accuSide); + bandEnergyMid[i] = accuMid; + accuMidSum = L_add(accuMidSum, accuMid); + bandEnergySide[i] = accuSide; + accuSideSum = L_add(accuSideSum, accuSide); + + } + *bandEnergyMidSum = accuMidSum; + *bandEnergySideSum = accuSideSum; +} + +#endif diff --git a/jni/src/bit_cnt.c b/jni/src/bit_cnt.c new file mode 100644 index 000000000..9fe511cd9 --- /dev/null +++ b/jni/src/bit_cnt.c @@ -0,0 +1,885 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: bit_cnt.c + + Content: Huffman Bitcounter & coder functions + +*******************************************************************************/ + +#include "bit_cnt.h" +#include "aac_rom.h" + +#define HI_LTAB(a) (a>>8) +#define LO_LTAB(a) (a & 0xff) + +#define EXPAND(a) ((((Word32)(a&0xff00)) << 8)|(Word32)(a&0xff)) + + +/***************************************************************************** +* +* function name: count1_2_3_4_5_6_7_8_9_10_11 +* description: counts tables 1-11 +* returns: +* input: quantized spectrum +* output: bitCount for tables 1-11 +* +*****************************************************************************/ + +static void count1_2_3_4_5_6_7_8_9_10_11(const Word16 *values, + const Word16 width, + Word16 *bitCount) +{ + Word32 t0,t1,t2,t3,i; + Word32 bc1_2,bc3_4,bc5_6,bc7_8,bc9_10; + Word16 bc11,sc; + + bc1_2=0; + bc3_4=0; + bc5_6=0; + bc7_8=0; + bc9_10=0; + bc11=0; + sc=0; + + for(i=0;i0) + (t1>0) + (t2>0) + (t3>0); + } + + bitCount[1]=extract_h(bc1_2); + bitCount[2]=extract_l(bc1_2); + bitCount[3]=extract_h(bc3_4) + sc; + bitCount[4]=extract_l(bc3_4) + sc; + bitCount[5]=extract_h(bc5_6); + bitCount[6]=extract_l(bc5_6); + bitCount[7]=extract_h(bc7_8) + sc; + bitCount[8]=extract_l(bc7_8) + sc; + bitCount[9]=extract_h(bc9_10) + sc; + bitCount[10]=extract_l(bc9_10) + sc; + bitCount[11]=bc11 + sc; +} + + +/***************************************************************************** +* +* function name: count3_4_5_6_7_8_9_10_11 +* description: counts tables 3-11 +* returns: +* input: quantized spectrum +* output: bitCount for tables 3-11 +* +*****************************************************************************/ + +static void count3_4_5_6_7_8_9_10_11(const Word16 *values, + const Word16 width, + Word16 *bitCount) +{ + Word32 t0,t1,t2,t3, i; + Word32 bc3_4,bc5_6,bc7_8,bc9_10; + Word16 bc11,sc; + + bc3_4=0; + bc5_6=0; + bc7_8=0; + bc9_10=0; + bc11=0; + sc=0; + + for(i=0;i0) + (t1>0) + (t2>0) + (t3>0); + } + + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=extract_h(bc3_4) + sc; + bitCount[4]=extract_l(bc3_4) + sc; + bitCount[5]=extract_h(bc5_6); + bitCount[6]=extract_l(bc5_6); + bitCount[7]=extract_h(bc7_8) + sc; + bitCount[8]=extract_l(bc7_8) + sc; + bitCount[9]=extract_h(bc9_10) + sc; + bitCount[10]=extract_l(bc9_10) + sc; + bitCount[11]=bc11 + sc; + +} + + + +/***************************************************************************** +* +* function name: count5_6_7_8_9_10_11 +* description: counts tables 5-11 +* returns: +* input: quantized spectrum +* output: bitCount for tables 5-11 +* +*****************************************************************************/ +static void count5_6_7_8_9_10_11(const Word16 *values, + const Word16 width, + Word16 *bitCount) +{ + + Word32 t0,t1,i; + Word32 bc5_6,bc7_8,bc9_10; + Word16 bc11,sc; + + bc5_6=0; + bc7_8=0; + bc9_10=0; + bc11=0; + sc=0; + + for(i=0;i0) + (t1>0); + } + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=INVALID_BITCOUNT; + bitCount[4]=INVALID_BITCOUNT; + bitCount[5]=extract_h(bc5_6); + bitCount[6]=extract_l(bc5_6); + bitCount[7]=extract_h(bc7_8) + sc; + bitCount[8]=extract_l(bc7_8) + sc; + bitCount[9]=extract_h(bc9_10) + sc; + bitCount[10]=extract_l(bc9_10) + sc; + bitCount[11]=bc11 + sc; + +} + + +/***************************************************************************** +* +* function name: count7_8_9_10_11 +* description: counts tables 7-11 +* returns: +* input: quantized spectrum +* output: bitCount for tables 7-11 +* +*****************************************************************************/ + +static void count7_8_9_10_11(const Word16 *values, + const Word16 width, + Word16 *bitCount) +{ + Word32 t0,t1, i; + Word32 bc7_8,bc9_10; + Word16 bc11,sc; + + bc7_8=0; + bc9_10=0; + bc11=0; + sc=0; + + for(i=0;i0) + (t1>0); + } + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=INVALID_BITCOUNT; + bitCount[4]=INVALID_BITCOUNT; + bitCount[5]=INVALID_BITCOUNT; + bitCount[6]=INVALID_BITCOUNT; + bitCount[7]=extract_h(bc7_8) + sc; + bitCount[8]=extract_l(bc7_8) + sc; + bitCount[9]=extract_h(bc9_10) + sc; + bitCount[10]=extract_l(bc9_10) + sc; + bitCount[11]=bc11 + sc; + +} + +/***************************************************************************** +* +* function name: count9_10_11 +* description: counts tables 9-11 +* returns: +* input: quantized spectrum +* output: bitCount for tables 9-11 +* +*****************************************************************************/ +static void count9_10_11(const Word16 *values, + const Word16 width, + Word16 *bitCount) +{ + + Word32 t0,t1,i; + Word32 bc9_10; + Word16 bc11,sc; + + bc9_10=0; + bc11=0; + sc=0; + + for(i=0;i0) + (t1>0); + } + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=INVALID_BITCOUNT; + bitCount[4]=INVALID_BITCOUNT; + bitCount[5]=INVALID_BITCOUNT; + bitCount[6]=INVALID_BITCOUNT; + bitCount[7]=INVALID_BITCOUNT; + bitCount[8]=INVALID_BITCOUNT; + bitCount[9]=extract_h(bc9_10) + sc; + bitCount[10]=extract_l(bc9_10) + sc; + bitCount[11]=bc11 + sc; + +} + +/***************************************************************************** +* +* function name: count11 +* description: counts table 11 +* returns: +* input: quantized spectrum +* output: bitCount for table 11 +* +*****************************************************************************/ + static void count11(const Word16 *values, + const Word16 width, + Word16 *bitCount) +{ + Word32 t0,t1,i; + Word16 bc11,sc; + + bc11=0; + sc=0; + for(i=0;i0) + (t1>0); + } + + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=INVALID_BITCOUNT; + bitCount[4]=INVALID_BITCOUNT; + bitCount[5]=INVALID_BITCOUNT; + bitCount[6]=INVALID_BITCOUNT; + bitCount[7]=INVALID_BITCOUNT; + bitCount[8]=INVALID_BITCOUNT; + bitCount[9]=INVALID_BITCOUNT; + bitCount[10]=INVALID_BITCOUNT; + bitCount[11]=bc11 + sc; +} + +/***************************************************************************** +* +* function name: countEsc +* description: counts table 11 (with Esc) +* returns: +* input: quantized spectrum +* output: bitCount for tables 11 (with Esc) +* +*****************************************************************************/ + +static void countEsc(const Word16 *values, + const Word16 width, + Word16 *bitCount) +{ + Word32 t0,t1,t00,t01,i; + Word16 bc11,ec,sc; + + bc11=0; + sc=0; + ec=0; + for(i=0;i0) + (t1>0); + + t00 = min(t0,16); + t01 = min(t1,16); + bc11 = bc11 + huff_ltab11[t00][t01]; + + + if(t0 >= 16){ + ec = ec + 5; + while(sub(t0=(t0 >> 1), 16) >= 0) { + ec = ec + 2; + } + } + + + if(t1 >= 16){ + ec = ec + 5; + while(sub(t1=(t1 >> 1), 16) >= 0) { + ec = ec + 2; + } + } + } + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=INVALID_BITCOUNT; + bitCount[4]=INVALID_BITCOUNT; + bitCount[5]=INVALID_BITCOUNT; + bitCount[6]=INVALID_BITCOUNT; + bitCount[7]=INVALID_BITCOUNT; + bitCount[8]=INVALID_BITCOUNT; + bitCount[9]=INVALID_BITCOUNT; + bitCount[10]=INVALID_BITCOUNT; + bitCount[11]=bc11 + sc + ec; +} + + +typedef void (*COUNT_FUNCTION)(const Word16 *values, + const Word16 width, + Word16 *bitCount); + +static COUNT_FUNCTION countFuncTable[CODE_BOOK_ESC_LAV+1] = + { + + count1_2_3_4_5_6_7_8_9_10_11, /* 0 */ + count1_2_3_4_5_6_7_8_9_10_11, /* 1 */ + count3_4_5_6_7_8_9_10_11, /* 2 */ + count5_6_7_8_9_10_11, /* 3 */ + count5_6_7_8_9_10_11, /* 4 */ + count7_8_9_10_11, /* 5 */ + count7_8_9_10_11, /* 6 */ + count7_8_9_10_11, /* 7 */ + count9_10_11, /* 8 */ + count9_10_11, /* 9 */ + count9_10_11, /* 10 */ + count9_10_11, /* 11 */ + count9_10_11, /* 12 */ + count11, /* 13 */ + count11, /* 14 */ + count11, /* 15 */ + countEsc /* 16 */ + }; + +/***************************************************************************** +* +* function name: bitCount +* description: count bits +* +*****************************************************************************/ +Word16 bitCount(const Word16 *values, + const Word16 width, + Word16 maxVal, + Word16 *bitCount) +{ + /* + check if we can use codebook 0 + */ + + if(maxVal == 0) + bitCount[0] = 0; + else + bitCount[0] = INVALID_BITCOUNT; + + maxVal = min(maxVal, CODE_BOOK_ESC_LAV); + countFuncTable[maxVal](values,width,bitCount); + + return(0); +} + +/***************************************************************************** +* +* function name: codeValues +* description: write huffum bits +* +*****************************************************************************/ +Word16 codeValues(Word16 *values, Word16 width, Word16 codeBook, HANDLE_BIT_BUF hBitstream) +{ + + Word32 i, t0, t1, t2, t3, t00, t01; + UWord16 codeWord, codeLength; + Word16 sign, signLength; + + + switch (codeBook) { + case CODE_BOOK_ZERO_NO: + break; + + case CODE_BOOK_1_NO: + for(i=0; i= 16){ + Word16 n, p; + n=0; + p=t0; + while(sub(p=(p >> 1), 16) >= 0){ + + WriteBits(hBitstream,1,1); + n = n + 1; + } + WriteBits(hBitstream,0,1); + n = n + 4; + WriteBits(hBitstream,(t0 - (1 << n)),n); + } + + if(t1 >= 16){ + Word16 n, p; + n=0; + p=t1; + while(sub(p=(p >> 1), 16) >= 0){ + + WriteBits(hBitstream,1,1); + n = n + 1; + } + WriteBits(hBitstream,0,1); + n = n + 4; + WriteBits(hBitstream,(t1 - (1 << n)),n); + } + } + break; + + default: + break; + } + return(0); +} + +Word16 bitCountScalefactorDelta(Word16 delta) +{ + return(huff_ltabscf[delta+CODE_BOOK_SCF_LAV]); +} + +Word16 codeScalefactorDelta(Word16 delta, HANDLE_BIT_BUF hBitstream) +{ + Word32 codeWord; + Word16 codeLength; + + + if(delta > CODE_BOOK_SCF_LAV || delta < -CODE_BOOK_SCF_LAV) + return(1); + + codeWord = huff_ctabscf[delta + CODE_BOOK_SCF_LAV]; + codeLength = huff_ltabscf[delta + CODE_BOOK_SCF_LAV]; + WriteBits(hBitstream,codeWord,codeLength); + return(0); +} diff --git a/jni/src/bitbuffer.c b/jni/src/bitbuffer.c new file mode 100644 index 000000000..0ce93d395 --- /dev/null +++ b/jni/src/bitbuffer.c @@ -0,0 +1,173 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: bitbuffer.c + + Content: Bit Buffer Management functions + +*******************************************************************************/ + +#include "bitbuffer.h" + +/***************************************************************************** +* +* function name: updateBitBufWordPtr +* description: update Bit Buffer pointer +* +*****************************************************************************/ +static void updateBitBufWordPtr(HANDLE_BIT_BUF hBitBuf, + UWord8 **pBitBufWord, + Word16 cnt) +{ + *pBitBufWord += cnt; + + + if(*pBitBufWord > hBitBuf->pBitBufEnd) { + *pBitBufWord -= (hBitBuf->pBitBufEnd - hBitBuf->pBitBufBase + 1); + } + + if(*pBitBufWord < hBitBuf->pBitBufBase) { + *pBitBufWord += (hBitBuf->pBitBufEnd - hBitBuf->pBitBufBase + 1); + } +} + + +/***************************************************************************** +* +* function name: CreateBitBuffer +* description: create and init Bit Buffer Management +* +*****************************************************************************/ +HANDLE_BIT_BUF CreateBitBuffer(HANDLE_BIT_BUF hBitBuf, + UWord8 *pBitBufBase, + Word16 bitBufSize) +{ + assert(bitBufSize*8 <= 32768); + + hBitBuf->pBitBufBase = pBitBufBase; + hBitBuf->pBitBufEnd = pBitBufBase + bitBufSize - 1; + + hBitBuf->pWriteNext = pBitBufBase; + + hBitBuf->cache = 0; + + hBitBuf->wBitPos = 0; + hBitBuf->cntBits = 0; + + hBitBuf->size = (bitBufSize << 3); + hBitBuf->isValid = 1; + + return hBitBuf; +} + +/***************************************************************************** +* +* function name: DeleteBitBuffer +* description: uninit Bit Buffer Management +* +*****************************************************************************/ +void DeleteBitBuffer(HANDLE_BIT_BUF *hBitBuf) +{ + if(*hBitBuf) + (*hBitBuf)->isValid = 0; + *hBitBuf = NULL; +} + +/***************************************************************************** +* +* function name: ResetBitBuf +* description: reset Bit Buffer Management +* +*****************************************************************************/ +void ResetBitBuf(HANDLE_BIT_BUF hBitBuf, + UWord8 *pBitBufBase, + Word16 bitBufSize) +{ + hBitBuf->pBitBufBase = pBitBufBase; + hBitBuf->pBitBufEnd = pBitBufBase + bitBufSize - 1; + + + hBitBuf->pWriteNext = pBitBufBase; + + hBitBuf->wBitPos = 0; + hBitBuf->cntBits = 0; + + hBitBuf->cache = 0; +} + +/***************************************************************************** +* +* function name: CopyBitBuf +* description: copy Bit Buffer Management +* +*****************************************************************************/ +void CopyBitBuf(HANDLE_BIT_BUF hBitBufSrc, + HANDLE_BIT_BUF hBitBufDst) +{ + *hBitBufDst = *hBitBufSrc; +} + +/***************************************************************************** +* +* function name: GetBitsAvail +* description: get available bits +* +*****************************************************************************/ +Word16 GetBitsAvail(HANDLE_BIT_BUF hBitBuf) +{ + return hBitBuf->cntBits; +} + +/***************************************************************************** +* +* function name: WriteBits +* description: write bits to the buffer +* +*****************************************************************************/ +Word16 WriteBits(HANDLE_BIT_BUF hBitBuf, + UWord32 writeValue, + Word16 noBitsToWrite) +{ + Word16 wBitPos; + + assert(noBitsToWrite <= (Word16)sizeof(Word32)*8); + + if(noBitsToWrite == 0) + return noBitsToWrite; + + hBitBuf->cntBits += noBitsToWrite; + + wBitPos = hBitBuf->wBitPos; + wBitPos += noBitsToWrite; + writeValue &= ~(0xffffffff << noBitsToWrite); // Mask out everything except the lowest noBitsToWrite bits + writeValue <<= 32 - wBitPos; + writeValue |= hBitBuf->cache; + + while (wBitPos >= 8) + { + UWord8 tmp; + tmp = (UWord8)((writeValue >> 24) & 0xFF); + + *hBitBuf->pWriteNext++ = tmp; + writeValue <<= 8; + wBitPos -= 8; + } + + hBitBuf->wBitPos = wBitPos; + hBitBuf->cache = writeValue; + + return noBitsToWrite; +} diff --git a/jni/src/bitenc.c b/jni/src/bitenc.c new file mode 100644 index 000000000..fcc12ddfc --- /dev/null +++ b/jni/src/bitenc.c @@ -0,0 +1,690 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: bitenc.c + + Content: Bitstream encoder functions + +*******************************************************************************/ + +#include "bitenc.h" +#include "bit_cnt.h" +#include "dyn_bits.h" +#include "qc_data.h" +#include "interface.h" + + +static const Word16 globalGainOffset = 100; +static const Word16 icsReservedBit = 0; + + +/***************************************************************************** +* +* function name: encodeSpectralData +* description: encode spectral data +* returns: spectral bits used +* +*****************************************************************************/ +static Word32 encodeSpectralData(Word16 *sfbOffset, + SECTION_DATA *sectionData, + Word16 *quantSpectrum, + HANDLE_BIT_BUF hBitStream) +{ + Word16 i,sfb; + Word16 dbgVal; + SECTION_INFO* psectioninfo; + dbgVal = GetBitsAvail(hBitStream); + + for(i=0; inoOfSections; i++) { + psectioninfo = &(sectionData->sectionInfo[i]); + /* + huffencode spectral data for this section + */ + for(sfb=psectioninfo->sfbStart; + sfbsfbStart+psectioninfo->sfbCnt; + sfb++) { + codeValues(quantSpectrum+sfbOffset[sfb], + sfbOffset[sfb+1] - sfbOffset[sfb], + psectioninfo->codeBook, + hBitStream); + } + } + + return(GetBitsAvail(hBitStream)-dbgVal); +} + +/***************************************************************************** +* +* function name:encodeGlobalGain +* description: encodes Global Gain (common scale factor) +* returns: none +* +*****************************************************************************/ +static void encodeGlobalGain(Word16 globalGain, + Word16 logNorm, + Word16 scalefac, + HANDLE_BIT_BUF hBitStream) +{ + WriteBits(hBitStream, ((globalGain - scalefac) + globalGainOffset-(logNorm << 2)), 8); +} + + +/***************************************************************************** +* +* function name:encodeIcsInfo +* description: encodes Ics Info +* returns: none +* +*****************************************************************************/ + +static void encodeIcsInfo(Word16 blockType, + Word16 windowShape, + Word16 groupingMask, + SECTION_DATA *sectionData, + HANDLE_BIT_BUF hBitStream) +{ + WriteBits(hBitStream,icsReservedBit,1); + WriteBits(hBitStream,blockType,2); + WriteBits(hBitStream,windowShape,1); + + + switch(blockType){ + case LONG_WINDOW: + case START_WINDOW: + case STOP_WINDOW: + WriteBits(hBitStream,sectionData->maxSfbPerGroup,6); + + /* No predictor data present */ + WriteBits(hBitStream, 0, 1); + break; + + case SHORT_WINDOW: + WriteBits(hBitStream,sectionData->maxSfbPerGroup,4); + + /* + Write grouping bits + */ + WriteBits(hBitStream,groupingMask,TRANS_FAC-1); + break; + } +} + +/***************************************************************************** +* +* function name: encodeSectionData +* description: encode section data (common Huffman codebooks for adjacent +* SFB's) +* returns: none +* +*****************************************************************************/ +static Word32 encodeSectionData(SECTION_DATA *sectionData, + HANDLE_BIT_BUF hBitStream) +{ + Word16 sectEscapeVal=0,sectLenBits=0; + Word16 sectLen; + Word16 i; + Word16 dbgVal=GetBitsAvail(hBitStream); + + + + switch(sectionData->blockType) + { + case LONG_WINDOW: + case START_WINDOW: + case STOP_WINDOW: + sectEscapeVal = SECT_ESC_VAL_LONG; + sectLenBits = SECT_BITS_LONG; + break; + + case SHORT_WINDOW: + sectEscapeVal = SECT_ESC_VAL_SHORT; + sectLenBits = SECT_BITS_SHORT; + break; + } + + for(i=0;inoOfSections;i++) { + WriteBits(hBitStream,sectionData->sectionInfo[i].codeBook,4); + sectLen = sectionData->sectionInfo[i].sfbCnt; + + while(sectLen >= sectEscapeVal) { + + WriteBits(hBitStream,sectEscapeVal,sectLenBits); + sectLen = sectLen - sectEscapeVal; + } + WriteBits(hBitStream,sectLen,sectLenBits); + } + return(GetBitsAvail(hBitStream)-dbgVal); +} + +/***************************************************************************** +* +* function name: encodeScaleFactorData +* description: encode DPCM coded scale factors +* returns: none +* +*****************************************************************************/ +static Word32 encodeScaleFactorData(UWord16 *maxValueInSfb, + SECTION_DATA *sectionData, + Word16 *scalefac, + HANDLE_BIT_BUF hBitStream) +{ + Word16 i,j,lastValScf,deltaScf; + Word16 dbgVal = GetBitsAvail(hBitStream); + SECTION_INFO* psectioninfo; + + lastValScf=scalefac[sectionData->firstScf]; + + for(i=0;inoOfSections;i++){ + psectioninfo = &(sectionData->sectionInfo[i]); + if (psectioninfo->codeBook != CODE_BOOK_ZERO_NO){ + for (j=psectioninfo->sfbStart; + jsfbStart+psectioninfo->sfbCnt; j++){ + + if(maxValueInSfb[j] == 0) { + deltaScf = 0; + } + else { + deltaScf = lastValScf - scalefac[j]; + lastValScf = scalefac[j]; + } + + if(codeScalefactorDelta(deltaScf,hBitStream)){ + return(1); + } + } + } + + } + return(GetBitsAvail(hBitStream)-dbgVal); +} + +/***************************************************************************** +* +* function name:encodeMsInfo +* description: encodes MS-Stereo Info +* returns: none +* +*****************************************************************************/ +static void encodeMSInfo(Word16 sfbCnt, + Word16 grpSfb, + Word16 maxSfb, + Word16 msDigest, + Word16 *jsFlags, + HANDLE_BIT_BUF hBitStream) +{ + Word16 sfb, sfbOff; + + + switch(msDigest) + { + case MS_NONE: + WriteBits(hBitStream,SI_MS_MASK_NONE,2); + break; + + case MS_ALL: + WriteBits(hBitStream,SI_MS_MASK_ALL,2); + break; + + case MS_SOME: + WriteBits(hBitStream,SI_MS_MASK_SOME,2); + for(sfbOff = 0; sfbOff < sfbCnt; sfbOff+=grpSfb) { + for(sfb=0; sfb 3 || + tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] < -4) { + coefBits = 4; + break; + } + } + } + else { + coefBits = 2; + for(k=0; k 1 || + tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] < -2) { + coefBits = 3; + break; + } + } + } + WriteBits(hBitStream, tnsInfo.coefRes[i] - coefBits, 1); /*coef_compres*/ + for (k=0; kfirstScf], hBitStream); + + + if(!commonWindow) { + encodeIcsInfo(sectionData->blockType, windowShape, groupingMask, sectionData, hBitStream); + } + + encodeSectionData(sectionData, hBitStream); + + encodeScaleFactorData(maxValueInSfb, + sectionData, + scf, + hBitStream); + + encodePulseData(hBitStream); + + encodeTnsData(tnsInfo, sectionData->blockType, hBitStream); + + encodeGainControlData(hBitStream); + + encodeSpectralData(sfbOffset, + sectionData, + quantSpec, + hBitStream); + +} + +/***************************************************************************** +* +* function name: writeSingleChannelElement +* description: write single channel element to bitstream +* returns: none +* +*****************************************************************************/ +static Word16 writeSingleChannelElement(Word16 instanceTag, + Word16 *sfbOffset, + QC_OUT_CHANNEL* qcOutChannel, + HANDLE_BIT_BUF hBitStream, + TNS_INFO tnsInfo) +{ + WriteBits(hBitStream,ID_SCE,3); + WriteBits(hBitStream,instanceTag,4); + writeIndividualChannelStream(0, + qcOutChannel->mdctScale, + qcOutChannel->windowShape, + qcOutChannel->groupingMask, + sfbOffset, + qcOutChannel->scf, + qcOutChannel->maxValueInSfb, + qcOutChannel->globalGain, + qcOutChannel->quantSpec, + &(qcOutChannel->sectionData), + hBitStream, + tnsInfo + ); + return(0); +} + + + +/***************************************************************************** +* +* function name: writeChannelPairElement +* description: +* returns: none +* +*****************************************************************************/ +static Word16 writeChannelPairElement(Word16 instanceTag, + Word16 msDigest, + Word16 msFlags[MAX_GROUPED_SFB], + Word16 *sfbOffset[2], + QC_OUT_CHANNEL qcOutChannel[2], + HANDLE_BIT_BUF hBitStream, + TNS_INFO tnsInfo[2]) +{ + WriteBits(hBitStream,ID_CPE,3); + WriteBits(hBitStream,instanceTag,4); + WriteBits(hBitStream,1,1); /* common window */ + + encodeIcsInfo(qcOutChannel[0].sectionData.blockType, + qcOutChannel[0].windowShape, + qcOutChannel[0].groupingMask, + &(qcOutChannel[0].sectionData), + hBitStream); + + encodeMSInfo(qcOutChannel[0].sectionData.sfbCnt, + qcOutChannel[0].sectionData.sfbPerGroup, + qcOutChannel[0].sectionData.maxSfbPerGroup, + msDigest, + msFlags, + hBitStream); + + writeIndividualChannelStream(1, + qcOutChannel[0].mdctScale, + qcOutChannel[0].windowShape, + qcOutChannel[0].groupingMask, + sfbOffset[0], + qcOutChannel[0].scf, + qcOutChannel[0].maxValueInSfb, + qcOutChannel[0].globalGain, + qcOutChannel[0].quantSpec, + &(qcOutChannel[0].sectionData), + hBitStream, + tnsInfo[0]); + + writeIndividualChannelStream(1, + qcOutChannel[1].mdctScale, + qcOutChannel[1].windowShape, + qcOutChannel[1].groupingMask, + sfbOffset[1], + qcOutChannel[1].scf, + qcOutChannel[1].maxValueInSfb, + qcOutChannel[1].globalGain, + qcOutChannel[1].quantSpec, + &(qcOutChannel[1].sectionData), + hBitStream, + tnsInfo[1]); + + return(0); +} + + + +/***************************************************************************** +* +* function name: writeFillElement +* description: write fill elements to bitstream +* returns: none +* +*****************************************************************************/ +static void writeFillElement( const UWord8 *ancBytes, + Word16 totFillBits, + HANDLE_BIT_BUF hBitStream) +{ + Word16 i; + Word16 cnt,esc_count; + + /* + Write fill Element(s): + amount of a fill element can be 7+X*8 Bits, X element of [0..270] + */ + + while(totFillBits >= (3+4)) { + cnt = min(((totFillBits - (3+4)) >> 3), ((1<<4)-1)); + + WriteBits(hBitStream,ID_FIL,3); + WriteBits(hBitStream,cnt,4); + + totFillBits = totFillBits - (3+4); + + + if ((cnt == (1<<4)-1)) { + + esc_count = min( ((totFillBits >> 3) - ((1<<4)-1)), (1<<8)-1); + WriteBits(hBitStream,esc_count,8); + totFillBits = (totFillBits - 8); + cnt = cnt + (esc_count - 1); + } + + for(i=0;iqcElement.adtsUsed) /* write adts header*/ + { + WriteBits(hBitStream, 0xFFF, 12); /* 12 bit Syncword */ + WriteBits(hBitStream, 1, 1); /* ID == 0 for MPEG4 AAC, 1 for MPEG2 AAC */ + WriteBits(hBitStream, 0, 2); /* layer == 0 */ + WriteBits(hBitStream, 1, 1); /* protection absent */ + WriteBits(hBitStream, 1, 2); /* profile */ + WriteBits(hBitStream, sampindex, 4); /* sampling rate */ + WriteBits(hBitStream, 0, 1); /* private bit */ + WriteBits(hBitStream, elInfo.nChannelsInEl, 3); /* ch. config (must be > 0) */ + /* simply using numChannels only works for + 6 channels or less, else a channel + configuration should be written */ + WriteBits(hBitStream, 0, 1); /* original/copy */ + WriteBits(hBitStream, 0, 1); /* home */ + + /* Variable ADTS header */ + WriteBits(hBitStream, 0, 1); /* copyr. id. bit */ + WriteBits(hBitStream, 0, 1); /* copyr. id. start */ + WriteBits(hBitStream, *globUsedBits >> 3, 13); + WriteBits(hBitStream, 0x7FF, 11); /* buffer fullness (0x7FF for VBR) */ + WriteBits(hBitStream, 0, 2); /* raw data blocks (0+1=1) */ + } + + *globUsedBits=0; + + { + + Word16 *sfbOffset[2]; + TNS_INFO tnsInfo[2]; + elementUsedBits = 0; + + switch (elInfo.elType) { + + case ID_SCE: /* single channel */ + sfbOffset[0] = psyOut->psyOutChannel[elInfo.ChannelIndex[0]].sfbOffsets; + tnsInfo[0] = psyOut->psyOutChannel[elInfo.ChannelIndex[0]].tnsInfo; + + writeSingleChannelElement(elInfo.instanceTag, + sfbOffset[0], + &qcOut->qcChannel[elInfo.ChannelIndex[0]], + hBitStream, + tnsInfo[0]); + break; + + case ID_CPE: /* channel pair */ + { + Word16 msDigest; + Word16 *msFlags = psyOut->psyOutElement.toolsInfo.msMask; + msDigest = psyOut->psyOutElement.toolsInfo.msDigest; + sfbOffset[0] = + psyOut->psyOutChannel[elInfo.ChannelIndex[0]].sfbOffsets; + sfbOffset[1] = + psyOut->psyOutChannel[elInfo.ChannelIndex[1]].sfbOffsets; + + tnsInfo[0]= + psyOut->psyOutChannel[elInfo.ChannelIndex[0]].tnsInfo; + tnsInfo[1]= + psyOut->psyOutChannel[elInfo.ChannelIndex[1]].tnsInfo; + writeChannelPairElement(elInfo.instanceTag, + msDigest, + msFlags, + sfbOffset, + &qcOut->qcChannel[elInfo.ChannelIndex[0]], + hBitStream, + tnsInfo); + } + break; + + default: + return(1); + + } /* switch */ + + elementUsedBits = elementUsedBits - bitMarkUp; + bitMarkUp = GetBitsAvail(hBitStream); + frameBits = frameBits + elementUsedBits + bitMarkUp; + + } + + writeFillElement(NULL, + qcOut->totFillBits, + hBitStream); + + WriteBits(hBitStream,ID_END,3); + + /* byte alignement */ + WriteBits(hBitStream,0, (8 - (hBitStream->cntBits & 7)) & 7); + + *globUsedBits = *globUsedBits- bitMarkUp; + bitMarkUp = GetBitsAvail(hBitStream); + *globUsedBits = *globUsedBits + bitMarkUp; + frameBits = frameBits + *globUsedBits; + + + if (frameBits != (qcOut->totStaticBitsUsed+qcOut->totDynBitsUsed + qcOut->totAncBitsUsed + + qcOut->totFillBits + qcOut->alignBits)) { + return(-1); + } + return(0); +} diff --git a/jni/src/block_switch.c b/jni/src/block_switch.c new file mode 100644 index 000000000..47fd15e71 --- /dev/null +++ b/jni/src/block_switch.c @@ -0,0 +1,431 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: block_switch.c + + Content: Block switching functions + +*******************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "psy_const.h" +#include "block_switch.h" + + +#define ENERGY_SHIFT (8 - 1) + +/**************** internal function prototypes ***********/ +static Word16 +IIRFilter(const Word16 in, const Word32 coeff[], Word32 states[]); + +static Word32 +SrchMaxWithIndex(const Word32 *in, Word16 *index, Word16 n); + + +Word32 +CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, + Word16 *timeSignal, + Word16 chIncrement, + Word16 windowLen); + + + +/****************** Constants *****************************/ + + +/* + IIR high pass coeffs +*/ +Word32 hiPassCoeff[BLOCK_SWITCHING_IIR_LEN] = { + 0xbec8b439, 0x609d4952 /* -0.5095f, 0.7548f */ +}; + +static const Word32 accWindowNrgFac = 0x26666666; /* factor for accumulating filtered window energies 0.3 */ +static const Word32 oneMinusAccWindowNrgFac = 0x5999999a; /* 0.7 */ +static const Word32 invAttackRatioHighBr = 0x0ccccccd; /* inverted lower ratio limit for attacks 0.1*/ +static const Word32 invAttackRatioLowBr = 0x072b020c; /* 0.056 */ +static const Word32 minAttackNrg = 0x00001e84; /* minimum energy for attacks 1e+6 */ + + +/****************** Routines ****************************/ + + +/***************************************************************************** +* +* function name: InitBlockSwitching +* description: init Block Switching parameter. +* returns: TRUE if success +* +**********************************************************************************/ +Word16 InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, + const Word32 bitRate, const Word16 nChannels) +{ + /* select attackRatio */ + + if ((sub(nChannels,1)==0 && L_sub(bitRate, 24000) > 0) || + (sub(nChannels,1)>0 && bitRate > (nChannels * 16000))) { + blockSwitchingControl->invAttackRatio = invAttackRatioHighBr; + } + else { + blockSwitchingControl->invAttackRatio = invAttackRatioLowBr; + } + + return(TRUE); +} + +static Word16 suggestedGroupingTable[TRANS_FAC][MAX_NO_OF_GROUPS] = { + /* Attack in Window 0 */ {1, 3, 3, 1}, + /* Attack in Window 1 */ {1, 1, 3, 3}, + /* Attack in Window 2 */ {2, 1, 3, 2}, + /* Attack in Window 3 */ {3, 1, 3, 1}, + /* Attack in Window 4 */ {3, 1, 1, 3}, + /* Attack in Window 5 */ {3, 2, 1, 2}, + /* Attack in Window 6 */ {3, 3, 1, 1}, + /* Attack in Window 7 */ {3, 3, 1, 1} +}; + +/***************************************************************************** +* +* function name: BlockSwitching +* description: detect this frame whether there is an attack +* returns: TRUE if success +* +**********************************************************************************/ +Word16 BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, + Word16 *timeSignal, + Word32 sampleRate, + Word16 chIncrement) +{ + Word32 i, w; + Word32 enM1, enMax; + + /* Reset grouping info */ + for (i=0; igroupLen[i] = 0; + } + + + /* Search for position and amplitude of attack in last frame (1 windows delay) */ + blockSwitchingControl->maxWindowNrg = SrchMaxWithIndex( &blockSwitchingControl->windowNrg[0][BLOCK_SWITCH_WINDOWS-1], + &blockSwitchingControl->attackIndex, + BLOCK_SWITCH_WINDOWS); + + blockSwitchingControl->attackIndex = blockSwitchingControl->lastAttackIndex; + + /* Set grouping info */ + blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS; + + for (i=0; igroupLen[i] = suggestedGroupingTable[blockSwitchingControl->attackIndex][i]; + } + + /* if the samplerate is less than 16000, it should be all the short block, avoid pre&post echo */ + if(sampleRate >= 16000) { + /* Save current window energy as last window energy */ + for (w=0; wwindowNrg[0][w] = blockSwitchingControl->windowNrg[1][w]; + blockSwitchingControl->windowNrgF[0][w] = blockSwitchingControl->windowNrgF[1][w]; + } + + + /* Calculate unfiltered and filtered energies in subwindows and combine to segments */ + CalcWindowEnergy(blockSwitchingControl, timeSignal, chIncrement, BLOCK_SWITCH_WINDOW_LEN); + + /* reset attack */ + blockSwitchingControl->attack = FALSE; + + enMax = 0; + enM1 = blockSwitchingControl->windowNrgF[0][BLOCK_SWITCH_WINDOWS-1]; + + for (w=0; waccWindowNrg); + enM1_Shf = norm_l(enM1); + windowNrgF_Shf = norm_l(blockSwitchingControl->windowNrgF[1][w]); + + accWindowNrg_Tmp = blockSwitchingControl->accWindowNrg << accWindowNrg_Shf; + enM1_Tmp = enM1 << enM1_Shf; + windowNrgF_Tmp = blockSwitchingControl->windowNrgF[1][w] << windowNrgF_Shf; + + /* a sliding average of the previous energies */ + blockSwitchingControl->accWindowNrg = (fixmul(oneMinusAccWindowNrgFac, accWindowNrg_Tmp) >> accWindowNrg_Shf) + + (fixmul(accWindowNrgFac, enM1_Tmp) >> enM1_Shf); + + + /* if the energy with the ratio is bigger than the average, and the attack and short block */ + if ((fixmul(windowNrgF_Tmp, blockSwitchingControl->invAttackRatio) >> windowNrgF_Shf) > + blockSwitchingControl->accWindowNrg ) { + blockSwitchingControl->attack = TRUE; + blockSwitchingControl->lastAttackIndex = w; + } + enM1 = blockSwitchingControl->windowNrgF[1][w]; + enMax = max(enMax, enM1); + } + + if (enMax < minAttackNrg) { + blockSwitchingControl->attack = FALSE; + } + } + else + { + blockSwitchingControl->attack = TRUE; + } + + /* Check if attack spreads over frame border */ + if ((!blockSwitchingControl->attack) && (blockSwitchingControl->lastattack)) { + + if (blockSwitchingControl->attackIndex == TRANS_FAC-1) { + blockSwitchingControl->attack = TRUE; + } + + blockSwitchingControl->lastattack = FALSE; + } + else { + blockSwitchingControl->lastattack = blockSwitchingControl->attack; + } + + blockSwitchingControl->windowSequence = blockSwitchingControl->nextwindowSequence; + + + if (blockSwitchingControl->attack) { + blockSwitchingControl->nextwindowSequence = SHORT_WINDOW; + } + else { + blockSwitchingControl->nextwindowSequence = LONG_WINDOW; + } + + /* update short block group */ + if (blockSwitchingControl->nextwindowSequence == SHORT_WINDOW) { + + if (blockSwitchingControl->windowSequence== LONG_WINDOW) { + blockSwitchingControl->windowSequence = START_WINDOW; + } + + if (blockSwitchingControl->windowSequence == STOP_WINDOW) { + blockSwitchingControl->windowSequence = SHORT_WINDOW; + blockSwitchingControl->noOfGroups = 3; + blockSwitchingControl->groupLen[0] = 3; + blockSwitchingControl->groupLen[1] = 3; + blockSwitchingControl->groupLen[2] = 2; + } + } + + /* update block type */ + if (blockSwitchingControl->nextwindowSequence == LONG_WINDOW) { + + if (blockSwitchingControl->windowSequence == SHORT_WINDOW) { + blockSwitchingControl->nextwindowSequence = STOP_WINDOW; + } + } + + return(TRUE); +} + + +/***************************************************************************** +* +* function name: SrchMaxWithIndex +* description: search for the biggest value in an array +* returns: the max value +* +**********************************************************************************/ +static Word32 SrchMaxWithIndex(const Word32 in[], Word16 *index, Word16 n) +{ + Word32 max; + Word32 i, idx; + + /* Search maximum value in array and return index and value */ + max = 0; + idx = 0; + + for (i = 0; i < n; i++) { + + if (in[i+1] > max) { + max = in[i+1]; + idx = i; + } + } + *index = idx; + + return(max); +} + +/***************************************************************************** +* +* function name: CalcWindowEnergy +* description: calculate the energy before iir-filter and after irr-filter +* returns: TRUE if success +* +**********************************************************************************/ +#ifndef ARMV5E +Word32 CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, + Word16 *timeSignal, + Word16 chIncrement, + Word16 windowLen) +{ + Word32 w, i, wOffset, tidx, ch; + Word32 accuUE, accuFE; + Word32 tempUnfiltered; + Word32 tempFiltered; + Word32 states0, states1; + Word32 Coeff0, Coeff1; + + + states0 = blockSwitchingControl->iirStates[0]; + states1 = blockSwitchingControl->iirStates[1]; + Coeff0 = hiPassCoeff[0]; + Coeff1 = hiPassCoeff[1]; + tidx = 0; + for (w=0; w < BLOCK_SWITCH_WINDOWS; w++) { + + accuUE = 0; + accuFE = 0; + + for(i=0; i> ENERGY_SHIFT; + accuFE += (tempFiltered * tempFiltered) >> ENERGY_SHIFT; + } + + blockSwitchingControl->windowNrg[1][w] = accuUE; + blockSwitchingControl->windowNrgF[1][w] = accuFE; + + } + + blockSwitchingControl->iirStates[0] = states0; + blockSwitchingControl->iirStates[1] = states1; + + return(TRUE); +} +#endif + +/***************************************************************************** +* +* function name: IIRFilter +* description: calculate the iir-filter for an array +* returns: the result after iir-filter +* +**********************************************************************************/ +static Word16 IIRFilter(const Word16 in, const Word32 coeff[], Word32 states[]) +{ + Word32 accu1, accu2, accu3; + Word32 out; + + accu1 = L_mpy_ls(coeff[1], in); + accu3 = accu1 - states[0]; + accu2 = fixmul( coeff[0], states[1] ); + out = accu3 - accu2; + + states[0] = accu1; + states[1] = out; + + return round16(out); +} + + +static Word16 synchronizedBlockTypeTable[4][4] = { + /* LONG_WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW */ + /* LONG_WINDOW */{LONG_WINDOW, START_WINDOW, SHORT_WINDOW, STOP_WINDOW}, + /* START_WINDOW */{START_WINDOW, START_WINDOW, SHORT_WINDOW, SHORT_WINDOW}, + /* SHORT_WINDOW */{SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW}, + /* STOP_WINDOW */{STOP_WINDOW, SHORT_WINDOW, SHORT_WINDOW, STOP_WINDOW} +}; + + +/***************************************************************************** +* +* function name: SyncBlockSwitching +* description: update block type and group value +* returns: TRUE if success +* +**********************************************************************************/ +Word16 SyncBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft, + BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight, + const Word16 nChannels) +{ + Word16 i; + Word16 patchType = LONG_WINDOW; + + + if (nChannels == 1) { /* Mono */ + if (blockSwitchingControlLeft->windowSequence != SHORT_WINDOW) { + blockSwitchingControlLeft->noOfGroups = 1; + blockSwitchingControlLeft->groupLen[0] = 1; + + for (i=1; igroupLen[i] = 0; + } + } + } + else { /* Stereo common Window */ + patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlLeft->windowSequence]; + patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlRight->windowSequence]; + + /* Set synchronized Blocktype */ + blockSwitchingControlLeft->windowSequence = patchType; + blockSwitchingControlRight->windowSequence = patchType; + + /* Synchronize grouping info */ + if(patchType != SHORT_WINDOW) { /* Long Blocks */ + /* Set grouping info */ + blockSwitchingControlLeft->noOfGroups = 1; + blockSwitchingControlRight->noOfGroups = 1; + blockSwitchingControlLeft->groupLen[0] = 1; + blockSwitchingControlRight->groupLen[0] = 1; + + for (i=1; igroupLen[i] = 0; + blockSwitchingControlRight->groupLen[i] = 0; + } + } + else { + + if (blockSwitchingControlLeft->maxWindowNrg > blockSwitchingControlRight->maxWindowNrg) { + /* Left Channel wins */ + blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups; + for (i=0; igroupLen[i] = blockSwitchingControlLeft->groupLen[i]; + } + } + else { + /* Right Channel wins */ + blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups; + for (i=0; igroupLen[i] = blockSwitchingControlRight->groupLen[i]; + } + } + } + } /*endif Mono or Stereo */ + + return(TRUE); +} diff --git a/jni/src/channel_map.c b/jni/src/channel_map.c new file mode 100644 index 000000000..f6552ed42 --- /dev/null +++ b/jni/src/channel_map.c @@ -0,0 +1,123 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: channel_map.c + + Content: channel mapping functions + +*******************************************************************************/ + +#include "channel_map.h" +#include "bitenc.h" +#include "psy_const.h" +#include "qc_data.h" + +static const Word16 maxChannelBits = MAXBITS_COEF; + +static Word16 initElement(ELEMENT_INFO* elInfo, ELEMENT_TYPE elType) +{ + Word16 error=0; + + elInfo->elType=elType; + + switch(elInfo->elType) { + + case ID_SCE: + elInfo->nChannelsInEl=1; + + elInfo->ChannelIndex[0]=0; + + elInfo->instanceTag=0; + break; + + case ID_CPE: + + elInfo->nChannelsInEl=2; + + elInfo->ChannelIndex[0]=0; + elInfo->ChannelIndex[1]=1; + + elInfo->instanceTag=0; + break; + + default: + error=1; + } + + return error; +} + + +Word16 InitElementInfo (Word16 nChannels, ELEMENT_INFO* elInfo) +{ + Word16 error; + error = 0; + + switch(nChannels) { + + case 1: + initElement(elInfo, ID_SCE); + break; + + case 2: + initElement(elInfo, ID_CPE); + break; + + default: + error=4; + } + + return error; +} + + +Word16 InitElementBits(ELEMENT_BITS *elementBits, + ELEMENT_INFO elInfo, + Word32 bitrateTot, + Word16 averageBitsTot, + Word16 staticBitsTot) +{ + Word16 error; + error = 0; + + switch(elInfo.nChannelsInEl) { + case 1: + elementBits->chBitrate = bitrateTot; + elementBits->averageBits = averageBitsTot - staticBitsTot; + elementBits->maxBits = maxChannelBits; + + elementBits->maxBitResBits = maxChannelBits - averageBitsTot; + elementBits->maxBitResBits = elementBits->maxBitResBits - (elementBits->maxBitResBits & 7); + elementBits->bitResLevel = elementBits->maxBitResBits; + elementBits->relativeBits = 0x4000; /* 1.0f/2 */ + break; + + case 2: + elementBits->chBitrate = bitrateTot >> 1; + elementBits->averageBits = averageBitsTot - staticBitsTot; + elementBits->maxBits = maxChannelBits << 1; + + elementBits->maxBitResBits = (maxChannelBits << 1) - averageBitsTot; + elementBits->maxBitResBits = elementBits->maxBitResBits - (elementBits->maxBitResBits & 7); + elementBits->bitResLevel = elementBits->maxBitResBits; + elementBits->relativeBits = 0x4000; /* 1.0f/2 */ + break; + + default: + error = 1; + } + return error; +} diff --git a/jni/src/cmnMemory.c b/jni/src/cmnMemory.c new file mode 100644 index 000000000..aa52bd98f --- /dev/null +++ b/jni/src/cmnMemory.c @@ -0,0 +1,71 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: cmnMemory.c + + Content: sample code for memory operator implementation + +*******************************************************************************/ +#include "cmnMemory.h" + +#include +#include + +//VO_MEM_OPERATOR g_memOP; + +VO_U32 cmnMemAlloc (VO_S32 uID, VO_MEM_INFO * pMemInfo) +{ + if (!pMemInfo) + return VO_ERR_INVALID_ARG; + + pMemInfo->VBuffer = malloc (pMemInfo->Size); + return 0; +} + +VO_U32 cmnMemFree (VO_S32 uID, VO_PTR pMem) +{ + free (pMem); + return 0; +} + +VO_U32 cmnMemSet (VO_S32 uID, VO_PTR pBuff, VO_U8 uValue, VO_U32 uSize) +{ + memset (pBuff, uValue, uSize); + return 0; +} + +VO_U32 cmnMemCopy (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize) +{ + memcpy (pDest, pSource, uSize); + return 0; +} + +VO_U32 cmnMemCheck (VO_S32 uID, VO_PTR pBuffer, VO_U32 uSize) +{ + return 0; +} + +VO_S32 cmnMemCompare (VO_S32 uID, VO_PTR pBuffer1, VO_PTR pBuffer2, VO_U32 uSize) +{ + return memcmp(pBuffer1, pBuffer2, uSize); +} + +VO_U32 cmnMemMove (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize) +{ + memmove (pDest, pSource, uSize); + return 0; +} + diff --git a/jni/src/dyn_bits.c b/jni/src/dyn_bits.c new file mode 100644 index 000000000..77691884d --- /dev/null +++ b/jni/src/dyn_bits.c @@ -0,0 +1,545 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: dyn_bits.c + + Content: Noiseless coder module functions + +*******************************************************************************/ + +#include "aac_rom.h" +#include "dyn_bits.h" +#include "bit_cnt.h" +#include "psy_const.h" + + +/***************************************************************************** +* +* function name: buildBitLookUp +* description: count bits using all possible tables +* +*****************************************************************************/ +static void +buildBitLookUp(const Word16 *quantSpectrum, + const Word16 maxSfb, + const Word16 *sfbOffset, + const UWord16 *sfbMax, + Word16 bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1], + SECTION_INFO * sectionInfo) +{ + Word32 i; + + for (i=0; i maxMergeGain) { + maxMergeGain = mergeGainLookUp[i]; + *maxNdx = i; + } + } + return extract_l(maxMergeGain); +} + + + +static Word16 +CalcMergeGain(const SECTION_INFO *sectionInfo, + Word16 bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1], + const Word16 *sideInfoTab, + const Word16 ndx1, + const Word16 ndx2) +{ + Word32 SplitBits; + Word32 MergeBits; + Word32 MergeGain; + + /* + Bit amount for splitted sections + */ + SplitBits = sectionInfo[ndx1].sectionBits + sectionInfo[ndx2].sectionBits; + + MergeBits = sideInfoTab[sectionInfo[ndx1].sfbCnt + sectionInfo[ndx2].sfbCnt] + + findMinMergeBits(bitLookUp[ndx1], bitLookUp[ndx2]); + MergeGain = (SplitBits - MergeBits); + + return extract_l(MergeGain); +} + +/* + sectioning Stage 0:find minimum codbooks +*/ + +static void +gmStage0(SECTION_INFO * sectionInfo, + Word16 bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1], + const Word16 maxSfb) +{ + Word32 i; + + for (i=0; icodeBook != sectionInfo_e->codeBook) + break; + sectionInfo_s->sfbCnt += 1; + sectionInfo_s->sectionBits += sectionInfo_e->sectionBits; + + mergeBitLookUp(bitLookUp[mergeStart], bitLookUp[mergeEnd]); + } + + sectionInfo_s->sectionBits += sideInfoTab[sectionInfo_s->sfbCnt]; + sectionInfo[mergeEnd - 1].sfbStart = sectionInfo_s->sfbStart; /* speed up prev search */ + + mergeStart = mergeEnd; + + + } while (mergeStart - maxSfb < 0); +} + +/* + sectioning Stage 2:greedy merge algorithm, merge connected sections with + maximum bit gain until no more gain is possible +*/ +static void +gmStage2(SECTION_INFO *sectionInfo, + Word16 mergeGainLookUp[MAX_SFB_LONG], + Word16 bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1], + const Word16 maxSfb, + const Word16 *sideInfoTab) +{ + Word16 i; + + for (i=0; i+sectionInfo[i].sfbCntnoOfSections = 0; + sectionData->huffmanBits = 0; + sectionData->sideInfoBits = 0; + + + if (sectionData->maxSfbPerGroup == 0) + return; + + /* + loop trough groups + */ + for (grpNdx=0; grpNdxsfbCnt; grpNdx+=sectionData->sfbPerGroup) { + + sectionInfo = sectionData->sectionInfo + sectionData->noOfSections; + + buildBitLookUp(quantSpectrum, + sectionData->maxSfbPerGroup, + sfbOffset + grpNdx, + maxValueInSfb + grpNdx, + bitLookUp, + sectionInfo); + + /* + 0.Stage + */ + gmStage0(sectionInfo, bitLookUp, sectionData->maxSfbPerGroup); + + /* + 1.Stage + */ + gmStage1(sectionInfo, bitLookUp, sectionData->maxSfbPerGroup, sideInfoTab); + + + /* + 2.Stage + */ + gmStage2(sectionInfo, + mergeGainLookUp, + bitLookUp, + sectionData->maxSfbPerGroup, + sideInfoTab); + + + /* + compress output, calculate total huff and side bits + */ + for (i=0; imaxSfbPerGroup; i+=sectionInfo[i].sfbCnt) { + findBestBook(bitLookUp[i], &(sectionInfo[i].codeBook)); + sectionInfo[i].sfbStart = sectionInfo[i].sfbStart + grpNdx; + + sectionData->huffmanBits = (sectionData->huffmanBits + + (sectionInfo[i].sectionBits - sideInfoTab[sectionInfo[i].sfbCnt])); + sectionData->sideInfoBits = (sectionData->sideInfoBits + sideInfoTab[sectionInfo[i].sfbCnt]); + sectionData->sectionInfo[sectionData->noOfSections] = sectionInfo[i]; + sectionData->noOfSections = sectionData->noOfSections + 1; + } + } +} + + +/******************************************************************************* +* +* functionname: scfCount +* returns : --- +* description : count bits used by scalefactors. +* +********************************************************************************/ +static void scfCount(const Word16 *scalefacGain, + const UWord16 *maxValueInSfb, + SECTION_DATA * sectionData) + +{ + SECTION_INFO *psectionInfo; + SECTION_INFO *psectionInfom; + + /* counter */ + Word32 i = 0; /* section counter */ + Word32 j = 0; /* sfb counter */ + Word32 k = 0; /* current section auxiliary counter */ + Word32 m = 0; /* other section auxiliary counter */ + Word32 n = 0; /* other sfb auxiliary counter */ + + /* further variables */ + Word32 lastValScf = 0; + Word32 deltaScf = 0; + Flag found = 0; + Word32 scfSkipCounter = 0; + + + sectionData->scalefacBits = 0; + + + if (scalefacGain == NULL) { + return; + } + + lastValScf = 0; + sectionData->firstScf = 0; + + psectionInfo = sectionData->sectionInfo; + for (i=0; inoOfSections; i++) { + + if (psectionInfo->codeBook != CODE_BOOK_ZERO_NO) { + sectionData->firstScf = psectionInfo->sfbStart; + lastValScf = scalefacGain[sectionData->firstScf]; + break; + } + psectionInfo += 1; + } + + psectionInfo = sectionData->sectionInfo; + for (i=0; inoOfSections; i++, psectionInfo += 1) { + + if (psectionInfo->codeBook != CODE_BOOK_ZERO_NO + && psectionInfo->codeBook != CODE_BOOK_PNS_NO) { + for (j = psectionInfo->sfbStart; + j < (psectionInfo->sfbStart + psectionInfo->sfbCnt); j++) { + /* check if we can repeat the last value to save bits */ + + if (maxValueInSfb[j] == 0) { + found = 0; + + if (scfSkipCounter == 0) { + /* end of section */ + + if (j - ((psectionInfo->sfbStart + psectionInfo->sfbCnt) - 1) == 0) { + found = 0; + } + else { + for (k = j + 1; k < psectionInfo->sfbStart + psectionInfo->sfbCnt; k++) { + + if (maxValueInSfb[k] != 0) { + int tmp = L_abs(scalefacGain[k] - lastValScf); + found = 1; + + if ( tmp < CODE_BOOK_SCF_LAV) { + /* save bits */ + deltaScf = 0; + } + else { + /* do not save bits */ + deltaScf = lastValScf - scalefacGain[j]; + lastValScf = scalefacGain[j]; + scfSkipCounter = 0; + } + break; + } + /* count scalefactor skip */ + scfSkipCounter = scfSkipCounter + 1; + } + } + + psectionInfom = psectionInfo + 1; + /* search for the next maxValueInSfb[] != 0 in all other sections */ + for (m = i + 1; (m < sectionData->noOfSections) && (found == 0); m++) { + + if ((psectionInfom->codeBook != CODE_BOOK_ZERO_NO) && + (psectionInfom->codeBook != CODE_BOOK_PNS_NO)) { + for (n = psectionInfom->sfbStart; + n < (psectionInfom->sfbStart + psectionInfom->sfbCnt); n++) { + + if (maxValueInSfb[n] != 0) { + found = 1; + + if ( (abs_s(scalefacGain[n] - lastValScf) < CODE_BOOK_SCF_LAV)) { + deltaScf = 0; + } + else { + deltaScf = (lastValScf - scalefacGain[j]); + lastValScf = scalefacGain[j]; + scfSkipCounter = 0; + } + break; + } + /* count scalefactor skip */ + scfSkipCounter = scfSkipCounter + 1; + } + } + + psectionInfom += 1; + } + + if (found == 0) { + deltaScf = 0; + scfSkipCounter = 0; + } + } + else { + deltaScf = 0; + scfSkipCounter = scfSkipCounter - 1; + } + } + else { + deltaScf = lastValScf - scalefacGain[j]; + lastValScf = scalefacGain[j]; + } + sectionData->scalefacBits += bitCountScalefactorDelta(deltaScf); + } + } + } +} + + +typedef Word16 (*lookUpTable)[CODE_BOOK_ESC_NDX + 1]; + + +Word16 +dynBitCount(const Word16 *quantSpectrum, + const UWord16 *maxValueInSfb, + const Word16 *scalefac, + const Word16 blockType, + const Word16 sfbCnt, + const Word16 maxSfbPerGroup, + const Word16 sfbPerGroup, + const Word16 *sfbOffset, + SECTION_DATA *sectionData) +{ + sectionData->blockType = blockType; + sectionData->sfbCnt = sfbCnt; + sectionData->sfbPerGroup = sfbPerGroup; + if(sfbPerGroup) + sectionData->noOfGroups = sfbCnt/sfbPerGroup; + else + sectionData->noOfGroups = 0x7fff; + sectionData->maxSfbPerGroup = maxSfbPerGroup; + + noiselessCounter(sectionData, + sectionData->mergeGainLookUp, + (lookUpTable)sectionData->bitLookUp, + quantSpectrum, + maxValueInSfb, + sfbOffset, + blockType); + + scfCount(scalefac, + maxValueInSfb, + sectionData); + + + return (sectionData->huffmanBits + sectionData->sideInfoBits + + sectionData->scalefacBits); +} + diff --git a/jni/src/grp_data.c b/jni/src/grp_data.c new file mode 100644 index 000000000..7861e1cdc --- /dev/null +++ b/jni/src/grp_data.c @@ -0,0 +1,188 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: grp_data.c + + Content: Short block grouping function + +*******************************************************************************/ + +#include "basic_op.h" +#include "psy_const.h" +#include "interface.h" +#include "grp_data.h" + +/***************************************************************************** +* +* function name: groupShortData +* description: group short data for next quantization and coding +* +**********************************************************************************/ +void +groupShortData(Word32 *mdctSpectrum, + Word32 *tmpSpectrum, + SFB_THRESHOLD *sfbThreshold, + SFB_ENERGY *sfbEnergy, + SFB_ENERGY *sfbEnergyMS, + SFB_ENERGY *sfbSpreadedEnergy, + const Word16 sfbCnt, + const Word16 *sfbOffset, + const Word16 *sfbMinSnr, + Word16 *groupedSfbOffset, + Word16 *maxSfbPerGroup, + Word16 *groupedSfbMinSnr, + const Word16 noOfGroups, + const Word16 *groupLen) +{ + Word32 i, j; + Word32 line; + Word32 sfb; + Word32 grp; + Word32 wnd; + Word32 offset; + Word32 highestSfb; + + /* for short: regroup and */ + /* cumulate energies und thresholds group-wise . */ + + /* calculate sfbCnt */ + highestSfb = 0; + for (wnd=0; wnd=highestSfb; sfb--) { + for (line=(sfbOffset[sfb + 1] - 1); line>=sfbOffset[sfb]; line--) { + + if (mdctSpectrum[wnd*FRAME_LEN_SHORT+line] != 0) break; + } + + if (line >= sfbOffset[sfb]) break; + } + highestSfb = max(highestSfb, sfb); + } + + if (highestSfb < 0) { + highestSfb = 0; + } + *maxSfbPerGroup = highestSfb + 1; + + /* calculate sfbOffset */ + i = 0; + offset = 0; + for (grp = 0; grp < noOfGroups; grp++) { + for (sfb = 0; sfb < sfbCnt; sfb++) { + groupedSfbOffset[i] = offset + sfbOffset[sfb] * groupLen[grp]; + i += 1; + } + offset += groupLen[grp] * FRAME_LEN_SHORT; + } + groupedSfbOffset[i] = FRAME_LEN_LONG; + i += 1; + + /* calculate minSnr */ + i = 0; + offset = 0; + for (grp = 0; grp < noOfGroups; grp++) { + for (sfb = 0; sfb < sfbCnt; sfb++) { + groupedSfbMinSnr[i] = sfbMinSnr[sfb]; + i += 1; + } + offset += groupLen[grp] * FRAME_LEN_SHORT; + } + + + /* sum up sfbThresholds */ + wnd = 0; + i = 0; + for (grp = 0; grp < noOfGroups; grp++) { + for (sfb = 0; sfb < sfbCnt; sfb++) { + Word32 thresh = sfbThreshold->sfbShort[wnd][sfb]; + for (j=1; jsfbShort[wnd+j][sfb]); + } + sfbThreshold->sfbLong[i] = thresh; + i += 1; + } + wnd += groupLen[grp]; + } + + /* sum up sfbEnergies left/right */ + wnd = 0; + i = 0; + for (grp = 0; grp < noOfGroups; grp++) { + for (sfb = 0; sfb < sfbCnt; sfb++) { + Word32 energy = sfbEnergy->sfbShort[wnd][sfb]; + for (j=1; jsfbShort[wnd+j][sfb]); + } + sfbEnergy->sfbLong[i] = energy; + i += 1; + } + wnd += groupLen[grp]; + } + + /* sum up sfbEnergies mid/side */ + wnd = 0; + i = 0; + for (grp = 0; grp < noOfGroups; grp++) { + for (sfb = 0; sfb < sfbCnt; sfb++) { + Word32 energy = sfbEnergyMS->sfbShort[wnd][sfb]; + for (j=1; jsfbShort[wnd+j][sfb]); + } + sfbEnergyMS->sfbLong[i] = energy; + i += 1; + } + wnd += groupLen[grp]; + } + + /* sum up sfbSpreadedEnergies */ + wnd = 0; + i = 0; + for (grp = 0; grp < noOfGroups; grp++) { + for (sfb = 0; sfb < sfbCnt; sfb++) { + Word32 energy = sfbSpreadedEnergy->sfbShort[wnd][sfb]; + for (j=1; jsfbShort[wnd+j][sfb]); + } + sfbSpreadedEnergy->sfbLong[i] = energy; + i += 1; + } + wnd += groupLen[grp]; + } + + /* re-group spectrum */ + wnd = 0; + i = 0; + for (grp = 0; grp < noOfGroups; grp++) { + for (sfb = 0; sfb < sfbCnt; sfb++) { + for (j = 0; j < groupLen[grp]; j++) { + Word16 lineOffset = FRAME_LEN_SHORT * (wnd + j); + for (line = lineOffset + sfbOffset[sfb]; line < lineOffset + sfbOffset[sfb+1]; line++) { + tmpSpectrum[i] = mdctSpectrum[line]; + i = i + 1; + } + } + } + wnd += groupLen[grp]; + } + + for(i=0;imaxSfbPerGroup = maxSfbPerGroup; + psyOutCh->sfbCnt = groupedSfbCnt; + if(noOfGroups) + psyOutCh->sfbPerGroup = groupedSfbCnt/ noOfGroups; + else + psyOutCh->sfbPerGroup = 0x7fff; + psyOutCh->windowSequence = windowSequence; + psyOutCh->windowShape = windowShape; + psyOutCh->mdctScale = mdctScale; + psyOutCh->mdctSpectrum = groupedMdctSpectrum; + psyOutCh->sfbEnergy = groupedSfbEnergy->sfbLong; + psyOutCh->sfbThreshold = groupedSfbThreshold->sfbLong; + psyOutCh->sfbSpreadedEnergy = groupedSfbSpreadedEnergy->sfbLong; + + tmpV = psyOutCh->sfbOffsets; + for(j=0; jsfbMinSnr; + for(j=0;jgroupingMask = mask; + + if (windowSequence != SHORT_WINDOW) { + psyOutCh->sfbEnSumLR = sfbEnergySumLR.sfbLong; + psyOutCh->sfbEnSumMS = sfbEnergySumMS.sfbLong; + } + else { + Word32 i; + Word32 accuSumMS=0; + Word32 accuSumLR=0; + const Word32 *pSumMS = sfbEnergySumMS.sfbShort; + const Word32 *pSumLR = sfbEnergySumLR.sfbShort; + + for (i=TRANS_FAC; i; i--) { + accuSumLR = L_add(accuSumLR, *pSumLR); pSumLR++; + accuSumMS = L_add(accuSumMS, *pSumMS); pSumMS++; + } + psyOutCh->sfbEnSumMS = accuSumMS; + psyOutCh->sfbEnSumLR = accuSumLR; + } +} diff --git a/jni/src/line_pe.c b/jni/src/line_pe.c new file mode 100644 index 000000000..480dc288b --- /dev/null +++ b/jni/src/line_pe.c @@ -0,0 +1,145 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: line_pe.c + + Content: Perceptual entropie module functions + +*******************************************************************************/ + +#include "basic_op.h" +#include "oper_32b.h" +#include "typedef.h" +#include "line_pe.h" + + +static const Word16 C1_I = 12; /* log(8.0)/log(2) *4 */ +static const Word32 C2_I = 10830; /* log(2.5)/log(2) * 1024 * 4 * 2 */ +static const Word16 C3_I = 573; /* (1-C2/C1) *1024 */ + + +/***************************************************************************** +* +* function name: prepareSfbPe +* description: constants that do not change during successive pe calculations +* +**********************************************************************************/ +void prepareSfbPe(PE_DATA *peData, + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], + Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB], + const Word16 nChannels, + const Word16 peOffset) +{ + Word32 sfbGrp, sfb; + Word32 ch; + + for(ch=0; chpeChannelData[ch]; + for(sfbGrp=0;sfbGrpsfbCnt; sfbGrp+=psyOutChan->sfbPerGroup){ + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + peChanData->sfbNLines4[sfbGrp+sfb] = sfbNRelevantLines[ch][sfbGrp+sfb]; + sfbNRelevantLines[ch][sfbGrp+sfb] = sfbNRelevantLines[ch][sfbGrp+sfb] >> 2; + peChanData->sfbLdEnergy[sfbGrp+sfb] = logSfbEnergy[ch][sfbGrp+sfb]; + } + } + } + peData->offset = peOffset; +} + + +/***************************************************************************** +* +* function name: calcSfbPe +* description: constPart is sfbPe without the threshold part n*ld(thr) or n*C3*ld(thr) +* +**********************************************************************************/ +void calcSfbPe(PE_DATA *peData, + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + const Word16 nChannels) +{ + Word32 ch; + Word32 sfbGrp, sfb; + Word32 nLines4; + Word32 ldThr, ldRatio; + Word32 pe, constPart, nActiveLines; + + peData->pe = peData->offset; + peData->constPart = 0; + peData->nActiveLines = 0; + for(ch=0; chpeChannelData[ch]; + const Word32 *sfbEnergy = psyOutChan->sfbEnergy; + const Word32 *sfbThreshold = psyOutChan->sfbThreshold; + + pe = 0; + constPart = 0; + nActiveLines = 0; + + for(sfbGrp=0; sfbGrpsfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) { + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + Word32 nrg = sfbEnergy[sfbGrp+sfb]; + Word32 thres = sfbThreshold[sfbGrp+sfb]; + Word32 sfbLDEn = peChanData->sfbLdEnergy[sfbGrp+sfb]; + + if (nrg > thres) { + ldThr = iLog4(thres); + + ldRatio = sfbLDEn - ldThr; + + nLines4 = peChanData->sfbNLines4[sfbGrp+sfb]; + + /* sfbPe = nl*log2(en/thr)*/ + if (ldRatio >= C1_I) { + peChanData->sfbPe[sfbGrp+sfb] = (nLines4*ldRatio + 8) >> 4; + peChanData->sfbConstPart[sfbGrp+sfb] = ((nLines4*sfbLDEn)) >> 4; + } + else { + /* sfbPe = nl*(c2 + c3*log2(en/thr))*/ + peChanData->sfbPe[sfbGrp+sfb] = extract_l((L_mpy_wx( + (C2_I + C3_I * ldRatio * 2) << 4, nLines4) + 4) >> 3); + peChanData->sfbConstPart[sfbGrp+sfb] = extract_l(( L_mpy_wx( + (C2_I + C3_I * sfbLDEn * 2) << 4, nLines4) + 4) >> 3); + nLines4 = (nLines4 * C3_I + (1024<<1)) >> 10; + } + peChanData->sfbNActiveLines[sfbGrp+sfb] = nLines4 >> 2; + } + else { + peChanData->sfbPe[sfbGrp+sfb] = 0; + peChanData->sfbConstPart[sfbGrp+sfb] = 0; + peChanData->sfbNActiveLines[sfbGrp+sfb] = 0; + } + pe = pe + peChanData->sfbPe[sfbGrp+sfb]; + constPart = constPart + peChanData->sfbConstPart[sfbGrp+sfb]; + nActiveLines = nActiveLines + peChanData->sfbNActiveLines[sfbGrp+sfb]; + } + } + + peChanData->pe = saturate(pe); + peChanData->constPart = saturate(constPart); + peChanData->nActiveLines = saturate(nActiveLines); + + + pe += peData->pe; + peData->pe = saturate(pe); + constPart += peData->constPart; + peData->constPart = saturate(constPart); + nActiveLines += peData->nActiveLines; + peData->nActiveLines = saturate(nActiveLines); + } +} diff --git a/jni/src/memalign.c b/jni/src/memalign.c new file mode 100644 index 000000000..bb266dcde --- /dev/null +++ b/jni/src/memalign.c @@ -0,0 +1,112 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +/******************************************************************************* + File: mem_align.c + + Content: Memory alloc alignments functions + +*******************************************************************************/ + + +#include "memalign.h" +#ifdef _MSC_VER +#include +#else +#include +#endif + +/***************************************************************************** +* +* function name: mem_malloc +* description: malloc the alignments memory +* returns: the point of the memory +* +**********************************************************************************/ +void * +mem_malloc(VO_MEM_OPERATOR *pMemop, unsigned int size, unsigned char alignment, unsigned int CodecID) +{ + int ret; + unsigned char *mem_ptr; + VO_MEM_INFO MemInfo; + + if (!alignment) { + + MemInfo.Flag = 0; + MemInfo.Size = size + 1; + ret = pMemop->Alloc(CodecID, &MemInfo); + if(ret != 0) + return 0; + mem_ptr = (unsigned char *)MemInfo.VBuffer; + + pMemop->Set(CodecID, mem_ptr, 0, size + 1); + + *mem_ptr = (unsigned char)1; + + return ((void *)(mem_ptr+1)); + } else { + unsigned char *tmp; + + MemInfo.Flag = 0; + MemInfo.Size = size + alignment; + ret = pMemop->Alloc(CodecID, &MemInfo); + if(ret != 0) + return 0; + + tmp = (unsigned char *)MemInfo.VBuffer; + + pMemop->Set(CodecID, tmp, 0, size + alignment); + + mem_ptr = + (unsigned char *) ((intptr_t) (tmp + alignment - 1) & + (~((intptr_t) (alignment - 1)))); + + if (mem_ptr == tmp) + mem_ptr += alignment; + + *(mem_ptr - 1) = (unsigned char) (mem_ptr - tmp); + + return ((void *)mem_ptr); + } + + return(0); +} + + +/***************************************************************************** +* +* function name: mem_free +* description: free the memory +* +*******************************************************************************/ +void +mem_free(VO_MEM_OPERATOR *pMemop, void *mem_ptr, unsigned int CodecID) +{ + + unsigned char *ptr; + + if (mem_ptr == 0) + return; + + ptr = mem_ptr; + + ptr -= *(ptr - 1); + + pMemop->Free(CodecID, ptr); +} + + + diff --git a/jni/src/ms_stereo.c b/jni/src/ms_stereo.c new file mode 100644 index 000000000..2e34f14b9 --- /dev/null +++ b/jni/src/ms_stereo.c @@ -0,0 +1,139 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: ms_stereo.c + + Content: MS stereo processing function + +*******************************************************************************/ + +#include "basic_op.h" +#include "oper_32b.h" +#include "psy_const.h" +#include "ms_stereo.h" + + +/******************************************************************************** +* +* function name: MsStereoProcessing +* description: detect use ms stereo or not +* if ((min(thrLn, thrRn)*min(thrLn, thrRn))/(enMn*enSn)) +* >= ((thrLn *thrRn)/(enLn*enRn)) then ms stereo +* +**********************************************************************************/ +void MsStereoProcessing(Word32 *sfbEnergyLeft, + Word32 *sfbEnergyRight, + const Word32 *sfbEnergyMid, + const Word32 *sfbEnergySide, + Word32 *mdctSpectrumLeft, + Word32 *mdctSpectrumRight, + Word32 *sfbThresholdLeft, + Word32 *sfbThresholdRight, + Word32 *sfbSpreadedEnLeft, + Word32 *sfbSpreadedEnRight, + Word16 *msDigest, + Word16 *msMask, + const Word16 sfbCnt, + const Word16 sfbPerGroup, + const Word16 maxSfbPerGroup, + const Word16 *sfbOffset) { + Word32 temp; + Word32 sfb,sfboffs, j; + Word32 msMaskTrueSomewhere = 0; + Word32 msMaskFalseSomewhere = 0; + + for (sfb=0; sfb> 8) + 1); + + temp = pnms - pnlr; + if( temp > 0 ){ + + msMask[idx] = 1; + msMaskTrueSomewhere = 1; + + for (j=sfbOffset[idx]; j> 1); + right = (mdctSpectrumRight[j] >> 1); + mdctSpectrumLeft[j] = left + right; + mdctSpectrumRight[j] = left - right; + } + + sfbThresholdLeft[idx] = minThreshold; + sfbThresholdRight[idx] = minThreshold; + sfbEnergyLeft[idx] = sfbEnergyMid[idx]; + sfbEnergyRight[idx] = sfbEnergySide[idx]; + + sfbSpreadedEnRight[idx] = min(sfbSpreadedEnLeft[idx],sfbSpreadedEnRight[idx]) >> 1; + sfbSpreadedEnLeft[idx] = sfbSpreadedEnRight[idx]; + + } + else { + msMask[idx] = 0; + msMaskFalseSomewhere = 1; + } + } + if ( msMaskTrueSomewhere ) { + if(msMaskFalseSomewhere ) { + *msDigest = SI_MS_MASK_SOME; + } else { + *msDigest = SI_MS_MASK_ALL; + } + } else { + *msDigest = SI_MS_MASK_NONE; + } + } + +} diff --git a/jni/src/pre_echo_control.c b/jni/src/pre_echo_control.c new file mode 100644 index 000000000..1406e11b0 --- /dev/null +++ b/jni/src/pre_echo_control.c @@ -0,0 +1,113 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: pre_echo_control.c + + Content: Pre echo control functions + +*******************************************************************************/ + +#include "basic_op.h" +#include "oper_32b.h" + +#include "oper_32b.h" +#include "pre_echo_control.h" + + +/***************************************************************************** +* +* function name:InitPreEchoControl +* description: init pre echo control parameter +* +*****************************************************************************/ +void InitPreEchoControl(Word32 *pbThresholdNm1, + Word16 numPb, + Word32 *pbThresholdQuiet) +{ + Word16 pb; + + for(pb=0; pb 0 ) { + for(i = 0; i < numPb; i++) { + tmpThreshold1 = pbThresholdNm1[i] >> (scaling-1); + tmpThreshold2 = L_mpy_ls(pbThreshold[i], minRemainingThresholdFactor); + + /* copy thresholds to internal memory */ + pbThresholdNm1[i] = pbThreshold[i]; + + + if(pbThreshold[i] > tmpThreshold1) { + pbThreshold[i] = tmpThreshold1; + } + + if(tmpThreshold2 > pbThreshold[i]) { + pbThreshold[i] = tmpThreshold2; + } + + } + } + else { + scaling = -scaling; + for(i = 0; i < numPb; i++) { + + tmpThreshold1 = pbThresholdNm1[i] << 1; + tmpThreshold2 = L_mpy_ls(pbThreshold[i], minRemainingThresholdFactor); + + /* copy thresholds to internal memory */ + pbThresholdNm1[i] = pbThreshold[i]; + + + if(((pbThreshold[i] >> scaling) > tmpThreshold1)) { + pbThreshold[i] = tmpThreshold1 << scaling; + } + + if(tmpThreshold2 > pbThreshold[i]) { + pbThreshold[i] = tmpThreshold2; + } + + } + } +} + diff --git a/jni/src/psy_configuration.c b/jni/src/psy_configuration.c new file mode 100644 index 000000000..dd40f9b24 --- /dev/null +++ b/jni/src/psy_configuration.c @@ -0,0 +1,505 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: psy_configuration.c + + Content: Psychoaccoustic configuration functions + +*******************************************************************************/ + +#include "basic_op.h" +#include "oper_32b.h" +#include "psy_configuration.h" +#include "adj_thr.h" +#include "aac_rom.h" + + + +#define BARC_SCALE 100 /* integer barc values are scaled with 100 */ +#define LOG2_1000 301 /* log2*1000 */ +#define PI2_1000 1571 /* pi/2*1000*/ +#define ATAN_COEF1 3560 /* 1000/0.280872f*/ +#define ATAN_COEF2 281 /* 1000*0.280872f*/ + + +typedef struct{ + Word32 sampleRate; + const UWord8 *paramLong; + const UWord8 *paramShort; +}SFB_INFO_TAB; + +static const Word16 ABS_LEV = 20; +static const Word16 BARC_THR_QUIET[] = {15, 10, 7, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 5, 10, 20, 30}; + + + +static const Word16 max_bark = 24; /* maximum bark-value */ +static const Word16 maskLow = 30; /* in 1dB/bark */ +static const Word16 maskHigh = 15; /* in 1*dB/bark */ +static const Word16 c_ratio = 0x0029; /* pow(10.0f, -(29.0f/10.0f)) */ + +static const Word16 maskLowSprEnLong = 30; /* in 1dB/bark */ +static const Word16 maskHighSprEnLong = 20; /* in 1dB/bark */ +static const Word16 maskHighSprEnLongLowBr = 15; /* in 1dB/bark */ +static const Word16 maskLowSprEnShort = 20; /* in 1dB/bark */ +static const Word16 maskHighSprEnShort = 15; /* in 1dB/bark */ +static const Word16 c_minRemainingThresholdFactor = 0x0148; /* 0.01 *(1 << 15)*/ +static const Word32 c_maxsnr = 0x66666666; /* upper limit is -1 dB */ +static const Word32 c_minsnr = 0x00624dd3; /* lower limit is -25 dB */ + +static const Word32 c_maxClipEnergyLong = 0x77359400; /* 2.0e9f*/ +static const Word32 c_maxClipEnergyShort = 0x01dcd650; /* 2.0e9f/(AACENC_TRANS_FAC*AACENC_TRANS_FAC)*/ + + +Word32 GetSRIndex(Word32 sampleRate) +{ + if (92017 <= sampleRate) return 0; + if (75132 <= sampleRate) return 1; + if (55426 <= sampleRate) return 2; + if (46009 <= sampleRate) return 3; + if (37566 <= sampleRate) return 4; + if (27713 <= sampleRate) return 5; + if (23004 <= sampleRate) return 6; + if (18783 <= sampleRate) return 7; + if (13856 <= sampleRate) return 8; + if (11502 <= sampleRate) return 9; + if (9391 <= sampleRate) return 10; + + return 11; +} + + +/********************************************************************************* +* +* function name: atan_1000 +* description: calculates 1000*atan(x/1000) +* based on atan approx for x > 0 +* atan(x) = x/((float)1.0f+(float)0.280872f*x*x) if x < 1 +* = pi/2 - x/((float)0.280872f +x*x) if x >= 1 +* return: 1000*atan(x/1000) +* +**********************************************************************************/ +static Word16 atan_1000(Word32 val) +{ + Word32 y; + + + if(L_sub(val, 1000) < 0) { + y = extract_l(((1000 * val) / (1000 + ((val * val) / ATAN_COEF1)))); + } + else { + y = PI2_1000 - ((1000 * val) / (ATAN_COEF2 + ((val * val) / 1000))); + } + + return extract_l(y); +} + + +/***************************************************************************** +* +* function name: BarcLineValue +* description: Calculates barc value for one frequency line +* returns: barc value of line * BARC_SCALE +* input: number of lines in transform, index of line to check, Fs +* output: +* +*****************************************************************************/ +static Word16 BarcLineValue(Word16 noOfLines, Word16 fftLine, Word32 samplingFreq) +{ + Word32 center_freq, temp, bvalFFTLine; + + /* center frequency of fft line */ + center_freq = (fftLine * samplingFreq) / (noOfLines << 1); + temp = atan_1000((center_freq << 2) / (3*10)); + bvalFFTLine = + (26600 * atan_1000((center_freq*76) / 100) + 7*temp*temp) / (2*1000*1000 / BARC_SCALE); + + return saturate(bvalFFTLine); +} + +/***************************************************************************** +* +* function name: initThrQuiet +* description: init thredhold in quiet +* +*****************************************************************************/ +static void initThrQuiet(Word16 numPb, + const Word16 *pbOffset, + Word16 *pbBarcVal, + Word32 *pbThresholdQuiet) { + Word16 i; + Word16 barcThrQuiet; + + for(i=0; i0) + bv1 = (pbBarcVal[i] + pbBarcVal[i-1]) >> 1; + else + bv1 = pbBarcVal[i] >> 1; + + + if (i < (numPb - 1)) + bv2 = (pbBarcVal[i] + pbBarcVal[i+1]) >> 1; + else { + bv2 = pbBarcVal[i]; + } + + bv1 = min((bv1 / BARC_SCALE), max_bark); + bv2 = min((bv2 / BARC_SCALE), max_bark); + + barcThrQuiet = min(BARC_THR_QUIET[bv1], BARC_THR_QUIET[bv2]); + + + /* + we calculate + pow(10.0f,(float)(barcThrQuiet - ABS_LEV)*0.1)*(float)ABS_LOW*(pbOffset[i+1] - pbOffset[i]); + */ + + pbThresholdQuiet[i] = pow2_xy((((barcThrQuiet - ABS_LEV) * 100) + + LOG2_1000*(14+2*LOG_NORM_PCM)), LOG2_1000) * (pbOffset[i+1] - pbOffset[i]); + } +} + + +/***************************************************************************** +* +* function name: initSpreading +* description: init energy spreading parameter +* +*****************************************************************************/ +static void initSpreading(Word16 numPb, + Word16 *pbBarcValue, + Word16 *pbMaskLoFactor, + Word16 *pbMaskHiFactor, + Word16 *pbMaskLoFactorSprEn, + Word16 *pbMaskHiFactorSprEn, + const Word32 bitrate, + const Word16 blockType) +{ + Word16 i; + Word16 maskLowSprEn, maskHighSprEn; + + + if (sub(blockType, SHORT_WINDOW) != 0) { + maskLowSprEn = maskLowSprEnLong; + + if (bitrate > 22000) + maskHighSprEn = maskHighSprEnLong; + else + maskHighSprEn = maskHighSprEnLongLowBr; + } + else { + maskLowSprEn = maskLowSprEnShort; + maskHighSprEn = maskHighSprEnShort; + } + + for(i=0; i 0) { + Word32 dbVal; + Word16 dbark = pbBarcValue[i] - pbBarcValue[i-1]; + + /* + we calulate pow(10.0f, -0.1*dbVal/BARC_SCALE) + */ + dbVal = (maskHigh * dbark); + pbMaskHiFactor[i] = round16(pow2_xy(L_negate(dbVal), (Word32)LOG2_1000)); /* 0.301 log10(2) */ + + dbVal = (maskLow * dbark); + pbMaskLoFactor[i-1] = round16(pow2_xy(L_negate(dbVal),(Word32)LOG2_1000)); + + + dbVal = (maskHighSprEn * dbark); + pbMaskHiFactorSprEn[i] = round16(pow2_xy(L_negate(dbVal),(Word32)LOG2_1000)); + dbVal = (maskLowSprEn * dbark); + pbMaskLoFactorSprEn[i-1] = round16(pow2_xy(L_negate(dbVal),(Word32)LOG2_1000)); + } + else { + pbMaskHiFactor[i] = 0; + pbMaskLoFactor[numPb-1] = 0; + + pbMaskHiFactorSprEn[i] = 0; + pbMaskLoFactorSprEn[numPb-1] = 0; + } + } + +} + + +/***************************************************************************** +* +* function name: initBarcValues +* description: init bark value +* +*****************************************************************************/ +static void initBarcValues(Word16 numPb, + const Word16 *pbOffset, + Word16 numLines, + Word32 samplingFrequency, + Word16 *pbBval) +{ + Word16 i; + Word16 pbBval0, pbBval1; + + pbBval0 = 0; + + for(i=0; i> 1; + pbBval0 = pbBval1; + } +} + + +/***************************************************************************** +* +* function name: initMinSnr +* description: calculate min snr parameter +* minSnr(n) = 1/(2^sfbPemin(n)/w(n) - 1.5) +* +*****************************************************************************/ +static void initMinSnr(const Word32 bitrate, + const Word32 samplerate, + const Word16 numLines, + const Word16 *sfbOffset, + const Word16 *pbBarcVal, + const Word16 sfbActive, + Word16 *sfbMinSnr) +{ + Word16 sfb; + Word16 barcWidth; + Word16 pePerWindow; + Word32 pePart; + Word32 snr; + Word16 pbVal0, pbVal1, shift; + + /* relative number of active barks */ + + + pePerWindow = bits2pe(extract_l((bitrate * numLines) / samplerate)); + + pbVal0 = 0; + + for (sfb=0; sfb 0x00008000) + { + shift = norm_l(snr); + snr = Div_32(0x00008000 << shift, snr << shift); + } + else + { + snr = 0x7fffffff; + } + + /* upper limit is -1 dB */ + snr = min(snr, c_maxsnr); + /* lower limit is -25 dB */ + snr = max(snr, c_minsnr); + sfbMinSnr[sfb] = round16(snr); + } + +} + +/***************************************************************************** +* +* function name: InitPsyConfigurationLong +* description: init long block psychoacoustic configuration +* +*****************************************************************************/ +Word16 InitPsyConfigurationLong(Word32 bitrate, + Word32 samplerate, + Word16 bandwidth, + PSY_CONFIGURATION_LONG *psyConf) +{ + Word32 samplerateindex; + Word16 sfbBarcVal[MAX_SFB_LONG]; + Word16 sfb; + + /* + init sfb table + */ + samplerateindex = GetSRIndex(samplerate); + psyConf->sfbCnt = sfBandTotalLong[samplerateindex]; + psyConf->sfbOffset = sfBandTabLong + sfBandTabLongOffset[samplerateindex]; + psyConf->sampRateIdx = samplerateindex; + + /* + calculate barc values for each pb + */ + initBarcValues(psyConf->sfbCnt, + psyConf->sfbOffset, + psyConf->sfbOffset[psyConf->sfbCnt], + samplerate, + sfbBarcVal); + + /* + init thresholds in quiet + */ + initThrQuiet(psyConf->sfbCnt, + psyConf->sfbOffset, + sfbBarcVal, + psyConf->sfbThresholdQuiet); + + /* + calculate spreading function + */ + initSpreading(psyConf->sfbCnt, + sfbBarcVal, + psyConf->sfbMaskLowFactor, + psyConf->sfbMaskHighFactor, + psyConf->sfbMaskLowFactorSprEn, + psyConf->sfbMaskHighFactorSprEn, + bitrate, + LONG_WINDOW); + + /* + init ratio + */ + psyConf->ratio = c_ratio; + + psyConf->maxAllowedIncreaseFactor = 2; + psyConf->minRemainingThresholdFactor = c_minRemainingThresholdFactor; /* 0.01 *(1 << 15)*/ + + psyConf->clipEnergy = c_maxClipEnergyLong; + psyConf->lowpassLine = extract_l((bandwidth<<1) * FRAME_LEN_LONG / samplerate); + + for (sfb = 0; sfb < psyConf->sfbCnt; sfb++) { + if (sub(psyConf->sfbOffset[sfb], psyConf->lowpassLine) >= 0) + break; + } + psyConf->sfbActive = sfb; + + /* + calculate minSnr + */ + initMinSnr(bitrate, + samplerate, + psyConf->sfbOffset[psyConf->sfbCnt], + psyConf->sfbOffset, + sfbBarcVal, + psyConf->sfbActive, + psyConf->sfbMinSnr); + + + return(0); +} + +/***************************************************************************** +* +* function name: InitPsyConfigurationShort +* description: init short block psychoacoustic configuration +* +*****************************************************************************/ +Word16 InitPsyConfigurationShort(Word32 bitrate, + Word32 samplerate, + Word16 bandwidth, + PSY_CONFIGURATION_SHORT *psyConf) +{ + Word32 samplerateindex; + Word16 sfbBarcVal[MAX_SFB_SHORT]; + Word16 sfb; + /* + init sfb table + */ + samplerateindex = GetSRIndex(samplerate); + psyConf->sfbCnt = sfBandTotalShort[samplerateindex]; + psyConf->sfbOffset = sfBandTabShort + sfBandTabShortOffset[samplerateindex]; + psyConf->sampRateIdx = samplerateindex; + /* + calculate barc values for each pb + */ + initBarcValues(psyConf->sfbCnt, + psyConf->sfbOffset, + psyConf->sfbOffset[psyConf->sfbCnt], + samplerate, + sfbBarcVal); + + /* + init thresholds in quiet + */ + initThrQuiet(psyConf->sfbCnt, + psyConf->sfbOffset, + sfbBarcVal, + psyConf->sfbThresholdQuiet); + + /* + calculate spreading function + */ + initSpreading(psyConf->sfbCnt, + sfbBarcVal, + psyConf->sfbMaskLowFactor, + psyConf->sfbMaskHighFactor, + psyConf->sfbMaskLowFactorSprEn, + psyConf->sfbMaskHighFactorSprEn, + bitrate, + SHORT_WINDOW); + + /* + init ratio + */ + psyConf->ratio = c_ratio; + + psyConf->maxAllowedIncreaseFactor = 2; + psyConf->minRemainingThresholdFactor = c_minRemainingThresholdFactor; + + psyConf->clipEnergy = c_maxClipEnergyShort; + + psyConf->lowpassLine = extract_l(((bandwidth << 1) * FRAME_LEN_SHORT) / samplerate); + + for (sfb = 0; sfb < psyConf->sfbCnt; sfb++) { + + if (psyConf->sfbOffset[sfb] >= psyConf->lowpassLine) + break; + } + psyConf->sfbActive = sfb; + + /* + calculate minSnr + */ + initMinSnr(bitrate, + samplerate, + psyConf->sfbOffset[psyConf->sfbCnt], + psyConf->sfbOffset, + sfbBarcVal, + psyConf->sfbActive, + psyConf->sfbMinSnr); + + return(0); +} + diff --git a/jni/src/psy_main.c b/jni/src/psy_main.c new file mode 100644 index 000000000..4e9218c81 --- /dev/null +++ b/jni/src/psy_main.c @@ -0,0 +1,811 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: psy_main.c + + Content: Psychoacoustic major functions + +*******************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "psy_const.h" +#include "block_switch.h" +#include "transform.h" +#include "spreading.h" +#include "pre_echo_control.h" +#include "band_nrg.h" +#include "psy_configuration.h" +#include "psy_data.h" +#include "ms_stereo.h" +#include "interface.h" +#include "psy_main.h" +#include "grp_data.h" +#include "tns_func.h" +#include "memalign.h" + +/* long start short stop */ +static Word16 blockType2windowShape[] = {KBD_WINDOW,SINE_WINDOW,SINE_WINDOW,KBD_WINDOW}; + +/* + forward definitions +*/ +static Word16 advancePsychLong(PSY_DATA* psyData, + TNS_DATA* tnsData, + PSY_CONFIGURATION_LONG *hPsyConfLong, + PSY_OUT_CHANNEL* psyOutChannel, + Word32 *pScratchTns, + const TNS_DATA *tnsData2, + const Word16 ch); + +static Word16 advancePsychLongMS (PSY_DATA psyData[MAX_CHANNELS], + const PSY_CONFIGURATION_LONG *hPsyConfLong); + +static Word16 advancePsychShort(PSY_DATA* psyData, + TNS_DATA* tnsData, + const PSY_CONFIGURATION_SHORT *hPsyConfShort, + PSY_OUT_CHANNEL* psyOutChannel, + Word32 *pScratchTns, + const TNS_DATA *tnsData2, + const Word16 ch); + +static Word16 advancePsychShortMS (PSY_DATA psyData[MAX_CHANNELS], + const PSY_CONFIGURATION_SHORT *hPsyConfShort); + + +/***************************************************************************** +* +* function name: PsyNew +* description: allocates memory for psychoacoustic +* returns: an error code +* input: pointer to a psych handle +* +*****************************************************************************/ +Word16 PsyNew(PSY_KERNEL *hPsy, Word32 nChan, VO_MEM_OPERATOR *pMemOP) +{ + Word16 i; + Word32 *mdctSpectrum; + Word32 *scratchTNS; + Word16 *mdctDelayBuffer; + + mdctSpectrum = (Word32 *)mem_malloc(pMemOP, nChan * FRAME_LEN_LONG * sizeof(Word32), 32, VO_INDEX_ENC_AAC); + if(NULL == mdctSpectrum) + return 1; + + scratchTNS = (Word32 *)mem_malloc(pMemOP, nChan * FRAME_LEN_LONG * sizeof(Word32), 32, VO_INDEX_ENC_AAC); + if(NULL == scratchTNS) + { + return 1; + } + + mdctDelayBuffer = (Word16 *)mem_malloc(pMemOP, nChan * BLOCK_SWITCHING_OFFSET * sizeof(Word16), 32, VO_INDEX_ENC_AAC); + if(NULL == mdctDelayBuffer) + { + return 1; + } + + for (i=0; ipsyData[i].mdctDelayBuffer = mdctDelayBuffer + i*BLOCK_SWITCHING_OFFSET; + hPsy->psyData[i].mdctSpectrum = mdctSpectrum + i*FRAME_LEN_LONG; + } + + hPsy->pScratchTns = scratchTNS; + + return 0; +} + + +/***************************************************************************** +* +* function name: PsyDelete +* description: allocates memory for psychoacoustic +* returns: an error code +* +*****************************************************************************/ +Word16 PsyDelete(PSY_KERNEL *hPsy, VO_MEM_OPERATOR *pMemOP) +{ + Word32 nch; + + if(hPsy) + { + if(hPsy->psyData[0].mdctDelayBuffer) + mem_free(pMemOP, hPsy->psyData[0].mdctDelayBuffer, VO_INDEX_ENC_AAC); + + if(hPsy->psyData[0].mdctSpectrum) + mem_free(pMemOP, hPsy->psyData[0].mdctSpectrum, VO_INDEX_ENC_AAC); + + for (nch=0; nchpsyData[nch].mdctDelayBuffer = NULL; + hPsy->psyData[nch].mdctSpectrum = NULL; + } + + if(hPsy->pScratchTns) + { + mem_free(pMemOP, hPsy->pScratchTns, VO_INDEX_ENC_AAC); + hPsy->pScratchTns = NULL; + } + } + + return 0; +} + + +/***************************************************************************** +* +* function name: PsyOutNew +* description: allocates memory for psyOut struc +* returns: an error code +* input: pointer to a psych handle +* +*****************************************************************************/ +Word16 PsyOutNew(PSY_OUT *hPsyOut, VO_MEM_OPERATOR *pMemOP) +{ + pMemOP->Set(VO_INDEX_ENC_AAC, hPsyOut, 0, sizeof(PSY_OUT)); + /* + alloc some more stuff, tbd + */ + return 0; +} + +/***************************************************************************** +* +* function name: PsyOutDelete +* description: allocates memory for psychoacoustic +* returns: an error code +* +*****************************************************************************/ +Word16 PsyOutDelete(PSY_OUT *hPsyOut, VO_MEM_OPERATOR *pMemOP) +{ + hPsyOut=NULL; + return 0; +} + + +/***************************************************************************** +* +* function name: psyMainInit +* description: initializes psychoacoustic +* returns: an error code +* +*****************************************************************************/ + +Word16 psyMainInit(PSY_KERNEL *hPsy, + Word32 sampleRate, + Word32 bitRate, + Word16 channels, + Word16 tnsMask, + Word16 bandwidth) +{ + Word16 ch, err; + Word32 channelBitRate = bitRate/channels; + + err = InitPsyConfigurationLong(channelBitRate, + sampleRate, + bandwidth, + &(hPsy->psyConfLong)); + + if (!err) { + hPsy->sampleRateIdx = hPsy->psyConfLong.sampRateIdx; + err = InitTnsConfigurationLong(bitRate, sampleRate, channels, + &hPsy->psyConfLong.tnsConf, &hPsy->psyConfLong, tnsMask&2); + } + + if (!err) + err = InitPsyConfigurationShort(channelBitRate, + sampleRate, + bandwidth, + &hPsy->psyConfShort); + if (!err) { + err = InitTnsConfigurationShort(bitRate, sampleRate, channels, + &hPsy->psyConfShort.tnsConf, &hPsy->psyConfShort, tnsMask&1); + } + + if (!err) + for(ch=0;ch < channels;ch++){ + + InitBlockSwitching(&hPsy->psyData[ch].blockSwitchingControl, + bitRate, channels); + + InitPreEchoControl(hPsy->psyData[ch].sfbThresholdnm1, + hPsy->psyConfLong.sfbCnt, + hPsy->psyConfLong.sfbThresholdQuiet); + hPsy->psyData[ch].mdctScalenm1 = 0; + } + + return(err); +} + +/***************************************************************************** +* +* function name: psyMain +* description: psychoacoustic main function +* returns: an error code +* +* This function assumes that enough input data is in the modulo buffer. +* +*****************************************************************************/ + +Word16 psyMain(Word16 nChannels, + ELEMENT_INFO *elemInfo, + Word16 *timeSignal, + PSY_DATA psyData[MAX_CHANNELS], + TNS_DATA tnsData[MAX_CHANNELS], + PSY_CONFIGURATION_LONG *hPsyConfLong, + PSY_CONFIGURATION_SHORT *hPsyConfShort, + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + PSY_OUT_ELEMENT *psyOutElement, + Word32 *pScratchTns, + Word32 sampleRate) +{ + Word16 maxSfbPerGroup[MAX_CHANNELS]; + Word16 mdctScalingArray[MAX_CHANNELS]; + + Word16 ch; /* counts through channels */ + Word16 sfb; /* counts through scalefactor bands */ + Word16 line; /* counts through lines */ + Word16 channels; + Word16 maxScale; + + channels = elemInfo->nChannelsInEl; + maxScale = 0; + + /* block switching */ + for(ch = 0; ch < channels; ch++) { + BlockSwitching(&psyData[ch].blockSwitchingControl, + timeSignal+elemInfo->ChannelIndex[ch], + sampleRate, + nChannels); + } + + /* synch left and right block type */ + SyncBlockSwitching(&psyData[0].blockSwitchingControl, + &psyData[1].blockSwitchingControl, + channels); + + /* transform + and get maxScale (max mdctScaling) for all channels */ + for(ch=0; chChannelIndex[ch], + nChannels, + psyData[ch].mdctSpectrum, + &(mdctScalingArray[ch]), + psyData[ch].blockSwitchingControl.windowSequence); + maxScale = max(maxScale, mdctScalingArray[ch]); + } + + /* common scaling for all channels */ + for (ch=0; ch 0) { + Word32 *Spectrum = psyData[ch].mdctSpectrum; + for(line=0; line> scaleDiff; + Spectrum++; + } + } + psyData[ch].mdctScale = maxScale; + } + + for (ch=0; chsfbCnt-1; sfb>=0; sfb--) { + for (line=hPsyConfLong->sfbOffset[sfb+1] - 1; line>=hPsyConfLong->sfbOffset[sfb]; line--) { + + if (psyData[ch].mdctSpectrum[line] != 0) break; + } + if (line >= hPsyConfLong->sfbOffset[sfb]) break; + } + maxSfbPerGroup[ch] = sfb + 1; + + /* Calc bandwise energies for mid and side channel + Do it only if 2 channels exist */ + + if (ch == 1) + advancePsychLongMS(psyData, hPsyConfLong); + } + else { + advancePsychShort(&psyData[ch], + &tnsData[ch], + hPsyConfShort, + &psyOutChannel[ch], + pScratchTns, + &tnsData[1 - ch], + ch); + + /* Calc bandwise energies for mid and side channel + Do it only if 2 channels exist */ + + if (ch == 1) + advancePsychShortMS (psyData, hPsyConfShort); + } + } + + /* group short data */ + for(ch=0; chsfbCnt, + hPsyConfShort->sfbOffset, + hPsyConfShort->sfbMinSnr, + psyOutElement->groupedSfbOffset[ch], + &maxSfbPerGroup[ch], + psyOutElement->groupedSfbMinSnr[ch], + psyData[ch].blockSwitchingControl.noOfGroups, + psyData[ch].blockSwitchingControl.groupLen); + } + } + + +#if (MAX_CHANNELS>1) + /* + stereo Processing + */ + if (channels == 2) { + psyOutElement->toolsInfo.msDigest = MS_NONE; + maxSfbPerGroup[0] = maxSfbPerGroup[1] = max(maxSfbPerGroup[0], maxSfbPerGroup[1]); + + + if (psyData[0].blockSwitchingControl.windowSequence != SHORT_WINDOW) + MsStereoProcessing(psyData[0].sfbEnergy.sfbLong, + psyData[1].sfbEnergy.sfbLong, + psyData[0].sfbEnergyMS.sfbLong, + psyData[1].sfbEnergyMS.sfbLong, + psyData[0].mdctSpectrum, + psyData[1].mdctSpectrum, + psyData[0].sfbThreshold.sfbLong, + psyData[1].sfbThreshold.sfbLong, + psyData[0].sfbSpreadedEnergy.sfbLong, + psyData[1].sfbSpreadedEnergy.sfbLong, + (Word16*)&psyOutElement->toolsInfo.msDigest, + (Word16*)psyOutElement->toolsInfo.msMask, + hPsyConfLong->sfbCnt, + hPsyConfLong->sfbCnt, + maxSfbPerGroup[0], + (const Word16*)hPsyConfLong->sfbOffset); + else + MsStereoProcessing(psyData[0].sfbEnergy.sfbLong, + psyData[1].sfbEnergy.sfbLong, + psyData[0].sfbEnergyMS.sfbLong, + psyData[1].sfbEnergyMS.sfbLong, + psyData[0].mdctSpectrum, + psyData[1].mdctSpectrum, + psyData[0].sfbThreshold.sfbLong, + psyData[1].sfbThreshold.sfbLong, + psyData[0].sfbSpreadedEnergy.sfbLong, + psyData[1].sfbSpreadedEnergy.sfbLong, + (Word16*)&psyOutElement->toolsInfo.msDigest, + (Word16*)psyOutElement->toolsInfo.msMask, + psyData[0].blockSwitchingControl.noOfGroups*hPsyConfShort->sfbCnt, + hPsyConfShort->sfbCnt, + maxSfbPerGroup[0], + (const Word16*)psyOutElement->groupedSfbOffset[0]); + } + +#endif /* (MAX_CHANNELS>1) */ + + /* + build output + */ + for(ch=0;chsfbCnt, + hPsyConfLong->sfbOffset, + maxSfbPerGroup[ch], + hPsyConfLong->sfbMinSnr, + psyData[ch].blockSwitchingControl.noOfGroups, + psyData[ch].blockSwitchingControl.groupLen, + &psyOutChannel[ch]); + else + BuildInterface(psyData[ch].mdctSpectrum, + psyData[ch].mdctScale, + &psyData[ch].sfbThreshold, + &psyData[ch].sfbEnergy, + &psyData[ch].sfbSpreadedEnergy, + psyData[ch].sfbEnergySum, + psyData[ch].sfbEnergySumMS, + SHORT_WINDOW, + SINE_WINDOW, + psyData[0].blockSwitchingControl.noOfGroups*hPsyConfShort->sfbCnt, + psyOutElement->groupedSfbOffset[ch], + maxSfbPerGroup[ch], + psyOutElement->groupedSfbMinSnr[ch], + psyData[ch].blockSwitchingControl.noOfGroups, + psyData[ch].blockSwitchingControl.groupLen, + &psyOutChannel[ch]); + } + + return(0); /* no error */ +} + +/***************************************************************************** +* +* function name: advancePsychLong +* description: psychoacoustic for long blocks +* +*****************************************************************************/ + +static Word16 advancePsychLong(PSY_DATA* psyData, + TNS_DATA* tnsData, + PSY_CONFIGURATION_LONG *hPsyConfLong, + PSY_OUT_CHANNEL* psyOutChannel, + Word32 *pScratchTns, + const TNS_DATA* tnsData2, + const Word16 ch) +{ + Word32 i; + Word32 normEnergyShift = (psyData->mdctScale + 1) << 1; /* in reference code, mdct spectrum must be multipied with 2, so +1 */ + Word32 clipEnergy = hPsyConfLong->clipEnergy >> normEnergyShift; + Word32 *data0, *data1, tdata; + + /* low pass */ + data0 = psyData->mdctSpectrum + hPsyConfLong->lowpassLine; + for(i=hPsyConfLong->lowpassLine; imdctSpectrum, + hPsyConfLong->sfbOffset, + hPsyConfLong->sfbActive, + psyData->sfbEnergy.sfbLong, + &psyData->sfbEnergySum.sfbLong); + + /* + TNS detect + */ + TnsDetect(tnsData, + hPsyConfLong->tnsConf, + pScratchTns, + (const Word16*)hPsyConfLong->sfbOffset, + psyData->mdctSpectrum, + 0, + psyData->blockSwitchingControl.windowSequence, + psyData->sfbEnergy.sfbLong); + + /* TnsSync */ + if (ch == 1) { + TnsSync(tnsData, + tnsData2, + hPsyConfLong->tnsConf, + 0, + psyData->blockSwitchingControl.windowSequence); + } + + /* Tns Encoder */ + TnsEncode(&psyOutChannel->tnsInfo, + tnsData, + hPsyConfLong->sfbCnt, + hPsyConfLong->tnsConf, + hPsyConfLong->lowpassLine, + psyData->mdctSpectrum, + 0, + psyData->blockSwitchingControl.windowSequence); + + /* first part of threshold calculation */ + data0 = psyData->sfbEnergy.sfbLong; + data1 = psyData->sfbThreshold.sfbLong; + for (i=hPsyConfLong->sfbCnt; i; i--) { + tdata = L_mpy_ls(*data0++, hPsyConfLong->ratio); + *data1++ = min(tdata, clipEnergy); + } + + /* Calc sfb-bandwise mdct-energies for left and right channel again */ + if (tnsData->dataRaw.tnsLong.subBlockInfo.tnsActive!=0) { + Word16 tnsStartBand = hPsyConfLong->tnsConf.tnsStartBand; + CalcBandEnergy( psyData->mdctSpectrum, + hPsyConfLong->sfbOffset+tnsStartBand, + hPsyConfLong->sfbActive - tnsStartBand, + psyData->sfbEnergy.sfbLong+tnsStartBand, + &psyData->sfbEnergySum.sfbLong); + + data0 = psyData->sfbEnergy.sfbLong; + tdata = psyData->sfbEnergySum.sfbLong; + for (i=0; isfbEnergySum.sfbLong = tdata; + } + + + /* spreading energy */ + SpreadingMax(hPsyConfLong->sfbCnt, + hPsyConfLong->sfbMaskLowFactor, + hPsyConfLong->sfbMaskHighFactor, + psyData->sfbThreshold.sfbLong); + + /* threshold in quiet */ + data0 = psyData->sfbThreshold.sfbLong; + data1 = hPsyConfLong->sfbThresholdQuiet; + for (i=hPsyConfLong->sfbCnt; i; i--) + { + *data0 = max(*data0, (*data1 >> normEnergyShift)); + data0++; data1++; + } + + /* preecho control */ + if (psyData->blockSwitchingControl.windowSequence == STOP_WINDOW) { + data0 = psyData->sfbThresholdnm1; + for (i=hPsyConfLong->sfbCnt; i; i--) { + *data0++ = MAX_32; + } + psyData->mdctScalenm1 = 0; + } + + PreEchoControl( psyData->sfbThresholdnm1, + hPsyConfLong->sfbCnt, + hPsyConfLong->maxAllowedIncreaseFactor, + hPsyConfLong->minRemainingThresholdFactor, + psyData->sfbThreshold.sfbLong, + psyData->mdctScale, + psyData->mdctScalenm1); + psyData->mdctScalenm1 = psyData->mdctScale; + + + if (psyData->blockSwitchingControl.windowSequence== START_WINDOW) { + data0 = psyData->sfbThresholdnm1; + for (i=hPsyConfLong->sfbCnt; i; i--) { + *data0++ = MAX_32; + } + psyData->mdctScalenm1 = 0; + } + + /* apply tns mult table on cb thresholds */ + ApplyTnsMultTableToRatios(hPsyConfLong->tnsConf.tnsRatioPatchLowestCb, + hPsyConfLong->tnsConf.tnsStartBand, + tnsData->dataRaw.tnsLong.subBlockInfo, + psyData->sfbThreshold.sfbLong); + + + /* spreaded energy */ + data0 = psyData->sfbSpreadedEnergy.sfbLong; + data1 = psyData->sfbEnergy.sfbLong; + for (i=hPsyConfLong->sfbCnt; i; i--) { + //psyData->sfbSpreadedEnergy.sfbLong[i] = psyData->sfbEnergy.sfbLong[i]; + *data0++ = *data1++; + } + + /* spreading energy */ + SpreadingMax(hPsyConfLong->sfbCnt, + hPsyConfLong->sfbMaskLowFactorSprEn, + hPsyConfLong->sfbMaskHighFactorSprEn, + psyData->sfbSpreadedEnergy.sfbLong); + + return 0; +} + +/***************************************************************************** +* +* function name: advancePsychLongMS +* description: update mdct-energies for left add or minus right channel +* for long block +* +*****************************************************************************/ +static Word16 advancePsychLongMS (PSY_DATA psyData[MAX_CHANNELS], + const PSY_CONFIGURATION_LONG *hPsyConfLong) +{ + CalcBandEnergyMS(psyData[0].mdctSpectrum, + psyData[1].mdctSpectrum, + hPsyConfLong->sfbOffset, + hPsyConfLong->sfbActive, + psyData[0].sfbEnergyMS.sfbLong, + &psyData[0].sfbEnergySumMS.sfbLong, + psyData[1].sfbEnergyMS.sfbLong, + &psyData[1].sfbEnergySumMS.sfbLong); + + return 0; +} + + +/***************************************************************************** +* +* function name: advancePsychShort +* description: psychoacoustic for short blocks +* +*****************************************************************************/ + +static Word16 advancePsychShort(PSY_DATA* psyData, + TNS_DATA* tnsData, + const PSY_CONFIGURATION_SHORT *hPsyConfShort, + PSY_OUT_CHANNEL* psyOutChannel, + Word32 *pScratchTns, + const TNS_DATA *tnsData2, + const Word16 ch) +{ + Word32 w; + Word32 normEnergyShift = (psyData->mdctScale + 1) << 1; /* in reference code, mdct spectrum must be multipied with 2, so +1 */ + Word32 clipEnergy = hPsyConfShort->clipEnergy >> normEnergyShift; + Word32 wOffset = 0; + Word32 *data0; + const Word32 *data1; + + for(w = 0; w < TRANS_FAC; w++) { + Word32 i, tdata; + + /* low pass */ + data0 = psyData->mdctSpectrum + wOffset + hPsyConfShort->lowpassLine; + for(i=hPsyConfShort->lowpassLine; imdctSpectrum+wOffset, + hPsyConfShort->sfbOffset, + hPsyConfShort->sfbActive, + psyData->sfbEnergy.sfbShort[w], + &psyData->sfbEnergySum.sfbShort[w]); + /* + TNS + */ + TnsDetect(tnsData, + hPsyConfShort->tnsConf, + pScratchTns, + (const Word16*)hPsyConfShort->sfbOffset, + psyData->mdctSpectrum+wOffset, + w, + psyData->blockSwitchingControl.windowSequence, + psyData->sfbEnergy.sfbShort[w]); + + /* TnsSync */ + if (ch == 1) { + TnsSync(tnsData, + tnsData2, + hPsyConfShort->tnsConf, + w, + psyData->blockSwitchingControl.windowSequence); + } + + TnsEncode(&psyOutChannel->tnsInfo, + tnsData, + hPsyConfShort->sfbCnt, + hPsyConfShort->tnsConf, + hPsyConfShort->lowpassLine, + psyData->mdctSpectrum+wOffset, + w, + psyData->blockSwitchingControl.windowSequence); + + /* first part of threshold calculation */ + data0 = psyData->sfbThreshold.sfbShort[w]; + data1 = psyData->sfbEnergy.sfbShort[w]; + for (i=hPsyConfShort->sfbCnt; i; i--) { + tdata = L_mpy_ls(*data1++, hPsyConfShort->ratio); + *data0++ = min(tdata, clipEnergy); + } + + /* Calc sfb-bandwise mdct-energies for left and right channel again */ + if (tnsData->dataRaw.tnsShort.subBlockInfo[w].tnsActive != 0) { + Word16 tnsStartBand = hPsyConfShort->tnsConf.tnsStartBand; + CalcBandEnergy( psyData->mdctSpectrum+wOffset, + hPsyConfShort->sfbOffset+tnsStartBand, + (hPsyConfShort->sfbActive - tnsStartBand), + psyData->sfbEnergy.sfbShort[w]+tnsStartBand, + &psyData->sfbEnergySum.sfbShort[w]); + + tdata = psyData->sfbEnergySum.sfbShort[w]; + data0 = psyData->sfbEnergy.sfbShort[w]; + for (i=tnsStartBand; i; i--) + tdata += *data0++; + + psyData->sfbEnergySum.sfbShort[w] = tdata; + } + + /* spreading */ + SpreadingMax(hPsyConfShort->sfbCnt, + hPsyConfShort->sfbMaskLowFactor, + hPsyConfShort->sfbMaskHighFactor, + psyData->sfbThreshold.sfbShort[w]); + + + /* threshold in quiet */ + data0 = psyData->sfbThreshold.sfbShort[w]; + data1 = hPsyConfShort->sfbThresholdQuiet; + for (i=hPsyConfShort->sfbCnt; i; i--) + { + *data0 = max(*data0, (*data1 >> normEnergyShift)); + + data0++; data1++; + } + + + /* preecho */ + PreEchoControl( psyData->sfbThresholdnm1, + hPsyConfShort->sfbCnt, + hPsyConfShort->maxAllowedIncreaseFactor, + hPsyConfShort->minRemainingThresholdFactor, + psyData->sfbThreshold.sfbShort[w], + psyData->mdctScale, + w==0 ? psyData->mdctScalenm1 : psyData->mdctScale); + + /* apply tns mult table on cb thresholds */ + ApplyTnsMultTableToRatios( hPsyConfShort->tnsConf.tnsRatioPatchLowestCb, + hPsyConfShort->tnsConf.tnsStartBand, + tnsData->dataRaw.tnsShort.subBlockInfo[w], + psyData->sfbThreshold.sfbShort[w]); + + /* spreaded energy */ + data0 = psyData->sfbSpreadedEnergy.sfbShort[w]; + data1 = psyData->sfbEnergy.sfbShort[w]; + for (i=hPsyConfShort->sfbCnt; i; i--) { + *data0++ = *data1++; + } + SpreadingMax(hPsyConfShort->sfbCnt, + hPsyConfShort->sfbMaskLowFactorSprEn, + hPsyConfShort->sfbMaskHighFactorSprEn, + psyData->sfbSpreadedEnergy.sfbShort[w]); + + wOffset += FRAME_LEN_SHORT; + } /* for TRANS_FAC */ + + psyData->mdctScalenm1 = psyData->mdctScale; + + return 0; +} + +/***************************************************************************** +* +* function name: advancePsychShortMS +* description: update mdct-energies for left add or minus right channel +* for short block +* +*****************************************************************************/ +static Word16 advancePsychShortMS (PSY_DATA psyData[MAX_CHANNELS], + const PSY_CONFIGURATION_SHORT *hPsyConfShort) +{ + Word32 w, wOffset; + wOffset = 0; + for(w=0; wsfbOffset, + hPsyConfShort->sfbActive, + psyData[0].sfbEnergyMS.sfbShort[w], + &psyData[0].sfbEnergySumMS.sfbShort[w], + psyData[1].sfbEnergyMS.sfbShort[w], + &psyData[1].sfbEnergySumMS.sfbShort[w]); + wOffset += FRAME_LEN_SHORT; + } + + return 0; +} diff --git a/jni/src/qc_main.c b/jni/src/qc_main.c new file mode 100644 index 000000000..48ff30087 --- /dev/null +++ b/jni/src/qc_main.c @@ -0,0 +1,580 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: qc_main.c + + Content: Quantizing & coding functions + +*******************************************************************************/ + +#include "basic_op.h" +#include "oper_32b.h" +#include "qc_main.h" +#include "quantize.h" +#include "interface.h" +#include "adj_thr.h" +#include "sf_estim.h" +#include "stat_bits.h" +#include "bit_cnt.h" +#include "dyn_bits.h" +#include "channel_map.h" +#include "memalign.h" + + +typedef enum{ + FRAME_LEN_BYTES_MODULO = 1, + FRAME_LEN_BYTES_INT = 2 +}FRAME_LEN_RESULT_MODE; + +static const Word16 maxFillElemBits = 7 + 270*8; + +/* forward declarations */ + +static Word16 calcMaxValueInSfb(Word16 sfbCnt, + Word16 maxSfbPerGroup, + Word16 sfbPerGroup, + Word16 sfbOffset[MAX_GROUPED_SFB], + Word16 quantSpectrum[FRAME_LEN_LONG], + UWord16 maxValue[MAX_GROUPED_SFB]); + + +/***************************************************************************** +* +* function name: calcFrameLen +* description: estimate the frame length according the bitrates +* +*****************************************************************************/ +static Word16 calcFrameLen(Word32 bitRate, + Word32 sampleRate, + FRAME_LEN_RESULT_MODE mode) +{ + + Word32 result; + Word32 quot; + + result = (FRAME_LEN_LONG >> 3) * bitRate; + quot = result / sampleRate; + + + if (mode == FRAME_LEN_BYTES_MODULO) { + result -= quot * sampleRate; + } + else { /* FRAME_LEN_BYTES_INT */ + result = quot; + } + + return result; +} + +/***************************************************************************** +* +* function name:framePadding +* description: Calculates if padding is needed for actual frame +* returns: paddingOn or not +* +*****************************************************************************/ +static Word16 framePadding(Word32 bitRate, + Word32 sampleRate, + Word32 *paddingRest) +{ + Word16 paddingOn; + Word16 difference; + + paddingOn = 0; + + difference = calcFrameLen( bitRate, + sampleRate, + FRAME_LEN_BYTES_MODULO ); + *paddingRest = *paddingRest - difference; + + + if (*paddingRest <= 0 ) { + paddingOn = 1; + *paddingRest = *paddingRest + sampleRate; + } + + return paddingOn; +} + + +/********************************************************************************* +* +* function name: QCOutNew +* description: init qcout parameter +* returns: 0 if success +* +**********************************************************************************/ + +Word16 QCOutNew(QC_OUT *hQC, Word16 nChannels, VO_MEM_OPERATOR *pMemOP) +{ + Word32 i; + Word16 *quantSpec; + Word16 *scf; + UWord16 *maxValueInSfb; + + quantSpec = (Word16 *)mem_malloc(pMemOP, nChannels * FRAME_LEN_LONG * sizeof(Word16), 32, VO_INDEX_ENC_AAC); + if(NULL == quantSpec) + return 1; + scf = (Word16 *)mem_malloc(pMemOP, nChannels * MAX_GROUPED_SFB * sizeof(Word16), 32, VO_INDEX_ENC_AAC); + if(NULL == scf) + { + return 1; + } + maxValueInSfb = (UWord16 *)mem_malloc(pMemOP, nChannels * MAX_GROUPED_SFB * sizeof(UWord16), 32, VO_INDEX_ENC_AAC); + if(NULL == maxValueInSfb) + { + return 1; + } + + for (i=0; iqcChannel[i].quantSpec = quantSpec + i*FRAME_LEN_LONG; + + hQC->qcChannel[i].maxValueInSfb = maxValueInSfb + i*MAX_GROUPED_SFB; + + hQC->qcChannel[i].scf = scf + i*MAX_GROUPED_SFB; + } + + return 0; +} + + +/********************************************************************************* +* +* function name: QCOutDelete +* description: unint qcout parameter +* returns: 0 if success +* +**********************************************************************************/ +void QCOutDelete(QC_OUT* hQC, VO_MEM_OPERATOR *pMemOP) +{ + Word32 i; + if(hQC) + { + if(hQC->qcChannel[0].quantSpec) + mem_free(pMemOP, hQC->qcChannel[0].quantSpec, VO_INDEX_ENC_AAC); + + if(hQC->qcChannel[0].maxValueInSfb) + mem_free(pMemOP, hQC->qcChannel[0].maxValueInSfb, VO_INDEX_ENC_AAC); + + if(hQC->qcChannel[0].scf) + mem_free(pMemOP, hQC->qcChannel[0].scf, VO_INDEX_ENC_AAC); + + for (i=0; iqcChannel[i].quantSpec = NULL; + + hQC->qcChannel[i].maxValueInSfb = NULL; + + hQC->qcChannel[i].scf = NULL; + } + } +} + +/********************************************************************************* +* +* function name: QCNew +* description: set QC to zero +* returns: 0 if success +* +**********************************************************************************/ +Word16 QCNew(QC_STATE *hQC, VO_MEM_OPERATOR *pMemOP) +{ + pMemOP->Set(VO_INDEX_ENC_AAC, hQC,0,sizeof(QC_STATE)); + + return (0); +} + +/********************************************************************************* +* +* function name: QCDelete +* description: unint qcout parameter +* +**********************************************************************************/ +void QCDelete(QC_STATE *hQC, VO_MEM_OPERATOR *pMemOP) +{ + + /* + nothing to do + */ + hQC=NULL; +} + +/********************************************************************************* +* +* function name: QCInit +* description: init QD parameter +* returns: 0 if success +* +**********************************************************************************/ +Word16 QCInit(QC_STATE *hQC, + struct QC_INIT *init) +{ + hQC->nChannels = init->elInfo->nChannelsInEl; + hQC->maxBitsTot = init->maxBits; + hQC->bitResTot = sub(init->bitRes, init->averageBits); + hQC->averageBitsTot = init->averageBits; + hQC->maxBitFac = init->maxBitFac; + + hQC->padding.paddingRest = init->padding.paddingRest; + + hQC->globStatBits = 3; /* for ID_END */ + + /* channel elements init */ + InitElementBits(&hQC->elementBits, + *init->elInfo, + init->bitrate, + init->averageBits, + hQC->globStatBits); + + /* threshold parameter init */ + AdjThrInit(&hQC->adjThr, + init->meanPe, + hQC->elementBits.chBitrate); + + return 0; +} + + +/********************************************************************************* +* +* function name: QCMain +* description: quantization and coding the spectrum +* returns: 0 if success +* +**********************************************************************************/ +Word16 QCMain(QC_STATE* hQC, + ELEMENT_BITS* elBits, + ATS_ELEMENT* adjThrStateElement, + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], /* may be modified in-place */ + PSY_OUT_ELEMENT* psyOutElement, + QC_OUT_CHANNEL qcOutChannel[MAX_CHANNELS], /* out */ + QC_OUT_ELEMENT* qcOutElement, + Word16 nChannels, + Word16 ancillaryDataBytes) +{ + Word16 maxChDynBits[MAX_CHANNELS]; + Word16 chBitDistribution[MAX_CHANNELS]; + Word32 ch; + + if (elBits->bitResLevel < 0) { + return -1; + } + + if (elBits->bitResLevel > elBits->maxBitResBits) { + return -1; + } + + qcOutElement->staticBitsUsed = countStaticBitdemand(psyOutChannel, + psyOutElement, + nChannels, + qcOutElement->adtsUsed); + + + if (ancillaryDataBytes) { + qcOutElement->ancBitsUsed = 7 + (ancillaryDataBytes << 3); + + if (ancillaryDataBytes >= 15) + qcOutElement->ancBitsUsed = qcOutElement->ancBitsUsed + 8; + } + else { + qcOutElement->ancBitsUsed = 0; + } + + CalcFormFactor(hQC->logSfbFormFactor, hQC->sfbNRelevantLines, hQC->logSfbEnergy, psyOutChannel, nChannels); + + /*adjust thresholds for the desired bitrate */ + AdjustThresholds(&hQC->adjThr, + adjThrStateElement, + psyOutChannel, + psyOutElement, + chBitDistribution, + hQC->logSfbEnergy, + hQC->sfbNRelevantLines, + qcOutElement, + elBits, + nChannels, + hQC->maxBitFac); + + /*estimate scale factors */ + EstimateScaleFactors(psyOutChannel, + qcOutChannel, + hQC->logSfbEnergy, + hQC->logSfbFormFactor, + hQC->sfbNRelevantLines, + nChannels); + + /* condition to prevent empty bitreservoir */ + for (ch = 0; ch < nChannels; ch++) { + Word32 maxDynBits; + maxDynBits = elBits->averageBits + elBits->bitResLevel - 7; /* -7 bec. of align bits */ + maxDynBits = maxDynBits - qcOutElement->staticBitsUsed + qcOutElement->ancBitsUsed; + maxChDynBits[ch] = extract_l(chBitDistribution[ch] * maxDynBits / 1000); + } + + qcOutElement->dynBitsUsed = 0; + for (ch = 0; ch < nChannels; ch++) { + Word32 chDynBits; + Flag constraintsFulfilled; + Word32 iter; + iter = 0; + do { + constraintsFulfilled = 1; + + QuantizeSpectrum(psyOutChannel[ch].sfbCnt, + psyOutChannel[ch].maxSfbPerGroup, + psyOutChannel[ch].sfbPerGroup, + psyOutChannel[ch].sfbOffsets, + psyOutChannel[ch].mdctSpectrum, + qcOutChannel[ch].globalGain, + qcOutChannel[ch].scf, + qcOutChannel[ch].quantSpec); + + if (calcMaxValueInSfb(psyOutChannel[ch].sfbCnt, + psyOutChannel[ch].maxSfbPerGroup, + psyOutChannel[ch].sfbPerGroup, + psyOutChannel[ch].sfbOffsets, + qcOutChannel[ch].quantSpec, + qcOutChannel[ch].maxValueInSfb) > MAX_QUANT) { + constraintsFulfilled = 0; + } + + chDynBits = dynBitCount(qcOutChannel[ch].quantSpec, + qcOutChannel[ch].maxValueInSfb, + qcOutChannel[ch].scf, + psyOutChannel[ch].windowSequence, + psyOutChannel[ch].sfbCnt, + psyOutChannel[ch].maxSfbPerGroup, + psyOutChannel[ch].sfbPerGroup, + psyOutChannel[ch].sfbOffsets, + &qcOutChannel[ch].sectionData); + + if (chDynBits >= maxChDynBits[ch]) { + constraintsFulfilled = 0; + } + + if (!constraintsFulfilled) { + qcOutChannel[ch].globalGain = qcOutChannel[ch].globalGain + 1; + } + + iter = iter + 1; + + } while(!constraintsFulfilled); + + qcOutElement->dynBitsUsed = qcOutElement->dynBitsUsed + chDynBits; + + qcOutChannel[ch].mdctScale = psyOutChannel[ch].mdctScale; + qcOutChannel[ch].groupingMask = psyOutChannel[ch].groupingMask; + qcOutChannel[ch].windowShape = psyOutChannel[ch].windowShape; + } + + /* save dynBitsUsed for correction of bits2pe relation */ + AdjThrUpdate(adjThrStateElement, qcOutElement->dynBitsUsed); + + { + Word16 bitResSpace = elBits->maxBitResBits - elBits->bitResLevel; + Word16 deltaBitRes = elBits->averageBits - + (qcOutElement->staticBitsUsed + + qcOutElement->dynBitsUsed + qcOutElement->ancBitsUsed); + + qcOutElement->fillBits = max(0, (deltaBitRes - bitResSpace)); + } + + return 0; /* OK */ +} + + +/********************************************************************************* +* +* function name: calcMaxValueInSfb +* description: search the max Spectrum in one sfb +* +**********************************************************************************/ +static Word16 calcMaxValueInSfb(Word16 sfbCnt, + Word16 maxSfbPerGroup, + Word16 sfbPerGroup, + Word16 sfbOffset[MAX_GROUPED_SFB], + Word16 quantSpectrum[FRAME_LEN_LONG], + UWord16 maxValue[MAX_GROUPED_SFB]) +{ + Word16 sfbOffs, sfb; + Word16 maxValueAll; + + maxValueAll = 0; + + for(sfbOffs=0;sfbOffsbitResTot = 0; + + elBits = &qcKernel->elementBits; + + + if (elBits->averageBits > 0) { + /* constant bitrate */ + Word16 bitsUsed; + bitsUsed = (qcOut->qcElement.staticBitsUsed + qcOut->qcElement.dynBitsUsed) + + (qcOut->qcElement.ancBitsUsed + qcOut->qcElement.fillBits); + elBits->bitResLevel = elBits->bitResLevel + (elBits->averageBits - bitsUsed); + qcKernel->bitResTot = qcKernel->bitResTot + elBits->bitResLevel; + } + else { + /* variable bitrate */ + elBits->bitResLevel = elBits->maxBits; + qcKernel->bitResTot = qcKernel->maxBitsTot; + } +} + +/********************************************************************************* +* +* function name: FinalizeBitConsumption +* description: count bits used +* +**********************************************************************************/ +Word16 FinalizeBitConsumption(QC_STATE *qcKernel, + QC_OUT* qcOut) +{ + Word32 nFullFillElem; + Word32 totFillBits; + Word16 diffBits; + Word16 bitsUsed; + + totFillBits = 0; + + qcOut->totStaticBitsUsed = qcKernel->globStatBits; + qcOut->totStaticBitsUsed += qcOut->qcElement.staticBitsUsed; + qcOut->totDynBitsUsed = qcOut->qcElement.dynBitsUsed; + qcOut->totAncBitsUsed = qcOut->qcElement.ancBitsUsed; + qcOut->totFillBits = qcOut->qcElement.fillBits; + + if (qcOut->qcElement.fillBits) { + totFillBits += qcOut->qcElement.fillBits; + } + + nFullFillElem = (max((qcOut->totFillBits - 1), 0) / maxFillElemBits) * maxFillElemBits; + + qcOut->totFillBits = qcOut->totFillBits - nFullFillElem; + + /* check fill elements */ + + if (qcOut->totFillBits > 0) { + /* minimum Fillelement contains 7 (TAG + byte cnt) bits */ + qcOut->totFillBits = max(7, qcOut->totFillBits); + /* fill element size equals n*8 + 7 */ + qcOut->totFillBits = qcOut->totFillBits + ((8 - ((qcOut->totFillBits - 7) & 0x0007)) & 0x0007); + } + + qcOut->totFillBits = qcOut->totFillBits + nFullFillElem; + + /* now distribute extra fillbits and alignbits over channel elements */ + qcOut->alignBits = 7 - ((qcOut->totDynBitsUsed + qcOut->totStaticBitsUsed + + qcOut->totAncBitsUsed + qcOut->totFillBits - 1) & 0x0007); + + + if ( (qcOut->alignBits + qcOut->totFillBits - totFillBits == 8) && + (qcOut->totFillBits > 8)) + qcOut->totFillBits = qcOut->totFillBits - 8; + + + diffBits = qcOut->alignBits + qcOut->totFillBits - totFillBits; + + if(diffBits>=0) { + qcOut->qcElement.fillBits += diffBits; + } + + bitsUsed = qcOut->totDynBitsUsed + qcOut->totStaticBitsUsed + qcOut->totAncBitsUsed; + bitsUsed = bitsUsed + qcOut->totFillBits + qcOut->alignBits; + + if (bitsUsed > qcKernel->maxBitsTot) { + return -1; + } + return bitsUsed; +} + + +/********************************************************************************* +* +* function name: AdjustBitrate +* description: adjusts framelength via padding on a frame to frame basis, +* to achieve a bitrate that demands a non byte aligned +* framelength +* return: errorcode +* +**********************************************************************************/ +Word16 AdjustBitrate(QC_STATE *hQC, + Word32 bitRate, /* total bitrate */ + Word32 sampleRate) /* output sampling rate */ +{ + Word16 paddingOn; + Word16 frameLen; + Word16 codeBits; + Word16 codeBitsLast; + + /* Do we need a extra padding byte? */ + paddingOn = framePadding(bitRate, + sampleRate, + &hQC->padding.paddingRest); + + /* frame length */ + frameLen = paddingOn + calcFrameLen(bitRate, + sampleRate, + FRAME_LEN_BYTES_INT); + + frameLen = frameLen << 3; + codeBitsLast = hQC->averageBitsTot - hQC->globStatBits; + codeBits = frameLen - hQC->globStatBits; + + /* calculate bits for every channel element */ + if (codeBits != codeBitsLast) { + Word16 totalBits = 0; + + hQC->elementBits.averageBits = (hQC->elementBits.relativeBits * codeBits) >> 16; /* relativeBits was scaled down by 2 */ + totalBits += hQC->elementBits.averageBits; + + hQC->elementBits.averageBits = hQC->elementBits.averageBits + (codeBits - totalBits); + } + + hQC->averageBitsTot = frameLen; + + return 0; +} diff --git a/jni/src/quantize.c b/jni/src/quantize.c new file mode 100644 index 000000000..0d0f55040 --- /dev/null +++ b/jni/src/quantize.c @@ -0,0 +1,445 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: quantize.c + + Content: quantization functions + +*******************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "quantize.h" +#include "aac_rom.h" + +#define MANT_DIGITS 9 +#define MANT_SIZE (1<> (INT_BITS-2-MANT_DIGITS)) & (MANT_SIZE-1)]; +} + + +/***************************************************************************** +* +* function name:quantizeSingleLine +* description: quantizes spectrum +* quaSpectrum = mdctSpectrum^3/4*2^(-(3/16)*gain) +* +*****************************************************************************/ +static Word16 quantizeSingleLine(const Word16 gain, const Word32 absSpectrum) +{ + Word32 e, minusFinalExp, finalShift; + Word32 x; + Word16 qua = 0; + + + if (absSpectrum) { + e = norm_l(absSpectrum); + x = pow34(absSpectrum << e); + + /* calculate the final fractional exponent times 16 (was 3*(4*e + gain) + (INT_BITS-1)*16) */ + minusFinalExp = (e << 2) + gain; + minusFinalExp = (minusFinalExp << 1) + minusFinalExp; + minusFinalExp = minusFinalExp + ((INT_BITS-1) << 4); + + /* separate the exponent into a shift, and a multiply */ + finalShift = minusFinalExp >> 4; + + if (finalShift < INT_BITS) { + x = L_mpy_wx(x, pow2tominusNover16[minusFinalExp & 15]); + + x += XROUND >> (INT_BITS - finalShift); + + /* shift and quantize */ + finalShift--; + + if(finalShift >= 0) + x >>= finalShift; + else + x <<= (-finalShift); + + qua = saturate(x); + } + } + + return qua; +} + +/***************************************************************************** +* +* function name:quantizeLines +* description: quantizes spectrum lines +* quaSpectrum = mdctSpectrum^3/4*2^(-(3/16)*gain) +* input: global gain, number of lines to process, spectral data +* output: quantized spectrum +* +*****************************************************************************/ +static void quantizeLines(const Word16 gain, + const Word16 noOfLines, + const Word32 *mdctSpectrum, + Word16 *quaSpectrum) +{ + Word32 line; + Word32 m = gain&3; + Word32 g = (gain >> 2) + 4; + Word32 mdctSpeL; + const Word16 *pquat; + /* gain&3 */ + + pquat = quantBorders[m]; + + g += 16; + + if(g >= 0) + { + for (line=0; line> g; + + if (saShft > pquat[0]) { + + if (saShft < pquat[1]) { + + qua = mdctSpeL>0 ? 1 : -1; + } + else { + + if (saShft < pquat[2]) { + + qua = mdctSpeL>0 ? 2 : -2; + } + else { + + if (saShft < pquat[3]) { + + qua = mdctSpeL>0 ? 3 : -3; + } + else { + qua = quantizeSingleLine(gain, sa); + /* adjust the sign. Since 0 < qua < 1, this cannot overflow. */ + + if (mdctSpeL < 0) + qua = -qua; + } + } + } + } + } + quaSpectrum[line] = qua ; + } + } + else + { + for (line=0; line pquat[0]) { + + if (saShft < pquat[1]) { + + qua = mdctSpeL>0 ? 1 : -1; + } + else { + + if (saShft < pquat[2]) { + + qua = mdctSpeL>0 ? 2 : -2; + } + else { + + if (saShft < pquat[3]) { + + qua = mdctSpeL>0 ? 3 : -3; + } + else { + qua = quantizeSingleLine(gain, sa); + /* adjust the sign. Since 0 < qua < 1, this cannot overflow. */ + + if (mdctSpeL < 0) + qua = -qua; + } + } + } + } + } + quaSpectrum[line] = qua ; + } + } + +} + + +/***************************************************************************** +* +* function name:iquantizeLines +* description: iquantizes spectrum lines without sign +* mdctSpectrum = iquaSpectrum^4/3 *2^(0.25*gain) +* input: global gain, number of lines to process,quantized spectrum +* output: spectral data +* +*****************************************************************************/ +static void iquantizeLines(const Word16 gain, + const Word16 noOfLines, + const Word16 *quantSpectrum, + Word32 *mdctSpectrum) +{ + Word32 iquantizermod; + Word32 iquantizershift; + Word32 line; + + iquantizermod = gain & 3; + iquantizershift = gain >> 2; + + for (line=0; line> (INT_BITS-2-MANT_DIGITS)) & (~MANT_SIZE); + + /* calculate "mantissa" ^4/3 */ + s = mTab_4_3[tabIndex]; + + /* get approperiate exponent multiplier for specExp^3/4 combined with scfMod */ + t = specExpMantTableComb_enc[iquantizermod][specExp]; + + /* multiply "mantissa" ^4/3 with exponent multiplier */ + accu = MULHIGH(s, t); + + /* get approperiate exponent shifter */ + specExp = specExpTableComb_enc[iquantizermod][specExp]; + + specExp += iquantizershift + 1; + if(specExp >= 0) + mdctSpectrum[line] = accu << specExp; + else + mdctSpectrum[line] = accu >> (-specExp); + } + else { + mdctSpectrum[line] = 0; + } + } +} + +/***************************************************************************** +* +* function name: QuantizeSpectrum +* description: quantizes the entire spectrum +* returns: +* input: number of scalefactor bands to be quantized, ... +* output: quantized spectrum +* +*****************************************************************************/ +void QuantizeSpectrum(Word16 sfbCnt, + Word16 maxSfbPerGroup, + Word16 sfbPerGroup, + Word16 *sfbOffset, + Word32 *mdctSpectrum, + Word16 globalGain, + Word16 *scalefactors, + Word16 *quantizedSpectrum) +{ + Word32 sfbOffs, sfb; + + for(sfbOffs=0;sfbOffs> 2) + 4; + Word32 g2 = (g << 1) + 1; + const Word16 *pquat, *repquat; + /* gain&3 */ + + pquat = quantBorders[m]; + repquat = quantRecon[m]; + + dist = 0; + g += 16; + if(g2 < 0 && g >= 0) + { + g2 = -g2; + for(line=0; line> g; + + if (saShft < pquat[0]) { + distSingle = (saShft * saShft) >> g2; + } + else { + + if (saShft < pquat[1]) { + diff = saShft - repquat[0]; + distSingle = (diff * diff) >> g2; + } + else { + + if (saShft < pquat[2]) { + diff = saShft - repquat[1]; + distSingle = (diff * diff) >> g2; + } + else { + + if (saShft < pquat[3]) { + diff = saShft - repquat[2]; + distSingle = (diff * diff) >> g2; + } + else { + Word16 qua = quantizeSingleLine(gain, sa); + Word32 iqval, diff32; + /* now that we have quantized x, re-quantize it. */ + iquantizeLines(gain, 1, &qua, &iqval); + diff32 = sa - iqval; + distSingle = fixmul(diff32, diff32); + } + } + } + } + + dist = L_add(dist, distSingle); + } + } + } + else + { + for(line=0; line> 1; + preshift = postshift << 1; + postshift = postshift + 8; /* sqrt/256 */ + if(preshift >= 0) + y = x << preshift; /* now 1/4 <= y < 1 */ + else + y = x >> (-preshift); + y = formfac_sqrttable[y-32]; + + if(postshift >= 0) + y = y >> postshift; + else + y = y << (-postshift); + + return y; +} + + +/********************************************************************************* +* +* function name: CalcFormFactorChannel +* description: calculate the form factor one channel +* ffac(n) = sqrt(abs(X(k)) + sqrt(abs(X(k+1)) + .... +* +**********************************************************************************/ +static void +CalcFormFactorChannel(Word16 *logSfbFormFactor, + Word16 *sfbNRelevantLines, + Word16 *logSfbEnergy, + PSY_OUT_CHANNEL *psyOutChan) +{ + Word32 sfbw, sfbw1; + Word32 i, j; + Word32 sfbOffs, sfb, shift; + + sfbw = sfbw1 = 0; + for (sfbOffs=0; sfbOffssfbCnt; sfbOffs+=psyOutChan->sfbPerGroup){ + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + i = sfbOffs+sfb; + + if (psyOutChan->sfbEnergy[i] > psyOutChan->sfbThreshold[i]) { + Word32 accu, avgFormFactor,iSfbWidth; + Word32 *mdctSpec; + sfbw = psyOutChan->sfbOffsets[i+1] - psyOutChan->sfbOffsets[i]; + iSfbWidth = invSBF[(sfbw >> 2) - 1]; + mdctSpec = psyOutChan->mdctSpectrum + psyOutChan->sfbOffsets[i]; + accu = 0; + /* calc sum of sqrt(spec) */ + for (j=sfbw; j; j--) { + accu += formfac_sqrt(L_abs(*mdctSpec)); mdctSpec++; + } + logSfbFormFactor[i] = iLog4(accu); + logSfbEnergy[i] = iLog4(psyOutChan->sfbEnergy[i]); + avgFormFactor = fixmul(rsqrt(psyOutChan->sfbEnergy[i],INT_BITS), iSfbWidth); + avgFormFactor = rsqrt((Word32)avgFormFactor,INT_BITS) >> 10; + /* result is multiplied by 4 */ + if(avgFormFactor) + sfbNRelevantLines[i] = accu / avgFormFactor; + else + sfbNRelevantLines[i] = 0x7fff; + } + else { + /* set number of lines to zero */ + sfbNRelevantLines[i] = 0; + } + } + } +} + +/********************************************************************************* +* +* function name: improveScf +* description: find better scalefactor with analysis by synthesis +* +**********************************************************************************/ +static Word16 improveScf(Word32 *spec, + Word16 sfbWidth, + Word32 thresh, + Word16 scf, + Word16 minScf, + Word32 *dist, + Word16 *minScfCalculated) +{ + Word32 cnt; + Word32 sfbDist; + Word32 scfBest; + Word32 thresh125 = L_add(thresh, (thresh >> 2)); + + scfBest = scf; + + /* calc real distortion */ + sfbDist = calcSfbDist(spec, sfbWidth, scf); + *minScfCalculated = scf; + if(!sfbDist) + return scfBest; + + if (sfbDist > thresh125) { + Word32 scfEstimated; + Word32 sfbDistBest; + scfEstimated = scf; + sfbDistBest = sfbDist; + + cnt = 0; + while (sfbDist > thresh125 && (cnt < 3)) { + + scf = scf + 1; + sfbDist = calcSfbDist(spec, sfbWidth, scf); + + if (sfbDist < sfbDistBest) { + scfBest = scf; + sfbDistBest = sfbDist; + } + cnt = cnt + 1; + } + cnt = 0; + scf = scfEstimated; + sfbDist = sfbDistBest; + while ((sfbDist > thresh125) && (cnt < 1) && (scf > minScf)) { + + scf = scf - 1; + sfbDist = calcSfbDist(spec, sfbWidth, scf); + + if (sfbDist < sfbDistBest) { + scfBest = scf; + sfbDistBest = sfbDist; + } + *minScfCalculated = scf; + cnt = cnt + 1; + } + *dist = sfbDistBest; + } + else { + Word32 sfbDistBest; + Word32 sfbDistAllowed; + Word32 thresh08 = fixmul(COEF08_31, thresh); + sfbDistBest = sfbDist; + + if (sfbDist < thresh08) + sfbDistAllowed = sfbDist; + else + sfbDistAllowed = thresh08; + for (cnt=0; cnt<3; cnt++) { + scf = scf + 1; + sfbDist = calcSfbDist(spec, sfbWidth, scf); + + if (fixmul(COEF08_31,sfbDist) < sfbDistAllowed) { + *minScfCalculated = scfBest + 1; + scfBest = scf; + sfbDistBest = sfbDist; + } + } + *dist = sfbDistBest; + } + + /* return best scalefactor */ + return scfBest; +} + +/********************************************************************************* +* +* function name: countSingleScfBits +* description: count single scf bits in huffum +* +**********************************************************************************/ +static Word16 countSingleScfBits(Word16 scf, Word16 scfLeft, Word16 scfRight) +{ + Word16 scfBits; + + scfBits = bitCountScalefactorDelta(scfLeft - scf) + + bitCountScalefactorDelta(scf - scfRight); + + return scfBits; +} + +/********************************************************************************* +* +* function name: calcSingleSpecPe +* description: ldRatio = log2(en(n)) - 0,375*scfGain(n) +* nbits = 0.7*nLines*ldRation for ldRation >= c1 +* nbits = 0.7*nLines*(c2 + c3*ldRatio) for ldRation < c1 +* +**********************************************************************************/ +static Word16 calcSingleSpecPe(Word16 scf, Word16 sfbConstPePart, Word16 nLines) +{ + Word32 specPe; + Word32 ldRatio; + Word32 scf3; + + ldRatio = sfbConstPePart << 3; /* (sfbConstPePart -0.375*scf)*8 */ + scf3 = scf + scf + scf; + ldRatio = ldRatio - scf3; + + if (ldRatio < PE_C1_8) { + /* 21 : 2*8*PE_C2, 2*PE_C3 ~ 1*/ + ldRatio = (ldRatio + PE_C2_16) >> 1; + } + specPe = nLines * ldRatio; + specPe = (specPe * PE_SCALE) >> 14; + + return saturate(specPe); +} + + +/********************************************************************************* +* +* function name: countScfBitsDiff +* description: count different scf bits used +* +**********************************************************************************/ +static Word16 countScfBitsDiff(Word16 *scfOld, Word16 *scfNew, + Word16 sfbCnt, Word16 startSfb, Word16 stopSfb) +{ + Word32 scfBitsDiff; + Word32 sfb, sfbLast; + Word32 sfbPrev, sfbNext; + + scfBitsDiff = 0; + sfb = 0; + + /* search for first relevant sfb */ + sfbLast = startSfb; + while (sfbLast < stopSfb && scfOld[sfbLast] == VOAAC_SHRT_MIN) { + + sfbLast = sfbLast + 1; + } + /* search for previous relevant sfb and count diff */ + sfbPrev = startSfb - 1; + while ((sfbPrev>=0) && scfOld[sfbPrev] == VOAAC_SHRT_MIN) { + + sfbPrev = sfbPrev - 1; + } + + if (sfbPrev>=0) { + scfBitsDiff += bitCountScalefactorDelta(scfNew[sfbPrev] - scfNew[sfbLast]) - + bitCountScalefactorDelta(scfOld[sfbPrev] - scfOld[sfbLast]); + } + /* now loop through all sfbs and count diffs of relevant sfbs */ + for (sfb=sfbLast+1; sfb> 2; + } + + + ldRatioOld = sfbConstPePart[sfb] << 3; + scf3 = scfOld[sfb] + scfOld[sfb] + scfOld[sfb]; + ldRatioOld = ldRatioOld - scf3; + ldRatioNew = sfbConstPePart[sfb] << 3; + scf3 = scfNew[sfb] + scfNew[sfb] + scfNew[sfb]; + ldRatioNew = ldRatioNew - scf3; + + if (ldRatioOld < PE_C1_8) { + /* 21 : 2*8*PE_C2, 2*PE_C3 ~ 1*/ + ldRatioOld = (ldRatioOld + PE_C2_16) >> 1; + } + + if (ldRatioNew < PE_C1_8) { + /* 21 : 2*8*PE_C2, 2*PE_C3 ~ 1*/ + ldRatioNew = (ldRatioNew + PE_C2_16) >> 1; + } + + specPeDiff += sfbNRelevantLines[sfb] * (ldRatioNew - ldRatioOld); + } + } + + specPeDiff = (specPeDiff * PE_SCALE) >> 14; + + return saturate(specPeDiff); +} + + +/********************************************************************************* +* +* function name: assimilateSingleScf +* description: searched for single scalefactor bands, where the number of bits gained +* by using a smaller scfgain(n) is greater than the estimated increased +* bit demand +* +**********************************************************************************/ +static void assimilateSingleScf(PSY_OUT_CHANNEL *psyOutChan, + Word16 *scf, + Word16 *minScf, + Word32 *sfbDist, + Word16 *sfbConstPePart, + Word16 *logSfbEnergy, + Word16 *logSfbFormFactor, + Word16 *sfbNRelevantLines, + Word16 *minScfCalculated, + Flag restartOnSuccess) +{ + Word16 sfbLast, sfbAct, sfbNext, scfAct, scfMin; + Word16 *scfLast, *scfNext; + Word32 sfbPeOld, sfbPeNew; + Word32 sfbDistNew; + Word32 j; + Flag success; + Word16 deltaPe, deltaPeNew, deltaPeTmp; + Word16 *prevScfLast = psyOutChan->prevScfLast; + Word16 *prevScfNext = psyOutChan->prevScfNext; + Word16 *deltaPeLast = psyOutChan->deltaPeLast; + Flag updateMinScfCalculated; + + success = 0; + deltaPe = 0; + + for(j=0;jsfbCnt;j++){ + prevScfLast[j] = MAX_16; + prevScfNext[j] = MAX_16; + deltaPeLast[j] = MAX_16; + } + + sfbLast = -1; + sfbAct = -1; + sfbNext = -1; + scfLast = 0; + scfNext = 0; + scfMin = MAX_16; + do { + /* search for new relevant sfb */ + sfbNext = sfbNext + 1; + while (sfbNext < psyOutChan->sfbCnt && scf[sfbNext] == MIN_16) { + + sfbNext = sfbNext + 1; + } + + if ((sfbLast>=0) && (sfbAct>=0) && sfbNext < psyOutChan->sfbCnt) { + /* relevant scfs to the left and to the right */ + scfAct = scf[sfbAct]; + scfLast = scf + sfbLast; + scfNext = scf + sfbNext; + scfMin = min(*scfLast, *scfNext); + } + else { + + if (sfbLast == -1 && (sfbAct>=0) && sfbNext < psyOutChan->sfbCnt) { + /* first relevant scf */ + scfAct = scf[sfbAct]; + scfLast = &scfAct; + scfNext = scf + sfbNext; + scfMin = *scfNext; + } + else { + + if ((sfbLast>=0) && (sfbAct>=0) && sfbNext == psyOutChan->sfbCnt) { + /* last relevant scf */ + scfAct = scf[sfbAct]; + scfLast = scf + sfbLast; + scfNext = &scfAct; + scfMin = *scfLast; + } + } + } + + if (sfbAct>=0) + scfMin = max(scfMin, minScf[sfbAct]); + + if ((sfbAct >= 0) && + (sfbLast>=0 || sfbNext < psyOutChan->sfbCnt) && + scfAct > scfMin && + (*scfLast != prevScfLast[sfbAct] || + *scfNext != prevScfNext[sfbAct] || + deltaPe < deltaPeLast[sfbAct])) { + success = 0; + + /* estimate required bits for actual scf */ + if (sfbConstPePart[sfbAct] == MIN_16) { + sfbConstPePart[sfbAct] = logSfbEnergy[sfbAct] - + logSfbFormFactor[sfbAct] + 11-8*4; /* 4*log2(6.75) - 32 */ + + if (sfbConstPePart[sfbAct] < 0) + sfbConstPePart[sfbAct] = sfbConstPePart[sfbAct] + 3; + sfbConstPePart[sfbAct] = sfbConstPePart[sfbAct] >> 2; + } + + sfbPeOld = calcSingleSpecPe(scfAct, sfbConstPePart[sfbAct], sfbNRelevantLines[sfbAct]) + + countSingleScfBits(scfAct, *scfLast, *scfNext); + deltaPeNew = deltaPe; + updateMinScfCalculated = 1; + do { + scfAct = scfAct - 1; + /* check only if the same check was not done before */ + + if (scfAct < minScfCalculated[sfbAct]) { + sfbPeNew = calcSingleSpecPe(scfAct, sfbConstPePart[sfbAct], sfbNRelevantLines[sfbAct]) + + countSingleScfBits(scfAct, *scfLast, *scfNext); + /* use new scf if no increase in pe and + quantization error is smaller */ + deltaPeTmp = deltaPe + sfbPeNew - sfbPeOld; + + if (deltaPeTmp < 10) { + sfbDistNew = calcSfbDist(psyOutChan->mdctSpectrum+ + psyOutChan->sfbOffsets[sfbAct], + (psyOutChan->sfbOffsets[sfbAct+1] - psyOutChan->sfbOffsets[sfbAct]), + scfAct); + if (sfbDistNew < sfbDist[sfbAct]) { + /* success, replace scf by new one */ + scf[sfbAct] = scfAct; + sfbDist[sfbAct] = sfbDistNew; + deltaPeNew = deltaPeTmp; + success = 1; + } + /* mark as already checked */ + + if (updateMinScfCalculated) { + minScfCalculated[sfbAct] = scfAct; + } + } + else { + updateMinScfCalculated = 0; + } + } + + } while (scfAct > scfMin); + deltaPe = deltaPeNew; + /* save parameters to avoid multiple computations of the same sfb */ + prevScfLast[sfbAct] = *scfLast; + prevScfNext[sfbAct] = *scfNext; + deltaPeLast[sfbAct] = deltaPe; + } + + if (success && restartOnSuccess) { + /* start again at first sfb */ + sfbLast = -1; + sfbAct = -1; + sfbNext = -1; + scfLast = 0; + scfNext = 0; + scfMin = MAX_16; + success = 0; + } + else { + /* shift sfbs for next band */ + sfbLast = sfbAct; + sfbAct = sfbNext; + } + + } while (sfbNext < psyOutChan->sfbCnt); +} + + +/********************************************************************************* +* +* function name: assimilateMultipleScf +* description: scalefactor difference reduction +* +**********************************************************************************/ +static void assimilateMultipleScf(PSY_OUT_CHANNEL *psyOutChan, + Word16 *scf, + Word16 *minScf, + Word32 *sfbDist, + Word16 *sfbConstPePart, + Word16 *logSfbEnergy, + Word16 *logSfbFormFactor, + Word16 *sfbNRelevantLines) +{ + Word32 sfb, startSfb, stopSfb, scfMin, scfMax, scfAct; + Flag possibleRegionFound; + Word32 deltaScfBits; + Word32 deltaSpecPe; + Word32 deltaPe, deltaPeNew; + Word32 sfbCnt; + Word32 *sfbDistNew = psyOutChan->sfbDistNew; + Word16 *scfTmp = psyOutChan->prevScfLast; + + deltaPe = 0; + sfbCnt = psyOutChan->sfbCnt; + + /* calc min and max scalfactors */ + scfMin = MAX_16; + scfMax = MIN_16; + for (sfb=0; sfb scfAct)) { + sfb = sfb + 1; + } + stopSfb = sfb; + + possibleRegionFound = 0; + + if (startSfb < sfbCnt) { + possibleRegionFound = 1; + for (sfb=startSfb; sfbmdctSpectrum + + psyOutChan->sfbOffsets[sfb], + (psyOutChan->sfbOffsets[sfb+1] - psyOutChan->sfbOffsets[sfb]), + scfAct); + + + if (sfbDistNew[sfb] > psyOutChan->sfbThreshold[sfb]) { + distNewSum = distOldSum << 1; + break; + } + distNewSum = L_add(distNewSum, sfbDistNew[sfb]); + } + } + + if (distNewSum < distOldSum) { + deltaPe = deltaPeNew; + for (sfb=startSfb; sfb scfMin); + } +} + +/********************************************************************************* +* +* function name: EstimateScaleFactorsChannel +* description: estimate scale factors for one channel +* +**********************************************************************************/ +static void +EstimateScaleFactorsChannel(PSY_OUT_CHANNEL *psyOutChan, + Word16 *scf, + Word16 *globalGain, + Word16 *logSfbEnergy, + Word16 *logSfbFormFactor, + Word16 *sfbNRelevantLines) +{ + Word32 i, j; + Word32 thresh, energy; + Word32 energyPart, thresholdPart; + Word32 scfInt, minScf, maxScf, maxAllowedScf, lastSf; + Word32 maxSpec; + Word32 *sfbDist = psyOutChan->sfbDist; + Word16 *minSfMaxQuant = psyOutChan->minSfMaxQuant; + Word16 *minScfCalculated = psyOutChan->minScfCalculated; + + + for (i=0; isfbCnt; i++) { + Word32 sbfwith, sbfStart; + Word32 *mdctSpec; + thresh = psyOutChan->sfbThreshold[i]; + energy = psyOutChan->sfbEnergy[i]; + + sbfStart = psyOutChan->sfbOffsets[i]; + sbfwith = psyOutChan->sfbOffsets[i+1] - sbfStart; + mdctSpec = psyOutChan->mdctSpectrum+sbfStart; + + maxSpec = 0; + /* maximum of spectrum */ + for (j=sbfwith; j; j-- ) { + Word32 absSpec = L_abs(*mdctSpec); mdctSpec++; + maxSpec |= absSpec; + } + + /* scfs without energy or with thresh>energy are marked with MIN_16 */ + scf[i] = MIN_16; + minSfMaxQuant[i] = MIN_16; + + if ((maxSpec > 0) && (energy > thresh)) { + + energyPart = logSfbFormFactor[i]; + thresholdPart = iLog4(thresh); + /* -20 = 4*log2(6.75) - 32 */ + scfInt = ((thresholdPart - energyPart - 20) * SCALE_ESTIMATE_COEF) >> 15; + + minSfMaxQuant[i] = iLog4(maxSpec) - 68; /* 68 -16/3*log(MAX_QUANT+0.5-logCon)/log(2) + 1 */ + + + if (minSfMaxQuant[i] > scfInt) { + scfInt = minSfMaxQuant[i]; + } + + /* find better scalefactor with analysis by synthesis */ + scfInt = improveScf(psyOutChan->mdctSpectrum+sbfStart, + sbfwith, + thresh, scfInt, minSfMaxQuant[i], + &sfbDist[i], &minScfCalculated[i]); + + scf[i] = scfInt; + } + } + + + /* scalefactor differece reduction */ + { + Word16 sfbConstPePart[MAX_GROUPED_SFB]; + for(i=0;isfbCnt;i++) { + sfbConstPePart[i] = MIN_16; + } + + assimilateSingleScf(psyOutChan, scf, + minSfMaxQuant, sfbDist, sfbConstPePart, logSfbEnergy, + logSfbFormFactor, sfbNRelevantLines, minScfCalculated, 1); + + assimilateMultipleScf(psyOutChan, scf, + minSfMaxQuant, sfbDist, sfbConstPePart, logSfbEnergy, + logSfbFormFactor, sfbNRelevantLines); + } + + /* get max scalefac for global gain */ + maxScf = MIN_16; + minScf = MAX_16; + for (i=0; isfbCnt; i++) { + + if (maxScf < scf[i]) { + maxScf = scf[i]; + } + + if ((scf[i] != MIN_16) && (minScf > scf[i])) { + minScf = scf[i]; + } + } + /* limit scf delta */ + maxAllowedScf = minScf + MAX_SCF_DELTA; + for(i=0; isfbCnt; i++) { + + if ((scf[i] != MIN_16) && (maxAllowedScf < scf[i])) { + scf[i] = maxAllowedScf; + } + } + /* new maxScf if any scf has been limited */ + + if (maxAllowedScf < maxScf) { + maxScf = maxAllowedScf; + } + + /* calc loop scalefactors */ + + if (maxScf > MIN_16) { + *globalGain = maxScf; + lastSf = 0; + + for(i=0; isfbCnt; i++) { + + if (scf[i] == MIN_16) { + scf[i] = lastSf; + /* set band explicitely to zero */ + for (j=psyOutChan->sfbOffsets[i]; jsfbOffsets[i+1]; j++) { + psyOutChan->mdctSpectrum[j] = 0; + } + } + else { + scf[i] = maxScf - scf[i]; + lastSf = scf[i]; + } + } + } + else{ + *globalGain = 0; + /* set spectrum explicitely to zero */ + for(i=0; isfbCnt; i++) { + scf[i] = 0; + for (j=psyOutChan->sfbOffsets[i]; jsfbOffsets[i+1]; j++) { + psyOutChan->mdctSpectrum[j] = 0; + } + } + } +} + +/********************************************************************************* +* +* function name: CalcFormFactor +* description: estimate Form factors for all channel +* +**********************************************************************************/ +void +CalcFormFactor(Word16 logSfbFormFactor[MAX_CHANNELS][MAX_GROUPED_SFB], + Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB], + Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], + PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + const Word16 nChannels) +{ + Word16 j; + + for (j=0; j=0; i--) { + pbSpreadedEnergy[i] = max(pbSpreadedEnergy[i], + L_mpy_ls(pbSpreadedEnergy[i+1], maskLowFactor[i])); + } +} diff --git a/jni/src/stat_bits.c b/jni/src/stat_bits.c new file mode 100644 index 000000000..c2bd8bde6 --- /dev/null +++ b/jni/src/stat_bits.c @@ -0,0 +1,237 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: stat_bits.c + + Content: Static bit counter functions + +*******************************************************************************/ + +#include "stat_bits.h" +#include "bitenc.h" +#include "tns.h" + + +typedef enum { + SI_ID_BITS =(3), + SI_FILL_COUNT_BITS =(4), + SI_FILL_ESC_COUNT_BITS =(8), + SI_FILL_EXTENTION_BITS =(4), + SI_FILL_NIBBLE_BITS =(4), + SI_SCE_BITS =(4), + SI_CPE_BITS =(5), + SI_CPE_MS_MASK_BITS =(2) , + SI_ICS_INFO_BITS_LONG =(1+2+1+6+1), + SI_ICS_INFO_BITS_SHORT =(1+2+1+4+7), + SI_ICS_BITS =(8+1+1+1) +} SI_BITS; + + +/********************************************************************************* +* +* function name: countMsMaskBits +* description: count ms stereo bits demand +* +**********************************************************************************/ +static Word16 countMsMaskBits(Word16 sfbCnt, + Word16 sfbPerGroup, + Word16 maxSfbPerGroup, + struct TOOLSINFO *toolsInfo) +{ + Word16 msBits, sfbOff, sfb; + msBits = 0; + + + switch(toolsInfo->msDigest) { + case MS_NONE: + case MS_ALL: + break; + + case MS_SOME: + for(sfbOff=0; sfbOfftnsActive[i]!=0) { + tnsPresent = 1; + } + } + + if (tnsPresent) { + /* there is data to be written*/ + /*count += 1; */ + for (i=0; itnsActive[i]) { + count += 1; + + if (blockType == 2) { + count += 4; + count += 3; + } + else { + count += 6; + count += 5; + } + + if (tnsInfo->order[i]) { + count += 1; /*direction*/ + count += 1; /*coef_compression */ + + if (tnsInfo->coefRes[i] == 4) { + ptcoef = tnsInfo->coef + i*TNS_MAX_ORDER_SHORT; + coefBits = 3; + for(k=0; korder[i]; k++) { + + if ((ptcoef[k] > 3) || (ptcoef[k] < -4)) { + coefBits = 4; + break; + } + } + } + else { + coefBits = 2; + ptcoef = tnsInfo->coef + i*TNS_MAX_ORDER_SHORT; + for(k=0; korder[i]; k++) { + + if ((ptcoef[k] > 1) || (ptcoef[k] < -2)) { + coefBits = 3; + break; + } + } + } + for (k=0; korder[i]; k++ ) { + count += coefBits; + } + } + } + } + } + + return count; +} + +/********************************************************************************** +* +* function name: countTnsBits +* description: count tns bit demand +* +**********************************************************************************/ +static Word16 countTnsBits(TNS_INFO *tnsInfo,Word16 blockType) +{ + return(tnsCount(tnsInfo, blockType)); +} + +/********************************************************************************* +* +* function name: countStaticBitdemand +* description: count static bit demand include tns +* +**********************************************************************************/ +Word16 countStaticBitdemand(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], + PSY_OUT_ELEMENT *psyOutElement, + Word16 channels, + Word16 adtsUsed) +{ + Word32 statBits; + Word32 ch; + + statBits = 0; + + /* if adts used, add 56 bits */ + if(adtsUsed) statBits += 56; + + + switch (channels) { + case 1: + statBits += SI_ID_BITS+SI_SCE_BITS+SI_ICS_BITS; + statBits += countTnsBits(&(psyOutChannel[0].tnsInfo), + psyOutChannel[0].windowSequence); + + switch(psyOutChannel[0].windowSequence){ + case LONG_WINDOW: + case START_WINDOW: + case STOP_WINDOW: + statBits += SI_ICS_INFO_BITS_LONG; + break; + case SHORT_WINDOW: + statBits += SI_ICS_INFO_BITS_SHORT; + break; + } + break; + case 2: + statBits += SI_ID_BITS+SI_CPE_BITS+2*SI_ICS_BITS; + + statBits += SI_CPE_MS_MASK_BITS; + statBits += countMsMaskBits(psyOutChannel[0].sfbCnt, + psyOutChannel[0].sfbPerGroup, + psyOutChannel[0].maxSfbPerGroup, + &psyOutElement->toolsInfo); + + switch (psyOutChannel[0].windowSequence) { + case LONG_WINDOW: + case START_WINDOW: + case STOP_WINDOW: + statBits += SI_ICS_INFO_BITS_LONG; + break; + case SHORT_WINDOW: + statBits += SI_ICS_INFO_BITS_SHORT; + break; + } + for(ch=0; ch<2; ch++) + statBits += countTnsBits(&(psyOutChannel[ch].tnsInfo), + psyOutChannel[ch].windowSequence); + break; + } + + return statBits; +} + diff --git a/jni/src/tns.c b/jni/src/tns.c new file mode 100644 index 000000000..455a864cb --- /dev/null +++ b/jni/src/tns.c @@ -0,0 +1,932 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: tns.c + + Content: Definition TNS tools functions + +*******************************************************************************/ + +#include "basic_op.h" +#include "oper_32b.h" +#include "assert.h" +#include "aac_rom.h" +#include "psy_const.h" +#include "tns.h" +#include "tns_param.h" +#include "psy_configuration.h" +#include "tns_func.h" + +#define TNS_MODIFY_BEGIN 2600 /* Hz */ +#define RATIO_PATCH_LOWER_BORDER 380 /* Hz */ +#define TNS_GAIN_THRESH 141 /* 1.41*100 */ +#define NORM_COEF 0x028f5c28 + +static const Word32 TNS_PARCOR_THRESH = 0x0ccccccd; /* 0.1*(1 << 31) */ +/* Limit bands to > 2.0 kHz */ +static unsigned short tnsMinBandNumberLong[12] = +{ 11, 12, 15, 16, 17, 20, 25, 26, 24, 28, 30, 31 }; +static unsigned short tnsMinBandNumberShort[12] = +{ 2, 2, 2, 3, 3, 4, 6, 6, 8, 10, 10, 12 }; + +/**************************************/ +/* Main/Low Profile TNS Parameters */ +/**************************************/ +static unsigned short tnsMaxBandsLongMainLow[12] = +{ 31, 31, 34, 40, 42, 51, 46, 46, 42, 42, 42, 39 }; + +static unsigned short tnsMaxBandsShortMainLow[12] = +{ 9, 9, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14 }; + + +static void CalcWeightedSpectrum(const Word32 spectrum[], + Word16 weightedSpectrum[], + Word32* sfbEnergy, + const Word16* sfbOffset, Word16 lpcStartLine, + Word16 lpcStopLine, Word16 lpcStartBand,Word16 lpcStopBand, + Word32 *pWork32); + + + +void AutoCorrelation(const Word16 input[], Word32 corr[], + Word16 samples, Word16 corrCoeff); +static Word16 AutoToParcor(Word32 workBuffer[], Word32 reflCoeff[], Word16 numOfCoeff); + +static Word16 CalcTnsFilter(const Word16* signal, const Word32 window[], Word16 numOfLines, + Word16 tnsOrder, Word32 parcor[]); + + +static void Parcor2Index(const Word32 parcor[], Word16 index[], Word16 order, + Word16 bitsPerCoeff); + +static void Index2Parcor(const Word16 index[], Word32 parcor[], Word16 order, + Word16 bitsPerCoeff); + + + +static void AnalysisFilterLattice(const Word32 signal[], Word16 numOfLines, + const Word32 parCoeff[], Word16 order, + Word32 output[]); + + +/** +* +* function name: FreqToBandWithRounding +* description: Retrieve index of nearest band border +* returnt: index +* +*/ +static Word16 FreqToBandWithRounding(Word32 freq, /*!< frequency in Hertz */ + Word32 fs, /*!< Sampling frequency in Hertz */ + Word16 numOfBands, /*!< total number of bands */ + const Word16 *bandStartOffset) /*!< table of band borders */ +{ + Word32 lineNumber, band; + Word32 temp, shift; + + /* assert(freq >= 0); */ + shift = norm_l(fs); + lineNumber = (extract_l(fixmul((bandStartOffset[numOfBands] << 2),Div_32(freq << shift,fs << shift))) + 1) >> 1; + + /* freq > fs/2 */ + temp = lineNumber - bandStartOffset[numOfBands] ; + if (temp >= 0) + return numOfBands; + + /* find band the line number lies in */ + for (band=0; band 0) break; + } + + temp = (lineNumber - bandStartOffset[band]); + temp = (temp - (bandStartOffset[band + 1] - lineNumber)); + if ( temp > 0 ) + { + band = band + 1; + } + + return extract_l(band); +} + + +/** +* +* function name: InitTnsConfigurationLong +* description: Fill TNS_CONFIG structure with sensible content for long blocks +* returns: 0 if success +* +*/ +Word16 InitTnsConfigurationLong(Word32 bitRate, /*!< bitrate */ + Word32 sampleRate, /*!< Sampling frequency */ + Word16 channels, /*!< number of channels */ + TNS_CONFIG *tC, /*!< TNS Config struct (modified) */ + PSY_CONFIGURATION_LONG *pC, /*!< psy config struct */ + Word16 active) /*!< tns active flag */ +{ + + Word32 bitratePerChannel; + tC->maxOrder = TNS_MAX_ORDER; + tC->tnsStartFreq = 1275; + tC->coefRes = 4; + + /* to avoid integer division */ + if ( sub(channels,2) == 0 ) { + bitratePerChannel = bitRate >> 1; + } + else { + bitratePerChannel = bitRate; + } + + tC->tnsMaxSfb = tnsMaxBandsLongMainLow[pC->sampRateIdx]; + + tC->tnsActive = active; + + /* now calc band and line borders */ + tC->tnsStopBand = min(pC->sfbCnt, tC->tnsMaxSfb); + tC->tnsStopLine = pC->sfbOffset[tC->tnsStopBand]; + + tC->tnsStartBand = FreqToBandWithRounding(tC->tnsStartFreq, sampleRate, + pC->sfbCnt, (const Word16*)pC->sfbOffset); + + tC->tnsModifyBeginCb = FreqToBandWithRounding(TNS_MODIFY_BEGIN, + sampleRate, + pC->sfbCnt, + (const Word16*)pC->sfbOffset); + + tC->tnsRatioPatchLowestCb = FreqToBandWithRounding(RATIO_PATCH_LOWER_BORDER, + sampleRate, + pC->sfbCnt, + (const Word16*)pC->sfbOffset); + + + tC->tnsStartLine = pC->sfbOffset[tC->tnsStartBand]; + + tC->lpcStopBand = tnsMaxBandsLongMainLow[pC->sampRateIdx]; + tC->lpcStopBand = min(tC->lpcStopBand, pC->sfbActive); + + tC->lpcStopLine = pC->sfbOffset[tC->lpcStopBand]; + + tC->lpcStartBand = tnsMinBandNumberLong[pC->sampRateIdx]; + + tC->lpcStartLine = pC->sfbOffset[tC->lpcStartBand]; + + tC->threshold = TNS_GAIN_THRESH; + + + return(0); +} + +/** +* +* function name: InitTnsConfigurationShort +* description: Fill TNS_CONFIG structure with sensible content for short blocks +* returns: 0 if success +* +*/ +Word16 InitTnsConfigurationShort(Word32 bitRate, /*!< bitrate */ + Word32 sampleRate, /*!< Sampling frequency */ + Word16 channels, /*!< number of channels */ + TNS_CONFIG *tC, /*!< TNS Config struct (modified) */ + PSY_CONFIGURATION_SHORT *pC, /*!< psy config struct */ + Word16 active) /*!< tns active flag */ +{ + Word32 bitratePerChannel; + tC->maxOrder = TNS_MAX_ORDER_SHORT; + tC->tnsStartFreq = 2750; + tC->coefRes = 3; + + /* to avoid integer division */ + if ( sub(channels,2) == 0 ) { + bitratePerChannel = L_shr(bitRate,1); + } + else { + bitratePerChannel = bitRate; + } + + tC->tnsMaxSfb = tnsMaxBandsShortMainLow[pC->sampRateIdx]; + + tC->tnsActive = active; + + /* now calc band and line borders */ + tC->tnsStopBand = min(pC->sfbCnt, tC->tnsMaxSfb); + tC->tnsStopLine = pC->sfbOffset[tC->tnsStopBand]; + + tC->tnsStartBand=FreqToBandWithRounding(tC->tnsStartFreq, sampleRate, + pC->sfbCnt, (const Word16*)pC->sfbOffset); + + tC->tnsModifyBeginCb = FreqToBandWithRounding(TNS_MODIFY_BEGIN, + sampleRate, + pC->sfbCnt, + (const Word16*)pC->sfbOffset); + + tC->tnsRatioPatchLowestCb = FreqToBandWithRounding(RATIO_PATCH_LOWER_BORDER, + sampleRate, + pC->sfbCnt, + (const Word16*)pC->sfbOffset); + + + tC->tnsStartLine = pC->sfbOffset[tC->tnsStartBand]; + + tC->lpcStopBand = tnsMaxBandsShortMainLow[pC->sampRateIdx]; + + tC->lpcStopBand = min(tC->lpcStopBand, pC->sfbActive); + + tC->lpcStopLine = pC->sfbOffset[tC->lpcStopBand]; + + tC->lpcStartBand = tnsMinBandNumberShort[pC->sampRateIdx]; + + tC->lpcStartLine = pC->sfbOffset[tC->lpcStartBand]; + + tC->threshold = TNS_GAIN_THRESH; + + return(0); +} + +/** +* +* function name: TnsDetect +* description: Calculate TNS filter and decide on TNS usage +* returns: 0 if success +* +*/ +Word32 TnsDetect(TNS_DATA* tnsData, /*!< tns data structure (modified) */ + TNS_CONFIG tC, /*!< tns config structure */ + Word32* pScratchTns, /*!< pointer to scratch space */ + const Word16 sfbOffset[], /*!< scalefactor size and table */ + Word32* spectrum, /*!< spectral data */ + Word16 subBlockNumber, /*!< subblock num */ + Word16 blockType, /*!< blocktype (long or short) */ + Word32 * sfbEnergy) /*!< sfb-wise energy */ +{ + + Word32 predictionGain; + Word32 temp; + Word32* pWork32 = &pScratchTns[subBlockNumber >> 8]; + Word16* pWeightedSpectrum = (Word16 *)&pScratchTns[subBlockNumber >> 8]; + + + if (tC.tnsActive) { + CalcWeightedSpectrum(spectrum, + pWeightedSpectrum, + sfbEnergy, + sfbOffset, + tC.lpcStartLine, + tC.lpcStopLine, + tC.lpcStartBand, + tC.lpcStopBand, + pWork32); + + temp = blockType - SHORT_WINDOW; + if ( temp != 0 ) { + predictionGain = CalcTnsFilter( &pWeightedSpectrum[tC.lpcStartLine], + tC.acfWindow, + tC.lpcStopLine - tC.lpcStartLine, + tC.maxOrder, + tnsData->dataRaw.tnsLong.subBlockInfo.parcor); + + + temp = predictionGain - tC.threshold; + if ( temp > 0 ) { + tnsData->dataRaw.tnsLong.subBlockInfo.tnsActive = 1; + } + else { + tnsData->dataRaw.tnsLong.subBlockInfo.tnsActive = 0; + } + + tnsData->dataRaw.tnsLong.subBlockInfo.predictionGain = predictionGain; + } + else{ + + predictionGain = CalcTnsFilter( &pWeightedSpectrum[tC.lpcStartLine], + tC.acfWindow, + tC.lpcStopLine - tC.lpcStartLine, + tC.maxOrder, + tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].parcor); + + temp = predictionGain - tC.threshold; + if ( temp > 0 ) { + tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].tnsActive = 1; + } + else { + tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].tnsActive = 0; + } + + tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].predictionGain = predictionGain; + } + + } + else{ + + temp = blockType - SHORT_WINDOW; + if ( temp != 0 ) { + tnsData->dataRaw.tnsLong.subBlockInfo.tnsActive = 0; + tnsData->dataRaw.tnsLong.subBlockInfo.predictionGain = 0; + } + else { + tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].tnsActive = 0; + tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].predictionGain = 0; + } + } + + return(0); +} + + +/***************************************************************************** +* +* function name: TnsSync +* description: update tns parameter +* +*****************************************************************************/ +void TnsSync(TNS_DATA *tnsDataDest, + const TNS_DATA *tnsDataSrc, + const TNS_CONFIG tC, + const Word16 subBlockNumber, + const Word16 blockType) +{ + TNS_SUBBLOCK_INFO *sbInfoDest; + const TNS_SUBBLOCK_INFO *sbInfoSrc; + Word32 i, temp; + + temp = blockType - SHORT_WINDOW; + if ( temp != 0 ) { + sbInfoDest = &tnsDataDest->dataRaw.tnsLong.subBlockInfo; + sbInfoSrc = &tnsDataSrc->dataRaw.tnsLong.subBlockInfo; + } + else { + sbInfoDest = &tnsDataDest->dataRaw.tnsShort.subBlockInfo[subBlockNumber]; + sbInfoSrc = &tnsDataSrc->dataRaw.tnsShort.subBlockInfo[subBlockNumber]; + } + + if (100*abs_s(sbInfoDest->predictionGain - sbInfoSrc->predictionGain) < + (3 * sbInfoDest->predictionGain)) { + sbInfoDest->tnsActive = sbInfoSrc->tnsActive; + for ( i=0; i< tC.maxOrder; i++) { + sbInfoDest->parcor[i] = sbInfoSrc->parcor[i]; + } + } +} + +/***************************************************************************** +* +* function name: TnsEncode +* description: do TNS filtering +* returns: 0 if success +* +*****************************************************************************/ +Word16 TnsEncode(TNS_INFO* tnsInfo, /*!< tns info structure (modified) */ + TNS_DATA* tnsData, /*!< tns data structure (modified) */ + Word16 numOfSfb, /*!< number of scale factor bands */ + TNS_CONFIG tC, /*!< tns config structure */ + Word16 lowPassLine, /*!< lowpass line */ + Word32* spectrum, /*!< spectral data (modified) */ + Word16 subBlockNumber, /*!< subblock num */ + Word16 blockType) /*!< blocktype (long or short) */ +{ + Word32 i; + Word32 temp_s; + Word32 temp; + TNS_SUBBLOCK_INFO *psubBlockInfo; + + temp_s = blockType - SHORT_WINDOW; + if ( temp_s != 0) { + psubBlockInfo = &tnsData->dataRaw.tnsLong.subBlockInfo; + if (psubBlockInfo->tnsActive == 0) { + tnsInfo->tnsActive[subBlockNumber] = 0; + return(0); + } + else { + + Parcor2Index(psubBlockInfo->parcor, + tnsInfo->coef, + tC.maxOrder, + tC.coefRes); + + Index2Parcor(tnsInfo->coef, + psubBlockInfo->parcor, + tC.maxOrder, + tC.coefRes); + + for (i=tC.maxOrder - 1; i>=0; i--) { + temp = psubBlockInfo->parcor[i] - TNS_PARCOR_THRESH; + if ( temp > 0 ) + break; + temp = psubBlockInfo->parcor[i] + TNS_PARCOR_THRESH; + if ( temp < 0 ) + break; + } + tnsInfo->order[subBlockNumber] = i + 1; + + + tnsInfo->tnsActive[subBlockNumber] = 1; + for (i=subBlockNumber+1; itnsActive[i] = 0; + } + tnsInfo->coefRes[subBlockNumber] = tC.coefRes; + tnsInfo->length[subBlockNumber] = numOfSfb - tC.tnsStartBand; + + + AnalysisFilterLattice(&(spectrum[tC.tnsStartLine]), + (min(tC.tnsStopLine,lowPassLine) - tC.tnsStartLine), + psubBlockInfo->parcor, + tnsInfo->order[subBlockNumber], + &(spectrum[tC.tnsStartLine])); + + } + } /* if (blockType!=SHORT_WINDOW) */ + else /*short block*/ { + psubBlockInfo = &tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber]; + if (psubBlockInfo->tnsActive == 0) { + tnsInfo->tnsActive[subBlockNumber] = 0; + return(0); + } + else { + + Parcor2Index(psubBlockInfo->parcor, + &tnsInfo->coef[subBlockNumber*TNS_MAX_ORDER_SHORT], + tC.maxOrder, + tC.coefRes); + + Index2Parcor(&tnsInfo->coef[subBlockNumber*TNS_MAX_ORDER_SHORT], + psubBlockInfo->parcor, + tC.maxOrder, + tC.coefRes); + for (i=(tC.maxOrder - 1); i>=0; i--) { + temp = psubBlockInfo->parcor[i] - TNS_PARCOR_THRESH; + if ( temp > 0 ) + break; + + temp = psubBlockInfo->parcor[i] + TNS_PARCOR_THRESH; + if ( temp < 0 ) + break; + } + tnsInfo->order[subBlockNumber] = i + 1; + + tnsInfo->tnsActive[subBlockNumber] = 1; + tnsInfo->coefRes[subBlockNumber] = tC.coefRes; + tnsInfo->length[subBlockNumber] = numOfSfb - tC.tnsStartBand; + + + AnalysisFilterLattice(&(spectrum[tC.tnsStartLine]), (tC.tnsStopLine - tC.tnsStartLine), + psubBlockInfo->parcor, + tnsInfo->order[subBlockNumber], + &(spectrum[tC.tnsStartLine])); + + } + } + + return(0); +} + + +/***************************************************************************** +* +* function name: m_pow2_cordic +* description: Iterative power function +* +* Calculates pow(2.0,x-1.0*(scale+1)) with INT_BITS bit precision +* using modified cordic algorithm +* returns: the result of pow2 +* +*****************************************************************************/ +static Word32 m_pow2_cordic(Word32 x, Word16 scale) +{ + Word32 k; + + Word32 accu_y = 0x40000000; + accu_y = L_shr(accu_y,scale); + + for(k=1; k= 0) { + + x = L_sub(x, z); + accu_y = L_add(accu_y, (accu_y >> k)); + } + } + return(accu_y); +} + + +/***************************************************************************** +* +* function name: CalcWeightedSpectrum +* description: Calculate weighted spectrum for LPC calculation +* +*****************************************************************************/ +static void CalcWeightedSpectrum(const Word32 spectrum[], /*!< input spectrum */ + Word16 weightedSpectrum[], + Word32 *sfbEnergy, /*!< sfb energies */ + const Word16 *sfbOffset, + Word16 lpcStartLine, + Word16 lpcStopLine, + Word16 lpcStartBand, + Word16 lpcStopBand, + Word32 *pWork32) +{ + #define INT_BITS_SCAL 1<<(INT_BITS/2) + + Word32 i, sfb, shift; + Word32 maxShift; + Word32 tmp_s, tmp2_s; + Word32 tmp, tmp2; + Word32 maxWS; + Word32 tnsSfbMean[MAX_SFB]; /* length [lpcStopBand-lpcStartBand] should be sufficient here */ + + maxWS = 0; + + /* calc 1.0*2^-INT_BITS/2/sqrt(en) */ + for( sfb = lpcStartBand; sfb < lpcStopBand; sfb++) { + + tmp2 = sfbEnergy[sfb] - 2; + if( tmp2 > 0) { + tmp = rsqrt(sfbEnergy[sfb], INT_BITS); + if(tmp > INT_BITS_SCAL) + { + shift = norm_l(tmp); + tmp = Div_32( INT_BITS_SCAL << shift, tmp << shift ); + } + else + { + tmp = 0x7fffffff; + } + } + else { + tmp = 0x7fffffff; + } + tnsSfbMean[sfb] = tmp; + } + + /* spread normalized values from sfbs to lines */ + sfb = lpcStartBand; + tmp = tnsSfbMean[sfb]; + for ( i=lpcStartLine; i=lpcStartLine; i--){ + pWork32[i] = (pWork32[i] + pWork32[i + 1]) >> 1; + } + /* filter up */ + for (i=(lpcStartLine + 1); i> 1; + } + + /* weight and normalize */ + for (i=lpcStartLine; i= 0) + { + for (i=lpcStartLine; i> maxShift; + } + } + else + { + maxShift = -maxShift; + for (i=lpcStartLine; i> scf)); + } + corr[0] = accu; + + /* early termination if all corr coeffs are likely going to be zero */ + if(corr[0] == 0) return ; + + /* calc all other corrCoef: R[j] = sum { t[i] * t[i+j] } ; i = 0..(N-j-1), j=1..p */ + for(i=1; i> scf)); + } + corr[i] = accu; + } +} +#endif + +/***************************************************************************** +* +* function name: AutoToParcor +* description: conversion autocorrelation to reflection coefficients +* returns: prediction gain +* input: input values, no. of output values (=order), +* ptr. to workbuffer (required size: 2*order) +* output: reflection coefficients +* +*****************************************************************************/ +static Word16 AutoToParcor(Word32 workBuffer[], Word32 reflCoeff[], Word16 numOfCoeff) { + + Word32 i, j, shift; + Word32 *pWorkBuffer; /* temp pointer */ + Word32 predictionGain = 0; + Word32 num, denom; + Word32 temp, workBuffer0; + + + num = workBuffer[0]; + temp = workBuffer[numOfCoeff]; + + for(i=0; i 0) + index=i; + } + return extract_l(index - 4); +} + +static Word16 Search4(Word32 parcor) +{ + Word32 index = 0; + Word32 i; + Word32 temp; + + + for (i=0;i<16;i++) { + temp = L_sub(parcor, tnsCoeff4Borders[i]); + if (temp > 0) + index=i; + } + return extract_l(index - 8); +} + + + +/***************************************************************************** +* +* functionname: Parcor2Index +* description: quantization index for reflection coefficients +* +*****************************************************************************/ +static void Parcor2Index(const Word32 parcor[], /*!< parcor coefficients */ + Word16 index[], /*!< quantized coeff indices */ + Word16 order, /*!< filter order */ + Word16 bitsPerCoeff) { /*!< quantizer resolution */ + Word32 i; + Word32 temp; + + for(i=0; i> 1; + tmpSave = x; + + for (i=0; i<(order - 1); i++) { + + tmp = L_add(fixmul(coef_par[i], x), state_par[i]); + x = L_add(fixmul(coef_par[i], state_par[i]), x); + + state_par[i] = tmpSave; + tmpSave = tmp; + } + + /* last stage: only need half operations */ + accu = fixmul(state_par[order - 1], coef_par[(order - 1)]); + state_par[(order - 1)] = tmpSave; + + x = L_add(accu, x); + x = L_add(x, x); + + return x; +} + +/***************************************************************************** +* +* functionname: AnalysisFilterLattice +* description: filters spectral lines with TNS filter +* +*****************************************************************************/ +static void AnalysisFilterLattice(const Word32 signal[], /*!< input spectrum */ + Word16 numOfLines, /*!< no. of lines */ + const Word32 parCoeff[],/*!< PARC coefficients */ + Word16 order, /*!< filter order */ + Word32 output[]) /*!< filtered signal values */ +{ + + Word32 state_par[TNS_MAX_ORDER]; + Word32 j; + + for ( j=0; j> 2); + } + } +} diff --git a/jni/src/transform.c b/jni/src/transform.c new file mode 100644 index 000000000..a02336f3f --- /dev/null +++ b/jni/src/transform.c @@ -0,0 +1,678 @@ +/* + ** Copyright 2003-2010, VisualOn, Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +/******************************************************************************* + File: transform.c + + Content: MDCT Transform functionss + +*******************************************************************************/ + +#include "basic_op.h" +#include "psy_const.h" +#include "transform.h" +#include "aac_rom.h" + + +#define LS_TRANS ((FRAME_LEN_LONG-FRAME_LEN_SHORT)/2) /* 448 */ +#define SQRT1_2 0x5a82799a /* sqrt(1/2) in Q31 */ +#define swap2(p0,p1) \ + t = p0; t1 = *(&(p0)+1); \ + p0 = p1; *(&(p0)+1) = *(&(p1)+1); \ + p1 = t; *(&(p1)+1) = t1 + +/********************************************************************************* +* +* function name: Shuffle +* description: Shuffle points prepared function for fft +* +**********************************************************************************/ +static void Shuffle(int *buf, int num, const unsigned char* bitTab) +{ + int *part0, *part1; + int i, j; + int t, t1; + + part0 = buf; + part1 = buf + num; + + while ((i = *bitTab++) != 0) { + j = *bitTab++; + + swap2(part0[4*i+0], part0[4*j+0]); + swap2(part0[4*i+2], part1[4*j+0]); + swap2(part1[4*i+0], part0[4*j+2]); + swap2(part1[4*i+2], part1[4*j+2]); + } + + do { + swap2(part0[4*i+2], part1[4*i+0]); + } while ((i = *bitTab++) != 0); +} + +#if !defined(ARMV5E) && !defined(ARMV7Neon) + +/***************************************************************************** +* +* function name: Radix4First +* description: Radix 4 point prepared function for fft +* +**********************************************************************************/ +static void Radix4First(int *buf, int num) +{ + int r0, r1, r2, r3; + int r4, r5, r6, r7; + + for (; num != 0; num--) + { + r0 = buf[0] + buf[2]; + r1 = buf[1] + buf[3]; + r2 = buf[0] - buf[2]; + r3 = buf[1] - buf[3]; + r4 = buf[4] + buf[6]; + r5 = buf[5] + buf[7]; + r6 = buf[4] - buf[6]; + r7 = buf[5] - buf[7]; + + buf[0] = r0 + r4; + buf[1] = r1 + r5; + buf[4] = r0 - r4; + buf[5] = r1 - r5; + buf[2] = r2 + r7; + buf[3] = r3 - r6; + buf[6] = r2 - r7; + buf[7] = r3 + r6; + + buf += 8; + } +} + +/***************************************************************************** +* +* function name: Radix8First +* description: Radix 8 point prepared function for fft +* +**********************************************************************************/ +static void Radix8First(int *buf, int num) +{ + int r0, r1, r2, r3; + int i0, i1, i2, i3; + int r4, r5, r6, r7; + int i4, i5, i6, i7; + int t0, t1, t2, t3; + + for ( ; num != 0; num--) + { + r0 = buf[0] + buf[2]; + i0 = buf[1] + buf[3]; + r1 = buf[0] - buf[2]; + i1 = buf[1] - buf[3]; + r2 = buf[4] + buf[6]; + i2 = buf[5] + buf[7]; + r3 = buf[4] - buf[6]; + i3 = buf[5] - buf[7]; + + r4 = (r0 + r2) >> 1; + i4 = (i0 + i2) >> 1; + r5 = (r0 - r2) >> 1; + i5 = (i0 - i2) >> 1; + r6 = (r1 - i3) >> 1; + i6 = (i1 + r3) >> 1; + r7 = (r1 + i3) >> 1; + i7 = (i1 - r3) >> 1; + + r0 = buf[ 8] + buf[10]; + i0 = buf[ 9] + buf[11]; + r1 = buf[ 8] - buf[10]; + i1 = buf[ 9] - buf[11]; + r2 = buf[12] + buf[14]; + i2 = buf[13] + buf[15]; + r3 = buf[12] - buf[14]; + i3 = buf[13] - buf[15]; + + t0 = (r0 + r2) >> 1; + t1 = (i0 + i2) >> 1; + t2 = (r0 - r2) >> 1; + t3 = (i0 - i2) >> 1; + + buf[ 0] = r4 + t0; + buf[ 1] = i4 + t1; + buf[ 8] = r4 - t0; + buf[ 9] = i4 - t1; + buf[ 4] = r5 + t3; + buf[ 5] = i5 - t2; + buf[12] = r5 - t3; + buf[13] = i5 + t2; + + r0 = r1 - i3; + i0 = i1 + r3; + r2 = r1 + i3; + i2 = i1 - r3; + + t0 = MULHIGH(SQRT1_2, r0 - i0); + t1 = MULHIGH(SQRT1_2, r0 + i0); + t2 = MULHIGH(SQRT1_2, r2 - i2); + t3 = MULHIGH(SQRT1_2, r2 + i2); + + buf[ 6] = r6 - t0; + buf[ 7] = i6 - t1; + buf[14] = r6 + t0; + buf[15] = i6 + t1; + buf[ 2] = r7 + t3; + buf[ 3] = i7 - t2; + buf[10] = r7 - t3; + buf[11] = i7 + t2; + + buf += 16; + } +} + +/***************************************************************************** +* +* function name: Radix4FFT +* description: Radix 4 point fft core function +* +**********************************************************************************/ +static void Radix4FFT(int *buf, int num, int bgn, int *twidTab) +{ + int r0, r1, r2, r3; + int r4, r5, r6, r7; + int t0, t1; + int sinx, cosx; + int i, j, step; + int *xptr, *csptr; + + for (num >>= 2; num != 0; num >>= 2) + { + step = 2*bgn; + xptr = buf; + + for (i = num; i != 0; i--) + { + csptr = twidTab; + + for (j = bgn; j != 0; j--) + { + r0 = xptr[0]; + r1 = xptr[1]; + xptr += step; + + t0 = xptr[0]; + t1 = xptr[1]; + cosx = csptr[0]; + sinx = csptr[1]; + r2 = MULHIGH(cosx, t0) + MULHIGH(sinx, t1); /* cos*br + sin*bi */ + r3 = MULHIGH(cosx, t1) - MULHIGH(sinx, t0); /* cos*bi - sin*br */ + xptr += step; + + t0 = r0 >> 2; + t1 = r1 >> 2; + r0 = t0 - r2; + r1 = t1 - r3; + r2 = t0 + r2; + r3 = t1 + r3; + + t0 = xptr[0]; + t1 = xptr[1]; + cosx = csptr[2]; + sinx = csptr[3]; + r4 = MULHIGH(cosx, t0) + MULHIGH(sinx, t1); /* cos*cr + sin*ci */ + r5 = MULHIGH(cosx, t1) - MULHIGH(sinx, t0); /* cos*ci - sin*cr */ + xptr += step; + + t0 = xptr[0]; + t1 = xptr[1]; + cosx = csptr[4]; + sinx = csptr[5]; + r6 = MULHIGH(cosx, t0) + MULHIGH(sinx, t1); /* cos*cr + sin*ci */ + r7 = MULHIGH(cosx, t1) - MULHIGH(sinx, t0); /* cos*ci - sin*cr */ + csptr += 6; + + t0 = r4; + t1 = r5; + r4 = t0 + r6; + r5 = r7 - t1; + r6 = t0 - r6; + r7 = r7 + t1; + + xptr[0] = r0 + r5; + xptr[1] = r1 + r6; + xptr -= step; + + xptr[0] = r2 - r4; + xptr[1] = r3 - r7; + xptr -= step; + + xptr[0] = r0 - r5; + xptr[1] = r1 - r6; + xptr -= step; + + xptr[0] = r2 + r4; + xptr[1] = r3 + r7; + xptr += 2; + } + xptr += 3*step; + } + twidTab += 3*step; + bgn <<= 2; + } +} + +/********************************************************************************* +* +* function name: PreMDCT +* description: prepare MDCT process for next FFT compute +* +**********************************************************************************/ +static void PreMDCT(int *buf0, int num, const int *csptr) +{ + int i; + int tr1, ti1, tr2, ti2; + int cosa, sina, cosb, sinb; + int *buf1; + + buf1 = buf0 + num - 1; + + for(i = num >> 2; i != 0; i--) + { + cosa = *csptr++; + sina = *csptr++; + cosb = *csptr++; + sinb = *csptr++; + + tr1 = *(buf0 + 0); + ti2 = *(buf0 + 1); + tr2 = *(buf1 - 1); + ti1 = *(buf1 + 0); + + *buf0++ = MULHIGH(cosa, tr1) + MULHIGH(sina, ti1); + *buf0++ = MULHIGH(cosa, ti1) - MULHIGH(sina, tr1); + + *buf1-- = MULHIGH(cosb, ti2) - MULHIGH(sinb, tr2); + *buf1-- = MULHIGH(cosb, tr2) + MULHIGH(sinb, ti2); + } +} + +/********************************************************************************* +* +* function name: PostMDCT +* description: post MDCT process after next FFT for MDCT +* +**********************************************************************************/ +static void PostMDCT(int *buf0, int num, const int *csptr) +{ + int i; + int tr1, ti1, tr2, ti2; + int cosa, sina, cosb, sinb; + int *buf1; + + buf1 = buf0 + num - 1; + + for(i = num >> 2; i != 0; i--) + { + cosa = *csptr++; + sina = *csptr++; + cosb = *csptr++; + sinb = *csptr++; + + tr1 = *(buf0 + 0); + ti1 = *(buf0 + 1); + ti2 = *(buf1 + 0); + tr2 = *(buf1 - 1); + + *buf0++ = MULHIGH(cosa, tr1) + MULHIGH(sina, ti1); + *buf1-- = MULHIGH(sina, tr1) - MULHIGH(cosa, ti1); + + *buf0++ = MULHIGH(sinb, tr2) - MULHIGH(cosb, ti2); + *buf1-- = MULHIGH(cosb, tr2) + MULHIGH(sinb, ti2); + } +} +#else +void Radix4First(int *buf, int num); +void Radix8First(int *buf, int num); +void Radix4FFT(int *buf, int num, int bgn, int *twidTab); +void PreMDCT(int *buf0, int num, const int *csptr); +void PostMDCT(int *buf0, int num, const int *csptr); +#endif + + +/********************************************************************************** +* +* function name: Mdct_Long +* description: the long block mdct, include long_start block, end_long block +* +**********************************************************************************/ +void Mdct_Long(int *buf) +{ + PreMDCT(buf, 1024, cossintab + 128); + + Shuffle(buf, 512, bitrevTab + 17); + Radix8First(buf, 512 >> 3); + Radix4FFT(buf, 512 >> 3, 8, (int *)twidTab512); + + PostMDCT(buf, 1024, cossintab + 128); +} + + +/********************************************************************************** +* +* function name: Mdct_Short +* description: the short block mdct +* +**********************************************************************************/ +void Mdct_Short(int *buf) +{ + PreMDCT(buf, 128, cossintab); + + Shuffle(buf, 64, bitrevTab); + Radix4First(buf, 64 >> 2); + Radix4FFT(buf, 64 >> 2, 4, (int *)twidTab64); + + PostMDCT(buf, 128, cossintab); +} + + +/***************************************************************************** +* +* function name: shiftMdctDelayBuffer +* description: the mdct delay buffer has a size of 1600, +* so the calculation of LONG,STOP must be spilt in two +* passes with 1024 samples and a mid shift, +* the SHORT transforms can be completed in the delay buffer, +* and afterwards a shift +* +**********************************************************************************/ +static void shiftMdctDelayBuffer(Word16 *mdctDelayBuffer, /*! start of mdct delay buffer */ + Word16 *timeSignal, /*! pointer to new time signal samples, interleaved */ + Word16 chIncrement /*! number of channels */ + ) +{ + Word32 i; + Word16 *srBuf = mdctDelayBuffer; + Word16 *dsBuf = mdctDelayBuffer+FRAME_LEN_LONG; + + for(i = 0; i < BLOCK_SWITCHING_OFFSET-FRAME_LEN_LONG; i+= 8) + { + *srBuf++ = *dsBuf++; *srBuf++ = *dsBuf++; + *srBuf++ = *dsBuf++; *srBuf++ = *dsBuf++; + *srBuf++ = *dsBuf++; *srBuf++ = *dsBuf++; + *srBuf++ = *dsBuf++; *srBuf++ = *dsBuf++; + } + + srBuf = mdctDelayBuffer + BLOCK_SWITCHING_OFFSET-FRAME_LEN_LONG; + dsBuf = timeSignal; + + for(i=0; i> 16); + timeSignalSample = (*dctIn1--) << minSf; + ws2 = timeSignalSample * (*winPtr & 0xffff); + winPtr ++; + /* shift 2 to avoid overflow next */ + *outData0++ = (ws1 >> 2) - (ws2 >> 2); + } + + shiftMdctDelayBuffer(mdctDelayBuffer,timeSignal,chIncrement); + + /* add windows and pre add for mdct to new buffer*/ + dctIn0 = mdctDelayBuffer; + dctIn1 = mdctDelayBuffer + FRAME_LEN_LONG - 1; + outData0 = realOut + FRAME_LEN_LONG/2 - 1; + winPtr = (int *)LongWindowKBD; + for(i=0;i> 16); + winPtr++; + /* shift 2 to avoid overflow next */ + *outData0-- = -((ws1 >> 2) + (ws2 >> 2)); + } + + Mdct_Long(realOut); + /* update scale factor */ + minSf = 14 - minSf; + *mdctScale=minSf; + break; + + case START_WINDOW: + /* + we access BLOCK_SWITCHING_OFFSET (1600 ) delay buffer samples + no timeSignal samples + and get the biggest scale factor for next calculate more precise + */ + minSf = getScalefactorOfShortVectorStride(mdctDelayBuffer,BLOCK_SWITCHING_OFFSET,1); + minSf = min(minSf,14); + + dctIn0 = mdctDelayBuffer; + dctIn1 = mdctDelayBuffer + FRAME_LEN_LONG - 1; + outData0 = realOut + FRAME_LEN_LONG/2; + winPtr = (int *)LongWindowKBD; + + /* add windows and pre add for mdct to last buffer*/ + for(i=0;i> 16); + timeSignalSample = (*dctIn1--) << minSf; + ws2 = timeSignalSample * (*winPtr & 0xffff); + winPtr ++; + *outData0++ = (ws1 >> 2) - (ws2 >> 2); /* shift 2 to avoid overflow next */ + } + + shiftMdctDelayBuffer(mdctDelayBuffer,timeSignal,chIncrement); + + outData0 = realOut + FRAME_LEN_LONG/2 - 1; + for(i=0;i> 16); + winPtr++; + *outData0-- = -((ws1 >> 2) + (ws2 >> 2)); /* shift 2 to avoid overflow next */ + } + + Mdct_Long(realOut); + /* update scale factor */ + minSf = 14 - minSf; + *mdctScale= minSf; + break; + + case STOP_WINDOW: + /* + we access BLOCK_SWITCHING_OFFSET-LS_TRANS (1600-448 ) delay buffer samples + 448 new timeSignal samples + and get the biggest scale factor for next calculate more precise + */ + delayBufferSf = getScalefactorOfShortVectorStride(mdctDelayBuffer+LS_TRANS,BLOCK_SWITCHING_OFFSET-LS_TRANS,1); + timeSignalSf = getScalefactorOfShortVectorStride(timeSignal,2*FRAME_LEN_LONG-BLOCK_SWITCHING_OFFSET,chIncrement); + minSf = min(delayBufferSf,timeSignalSf); + minSf = min(minSf,13); + + outData0 = realOut + FRAME_LEN_LONG/2; + dctIn1 = mdctDelayBuffer + FRAME_LEN_LONG - 1; + for(i=0;i> 16); + timeSignalSample= (*dctIn1--) << minSf; + ws2 = timeSignalSample * (*winPtr & 0xffff); + winPtr++; + *outData0++ = (ws1 >> 2) - (ws2 >> 2); /* shift 2 to avoid overflow next */ + } + + shiftMdctDelayBuffer(mdctDelayBuffer,timeSignal,chIncrement); + + /* add windows and pre add for mdct to new buffer*/ + dctIn0 = mdctDelayBuffer; + dctIn1 = mdctDelayBuffer + FRAME_LEN_LONG - 1; + outData0 = realOut + FRAME_LEN_LONG/2 - 1; + winPtr = (int *)LongWindowKBD; + for(i=0;i> 16); + *outData0-- = -((ws1 >> 2) + (ws2 >> 2)); /* shift 2 to avoid overflow next */ + winPtr++; + } + + Mdct_Long(realOut); + minSf = 14 - minSf; + *mdctScale= minSf; /* update scale factor */ + break; + + case SHORT_WINDOW: + /* + we access BLOCK_SWITCHING_OFFSET (1600 ) delay buffer samples + no new timeSignal samples + and get the biggest scale factor for next calculate more precise + */ + minSf = getScalefactorOfShortVectorStride(mdctDelayBuffer+TRANSFORM_OFFSET_SHORT,9*FRAME_LEN_SHORT,1); + minSf = min(minSf,10); + + + for(w=0;w> 16); + timeSignalSample= *dctIn1 << minSf; + ws2 = timeSignalSample * (*winPtr & 0xffff); + *outData0++ = (ws1 >> 2) - (ws2 >> 2); /* shift 2 to avoid overflow next */ + + timeSignalSample= *(dctIn0 + FRAME_LEN_SHORT) << minSf; + ws1 = timeSignalSample * (*winPtr & 0xffff); + timeSignalSample= *(dctIn1 + FRAME_LEN_SHORT) << minSf; + ws2 = timeSignalSample * (*winPtr >> 16); + *outData1-- = -((ws1 >> 2) + (ws2 >> 2)); /* shift 2 to avoid overflow next */ + + winPtr++; + dctIn0++; + dctIn1--; + } + + Mdct_Short(realOut); + realOut += FRAME_LEN_SHORT; + } + + minSf = 11 - minSf; + *mdctScale = minSf; /* update scale factor */ + + shiftMdctDelayBuffer(mdctDelayBuffer,timeSignal,chIncrement); + break; + } +} + diff --git a/libs/armeabi/libaac-encoder.so b/libs/armeabi/libaac-encoder.so new file mode 100755 index 0000000000000000000000000000000000000000..8d592f086a1fc99839550a0a6c7f5fb937e5aa57 GIT binary patch literal 109064 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 literal 0 HcmV?d00001 diff --git a/libs/xom-1.2.7.jar b/libs/xom-1.2.7.jar new file mode 100644 index 0000000000000000000000000000000000000000..e2d6afec484d24c3917d8f25bdce237b5d418d2b GIT binary patch literal 312996 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

_Cgh-x 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 z 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 JO@N)V{Rgy8KU4q! literal 0 HcmV?d00001 diff --git a/local.properties b/local.properties new file mode 100644 index 000000000..e78db3af3 --- /dev/null +++ b/local.properties @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked in Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=/home/timsu/src/android-sdk diff --git a/proguard.cfg b/proguard.cfg new file mode 100644 index 000000000..b1cdf17b5 --- /dev/null +++ b/proguard.cfg @@ -0,0 +1,40 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class com.android.vending.licensing.ILicensingService + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} diff --git a/project.properties b/project.properties new file mode 100644 index 000000000..ea89160e0 --- /dev/null +++ b/project.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-8 diff --git a/res/drawable-hdpi/ic_launcher.png b/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..8074c4c571b8cd19e27f4ee5545df367420686d7 GIT binary patch literal 4147 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 literal 0 HcmV?d00001 diff --git a/res/drawable-ldpi/ic_launcher.png b/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..1095584ec21f71cd0afc9e0993aa2209671b590c GIT binary patch literal 1723 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 + + +