From 71396a86a05d02191b47ba462ad1f373603951c7 Mon Sep 17 00:00:00 2001 From: Asmin Studios Date: Sat, 24 Oct 2026 15:40:51 +0200 Subject: [PATCH] asminvoicechat second commit --- .gitea/workflows/build-plugin.yml | 140 +- .gitignore | 4 + AsminVoiceChat-1.0.0.jar | Bin 932497 -> 940418 bytes LICENSE-upstream.txt | 1 + README.md | 6 +- build.gradle | 160 ++ gradle.properties | 2 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 48462 bytes gradle/wrapper/gradle-wrapper.properties | 9 + gradlew | 248 +++ gradlew.bat | 82 + settings.gradle | 8 + .../voicechat/api/BukkitVoicechatService.java | 12 + .../voicechat/api/ClientVoicechatSocket.java | 21 + .../de/maxhenkel/voicechat/api/Entity.java | 22 + .../voicechat/api/ForgeVoicechatPlugin.java | 6 +- .../de/maxhenkel/voicechat/api/Group.java | 115 ++ .../de/maxhenkel/voicechat/api/Player.java | 10 + .../de/maxhenkel/voicechat/api/Position.java | 20 + .../maxhenkel/voicechat/api/RawUdpPacket.java | 13 + .../maxhenkel/voicechat/api/ServerLevel.java | 10 + .../maxhenkel/voicechat/api/ServerPlayer.java | 10 + .../maxhenkel/voicechat/api/VoicechatApi.java | 116 ++ .../voicechat/api/VoicechatClientApi.java | 166 ++ .../voicechat/api/VoicechatConnection.java | 80 + .../voicechat/api/VoicechatPlugin.java | 26 + .../voicechat/api/VoicechatServerApi.java | 343 ++++ .../voicechat/api/VoicechatSocket.java | 23 + .../voicechat/api/VolumeCategory.java | 97 + .../voicechat/api/audio/AudioConverter.java | 27 + .../voicechat/api/audio/package-info.java | 4 + .../api/audiochannel/AudioChannel.java | 65 + .../api/audiochannel/AudioPlayer.java | 39 + .../api/audiochannel/ClientAudioChannel.java | 38 + .../ClientEntityAudioChannel.java | 32 + .../ClientLocationalAudioChannel.java | 29 + .../ClientStaticAudioChannel.java | 5 + .../api/audiochannel/EntityAudioChannel.java | 43 + .../audiochannel/LocationalAudioChannel.java | 29 + .../api/audiochannel/StaticAudioChannel.java | 38 + .../api/audiochannel/package-info.java | 4 + .../api/audiolistener/AudioListener.java | 11 +- .../audiolistener/PlayerAudioListener.java | 47 + .../api/audiolistener/package-info.java | 6 + .../api/audiosender/AudioSender.java | 52 + .../api/audiosender/package-info.java | 6 + .../voicechat/api/config/ConfigAccessor.java | 100 + .../api/config/VolumeConfigAccessor.java | 51 + .../voicechat/api/config/package-info.java | 4 + .../voicechat/api/events/ClientEvent.java | 12 + .../api/events/ClientReceiveSoundEvent.java | 73 + .../api/events/ClientSoundEvent.java | 29 + .../ClientVoicechatConnectionEvent.java | 13 + .../ClientVoicechatInitializationEvent.java | 22 + .../api/events/CreateGroupEvent.java | 21 + .../api/events/CreateOpenALContextEvent.java | 18 + .../api/events/DestroyOpenALContextEvent.java | 18 + .../api/events/EntitySoundPacketEvent.java | 10 + .../maxhenkel/voicechat/api/events/Event.java | 23 + .../api/events/EventRegistration.java | 28 + .../voicechat/api/events/GroupEvent.java | 22 + .../voicechat/api/events/JoinGroupEvent.java | 18 + .../voicechat/api/events/LeaveGroupEvent.java | 21 + .../events/LocationalSoundPacketEvent.java | 10 + .../api/events/MergeClientSoundEvent.java | 22 + .../api/events/MicrophoneMuteEvent.java | 13 + .../api/events/MicrophonePacketEvent.java | 10 + .../api/events/NameTagIconRenderEvent.java | 30 + .../api/events/OpenALSoundEvent.java | 59 + .../voicechat/api/events/PacketEvent.java | 27 + .../api/events/PlayerConnectedEvent.java | 12 + .../api/events/PlayerDisconnectedEvent.java | 12 + .../api/events/PlayerStateChangedEvent.java | 35 + .../events/RegisterVolumeCategoryEvent.java | 5 + .../api/events/RemoveGroupEvent.java | 25 + .../voicechat/api/events/ServerEvent.java | 12 + .../api/events/SoundPacketEvent.java | 23 + .../api/events/StaticSoundPacketEvent.java | 10 + .../events/UnregisterVolumeCategoryEvent.java | 5 + .../api/events/VoiceDistanceEvent.java | 39 + .../voicechat/api/events/VoiceHostEvent.java | 24 + .../api/events/VoicechatDisableEvent.java | 13 + .../events/VoicechatServerStartedEvent.java | 5 + .../events/VoicechatServerStartingEvent.java | 22 + .../events/VoicechatServerStoppedEvent.java | 5 + .../api/events/VolumeCategoryEvent.java | 12 + .../voicechat/api/events/package-info.java | 6 + .../voicechat/api/mp3/Mp3Decoder.java | 37 + .../voicechat/api/mp3/Mp3Encoder.java | 30 + .../voicechat/api/mp3/package-info.java | 4 + .../voicechat/api/opus/OpusDecoder.java | 45 + .../voicechat/api/opus/OpusEncoder.java | 34 + .../voicechat/api/opus/OpusEncoderMode.java | 8 + .../voicechat/api/opus/package-info.java | 4 + .../maxhenkel/voicechat/api/package-info.java | 4 + .../api/packets/ConvertablePacket.java | 64 + .../api/packets/EntitySoundPacket.java | 60 + .../api/packets/LocationalSoundPacket.java | 46 + .../api/packets/MicrophonePacket.java | 22 + .../voicechat/api/packets/Packet.java | 4 - .../voicechat/api/packets/SoundPacket.java | 100 + .../api/packets/StaticSoundPacket.java | 18 + .../voicechat/api/packets/package-info.java | 4 + .../de/maxhenkel/voicechat/BukkitVersion.java | 38 +- .../de/maxhenkel/voicechat/PaperVersion.java | 28 +- .../java}/de/maxhenkel/voicechat/Version.java | 42 +- .../de/maxhenkel/voicechat/Voicechat.java | 157 ++ .../voicechat/command/VoiceChatCommands.java | 213 +- .../compatibility/BaseCompatibility.java | 217 ++ .../BukkitCompatibilityManager.java | 216 +- .../compatibility/Compatibility.java | 76 + .../compatibility/Compatibility1_12.java | 82 + .../compatibility/Compatibility1_16.java | 84 + .../compatibility/Compatibility1_17.java | 77 + .../compatibility/Compatibility1_18.java | 78 + .../compatibility/Compatibility1_19.java | 91 + .../compatibility/Compatibility1_19_1.java | 71 + .../compatibility/Compatibility1_20.java | 69 + .../compatibility/Compatibility1_20_2.java | 60 + .../compatibility/Compatibility1_20_3.java | 97 + .../compatibility/Compatibility1_21_5.java | 31 +- .../compatibility/Compatibility1_8.java | 76 +- .../CompatibilityReflectionException.java | 9 +- .../compatibility/FallbackCompatibility.java | 40 +- .../JsonMessageBaseCompatibility.java | 23 + .../compatibility/PlayerHideEvent.java | 13 +- .../compatibility/PlayerShowEvent.java | 13 +- .../compatibility/ReflectionUtils.java | 150 +- .../compatibility/SpigotCompatibility.java | 72 + .../voicechat/config/ServerConfig.java | 129 ++ .../voicechat/config/Translations.java | 68 + .../voicechat/debug/CooldownTimer.java | 14 +- .../voicechat/debug/PingHandler.java | 24 +- .../VoicechatUncaughtExceptionHandler.java | 9 +- .../commodore/CommodoreCommands.java | 40 + .../GroupNameSuggestionProvider.java | 18 +- .../MissingArgumentTypeException.java | 9 +- .../placeholderapi/VoicechatExpansion.java | 36 +- .../viaversion/ViaVersionCompatibility.java | 32 +- .../voicechat/logging/JavaLoggingLogger.java | 78 +- .../maxhenkel/voicechat/logging/LogLevel.java | 7 +- .../voicechat/logging/VoicechatLogger.java | 33 + .../voicechat/net/AddCategoryPacket.java | 18 +- .../voicechat/net/AddGroupPacket.java | 18 +- .../voicechat/net/CreateGroupPacket.java | 43 +- .../voicechat/net/JoinGroupPacket.java | 37 +- .../voicechat/net/JoinedGroupPacket.java | 36 +- .../voicechat/net/LeaveGroupPacket.java | 20 +- .../maxhenkel/voicechat/net/NetManager.java | 132 ++ .../de/maxhenkel/voicechat/net/Packet.java | 19 + .../voicechat/net/PacketRateLimiter.java | 43 +- .../voicechat/net/PlayerStatePacket.java | 18 +- .../voicechat/net/PlayerStatesPacket.java | 29 +- .../voicechat/net/RemoveCategoryPacket.java | 18 +- .../voicechat/net/RemoveGroupPacket.java | 19 +- .../net/RemovePlayerStatePacket.java | 19 +- .../voicechat/net/RequestSecretPacket.java | 21 +- .../maxhenkel/voicechat/net/SecretPacket.java | 78 +- .../voicechat/net/UpdateStatePacket.java | 21 +- .../permission/PermissionManager.java | 14 + .../voicechat/plugins/CategoryManager.java | 23 +- .../voicechat/plugins/EventBuilder.java | 24 +- .../voicechat/plugins/PluginManager.java | 300 +++ .../impl/BukkitVoicechatServiceImpl.java | 19 +- .../voicechat/plugins/impl/EntityImpl.java | 32 +- .../voicechat/plugins/impl/GroupImpl.java | 133 +- .../voicechat/plugins/impl/PlayerImpl.java | 20 + .../voicechat/plugins/impl/PositionImpl.java | 32 +- .../plugins/impl/RawUdpPacketImpl.java | 16 +- .../plugins/impl/ServerLevelImpl.java | 26 +- .../plugins/impl/ServerPlayerImpl.java | 21 + .../plugins/impl/VoicechatApiImpl.java | 57 +- .../plugins/impl/VoicechatConnectionImpl.java | 58 +- .../plugins/impl/VoicechatServerApiImpl.java | 117 +- .../plugins/impl/VoicechatSocketBase.java | 17 +- .../plugins/impl/VoicechatSocketImpl.java | 84 +- .../plugins/impl/VolumeCategoryImpl.java | 104 +- .../impl/audio/AudioConverterImpl.java | 8 +- .../impl/audiochannel/AudioChannelImpl.java | 22 +- .../impl/audiochannel/AudioPlayerImpl.java | 76 +- .../impl/audiochannel/AudioSupplier.java | 28 + .../audiochannel/EntityAudioChannelImpl.java | 38 +- .../LocationalAudioChannelImpl.java | 37 +- .../audiochannel/StaticAudioChannelImpl.java | 102 + .../PlayerAudioListenerImpl.java | 41 +- .../impl/audiosender/AudioSenderImpl.java | 32 +- .../impl/config/ConfigAccessorImpl.java | 21 +- .../impl/events/CreateGroupEventImpl.java | 14 +- .../events/EntitySoundPacketEventImpl.java | 14 +- .../plugins/impl/events/EventImpl.java | 14 +- .../plugins/impl/events/GroupEventImpl.java | 20 +- .../impl/events/JoinGroupEventImpl.java | 10 +- .../impl/events/LeaveGroupEventImpl.java | 14 +- .../LocationalSoundPacketEventImpl.java | 14 +- .../events/MicrophonePacketEventImpl.java | 10 +- .../plugins/impl/events/PacketEventImpl.java | 24 +- .../impl/events/PlayerConnectedEventImpl.java | 12 +- .../events/PlayerDisconnectedEventImpl.java | 13 +- .../events/PlayerStateChangedEventImpl.java | 33 +- .../RegisterVolumeCategoryEventImpl.java | 11 +- .../impl/events/RemoveGroupEventImpl.java | 12 +- .../plugins/impl/events/ServerEventImpl.java | 11 +- .../impl/events/SoundPacketEventImpl.java | 17 +- .../events/StaticSoundPacketEventImpl.java | 14 +- .../UnregisterVolumeCategoryEventImpl.java | 11 +- .../impl/events/VoiceDistanceEventImpl.java | 22 +- .../impl/events/VoiceHostEventImpl.java | 18 +- .../VoicechatServerStartedEventImpl.java | 11 + .../VoicechatServerStartingEventImpl.java | 18 +- .../VoicechatServerStoppedEventImpl.java | 11 + .../impl/events/VolumeCategoryEventImpl.java | 12 +- .../impl/opus/JavaOpusDecoderImpl.java | 79 +- .../impl/opus/JavaOpusEncoderImpl.java | 49 +- .../plugins/impl/opus/OpusManager.java | 25 +- .../impl/packets/ConvertablePacketImpl.java | 185 +- .../impl/packets/EntitySoundPacketImpl.java | 52 +- .../packets/LocationalSoundPacketImpl.java | 58 +- .../impl/packets/MicrophonePacketImpl.java | 77 + .../plugins/impl/packets/SoundPacketImpl.java | 69 +- .../impl/packets/StaticSoundPacketImpl.java | 29 +- .../voicechat/util/FriendlyByteBuf.java | 647 +++--- .../de/maxhenkel/voicechat/util/Key.java | 18 +- .../voicechat/voice/common/AudioUtils.java | 30 +- .../voice/common/AuthenticateAckPacket.java | 14 +- .../voice/common/AuthenticatePacket.java | 20 +- .../voicechat/voice/common/ClientGroup.java | 45 +- .../common/ConnectionCheckAckPacket.java | 14 +- .../voice/common/ConnectionCheckPacket.java | 14 +- .../voice/common/GroupSoundPacket.java | 43 +- .../voice/common/KeepAlivePacket.java | 14 +- .../voice/common/LocationSoundPacket.java | 56 +- .../voicechat/voice/common/MicPacket.java | 24 +- .../voice/common/NetworkMessage.java | 113 +- .../voicechat/voice/common/Packet.java | 15 + .../voicechat/voice/common/PingPacket.java | 19 +- .../voice/common/PlayerSoundPacket.java | 59 +- .../voicechat/voice/common/PlayerState.java | 52 +- .../voicechat/voice/common/Secret.java | 45 +- .../voicechat/voice/common/SoundPacket.java | 35 +- .../voicechat/voice/common/Utils.java | 11 +- .../voice/server/ClientConnection.java | 16 +- .../voicechat/voice/server/Group.java | 42 +- .../voicechat/voice/server/PingManager.java | 63 +- .../voice/server/PlayerStateManager.java | 116 +- .../voicechat/voice/server/Server.java | 559 ++++++ .../voice/server/ServerCategoryManager.java | 24 +- .../voice/server/ServerGroupManager.java | 105 +- .../voice/server/ServerPlayerManager.java | 92 +- .../voice/server/ServerVoiceEvents.java | 98 +- .../maxhenkel/voicechat/BuildConstants.java | 17 +- .../assets/voicechat/lang/en_us.json | 230 +++ .../voicechat/FallbackTranslations.java | 246 --- .../de/maxhenkel/voicechat/Voicechat.java | 167 -- .../voicechat/api/BukkitVoicechatService.java | 11 - .../voicechat/api/ClientVoicechatSocket.java | 20 - .../de/maxhenkel/voicechat/api/Entity.java | 16 - .../de/maxhenkel/voicechat/api/Group.java | 47 - .../de/maxhenkel/voicechat/api/Player.java | 12 - .../de/maxhenkel/voicechat/api/Position.java | 13 - .../maxhenkel/voicechat/api/RawUdpPacket.java | 15 - .../maxhenkel/voicechat/api/ServerLevel.java | 9 - .../maxhenkel/voicechat/api/ServerPlayer.java | 13 - .../maxhenkel/voicechat/api/VoicechatApi.java | 52 - .../voicechat/api/VoicechatClientApi.java | 78 - .../voicechat/api/VoicechatConnection.java | 33 - .../voicechat/api/VoicechatPlugin.java | 18 - .../voicechat/api/VoicechatServerApi.java | 125 -- .../voicechat/api/VoicechatSocket.java | 22 - .../voicechat/api/VolumeCategory.java | 44 - .../voicechat/api/audio/AudioConverter.java | 19 - .../api/audiochannel/AudioChannel.java | 33 - .../api/audiochannel/AudioPlayer.java | 19 - .../api/audiochannel/ClientAudioChannel.java | 22 - .../ClientEntityAudioChannel.java | 21 - .../ClientLocationalAudioChannel.java | 19 - .../ClientStaticAudioChannel.java | 11 - .../api/audiochannel/EntityAudioChannel.java | 23 - .../audiochannel/LocationalAudioChannel.java | 19 - .../api/audiochannel/StaticAudioChannel.java | 21 - .../audiolistener/PlayerAudioListener.java | 26 - .../api/audiosender/AudioSender.java | 19 - .../voicechat/api/config/ConfigAccessor.java | 49 - .../api/config/VolumeConfigAccessor.java | 13 - .../voicechat/api/events/ClientEvent.java | 13 - .../api/events/ClientReceiveSoundEvent.java | 42 - .../api/events/ClientSoundEvent.java | 16 - .../ClientVoicechatConnectionEvent.java | 12 - .../ClientVoicechatInitializationEvent.java | 20 - .../api/events/CreateGroupEvent.java | 23 - .../api/events/CreateOpenALContextEvent.java | 14 - .../api/events/DestroyOpenALContextEvent.java | 14 - .../api/events/EntitySoundPacketEvent.java | 12 - .../maxhenkel/voicechat/api/events/Event.java | 13 - .../api/events/EventRegistration.java | 16 - .../voicechat/api/events/GroupEvent.java | 22 - .../voicechat/api/events/JoinGroupEvent.java | 18 - .../voicechat/api/events/LeaveGroupEvent.java | 23 - .../events/LocationalSoundPacketEvent.java | 12 - .../api/events/MergeClientSoundEvent.java | 12 - .../api/events/MicrophoneMuteEvent.java | 12 - .../api/events/MicrophonePacketEvent.java | 12 - .../api/events/NameTagIconRenderEvent.java | 13 - .../api/events/OpenALSoundEvent.java | 35 - .../voicechat/api/events/PacketEvent.java | 24 - .../api/events/PlayerConnectedEvent.java | 13 - .../api/events/PlayerDisconnectedEvent.java | 13 - .../api/events/PlayerStateChangedEvent.java | 25 - .../events/RegisterVolumeCategoryEvent.java | 11 - .../api/events/RemoveGroupEvent.java | 24 - .../voicechat/api/events/ServerEvent.java | 13 - .../api/events/SoundPacketEvent.java | 18 - .../api/events/StaticSoundPacketEvent.java | 12 - .../events/UnregisterVolumeCategoryEvent.java | 11 - .../api/events/VoiceDistanceEvent.java | 20 - .../voicechat/api/events/VoiceHostEvent.java | 17 - .../api/events/VoicechatDisableEvent.java | 12 - .../events/VoicechatServerStartedEvent.java | 11 - .../events/VoicechatServerStartingEvent.java | 20 - .../events/VoicechatServerStoppedEvent.java | 11 - .../api/events/VolumeCategoryEvent.java | 13 - .../voicechat/api/mp3/Mp3Decoder.java | 16 - .../voicechat/api/mp3/Mp3Encoder.java | 13 - .../voicechat/api/opus/OpusDecoder.java | 22 - .../voicechat/api/opus/OpusEncoder.java | 15 - .../voicechat/api/opus/OpusEncoderMode.java | 12 - .../api/packets/ConvertablePacket.java | 28 - .../api/packets/EntitySoundPacket.java | 26 - .../api/packets/LocationalSoundPacket.java | 22 - .../api/packets/MicrophonePacket.java | 18 - .../voicechat/api/packets/SoundPacket.java | 42 - .../api/packets/StaticSoundPacket.java | 15 - .../commodore/AbstractCommodore.java | 120 -- .../BrigadierUnsupportedException.java | 12 - .../voicechat/commodore/Commodore.java | 48 - .../commodore/CommodoreProvider.java | 68 - .../voicechat/commodore/PaperCommodore.java | 114 -- .../commodore/ReflectionCommodore.java | 186 -- .../voicechat/commodore/ReflectionUtil.java | 68 - .../commodore/file/AbstractIterator.java | 81 - .../commodore/file/ArgumentTypeParser.java | 18 - .../file/BrigadierArgumentTypeParser.java | 225 --- .../commodore/file/CommodoreFileReader.java | 88 - .../voicechat/commodore/file/Lexer.java | 78 - .../commodore/file/ParseException.java | 20 - .../voicechat/commodore/file/Parser.java | 85 - .../voicechat/commodore/file/Token.java | 30 - .../voicechat/commodore/file/TokenStream.java | 22 - .../compatibility/BaseCompatibility.java | 211 -- .../compatibility/Compatibility.java | 82 - .../compatibility/Compatibility1_12.java | 83 - .../compatibility/Compatibility1_16.java | 83 - .../compatibility/Compatibility1_17.java | 78 - .../compatibility/Compatibility1_18.java | 79 - .../compatibility/Compatibility1_19.java | 84 - .../compatibility/Compatibility1_19_1.java | 74 - .../compatibility/Compatibility1_20.java | 72 - .../compatibility/Compatibility1_20_2.java | 67 - .../compatibility/Compatibility1_20_3.java | 91 - .../JsonMessageBaseCompatibility.java | 30 - .../compatibility/SpigotCompatibility.java | 74 - .../voicechat/concentus/Analysis.java | 397 ---- .../voicechat/concentus/AnalysisInfo.java | 39 - .../voicechat/concentus/ApplySineWindow.java | 46 - .../maxhenkel/voicechat/concentus/Arrays.java | 86 - .../voicechat/concentus/Autocorrelation.java | 186 -- .../voicechat/concentus/BWExpander.java | 30 - .../maxhenkel/voicechat/concentus/Bands.java | 986 --------- .../voicechat/concentus/BoxedValueByte.java | 13 - .../voicechat/concentus/BoxedValueInt.java | 13 - .../voicechat/concentus/BoxedValueShort.java | 13 - .../voicechat/concentus/BurgModified.java | 209 -- .../de/maxhenkel/voicechat/concentus/CNG.java | 116 -- .../voicechat/concentus/CNGState.java | 28 - .../maxhenkel/voicechat/concentus/CWRS.java | 116 -- .../voicechat/concentus/CeltCommon.java | 843 -------- .../voicechat/concentus/CeltConstants.java | 36 - .../voicechat/concentus/CeltDecoder.java | 534 ----- .../voicechat/concentus/CeltEncoder.java | 888 --------- .../voicechat/concentus/CeltLPC.java | 99 - .../voicechat/concentus/CeltMode.java | 58 - .../voicechat/concentus/CeltPitchXCorr.java | 110 - .../voicechat/concentus/CeltTables.java | 80 - .../voicechat/concentus/ChannelLayout.java | 24 - .../voicechat/concentus/CodeSigns.java | 65 - .../voicechat/concentus/CodecHelpers.java | 370 ---- .../voicechat/concentus/CorrelateMatrix.java | 94 - .../voicechat/concentus/DecControlState.java | 26 - .../voicechat/concentus/DecodeAPI.java | 245 --- .../voicechat/concentus/DecodeCore.java | 145 -- .../voicechat/concentus/DecodeIndices.java | 68 - .../voicechat/concentus/DecodeParameters.java | 66 - .../voicechat/concentus/DecodePitch.java | 37 - .../voicechat/concentus/DecodePulses.java | 62 - .../voicechat/concentus/DecoderAPIFlag.java | 14 - .../voicechat/concentus/Downmix.java | 36 - .../voicechat/concentus/EncControlState.java | 105 - .../voicechat/concentus/EncodeAPI.java | 352 ---- .../voicechat/concentus/EncodeIndices.java | 104 - .../voicechat/concentus/EncodePulses.java | 132 -- .../voicechat/concentus/EntropyCoder.java | 451 ----- .../voicechat/concentus/FFTState.java | 18 - .../voicechat/concentus/Filters.java | 274 --- .../voicechat/concentus/FindLPC.java | 80 - .../voicechat/concentus/FindLTP.java | 153 -- .../voicechat/concentus/FindPitchLags.java | 72 - .../voicechat/concentus/FindPredCoefs.java | 83 - .../voicechat/concentus/GainQuantization.java | 61 - .../voicechat/concentus/HPVariableCutoff.java | 29 - .../voicechat/concentus/Inlines.java | 1263 ------------ .../de/maxhenkel/voicechat/concentus/K2A.java | 40 - .../voicechat/concentus/Kernels.java | 267 --- .../voicechat/concentus/KissFFT.java | 296 --- .../concentus/LPCInversePredGain.java | 74 - .../concentus/LTPAnalysisFilter.java | 41 - .../voicechat/concentus/LTPScaleControl.java | 25 - .../voicechat/concentus/Laplace.java | 85 - .../voicechat/concentus/LinearAlgebra.java | 106 - .../maxhenkel/voicechat/concentus/MDCT.java | 150 -- .../voicechat/concentus/MDCTLookup.java | 17 - .../voicechat/concentus/MLPState.java | 14 - .../concentus/MultiLayerPerceptron.java | 61 - .../maxhenkel/voicechat/concentus/NLSF.java | 625 ------ .../voicechat/concentus/NLSFCodebook.java | 36 - .../concentus/NoiseShapeAnalysis.java | 251 --- .../voicechat/concentus/OpusApplication.java | 13 - .../voicechat/concentus/OpusBandwidth.java | 16 - .../concentus/OpusBandwidthHelpers.java | 72 - .../voicechat/concentus/OpusConstants.java | 17 - .../voicechat/concentus/OpusDecoder.java | 499 ----- .../voicechat/concentus/OpusEncoder.java | 1062 ---------- .../voicechat/concentus/OpusError.java | 16 - .../voicechat/concentus/OpusException.java | 31 - .../voicechat/concentus/OpusFramesize.java | 18 - .../concentus/OpusFramesizeHelpers.java | 42 - .../voicechat/concentus/OpusMSDecoder.java | 235 --- .../voicechat/concentus/OpusMSEncoder.java | 735 ------- .../voicechat/concentus/OpusMode.java | 14 - .../voicechat/concentus/OpusMultistream.java | 60 - .../voicechat/concentus/OpusPacketInfo.java | 282 --- .../voicechat/concentus/OpusRepacketizer.java | 261 --- .../voicechat/concentus/OpusSignal.java | 13 - .../voicechat/concentus/OpusTables.java | 40 - .../de/maxhenkel/voicechat/concentus/PLC.java | 240 --- .../voicechat/concentus/PLCStruct.java | 42 - .../maxhenkel/voicechat/concentus/Pitch.java | 267 --- .../concentus/PitchAnalysisCore.java | 458 ----- .../voicechat/concentus/ProcessGains.java | 61 - .../voicechat/concentus/PulseCache.java | 22 - .../voicechat/concentus/QuantizeBands.java | 303 --- .../voicechat/concentus/QuantizeLTPGains.java | 64 - .../maxhenkel/voicechat/concentus/Rate.java | 308 --- .../concentus/RegularizeCorrelations.java | 20 - .../voicechat/concentus/Resampler.java | 375 ---- .../voicechat/concentus/ResidualEnergy.java | 87 - .../maxhenkel/voicechat/concentus/Schur.java | 96 - .../voicechat/concentus/ShellCoder.java | 91 - .../voicechat/concentus/SideInfoIndices.java | 52 - .../voicechat/concentus/Sigmoid.java | 31 - .../concentus/SilkChannelDecoder.java | 197 -- .../concentus/SilkChannelEncoder.java | 671 ------- .../voicechat/concentus/SilkConstants.java | 157 -- .../voicechat/concentus/SilkDecoder.java | 32 - .../concentus/SilkDecoderControl.java | 27 - .../voicechat/concentus/SilkEncoder.java | 52 - .../concentus/SilkEncoderControl.java | 61 - .../voicechat/concentus/SilkError.java | 27 - .../voicechat/concentus/SilkLPState.java | 42 - .../voicechat/concentus/SilkNSQState.java | 715 ------- .../concentus/SilkPrefilterState.java | 32 - .../concentus/SilkResamplerState.java | 58 - .../voicechat/concentus/SilkShapeState.java | 22 - .../voicechat/concentus/SilkTables.java | 211 -- .../voicechat/concentus/SilkVADState.java | 36 - .../maxhenkel/voicechat/concentus/Sort.java | 87 - .../maxhenkel/voicechat/concentus/Spread.java | 15 - .../maxhenkel/voicechat/concentus/Stereo.java | 283 --- .../concentus/StereoDecodeState.java | 22 - .../concentus/StereoEncodeState.java | 38 - .../voicechat/concentus/StereoWidthState.java | 24 - .../voicechat/concentus/SumSqrShift.java | 81 - .../voicechat/concentus/TOCStruct.java | 22 - .../concentus/TonalityAnalysisState.java | 92 - .../voicechat/concentus/TuningParameters.java | 56 - .../de/maxhenkel/voicechat/concentus/VQ.java | 230 --- .../voicechat/concentus/VQ_WMat_EC.java | 60 - .../concentus/VoiceActivityDetection.java | 152 -- .../voicechat/concentus/VorbisLayout.java | 18 - .../voicechat/config/ServerConfig.java | 59 - .../voicechat/config/Translations.java | 31 - .../configbuilder/CommentedProperties.java | 454 ----- .../CommentedPropertyConfig.java | 144 -- .../voicechat/configbuilder/Config.java | 11 - .../configbuilder/ConfigBuilder.java | 167 -- .../configbuilder/ConfigBuilderImpl.java | 211 -- .../configbuilder/MigratableConfig.java | 21 - .../configbuilder/MigratableConfigImpl.java | 58 - .../custom/AbstractValueList.java | 162 -- .../custom/AbstractValueMap.java | 120 -- .../configbuilder/custom/IntegerList.java | 27 - .../configbuilder/custom/StringList.java | 27 - .../configbuilder/custom/StringMap.java | 36 - .../IntegerListValueSerializer.java | 42 - .../serializer/StringListValueSerializer.java | 32 - .../serializer/StringMapValueSerializer.java | 55 - .../custom/serializer/UUIDSerializer.java | 23 - .../entry/AbstractConfigEntry.java | 134 -- .../entry/AbstractRangedConfigEntry.java | 49 - .../entry/BooleanConfigEntry.java | 17 - .../configbuilder/entry/ConfigEntry.java | 29 - .../entry/DoubleConfigEntry.java | 40 - .../configbuilder/entry/EnumConfigEntry.java | 17 - .../configbuilder/entry/FloatConfigEntry.java | 40 - .../entry/GenericConfigEntry.java | 17 - .../entry/IntegerConfigEntry.java | 40 - .../configbuilder/entry/LongConfigEntry.java | 40 - .../entry/RangedConfigEntry.java | 20 - .../entry/StringConfigEntry.java | 17 - .../entry/serializer/BooleanSerializer.java | 28 - .../entry/serializer/DoubleSerializer.java | 33 - .../entry/serializer/EnumSerializer.java | 37 - .../entry/serializer/FloatSerializer.java | 33 - .../entry/serializer/IntegerSerializer.java | 33 - .../entry/serializer/LongSerializer.java | 33 - .../entry/serializer/StringSerializer.java | 28 - .../entry/serializer/ValueSerializable.java | 17 - .../entry/serializer/ValueSerializer.java | 18 - .../commodore/CommodoreCommands.java | 44 - .../voicechat/logging/VoicechatLogger.java | 37 - .../maxhenkel/voicechat/net/NetManager.java | 162 -- .../de/maxhenkel/voicechat/net/Packet.java | 23 - .../de/maxhenkel/voicechat/org/json/CDL.java | 196 -- .../maxhenkel/voicechat/org/json/Cookie.java | 121 -- .../voicechat/org/json/CookieList.java | 45 - .../de/maxhenkel/voicechat/org/json/HTTP.java | 69 - .../voicechat/org/json/HTTPTokener.java | 39 - .../voicechat/org/json/JSONArray.java | 855 -------- .../voicechat/org/json/JSONException.java | 22 - .../maxhenkel/voicechat/org/json/JSONML.java | 332 --- .../org/json/JSONMLParserConfiguration.java | 35 - .../voicechat/org/json/JSONObject.java | 1771 ----------------- .../org/json/JSONParserConfiguration.java | 65 - .../voicechat/org/json/JSONPointer.java | 158 -- .../org/json/JSONPointerException.java | 20 - .../org/json/JSONPropertyIgnore.java | 17 - .../voicechat/org/json/JSONPropertyName.java | 18 - .../voicechat/org/json/JSONString.java | 9 - .../voicechat/org/json/JSONStringer.java | 19 - .../voicechat/org/json/JSONTokener.java | 401 ---- .../voicechat/org/json/JSONWriter.java | 204 -- .../org/json/ParserConfiguration.java | 46 - .../voicechat/org/json/Property.java | 36 - .../org/json/StringBuilderWriter.java | 81 - .../de/maxhenkel/voicechat/org/json/XML.java | 623 ------ .../org/json/XMLParserConfiguration.java | 175 -- .../voicechat/org/json/XMLTokener.java | 278 --- .../org/json/XMLXsiTypeConverter.java | 9 - .../permission/PermissionManager.java | 19 - .../voicechat/plugins/PluginManager.java | 308 --- .../voicechat/plugins/impl/PlayerImpl.java | 30 - .../plugins/impl/ServerPlayerImpl.java | 31 - .../impl/audiochannel/AudioSupplier.java | 31 - .../audiochannel/StaticAudioChannelImpl.java | 113 -- .../VoicechatServerStartedEventImpl.java | 17 - .../VoicechatServerStoppedEventImpl.java | 17 - .../impl/packets/MicrophonePacketImpl.java | 84 - .../voicechat/voice/common/Packet.java | 17 - .../voicechat/voice/common/Secret.java | 140 -- .../voicechat/voice/server/Server.java | 502 ----- .../voice/server/ServerVoiceEvents.java | 167 -- source/decompiled/summary.txt | 2 - source/resources/CONCENTUS_LICENSE | 37 - source/resources/META-INF/MANIFEST.MF | 6 - .../configbuilder/pom.properties | 3 - .../configbuilder/pom.xml | 81 - .../maven/me.lucko/commodore/pom.properties | 5 - .../META-INF/maven/me.lucko/commodore/pom.xml | 162 -- .../org.concentus/Concentus/pom.properties | 3 - .../maven/org.concentus/Concentus/pom.xml | 63 - .../maven/org.json/json/pom.properties | 3 - .../META-INF/maven/org.json/json/pom.xml | 263 --- source/resources/plugin.yml | 28 - 581 files changed, 9084 insertions(+), 38713 deletions(-) create mode 100644 .gitignore create mode 100644 LICENSE-upstream.txt create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/BukkitVoicechatService.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/ClientVoicechatSocket.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/Entity.java rename source/{decompiled => api/src/main/java}/de/maxhenkel/voicechat/api/ForgeVoicechatPlugin.java (67%) create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/Group.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/Player.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/Position.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/RawUdpPacket.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/ServerLevel.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/ServerPlayer.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatApi.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatClientApi.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatConnection.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatPlugin.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatServerApi.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatSocket.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/VolumeCategory.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audio/AudioConverter.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audio/package-info.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/AudioChannel.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/AudioPlayer.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientAudioChannel.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientEntityAudioChannel.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientLocationalAudioChannel.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientStaticAudioChannel.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/EntityAudioChannel.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/LocationalAudioChannel.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/StaticAudioChannel.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/package-info.java rename source/{decompiled => api/src/main/java}/de/maxhenkel/voicechat/api/audiolistener/AudioListener.java (57%) create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/PlayerAudioListener.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/package-info.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiosender/AudioSender.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/audiosender/package-info.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/config/ConfigAccessor.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/config/VolumeConfigAccessor.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/config/package-info.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientReceiveSoundEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientSoundEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientVoicechatConnectionEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientVoicechatInitializationEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/CreateGroupEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/CreateOpenALContextEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/DestroyOpenALContextEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/EntitySoundPacketEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/Event.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/EventRegistration.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/GroupEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/JoinGroupEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/LeaveGroupEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/LocationalSoundPacketEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/MergeClientSoundEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/MicrophoneMuteEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/MicrophonePacketEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/NameTagIconRenderEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/OpenALSoundEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/PacketEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerConnectedEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerDisconnectedEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerStateChangedEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/RegisterVolumeCategoryEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/RemoveGroupEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/ServerEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/SoundPacketEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/StaticSoundPacketEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/UnregisterVolumeCategoryEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoiceDistanceEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoiceHostEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatDisableEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStartedEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStartingEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStoppedEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/VolumeCategoryEvent.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/events/package-info.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/Mp3Decoder.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/Mp3Encoder.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/package-info.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusDecoder.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusEncoder.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusEncoderMode.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/opus/package-info.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/package-info.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/packets/ConvertablePacket.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/packets/EntitySoundPacket.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/packets/LocationalSoundPacket.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/packets/MicrophonePacket.java rename source/{decompiled => api/src/main/java}/de/maxhenkel/voicechat/api/packets/Packet.java (65%) create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/packets/SoundPacket.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/packets/StaticSoundPacket.java create mode 100644 source/api/src/main/java/de/maxhenkel/voicechat/api/packets/package-info.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/BukkitVersion.java (71%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/PaperVersion.java (77%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/Version.java (59%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/Voicechat.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/command/VoiceChatCommands.java (70%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/BaseCompatibility.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/compatibility/BukkitCompatibilityManager.java (78%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_12.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_16.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_17.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_18.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_19.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_19_1.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20_2.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20_3.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/compatibility/Compatibility1_21_5.java (88%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/compatibility/Compatibility1_8.java (64%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/compatibility/CompatibilityReflectionException.java (70%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/compatibility/FallbackCompatibility.java (64%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/JsonMessageBaseCompatibility.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/compatibility/PlayerHideEvent.java (70%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/compatibility/PlayerShowEvent.java (70%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/compatibility/ReflectionUtils.java (56%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/SpigotCompatibility.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/config/ServerConfig.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/config/Translations.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/debug/CooldownTimer.java (71%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/debug/PingHandler.java (80%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/debug/VoicechatUncaughtExceptionHandler.java (65%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/commodore/CommodoreCommands.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/integration/commodore/GroupNameSuggestionProvider.java (71%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/integration/commodore/MissingArgumentTypeException.java (59%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/integration/placeholderapi/VoicechatExpansion.java (71%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/integration/viaversion/ViaVersionCompatibility.java (56%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/logging/JavaLoggingLogger.java (52%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/logging/LogLevel.java (71%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/logging/VoicechatLogger.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/AddCategoryPacket.java (75%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/AddGroupPacket.java (75%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/CreateGroupPacket.java (64%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/JoinGroupPacket.java (67%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/JoinedGroupPacket.java (64%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/LeaveGroupPacket.java (76%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/net/NetManager.java create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/net/Packet.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/PacketRateLimiter.java (57%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/PlayerStatePacket.java (74%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/PlayerStatesPacket.java (66%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/RemoveCategoryPacket.java (73%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/RemoveGroupPacket.java (74%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/RemovePlayerStatePacket.java (74%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/RequestSecretPacket.java (71%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/SecretPacket.java (59%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/net/UpdateStatePacket.java (73%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/permission/PermissionManager.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/CategoryManager.java (56%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/EventBuilder.java (62%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/PluginManager.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/BukkitVoicechatServiceImpl.java (56%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/EntityImpl.java (54%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/GroupImpl.java (58%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/PlayerImpl.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/PositionImpl.java (57%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/RawUdpPacketImpl.java (78%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/ServerLevelImpl.java (53%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/ServerPlayerImpl.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/VoicechatApiImpl.java (62%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/VoicechatConnectionImpl.java (69%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/VoicechatServerApiImpl.java (72%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketBase.java (68%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketImpl.java (57%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/VolumeCategoryImpl.java (61%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/audio/AudioConverterImpl.java (90%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioChannelImpl.java (80%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioPlayerImpl.java (57%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioSupplier.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/audiochannel/EntityAudioChannelImpl.java (54%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/audiochannel/LocationalAudioChannelImpl.java (57%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/StaticAudioChannelImpl.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/audiolistener/PlayerAudioListenerImpl.java (66%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/audiosender/AudioSenderImpl.java (79%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/config/ConfigAccessorImpl.java (54%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/CreateGroupEventImpl.java (58%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/EntitySoundPacketEventImpl.java (62%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/EventImpl.java (68%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/GroupEventImpl.java (66%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/JoinGroupEventImpl.java (63%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/LeaveGroupEventImpl.java (58%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/LocationalSoundPacketEventImpl.java (62%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/MicrophonePacketEventImpl.java (63%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/PacketEventImpl.java (70%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/PlayerConnectedEventImpl.java (67%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/PlayerDisconnectedEventImpl.java (57%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/PlayerStateChangedEventImpl.java (63%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/RegisterVolumeCategoryEventImpl.java (54%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/RemoveGroupEventImpl.java (53%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/ServerEventImpl.java (67%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/SoundPacketEventImpl.java (65%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/StaticSoundPacketEventImpl.java (62%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/UnregisterVolumeCategoryEventImpl.java (54%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/VoiceDistanceEventImpl.java (73%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/VoiceHostEventImpl.java (68%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartedEventImpl.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartingEventImpl.java (63%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStoppedEventImpl.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/events/VolumeCategoryEventImpl.java (67%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusDecoderImpl.java (54%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusEncoderImpl.java (60%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/opus/OpusManager.java (69%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/packets/ConvertablePacketImpl.java (59%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/packets/EntitySoundPacketImpl.java (62%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/packets/LocationalSoundPacketImpl.java (59%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/MicrophonePacketImpl.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/packets/SoundPacketImpl.java (64%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/plugins/impl/packets/StaticSoundPacketImpl.java (60%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/util/FriendlyByteBuf.java (52%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/util/Key.java (76%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/AudioUtils.java (65%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/AuthenticateAckPacket.java (64%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/AuthenticatePacket.java (69%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/ClientGroup.java (66%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/ConnectionCheckAckPacket.java (64%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/ConnectionCheckPacket.java (64%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/GroupSoundPacket.java (57%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/KeepAlivePacket.java (65%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/LocationSoundPacket.java (59%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/MicPacket.java (70%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/NetworkMessage.java (64%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/Packet.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/PingPacket.java (72%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/PlayerSoundPacket.java (56%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/PlayerState.java (69%) rename source/{patch => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/Secret.java (84%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/SoundPacket.java (62%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/common/Utils.java (72%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/server/ClientConnection.java (81%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/server/Group.java (62%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/server/PingManager.java (53%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/server/PlayerStateManager.java (63%) create mode 100644 source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/Server.java rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/server/ServerCategoryManager.java (80%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/server/ServerGroupManager.java (66%) rename source/{decompiled => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/server/ServerPlayerManager.java (51%) rename source/{patch => bukkit/src/main/java}/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java (64%) rename source/{decompiled => bukkit/src/template/java}/de/maxhenkel/voicechat/BuildConstants.java (51%) create mode 100644 source/common/src/main/resources/assets/voicechat/lang/en_us.json delete mode 100644 source/decompiled/de/maxhenkel/voicechat/FallbackTranslations.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/Voicechat.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/BukkitVoicechatService.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/ClientVoicechatSocket.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/Entity.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/Group.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/Player.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/Position.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/RawUdpPacket.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/ServerLevel.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/ServerPlayer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/VoicechatApi.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/VoicechatClientApi.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/VoicechatConnection.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/VoicechatPlugin.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/VoicechatServerApi.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/VoicechatSocket.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/VolumeCategory.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audio/AudioConverter.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiochannel/AudioChannel.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiochannel/AudioPlayer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientAudioChannel.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientEntityAudioChannel.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientLocationalAudioChannel.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientStaticAudioChannel.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiochannel/EntityAudioChannel.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiochannel/LocationalAudioChannel.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiochannel/StaticAudioChannel.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiolistener/PlayerAudioListener.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/audiosender/AudioSender.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/config/ConfigAccessor.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/config/VolumeConfigAccessor.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/ClientEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/ClientReceiveSoundEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/ClientSoundEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/ClientVoicechatConnectionEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/ClientVoicechatInitializationEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/CreateGroupEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/CreateOpenALContextEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/DestroyOpenALContextEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/EntitySoundPacketEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/Event.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/EventRegistration.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/GroupEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/JoinGroupEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/LeaveGroupEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/LocationalSoundPacketEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/MergeClientSoundEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/MicrophoneMuteEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/MicrophonePacketEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/NameTagIconRenderEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/OpenALSoundEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/PacketEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/PlayerConnectedEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/PlayerDisconnectedEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/PlayerStateChangedEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/RegisterVolumeCategoryEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/RemoveGroupEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/ServerEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/SoundPacketEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/StaticSoundPacketEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/UnregisterVolumeCategoryEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/VoiceDistanceEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/VoiceHostEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatDisableEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStartedEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStartingEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStoppedEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/events/VolumeCategoryEvent.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/mp3/Mp3Decoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/mp3/Mp3Encoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/opus/OpusDecoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/opus/OpusEncoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/opus/OpusEncoderMode.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/packets/ConvertablePacket.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/packets/EntitySoundPacket.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/packets/LocationalSoundPacket.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/packets/MicrophonePacket.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/packets/SoundPacket.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/api/packets/StaticSoundPacket.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/AbstractCommodore.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/BrigadierUnsupportedException.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/Commodore.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/CommodoreProvider.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/PaperCommodore.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/ReflectionCommodore.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/ReflectionUtil.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/file/AbstractIterator.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/file/ArgumentTypeParser.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/file/BrigadierArgumentTypeParser.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/file/CommodoreFileReader.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/file/Lexer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/file/ParseException.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/file/Parser.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/file/Token.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/commodore/file/TokenStream.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/BaseCompatibility.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_12.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_16.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_17.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_18.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_19.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_19_1.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20_2.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20_3.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/JsonMessageBaseCompatibility.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/compatibility/SpigotCompatibility.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Analysis.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/AnalysisInfo.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/ApplySineWindow.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Arrays.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Autocorrelation.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/BWExpander.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Bands.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueByte.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueInt.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueShort.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/BurgModified.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CNG.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CNGState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CWRS.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CeltCommon.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CeltConstants.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CeltDecoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CeltEncoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CeltLPC.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CeltMode.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CeltPitchXCorr.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CeltTables.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/ChannelLayout.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CodeSigns.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CodecHelpers.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/CorrelateMatrix.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/DecControlState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/DecodeAPI.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/DecodeCore.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/DecodeIndices.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/DecodeParameters.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/DecodePitch.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/DecodePulses.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/DecoderAPIFlag.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Downmix.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/EncControlState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/EncodeAPI.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/EncodeIndices.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/EncodePulses.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/EntropyCoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/FFTState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Filters.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/FindLPC.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/FindLTP.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/FindPitchLags.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/FindPredCoefs.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/GainQuantization.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/HPVariableCutoff.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Inlines.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/K2A.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Kernels.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/KissFFT.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/LPCInversePredGain.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/LTPAnalysisFilter.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/LTPScaleControl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Laplace.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/LinearAlgebra.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/MDCT.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/MDCTLookup.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/MLPState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/MultiLayerPerceptron.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/NLSF.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/NLSFCodebook.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/NoiseShapeAnalysis.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusApplication.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusBandwidth.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusBandwidthHelpers.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusConstants.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusDecoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusEncoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusError.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusException.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusFramesize.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusFramesizeHelpers.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusMSDecoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusMSEncoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusMode.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusMultistream.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusPacketInfo.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusRepacketizer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusSignal.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/OpusTables.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/PLC.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/PLCStruct.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Pitch.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/PitchAnalysisCore.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/ProcessGains.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/PulseCache.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/QuantizeBands.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/QuantizeLTPGains.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Rate.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/RegularizeCorrelations.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Resampler.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/ResidualEnergy.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Schur.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/ShellCoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SideInfoIndices.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Sigmoid.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkChannelDecoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkChannelEncoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkConstants.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkDecoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkDecoderControl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkEncoder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkEncoderControl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkError.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkLPState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkNSQState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkPrefilterState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkResamplerState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkShapeState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkTables.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SilkVADState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Sort.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Spread.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/Stereo.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/StereoDecodeState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/StereoEncodeState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/StereoWidthState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/SumSqrShift.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/TOCStruct.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/TonalityAnalysisState.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/TuningParameters.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/VQ.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/VQ_WMat_EC.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/VoiceActivityDetection.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/concentus/VorbisLayout.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/config/ServerConfig.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/config/Translations.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/CommentedProperties.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/CommentedPropertyConfig.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/Config.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/ConfigBuilder.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/ConfigBuilderImpl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/MigratableConfig.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/MigratableConfigImpl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/AbstractValueList.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/AbstractValueMap.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/IntegerList.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/StringList.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/StringMap.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/IntegerListValueSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/StringListValueSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/StringMapValueSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/UUIDSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/AbstractConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/AbstractRangedConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/BooleanConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/ConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/DoubleConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/EnumConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/FloatConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/GenericConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/IntegerConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/LongConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/RangedConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/StringConfigEntry.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/BooleanSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/DoubleSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/EnumSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/FloatSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/IntegerSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/LongSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/StringSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/ValueSerializable.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/ValueSerializer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/integration/commodore/CommodoreCommands.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/logging/VoicechatLogger.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/net/NetManager.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/net/Packet.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/CDL.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/Cookie.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/CookieList.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/HTTP.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/HTTPTokener.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONArray.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONException.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONML.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONMLParserConfiguration.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONObject.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONParserConfiguration.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONPointer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONPointerException.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONPropertyIgnore.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONPropertyName.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONString.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONStringer.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONTokener.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/JSONWriter.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/ParserConfiguration.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/Property.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/StringBuilderWriter.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/XML.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/XMLParserConfiguration.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/XMLTokener.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/org/json/XMLXsiTypeConverter.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/permission/PermissionManager.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/plugins/PluginManager.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/plugins/impl/PlayerImpl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/plugins/impl/ServerPlayerImpl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioSupplier.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/StaticAudioChannelImpl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartedEventImpl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStoppedEventImpl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/MicrophonePacketImpl.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/voice/common/Packet.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/voice/common/Secret.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/voice/server/Server.java delete mode 100644 source/decompiled/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java delete mode 100644 source/decompiled/summary.txt delete mode 100644 source/resources/CONCENTUS_LICENSE delete mode 100644 source/resources/META-INF/MANIFEST.MF delete mode 100644 source/resources/META-INF/maven/de.maxhenkel.configbuilder/configbuilder/pom.properties delete mode 100644 source/resources/META-INF/maven/de.maxhenkel.configbuilder/configbuilder/pom.xml delete mode 100644 source/resources/META-INF/maven/me.lucko/commodore/pom.properties delete mode 100644 source/resources/META-INF/maven/me.lucko/commodore/pom.xml delete mode 100644 source/resources/META-INF/maven/org.concentus/Concentus/pom.properties delete mode 100644 source/resources/META-INF/maven/org.concentus/Concentus/pom.xml delete mode 100644 source/resources/META-INF/maven/org.json/json/pom.properties delete mode 100644 source/resources/META-INF/maven/org.json/json/pom.xml delete mode 100644 source/resources/plugin.yml diff --git a/.gitea/workflows/build-plugin.yml b/.gitea/workflows/build-plugin.yml index b35b691..d8cfbd5 100644 --- a/.gitea/workflows/build-plugin.yml +++ b/.gitea/workflows/build-plugin.yml @@ -13,18 +13,20 @@ concurrency: cancel-in-progress: false jobs: - prepare-release: + build-and-release: runs-on: docker-builder - outputs: - version: ${{ steps.version.outputs.version }} - tag: ${{ steps.version.outputs.tag }} - release_id: ${{ steps.release.outputs.release_id }} steps: - name: Checkout repository and tags uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Set up Java 25 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '25' + - name: Calculate next version id: version shell: bash @@ -44,134 +46,36 @@ jobs: echo "version=$version" >> "$GITHUB_OUTPUT" echo "tag=v$version" >> "$GITHUB_OUTPUT" - - name: Create Gitea release - id: release + - name: Build plugin and run crypto test + shell: bash + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + set -euo pipefail + chmod +x ./gradlew + ./gradlew --no-daemon clean build -PbuildVersion="$VERSION" + + - name: Create Gitea release and upload plugin + shell: bash env: GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} GITEA_SERVER_URL: ${{ gitea.server_url }} GITEA_REPOSITORY: ${{ gitea.repository }} VERSION: ${{ steps.version.outputs.version }} TAG: ${{ steps.version.outputs.tag }} - shell: bash run: | set -euo pipefail if [[ -z "$GITEA_TOKEN" ]]; then echo "Add a repository write token as the GITEA_TOKEN secret." exit 1 fi + jar="build/libs/AsminVoiceChat-${VERSION}.jar" api="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY" release="$(curl --fail-with-body -sS -X POST "$api/releases" \ -H "Authorization: token $GITEA_TOKEN" \ -H 'Content-Type: application/json' \ - -d "{\"tag_name\":\"$TAG\",\"name\":\"AsminVoiceChat $VERSION\",\"body\":\"Dual-protocol Simple Voice Chat server release.\",\"draft\":false,\"prerelease\":false}")" + -d "{\"tag_name\":\"$TAG\",\"name\":\"AsminVoiceChat $VERSION\",\"body\":\"AsminVoiceChat $VERSION\",\"draft\":false,\"prerelease\":false}")" release_id="$(python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' <<< "$release")" - echo "release_id=$release_id" >> "$GITHUB_OUTPUT" - - build-and-test: - needs: prepare-release - runs-on: docker-builder - strategy: - fail-fast: false - matrix: - java: - - '16' - - '17' - - '18' - - '19' - - '20' - - '21' - - '22' - - '23' - - '24' - - '25' - - '26' - - '27-ea' - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Java ${{ matrix.java }} - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: ${{ matrix.java }} - - - name: Download 2.6.25 base and compile dependencies - shell: bash - run: | - set -euo pipefail - mkdir -p build/deps build/classes build/test-classes - hangar="https://hangarcdn.papermc.io/plugins/henkelmax/SimpleVoiceChat/versions/bukkit-2.6.25/PAPER/voicechat-bukkit-2.6.25.jar" - curl --fail --location --silent --show-error "$hangar" -o build/deps/voicechat-bukkit-2.6.25.jar - - repo="https://repo.papermc.io/repository/maven-public" - curl --fail --location --silent --show-error "$repo/io/papermc/paper/paper-api/1.17.1-R0.1-SNAPSHOT/paper-api-1.17.1-R0.1-20220414.034903-311.jar" -o build/deps/paper-api.jar - curl --fail --location --silent --show-error "$repo/net/md-5/bungeecord-chat/1.16-R0.4/bungeecord-chat-1.16-R0.4.jar" -o build/deps/bungeecord-chat.jar - curl --fail --location --silent --show-error "$repo/net/kyori/adventure-api/4.9.3/adventure-api-4.9.3.jar" -o build/deps/adventure-api.jar - curl --fail --location --silent --show-error "$repo/net/kyori/adventure-key/4.9.3/adventure-key-4.9.3.jar" -o build/deps/adventure-key.jar - curl --fail --location --silent --show-error "$repo/net/kyori/examination-api/1.3.0/examination-api-1.3.0.jar" -o build/deps/examination-api.jar - curl --fail --location --silent --show-error "$repo/net/kyori/examination-string/1.3.0/examination-string-1.3.0.jar" -o build/deps/examination-string.jar - curl --fail --location --silent --show-error "$repo/org/jetbrains/annotations/22.0.0/annotations-22.0.0.jar" -o build/deps/annotations.jar - curl --fail --location --silent --show-error "$repo/io/netty/netty-buffer/4.1.63.Final/netty-buffer-4.1.63.Final.jar" -o build/deps/netty-buffer.jar - curl --fail --location --silent --show-error "$repo/io/netty/netty-common/4.1.63.Final/netty-common-4.1.63.Final.jar" -o build/deps/netty-common.jar - - - name: Compile Java 8-compatible patch classes - env: - VERSION: ${{ needs.prepare-release.outputs.version }} - shell: bash - run: | - set -euo pipefail - cp="build/deps/voicechat-bukkit-2.6.25.jar:$(printf '%s:' build/deps/*.jar)" - javac --release 8 -cp "$cp" -d build/classes \ - source/patch/de/maxhenkel/voicechat/voice/common/Secret.java \ - source/patch/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java - - sed "s/^version:.*/version: '$VERSION'/" plugin.yml > build/plugin.yml - python3 - <<'PY' - from pathlib import Path - from zipfile import ZIP_DEFLATED, ZipFile - - base = Path("build/deps/voicechat-bukkit-2.6.25.jar") - target = Path("build/AsminVoiceChat-${{ needs.prepare-release.outputs.version }}.jar") - replacements = { - "de/maxhenkel/voicechat/voice/common/Secret.class": Path("build/classes/de/maxhenkel/voicechat/voice/common/Secret.class"), - "de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.class": Path("build/classes/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.class"), - "plugin.yml": Path("build/plugin.yml"), - } - with ZipFile(base) as source, ZipFile(target, "w", ZIP_DEFLATED) as output: - for item in source.infolist(): - replacement = replacements.get(item.filename) - output.writestr(item, replacement.read_bytes() if replacement else source.read(item.filename)) - print(f"Built {target}") - PY - - - name: Run CBC/GCM interoperability test - shell: bash - run: | - set -euo pipefail - cp="build/AsminVoiceChat-${{ needs.prepare-release.outputs.version }}.jar:build/deps/netty-buffer.jar:build/deps/netty-common.jar" - javac --release 8 -cp "$cp" -d build/test-classes tests/ProtocolCryptoSelfTest.java - java -cp "build/test-classes:$cp" ProtocolCryptoSelfTest - - - name: Upload JVM-specific build to release - env: - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - GITEA_SERVER_URL: ${{ gitea.server_url }} - GITEA_REPOSITORY: ${{ gitea.repository }} - RELEASE_ID: ${{ needs.prepare-release.outputs.release_id }} - VERSION: ${{ needs.prepare-release.outputs.version }} - JAVA_VERSION: ${{ matrix.java }} - shell: bash - run: | - set -euo pipefail - api="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY" - file="build/AsminVoiceChat-${VERSION}.jar" - asset="AsminVoiceChat-${VERSION}-Java${JAVA_VERSION}.jar" - curl --fail-with-body -sS -X POST "$api/releases/$RELEASE_ID/assets?name=$asset" \ + curl --fail-with-body -sS -X POST "$api/releases/$release_id/assets?name=AsminVoiceChat-${VERSION}.jar" \ -H "Authorization: token $GITEA_TOKEN" \ - -F "attachment=@$file;filename=$asset" - if [[ "$JAVA_VERSION" == "21" ]]; then - curl --fail-with-body -sS -X POST "$api/releases/$RELEASE_ID/assets?name=AsminVoiceChat-${VERSION}.jar" \ - -H "Authorization: token $GITEA_TOKEN" \ - -F "attachment=@$file;filename=AsminVoiceChat-${VERSION}.jar" - fi + -F "attachment=@$jar;filename=AsminVoiceChat-${VERSION}.jar" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..394a356 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.gradle/ +build/ +*.class +*.log diff --git a/AsminVoiceChat-1.0.0.jar b/AsminVoiceChat-1.0.0.jar index 50ad3564de33cd9985d9c89a4d84ea8111c76381..a3971f91448ecf5db560fb59e06aefa522efb24b 100644 GIT binary patch literal 940418 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

UGk`gC7%I)s;jGG?@)wgWKyCc#K!~okK>&JJ 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

9J>7EcM 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%0D$gg_f3TjTTL{rTT(I<)G?VQS-X$Sh4C^1^TSk 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

3Zs_h!Kov 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

}9_z|8 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 z z;SxP)7jEwtmf#W2?5aL?ROYDK#a7vULO zLk}DG1ySpxsyi1z8rR_J8pwp)wb zj=zds9CZx7=20M3((`=R91L%UcimW6oLS(Gi}h8?xW5Q&`uLa(guq+f?wNe(?fTMJ z$2Y#lzQA;Ex;%eJWb}N;%kjeb6=qY64qHtXQGKo;aA*Ix#2ET~K&bm3jV$SuZd9(i z{(Cis5p>?Tc@A5$<_{n8@0Q*6Rwf>rkzaRLjSvkrHS(RsjJ$j1vEf{4DdrB+_Vgzc z`)k4MR8GKh3$>~Jxh;^@I zG=mD?O5T0z-z!Z6L-izK!^c0f`$m(lX=^}1SaOPxkFF=EfOO|Y^ba=-*vPuCdc1vWsl z*>lYGf)I~K@La1}AAUjyq}-sVOJk!fg=q9sK#2~2$rsxXmtA9n#L)`Xp_mvh@z<%MUR&TX($bC zNmdLp3_yNelU>9?CnC0L?WJxUA4Giy7M6yoXO8qTm%8*I^ykHUxHPb=0dK|eN1_1+oK%?rVVtU$?JQ#y=-@YT&uHv9_X3VMekI32?MB*Hea zzhF<@f(=@es}y$>D>54GVTvuX%>t=!w8LT7!n5ozT^?H=Z5cMp!PW6EhOl%X=dUqIvwCZMaP zD5EYP2h~5v;#FLiWL_3Qq^F&P;dWNDid8L!RT8HeotSxSGr8JrJR%Ti@W-R&VvGE# zVyUPIt!&n9L%DTK3rYIP>m^i&B(j8QK`K6LCBz?nn63V5%pF+&U=JA^ z?sf}VXpqCstM8VB1%iB&GPr;0wwYvt^LX5q4;S&S-&+@uOBL}Q32=5x!=I&Uj8as5 zZ$DQs!lg1n|4{b>2}WexU-GytvzEE|2si0U^2r26f(Oz6C!rHXfYdUZUuCCo<)P@dK_pf07BaA)E$jQ0z3UlX#E%Uq zokL{-!0qj12@pJeDdOB|{+h$++BE|0gV8Ry#?^Za1(I8D@XZTuVNiEC%R%j5qhRx z>llX8NABF|OIO{BWJm&iNgkAq5Y<@os5N%)%2JQAWB>=;e9mH(dwI3YLDykzZN z$yX6wTeLc@GyoqvpP_Bnon`24XVV#*qRUxtfyb0G#}bdBLZ3HUgIFWSZ$*9%Q5l

0B9dOM{x&deL0{w#&qH!^3!*T57Z2$*eSdaj5 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 P|0bT0L1Dg|?ccF;}yyQwW)! zm#H;8Ow|NKLO;Z)%(t!2le2J&Hg!L*yK>v;70`J~zS3p-T(Oh=TKPfKcY|z$J!;+wq7ry*SK!2($+ddn)_Wr<4Skmk~c2{W=j=sF- zd(V&O{CZB+)O1x(O;t}%b+6S6*P>5{!`;Wt5a;T<2K^UjUOWoL=t7omtA8X#iub(~ zaW*Ix9AqYsJtN-HGmTtKo^Hz#Yr3W1T#56RqkSfSWay*EVhQFT*`LC9d}!ML4no2X3vuRUT9D?T+!<)86C(W`NQmx%)Y% z)w<2<%5NRFFOVfha_IiwRA#(?vtO1qBG?CbiOjUsUt`^KIdY46B)}KA>low^{SvBo zi%8UnL=&VgVeB$q#+&4u=Ds<14F-MTy7&YQ3T=9I-&iFcuOxc6;M@7$@wc2sn{@<8_$$<)!mA%&Q%Gsg1h3 z0M}RE`Y2*Y`)kqt&g7c<&ysgz3)!!Q_{To?cwFtw{OUBS9otky=tN4P>W?^}6tel_ zM>Uz4S}l4TbzU8t4uuI;vEUA0(Nc`j-}GE?iwxOjq#9C4N2r~XY|um7so*eVmis1| zCgEV=);%3)pJn<+X+mlgwL^FzRZ}+Td?;Y!mN2p^Fv)1pPxh8B*dIG2LC~S{)AE`EEmWRP@ z*__y9gJyQTyQYcoP-~wWGH3n&DTUdxBEyH_exxw={~sx=s`!7UaIGf1qs~g|*X;X! z3i(DFodIvtN6M>48|pXNzEEJ96khPkBv&IIr19iZ^OJ4NxN@TDn4q*Jt|c*ji=2#= z6}4NTRUxb#Y8IsFmfgC0I}+7z`@-h#rQDra`}XFg>Dk#U+cvEpm)jJ)a?l_}zBbpJ z&Qt%>oZB3q-ERN=8H)fYLw^S#`LfbrA_ywVzH||2VN{&$p;lxEu!0~Nk6?y)fiqr`J< ztaK>Fp@**ALZM{mM(rfW$x%{1;#fnclC*DM#U^!=+Z=V|F`@S@A2H;{Mnd%>JlTiN z3nog;{Klj$OfABx{v$Uhx>#wtIca4{(IJNOxv+D&%F`m+V=0!6OK(Z}I(p@3OVngH zf<>_DwWA)46Ax95;Obn>AbiW~eKlv=tUfud6JjoqowL>uu1MTK$+A&XOs0!}vT@I2 z;GEzn?LB`f&iOA*BtaYXO*Tz&wh;VZ#_%pr%_$%qnQzMZ?}0OAH7(RlVQ+KiOlMB& zjElMZquNgnl7Nq!lbS74m)9DGuoTxpViPjq5kxjrsl57{wwJJ#=HL2;^M=83>ZCBJjasewcE;D`3&>4h%wX&TR55SsinC z7wbu!xh$NbQ0MX`)=KWFNc%X90a9NT=etX$BLGnwYERg8o`-ukEgyjTC+IM;lh`P9 z{*fVhmK?R&{35F*HMdJ``0ULz7kU_l)vt>=DU&rlT4$Q`VDzbDFivk>56+4rlOy@O z2a}U$<#YV)-*xQG=0Vv0+2Lq>0uMgn7GINnE#~3u71-eMK<1;qX1ud9cpzv@OpKVU zMJ*;LFN9CDkFAaA?~oa;3)h95F~E}#{wIB?8p1BB`6SDU=y#ot&6Q>~F16DnmY)XK zHb!)|NFHO3p7d&tNAk`o(JUtDdXF2ehii6mUvGz;s4n2AHp>2}MDBBMab&7=*;*Nk zivIRF9yFnj{B|0>zV8q)uV#t4qs4MeH~ukYO#IK`1Ec)vspJ z2yVu+j@`l68n|*;vfm}kpMoo$7nEE|p zf$x|%8kqTT`Vz$A+#ux8G?C-L(&%J9Y?Jvk6JF!RV`;^5{bp#Zzl=%x2N5s zk{0Dq=)NQOX>8gg+!j|zp|bY?l8Qq>eBTpT7%#49Qpw~li&A4_KQ?@ z-+~$wTqG02o57+mwKmg-BFh+W7nileCdC(IAyvs%qOdp=-${= zFvPcG%~zQIE8+t82o*|yqmj%Ff;TwVMiZO1aRJNLB+qcni47i{H=$U{VK3Sq*T@fD zr<9>UAImX!Qk~qkhQJtJH~JEOQ2E3NUIZ^aW(Tj^2ApnW`xck*X`6l zQ?S%(N{ug#`By^0A|T$-jIz3+k##(yJVnj1SsnQHA$1E27p1X+!+!Cy zQ_4dT-6$KTI$=w)0j1xyAASkCGcN*f?NT$>*hIP>72xsa+pcc(57vM`KXm@xmqWQ` zR$LshF|l4ra74>*NMp+AZ(>coq5saz_Vg_*08?>gbbH4ZTteSzUQPldU<}fTTq$|J zR{--7kbX}F=mUU*X-Xo4;!@*k@h^{l&>g{UX27m8DPTTU(@T%xT_A*feC zeh!8Z@H_XG zDYtj9$oRVZkROZ_lOeP=ns{cHB>BNW9Cf@hz>S4d#h-17JZJJWT6j)h*g4l8h;fG3 zc6x1eZfD57H)?2uspQA3>a9?bT~U__IsK>IxbhY|ia}7j5o$LdRICN;Ng|fP_%I(* zJ;Qa9wpW3>3Uelj0ldl`x$cF!>Lq+6`${3nmD9oob?6pY?hIVl2)O>R&E-xh#sOLH ztOITH%#I1#@}=e&+M|b%*!hh;@GEc&7*0?O%-$CY{gtVTDUwKhJ}}o3@MJj*e>PxW zGl<177I!u#!4#R@01H83Xbf>UK0JhHSbcMVr^>K{ExU=F3e?Q~iR;b^1`KyCh z*8GZ+I~Mq#L8+Oq-YP z_96Nw3iIglzKAb=>48l@+2X$GgSm$+0HuEXT4f<5RU# zU&!B$RIM`GNxe6%>Wx3-3%eKVcijMILm{)W4h$kG*wlXfA zFDy>aSvrIx7|!H`Li_&K{9dt32jOl|IQq||4j#@U6`6Q~D*WKOc0^G6VBw#}W!PU~ zEiDJ|m9g_e!_^j@d_fh2L{ePQ5)ORk=jqyuFeM5L#pDY|qXfP1eP9=>GlpN@NP~7m z9pU`{%v}J*lMZ+^^8}VR0!c~!3d}bcSO(4!3^bTu2405}L|!rqmY%s1q7a8fd7Y=hxGm*B@Qm=5%&6yl12vJwqzO>Q7fKVN~)z8vgrjhVh8 z4~fD^N`$Zo@qy>>RKc-_jsOhpR^-S6)sKRy|MdO;K~6wI!g-PZU`t>BTWsn77$p_0 zTum%xjVxUL@1ZC+!^aiv>4&A|;gKT6kunB>u@Oxoz(gl38K@efo($F1C243vHR7Im zCEo;^yDkK0^>hlB4tKLky{uh3DgX15Wnsmy0}*4?gNL$hhwSw|gK za9)$m8_P@5BgFPP{B2`%-ME5zUl_;6A*hvfownmX z38*%@v$aZbSkxkMs7~%`GCC=FhfnmO>EzViEP|#h+pda{^B!hhl${_u zfXK|*?B|B;rOb2MB4Lp~^kov$NvKuLzALsyWpg4;?UcR4O$tDNjzMShtTW2(l@IZV znGzQ>s{cU8c?nNp}W z9#T(naB8}@HHer5F-`IMiC8U?PjRfoH;3U1>rDyLFegfrp;%{z>7r1~k`&IeN|x10 z)!d*~X`@7eL+7feRWNPJOPwrxPOwX`rNOj@A7UM53OngWwv#C+yrM_7BYVLzmXl7i z{NYcXykLmU-0&y;WldqLamXT;d|Hx)Zp726%QeNjsYbqr!>n6vNa^FV%A>Wk;FS>2 zr6C_RuGF4L%@v>dl4I!#{Unf-g0tV079{HIO zF+hFqP|)!`X4-19tFzhGx7zaetqkIylqk-tT6rSJ8AeQ~WJr_Ow>{LI|7L50ZvG^> zxR%0gOCn^{D*c;Sj)6mQc_VtB>Nw053zKDLQ5&m;vRS@p-fTWZKttx6jn2c1rGhOW zkP7!}M*9$ypmVq_=@yqUE7_lt%N4d2D*V&s8`P(_CG z!KrYtDW=$dv-QE=TW`xbSK*&}e%2(%E=|8`-ChUIi)ViFerPWH7?{-g_LQG>O1}Er z?}zLOP$T!pf_WbJ@14WC%0`KKR`4zQSe`#9Jc#dj0!7;%?>B_7&FN!dU8V*O3WH7` zcKqiKm(+!umqt>#b4&_qs}|sL_bF`QZUU#nc^D@-s~7*AWZMEyy@;n@Ui;>mDnKOrQ;V*b%Ec_7 zdvkK4gtuDGQ7-%>Ci?Whi`z}R;9!h6Pmg*^bZJ!4WvZ`Y8$R%N_`|g4`o`QIRGytS z)l{K)s)i>s6xq`lx~g^&;}I%#3W(Aa)h4mLROa!Tf4AitA#!r@kS%*V>{7H8n!>}f zUmVL=uj~k#wUDavVymqPt7&-ay|aAptTHUWg~~G^Ur?LM6*60GoIDkihLkN?z|n}g zG$k@We1@A;zLhix9OGox+Qc3l@#WCO@?g8PrgCy801+>v0zFxP4&?`_g8^3^Kvwtx zRK7<+srKJK(C7Vtj4lFkTrd0%=ld&6FuB zo3EaDX0D&aS6Qm{Oy^L}3%^5y)3%6;NT*yw(Y_UK%JbvIt5g5Yv6awkC>AJ_xWp8@ zM6(tT8(r{bU*A?DtbK%Ziz#x0DW>~Prdr6av%k1RHbyU>=IQ>^tCrG-xY)_;8A!{M zZ35qTk|6+XfW4_}dT~l6wQh@yIqw^ zA4L}pevCvYp*0n~ZEWi52fIzIAC=zehR7&kPIp}qwaV6e0eYjDa>9FPc2m_LE=S_P z5R?8UI<7OUBJtJBsef`KeXh#fuDtCu-*lJw$e!_ z^vw%^b;{QwSmLnJGIIp%{h3vP8_^owzW``Z%1|*V81+i!4g1Jp;BgtxgnI@j4(HT5 zr`##8g6)YQ?vX#~A3W_b*0(93QW05H6kY+s#&xL2q-UgNY5(EbF>VLPhoAQv3scr4 z)1^n4cSyM)&U$k}OPX~mV+OsYA$jVoESp_dhViq;g!FR433Thsf)ckQLXK|~2z7fL zwuF1gTz`1at*K|CVYxwU)?D;N<+pp=1WmLve(~bm49heF_8~@Rl+H1OeF|iUUfu}; z_dxCgp2rmOO;Yhy8fORR{Pbs#izkyKvJa>oA6`eW1W2_PTjE~hfHwi6?LpK4kpe{c z#wmMj@pLk2?7fKp2pqR`JmDh=>oGjUD|AHEq#WK!xoCybObF@6w2dsc|Ex^a2AK0l zaA%bYxbsJHCs^;olql2!isnRpq#`-&k+i>DsI`8&-bXl8*7CTyzf7oh7wF>~KJw6C z$gDSh%^#|6jGMSHs5>PYwM$ zcf-`egGGuX8*T=~SSZOgokDJt!A^OTf;cG5uKC;^bxOEAWoP1st+{zCQ%X{i8U%zS zGB8lp3-Ur|uvV{-D7wJVk9HZei0T0MW9^pI-@_a=GCyDLU&LE-cJJx-W6$Zw&Bp1j z@0AqL<(-1CkNPzg)sojrhT>CvWl@?EtJmnwI9gn+^?Hi>Sb@1IYFXAbW7Q!BA_>?t zjf!+c9ad+2VPmf~;AEc|3=`kh!UF1#Tvp*mHgsN_8YxN79{BQrL`CCcmY620LEa~U za7^hr>O+UQ>2Y$U`7vBEYE9c=wY2p=(ExpBI5k2hmeCsPXF9nG@2-B!b#tX#Daxe@ zP1}{oh?A2OC>wl9xK4q#@Tk8Oi^|OrsW^9VC3E} zg9SJlf}7ZAF7RYRp&V&T-nyNPLYr{wd#<=W7Zm+@IAJ>-x;7dLV{&=SJNcZS^fl=e z^?I|)GPw$??u?y>ZYPSvzKHp=$UID3tu1l|>Jz5HEesd679(_CH2wK{*%+>^mF_Ge zt`Sp*D%Q!rJS6y&3k2LreqORRN z1j3}%B=ja@sGlO{>g-}Umt_vDLU^31!8DguNzIQWZC$bYAobW<^u^ktb)~9`>T%eI zqZzbIq(y|M%wnLS>{F>HPJO7-vxv8TYOd(Rvs*KNkk(O7G(c#fEcV=xm#p^_B3 zXv({iK+;#9!ETY(wrpK0mBM&`|z>$)BEun z7Sok|E_6bf=3onU1Nz<5yPm+?z3!NkwWCKl&X+m{iM6M1?T@zhs1(+ zRp~b}wV>GKD%|)ep)!jG0f;l>$daUyS(ja`XDAncjl~y!a*=l}8629wh+Z|_x(UNP ziwsub(tv|C=VLFLr;auPNiCwwtR~7**8m%)TL#lrp@0taiY-c5ld4Q*fNLsJEUOM_ zbY-Jos%Cym>huUlsp<~w#6d}>5+u9csI+4R@cTZ{a~M=;Kkyk)BQtvI{_x$egNE-L zJi`&zJ4B!&A0UtmpjV=zKj?M2L4hei_G!OJTpw-k8%GJD@a{ceuS`@Lh&RuoyvZFp zVp9kQU@DoF0lZ`mKH#^}9Quc)AujcOasB<1y^y{$Ld%{sT(l!Hf50mRMZlAY#f<~5 z<=B*jx|I>6yFwC3TWOU6XGXf)J9yNG zi;7Ikz8t79Z^LF+l{nZi>}pH|(Cq1j_(Nxh8SBS5tOzCs9^FOyT_?)lposFfzI*23& z{3x}LqND9QfN;fLvbwa396q(uwyVlL1S#G1>!@gD{H^P#RcdHM8Kl zaQ^9HmYZH!;k!P|JtCegUqdVF&CcdvNLo)WoJ0^g3-Dmv5J*xp-&JD&!Oj~?B0Ln~ zC*^|R`cP6cJOt={7J}-%N=a-5iAhfm)!RhB7*JjulnmSiFOVP@|7q*3kTu|*paDF2 ziA0G&3me!343Yz<#SaJAOH`1#=y%ndlG+w0TDMuF9VgRu<K^zn@ zfImP;JQyK<71L6?Zo8CU>_AmtHW8FC#az{2K4yDeW@MgV1D%jl<258kI$uK#|z z=pSvOmG@qprQ>Zxe3Z{OYn6x5*7urzV5vJja+M7#tg_Ipr%lO42h*-mpEAVkrrnV0 zEs#E@6yJ?8_~FH1$Q-2b)+tseIhTeS z#HiN1LUNcij+mO!&B1C6M}?>zr64im*I(R<`KM#%H~5siqX)52qRyaz2>aBdt zYp}&3q(*aDs>h9(EHj=hb&_ULM+ZI9Q{X=3TaufOYAiSUbsCCR-)~qiIS*kGt!oUj z^RzheF;rCGEu&>gE|mI3j%5xPY5NfrY{y$jC#igjXi*{t^gNa zZY=iH{D=-m7`l70E;EN9h!h-IwiZ^{lC3Qk6p^D!W@xZrM`muldA{X-1tK-JzV(1C zOQkRicvTHbTM4bKb?NZR1tr(BM|6-)Z@O0g7Zj4v(Mz7MFBdA}%)Ep9I}6)){3fz8 zvy=)y0|Cv_M~kipS)k%eDSSS*H}{8>ZRQoKqbN&uKD+juA%P6Hb9W5A#p}vr<^GFOJYDf=f@F zykeIyql8dx{C&Ku5*A)LV!n2+;8?vnsvV&ns~av6dIBqFeyRQ{8^ma0y# z+<(t)O-lQ&K|v&)OUiH#vM&%*f6mP3mkAdO60?NFw0Fty874+G!Amo#oWBt_8S8pW z@WoSF5cx@IM)I-nqunqe97CklD-J1YeMK?z=f~)cw@+9+I)}>X9!81@`M4R16_K$c2R zZJMl_YKyU_aZ^!Ki{iN``cBS9R8GqgA=QO_~vo+KwDH`xp~``-&`j`^!^!DdGBw_EarC0RSoZ)#OuEVWZ3C zcbCWAI@>lDvCu*PCN(vxs7snjCvC8zv#|lObWJu>Zg7K6YgVxAd4NYF8J4y7bEEq9 zsyrjs%pLWh@WcKkYa0E#XKfX4yj4A~c&#x<8pShsri^av0_9mX=k!vO+tJzcpQSEp zB(E?oP`$sbRFMQ6t%nD!L5k>giHUdF!ACYzmGO4m=BxmnVENsLlh0(LWYraDwS7DB zF6@)4f-y>&<09>K6;H~6UGx!C6Y@{V{oaBrcA@(E-r5@r^A=b2eeZ%V!GhOVJ8o9@ zYe^*ee`)|JX@6lRQ|_mA7S1KGFt<(W=_#pL(E}<^PY1) zpy8M4*D98n@MdhD)Tzbb{dFG*dFY9JM67P8=2eYE<4Pti@}{T zZ)l-w*61qp22FS_)o#v)9M4Au;31`1gA1 zBnFSQd~oog{x4W@WBdTqkG`>pDGh!KNS?|XNmClOR9t)~QUViFg7byJOxU)ABt7iZ zY90!QW=pmpi%ZBG7Us}wx+mWlGSq21QV|z0gN6gPs=?j@(Q+o+ z7m4hj5?U?Rm_Sy^Tb~5s~a;NyuZVp@;4) zbtv&rm=dh|-gDf&s~Rkvp5E{Kvgv*?>xz(2?q-eKfmHq+7RZ2ucOaO8{3W7>EC}K9 zS}Q`jQ;qeSiVxTKHMj%6Q;osYfB@m5wJW$Q$r_@rv5P)L78){-Y&0+N{1={e+CIOc zER6+>^LFdkHVa=4HjdH!WnIOsaYois?qi9Aqv6c_{9YoWN^pjB2}o}U=(&LRz(Ad0 zhOUR0Po4VMxZ>`>O=&24t<6i@h;qawm=HO(uMg|+aODnm_@ppYc#~SC-xehA7KAts zZsaih6D}MO79k;_#XLgEKkRh~??v_gprBUf-*#8FyL}CnK1M1Mlp#uMtLnRDO7IYA z#)iDulgG4i@H;w~91Ak|c29P2+GGFhi0MXhh`4aDKwxM>#b$R#iKpGAF`2RGt2H<| zLLD1jPLuhL=tFB9kQ1kJF|+tfFsCj75KcQCiVgDw!qtyoG!WmbYT2A_wjLe2Tk5+; zb+6RaK!%3JaJKXzea#N0n!VD|DD`d3SlO#JsJ6>)%N|_X$sXsm16fn;4mMik1LsPR zAptYTTWhx3*HqmiKZR`lvloB*n0v|{)*?H8zGb2y+z}^4AFYLVwSCDTMU?W|b_@fh zj5oBM%eeGNMA-(Dp;*TXqFJUdAoX$89wIUq|Vert^htXZt81s?w|pcSsqE}NIL zHtpkQ0HKbpDn5ypHTIV%IW-Pe1~Rvi!F!Enttyqp&Ft^#Hxa5K9<a-3&K7Q*$t)Kd##8vR1&%E^OaIs3KevmX||eJ7mu!v5Vafa~qM5^DaAQ zo%%k)9XwS1 zAa|^`L_OqrJpPOo*x7E0_S2{HDl|Wp5ZBjIcH5ycV!PpTD4wot<+ST)^Ww#zF)oxc zt^SeymVEhg-3>x2%8)e`m>w7hEyWH#IA`KFzl(v@aH{Yyfciej*zXUYKXCNo(WypOJ5TSF5$Mv)bpCdsw$A?1_~yUp!|zflmTM?7O``W=@6K{!%8c!W$vwY_OBM znDd&t3@Xw65(md@`H7v}mN2-Tje}k{x4p$l1Y-}im{xx?8Q;cnf%sw=IL?PYv?G6R zL)^1V%|DE!+g)p>_5zr77iv!c;8)FBaup0l23?yoc}&XRvVruL)`B4oF-WBDt^}Gu z6~Yw)aeeWJ>fob%BM(KY{9}Z0rw1)hGM8^ti$2$?d=ab)2ryqy_;JG$J)#PumVP4` z^{aSC1;I1RIunf!a5HhWaE9W~J{lm&p_~(mIIbyHrNf2Ty462^a1z(JN`Dux0L{n8 zCnVS$nY5Y|XbR(A?2H*An1#Q*B+Q$cJE$Yei=-6?hkpGMRpx5$Pu4+AtYl(9h5FhS{n`yA=#rAOuOzntYZ#I1_3Nn)!%qQE(gA)ZWgo0ng``<+mONK#C}Wv2Ah06bi~j?G_FqL$sw2G7{Kd*;>rI z^CYm4Uby?nv~{u8G{NGDTQFPp{&mmvTo?Ld<8xEh8&)TLQPta;iuVv6kKjxL(_p0( zIWz1B#+A=yqb(|%NTgkV=LplICk~H`HN@@S1&Mfd(J${^-F8LFY;Q`aW_s*sAF7Gk z9eJiVgrs!U+E!H_?>V&-jC|W!J*BImno_8%d;HNl-0He2t?qrmwAAG7<{>fVj^ZCj z`k_r;#rl`~*3GqT(FZnLxJK@;229nm4_Mv{LF=q|#HU={i)6XiE%Ht+!j2sr@Tt<& zGkH}!o?a7X96U)^F#{Dzj7byj5GmsQ#yQrh+Hyt_b_C0C-df}g!@l2!e2C#$zR($q z|F#rd8*lJmGo2_JhmCDwZ1xLnol6~TODvzb);kZT0%i zzA&R?WsN?rPTmpkn_4?? z2QzTvisx-HN*|;v+pSQ%C?Q2op zGe7-&-o-J@VYy+8)5;Zp`>k7jKsN78c#)iS8qACiv$-H4D)Xul%3kA@(Qp%zIvnLh z^$1OK*BNy*IH@cwrXz-bJ8O;#^C1(j20kTu%JCijde6O^N(OOj{g12 zO6;D4U$9tgKj*daTyxKr_b6y>X%oo}Ozgu4+gkMrgYpGCd(9ZW?iPO>AeAj3AV6Tu z$(?Qh&1~Tf=)*CVKO4wHXq3oVTobWfruHKpN#iOFm^v(FAL+Xuf5=7RJ?pvGgYc`q zGx$<{$&;nw7cD-PS7UoO13KB-SfAhFbPOC!x3)baD2O=7qvAf-X2QtX#M-pN!Bx-Pbc$${0j&lB zUVqH+8R7YMS4QcQB1_I<*Z3|5Nn@lVC1-1gS7kW!M%7!A@2VgIAI@V{Z{sULt4vEe z@|%h-ye$CB01j9JTNrn+H=aXugwPRwP%wT;H;F)s&x{+qYy zMUUQ3E0P

$#uUz0U+az~u>?dHFB=)t17{3g>)pz^;I`X0HPgXKamie^ItM65M%L z+ain=KHf}8cjQi6P*SPGv)@6$pX}&?n$J7uJzvVe1=fT)!yG6L>j6^Eh;^8V z1ga-jl6kqG96vF!Ky@-4+|cCi_V9K5p>C&`AiJ4(@J~Nb_|K4Tk(yOt*=Tp0@_orZ zrjG8yeg~qFKjhk(YtayPgxlAVOdSEDY)z!WXZ`OG?<%C&;Z0q%yl3CziNaSL<=*&m zkpIpsfIsQTTJ$RaB;C})!$Cu{Bw}Cu;bhCWk$-x*CKxa2KJJhJP~BOslsFX7E_E~M z6ub@Gef7er zXgS}!dzAl!$RWp4>MXuh4BzL&6pFy8U1DQ%{P~icy zy&O!Mejc0!#_47~=ZHrB+oj%U-B#0XP^WfT4Y7nBE_Lk(nkh$uvYEFjb)vW-u%3N! zD-Hj&(AuN*hdKG8*WJWAzXzc;iL3gb%J49oChqI@A}9hrkVGN|ArP3A z0Ky*Q2uusb|~)hZzN%Ec(Oy!bmj)$Mme zn#P#j#)>nZ!GbJ%vi%2zL25y80=4FqB9Klx6sL@cDU=RTT0wERR+?^vA{9^hqR-zN zjv3ay=9vkPEs+{ha;s3%q}jO;;rwB$$b%rx4(J2e%_$uC{r?gttjFlV{c{2~kLqu& zNO?MyZe+jgXulY(tHNOr?5*IzbunErQ|9P*BT@I-PvS41Pz!aVy z1Bq(Ufl!f0psfj#=Dy=TMd%v@)xQNc;82>?Km*=Y z4t_L4J?_DJeMZTtSIwzU*;51aw@eVADR>E`#J{)?zHtmvr;e}IEpYk6ceX+>?~P~~ z1A?DiFq1YPyclM0(%M6w$}(Xke+p0gU6$?-5bM`ka8UodW>{OY3p0EkxuU62JtpqZ zce2xa%e_C^O;JD9W)yPOlrG)lZu{Gl9;JRe?lcV7bug8-!x_9CIy-gE#k-+U>l~y` z{Gmrb+mffMM@&7BlJ+ty^?4QFZDnPF;{AISdZo9|a>wpW(SFQnB};AKA6X9Od3?sX;!o4cgR-+d>9w6=L+B&37K2|Q3W?xLnQAKzWwXuE<&UX!x zQvyUuJ)mFuiUF-@e-3gjIxP->eVOQq&tCEGgk_l8m4?Plb{x&{841Hso(@CXWC&}M zyXdEJ|20WBgd;K#9k-4I+Kg(CwO7bK9rnGB-O~_4SYr18-ExaLx7jDOd7egytGPGMIV;@mUuGFg>5BVAELa5bxZRKkqBoNh&@>Bthcl z5eSb&=MGna5{(a{+BlmdRVSDvefCS=%BkBv(T9^nnJUEsUc426K3N@yWv~ZbG*OBA zEw_C`Z_oAK!}V*zrmAK+9vXR8CnnPgn3FMgFt(X^FcHTEQ*tMBc@LanPlKT~!x|4q z`A|{+I+)?Rs=Tduc^`V!zt-{^d4;SlsixfU==Bj>yveJHTl~j?N!0Xi1I>QJ2#_^8 zW6=-J{2a}=hai!q9h@FTMUHxtDZtA>Vmu~StfMW<;MX5*s6vVEtixi}zXg>2HZ)%d zRZJ#V5~mDQ_JK&qO+6z*kovtcKO(x(VtmgJKBG$MXr069sOe=pma7lIssE@o&U5L9hBO3b%1b-u*lZwXSlh@aFL2EV9-P3aKk0 z4bePB zcF=o>Rig!|&N9W*U6}q;%{-a~QNKFEqgmKheUS*2dG(wTd)lsMefI15nIL*O66Tut z1iq8o->+?zk@ej(Ys8!}C!IVF=&n9zz%i9C%@K2o8xF<7_)B9WA>5T6x!iyG{=;&e z0fexqDkl0vOL=|m;Rx$`w8~+9)74VPCP>=gyay2PNkl?QBfVCTB)0ebW5z}FD#FuG zYVXNv{RnLONT6M@Pow{}G5MhVCWV{d7QgjclP3T>rlfi|!60X`mh7#XC>FQYC4jIdapT0O;+^pYJ?A$GV5;z zv9t#VHm8-X?Z+rp?UV#OER$5bLY# zvWtaVLEZd&c@^B!bfqJm7I?Q4P zSk$Ntbdgw`s}=T%@ZqE3!&}A(rXh|&B)0F5lcHEAT%25_IJr=1f=ObcL2!a;jeJ<6 z1TH}u8v{Mbs4=ddhlQ@~-n9>o($=>(6iKGwKE~)lhAE11l&uer^_9HhbcTT#qfpKi zOo^IygoJz~Ogb{`6@?}g>G6*2=RQ}JSK|I`N#jc5Zmgi-ne1T@RsV8z#ob$}`&8zz zhYbC~entkwu#lBf1bQBk<;q``z@Ttee4ke#;Qc{j(v-yKMJOEQso>(=l%$2chDhHp zMVN5$693JVv?LqJhH4bsi!k+n7(1unOro}3Pi)(ECbn(cwrxyo+qUgwV!p9Cv2E|{ z`u|{&?(2ykw3D+A&ASd&nME?m zpXr1Mbz86WxdM7279W*YHeW^v@jW$7McOdl_m-}iI9{Mg^~c^>K_BIhxjx@pLF_Ai zdHmgao5$v-@UoE&`EF#1vt#X6AppS+BJ==mWz7eh6ZiMv9cd2&@u;Z&MR4&>xO_jX zA+!%J>%~w9P&aDlClb!TVW|6t43l*mXwl5o{4Z}AX2Tde+c5F+u%_FoyJxnDrQDDN zAr8Hm+Q7(UXN*4E>8*!K+*txx{jKtGZ@KW2Q_jTcK0!!7fl#17HuKA%#(-_}&1ikV z#)M74r4lem7T69fln&|3QF=hgOG>-})ZR-A%Z9qjjGu64*;RVX=s<)^lHnZ3O-~8q zt$D^6n%C0Es0>aWU7R+X--Znq+f#x8LP^$xNH%!f4mR7XVD`NtLr1C2g+PWi`Y zn4#L&u1g^P;W{lWU+iy&j2DO(-OzVX;16lYdkV%7f3V~GGKMgJH0hU>`dI#$m=7$Q zU43y3e{}8_c3rtzZO<&bQ`_lLvX>%-zqqsmdBwnHyE8&SKrRuorcO@&ihwsz-~qzg z`l|qXr|6ugOh*&4`APnm?-=pa9n84yyM7PS8!eu@741#H)t7B-$m9aWfFO>)^ovb5 z(G!=7UJ*&VDDVw|z%l*b8UJ9XFJsad`PmWwv&K0Z6PPsPqMvM`RB0SrVNm}xHm=&> z(*SvnJ+4Xf{j^D9ni1m!yrqV*VR})sPX@Iy>*=fP_Cs@q*BM>-9yuq2LNx{Bhh1>d zOS+DdrZHm69Sw9Cbsk84G~+Vk-4!_~e@ti81U^IN%b`0C*JC7-KJNFw`r^T_I!E8y zFE7^$)B3`}-}uTe1Pn3XP_7>{wZ37ZiL3-iOuC&l@dk;5@@0amu*VpKJFm@7CL#I_ z#50%SDm863M@4{`5B=+ZPn|SJT>LoBjL;ysH};ZnF0(4N(~Wb&(jnePY%p|XTSVpz zgdOj;=*Zj)4Hwd>$0ZVP%bVWz?S+$07Ih@!Uy+R~j7zuP7=*vxs>2E_%jaD*G6RZ_ z25o+alWAe8SrApvQz!pcHH4uKPsF^xli?yif3 zi%TZyi~(jX$4aBw zZ`i-x_pL~JJ|NGk#hj2Q){+rJA>Pp0fbMIBldKs$jIc(9U`+&}UYhjqs{AJ!ly^A) zH_P+_w|QV!nD}yKU%R<#lgb;KpYrz8CN{B3mrXxpj35>z9dOp|L6tT_jj9*2*G4=^ zkLTxLN}l8s@Dqc2+zvqZXxwUvhGF@OKC#sJ%NlW)C zSWb%CLW3Uk$)Jmma*BAdMTb zpHUnjv!~p>T>(ZmR!VabO;l;h0{ld@yGg|QDDj`V#AU)PMeK9PU>FR`3(<3;Nx-b% za-m2`3_tR~b@-Vq#T>p1)S0@3A6dCR)H+u}4C7_dRSaWD8O^ksEaagJRPvIQda3N2 zIKg2N8rPWoz%1V(@?2S~k&hG22qL^vvG;5nDfE_|JkgnXzI7g8a&Y`GbDGAX>wXdV zgHQ%3ZZwg#BI;q>t8v8ad=uWi@k^n1v}XC9=jzzNBF?z-$rIx?{VbAk4Gm7ljCmM| zgkQUkWr_Z`AvM|L?>KG7EZw&PTuY+jC@0h2x^HCIOG%mK-ityWRVwF7C9@PIvo58h zmc+XsF@PJSJs-@j1mA9*;7YETiuZ`9N96o7YRNTq$@TByhn(@Vu6@ACdlo~p|DejH zHp;U5Rr6nRtO1#p0daz0exKw;Xw2&&_6|~a$)STIBWy9kqpP6iL z@6;h}K#m8F`irg=kX4t9;J68E*Tuo-je0LzXr&43hU1+cXys~(F+*b8kus(GwU#x% zgQA2~%EmMij-9A&EbrB|0)mm&(K+>~8CK|WWa4nBh8!D68u-6D;i_z%G6>ls)ZXV&; zT6G&o*C9iam?(`m-Y)G-lI3rqcUJ0Vbq3{kIJ$Yg;ga?5c8{HMo-MJ{Q@R0@WfFi_ z4Ac2@gsVh8r)E;6nPtBxt)}xL)lQ56t8^SuMzv&&p;hBi=mmFxRjV~@sS6+HbYQF>G>U*|HMAj zvO=-hjiY++r^aSq7B0{T$f`F|y_mqc&-Ca-la4dY6h&x^$+I=PQ&ai20q9t(ptCi> ztDL~Pa*aak3WwEpnVhHqHmR~aL#i^`D$RQ3z3N)VGi6$#$|$TWHQz3COKWA9O-2yq z=Zkol9WuFBx&i&3FVz(A5}4?U7{6NGR9q^4gUP8Q?Lh299P^1Pm%yrObh+Z!PKb{ zt2(nm2gjl1`7#>zx{Jv_rhUQ4{X`_*D8p`27F$kI&2wc{pti^8Rbq<~E~L5^5OX`p zs4l!}Yb+R0uy}Y1%optg4ee#&M@@u&9!DW1Mm6#VyQt@CISBn7UH^c_@Q`92UawQ% z7#52fRWAmks4l#+l1((w*-bdGJ_FxQ?5%ajnsggfbIf}nXd6^(f0IA$RNxfBB|WuJ zn?+ccm4BW^F?DXy@XOAuerF)}%wV`piO`P>R@-UcXot%KyyeyrWf5BhGg($J%zY z7-)K_(eP;=U3+%QIu=ZSBU*u$-Bo0Bt(`U#Yoi2 zkr9_DlahWU0P%a<--1hGK;QeNzx_yYrufm+)sdhHf-C$_a48R*>YpUuYI6#1vN*dt%DnZ@7>RIS2xz}XGeOd>qKE# z%~`W2uJ0-a-u91$d$NHV&Na4c{Hkd>MrQMo^)$mcd?nV<>Njsm6?9qE%-GB->|a=jW&y%F_1?s`w(QH4s8x_cb*0nf*|fY~ zgflK0VhSY3tk0%4^RH#*fOu};3n0$qmsP6M34SKUF@70Lr)XalpPTR++_!WuA6 z^J8<3TjiVKQ3FlmbemxURE)#Is^L5JbzlaXk4*k7mwksj3=E34WIW?CLVnv(AstM!PiIZ%HElW7$toP zOIP-5{2MGfoXtaZWHV|pTL%W89E{jrlg64T-PX1C_$Kc1titkl$5C zdG(d66t+*6b=9fb#}|fBw-O20!9zArYYs60o9oa-#)V6b#WxiR+jgE(TIaS0jfPEh zYXo0@$>f1u;)WK*pUxp0^?FQYP$R26D)Q%yMnfDhg}g~*)35>}$bTRWUApHE1P&#l z8yEL%-a_*1+E7`%YX?!L_AI9j<#KHwsuz=r{v0+~lbm#gNG zD+FwzFA+?=(J`9vz9oy!#GFW_vkFgzwKZvIM=Au+eeTzsM6oD(8ElNd(;JTu`EVHIoNa~ zS_N`a4QI$wEcI~CYx2R7+6_A8Nnb&HJ8C%<(sE6KMzG$c5<49ze*1LlJDlfc%~jVQ zDz5&}jOE($imzyUUGi&JXOE!Iojm=hqBfCtpx?R=@4lk*Y|#)p5+T}?eouwg{CYE& zqcCxM!*653&-?mD^fW3IuWaej1o8@3f7s0jUo`No+$uH%51~^QUzt}{uo|rcein2I z-Wd22(xUI3TPDAwE>^Hs>B;i?jQUc;wHuu;*BXX$J!W|5j|Q(i*}O%MHs8TIn?&VL zVpIL8UO&;^WgQ=e^&Z4|PYR$4`m}I+c9ZZQM(^j=zGWak+pHu-F`6D5*BU%jb{3K- zRi;sDd3KmeeiUBZDPMxc**s9hhs6cxd4NAjL;p9_#!Gwn(qlPNZbkp>;a8nuwA(t#?4p!!-IZ@ljdniB4wlKvn>`&sz& z1?;j~xCsV*=Kg9>ZPODzvkl4RdW3gvNDRIE^NtD;xGGP`KWFljPzgUZ-uI!*B6RTw zKJdsrzEuH~Qc)10-;;kbh0bqXn{?u8^Pv^CHGSKs&XvH;`_=k8Bf~=^|MG5F-_E3R z(V@RL*)K;DieqUy@DzoFBomBc$;Ljymsi(`%oH@Iph1)S&xEM8lG|2I6kc+pwok#{ z=6OA_l#`ce*nOcp9$-ZKsv=sD)@^8@W(ZIl&rE zG}j}RDQ060lM%;=43Q?ysFtJG69#jr-_>CV7=kF4)1=;IQ`5F1sGfE3&YlV^=R8w; zLhua~PZ&PK@<#Y98NdlFc;ucblh!kT?f|Px?UP2MXK!QzRanrehuBwx2JP5!eic z8bFqA)yXcU?jSW=Lgkv&93wTA(z<(mOx2p3HXg}c<1M=GW-_mMTpnhJL?OR+F>b2% za*}YU7CfDhixD-vkAxdlX3NLP)C(}1S@ZE)HNVH29Epz}7AXl-Up=?GhZJH5u{S_6 zPK`HV13*o=&H^480Bp%wIEZZQ#AbFvF&$t{Q??q$ZiS=Wn`FCkTzQmg4J)_zA$!)d z)a&V_-G62hk@@AinBExyxPM`t5hnpa)l55Q*y(EbYxAacN6y7r z8UXrY68l1tCQD@d7LNByl2|TBuHa}F{5<*)E;4SXoMjUW7JkWWAs(x#*t4Jh+s9$H zJlwX|X!3pXoS2wCT-Lipwe5Vr^eHmG^wInbc0!Zw@Y5qWjvbz>y|!5T_>bk=ki;FX zhPR7s!UE+mm-TWr2T72>uib)o8)F!fegwf(PZ?$wvSy3X*ky=Wcu|?Wik|}_ix-+U zP3CegTPDa&oOlqFePYJ`qVuLVZ6p@k0qvgLR)C}lIE!?;6O>Wr7o+i8*lkkp16aR= z#T(dO5i1YyJ`MQKz2K669#s0|oV~ia5Ls9xk0Z#uLryArcuU8_mZAglL9=EBJ86;i zJX^zezLd<@;sf0X%u^7HCp86PmC?Nmy*grW%$`jqp5*#ODLl&c;<-L#_6Zlfr0iE` zE#%5;_B>Y8v7#}#!x-czD@RqCGKTH+q5vV7^sB}{3$s&U3U+?DtVhD_e?N-nX%*^d z^K>j7xxs_-sPvxJ3V05T(uNAG!Vn{B@u@T%=s<~G^VObolDBAHwVc(zsJl_$& zObc8(nM#*t&D3?GIB8`f>$r^UU9r{-_u0g9hFI7m^VniWT)Pu+j{7!UK;c23erO_thZAWC4Qg5NRxTQKE7L=CvN|Ny*R)2Onc5u%L+z# z^?O@!>l2D4rG0Llq{^d>xYotR;LkAS2MQVgO3#(K)J*Lt+-4MMvLgh8O!~j}Uyx`= zaf-HIpsBCQ+2&vDXHyt+2ED;4N0X}tU$EMMynUy8jP~`966s#l^k^f-O)yW7bn z$PTgEL~u*j_(=+P=$4lHm8z3qQeXfoN@eiFFu$hW1X&VEBil=L$Ttkzc!Y82#NyZf)4@ z=h#fGH|DoA{KO|v5Z~0n4$v|09()i25a{kPl@Zv;H`sr+ZRgO*+?V_$zQ+H+Yt;V@ zxF*dc_&+>G%sfC2MG`WCnw978W4jnJ(0kYohZoSF05^C&WN(^ALw2hAeuyd!Y5+ zY!c>7ujr=pv@5skuo=dV*`X)Dr%PFbIu%w#qR&N-J0ujPo08VP_hGX&fOse^l8h!B z>0!g~U)wP#8Fxdf$f!g(Xr2;WVSCgVtPaE59l^ognFu`W5s#5#(g)t2f)^M&S?; zz~G=5FMy~$E47re*PP$Bc{Z^aozJSxT1O_Ks~~-OsV;PvAMjJOX@lan+FNBimmJ}$ ziX*6IqbYaKVwIOj`TXnM-qmy3qLu>)rFclms$I}<*7D=HLieV&9j)Pa&~qJ)kaBK2 z^osHuG)~8)-YpV%VMiqY1048E>x#LI4~Wr8k&rev9wIU47nB@`W8#AgU#g*t%U{{D zK5{#&iEPf7*wKmVOhthE1DpjGYno!sVOwSQ&bO-q0l;+vBr`+N+6tib%#p`#{?xuG z`8AdywVf@Qx4!RV`&vVM{mdUMuG|j4De#TAO%k-o2i_?-@h>_Yv-qEmjZa>0krif8 zIRy=uKYos+SN%!ZUqp0c8AHV(vq;lY&k543DY2fJf}|s)pme0XNmDNpu{5Ijgy=~I za>hLy2QU<{9P{YeD6#CSXtx&dF0G|~tttvjxbK=2_8Q(=S0#QDDjGcg#5a#Xl`{#e z0}1L!gbMDHVU&LE6;G&eZ0A8HKHM7zf>9&r$y!&S&2lU#Pm9 z7E%WW^h8?eR1@9NM1sUi>v!x)@X1t0wuE4p2-63L2SVhMoM1?7p)pcCVFG5dp(M5B z#CQ&Jjv*o_AYjsV(%V^{^=4P5fPWc0rNNdC4P0HvXL{PH+TKh#rz*~_PuyKQ{xfYm zSKt0_Gn3|de&8C@*sE7Pd392J&tWE;hwaZx=TP zt^PxCkhdUP?k+1&?g+hoZtpb^jl4yEHvQurizjORZI$-*_AW67>MCv=FE?Q~h=@Ez z@9$#4l{IN^Q)Wc7NtXnd-8J?a;i?z5GZ(fy8@b~qPp#^1kjvX{{E7uf{ud5gvmUK& zMP2^1Sy;G_C>T6wSnQpJh)}hN7qM4@?Ftqcnb>9thiIP6n6BjYH$yUSlhE}lSF5VN z^Q!Y?y*_Q+j;CpZetWsqvZEZy`NP?ET4ntsz{PPWBW?ctw<>WyCgJ9xB5c3xyEO)X zxk9&E1OfqOiP4>N)tuf)r@nkV0p5Q#0}uTqQl<6LN`hTseU-B9Bjv}S7z(q9U!uLhOMfA08YiLGScoj4i7Fr6(I8nvZZrj;L++`R@pxzznmp(SFE1Q! zau6ogPqAKCKc;G6$?sP{T^B$P4&J)2wh|fbr1Mv{%$sU{rHE(OwCML<73tHeJY(JX zxOPG}8bG^YQ`x5{?A2_(A`eZsjpz`ZNird*(3$aF+q=QCh0rF>ckQ?8uF# zBAAoKgeD)VQa?w^P~Pua@nWJ-S}G5S)E}O?{<(@fQ8i$O^~oJ$5#{hR+M_6inG5~5 z-49$fq-BsIr!4wmr00kHN|3!9Vu|a^JgH6hfUdy-U`<ksSnjtbN-_yra4Ml;}gviwmLRwv!}@B9Q>PS@R4U!O|LXYeQm_r z=2+G)9+6!Nj@ty{(g{NQfR5{cR%Furff1I<13eSIPy_EOG7F;E`F+M^Sn^7cuBTvGvZ-*a$_#KQRpd-lgu|9 zP^5qy_4loUvc_w2-?>NmxMNzj{sLol;F9UYPDx--?sn#-S;r^w4j=z%xdBuD$1z)9 zu6~31nc3kA4D)J=weNoRGzhhZYN5}u`_~RLk3HZ<$oaE_Qv;uUr5 zo{z|Xi1*HrkBs1O=D-hrJcx(Vf0W2GurFTyCHdn|A5-=>lc*E_IqWgY9n^g2JrRH` zHHj^oKjZjAQmGj3Sl$U_IP{)EQ*hnktJtvb=tFYQ5Ad24`sruPnzYQ5Vh;Bn^l|`N zC5b{#KGPJ+0*^3`J@^F~H|8|>MHwfVV(1@T)HqwuFDH;krSs%{HFN}BkDZuXG$jv~ zq^BF4$fp~e74O!bF1|t;v^)+fWhid;Sv8iJvtf`FKW7ry+-83 zhw}VXg*xcdfwF_tcb;nZpq9OVV{i=-^b50!9_~pA4kkAN$~=D= z@egP|Smp02^$(?SkFk13qxd|KJ|chSQF~yTV{N8T^iq*& z#VPb-;9caayn!7ld*^D|X(_r9KglJ1VX$@7i~Od|;4cJpx15ByQ7#lwc$#a>;tPUu@wVbQLpJoeLN3H&uX*C~d zz+JGu!}h5Hw2C+ttr=^?c9UJv&MC=dDqP9VsYVQ&vf17+3KXXs1_h?&uT;>G_PG(E9;kWV@3XV#&9D$uH6LO>|zh9+L^_93RC1t4-X^J|S%*t>N zDf`q4-K$iLn21;_3U!Qiz*G_l4o-iTQAo5Q9GO_ z7GI=+F%gs9Q7BPAOJ?9ERvj98#>tGc-UZVpmK|z&>Y-0oDbevKKy#9*I%%bj^+~s6 zrD!v zbrpqFtc@k0mzt4?Yo%w#;9445u{jn0|DvCdT2VsLFQlrGF~xY#WmmCSp=1rOq@obZ zsE_5bghA-ZK|T^0>qGvI5Tiny#5NCt;i2*tT&~B0n5t?fl5DN?&XZ|h(N|o(-(f22 zRCzgf)OB~br7Eve&k-YMOukEXQai=!r9azAK5@rshQH2reTdbwME9?*GV4n+!mEu6 zSd{6kWrWzf;?flzsLfHcC$PZEoW%MoShz(H_|P-9@-ecU>{z?R@Vw;d9>j0X78UKv zy4@y(m^KE8HjWSVj9l^) zxOYUTjq36-_a|pr*!s}2%z4#oniM`}T6oiw&9Rct9lbb5L~KX?wiPkKfhmb`>M&F* zTyQ4k^3{x(cFMx(oEnS*d6SkMTfVN?oNJQ{+1%H3&G43B);dxn3;Y3tGkSwATY`6bA95KF?QjmZG}&=4UwC}23` z2K$R`jk6U1M?hVcH|$&975vzVC5|JoEZyw(T`x~8v4ham#432M$*!$Bi&2sZBW?@Rj#IaUO$Hug@x}6dR`m0}z zXbcM2SeOfo&(w<8ON9yDln^O8rv20GJL_Clt?J@pb3-nd1u{U?Nh1$StVjVZDRpZ? zu=C(i*d;5k_&UHOn*Z_?Z_Lhjb*tN1l$*6$U$@%eo6&BDgCh+?Hs%5j?taW#@5-FI z5(R9nu(Z4=fc8OzP?9S|3-BhkDc@MJ=GeB_0xQxX3Ie+#KhUVRw7I!ABQIjF@m>;P zvOl;!|3Ff<pzDTI|>gT$-Z&b$Ov)~Rlqj2o-h0nbfYI|YmKaU3j!GB{hxx+ z{NhgWL;J-17WlZbOeorxto%su{u3O0dDpmNF(?*^d^k`kGj4qui-er-({UTy%QKl_ zrHI4Rgk`@g3YTWY=*24&9=>=?6#Kc;L1bFj!6BwV#$|47>BlE_GeBweS~e?&Dd0z+ zO=g{`=`6XdlgXNfv?+%X!|8?+05?Iv=o=IT*(^PEc18ZWLF+I2Y^2oXjm!<@wWDFh zf+df*su8L13`VZt!kDfbB+92^kg735*U;!^XiGi|rzs<&!z?Ar~JSFX{9GkOX?=05`;QVB3D-Nn>^tF}J$0(_bf?}bgaAp+T!a-@Ep_6nx zZP4Z|O!-L`^fXw@ka7g^iDQZ`g+C z>+Mr6l9GPo%SSt4WO(^pu+VDvWEf?;C8QuqjARika0xnyMOg3}6=R!)o9$lB&K7?n zhj8oW9qt}32-An4FRbBlMGCqRdL|BT)DtnWyj(j`u&Z*o`Z6|lV?m9??vSpa)YQUT z)tFN;cQ8AB*lOb=JT}4(b*7Maa%k6;#!u1il~^%16vMY^Ju~QwVVQk82+|tJOWAxs z5fhc^>#?fVL&6trBr`QZ0$M`P`6G(u~8x>0`%yBz%Ej8+4ua1i;-pHNay`9?@v34R1kYXtR1!?La2(ioY z3mgPr-~x&;``7F*V4zuIf4CiGWGCc5(p=UK(0^vY2@zh6f{-#&{a%n67y{tI%KH19 z=N4q|PLXi}kWUc(>5?aQA#)pN_Mmj97VaQC2NKJGo91~G8D4|2Ri1UH8flMpRi;vD zLm`dcHQkt5+JU6NTk)B64L>nmT%jwOVqPOF9BcMKb@A?SQY*yTD>W3A;~Z353QLJL z65@?SJMgdLwuA)lWpS8CvQ*YOWS$q+NqVjPxCMSovqiq#xAN#>b}?zhU{ zSgDZ~n|kP~ksdgCw7}NUOj?IKQX$ozsj<*uxzHfbGsA|WL1DoM1XcHccN%?LG;lqgy=t+Y2cw8I5y?LoQhY1$0juSOH>YIVn)-(0T->KoEb8*+oy2U$7t{uX9$=`W-kD#z(r z3}Ri3>D{tPKpdI+ho96dlvl4UF$Lyg1* zX*5{`#f9?UVu;zvtN|oei?L!C9$hfd6R!G_F-K84*Gh*QFn_8dIfhDgEhJM%uH%9& zL}vHlP-Zt7Hu3rawPvZfSbUFI>M5EBw-c{XPqfQFFXn*ranRal;L;Z`8OQ!&&CPm6 zx~MK&p+0G@k_zcM$X~`nWfd8rRBxJNw9b05dWWXiEAJguJDn`Wjx9S(lfs?d;KF`s zEJ73LN%oA=Q%b`u?fpwAF7Cl;;^*@F$kW=Tia5K6l__>rsW;){;{rD7bP~9yO8h4HVQ@kS~Y5+A$=)vr5*TjY5q#;}x zFn4uepJ|!`zS@0FJ;kVL$3m=W*Tmcv6jUTsVmb*=;NR}|)HrXGnU)^#>N8EfnXlhj zvd<_<>?IVw#*k8&j`ApAQHjF1|3e4^mB(U}ry=tL+K~s^5D$^VW^(aUEZd=$8!$*!IXZR^tS5|MG1{L*WjQ+Vvy(V8!hs%I(v<0FmDy+YRHi!`U0+ znma&j53k(f!|(SoM9AO30ryIRUlsnkDkZ!s@N7?8-s4*jc|T>q&!@O0?1>FKG3Jpu zb_~XP`SJTBp${plg&0?Zk7|O*F`!Va9dZn_{Znkk+A&)(j=UVwuQ&W4+lU%nCE}Te z-{-#I^GU-SeO{&F=`Xz@^@f#ixZcBmVu5cmzl}zuvJyw5z7eKPn@8(>%XN2R`~gQ7 z7VD!H($xUX1+4*hHH0?1YYvzG*Xjh40R^HSoD2GtC$~Q>zbG8b1Gi@O(EQ(m1`OVz z$?SeRGFKpKK8i(9ETZZxk`CE+5J%1c*U3K>vC%nrJTlbcA`Jw*5|6m;A@CDQl*H39 zI`8QO-6vcwn>Ev!T`L_BQ7xfJRZA$U<>D43E*%bO`_+43VU^}qN}8Zq1>o7@S@MP7 z$>R^fGPy|gTiNEIGHXU}GW6;pQqJyNeLYM&q8sBLbtEug9reu&I=`Ar`U#*M<<}3T zgLtswXAEHu2AFI(1+r@5F>d~tqC4`_H%}SOMP_*xqOsq1s7HpRy%%e|95`I`6k1?s z1s6}=uAM2->hjP#s6VpQvfg|6txw3?lZs-wQlXYu!N}sraljtsp69(LVv6n{-0?#VNxez-R?V6 zMbwQl4@pv|MzCLLX~xtdOOl+^Tyc^P%PA>_EZ4Yb(&+(p@#pD*(;Obt>(a1YK1a9a{aI^BvBRLBTkd*3JH56?+i#14F4I@bagczXn?&0p<-AC1I7V^sUe%PVz4)^LJ-_7 zM?82~1;_ssQQ{oxK&+aH^dRO>7*Y-baZ72Z%%~3^wc2->&OKEyRw(Unx`OBa;(UfO zV0YxDX_%!$cvP6Gg{y65lV~|Q)6pLcr*cMNIND`2iPG4qMXGI9C(<dVk_%w6bqA7BoQx$+oWrhsk=ZiQvnA*4hq;EBAfs zs=?(2as?5dIXBai82X>k{|;q-LC*A(C;c7^;*58`&{RzM^zTfWc%xE-hCo#^h>zr% zSCF7fPQ+0?5aji2NcPc?^VE=i)er|eA?9~eKyp)J42>{mPuYV^+4ZCz)r3w=6Izro zTo*xWjx(E6tSqLgETpi2mtD~D$~{_$Qjx8j2lh&`I)Po9e@87qsEGBGg*jzMHRWPu zkdv)W&0K@lnqpIciJC)Z6OdlB(;9)FBfDVGorqn4euAwrp`SOsu+C(aagGhW_%L5*bYOH!F4o?r4^uel0F%0OuskF7{?m~iag7h*ApId5)^Co#HMCQ z;X?b@=?UoVkgg#!M^Nd?@qAVOz`Yem_X6!A@qHNn3D_?FJ$KkI9H?Vssp&hx+mQEc z^?Ra+Arkv3f)*WzAuk7IhtvY~J)$X(N_E<=RE6_BL+S9sTq@=N6-u6)@(U+FryxW# z$ewGlF{L;|5ygJrB^$w#L_b0t&be_#!0KnmkRmd@lU-T4Y+?!5FKBl9|8 zv-1JRwTCNHF6h?MScMsN5|=fo@7I2zD?7_9Suy?~QC%w1A7UNLJB+);jvfs6Uf`(q zjH*{k`+I}0hPeA9L6pt**n3A4R2FAaqjPuZ>8XyMq2$wFe>8t-0WE@@)WSH=6(Hq| z$SP~7W2C}eZKFuO)08?IKm+nT_y3_z@c$&)(a5+Cq-SJCn7Uq&znCe|^4-f6P#LKZ z^AW~IZr+$|k!~vW)Q)vZhR*^Q(3vvlN9Q$uoqaSi@sY%e`hR0pNcd7hl%vpf!k09o z8Lo$}HG?2^;!Bs~)R+{+7@g$n*_3g({oq@RVOiw_5EdA6bH8$n1$kr#JtD+zpkwxq zSwaykaE~nzrj@f*)+wwzkvtk8B7cxy+`pHWFva5&qvoLB zk#%D)*)dJ&@wcY~uv`joc)T1`BufHRe8^$%4ugMd+5xcwcakjiG)~z1s{5tboH2D- zT3Z9+3*rSKNek`Lnwm(QG2U|j8bgSGUDsKh9&6>O%@O2`2 zq0IkiS_d{EQuGNVHt8;{F3XR!yI!8pxhKIEqP%VHwJV zgM0YdUaHYeGvhr61KE>^tUM!NPsW6*+e056*lvX$zh=U7l86MRT*(O=3obXwSlOI$ zoJ(Cj`EX4~;XOw)V7BMrY^>NH)y2|*mlV29qp=_BBNOW~*Mwl)~z{X0_k%(zfa=C=51UGAHt+PG3$xnEr^uB8C>EV_Limud(+ z{W=vXyt^W`d*1BuPj20Bsa?vC!2voo2Wo9wUZNYi=Jvg(sctKqpS5^^75FnU`xd3g zbi!b$U`(QDp%*m+QOts4C~X4KhYXQ+xMD=m`ci-S9s8hoU_|)rnOj>(q5eHkD8j;x zWlh{S)F_Uzy@&GGq6Z@z0|x7u%)`m?=a+j2T25}n&p#eF&Tl}ew*>{?D3!w=oH+QH z&4X_3!%c_PjZ1%>5fqO|WQvAiTCp)d{xxKz*Q-XIq90FaE~vF;VEQ)=ORt67TK?0l z8unOjtkLI7==Y)?bg*IM%7Nv;Rv$@3NXLqe1;C3Z8JjloScjp^G>;`W@eVdHc8$ia znng{$`3mE=@OKbc@mtNnjYb=@j-XgY)2rS0%{SH{00mwDLcp|g4s0JlpG!;kLoNH8 z$~MCf{!j%%D|wyRoWVUJ!Y^+;3dJ243jCm>Eq`@i@>T-4NK1uw8zC|lz!nX~gn@O+ zW!Cven>KdCBu(2et-Ae>tE<{+$a?eGb(?IoPUDye=OdJ-&p0ZsW0>OL6$a)bX5%9Y z_`8&n$gMc;dVm?jk6BWD**9kvFGBmFJ5AhW8^}Q=< zB*|4nIPrimopVBx$YbsyvanV=trI5)A;p1cZ9XJY5-NRBJ?T)09N(#NX_ovrk90Pv zSg>iW8^XLkBNT{wjY#2e)sGCxm5u|g)RB|(?GNKdrW{>&MoTE*z{QCO$-bf0kDoMd z-M_8o3-tQ@x2s+A@Y_DGBXkjf&~VtA7+Tv=%AlJ9bEr905M&rgG4|y6x7z#5eqM(_p=2`5=3)(@P;O1_s=l!i z5VLNBJQW@^>NNK6-Z`X~xbMWJD*IRw^?1DSxis_-)Zv+veLS0O(?EBR0DaH{<{T%V zq$Hr%47yj)@tLu_)5L4zZfQLalJ>dk?_d8pfX~d!ZFT&3d{2J{agP6L09R2Ev@^8v zbhdOBv$SzBb^4$2J0%fdkE4n@?9cw>VKd`lgYmPaQ&8fwDrvEq?4k8WHY{oh!D*{i zCPtQW5y323>Nt{cS!}3Z0h78#*ie{dw_0x{5Y9{cit~aYAdwFa;0TdO5tus4`4Ra( z>-BK*^L}4J7=%s^tfAF4o?g{@_lK_3Ts-{H6q@c~DRT5D9{mp93KjHpQ{Z;bO#%Gr z_g%tubtFPpyvlm<1eXgQ^0_c``u4Q(n4j6=$bl29hT zITxWi{rJ<DY1oNI$8Vo```<^DpK20m;@H{6XkmxB zp_&MX>tEJ*2(?~8Y{y&zOzZki=-hdCC3;pIyJXw0!ybV$EMd2%N4mRQ70PgWF8xNc z?z`|Qut?-yVg%Fag6{>u1b^A?VO7`@zYdNeCYH7TN+$uage8oSG;{I1z{2*77rJ|2 z1lw=ViCit*mLw&0gS?L|szt*1}mauhpf+Vzk7o*VIJKT`_+fAFlq);U=IG z73x+VU8fQywue{{68sf7rs>^nY5t8>*hu4@?X{V$&{6mkPmV&ZzO}zK3JA0Gv>0FT zRnM3UwcSvmO0n3e2*dJx`($0>WjYWuHN1I+0R;gujRG(uCC6dkyZIeOoyDFNN5!Df*HSz z9xyz=noU=7)O>fUVhksA(>|^4mYj#8J`jVxQ?Wh*-MWq1@+tWdbuNi9?JMI(AS!Khr@U9o6T+cjsu?cRFDE zFVlgNq5ik1x2=tngRRy7E9N#G)|F9$dM$EgWc{UNk-NSzb3pf4a?5e zot>Vvh0msDr;J0d?i2(_X!I`#>%NaA$JWqZV@oTP%j;=Ukc9ZqRJwlF1k3C?TtEy6 zmTcn=QZm>jP#`#6UN(97Ff_v9R;kohZO$mo9vMj-Uo2x?9D3)u`|V3kLfr#KaLWsk zhi`Y(MXCv!1(SllgN;<~LGBQ(yrD9iYHnxzTL)FL`^ig9hOHy}no{cvVQoKCCcsi# z4yKE{?B5rg&YpMP+Nmq?p+?^G%I%}xwO^kB)ipRiWK)Z3lk<)xYDz2Rq!Ih-y7!!U zOOU}-bBc8Usf}9eP}bl5?Iu`0ype0@q&kobKnK0_;)VSd(<6$l^xg$KnbIDz{*|rN z>Y5Tgm^pT8WwM68jF~h`ZMP#r;bVIL<1*jWKWzAT6s(IXYsj{1PjK3+l+_(ShWD7X z=Own^eAv_Xj(JEy-JG0U@(N4cc4f%zvbEQLeA@Zpflo*yxK~^w$M2H#JYm{R`w-z72Nbc@IE7zO zfoyt2kn)vZlCLV@T9|~ebhoT}kx?qUqKN!0D4)*1!BOTK3vY z%q{Humq`8I=Ft6DzlFY?mA;|z|E!Hkx>j1Im?1gK$C)@ehU^j%F%k`IPZYGW^-EKl z7uMzxo0Wh|PKlOAzhD_)nRk8WQl0QcU^BAQ8CF?~NVonMod5+pfgek7Q-sVKNo*@f z7@HBtSx(Kp$u*Vn|AZ8EuWemPj9d_b4;^=X7q=F;m`p^ z{|*&>&V<@n-i6%T85}iY{lRk;J?pl7X64_h8mZZs0jUbF0YclDJy$J2C`}6|zVROc zY+UbPT}>D4L3ML#S$`En-IE-uI;eV%n#QFpx8TV@iB)JKZQvcAZFNNwgu0HFyNbsI z37HP7b2TDwP$k$xuXSogIQ*X9qu54@ zzBZRnn5BTT&p_B;w+ZopwpDzBS37 zv85?R*_9jX7Hq2Wz}a_Yq0xP{9Mr9>&}E;!5bPQT`rm|o}-QQg%+O_I%UZrOvs8#|ALfUgRRav9`yj0z~ zY?*DByHMKNX2){Sw|1{qtS-ng-L((X&`#mO;=>vB$kBO^^LO5w7Nva z2cG$e!(>jJl>Npf1Co)=TL4InE5_J%i_!UQPQ2z^S?ldA=HVCUC`m!0y7>dlrh`X3eLiV3YPTb}EKD*{~uPx%*j5QEM=v zxdQ0gpXZt3${pFNQNS(R{$XBfqZa=9UbuVO4%^{Haa1W7-D{49wP+WMK(k_L?;}K*=I*c zGmhLRj_uorWps|>N_LL1z^Cn^Pu^M5-80hPLebxQ9=*V*y+*o!PO(DOA*go;P6^A# z4h$Z_p^q9O?IQd=d(71-qtc{94k@?H;-{gTi~WojOo6~MyNf{ zZpUQ{rW}QigFW%Avnp-ZzY2aZzH7RZO}u!GZx=Hy8@oTdA` zDu0L#L{hxn`Za?6gR1B@QTx1hR)&o&$fiEiEg0mU=*C8rc#Be`Q^>_tIV0GF3xVhx zNHxbB{r6P9!S*o@A|OZl5?&01;LQv+VgAMiPe{V&UtXK%_kOe&Ry1A`$? zJEVelSw(u&;H;o?X~qNY{Na8&`yBCeh{wgQrwd7&ZTNp%s5eZ)?qGgfJDtP+mtLOI z-_{2D4uV#u#s&`h|C8F2|5_QTd|RlOTz9!&I<2KOd!i4g0g{vbY|KkKHV+lr`8Vh` z@f)%f-wY>WL`oXw^|?DPrCm)l(F)>+Skp@xQz^hf^WsqoW(5o|rhd(aDnyb{1Y;ok zkNRVd2O+2+({G%N6B+xFY?-E z7d&VYL($(yvn*5=J{CiA)`ZbKScXX-cYCcm1`W#GYrdY#R$0RDnY|&oikUMyRQz!A zE7{`kHm@Tkb9`*GJH?Q4SUD0hCngByS0RO)Gpq5jmsWpjR<>3+?gWkT$wFkqb=UGunK0hb*%eYVdeSDDk^Rcmc&$y%#GP&Lr?coxf|8uXq>3` z6%Chd`6!MYo`jhj?1@hwLWX#nBW6>$qKK9wrd0zjdN(e^!$$ehn7r;d@xkqoGrD`x)=UZ0rs8Bznlyd5 z4sS63HVw$alAu%e@g#SMcvXJWGohP8J7buQ8Tn{HgchLBM;$)%2o5gs64bwov|c=wW)_A^i~N^vw{byX zkE~?X4og|sO#@H)@yPJbcXt6hTFkwF!a;Z1SIs@rE{s>UVD|-fL^1h}W**&2LA6#z zV>VZfmCBM!(_p*w&hnXSc`EuVla#um=M^b!<;s2sktKy#cSNRoWIWg5~O*sRw$7U*gemP#lmbg-4 z2(H}Qgp10OG?LC*tg>#l%2JYqb!pFR*;OzI0I)XanU~a=_LlG*Ii-0guu+c{X_HzR zTavQ16<(Unl%yvDNUbNv&#+Z+sWvktFF z8y)VgI>OdFFczHQYpzeMnI|GQR@VEmW!NBQ*ksr&@v2PoX&kmsDCEoK@cFAuQ_-dv z90V|^Y5OBa&Dyf-pgIdLvo2AUtiA|}FYDZg!>zetDu1FoO;CN{^Hx40zNq7uOL-r9 z{*B|?v7s@!Wg1B`f{HWr1vAJblg%zbY0V;%KugmPqj|pJygC$2b_%86-eJX~tjebMzPPNjL_P_9;ZqU_ba1h9`Sa%4v^J0^LuA zk-1<_TxT9YMt<~alSJBh0l&18h9&;d38%2C>ffd%Fsrkz0$Ce}=^+#LyM`4WG2dgT zJ0-SzW}Iwec7E3;zQ`#PwhoUp&=VJxddRt5ivq1}JXy8&0lbt3z7S8U@P)dGOX=(eM0t7tM{I*j!|t6RD#{oi2vm+ zJyaJ?Z#qP%zKwM#qq4UOnXLwIMlDU(N~t8^xnSqngbmmbvoLU6%(35|bvOilb|jJU z<1v{w{(yHJlsAd$d1{B|=~F=k6Ka30Qqy-feteuzRtIQ!A2FfQw1pzYJxQs!!O+{z z59_XsayQr6)W6)9PGbqgW zw~O&4tp9}hPgn(rTe$7^y?3NU{PBbOzu7;^{1N`2p5CMs7^{p$)RDi(Ytj3I?woCP zS%m`JLi5EE>5U(nZ@xn21l}ap@nizaL)DioKH18Mu%{AZTlhHBrFF?#&ypWr#s;)}Gran;@Wf>yBU-ZNEzSeyR_xks zN${keA7hG&^UGRmtFJcdTcV<1Wuj}=H_09zk4Uz?K6MpN0fw9@az!a`Lv-fK2%_-UK z@Z|2SsR~dzfYy3E8^2T;y&lvAuxM-PVDOKnWlM@^-~3{W_cEJS$;5(&tm99aMo4$h zgi~dMo}8p&%c*iX+N&3hEDfiq*p`CxbRa6N&ytDud0>9s?O0g%=ckjdgOQiISv7YI zyj2S)jt`q%+Ub!)pR-=)s*V<@^M312dVMtIxi~$0iiuzmlD}khYHng1377;-`F7!k znUW0)B@+!x=5iY<&)DqkSmRE^wfFvMVk|pbS~Ji;GVW29RBYc+$=}uLFA*yaF1snI zqyHV*T$#}Z4%WP8NAB7bZetBf;WmqfD6)CpCr`7~DEkOagPX<`;wE+!tZ}x28dcr) zR{QF==0*Wr_?iBT)X$7c!Reso#F>Gn$+3rW$#!OdbL4g3Dpbz{mjv*|dpc8JjIN7G>7f{+6O$o@aFi>7xx zq2(i2e(YBoquiMOqR2%U9g$NYaSR;m(m6B$ z!#uNy@M5-a*rO^6_ml(IFcWq42Xc+G{>JZp+<8NFX4kotDbR|M5XP0lP6BFE4rO#X#@-|3&r&1B-$70#s#O-mu8nsukACq_@Nw0?UPVP zZ@d_EOQ=`khONpF4O77Seh%j9Nsg;P*^W-6rh4!Pzn-#%ILqIS7x~w^h@J9+`!}3_#2JALG`Dks40`L z3^$*9oVW%weqyN40J#HQuW!BBK%g^j>i$eywO+P!Sw5=S;E2P&N`Z!WEF84DbgreD z{-R2K+LVUisY+97?3J;@hx#}^&DD{`!nR<_HI6~F=-MRP+ALGEV^}V?2;9yo*{!?; z*VS=Pr+ZhITRD%xsV2p7XT^a>2f_|xL|(-aJo9|H_Rvuj1;{%anN|6)xHnB>D2drcVfH`O~6;@#jLWo5q8^wuM4ccS0rfjW6QMd|P z90khm%IG`PM}n3zu{HoN5ce#^O9l71*2Av``*X~i#w3Sk587Wj7HujCbXHozR|d4~ zAois#oIo%-G-C=BYHUDyR+2U84kbWahEgm#X{v$$2SNFi`vYELH6u>^?4dYvtHY0Dwt zM=S(fkct1)T13eq7boOiguNgP&Cy{UL@zB0&p~-9B{iq&l7BNwA4S*W#spXa+c&T|=l4RBI=GY%iP*O{W|0FYY$+$s|@B^gV9m$9Cmn zM8~);ttBgCbcLj4mrVXl4ij35fn+X!$B!MzpxipRG!pxge{Gexd^_ zOn^mw@Amcqw2Fo97q8virs=BkDkYP1>6Efl0nsJ4)C^Wv<;qRj-owDk&)^3CYs~Dt z3PE&sE|q3{B~vcFMCJ{%K#GD>(JHJxT-bKEb~n2HF<=n0V_fuUtaQlnMYvohT42a% z&Vbyl1{fhR$W(Bt>26i(b_m7_)(d|2e)!jbJ+j%26`_rR+!SK|*+rd3qN$&4eofQ% z>Xs?)jg0n2M9e$Iu~s1GxX8u`>Bck@UT)BJy&tBgd#Eg)33|-TNCAm^BudQv54jtn z?PKHY16I7<=YPJ>oWmji#CdpV`LYv!j1;9K*9YQDG1HG)$c~fw5M^b?W6(>c=ZvSk zq-~5#Ibidrbi4#@Oi$eL`cO{ag?A2C+(GxmFTXZ*_SqiL%8qh((p}$by+ZUPz`F_a z?a3sKXpK+fEBo@7i*BiEy(Fvwa~9#YlzIOR)w{<=NH7U)AaROh2I}Xq+#4k~R=Cqh ztzqa+#G=O& zG=M%CCWCCge!g&PG${ zb8wK17u8{#N{tVOCfSbi{opp7!|Piv%ZOU&ut$Yw$tyhZVn-~;-7CYpd5xDD>1mt) zLa|=;zpz~wra%|@i{Y}it+HUZSO91tsovpuW<|!Dq2~c zY?ch%D)_$?fK`1G<)u-A;VZP$|v}&1Yph%+H9C_q{hagkoMKuJ5!QB7?{I$A!W&CtHsC$7{24AAGm;@)2n3k3FCNynx-;cdvF zV{zt`&tL=>L=YjKg}KkG(2WY*Xg_5_C5`y)^ps|e(9s*|mg=rAv}5OatYtKs)y)qY zwww&Ip#um0!gnBbu3HrgaW|H2Ri!8acvH>uh1e&F626C&(B7u4q8lEm=DKAP4XNA& zP)qlfv;(T{*jK?p!`&eP1Ok#JE>D8*xTUqasxbF~0Z4Q|xh|3(2ja^={ue16IYEoK z|J@@Z`R(=0{a?LNXDcUjX?=HN2YF)$Lu0#dX88ZL`NdD$qBvs=^IroefiB!1O-)rr z%4aSSA0n=_@{(HNMVqKbT2w)3=F-fYSKr0thM7m*+Te2_+0>P-@K?mZ#Sn(ON zPRy^LF>my42f3`wEUaW0vz(Ki+s7Y_)9+q6IiGHKxORc;K?UyA8ca3T8bH*F)XuXt zPU;q8kFm`21DcTvm4y4Id{fh@b5-Nn@`K8HHG5oK#B`V=6=n^Vtf_;xNB^XICzQN< z_eWx%GI@S}M{{dJ@7sTEL8O8}3IQERxz*@P85qg0-g-gYSqiF0|1;}Vm0k6xzj2u; zSUmG(YZ;a%ZQAxVP!@kp2nv8d&fq`K-{A##PsNz|{byd5CGU${istFeutk=uUb-AX z9Kq@5F^dAc&%(BH3i@Yy6uH%^Rp?XCMJmeYX)!tydGL{hDlh{;9u{t)YoHxuVj~Hf z36_K8KihLvFJ;6^=}{*v55qGW%2o6mzrd8o=;+*wO=YT0RGC30`g>toPJTnZc_w$Y z9jd^>z5WitoISm*8KUjrdt?T$VLl^=!)BSqAsti@tcH|qQbj5x`TYTr?Qg<;m`)zJ znT`&sh|sU)!e`6rUkSN3uDMzP3ENPu^e8=|#TLOTC2zXfNy=huJ)&8fv{WUT+m0~N z&e_mvrE2xn3ByL?ZgMsLZ6L-gma?HqYHECuF9J`f?8SdU92vdCP4)+LyVm&+qU=uz z(4UQcHH>)RqzwWbKj4`lFs7l+auGvch%VW_f`h@eS%w$gDi5E?&4vTqXk5;j`|Fk< zZr|2(kfL<6qMD*B>QW4>Z~NcGVouvRQDZKz-)d_a-%)R?mDj{cps~~bbk^vR>;*;j zd$bG7py2(0HqXU0h5(^OnJEB5Qpkcj!R5u0NJ0lFXmUz(i>*#$KyZlCk4P}~aU@7H z58;rj8*!P^q}V43mERnY^u(}o%!K-9 znjzuw>#q$nYHD|oR;GX$;Uv2Bd_Z^~Kz1%b6xr1cg!jgktTy3^{6Dj?3mjn&4*558 zF7{s{AF|R)qW^cvtn!5NT3BrQdfxCf^=bHL!lXfWBSm&WAWI-%;3KJQ1ZBp8KtLE; z%1p@IE08)k3EGFssM$h?mZKs#7%J0rl^-2iRn@#^;q5YOf&OlFd2ZvXo1=d8)%MJu zAidE3@I`dwn&JrTdj3W}Tx`3&A7<2k;E2&96%Qddw7A%8CyHB3I8ARYC0s~4S)WZ# zUY$uelPactK3p8qT1&wq5H_|seyi|a0T+f>tIpZU+nK;Q`YPTmRnYUiR{NO?tS@2E zSzB0gnn>2>*4p!<1g3BV!2GJTOC@meKP*W3A)DBUIiqRkJlr4yJK}_I?QeNM5hn0=J69SMd+lZ zMiYC)L;SrM7imkbjM~8N;X~ABuSAA>d3A9v;ey1&%u<6|k>$Oz*2bGIZ7iL+M`QOB z0tAw8bA4eWFS%~z)DlZnvKXhZNOq(QX9dcCwPF~648XJoY|7r8l`}h95Y3?ZlQ%TE zRtvd=JImHN7|nTyIWcW*ui{3L1JAFOvx?L2^N*aZr>rfu;J$G2GSm+zb7kt}o4B9RVp zq16kH_W!k-|(Y{h6Q2wx-Ky{kI<2{9AEa8_05%*Qcuv`CE?~Igld)@O@b) z;l;?CWI*AS2%U$tl}Ot1LT# ztotOmd(a(-2vu&FWIM&~WP`t`M-_@FvWLm3<98?% zb|rmW@1LKG=3miKQo_zF>9ZGBo$cnYcTW5W)gpw?*MteIB~NXgUA?1ET?tQw|ILmp z*<{pWjMQcA-o{opf|$}prm9!uzizr`G^tkf5j1~@qm3K@)Y()>bzL74=qdYoG;Nb-6+=uDW0921J|<2+??L)lY_{*cPlS4 z{>^FAv5)tet;YdLnz3Hc`qo#Mm)i;|N?aibnFUBoa%^2=KVDr*$bid6|H7(IAZHoJ7Mf4qS!%d)wB8G-&l734q!|>gF@qFq zJ0vUM=V4J!?Vam+Ekq@MBDgW3x}tnEpVZ#D)L1wmEDD8`ok;5M_5Fe`NCQ4@LY3&- z*bC1>$rffJd*!3W$+`I_r7Twd8A~`5cQW>Pn>M{& zYUGmshigln^u!-%$mhTYlhj)T`;R`aoHJ>%F=u-|aU)&4D1o;OXtUX2CPpU6khtDt zvq^+3c2f<1y^{mfsUE*B3d`in2NiN>YO+2wD>BR&d}t5Nc!BOd10hE5E07u6D=s3# zgljL^nR6mna^B>{mbo+E6!Jl4-{D8m5x{QCeq6JOFrwm1(W{g*nVY?jR(tPhH7_%a z(eAQ*&{#er(2S+fEwAda)pF31)77-hi7EqLJ>hmi{VIYoA**X*ui-k1u3mzzKq`7= zmGPEuJkmwJjI>>1x&-8io2KL5Q-mBA+UPq4#7}NzU*Qf!PuDNfj?+*qW!ubwrkA2| zmFbB`$P{~L`f~#YWb(?OZLs_lLF)u_^v(!FtCO3HKx5uGaP)571i3jA7!>?t(IYKn z61j>v1Jh&Jn!Xo?OUb8s@I}P&J2ZpSy=*7X3n+YnX;g?8h-w|t`=rgxd#!I8U4x899)ayd2gq5hogI~##--c>p3RV^a+^gI){gZ zGV8EzC!+Gl>0#NTFPxhE)k4%p#W;;2LDxbKan74+*l5ekEriXP*2?o?2v=Me1~Li>)g}pPVA0SV3VM>crGfa zrUV1m`FTDyI#9(zA&Arv$FY(aXjWXqoCKUG)?yTHLtD^7*x^w&&@y$!qnNHcQmB5x zN@%uVE;&$q-)8f>mdAlZomcRq?kiDA#+xXVNmTBS8>641n{j5i(~k#P6Eg>EA1I_< zsFFmtklL`C848Sl9`qsuoK2dU`sFLWO8UBR{&H<HxiyyhM+<)Jm}TU&-U=S!_t^ z-G^#QhXrQeUT*T9Jr@^hrqNx`98QusZ>Uz%h^yP`%Bc}$EsfC0a2ShDjBpu7usatk zhFy`al|E#(0_`~#Y!<$-U%)R_?@wh&+Sx?7JDA3-$0p$pDdzt6-ps)|6_@}r1lbX( z-sZzh4%eQZoLo(i?0Fp%Z0rf15zhF4NPA&N3&Gi)!#uNt;O#1T*Tj>rg)88f zndwUg*8AtuSc4Th?O9hlZNxp2lKo;7!4j^V z-md6@jGXnVSr2yF+_VPIGhLEwSIoB@LKdYE(%PXBC~v}n4zz<4Yh0?LA+%u<5V&_S zsVu{3TZUv?{rE|~d^U45mrZlXptelueDwHyt)BBzihu|x*so+Kgh^EIu+{x*|RfXN&2q{PsLMdQ>ytq ze@cJ(=-+vTq-l~g*W2xUvnAG`d6h*a6%8E)4fJJaufqab#SNAd^}sE!&E=)}?d2r( z^b1)%A`H+U>{PqK<9)mkzI_3bZV_jE%Kf^^>_qSayyWv{S{`f5?Xh^_d!2qTfE)gFOGG~+XkfB?`H6GTOnxVWVF2lG$|w>p ze-gb{-g=N6N7d3br^OqZwZYbUnZQR0URNjjhGil-?Hht6B#Jh&LU$TpO=Dr@8ubvi z;>o=!>soc09PEUxG1&xbenE+~2vEknsmt4tK|Dp?FTJ_Y>@)$90zoY!@F)u+ZmthOK<_RiX70EHMD0`?+HdZyPK_7i=63JwtQVQC4X>c@l{ z(h6mR9cT$0{o)EAB2e@v*}+3(+<5_GvHj_Oh8~NS@rVII0EY|}IRGv#hSX4pNv;Qz zoQpkChkBd~p*0iod#)7+Q#-`xqK|DO=#nE4*9{AO2ci|hHXpucsOSa41!5OnmZ7&6HO3$fEqe6@JK1tq-G6zu9Bigwjyl?I2FZ@r z!rsQSP-@V+g{#g~a+>DUW;CDdU@U)=&7yw}w_+Rj&e*>AGA`SjA})I-m7; z-Nld}{%%?=J#mJVT5|H3mp zWZDE*`Ukt;z6q#3%&;N6i2?o5o@!>Kw|d~Z9k|U1*6%%>jYvA28EI~8oyZZS!ADA^ z^+das5Dqqi!f90;Y}R*WbL9RvtD(4s3#Fo|m0#$c>Lqfe*f?1y!)V@H%|xt|iq60M zEKTwLw9f)~?+M=6+uD=TQ58$q2!IV6b7r*w5O9&iKjAcM!o#G5wrH#!+!ib=E}QmY zLI}4qb-~f0C`4p{?C1V)^`C2_`QD(ygIHYPpxEO8_WoA}b-2SD4g;&)6v*&_UPP<; z-_?u52R~bH3547*^l=7Jc>GV@Q0{LqR0$$L@kV~&4YRrlF}tGjr20p#>TgP~@7h3%{%ix8Ctie&vp`g%qCiuNr|t^4k%+mhY99JglDA=L zJf#V{5V#G4*c|k5<>w|JuB9jH25WnQ(T`pPc`cUKuV7J3*xg|Wx$L+;(o}~MK#|am zb!rj1+Wiw9_V6>eT!?b0XzQigI<9S~_$&gl z#zj2e>GWRsW^*2QA>;3MEs0=|sx^ZSZtx8jrw7+?`uAB}C{uguK<DqjS>ANw9%ajU9(%M>72_4u9NjL6eHd{tuqti{HyeuQqtL{z(D1)RkeUKtfl^s_ z(8hlE;qzhKaRZ67QPB!6-UvpE?}Pw9Xs`=ooEwW;aup}a>^!_))OqIy0}vFNhhHmf#p-lW*{;nl5L6M%tU*6cN>i#uO^nifs))pA%rIEkf` zGen!*A*vpJRRv8Lu}(w0muQ1e=8$i!%pNGDfit=%)l9Cqsn=G4E!0N?Cq8{e)15iw z-OR2?+okP^0DlBOIUhbJ7_wGCT%rg5M|PEZB$g7OHPe2Ef9JvOHA$)2om_yEyLvN& z6KF;^tbj`vA9d=)b2P)lqDY)>j;CqP2h0yz5t=$FLDQC;xG~p^23ZJ)COtzuj&C4;wW`)huOD- zhcgH8B0}7N_A@ZxzT08wzc4_s??}*c;w8yDKP_)SvPb_MB;2p9satbHI%bJp77Sqw zWwPvi2oeh6wFcqC8t+2A!+Bzpg>;8|$0Db?kvLmEkRQ_5-B4|lvm0omQ15;lbT&SeFFrKos((KK%P=;u+5>`-p6FxA4bx6nk^JNF z67jSKz6)?bbOx@gK=o(;uTtBeN2c5(l#XuRez5`Z3XTZ|&eug5GZlr=-2WvG@;G9uMi zN+7g(dYp<6MIH#g5Je6IRplKBB&Uo@?@E{*L7+6BHXjv&*; zc;3N)cr;o#Jh6tx?j4>W@;igz#~(+h!<`SvX4r&RJ4qEfHuIlJGz2k42_ECd27DL4 zC}7czcS?MeXV{dL_={)YaHP=n*Z`sXCq$D4Quff7gGg&Zs7{vvJ1b8YvyuJDY+!&n7?)Cj2~zkPB__;x`)ta zT2?V1c-E!gHR!uWn`fo0$h}iG#p&z19=u(AbxfXTsV^)am^_npjOk}$Rwf<{pU6G} zyF~bnuV>D+XQtgkeSjl#^e-qL3DfzyckU0=-KjoPTBq!t0X~D%#r(GzA8D?$x-Z~w z)N*s%?)Y6(^!Z=ADf9dnH7DsFEJl*K)+EM2J{*s*jidfytoZT0ucH zRTAOPAgeY?7;?4>ZVkevzA{0)#i&rYq60arLj!q{!zdNN;l4roE#8id=YsVbFRxJzysmylyftO5A~mRk;Nd27vVG^ z`d`od#&tgeF7w< z2krMH|Dh$N2Dxx7fGcW)F(d<7@7Om zLi0sC{g?VqH|;BW?C;2#o@1s{5ECs({2qOX zchpbnTuoa=m6BuIIp>vSbpxCQXaMn`d}t_BsGnN>`MqO-olXZ%Oain%DQE~ z55{AW>pr}i@*WmNy3mJfr|P}J!ea0d1Kq<^)MhHDPUrkY8&q}WZq}ENm#X5ZXKsUO zusW4tlaq=w(06P4Ju!Sy@^DkN&`Xu5X1DYSl~AyLH=WdZc0UVJ~K zumK#*3CTQ0X0P@dUeu7+_-WuAhlv55N&%9}O=*kfYhd2o!x@^XS|ChSizc!Ea-ijY zl@Op_8Q#EAW`%U9SiS0U>6wg+U#Eh|s|?GcfrS%geD0xQuS&7htCPbQ6Y-R*gN+DK z?N;UQ5ax!cU8zETsv8yBU|Gby#YJF7;kqy0UIV%ZP@dsekVARZ1r@bXS`l6+-F+HhdHF3j&%MS2xiP{b;X9_dp1VjRytUiU@ z&_(3S;3w(I$8^V7I2)%+5Hm(XqtFfpB+Ua)lHzN|s;?^sc_6tC(x6L z==SE6S$X@_9)D{UQ|-$DAy~ zht7a+NeY6cI@#yPJH#m$1DWgj!Q(%~S*uX{`r|DiG#wu*wZ{?bYt}dDygWwYwlRiX z?7D8!K#4X*RmOJrkFPgA-4h7t>IBAwj$mq6Fx16JYQK;F{_3tp|3hgXa*)rnu0mW+00?zP>?zwgCO6@q+&&w(x((E+{75|%A&*$;G9p(Or>r`<`D}bmK%}pYs8ZIj!^MAA;i{cv zh_*BetI%zi{1u+Mp(je6JT({iPcz|2YVRIhT93Bk_;inhcd@BG7>M42`Fe4VJnPI+ z$DrlRI0@sz`5=q?g7RvIpdI8g`c;TT%aW@q7BvckP|l67bwp5@ zr@)a(fhnq@ls00_yNDO;QR|nk-MGY~M14QyDRvAnBi;w)6lA=Tp>6UKO@~0@Yq^?a zhW5Q8$c@wP9#fh(-&ddOZA^3Jsy$5pUi)q$$y93pBgp~(J^|4Ps zgAe^cnt|;W*)bQcLILRF1VC<#1bdQHA^SaN_mn!3RQDd~GxAjBI zdRKj)_e;}yKes>l!*jA|Kg(pciPwsL&P=TCh}g$8$;w%Ai!EV=^8!0tejRVAW&ELC zsKq!v7P8t=C_>k7ZLR4yn=+)>rds6Q>1h(v~0sY)`7 zTbw$CZGid;S%#3L1$>h@j?*)tnq>9Ak=xK8&vw7y6azyrAa`CuzEc?~7B#ZR@xWyx(siZQ*o@*IvBdFRLuK{3mE|W>t z(^z6ti9WmxL*J-KJOf+H!&lBq1Y3!-I#ay6r4aa0X^_$t9TGM{OkC#@5^c_27a1Y_P0#k^#0?TmGWRkWc>TaN9JP4GW9I|~G^<>AA3@(WD3vW#RAzJG z`f4WNmqsUSoDd|?*{!tfR_yEJAGWbmz-zhDqUHi+^YOQ#c4*8}OpBO$-&j73QI@ys zu8#%LVK&FKv*eeWe>6yuADlTXDEFFa+KCtNa5qLR5I^?JL*1-MXbl{H*h#}Pa18v% zy}#b?);m3Z^x6F}a@st7_(Xv%Zz~!Hu<_Ml@|p*j#XVU6Z3vESgv9L_W?zb-TLwek zZ{(8OcBahjNY5`I>{nrpK7>8zFUpkr;o1m+7^fE^=Ua-p0D)lAZ|Nk{rXutPscEP_;J}~_7?Cx@R-9Cv>vHJ zQgrmhRZ^y8S(N#ex;;$Sth8QiQ8*sWg@1zudgqI721F2Y>L;)R%QGVCXSCNaY2vv` zTL4*caNS~WGVDky=f=B`8=$YBahG;`hA*jQPR;!ej)NCbDS3={QSFn)52r-Z&z0FJ zYbHv06YR{m=ScRM^C=w_yBtT7``N}f$#Hhi`09DhM6x83$EeW(lLyu^Ga2Bb6Er3H z6saB4`$iwiKcjLpPx-hel`;I{7=<8@l`5GU00dq6+-U)UtfFPOHfB`r3!8_NZN1NR z3@(Y^lyhd~T2ho!@Z#`udJZ^&@qe7x1-bQ6MHh;XP7j^`3XK+wyZ&5D)p=KS)NBi$ z8@4^A_spc-EJnjXM{4R|A%Q#{*W9QMRgg!%7e?)~G$F7R8@ijwNWY$ga_&B?=Ot-* zg@06B)$3Mjn$lJUX9@E}qpA3Qv=T=9nK=~hyt=fPOKWE!cQcqb?5_@HGL33nW#S%G+Ezv!N|4n;wWV&yPs0ZeQdSPq(` zx4iRyGjVXUC_-|WUIwKStM0=*a@`-bFc^y;e<1dVar4ZUz-q)??5{t61oZX3TrTY# zkjskl@t&1cejtrxl#_HZMP)*0k-d^ zrwHZ*2dY1kd2EK`v7G^dkLP2V_W2wLY^6%irRuQ5rwS^$p~fYc_tI*UsL-d%prPh5 z=;P8#_$qF-i`}?oeK~};`l*q~j&i1p{Q%~5Z8_v4=jS&|(HjVn-TRsXBdYap9BQOX zg!zj&yR-)Nc-Q6{m-hQ4v>a_XbmjplgThaPj0)pnkII^_Agl|EN~3B26P~weXPs|^ z|1Gi`^X!U8`%$J>{fKl~{u6=je~Ijb?Tk$fe-!HfBeskGEkCb-8Jg>6eX$+D^a~tK z1Tg@xa63&_fT4e5YB)53ELx@OMjSl5w}iAGdedjO2hMcchp-dMd{i0TD~;lH>y^`W zeDJXRbX;>S;19SCiO-dP2+>vXS-af$RPorknOB@CXrCY! z6mN9AQMVTJz2&*ZyJVYY`ioL;tJ$&%3adMRlkvnEybPu+Z+;Fh|0VzU#ei?Y%;h?< z$?A~KVB&t-$}hG#=;KOml^t@uF(Qt$5(bOq&NcS}a9ST@`=}1lXyxXjEn&r>H(|BR zZ!fgjXq6dgdFpz?d+*(@wuK7O%(o3g00SB+4L69n&y}E~2%9jKu#-WIvRXupvkE6l z|Bp%(-{d02kn-Pp#O}xuYVgPr8c94IWkft3l^97o1!+G?4UNX4-x~lScp>2GOhFl%7F=u&cB90Jn(A&X!G&V3XG%+|) z_=X$7g>e&jwAP1G7oX1sHE*7)nC;1D5sPul?PHW5>Hl~*-xc~+@vDd5yJHm>F8G@;UURxQCa zHZ@sZ3RkF}+cY*dH8yfTH$Ue92`1@(w|?nQZJpm*+$XG#+o?cCfdKB?`>rdz68x@gfjmMIj)=Z2lF6{lf(Qlwaim{U)p5qSN>7eYO zb=*>WM@Tbu!J}4 z0i=Q!+mD0!@9ZkkS#hgZ!c?1=BG|zET?1G)BC<2Z1LTQOpGXTkPZhjAc>^2Df_K6~ zA=^lH6}+-Ve`InQGNJ`kAcIig6V5~zF~bms=?Yt9F+%n#c9sTujSJ3Wgr?$D%|;&5 zW?K-TEJ67!E=hP!ratE(a1f?2_2mGvEc`3EP{VK;VLrjKqmXwbePlC4=$3(B?km5l z6f#LbudVs`e@#w8oDJH;84X#oGybO3ER;B|vSX`NK%D*|jBrs*;;6wQgrLNmOAQ+a zW)?dC#+^hFo;dr!b;IVwIp(YdlLo{z_2xS(bK}XHq-kR?+M;Bvwv0nLn(D{xU_v3V z9D5YOc)b~w2{I848n(@?-`B@ohobCuRHmVAsTpFi+d0xA5n*~Cwcz(7=~fT5c@lHQ z*@+f-m@~Lh_M$sdPO34Z980IiRr9+*gBjh@jlcDWi?DVP&n8BRC`S(eO-j{Ekug>p zec6-kP5Jp`Ox>dTKgX1jNX*Rfq5)j?>;0u6S$1Wd>jEB6Xhk5|5ux`CkN}`KyG8>r zP{F-y=R)yE3hyAGnc$CwL6UU?I|}3tE|j>jCQYGj{oxYa3wj*ezo1NHO01mus$r^a zHCGMtv}rqYZrixnrML^gmRAJV&yTQ9jL07ga(B3GTV~pt9<5SvS|niGOnBKSG0$-% zhKRW#payYi@Xn1YOuGU|rN_Y_09QH2q$wvjRw7cE@#N;hrzii8Tp&V3N}K8iu%g7g z-h_8^WUO)2HO=)kYMW!l%Gd~sV*!5ze7)K0X}5_^QtOD(7wRGzk6F#MhS9+IQo;s2 z3oL{_-PNQ>*Ah--o1n4>A*u&dC(bGWPV(y7!;N6#+)JrY!#qv(jZ%{k)%}mbFJSzV zl$Mto?X>Aq;qKdnefJhz&$f09`OfDGobeXtKjR22GOInZLbn1dDsUmnr{=^Na`z)! zv`2da04+Q229rlJ2!4tgTe5|mwllKO!uTnBZ_2fVk&_l#71J*1D~BCd?*N6k6ZqoL zHZNs}C+Gv8AQm~ixcq>fC6!u%rOa7}V{<`S1h}9%ZRLE{LX@{5Mfah!mKWzk4sg-l zFJv*?78o~_gDLxs9=?g>^;?s`Ubx6%k69LW|Qn;ok_cY$6^8Bvmo zmnKa!td}+@KQ)Li$BmqYwSlK@$U!}m`{bUJ^GuvGIB#j%E4$c)%oGN*gKMa}-dShV zOj?`+gWgx$uaVxnc!V!LCcN*-C-tTqjsfJVS&`o*+dT+i=kd3+nX# zkuD!`jEXN)ocYeQNN~Cn9zg|`ianw#-;kkr?y%xRxMP9q^XVu4F~fl1T@~t%P71D; z?4250zT2IqmP1lf_zy7Oy`I=xWp+O6%iukaVPA6GcP^fYhfqygtz~*EBXMj{d6+Gh zeMe8q#0$w1rCE1Q6lrp2UTMl>x#QShyLBKzqKlbY{1a#UUmwujt~;qOlP3o;1t?Q* zaka3I9v>{3(d13zJdgJZn(DyIYqS^YR;k9s&w0{FTFwSB4pla z^5aaf)=lU@{mj~}8Md%Dp9a2=pxIp*-M*Ux?atRs z=)!GgRk+*Ob2qq=3?eWsFaIgX*bCD>zdHQJEn{`Xt+Zg0ARiP&E-S33nXoG5kT@<; z1n%9rs+1Ld#g~G=LP8sLyxOS^ut>Y|7a;@dw9wTp?X2!4q;O?ITAsa|T~IW`I@m=j z0O&O6g~_27B*v)K8~^sm^*$J(n5c-Gotd$JIN4Y;o?+E% zH*bTz2!iE>4P?h0e|TudW|hYLEo$FT4O{%aYT=qAxEQEI0@|7t6`k9z3b7IkHlncd z+1tsTg>5cJKA*1ONjN`kmU{HBV^h{8C_HMC!$Hq5Hk=g-$yMYkY%o^63Cs*Q{{@qs zPK@=OM6U@v{4TL$Bjoxg*GG+JcVy$ARP%;A;{;5%nD??Z&hbc^i@MXMenbnDkY8ESspC=^>9 zSR+=6pgksFk{L!pJoL*xL5B(`Q;m&*1=RZSU!0EdEr?mQeY8Rbq}bC3Fj;?o6Q0Lh zFT}QHi4wosawqO(YU2N~0Vk@%K>b_L>EQc1wY}v|r(Y~q#BIeDa__~I$rOza%zCe2wmqn$@N`qYP5a*SwZjnSjeAaPWaOvP>r zLaYI?eBj*vt#OKwkY~GMpwtSnSZT3Z8XF}ZhC1$wL)rfn;0c=Ng}}Yz6ap<}0uY#S zIYE_ojbeo>31QZgz48iBK1#|(UgWE`Rjhp2d2N7~4h0$m z6xVFoI1=9L7@V5g=TZ$&D^~b=8JtQ~4bd~nrbgLKHASxg0nbWs>2PM$?~MI+<)%nD zV`6YPqpTpWQ?|)sj@?OglM7ifKF*!SX!xoyP|+;G7wPOrTHvMun(h=46Cf2cDs5P#Pf*J^R*kgX6R}nI*xzpmlv!j>g#%FSzU_9 zhlr0waO#Ou`t7Jo`o)Y0zd!x>vD(?NJvivrHGIEkAKxiAuKNfTeBdJ$%L}E%(dzmk z{Em#^R1OL8rVETJaidT;os*RLQiO*&&)!eW=Q;qYT(n&A*#z~z4vStc;&i*O&k!j< z<{?r4O8w_(xOW*UOKr(sQL3`MRdq@nyOwNxjF@RYllzYU?Ba={oNmvL6 zUW;NKjLRp2oh6f)m$NRkvS;$aPMwi`!MyApJ_Xj166hH|VWck{u1n16rT0Wioj-30 z{0iSph@dG}(jj}bZ&dk1Q_QtOI5|vFRBw-0L)Dyz8fst&?oHX_(C{;2^@ zfLp1h-&o2yN8FGXHCfXTwu~R%%-=@?Z&gQK)Dvgvfu`hu;e&qM2MPDD0jTOmP@ID= z`hG_kDdZG!sRt6Y>H&LgN0^Cy21WyhKuW>iwGzc;+yxQ)!@p}Qcknfmb(Pw+4W1KS z)`c74=X<|<{?)Fy?5%zUwa)alzGa3Q@KO&o-gu#2cBy0|@M0MYg!3Q2}ZS_fhy*WhU7=Ae;;qSQk}c`J4r;^4Ez1We%8?ABv&sJQY$ zHlZpUZE3=8|0(+J&&ysxd12M+zv4{K0D(vz>kF0rcfek)s8D|5}tgi`4K{cWq%v=*8$WG7+kBdu{O zZyw_5KM;GVe+iC07GqRY5Vx=vcAwSmrx@l@eUeMITK$c#PqEI5io>w(UOLG$$)l?O z5kI+coKHidpuzN{=J^*e^?PD3>W~p{isKpIC=>oTi6`conuj0KsF}pfGf8@Y_$Bj@ z9dC>*g(PlJKxWgKC%c5iaR0YWUp(BF)YSlkb%#|lO#a$F?T9iejzj&1SoF{QiJagA z;@Zy*Io~MJ+rxlZRK&v!@0-bfO~TOl1*OmLAejbZ}Px zsaR7tkc0g*PHP*V*Oz1Dvo4-Ev%LSg&CHO{h+w(02|1X`P6TOCO~=f(`Bgh~XOF*` z;EhwnYKS8pWh`;UqvD#$MjGuf=A>?MheJHiZCinwd*xr5aPmVXjujiKKp27wn7w8x z*IY-_b-`gJi6V!efjra)^%hb%@?)S^QV6n#GWpk&sNZ0?yVsUyX3Jg*r?W&@| zg`Pdk3daGdiHoJRI_LRVw8A#D|EMRR)m~SKiv15o2kY({`b}^R%K8(k&sr3B5`Q?3eaaN^Bf7pP)Ny@~`0I=1!nH9mC4tB7>7paIcWvvtssF9# z)91IxOZHVufs~Y*e5ml}?3pks2l_rj9LEST%z2}F-_>=F=Ngsp!`_V=@wnS=6pQ=M zD~C`*|Bm~@pyGq^+1z{Ce9HnJh2md_((@J_ARV~xP)I_2$)4=~KINSmcYAEA(1=9P zSql&}js%|2VglF{aa6Zx1fb0HKVDf91m!V>95?k%> zqq*By6n__akQoU}S(0S0zuz$9CpML@6y98{T?pjS2=%;>hoDsj%0vf@55PdI_&}$B zfKHNt=GI#RH?@j09WeaY^LAZP4H=~B5Xi57aa|2KZ-5GP#k9UasO@OC06`)R39kf( z*5Pdrns5fm?|QW$Z4XYmgL&Nw^ZNI{z{l(;;tnD4{`q@Lo72y53+?-d;|BLD;`kQb zH?sK_q|7~D>Xs)XCiO(7L+1Vlnr`UY0`2RU)r~mx9@|-8E@hy=Jo-n>k5aY`-ELO) z1@f|Y{ekS@M9^`Dh`L~SByYGZET_QGGg<1C;h@MbUYj}}kRXXtY?(m|UaDl7hc%~E zo}e~sUG~Sai1D?U61<3rTlkGLo60BQNQy%_yCLYTu_U`uITYjv_Wu73g-~dIpD)$jdWWy z^APex==FVpexAoB(qcQ!&v7|=r*;*6Ntt@TNSGlmNVowMVpfK#mNV7 zHo4y_3?)1ZG$(S85N*<%(j;fir?!s{ZOWfmn}z(s&*coW>I>WRooD9{s*iAO@;<5f zGg%KVlhO$0Xi1AlbG|kJA7QKfPc58PEl3}E={b@$M!s@gu~_r=Q>IG@?#fLu@dk!@ zgG;N2AXk6i0=xo>hT#**OQ=t+cdkz{ui%_{y~1Oc89SF~y%~!6$Tw6^$(rKSN2e1s zAGlAg>pb<<@xX%~UTZ=BjNN|JjL>=uEbp5c?1{X?n_f~hgc)e9aBAwo&4vgyL-tk& zjH;t+FuR@ig}yD~8+3f)ry)ipzd<6yYe3=+J3OM7d>Ykc;KbJ>W=IEUMOY_olC)x3 z!pgW%@&XYXqL*eGT~z{hcqgrjwAU$_<=^B|#S8~}zcR|WzX}OUbNc&)92UhsNnK<)%+y7ICS(CuH zsqgh%6Uo$sI6prvTp8Swe|U7xcNdslR)%U{QEu$YX?uAOFKJf9%$^~Y&ZgcY23P66 z!3g%Gak*DdY<;6WGpHfgLS|3|<4>{_w~wyaFrsVwcG0O|N+9LM9~y0kuMTO;MymNEzd!*jga7jBsmL*dArSv&{1G zEYO$&6d#SlIM!B2tz{W8?tRE%-(=aswve`=H1}MJsb>WB$cHgtxm`N$t}d8gFC@hMM#s0!I2kRwyz;{lRnF`-V45*ob}j0#;oEs0 z<&&v8DFL=Rs!ZW9N8iFa>bSj*g&rrk$(fTsCWRa2Z16Gg2$t`Yo-W;D*LY~ib!q)vz-v^=En|Kea z*CxW0@n)Np)|v%;=)Ku=0RKbsm+CQS78Zc4A3yJ`T*WJJ_7& zyi$l!up3UE4u~IQ$r+0Do|205x|Haayd*%P0PKhr-#`l!bz?gVUsBlMat7H(ENbIt z^7493mHzy_UiBQ8H8I`L7i2Jx)`b4?ZZcwDHAFKqBp-6)CjSQi--(gE;&Fuda}LG* z1B+q(PtKzLD=~x&Y>nM4jGfK@`+y)h;lI)XbMPlE>Wp9~m82kz7>X5;%_Uj%?F^EB z^z!&r)?8-Aa%Fk|4UzFeUjpI*b8cIEBf9$)IZes-m+dHu8gpiM1Q ztL8R6V)`60Be1s=<+ajb1)D?|A!idhhwD z+32c;#*6=~(R+zhBlOuqo`$Dcg&q@Q`4_lr6fY^_@J(=J6K_{;d{Aj*B9_tgv)1{6 zfUnJ=TdyoAs?A-gbV0g=@cHrOb}v<}{rUmy{B&Yv9nLmhCeL1*j4EvPGUgbnWIml{ zT9?Obcg1&0Kct=8&0RfjOxS80I^vW@YW})y%Y&cAH)67a-OHw8dAxh_`RzNABh5&U zV(2}v)J&H%aADFW@FnHE^{Yw$h_0E=Ob#sG`DkDVA0}YEfbgt&L+^%l*BMTwL0`_| zkH|_D=83`cj6U(j5^Pkhmo+1nD*=v7@Mg%b^?&Pk)Y#=QeFb7d!pmthjI88rC9o-y z;2S7{&NcJSV9nIk$13j_W^&If+*adBceA8HooQf0Quk2Q zK#*F0!j}i&`EI875T0(JKwU!mRx;#?Tl|OxySx!qzT(P`qdy#!0eY<^+n`YjgQ4DF zsDGTmKTsvE>wbx39EKqRFC;I%s?&bH3CK|+1fnJt9d$X&P>zU5CV1XJ^h=l&Fe}lQ zeTC13!H%RwpZKfRBjMbPSPwuNPlj+4nz1(kpPQ0k5!702$yDD0o9}Nl>10BR-qZ}Rb7X4@;mso}S3PDtSmKV6K-f=z z$&_@GNoFi|jr<;JRs1_RY0Cb5k(E@oFNXh}Vc@TCG}u2|&&^Mk@%{hKFbNZD`ycy7 zQl|e-we0wHITS_IknYVCIc;riq(cqSGF)Cp$^r~*lsp^rivY$2J$u2BbUbdx304;6 zo9GU;#39Un&=-Xv87pfbJI2-3)$g(A8b6cE-0rSiPzFt;4)$Wt0zYf%V~w@5GApb( z^YZ}9mKdV!yz`1^x#jH{y!#2}KTjzQJahLj(`Z42Zbi9g1ddj8Cz5>TL!x|#rD0#VHc`k;msj7TxvIRh`Ks&glX9Dnr@BN zv-H|??9w^Mp3oM(caP-CEmUE-XRhjRfs2F1ooA2O9g>OrY7w-B7RaQDBA6&L>`j?# zUqhaqE9Ize%}?j&JUr2ArQkHnu`T273A896gO4)fvzK4|)D|Ua@cm}hVoOqkQuXL( ztj`c%?}4|{Diun!aA}aBNBR0k$c1dp(mcYoj6ejsHfpwN6`-aDJ+#nbT;bnN3&kyT6U4V+`864sn-^XIy0krJUMxh{jXs zoa#lwfQdPfZ27$72?yc8Vgv9M!Dc>&F7FA-YBpYxb4KxBHTF^Jo_)C1Nd%aaocQi; z^Ruqw)k7T1#QA4abFqjS7Am^%!!iLs=t3*(9UQ1mlYq=|$t2{7aX z-2K*63wS}5pooE5!Nz~Vf-3|-k#zrG06bk>;&!Z`fYXHh4;f(ptE~S|(EU%yCFv?- zt78uPArKPMTgn<`n9nujL&Sjqs7tVMP@~s($wg-bwT7!61>Y@H8_)IVkEZ( zCTAgf%WZ(p#f50o=Y~YeoGjO-M$^lQN|*C@vHbyaH}5dUcNMREGHk7T$pQ@@%M)D! zTZ1b)ep@D?w@xJ?H*a_F>ylO0cI`kOTrQOx7OWoOUpLO@rs5LETjM{9cV5=ELDxxZ zOE@Al{CP8y0%+;{x%Ab=bB{~X1xo=yr>U@AUEn#6szC|@`7IO0!0`CbD(zTxo}Iyq zs|0&ggSAYE2Ud8JlMY`pP$EQMNeruKL`T^hRMU!No<5t?cZB zLnm*Y7`|3|-K^9aU-yKN1FD}uY}(Lo7B^AQ+L&$oaCTbP2hNB{}|N{wTt_%L5eChgvF zt5h&=E1kmxAi<*5+M->EygXGIL=y)SC5oIrdTeVZRcnkvtvb@n*r8hM4Nv|3`ehZT z(|2p5_BExGC9_)==Gif`NFc>a7TO$76Cu5_I_|Y87?s;VedKY!5cP@QAeFm;>95w~ zT+)nT6mWrp^XRfoO)0;CQ$KBedWui3b)vs5DG)>RA%uF65g`hGP0VMWczAW?bRVAq z+jceRb~4qaWcz{=#1RisJIs-`4(qaO?DAXjVp=p#v7uXk5-*2V`QqwX+-E3L@XZ~e z+v8|7)xehlbG(DvK0?wyLW;bB8h!$Yf0@_Et!t4?{tH?mnc!#YB9@FngRZ>)QH;tS zNv^%|Y~Zoe?Dv6Bh)ip0@|zu+kr#X(av0c>njg#TLr}{&NW={{U3V0kEOymBHVlCT z=00>&eB5mVwwVXrz_`A0gIuoQP?|yjz%&N=u2Uf<{M>ABVd^`L>i%pAQ1tjKJayfq z^}ftazI$Z(@B&nQH zf@-;SNCYfA*#jZuh%6p4QW%k4TB{NBj^W^7lf;SkI}#8cfW>r+^g^xoH7$1Kz{8XZYf9P(i6lAGO7o%6rMfD~7 zFy8W2R}(9xHwyb&icw=0%pgYoEJv)4)eLr1m12flWjw^4E+rpA0ig$xIRb&K<%v#( z(m|VojA`$WneBTw0Y3^mgZ^HyG#RS)Z5?uxr(hAp_CPqJMF310~sVD!}rY?vZ+HE1-T&1gx_Wy3`sG7W6<}&^%Gb^A5Wt}^L zuWu+9mio6#UVW_+JI}PmWho`8atFC`S(Jh4E zsV$gTfx#81%M#G05l7)DT9+BT)Nj3dw;Qx#M-dMfD8umUfh(?}ah^u4F~>o6;J2-> z&w;msW-i+oT9<6%t*%^9AHPW6yPNr9XItnc@THq8xC4)!?$;M9(A=}hrlVoGY)vKO z7>wUA&^s_`8{<5{`Hz%vL|VkkE2pG%Fg%!r|L zJ8(5=QmH4k1~jjprnga|bZWJdm0GViu6Yo^5;1V=TNSr(!v?!vZXD|xO&izTOy8%n z2LbIRQi+*EJOD70^R(JI^i&4+&xt3S~$UvqBh$p+hO zqZ`X~<7ik;I;i?aU;=&}h!?8Isuhjc!}XHniQ@vZb~~Iuh#%23cZ(QRiWAMgi0o}* z$vslS!r8Zp6LIyV|>@zV6 zmK5hJzYh<9#6`8C5rp4^jSz+bA1Kp;09bo~3}OFoLD%lp+m#kR5YX#S7s>peHj@7n zYX4nds07 zr&kbQ+GvAI{0(bszJbsYzqE=~nE)1bmcK1+q<>oyEDf94Jl@}*zgsMNcc**R10>i~ zUO)f2U8Qryave{kvzXD#cYQX70@MDOF5i=Q%KDw$@$>nn<5#R^goQlX|EAPMksIju z>?7^Joa z^J-y0jXkeJ4FCaaq87EUUg(z%cjrzIL$cJ~N<2HbiE*Z^VjwXVB~8?~qr|2-D4CPw zTOi0XK3u_#5N{GCIpyywNU;dt8!>tko>uopv2#jqYMjHI^Fq2>7AYfF9wmA@63us!I_xvUeiU5jW7tMi8s4q zQbG@a+15^?+D}DlAm>Yg&w=myAs(vpfY43a$WDSamBs68<423n(?Cg?EWTo!8m6G2 zy8|NSmOZJ*veQ6oLTJt58MB!1aQDXywFVEY#1Eb+=XgDC$T&n@Dja61w+bbmoWIFJy`I^Gj z=1i63DzfYCs$fuBR_|j+k`d=|$30pN=Jt{3!kHo7g^hZ`0Zh?w*e$bX3kv29Q_GC~ z=DNS^DIg$}1&!D!{`3t)Esg!kqs{{wt|oseAv1PjPM0WeNy|&e*1)n}snrrzux|t7 z!=7SQ=}3>8ujNOS34Vh#d<#*~T1G_rbM%YC{Fa<0gtZdE{Dh7Bt%M|G7X|Jdl$xHb zMd{~x_x|GL-gOQdO#a&(QUQW(c;dFlJOFrg)C*{uI)bx-qw76_!&&1n$7C#dHVEXQ zU3ym$wUjVOw0~d~OkTM>XSHTyY(o0S^WZGrz=0nzSa7QsSj#yTH3x-an<(wvGmlQMP)mbui*%H5#9CNa{gb{tJXAopgiN5L3SDFd+Gcl-e=1b0hKEU>}5q?fg z$$=86)>_7dxUztRIR2-0hfj5zw&1GgiJau*GZm#dB5X3c)wxP*v4d!3bqoK(+{WBu zws!a?YF#BMJa0SSkRkt$FCA>J&Rj>ntR+z&&;YTsxUey2;p#JZ(iXcDrwgZ>eTj|F zm?vI@3Ws5i$zFs>bO0OFG>n`tA?_TCe<5$dX<2#B6v$J*1A5z#6BTNR-DUcKPvR~I z{nrK#hrPiL^%}d&R%9U*;Gu}pXe1@$u|Rki?S^b&qla~3$rk24PIzb27nLYx16yg$ zKE!Jp<&m|6YE?#*JeO!ur^A3c_CcS6TK}=-oMLFS=g8;iOUYgexo3eUfC%5*AHM%W zL?lh`O7et=FEFX$^2Vh@IOC}G)o!gk%*rU2mLHWTFeEPm_DLnk^&9iq!XS0uJw)L) zX8}85bml23A{Rxc%F{12XA4vIxzTPl0hwqki34G+`FGZKNl=CMeoOp@jSU<*BD7H}3%X4xxM6tKn zclN<#tr<@hnCXzhj3JqXzLGkrTj(;bU?QSTG|4-%OU%H^L9jJPs7u$ORx2JGCh|GL zthGqmN%Pf@zNpijwqFQaM_WcLq{w5 ziu`C{@Nx?3=N9qUNa!kRvJ9;$$6(Q>3i0|E>2e_K0VPU+-X=QiSkfj7m5^@k(j-$k zGXz9x=$ct0P*3LK1a;bnFA?HRj16SuzIGZ87pUxUU6aHIQ|iB5av8EtsvpU5n`?`6 ztt$jN7YNnAb^a;_=VwR-3Tr8Ld*>}F$p0cCP>q~=O*A)Kf>?(6)TH4#2n$vr5u+tu z;lciyer0uLw^Fg1;Z-KZAV$e=#9oZw4$wZO4J2X33@48&L=^=*1=#!96J}SE8QX-D zE1!mc#@nG+2vCBqF5E8{%tzyZiPI9D3<-4x>GUg-n2x0(kG4|m??8zVVabLaR91{nk;O~)i>P)ZmN=D*CTttn@&-v#V02KB zgDl>qfS;uZ08Eu>OeI0F3JRZ2m6_QrA4uEZKQ%PuCQ)ZInlx3G!!3o+iQoxpHoC{Z zROyP0oLGU2E3#MN%;h2 z=^>>Yidl;ki3&xP&r|A|J5%W%6;TdCY1QQ9{G(gQhNv1vju3N@f(ir$+p74x4)Gp+ zK-s7#U(K9Sk&Xz#Dy1Y9C2KZ>T^}xEO%0ZrM4UIPwniSJ$B(Bfd)DmWrKN5W8m1i0 zJY5pYc?$hTnXiyBTR8w5lt9IYc}Wn4bd@xhoq`6QYLdy$1`Wxnd;Ses2B#~k4x@Xq zU=H)h-Fu>?7zF(c*&i+#PoP2a=ks$Nu!@3KqR+`xy9rAj-pfifZjD7mPEkDE1V-XX zyG9^;j)a5>+etbRH5@NxEeY9QcLLOlwatr#SVby?4A9j5zl2-fD04F>H`vJhR8QRPCtZq}N?EN=duPMx&ado~tKYMd9n)HMS zT@2$DtdZ`t4}DGigOQ`;IxVG?3rtXE-Lm@I8MF%LP(vRZ9&Yc>n7%-=HIl~(Du?At zVK6i*J}}g4E`xhu-ko@b4#{;r5I;!jhMeqKlMRn-ogV4ZFmm9tLFoyAp^?AX%O(@2|sX0<`qWh+Bu*I#k8@b z!c+8+2^#@B(=cXrEKMf4i<*51w?6r_0EQ*RniVdcWweYf=}P$&Q}8r)i0zG=o$Hjy zQ=?GZqFIA07CFgW>j-r>RH7IM7hYf~pi()zy%&R6xj{(^!(5G>A z;iO%x`mJb$Dd9~GU;}uxeDLweDk4B!(BtdWDuK7OEKnuE$C5|Ia$&uaeGZ?K>`=!r ziHYMtyNo_ZvSZEByJ((|1uRt=+F&v@lO;*vw2zHZEuP3U$<#6+3{ODUiXOlPZKRm% zaGX(Q=T9c8;LgKpa%{_;MKgD~%d+=+y+6X3A}~AN`BtahGn#4>RFw%MUYo412E$ z7VC{(DDst302|lB!UQ8C06GH-4yK=TO=XV&G{-Q|I-M6bSepDXJz;+ik?2FlZvy7BcTBs@ zcobcr*O2-y=5R$CX}AK^&=)TA1ZsPn}qtTS;&H z+&(>Ttuve8{LHAWr*RiT=holVup#wGgW|gZflf$6$&>-$sfJY5fuL%LrhAr*Wv3ps zBdRX*4ILU8g=383tp+j3{kY(LxbJa3uHJM_2?7fOk$_+A49U5QZO`LD^{*vqPUR|x zbYBp!hRAXKV~7TBM2l|7E_(P@g8N@!yNDl8SWI(f_hqs8wv5l1LRyu~p!r~WK>FDH zDV4B&$2fkeu;;w*5;fQ+jjHPIAYp_QBjoT+^o7jV}=*62uV$K)D(z1AcAZL3BqPM(UPtb}F<3@da z?Kn5{Qqgh3$gt-Gub&=^I%tFh`kKXrt03kO+a0LB0gqF|IZ@To*Yg|+jE3Zg#L#B+ z!PzYN@L75!+VKID)v@uLHHf+Qa~!hQ11Z-Bh^xR!K!tz(H>u~9Kp3v={-K*-BW!QM z%Q2O2^WJogFKlM;gZPXmA_is^Btn7g9zJv- z`r?7F4xat>FrN@qUI=l5A@m$Z*9bxP6n6tqcuQucrSl(Os z2e*#4IQ^wXR1|UJP6Un%?NNdaLbvZP9h)P!8fO(hPXH%ye!sj%>7y&E2tL*aHawab zzctJDP*rb%;sPJ1{{*T_>l3pnBfs1L3_;QbU#Qs*(<){sUf4cd?k9o7ZYGHuFn6wH z{4u&HdtD%2!T~oC6=d#52a(Jn*9b&j$O@k=4Plmtmbu+Rx9WFed?@VY{2}|BV~QW8 zzFp#+54=B(Bj0Kc_0|0ZLBH}B?evGi$3$*_y=!5X`b9|S`Uh7Ib?|%9{nBIfZYvQ< zwIjha)92_gjfY&U{-BLp^mgTobW0ngTgF>g;~Ue)-YEW{U;73h{VwpO_{|-Wa%mTS zYG>uOE$QG%Dnjq!D1DEe*lk9)GZcGdcT(z=SSrOj)i0JwL0hI1Kk?hp^C~{!5jvLA z3ce;hBtK0ohR8}vr`2~-XMul7XpVHLp8xn(`(IcXBBOSuOYFC%lT=@29P^HGPpnxBzy9l_x*Ctw=-4K)zwuq)id3FwSIm5q33#!Mp-m!9+{=9RzVa4h>IxLsa2KS@qKpv*0aCr}F^x??b)zd0s6IU~788ArP%!3no zz8=RV62q(iRXqA7y?B;-Q$03rIe89OnTLX7oF*#}e(>Pg6mA84{)n*=U-5NZwWCZ;U5D{EzJw33OQDU>A%EQgg@Mv z#z8PXyp>t`luM2{3u1;J>!kf}E8~jaTc{RPVPY(CJ^WeGh^b9ZuPQXBy-=ek%$up~ zq5k-}rzbH!-tH@k$1S`bEfblrE08~t&lR^)V?<1<_bFJDE?`!49K)Z)5BpgIFI-A+ zB<>*@$BpMXodl4q&ip}^Vo1KeDk@m#3yMF-T`s`6wf;5Ql`U0bhd+a%RGfh+E6)98 z>5?ip#cd^s5X47br`~TDb+U#PK#F9oRe{J>FYvavmR%uf`H7MW^}>$-gAoQNjuCi* zS+T0{ewngY(A0%imKcK)*Js+ zHeIpTnjp;vgbRLm1hysvTN5~2Y5UMGd!_Wcr=x+3Ikwq zhZ7$>CC6fTDi3Apj#TiJ&{maCW*ZGji^v;>Ug1Xue-W>U1{K5N>eO_Lif3q@l78`3 zO8@fn6sPY{(E>b1D!+-AFo#ask_FxL#bcT?5H?M`YqcrLO$XE^yEOGho7*b?)OgE& zQ`TL_h1(EVOeB-jXWAKb)2J)fj~2qhXPWng&@>~wPMmo-@P9LDQbiBs(siQS7uc2+py%z5&q%}KEXZcCw3gJERS=?*N3x^NT z8=lwb7oOMV7w>1~o0ZqxCpfQTP=;Akzv!>CUzBc(@!ndS=VzlMRll*eT-^o>^tau< zP}`OOqHni8b^R84?*+ts8G46&S@OvHH+|-OS$gMv6?FmWTC=FE>6)wHXUg1|ySIjM zt#dY4Sf|z7n{iz!oGUq+e4a7X3lJKGmE=sS72~T9%9;-ak?Ta#YP!4~pjayL5jgLO zrA^stgJuJzryDTUu3f>cxNs}X{Y5ZyMQ9lF`ND;`HR8OHrMM9hRGUIs*GDMJN>@N2 zeWZV=E0W+&G*)otXMu;Ey4Dn>7MbY?&XyGIX2<92MDd zDq40*I4*^5L}PV`J!iRX7h`0*9bfWqfkQ^6(#s^!2Z51MD%+Pw9|}@Quk5-&<5CXG zKEtAgfUz`+$0{M>-W4gyDMKO5j5$3!ZNWiK9ct8MrQw7J8`5WdCjz06p4HHsoVPrsX>P-#^s9GH037py02A1>o9`g=VDfm6oW5+5F zfBepufZ^AmxV}TjwOg>8EAZFz`g!Dd_|@)e=@_*8LOu=Q_Gg`mi&(o;N?i@Z#LA3^ zs})weH;m-{2@U>@W6UDkmn|X(wfUxS)b(&FZ}~Z{5|1Zuu*L*{_Yb{;LLMz3LR+u9 zhG1@DW~z)bPxuD6R4?3jc;h0UNRha^T-9aN+dQFSXAfa^+#*71@}d4BpW8qoujA#u zV-yc*9(|pEhwMhVN`~)EdN-v@yspCLL_36%8cM(Bv$}uOl0%7D`g!**NvuXKnzp0yx>X7-QZR#X!_)gkW6FhB{n z+mGDguF7aVNz5j>m0|iK#_o`xS`l@I*;W*=%i~%hc81)$(_TQoH3`Hf8DRA_vsVP! z1rxiVLKEv}1pE?GWl2F$P2r5)!5YRv(&%IIMng+!6w&5`myRemD@zg<(gWVS12v zlNxQ%oOq_WERu0Pi+qUJCJXAZCbEv>J65Fd%P5acF2r-qG|Y4HofNlWdac|tw1d!0 z?#ZgLa-n*Iv^|~n9iF}r$8^9ykl5whs*KqKjo)K74jc$}g*hS@;+47r?ZUw5aSME( zv^oyP@LVGJ!+B4HOe_}ZHllrarPr6vfv}VV$t}5G(dq%gBkS;Iqx+u|DB0L4Uiqj*Oc@jM9Y z+Yl$ec6WVK5Kfj0mAb}F2ukZ?miUUF29&rTprGh=g9vxc=@+IAonwp9;*y)6jujO^ zB2~Z8g0Crp_CnHGmCSgc5tM=Kp5Lc7wLt#D)Lip-Yy?x94|7Jx8gtG#J5t2{$_vS5we~=9lmEV# zl!lWVlE>f_hUTCZhUBeF>xFZjAgHci*_Pw{HcrP8`F76ed%R-s6Bi$d!maqbiEB8d z_wRT_6W1^2kL2S&4?i_e8t-cKv`!kGEpl;=HTHJ6(2tsK83UTuymENRkIOZ33aJa_ ztRLedgD`&l8$qdD&RqJFADaCM)4chpIifE};*E^6`Ph-sOX}JIhJAKqn;8-LZ%{*G zKV>rhwZmB0nGb9B*_3rXc~KV;Pb_mqS3&&0lYV6d!*#LqA#(+F$ ze-PQ4gkd6L0kfZ(_1Lz|P#%m<`R{z6&#ubNa8??KvYe&_TCzH zejIB=`3$?ng5%OTM-(as8LU=Rm=75anKS}*$_^DTja;6a7x{3ra2Ioejqk)>ZNr=$ z?3GV~6NHtPC8Oy0r{NRL+gozQS+u>v^;3=^;?+N}|H;DGfge9%{$HU8F}wc-Md&G@ z3jGqFZz2@1q5>WfHk;KE?K~G;uBfzHcUi=)ai= zrT;Jy*>(mm;PWyvJgxtmiO^+S-Lb{$zOspR>ek-#Yv0z~-m-2Z!Kl&aJ3>IUa*~BX z6KKGj{}#F{&N9o&r1W`lGSy?y(0Pt%-oeZ3|JK$rY^^r)z1Sh(Mg(uh#4T>Ew2vJ* zQuOiY)GSr2hR+=>R6!wS_tAk-C1I@%?(%E_xam?&tl}!LzlY;teQZvu^C|qqsoT5~ z^H2Q#C(qt-?HcJu>+KL&!?%!WHJo)b^T;GWB0fx?E*GQFu)=p?>z4r3IU;*cQ#rCgOzY>!~TC(G-{PU zB2V8q#7D^g0g3qk7482a5v{)eK_Z_2{h8VEJ+o`dJ|Wji67&c^O@*XI0+*5;u=J4h zfQpzT|6Ui&-ev7RJdGw^qgJ!>4MNOIQg3XvLQx)+0JQ#xkWk;&u5N8z+ghsv_!hkR zo8Rot{w)6K|M9lb>pVY`^UXtWSCzM zv^15Z1cy)k^fgDVnH4f1MS&WJQk9u_f*k4tz|StGtqGEv6UrM90BjIgpW0=kL)k@r z4#QsC)(l!(x_X`yW4dv*ifg@qMtnL9=hQ`qq=?2kb8L1QmLjl8h3m**=m064xr z0imWZvVn&VEgH$phYw7e1WBI*Wnb;mMan`+jAjqrfsIt=@yTox)VKp;XqXt0ldR4!)7D(8D>wP@BLydbHFM6oAvl*79ncEu07s zo-JR8+x78Ss?6Z2OZH9*UUV6jkie#+!w^e?Zy5*qQJH07|0u=|juArK$4FGmkG5y} zi_2&VN&Lp1;b$%Z)Hu#uN&m&d{=SbqB}&vh+1(K|joQqhE)QCc3?-M!xv@|wo*Jh{ zC^|dNuPW$0hB7@2+6I$CK{l9Th$?M#)C1&FSg2A9UM>vUCX>bijW{dNX=U`~L-bNJ z5yyKf;&#JMJR0yStqLS4b$AG&s2MsZNDp=qR{eG%{IUFbVs?bSSN)u=lOdXqqc*b=p3| z`y{n!wUL9SLU>1Xc_rfw-j!#TPH@eJ)C7`74K?~YeKnolkDjj|Z6woSfDTo$GD;@h zI$|9LJ*f=F6W75Y2GkWXnJSxiM}tsY95>^17`c>ReMQ6?=?fZaC&1Dx)sE+-byc`! z84kGA$rBi(!94I}*fcfzs>*u3WZ?-8MZ@8B$K)sSMF@=9r6o5utuJL_%20&mzb_1MMl8zm-;W6?^HQ4hQqI`mPmZ`$Z} z-mIpncD9|)eDD+eu}Dy+cfm#Gersz>`>?Vv81nj+y|3E1h<@d^GNUBDOHFodoU6__ zO8>nts`A|>Pf@987++bbDji=*sqAk$0hGidDP&bW$Ith~Ul)$(EH2;z>P#xPFQ|vp zp&%vcL>uX32C5&j5vK5d@^^5fsp6l3Q>CpKymAgxV%6*@(ywsB&i9#ga2EL3@)c_L zGQ2k9EFN(Q3juww!2Guo4_dDM#8ulLU83cnnAJ%noq&))mzP^=^YsL6sfqYyCk2k?$JN@Dr!#P=y<_TQGw zm#+3uFcE4gO1QB|(X^QX_W={Vy=DAJOfIk}Q$=RFEX}JtO)i@oV7>@3_#3sxBe?*5 z{W)Hdz#dkNeP#_4=)ZOE{t?aSdN5j(9T$G?pdW~)a7x~Wm0n-U=cw2cJG4Tl;v5eK8 zbHw&NHx>9EIj>gnlc}jxjc99h`Z_JDjnZtBnM_)xX)<_HZh`n24s*S(c6E|2Wc7rQ z0~w7q$-SV?2&TGJU4+^RX^94XEg(WFR+AhT!t7E_3%qu;oo%s{zcjS0eFB+IIB`&W zLaZce2fSSX3APpDd%8BYu7e&?u-Q(B`}}q#vJD1L$CO&~SYLz;E~7$O$B|CoA0>|5 zq~klA4SL^YN!!M{Kz_E?PE?Te^sL63W{A1n?_g*{*(XN^ys56pC}atYOFRQmr(U%# zL)DohzmvCd8lR~>!1OnSnIqvo2X^4AhnV>=;7&`Ynk$7`621gK2fluwRh?h3Igje| zk%3q0Hu^+LKbn3Br9#(U{0Z>-^Z|ZWWEm#ssf5!f_$6bYFe~UJh1RLm>c#;-3P&&_ zUpItZLvlKh**HkuoRWNpu8$bH@==?#WM!^fBGOQ5mViHrXN}wKB{K)W0DzF4AKr5w ztV*OCr{pz4`=O=LzuWdP|FE$Fq9Kh#WPu@1-?B}wM}@OLgx&79-nX_|)mmFyzlG=J zD#&E3lUACBd>Ux>&j}(xi~X8S5vJsAd@umDpNL%*SBiO;VfYH3bFWly^`}=+%pe5FU z%n83wkla+bR@!|@&#f!?M%^m3fl3?_3b@3ww!Wsf&|vDgYn_S!yt#KMvi6hPbt=BZ z@4cinde8j*kd)(_Y-sQ+g2C$X$}{cZh(!(yhX1DY@AVTMw|IjslqmMmqPg%f5|fl! z9pAE&4TWmu6W~1#X&+2P$}Qq%8uT3$Z;QUis9ZAR?L&qv!jLZQORZs9Y}f4_{~1ZQ z(q?Chto6}G^>P)n^EO|-+fvN;w@<44MJomB-)Yr&&Ca4Ow@7KkEB-s=pqEH;n)DTV zH6Wx{^mtg-FHQO$!x>=#V$+Bx0}uy z&Xk$CQfax1`y)yNY$sZ_!c+j-e$jq(ODDh+3#x<~^_q$4|Kef`Y44{0Jej5*Q z%w@E(uE4pWRPOqwcjA%%0+8A&?;>0Cfz^?dRiCys1aph)f zZ~(aRSf;T>Oy)>q^4&E&Y?~dK$2tNXy3utY3Kn##R>o==`iwZ`KTs%IT0jCzh_V%M z=0|vJB`sefeT9LlMrT!&A^n=zM9z%acr-1`qG9F?MFp)+7gQP9Bhn(g*`cDSSts+4 z!3U@|LmLriZ{99HJ|YoBjVl{54CyJ$U(@Z&cr^irj~pB=5FxLs?7HD`gc+Cf)iew$ zo07f-N+?aTf@2p6jo{1QmZDTYHFlk76ja$WF~GwmVuLYPL#tgdfcz>%4w(mjcNf|+ za<3u9P~ZB1VO?n1#TJy9LxQ0R3%q-0ecU*(ts}yD4NBg;5k`q8+tBJBPzy6^LY+-g zn>L$@?DSn8+2zF*xYBDS)Lm=`20++$NNW;D*ldQEEp#{aS!<}Yi!(u;jrFRgP~wWN zlw1i$duXwbMLKF81I}idO$hL8PE>2nThu|9F8qXu+#vdQG22F@hoq65%P3)wqkrCY zwt!EhwC5GPDWtJqgteQ>Rt%=o*B)W3sISrnnr1X1X&TL`Au|gU?tiX{eVf!_JttOe zwFb`j%bHrbKa7J!Jo4W9A{sXuWuCHr4s|eb+a}h#%C-Q8Gf4GJe!fbkzKLe742g!Z zW1IUT4e&XDurcPVa zR9{-Fw&~q;ZI*)D7~|A7O`paE=m|Mo4$mpz?^fA{%MYYOr-=ooi77QYwq9;gKHX8b zO~=_cSDz+YGGkys=2Lfzr{8I~N)XaMbMFSZMQbe`L+JJ5K|iy%{Pl7RUbw-5u5x&n zE9`KPuN8-JDV^$@>m%~$odkc2H>5@U{m`+g>htwhv+DjQg?$nL)^&+ z>4BIGwket>Pu-Nk{Mch)=Th?RL-|W1taYDxJGMdOrYU&?C4>&l=%}Zwvl&(LJ>!Pb zqSDF<`<}Hl5G}}7NS;B=Ei8nP`$g~4BnBt;8-QrzX@h}KzBu=1l&K^Id#x~GliZQm&j4^8>1v~Vd_j~j zU#}6#21v1x1&oB`Y(9_dmVxvwk!-S0GjJGWCvD-xu)(<&y8E=XFb6{63CT!Xmk70$ zNL8dk3@hfiOXxWA{jwiUXtz`x;v+V^TZG02L25l%OExxmOUR!<91=$hp|c`v?a@(0 zA&5a_TY%<1#%mJ39Fnav-m{N-mLpYRAzg#MuGrluJ95p@B9e`LB8T+JY2b)!G;1bu zbe#bMqM4NW46$DjRoU@0T#W&NB}QcZ&qUniz^NBO9T!Orp`Ud~@1x<*g$|rtMI`vK ze}{(DA|L_{0RTHIB$;AEU6(Y5FuN=g@j;Y`*HK!eB@(#@Yy}-+v+>iX%&els7foT- zS^zQ4DEl`y%uF&*@z8?Y&#=@JJAjcMnQsNYx3weO07b2ROk7xW6`*DgK}MZq>` zp1Fi$M807>L?oG-77_HX*}=8HloNR=W;`}3ap}@ZpMF>9PbG?GH?Mk+;3s)@zH3`f z`)-F7DHU0A?PpAze)>|5_ICIVax*FYY9;txM*8v#XRZ?+g~=V=st=LG=S8AP=Yb}{ zg`{67mD6G5`{Y9nfp?-W%Js6S{G?Q#&3*b2vC77|NLI%~U$L@gI+Xaf&?6$VpB9e1 z=?UKNRElcel(cP_JAm_HQF@P~q!$kx?;c6aRL=TniDI!v3y!+f>AJl53w|48&+?>wa#-N=1j3!gh(Oc~ zL0a`K5BJP%i;WSue<>X2)!)ExkR>UiAZUrKkB?SCQx(osY&9p!QJ7KR23M}XbgBNZ z^!AYtXG7SKuT=GaT9IfYoU3N|WArl-zOFYtk{MS`^C@*}UE!WEuAd3g2Fk6JKD;w!#o z>QOwJg%LM5*F#jKJ)LZaIM7&99GMj}(zYN!XQZ=cpfA=20{i$=ZFt8K#;%}vPxhr1 zjh#xK-~&CTI_ZtJ6yvD*JuzAN+_3Y2qXySVe&#R*6`PomqNhY{cPBWYU&QZG~$1NNs!+5_f|w3p6CwqzmR@}83{(v!#cYnHU6X~r}LvxPfP%!8doNCt#; z!Q|{z#Pol`CrI`MJa_!&a*8Cqr&CsnJ!twv5{OoY+u1rpQ4*i9%F9O9j$Bv`2n&0Y z3Sgj1$LhfJ0XU%d=ntmqHGYSGDjYQ8QDF+eoJ_Nh}lF(#S2>Zy8BG6LN-iW`7 zmQZLg7bEy(0iv{Ou-0c+*YF{x_E00~d489&6LIh`_|?NvLyMZ%D&zEx4-CjnSCE4R z4;ed&cOJ@6-`xY*X1bZsVw5IfCkx!GtAnj#15%pbSC6i~XCC*8mV&+)#*y5pqOy-T z6iTxmW~|)<1Q@@-;2K6md%Ku=lw5ZSLnhzC{@-@#kQVsQN%=+%IbR$#4FfgO;5~&2 zud)=^O;(zHv58Hj2-xsljC318*N3CW1UbUzOK16Ol?M1#l=npF&65?xDEZU%dz(=5 z>$Ope*-yAQXBGMg*kfrR|EcU;EO_YJcbNfd?1W-D6BIDS^h>^DQ}#=2FXlmQL~IPo zcu`mu()Kn$u>n$={6*Zg4-Vr3>c`3 z&At3vduzCwNHCC$C~zxF;QZo_TYh>V|Fl+{J^;Cv4HLjA@Qmb>iGM2dn@WiKAD@M<76F zPzdCbcbsY78C0!0-o%f?nwO%%;n^`~J@%0=E&0W6#Z%t!{_ToT+{_@OstGBE2}+tFx4JRD`XOk| zA>`?`6t@F3HtBP$6!t$z@~bw_F2&_wa|Mc^-HnUGU8v~%h*zs;m!e)A9p2oI8XS#_ zc)UD$-Q8Fl(O{d=dAob(-q+5><;d)A$7;%bdcT**e4f$y-J|n>a@g}f2Lo6;OF<0mL`VXd#SkXTG0|70Fc5PizB6O6Gm?l$q#kvn1?S&Yq zpok)f+K6MBji@#>B3l`lLq%mMhF_>;oBY&%eN=uo=mO)sdKJfM`Yx9rZoqharF9xV z{FPBhr{Y1f!*VHl zf*+7z4QmS{T`5|3E=GEYeuuyzv2TfjYBhWX%pqZnI!~l;otI4t(L$&j?)x74uzl#d z-1Da+v+`C<|C_PiPg~DY-yIMdJJFvngs}Sqj5{HV9ayN2uu~2+=7;PvqrWQ#^;e7t z)(#LRh2!MQ27}O_Utw*T5qTi%1EI|;&|yS_UJ9Enb>1@lx8tGT>RjV*#w&c*ckuou z=HF&LJouTOcZ<(#BaTCV_`046#2wd4z@&Um&@z%4+QVj0^cy-MeqE`tmZB2ej9cD+ zyn-x=CDR63I)m2N&k>hVjZZ#BAYq<|mt?EHH$X%|#7qQ%B)Gy9OUWrECg+;~5sM+> z4PpHP7>=2)$BsL&6b|G+eo5Ss_63(apa>*CuqpR&SIR%3bK>t$fLi1 zaxrq}FpDm-xrwuzN-afx?6T5CQKyuiySAfFBHZWbwrZigx5K8Ww%uhN1d(OVQ;D_6 zywAB|KgE1nkgeBZndVAE>y+yWpL5I>EvC;}5IKjD>D2$&xp2&#LPc0eUCTB=vPDC1 zY;tJGRVCx2UcJD7b{{I9YOBqY=T_iUC&#Tmm;oZf&I4yqFZcAZ#?hhMFzT|>EQ)XxWD*m()hNROp8pJNd^nHB?8WIaqpEo-NexOg? z{u?m*Kpnqh zcsiitjqyJo_rOs&#^a6uZUP^W{-b|AU9*W_-JcD?fD@fFqzwCpY~uQc5?B zvk!)VP{8d^pvslmLg5ov4*OTP`~iV*oocE(_|51ZX^(S*lGUGpCm;s2oXv7YTJs-o z)&O3pmXmSV^bZN4!bOJ#&66cg*^+z8a^oBs{7KV9dEq5g)n)17?|?dZGTO3LzUdFa z1k$4Xp6$&nuaJ!fL3uPyQzu8bw{s^)y!Y-7PmDKgr~4~(m+7;kbw$QVPjaSvlnhsC zrg!C}4lSmD0;b*Xky#0)t0KP8q~yn8)zZh3E*cR*P4!LnXn?k;j`-mr1F;gFa_p ztk(OU=MU+g9Mf<`Zd!0x_T+iP=}sam(I!LHmnEVaQ*AAOqmP> z3G?n+sJfPz8wnB?8K=K4{nS^0oY}cr6!)g^;0@JwM8rdruZHc09o}Qgqu1?6WO3QV z4C^f|a`9fUg10Fxb0}8FUW*Eql;PEmRL6GF4nA|>uv?ez8P#rlBMcd^e@B4;SD+G)w`&oymvV?rJ(15(V_Sa49I9sMlZcdlGpV` zTa)KjRw{~he2AS^AVnSd(g3PjNfIRoY%O@K#~i z^%q>ZL2ex$1(_!hi&N@uPrnhMUAU>Gbfw9f)cbx}x>uJ&OL||o?!Eb?6BUxHb{W#3 zqkUQ0W+WowKoNTM0}~)dop$3T4xN`fx>Sj$8OL>zd-_AD-#w)c2@yYZ*R#~!6fzAM z5MFWn^su%-@mrT;CbY_w=-E{1pa;@qTo$7r3vVK}h5Mh_?2(JRB*U1R1-PE4- zb-=>cw@JIjH=RVO>yxn0aTIjWbW^O*mw=qfbrG#8S|X6$iU#dvoeRa=lI%D8i)>^> zC0BM6DuY9%%JPE)+$DCeq&k`VCXhUK9*9VgG#etwtH;^E@kVYttmOvIzMhiKW9Sx} zQO?6t&c@j=uXGAx?%B0q!wpiH#isZ4#2=#&XL`3;_^4Ivvb>C+%mnaqd2~@m!AVZC zlznk0{dlU>IpxMheTQ>y7bowK!vmG zJ-+uY^B7{5ir=~bve-WfXYd@lr&IO4T8nlBTO~T$`?C3NocQ>CTnNfYwJ`bn%cAwS z!;Qv3pbe-~Zq<9kLA<*fME*1y=eb{?Yq%)S@^PQQ;1!v;+L-8}w-YS69+ix|hUxcj zx85ucQ z3wSgnx5qrEAK?|Hrm>- zYTm6_eJd7iAdzmKgNpW{zA1FZkwC&-z`6%HhNUqB<+oR^LZQwZ&gr3{jutE-K$tnv z+;f7g%x$52Z*z;5JGKs|ebH(SzL!GHx_Bt-NN!huqmB9P48qAJQ@o6)APs!@^MqU3 z_B0z7wk1pF4VDYVhDf<`gXhjNMCA?hV6VE}U7Z}NtXWjXvuUX2R=4Rv(m6hdV*j&V zP6bAzl=buB33f5Mja`31y?^RODf#H_s$1qnE*%xE`UfA}R){cBp~GECEwRB#<#&&y zlTFAS9(?0d7dh*|xiLK>Wj1}iuj3WXop3mJVeF>AHp<*1X54kNIm>HVb2A4BTv>X!@dE-07f#=BoOgS@jn$NOp8T{aG2)hFtOPF}KyN(nQI?B|Ua+ zy|xC)^O}Dt2QFCd^Ia%ZPSv+x-_kj%`4Q1ezCa!A`QV`Ci?5!Q#!V==FTOr zQR}>$r!<>Vc^w9v+DQ*(8bo&P*oKGV0(8a@|Lwp7mCMWp`tBPfqXPE8O>{j;X z*?P!yIJ`lzy#p(pQRKkgI*X&C6T7_Qm)9ovy7z@yatLq-zMH)|UG8~qX{uE#cF)O* zM&af`S;8P*y>1qX1p~pWJdzAWVBOq$*-I;Pd2hPRyWD0umjFi@I%~MswoIcVDmk}B zBc4^>?Z{o?)QcLzeyt1#^frKo3uhTZaJdEe-LFWJ{6+}F=^gT3?RdTF`VkWA6Avf* zT$1=ibArOscwWJ8!mOrB=>~CJqU&;yl1`?m!OrWCxFq^qD*?ZJV|ETFNe`qxmmLao zy+{;eMl8*CRmHiYyPa1BF6w2e)340x)TMS$hw_qHFnH;7#9_hO3b99P<&x_H*cKwrqjGxc2D(eQ#oX&S(y{G*Z5-+E8!01 z(S_O_roYEDH;$8hhm9v8(S)64(Y1+Iidf7sR~L}-o?4*xD1v-LrZ&3H?zrC@{Ago9 zoK8}QfHNTaRafTSF`HhEBf}DUVk8#%+Cq44R(nY@Tle^L1H8)3sy)kmVmK(V66xH+ z$Xmu&KQl;k4uZWDBx|`0?^3STxBQdlj(lxNIKTyVmw#(mdq;k4SR4N5ZJ}+l<&bwq zB5h`$2KXQG`dKNpu94i`;WjS1*t6ez%E%|@(&^DV5a zvee(v*`nP#C|nz9IM@L@zv*0gQt>g8bM`wp8q1nG|WhJ)gw>EblAqmuw9 z7P6Jsq9!XB0UHhP3+#k^Oy;T6n#5aQ3AAanL+%=rKLu;Jlxc3s7X}Cy3wX4PQgVmG z21mBJW4^aSe;G3TjpE6tsQP#Vowj%2mvv7YK1 z&L}P6EsMiI*LsIaUKP6@zxWg>&(c=q^!GXo5;c9X(E(BDuq|U^fbYdb7hqc{y7EVE zofmh7&jz!5jSVrpK|kPBnnCb;yfeavXl&KrR1d~pD+)9-cucb_1uG~;(Y~C+#0nCs z-2HZSv`5N(85!^vQrB50ZsFEHB&`O;&RuK#6&!wQCsdDJdHP!rLA&I7-oKyo_?c)C`7ijzv|62I&~Bqq#K* z-;L19NIh^napem44{32#Hl7R5ZnD<~U(h->U_*Z<8R00qE8Bs`H8)Ym3o8kO)!OdT zXdJveGGS+PxbGP6#_i<*)2=*idpHJ~%L%dQlbn^pO88U?HOml%2f4W1j%_Jshir#b zT#IaSqsF;bL7}juGND7Aa9~_H$Zc@AlsL6ftAI{!fzDY5rM7+N7xmmQTV&;J@Ne4!G^po)q}oIQ^JCHmAXg*t4G9yr-UL|*BbyoZyz3D~-&fP& z<|ctqAjI~b#FylFMk4UB0#Po*lU)>*P)IDZZni&s*F&`#g3|pKCD-VJp5n(gIiZ_;o zXQJOTj*I1oRXirTPgETbe;xJ`a(*97SRPanR&_$Cb*<&7wM2=^pzc8UQgYi=n6Xt| zpph%1KL^gyFB-1#dkBpC%)yo8(}QFVP3D-5q%5oyZv4$W;tQR8`k{*4`}L2=dvJ4< z=HHLaIDW_G_ZsWbYg^2G3G2AuXk&{Th>U5Q7&?lsYk)B5Y~b+q{HU~rsNZP#h9is` zhB}{{hg+L7ej|U(yMRZ@50e9ulz2f76a!nx1 z2@Od#%g~EfbEry3M4DE^8LczD&j92v_La{`B+hi7d^&h;6Wx5Fbt-V$l@FpcjLxw0 zv)E542vN2aC6QYbVFK}@lbRTkST&7>=I{j6#BuIRw4A3OQ&=i^B+bi!%yLB`0>a-S zHNV!w-DG)mj)71iPqP+@&>nPoGfz28y1J;X@)>o1wU1J#QY zSV(=P`8^BG+yC%Qw_~i9Snizks?ca;{v*l51DmXiJ7^OJW;{uqEcc zWY-mKSJ(}d-%^kOg6t|l0y*)@!hzXOutm#Kf4 zzL@{2_C&oe;(z$}g3T{Q{~U2)|JCuGM?mP`i9oskJ>~`77jy6Iev$jD_fwtllfkI) zEmh}JA9D=9qWB_}8NxFaELI9E7L`q=RwPSwQ?6EOc81*M^iqn+OyN_5%PHx!a-QMl z)UvFKz8TlleumCl1bW6!&4TJklx(SOi4{2xAZvCku`T%c5YIdPZg2=ZR6xuF-`3DBQN-!(Yu} zFoBVo-aLAyW*hlt+_thaa5?MOHq?_`%WN=B&%8fJ&rV=+HM4vDEy!Fm_(5sI{x7eV zqko7!!@vY**1kdR%v~#bbfyRc(x%n4F~f{CS|>`YyEFvQC~KiZhkmUr!`3~sG(+DS zvXM@g-k6(K-&{@G-mI5~;MRKDeT^-{&^`A6wGHr$*){Zx+O_ly{N30yV%Ov|V%NB} zQL9d|ZGks=(;#o?t~0&qcV+9g(G`K$SZB81)Yj}>o8D-$rnC9E*1h3gGrkG77OqwP z4DrHuMW7Y`jOVswZh^STygA$keT}R`<-Nk5{yESVz-L}3oSPpP+HrTo`n%|0R+~4q<)Nkt@(r@e?{4(_p{~Wb5uHS6lym}FS3G>DE zUgnSd9M&KEvdW*_YnnIt*OouN*T!IWyP?tiZ-c?;Uu(U^?Iy`J*k5(GslH%e+y21k zP5VPr|0tT5^3KgK-1aSlQ}(}Cyt7~Ae+RzU725mfS(XO$tTuURYEvxAJv-CX2c4JC z?t5Awc5>Cn!%J%qAgnO&53SPgl&rGfE?TDFHd=IEJ6d=;DQd$Nr2q2gC%u3(NO{Ml zm-UWLFY_NPtK$5r!p<-Cdc}1m7tp9ZdR!sbFV!E!tkAd*y?pLb?~PrrgnT1@=I>Me z-w0GSZ??1UX1H|1vW*kHE-n>%TyYtR+@c50kbL*dNdZKGpnm-gSKJ!*Xw@C(hi>;m+MHWKSTO%N~cZ&L2py9^d$|qF)zd zPJ2j>jlXK)1o}BhhHj@fCU56E;{17z&A)PE>>qB;cgA^Gx;)*-l6yFgJ--acsy|G} z1YSktkK#F(UyJ7)KbX$BJ{&E`{D(Y$_-_Hv=Q-UUEpprM&U5yU`rY_P3>^5U{m(zZ z{`Ef6eHA_We~_J1eNkY(=IfDvVW#KypJ5LhxW^v*yQki9=sCX%=(2s}*O`47)O`!e zumAkA*GTEV+8X_L{{GW{-j%|Czct_gfO|y1#g+1;OX08%6D|2lZ1noQ*x0$ZYD2G{ zs_F`U^zc1A>F~Wh3FxITIYlZq-9pKgNl(VXqBA*-TLw3cTYO>>rvbxKPD#RSL0!yT zow}IWI+ZcwI@KZD&&=-}el)pLEIYMRE<4vFlbPhHoSF4jqnz}{Q_A`%XQq9&J@rIe z=h4iZf~Dm-HB;kbroIMsnp2}Rl~dC=)k9maocUjryci8YZY{pCn}gm zJr&DFJ|%Q>a|-E(Qi`Yb#iXNkm?X4yxQU9(um-LVOH-R?+oS!<%w(7K7phbf{t6b8 z-m=#QeRUA6ng+oKD#0rq(?YfCpk}UOQSEY(CbDAHNJpe>L9ZC;C!uGanOoS+U7CCtAsnPRz-P z?d=o7?ZFd+?S;t%hcl|aXPdPh68obm0-Po|f; zd!1{aiCU-L(oeEhbq~T9!lU7>TuQ$&A2kok7xszCc6!R%!=8dq$``wd%Jv&dyTkRQ z-V;-b?}5aE*=7;=or;{uUeP;@Uz8WbjkcP|M!7!vHHQ=Wg1Qn-*B+8OeA zY3wSu92h=_(OeDtK9}`X;SR2@A?ymIx8nfrjr)^3qb&$rngoVjUWE_~0hj>o=J1HJdB5dcng_Nlc10 z`@c!QR?3xILYVgkfQrUADGdA4j@Z-mt32cQb8ZLGJa^?y+)+_I;l~KShIRk8l14P` zMLQ@_H>Ul_j>|pp;2HO&KRn@xcv+7$(i!z}PyGTuU|=@p1GyxfU-baqSR+`Uq;Pw$ z&*&zqD}$6ZdnRWLJhveu_d?T4;{5(ox|S>28Fg}o^^Cz0chrGEy>3;YdwjHeS!2;8-Ae+H zl3@l}`lG5qvfeGK@v}aOPthrv>tTEBx>%(6x&`7HKyZfv+ouDl8H=O{Mc?0#}}AD^!wR6ct3%iSB9iupq6 z`NmS)EYQd%=lu#rhJd+74bd_YZ}!t13IQGBAQ?oKMxN%8L)ZFQmWIOEQT8MQhFh*p z#+6*uiZx{}#Y4m)`NSvgG#Q`biuEX!HAn)keT~8F${;mdkNYz5Z*LsC1H2q_?~qe} zQ@Ih!v{TfTIZ7E~RT4yN(AK(r%=D9SJG9DOFd2XZb9tJvqf!2NuxJU*Ql_JQIVC}- z4ESqHITSx@^ayiFy?Z|kd~HU=T?&9`hf#LGPbTr`C2BK&-`m)*VYiebh01o&Phsff z!P1bYh?M_q$vxUOujmeZWHm->KtS>U#s!o#I=2*u0-)4CRW@oof|+VWP#X-ol5|rT zyq{G|4Zq_rN)h7_sHvmeVqe?bXSG;mJ2|+|jTmW`UA8`cnY~iY-S7&o zzSZQI8hzEEB>vZq#}7+iC{``Au5%`%gOR40>I04l(=J%2ccqf4GUS>JXEF+e) z1YC*dg0QMo#M72KD{Ttn0-y9qUU=ya`~Jd@j))L-i8LsnBS=9Z74g?OZ2p?!aB3gS zB#huoih0FHwrvvGZR1olZT(QqClqA#>i}Xd%AYuj~&X(Wq2RkFYTL=~(ZlvaV#O88t z3fvF|uM6B}&jj>*(e|UF8}p{8QlxAvi1Wk#d^kL6-$7~ z(pHQ+0HDViY=%9QSp&`!7`-~*`>C(Pk|oOI6;IB##({E69VD%aft&Sj6M{wKk#gdB zXH_`3?5BP-`8d^ImlOu@>J!d3f-L}Qu{642%tcemq*z%cJ~l}Y;ukofx0pp$>yx}B z_B*q}2U-Kiuy&z%S18!hZG_pYxW7VI99JRk*MF>5K+Vd2kFI>vwwzHjq}K?BoK;dV z=teq}TqxMSV;`s4O6=L$CiJ#@lQxj}{S$oS_TchkN0`tzu>V&x$8Uoj)l1z&;nzB7 zvJnZp$cLJC-N&(*O~Jk$%~=APJNVbLr~h~T$nI?VXMj?#Y5KcAw{)&JrH&tSu$6hj z#c%1;!oRy(zASOM0&B9$A6WB!=TVJB9+2Yvhw;W?-~4Q8G5vrJ{$ObJ1ZWI>Nu+TR z3ILxe1d7^$Q~x6EsTU=xb|R{sjF!SyU7o|6TVKje6M^KK>{=M1<^2=CNNZyh@?3KocsXb zef&g5_;InsaO-UGb}Dai?j5kWD=#OkJ;4&znRapS<^EABKUizP{)L@!=7E}__tU5y zzd1G=d1?N{u7Jkhr@$G(jX#|3oWaE635B%doUav(kb}HmD1Rk&00*4S+Nb>s5L&dN)Pa|Ga0A0f1VJI>Rwm3BO1Zj+J! zc>rw52Bl7E`HYTR;#V4%n?u6SEBVjW_v|;F$K)B^n_pnZ;pFR)*hxD?wb@=m>*Mzm zNp>89Ayc*#;ZPRI(3JWBDRetg`Hdi`y5Knh3esk@mjTA4ebHUkr*D0RU@1e?ySff@ z;Ph0ysT#wSwIo(^ALeohjc;*&AvZ)cnrp6^(eb0;`uBZab}m=9({Wz58~n!G%px}e zPSb;`Iik&?xU-2YzcjDJkXKRG;t<^gr@xUzaKhA>&?=)U|M*oXM zarFTQg77?JF+78nLXrKRH}LF+we+mk177C1J-4ElGa;@P;T#g)yN7^5{io1#x4t9i z-C0NXwlipl70{~94Aew6yqP{5IH(gT^zfE@aAo_|RP6G8LSKDc97tE)>T|uo<#Q@s z>A{(GjF#Kjw3A~(6VP3hKmpdIsE*zP5AhuG7Sh?zLX{$O(7XI zivzuDWrAdey9<2@0&KZ-0A3B5Aa@yRzf~4*CA!=eM+Db&R)zN#tBF~lGNTCMb>hOp zfJ>AA66Z1ecQhd5?pwp^54hv+k6;1A|5R3A)X~w-@qeEnkB*a;M=?YV$yNT+ykcRah%yKH}Ttk*Wf4}S)9@rwg{?aQ||R~YPo zrVVOJZqCQ9W7J%cV~UYVTUBs5y9`)tjnb8kJF+MRXdnPwJU z3R^4Y;QCFq@)(Ml+kqXw2dRXOEf$qDib&HIYJCsDgP6nl{hg#PxK+XN`5UCJ^$vg^b&9&N0OAS zhv^&>;LB4(Ubl7~{cfld&5cxPG6v%D>p(@oFiXzA1O$U-4ggZ_wG+QHv=CkL&`+^(KeYj^H0e(yH7a{Mqkn@ zYV z?EeDuA?j{yYXASyBa;*U54&qQMXp@54p&v7PdJp)SzsQ~ zztCL+#sH#Wi~av1cU_)AQLv75Hn0ABd8r-z_wQhm-5^mme?{rJ$EmIK^QFR=04%3+ zipHFVSPK~`79w0d3J6-Y*#7(PnxC1)?1R4f>@P2{NW7AfEp>(6&uX1rFUX`Bkj zklBNUaA6w;k~meoG9&1wXyQjPNdr|2`pRO|g72KPXbx&p5u{9qe_*j}vP8he{BaA^1M1+n$RmNkD|u3Q z&GwB8wtyaI|NMd=bNjO(FiJWR$3Uh$V%!kEQdiMV7)IrxhB7oIkV53l66{Y>7fDG& zB8|>aZERLmJJrp5?ASaj^yZlx{5HFF-Z*D|6js6NH?&c%%?W4|gU>WwDX)ufql0%R zuQ5BXD8%+e3XmmzYEASs7F3B8pnw-*f|WqvbXVe3+>0jI zpwo8+HS9~e@+|dR_yIp`My=+G|HWn`_yEnHFA`~(;UynE;d^<1JNetY1ALJLK1nWj zKH%$d+{Vuty=2;`=VWQ_O0H_v!8&^7yjgxfyZx*;*<-))q>qb6xJH??nd(|$*jZZM zwb{K!1CNogJ@ISgompidz&+Py-3f|pau%Vwusd+ecZbS5m7j}-mpWNL35$W<1P5D`}|NXgvhfm#SUutR1c=DDYVXN{K%u>5ljeA-v z*x5}e0kK_(g*h=c;V8d*NmU;O{bB}w;W`+FXzCWq2M$aaj+ci5rDJOwpk z9@nD2qLtvDG@2^*@TJvQ7l=(&3wamRRIlpIRGaa!DlNslc$z9oHjD==GPGi=p7!ur z*wPU)y5KTC-_eV){ZKupSE$iRJ#bS@BonT}NGK&86(tuEF3S?CBpWIv6XFlU&pz;_ zQrLYCLQK3$Zl-$nF4Sc_sUHy9|G<-AnTBI6Y>^Lg;T*b)gyZtZon(Q~r;9_cU>1-t zz7zasM?C#U4^a4V|A{~D|9{MI{C_**|BvDLqim#z7?Qh~Vq31O{e~z~Ns&ySER>%& zpQd8n9IqsVgwkF%`5Z(?(>ZM$IYNzcV0Wh_i)|dm-$!6NkkVlRlpH zgK_)ROe!Y%UZpTeqJ%79OGFUMX~pXuqjsz@4>~ zgM$-FTv~~1Z7fxFJA1h4pUVd48SDlb&lrQPf1ej3qRW&})kc@-(F3BBt}cuJX(^G@ z1oX)%B6{RyhM2Mt{0dlP-VCU}j=OLzE?$KRVX^WUt;Y*aGq|=+q|Cwyie+ge)$QMZ zoSNBK|Fsnxzbll)0m?}9_<~|Ewz)C#Ak|!#PJKi@ocd;I`w(vM@3NVmX+b_q(cg%h zb#P&7hA4t@r0vqBn+WszEVEwJf=$gdnMDB&Eel zO3-_{?$GnXUY*NN&q#DKVWy(Iz2>F%uB$k+#Y)4AbiHbmRj|pZ6;~G>R+(%B8WBXq zXz4@nMl6Wp1d%2{0h;I!fS-2ge6lF39-lWf#j<=$FB&@@v0v~0;@ zw_xEA??w^24s0sHJwH$BU0j17YYb#>26+NZ6QTeL1SlMeS^x^X4F>G=1MWXf6?+A> zbMYsf_5T?+xc{f&?0+}a|2=eMC;S+yA!2audWvl)s^;AXj;!%74BgKnU=k6cg}IG1 zsu4uv9Xh+y0oT^`?Seb<^zL~W*{)m2*TSf?05Q7Bt?6`Trx}yu)f)nS|IjTY{42}S zTE1sz`#hf$hDV*NXO;an!`<`WSR-;?3{mVv%d7P-l6IDUd4+2tU|#xoRHN$sIg8iV zR_u)9(9Gno%}C-JJjqf=Ig)}DRqp<&RlnNLw_MYSNF#Yt;^aN`XlU5vS$#C?axRMS zt~~wkgCUn0PiSUYgF2IEAn6^vXj#jG=Jk#US{(zZF}b6e*vzHVrl6Ydnq+2R%wAWm zYPeP@oZ_X?G1_PjV_DEgwgtv&Lp!z7Y(4#b886*j9;IA-Xs1|&)!#O$?#131IhG}p zyylbw54yIXK=7(RsA61bG_vh6+dT&#SQ{}9v4VjM3kh`~alwGej(eHkNU8q<{lZ#1 zBvarcQZS>k;vIZ+aEgdu*3#!>|Bj|^o=pe2h}#o20B+0eX6J!8??b)?)0iwp0T8k- z8d+i}ZOU93Sr!SzX!ns6cSH>^#OO>L1KXT;nS{ercbO%#SKXzQUfxEzS>NZ-c6@W% zIV4-Hn>GFkHi(hg5VbWw9r|x>?X8uXvjZLo2>*vF_CJQ#$twQ`Q!G2p$6I^ZW3*RX zeIeOo{a)HO%9`2%S;87+p9B$UpM;c<&4PomSvcYZO*G!tnzX^B=t5v^1^t{+N?Jd! zn8jZZBy)9{I_}6OD0Kl&gEFZpc%D&1JRj`6!-voMiw3l5mh(lbg^=>@Gt}An+G*y2 zr}yNgONamA-(V~-#%*o@DP^M%hr@PU`ZmC9!|iB6l9@B9ZX>bXdSObdF!(tqetux2 z2hNNsmFa;?NTHj!o_an<(gbqTtL2IzF(rnqESs!NWCE%yedv0tj8tReD?Wk_OUk6t ztVBEe6!BH*SruIHqfeY5^&IaA59H?Dna!pe&0Wi=euWmKy4XcJ4yYfCBxvyR97!Ef-7UP zas(+JI$gEwp}T-vztCPa!_!}&;i^uQD91`}6PDrhW+v{?SS|8zN{bI2Dk|lA-0Gvs zn~QtRFmyi)=s}aBEY5Y49W9_~ZnrdJdRi1pQZXN=;nApO4|L;kQ z)Y%l6lpHMYM1@nG-%yn5$SGL#4o{yc=?TrO=p+-tz-o0$46R`DhAg?W(Prch4Xm#k zq-BZ@>G&|i%NlXZRq?Qz)E3;tsay|lI(jEY{yR>?$v$^ElYv#Kan%RN{weIV{*{%# zZ<7tsPfbID_=d3J(N&UUaO&?t?3nDxXq4+3L{ih8o~ERxQA=!)X+D21ZjeK#Z0F$P zPLmf^#Zr^xQ-QRd!ZD?qwQtZsQSq$QZX)WhdI92S*(h=mX>@WWSjll++4Z@TX40l7 zMx9;jJdE`l54vN01rJEu=VdB5GaIduoHF|U7(7!_;5Tyq8wcXmp|wY&5qt=BbRdb} z0%+YKgPU@}SEWKtI$M8B^sSuKFe_^#rz<*r*-kD={@S9wu$eadgSt5j_B^g_q$zDK zp|_vbODvF)&2+VL0Sj}Eno}>Uz2Y*;HdL$OHhz?y8F*-|@pB%;1nYo0X|?|HIZIBD zLA!rnfH7eVW6IsrorJh;6{659gu@vYwkj6xar#t;#>!<%MX#h{*y0aJC)h@c2-%nm zas*2!cyeG#Gr+lxo{=Yk(e!$KW=z;`D)%R$Dys_--w#d*6IYe>=T5FeZU82$3d;7= z8kzbfBABPyUSzNy#fa1fb9Nz{{z~eS41d^uwF%Q8LX%Ai1R`(g?C#!bFazk2;mNF9 z=#&vGzW2?m9kL0Jfs?J>?_MGDe&n@oD|PMo-|v~Y|L}Y?8Do{+(bRBY_Q## zSq&grBcp%s=&PgdOV-uR?!KGm<-O~PzUb%-^d3CE%#oC{yT06Rs^Q*Q-`rfpIi&k| z+YZ>EOzyax-Jtw8g~~SU@71Qh^6C?CF1Q$BK6Ry54*g4Qstt5~s3Z2n6yaT3u#kx> z9cNv)gEa@Ic|SN`XGdv1E~OG7{q*3oIp`uY02?5~$IGG8LN?ZVsZEZn9O|^bbvS6Z zi9mqZc9he{o4{_$RWwy(FfMb#W<$bBGbf%f$aV+1`4Dc%Y^%(^3uf5awV^*IImUE` znw6qL84`Rk;%je z6_Dtk8s_J(P3kB=;bq#A;wYJFL9JhrrTV65Ki9NE-cW9}NNFWe*L4Kz1$dJQHMkBX zYv!XiOjpi0X$)aH$z9NoyQCT;?gw zLt5rie7Qb~G^F}myO8d**GY~nJAk~CBK)lXEHLyLR-^4%u8FiQ)NtANbUh| zo9nPipo)lK?~a9UMeE5kX;Xv2IQIVD@dE$eZb1ok90LSzrFU=asoP;TV-%KMqt5>k zFX0x{$l?xISa~PC3uA6ebfyC4v%>YZDWS~WnWV%m&)+~}GYbeCg zf=-4Fq>hz6b*r3(qP{ZR@JHI;!yWMb)Il)1r`qJ-Kc9BgW&G)f}H7 z(b!hJqM9>An|p4@u;Kendjg|y^e1e+w~OC4ADokV*>>)O_=BBBlWFQv7=C2zv5xcj zCj;;vdr3~x&rUI5Q@6BskGRLiiraGtb$j?-A$*L-DCY?n(hHHL5}oqYK7Zg)O#8&4 zy5y;${Nlwv*{+4m%i}aySKA}9cx|-BiYX*-f#;c%mG`zrH2Xv?oaZL6XHJZ`4qsdU^!#<(M=7D4NngKeGs@a!3Kbv^o6l?W5$fsK%May#1I4~AxPwSt z%wsCZjBX=I4q6>gvM$`8-x7P_!zPk_F_aKf6@Nxff{jd)e00EiFm8L#BoaT>K7#YY z!OkQyd@-zv@`R23wafG7v)nxs&fg^e__+Eneveb=^RDit-%%v64deB%ar&HtDn%0p zl_f&sAKViMIO_35N&jdKopB0>8dLI4G^5n@7HXM8eKkX(`Ee>45-!c)a1ruK28Tt- zN}-iOsRHX_X!>68Ehx|1@wXAlCQ=mz=u2L)3VrT@U8-)+Gva@$e6;8MVp_JQYTy%< zzhs3F*Jo!+I_DAWr$w}l6ZgW~lwa~XM;)vTbuA2Y(QBX}V;rlevN~_Ecfwmn?00{! z;#?PcQ(?34{LP!V#p(CD)Q&P(vV*bK-7e};wi@C2F;Lb){&d`zd<+0_SzgMK0`OKiaA2BSO|6^TIMjt)tY#M=``C5T-S(mMo*U12(U=}wa< zsy-}JV`5sT??hu9qb-8|Ub1IM&6arbN@rI64b{z_SpNk5`jE|bU+$TTEJ{%_rSXjg z4y-*Q@-51U_wooL1daRIv2ZY^+k3@uR8Q4{l>3wPfcG=jXz4fX6j~ zr&v3B3(vc+uUae`7|-jzJwGv~%e18~i<#_|hIhxI>Nu9YaWj|ah!8nr6TyK1`>l8# z6%rL!q+l@sg|+ihyt@NUi_HL1OhgTl5%MtO089jE!|hfJ)!?3 zZl(J&hwF+HqiiE)(G}rB6+Dhvrnnl^_~&D8QZnGR zL=-_|xN?)4)YI`Vl(go>ejQToruby(_u4diil>T=d&p5=>zq3fKZ4S%@YE5|1Lv3! z{QLyc%mKxudzxGf(t#q|9i{_5`LG-2A#{UxDv!J)=-&gio>@GeNqpbFFP_=J&$v>L z9P>9M`deeYJ#f7P(Vbn=oqh7I!O71U^`Kn!VI5y8^!p5pBbWJpoc)6?%9?#z#yV(}xVyc>i(SMy2Y#x$o{^sWOXa>O$oTK>VGx#Yc+l{3 z0@-5>vpXp2i?%lom2t}Ff?6TGH zgvl#mves=N@`v6t&uc!!MRdCRKc(roi=76{TP0IkNg76df zGzhA6YW#i7E0w)O`i_|(ALQ8ceO<#BXxXtA@{rHhPkSSI5YkXCVTZgUyNLi@h&%qaLU1!+XEzEp@M)$(LZd8!{9_iqatY8 z1uZix?g5Q)e)`JlBuGbUnt#5*YGpmULn zH_liUa>E(2oD?7(jiN*NR~XM}-{QOlyn&b}xa!Y{v1OWHP4Dv?F>b0IWJt>=1Aj)= z+*X^Auc>A7{*t$l5wM{{3=^k?{%IP`A%D7A)#WHksp^W9L=zHvqWY)9Pw;dgM5>pfv=$o_EtKNMI^#6OpV~7ORUrI(jYs@$`t!;bc~=l_?NCVdzkNDt zH&FFg5s|IRQ8481Se2finj123=8|e*nwFKjS+Q;05FXy6E0cTe*yN~Sc0CbV5y=5c zROXcfjlij=BqSXcsM%8}sma~0m3Onx9bj#d9;UT_6(FRXnA(z5M6_vX>!Qn(TUhA$ zr@|QtM0e`v4R2!C`;@A>R$U&ynvt&Vb| zAn^h~k+!%8xCa}J_uOADOJeXm%{L(AD7x~Dt51dNMh3i)zW@VSAurh$s`4E8tHyAS zLq-A2E5)tFKQQer={!V2`mI%rNY{|Xd66uImw%|k5o%FUnliVSu;hh%F=;#KXYv_A z$A@ATKeJ(#r3GG3!(d(&{OK}}qr^d7F&11{au+suK9m6&=QpRwc$=P2dLUN1!gUuR z5=ueq)$P-!zZ9Vi)miW*FDK$qluo73J?->k6_27sIy*KN0!RZk*0x&A79&R9Tc)FN zIO4w1`#VUmV@pzzXjJp(qN>64SdA+q9AC2)5XZoQF|4EDP_oMe1b&2)Au-7+>jnv> zl%bvIT;#3GNRn7=))ux}j0QtO<|@!Kg=H@`)vPt~ER__4c_2%SLw=P~FfJWNtXH8C>oV1$J^OErAL4iqN?nLh$o?!QHaD- z&?+gy$|j|hQ7}qPsw80%*Zh{jS4>c#DRB!mrcT)Y>h|Q(?d?>)VRqM-Ohb;ifgLS~ zkB}3dK+6vQ=iWhtU29=o!w_#gY8jxm%plajnH@FKiGjo2J`%2~A)V$yxz<2t~zGf4rI|asIq{X&#*JUl74yAe}EP8h$Su+>{G)@s8dM8k<1K5w^_GxnpwVU^OwY2@waj->ZZN*|Gh-Za!3Z&w*T-vHBSW?)F#X1n( zB#&wV1yesr37K{ZwE4MkPG;2aC<~8%)b-~$$tVcn43Y3d_)$Fopv z_S`vI$Vr>59q71=Mi-*P!+P49IhUxuQT&2vCWY@TJRfR?&Mj*3c=Ov- z!W1mTtgIx4G3*s6h6sgZ zjd@(LZPCwEnc>8&=OMXUS&fB+LZ$57UWbUG>7$?WM}$JxsK^tg+eSH;WEOh4py{(} z#Z*cVUV#k~W3=H-dnp0BS3^djV(JWfnCDwV6?iv9uxrNm=QvasjI#Pxv)yq6gYHH2 z{VHVR#soTOvF#G6iP|c(GKC56dKoWKcds}go z>=Ok2nce*WD`sCvC!6y0YlyB?x3QHVskyk(uG-h+Ay4@L4Oq5URQVj+-5m`AaLzaE zl?JS9bjZ@=S5wDtp~;CkF2*Wa0nmgPQAO<3YDs#P}35k)p+rW@mY!T9i@K^k`(>5=g!rk&c6CU)Q^9CRcR&R zyowZ%+5kovHkJN*<31klH&_dmGJ>`WmHC_-a`fIDp<6I?8({%cjj?jaT6o2d+lB@f z3T8+%uUoqB7UJ+lAMiAR24@9U{1->n@3%sd!5KrAp?au*9z+M{8w!SzY9C`(2OYDI z9Z>;_C7r*YL!a~WukQ0p))?!~wfPVcw{C{j0n=kfUb#9_*Yk0Ww%9zVm+U@lZ0P5I ze1Lc7fW_N`U(KExvm5J?}>{Zx8)eo3POV9okmv#&_VZP~X7XH0_0OG!FJT&c&)-jefOKG+}9a zkmilFvlY=gl5F}N{&K{03abqnyhu@;FbQ|Ylu`2WoDSr42^ZwFSmo>7uyMSUt0PpK zj$B@HkhfDpOO3r9OG~JMZt_xb$n|UA2Gha9LB`g=RJ=w^3NqE`h+`u)ET*b6*}m?) zE%T8<>CpiAEp&-GVoCJMM1(G{XIFu;J#MsHYz!~}t-qCOo*+_X2nA3W=_?rODKyR@ zSg_|Xr$tU%NDWPsOmR4efkbb#i9#aK-B^PRrt zi*hPXFXf9-y3w$**307+65=Z~wGDv=HPEf5(ycW9P~ zTl~m3zG?=EG#IJOOv!1hc0^!w+cgvskUvcXMOjI%#1g{Z{)oip;Qac zc&VoZnIM}qieneaaW%vtq52WT2E}rT)*jm=0>q%2WQ*k&v*CXPr6-P>w3EY5v(?Y* z`FPVC=C^|eWM~*RKv9u2YJ4XpDm3sltXiN|{9>*h7R=8cz@`~qwO6Xj|1Pz(mzP(! zJBSJgNl7r*r&(#5sSoq^ii|dXtAWE zGFq=RO0U#O(p936HUaMuPRQ4I@%+6-^$9L>Gh>Cl=@7NU1d2xO3^vRhn+ z#`-Eud+`_?sk*sgWf3p-E0CMNg%JwQqT`%^YQb9J+No|8_4+Uh>Z(AhtXSxs>y60o zB|#N?)Nq&2oHOIiVVcD+wP$tBC=DV~Dg}#_aYfcR(YYgRh}dUA@|gT*(jZIr7QxhV z4N{pWGH}MwPuCM=&)m!2)hWy8dKnKH@uRz75qat(1d6L$FT$~nejSN?c_y+^G{F7d z3B`t_#KvxmEZgmq0O3#i0rh}Q_f~}He>($@^$(j&Xo$Of$DXF7biqc9A0!sad=4E+ z^?nVdScMAtqJwE?dh5HA=*Zh zdSF+zSi*$U7;U6lbtge0{b< zM-$UDT9c3(87y-6SzkiIlysq~K}q;ajMY6_@JRF9=;_!>eI~Zb{meNO+C`XEXaJ~&c9uFNSQp;!#uXK-Fe_r$J7{B ztEvIbx;U?SV(rg-)3J&!G9~b)XNwr3cBXQL`;tarJnQ^VxF(5dlU&Vg;)O;i@18PE ztqyZh)*x2s+g(Rjc)^ZYup==yWJdZV(WGp#cy1xp;Z0@5R@9N6S3Gi4zl?aX9F$;(}z^&c#hUbU2BZ|46L16a`+KDxIc{HsKIlXf!7K zPYg!z6^{hf7PTAGhaKHfAG)X3{+L`$*%lVoFWdq!og4X>fy_ z+a5Yb?Ejh_%m@k!v((hy++58in#mdp7ck>)TIw}1P-m~pgu6p-Wu3~qo?8_#;wARw z0U_S3Ro4lA)(;Z)W{)NQrP8_Q{#!*K_t*ALO^*+wK*AS8IPov(eWy;>Qew5K{T~f- zAP9OoP?U8H#7Lke2+^7E;q%2b1s@1B+ET_dk`k4N#56S@kY#el#&@veoFN`XR()?B zJsVyt-tgdMXXMD?QKh^3u8qX+70Iew$`|3MkC^`BUW6KEjb$YbKWueA%_}dE3ppc3 zee_#AQOT#@=#Vo8x|0B%<*wMpzT2D66#QKNg`O&|-JNZx70OeHq1F3QVEYp3l_WzQ zI9pI+5Zsg9JU4}j4j^k`=s#Q(X)z!w`IyYR!mMP45Q~f`%#1J(3X$Mx(Zy+j$yK<7 zQ-jNGu!cG@6zF*fFb*i_yTlp+pc)aghFI5wjw`fuu>AoS3Ly|2eZgaMVNXiC`lxo> zf(=c;`=aN-s1dCnyT9-7cM#e1f^>gz>+psJ>v&V_4<@X3)VmyvoC{9zhm|h}YS3+z zz#2Uuwy6FHUmVYOcbY?OzAE($nJ-!MM<@|WeDjI9T$pDMggzs|!S?bHF+jd9JnV{~ z6h&3+fz|!ORvV11$wV~)-PK9i?b0DK_f z^DJ9sE z&E+E%EX!+EvaGHWS3?BbKE15~oLi)=u&*}g+@a|9Orb;r!6ZJoDi3zfk} zoAs7!7(Q2ugY&^aqE3zCdc(tO7+?V4gsGmDI20gmL2W-Y&0$VtX@A*S*58((Q~zXl zCFtCCmPix;q>tXQ;NASu2HU6M-IDIojM2 zMt1qfRg3pLZUq4SoVw|cte?sSm*wlROr7fUSsB%%+C!|Hh;p8h?Mer$ml?{9@OwDs z_9eqs^I6TMch#b#J4SZ#W{ba2X?r~p$JM%!O-qr8CGRgHVfXdlA1H3|m~J;8 zQI@q&Ys`fqkRg7@E`S-WBPh#8Cf_A(3N()PmZ@p$GX@|5bV#f>sxV_eqQ$Kod z-A3y8HN<~jP~Rxd=C^9;c=|^BHeS`ow(JmJYDCwmSVQ^3j;@F>-N7L=#4eFi4PYtJ zjaWO#w6$zT3SJIi8|(1iEKR*>&GptyWC+ATL^v@Uw?ON+d3UK2ZMggCP;9Vk3_wX* zA&UM9ckc_qKBj}9j&lr`7+69WI7(cwlf`m_Ar7Dubf)+?Gl&XoQASC66FO{JNIJ4T zV`Y)E5K{+E4<#qEvtAe%A^Ex;B&1t49Rnbrrm!L47)i%=8Rz6^5PCI zx?}zwE_6r#+vnsC!QaP!5b6%jKfwLUNcl=BJ3tTM(#yl{l6bhYYXYHP(CQMoxTD^P zNVVYBE1}TK$GOAaj`=&cdW-FYSG%bB8RHwhde-`C=LyhuaqJ$$1HU)t6T=#W| zM|?!Qk=NbfIA3`j?~js3g^TXxCJq#-b}1bnGRyzm5aWDxM!SpseUakpbRpqfUR&Xo?o&B zquv*2C>zcLv_MWMCYV=!akOV zoG}*iDq|a#2e#K};y0R=YprPG?B9-AIncpxN~+MZ$KN_)<6dJLkO*Aja5r2L!$eZ^ zSuT8$tDX@cf}zJ8f@qjyJtnY`6VB@1ZJM}{CXc$I8tHbEdRpOn7KN< zqznC-uk=3?c0o$Z8CN97xp@&tvy9OJQoe7TNeZG!{0J}>n8{;_z@>Gt2x|=69MBO# zSOlBD>o}s;58&~$uS?9~ zUKX{#QY`N^vS5UsGVusKI0T^YlF$w;HevFYlDfyI?2~H!m?7FLO7)Pw1=7sCC2}k2 zgaw>zK{HFDkTX_w;bgf#`n+XFz=|?2>%8ZNz@`OCvvQ+z#Ea1ItfJ^*P>6zN2?=6G zco3yfvKWaBQn|9siY$AUd4xi;bA)I);%E?`l1K?>RRhTnuIaM>rf6i{0XcSJZ2>xL z^(jQJZZ@Owz55q`xOo@)9pE%d5;7DCbr?rY{$u zzyzmPSzwLVw}--V;V!@#Q1{n{KSV9xOS^jlI^#s0$R*G@9XHu0%MW>0qVFSi;H25| z*;<;RlBV``d*vfu|4J3&E()159002Ed+7zr%mdBO)d!0!Bd>7%W~X93`MERT*?;dZ z9Mp~(UhVT6DN?Pdw?;Qx?-6jBQ8Sw<&@X;b7_r-}-~c8*%D!1cc<>$n%>DN~1TK?{uBR`5Dm!9O(9S7KV!mYh$` zrT50NCv(M%Qc*I?FBUvIsipVwU;mYo`hr`2A@{OzSTNE8Ckom@Um8Ia`5-5wh)PxQ z?D9j%?vCNLVN~>4{k{jf7Y(Qit3kwSU^bxr*9XvQA3JVN{`ds0-ER)thSg%NWU*2n za{CuQRkrMiN^3<~z?$*I5}fn6fj@cO_3Qtk?3{u$iMlo2W!vtuZGK(Vh3>L#yS}n* z+qP}n>auOynmRKlCgRN1KQ}uO8JUq8d*xoa^Igwt6n4jV7>^*C_(s|S?un^zOgKM_ zRTG0qA{<;3dnp395e)4KvosfL2@PLRXgHAFkPtCqTUaO%{trO^pcXJ_MvWA^CNANs ziYye_fTT<}psybMP*Y3z12!b7mw{n7h1yS_6~ZYuDZ zM2pa2HI4lQI}I4lUr4`lp>}eDV`RXnavA%@kn;Vy{AhThT<@WkXY!Z-MCbYwiX}*Y z+lUTJ^MoSJomg@pw9uzBwMywrj@)yw?MPA2t<`|o`1K3onZ<_|3-qJ)fPl$Z`xf(6 zKY&}gQq_N!BmBrT+acL^GL(?c-a5PH2`&-I89zhD?B@V%fa!KN1~Tu8wBkGSxvhfkBV@CrXrF@%?@NQ?skGc>@FFNM+rQM-AB zhO8Khe!;(G-61Kgr2GhE-*r(1+zN~ecLBA2ARuBxf-M|ySQUQX0A)qEbTc#Ug!KF0 zP8BrIAlGzj9Vyj3U7lDpV3AM}5*Y*G9Qrn_M1!vxnlgld!^&Hh-Lp!!>x9ef1w|?n zTq|wdYO9jF;XTVqY9WLFq8AiN5P9xAZ53_CQoZZY{3`U`6rwh#FBzgPYl)+N*%5t^ z9b~eIIxTK%|md70_!0wy&t1@^KKaW64U0W)ri9dxB z?eodPmGo%dtE4{#M#=9`ko2E6Wo13E1a^o`wrD4;79pryDaIKBVQ(x}6nB9OevISa zanP7h@=n-=@Q$$84Id{E&cDbIQ3pfRj7Md=^j%3M5 z%k2@yygtlDXb20L3bAG4^qzLG!~Wy$%2eCU>VjAf<-vMB0lnK|Ls~K8(J7#wq9(Vr%n6N zSmbX2HGK82KQ9}h5`urQM!@*g9KsT3RR((Lv{5VDDhE)27+n@^)@|}4sjuz z%+SaaPyt(yUeYACZNHX0<#QTT4BuiOSB8DC$HE_yo1<%X)FRbB|{G~F2V+Er@WyBtrc zlBsI%VU=VSzpx43e(w_&G2Rk<-T&!n9MXkM_wX-M-7NZ$$#ZOCPmk_q8>gOYiGW#R zZo|=-diyc0kVMU70iQoujHE%(viY7WHbJ0a<{oBc!%>An?098rQ{GX9eXQ)x z3lz#V=Hhebi}s{OUSgYbIsw}-vS;n8MnPg$UVkskq&>7nJx9J~y?SFEp>yit@r<}Z zEin&n17eQ+YE*y9PvfSr;2ABa5p9;eB&CmH$x=F+tz@xHJDb?U3VsnJT)4Nm9OQem z!b=`%^6W!<#uP52XyijzlB*Bk$p^ur%O z%Rz33okpP!`~+F11CvFcnX`wE7j@+EBe7{cbY4S{eaOgz>O9cKS`zPs(7dx~!u9?I zXNtyhzAQ5%1HpIcuXIQ7)F#5XMg97+pv{T3c0a8xQa^H_U4#1jX>flPBHm;-8_Q2% zGVf*8A5#iLr))yyOG=^sDAI_%2%eM*HA#{TbX1fRC)nrNAV1x*L8Zf*b+%wI+`rNv`2+aX8c7!HUPNt)#KWE^C1g> zV?DXr{v~_;MSu?fLzVdkOdgpQh>-v3j~XLO8q5033(Z8r;flRL6eBt`n*Q(<(Hv%M zunu)J^e+oVoGl{m%e~;UN@+zbHcv0XlPNIqO7POx#exHkg9FZ*1FF!H0ki@U!;-M5 z2BO3mjyafKD29Ges0seTl3RTliJp2Nk16e0p3~xQo^W};i=4F;M+d0znf`M(T>ZapVTH$LNkv5U zUayo*;o7?GCm2n^Q}uW$;Tt1k%Tg6#8xx1M8p||Jv>Maa1{x~@i@nw+yvtsT!&N4{ zE0imQPEhT!o@oTS*#^#a?#qIYu8%)?2MA4`>L`~z&rQxH&M}+fiSm_x56m|jospN2a`eBz8{;6t{=o>A|n5`b^+w>K) zPdSbO!06O%`%3e(?IRgrFl$$){_0w%rufBX<>`6t{4Fe-zg$v(np$B+CgGb$G=_0* zGUj+*EKc+$W`yOg-J0sDzB24Zyw%7TV7?y2tIPQ2k80Xi)WQxiVOHtneE z?#tj6giqM_JfrHey$m|0q`9LvMsANCQAB4P zHl@4!nOjT+wuHYR5MFAin`gb}BB^{dRz$js0X>nJg-M@Kh%Py_@dvymLJ2gU_hK&s zlsV@yHd$eExenu;GPp%lC@+Vl;QsHfI4+6uyx9z3g)B6O)Tmco9W~+Js=Xb&4+yG; zS^4tDe(Y;P7+VO&efcrop;vNsKuCDbr{GOr#(2G?L$1gp3!frPj3?@Pq|kzvI2Q7&WlOZlvU z15(~;!LC@XBXCZWYg-76b(Yhj#exbTDqVC2*@CB)>ms1wB*-K!IzT3a-c1i zcx%`X#uzl^Kfccs8bSJaES8eGu(xD*5Gw@UNO)PyE_;D{wZvW+31D~vC~Aj&qA;2r z=!G5NAeWQA2nL+6YBPh&|AsDuyw^9Va;p!T@Qk=?>sp{9Vo1vW>JWmo$HLy5o}Wbv0o=<9O3<;eQD$W$ySrHkbaRlue7#1w|2y}iBx znq~)1p$8hMhs0D)Svyw=1K#)$`(7P0Kt)z73k`2=XLl(t!A8ud`2d#Y#^NTtMv#bb zTy(g_l5WJ26Z2p|6ic%Mudo9SgmBW86H^CYQDV3b1ur?$sI|^kMB4Jccd%NF`s%k& zv7NC2goZ0KhjO&iP3B&m-1OqU)4NtG8lL;kE@w`{m59&Q{ikJ34EVwY)&j!o^72ND zqo%}ytu5@UD(u@3#y}fgV0&*Nr8@f}1OwiUuS{*w8vN7K(q3yf+JVEt?c(}y?=xl2 zHQ4pFOr9UnFY<1K`L&C(ihf@1vukBzg3VH#V3qgP3w`$uwxq%7i1FPZO@xu6jK^2P zmggh6u`59zqKOwp^RAXdE1dBm&%L@@c9qF?3QCTsp1~_IYJlGlKvMl-V~y1ziE+5e zkKM_hj#}}je^iKcYKZD9PWIOJ7!Dt^+9-g^J|pV~+F zX!fA)@A76Th#x-~|I?aLDI3H8ix@cjFT}u*ceQ=30ld^)6y_p=xI}1f%*?D7?pWb3 z2=hN>xG8y_B@wPrm-xlv`18>p@lA^Aa>Y^~9RTyRO-?~j45|J&$0_?M`z-s~ug{}B zogUC}(5GKXxSwmJIA0|Bv$m}8hQNKw!WyJ@4pwj_y*nU1m@y6P?Pqit{d~_*ADf!TAGwrVK_l)tm@0ldGOz> zPfaw_ItyiqZMwgpIL>5rtShsNmN;m5KN?(}Z5r#^cVI5R97>B;3;?GiO}bUb+C{T^ zF}e7VDpEnXS={zkUybl_b^VTAHLXK6J@X&t0Jx-ZlN9Y)*uDNb_tF)j zOeNLucc*rb*!`C)Wv7gWeSUg?)+Ts~I6kDkNVK`zN$md7o z0|S0q+m7yaG(=hT0Siq?Yn7Q!HY_E|#O4k1TkOJ**|V=w20P3qV=oz`czBn#3ldXF z2jmLfF~U|}-7*WEx+f#6^}(07`y)7RRI3p}hV7_Hc>*U!tkYFvqoZ3swL$wN>VZ;} zf5B+1ytutZn}5z|sNAG|!p*T>V)V^JCETWE155l>DBW9k9`3FbiO*#^0TO8rw*{BZ zkS%3qTTa45p@oiVk|rMegFu1KEdBo_y-2vO zY94>b!qj&xaQw%y;ArV!X76BUq-XWt)Q#C`89Xuco|~(?S1e-%rj$6JOl(y7`ep1y z5_a+(*>9JxKc*rH5{SlDGB*@wTI1UJ_gP=L=1Qf2Z$3q`@}ESvW1@dwxy{NSl&d_e zTJ@qR@`D-1n;ouKtobh=-8$Z20y!j>4T_BhUFNh$g>~h_RSSxfO(#m}Rdb3_oX09p z?f##8z87kq)x{IiuqZ`3DZ|DK9GUs2UVDM&Zq#hVPs*ol+2mwb8c_!q(CTInsnT(Z zL0o3UmyMNO*Pok82y1=wwPqUha|(`Y?|lR=ea0tWXXi~)!*Y+>KtuONiVB?z$uQ@D zh`EyBn697fnPzop-w2Hfu1L2z0tc%F9+{cZz%~26f^LGvv$Kidn=_#@1E=;Rd$NHn zqGP(6W1IcJ{g(@lDmQLHI=woBE}knYNh0cM>+xskh zVPofpDf||HZ3X^1OOaS?+xOTXUpmAIJ~V#Ma(h@5UZDCFkT70A2(W+s;4G4$W)4-6 zh+mTM2rjxA%oZ6pmplF*NjuSG4GI^ZdA385M5-)PRCLw{-IRD!b@1H}tlHrj@LwU> zptu%2_&46EB0$mUX?DXO{Iis^Pi8>FcntNmOwn zBQ>L_YWf9ghmRv)n`0YG|W37@}#X>WEi~}k~*}R=7b6)BbeTwW^x6KP$@rb)|iN}+F z+6a$4@1(pe6;8Z_PiQ$1#_gdcxegEz>dUtG(1}gh4SYBH10Ia}Ui|vX40;R^DZN-Y zyk8yjt{-`KFg$Pj&k1WDL$GfZH}`(^sNA%%-%YZpbT0n;`2gPk97m*Fj|G~Le*D1u z`Qr!se;PZodIlCo4u7qUZT_1&km~ND=$twXxZ-BDXNiwDj01wkrz(;(k%0wBj5!eh z`uj(Ghyol&mRg@B6=$R&K9wuAp~pNdtg6{6Tx%^*yJVSN`9|K7ENsxxv3%j;)NSRV z%3^6v;B8po^1!uh{``*j$Pg6WqRuso?CRxXbNs3E!|N*bWtB+48Kor_D`27Y{xo)A zXUE}k%E9SD>qU|!6JHu#h4QY|kVgfdNMnPON1%x{wu4nG;t25&K^S^7wuQF#yN;4T zeS_0Mj7N>_U*IY&w+4E=?)l}~qHRG6X2I|44f#J21;YWl(Uk@rDWg@FqY)Tu0Y)nH zR;ydACSs+gYqJ!J=aTrNhiIi;{!qiSB7(bqHVPEU)Yd2!MN#DsL+MYjQj8kiNp|T< zHs+fa@`6l0!RBa0K}3=2@htCQb&_Mu7>%me=)tT8eXCgzLA6rfC_V;Q7#=XUwUOm+9X=R@h3C-6xpn*G%3Neg9Lk|^)D>=d$#c^^>jW% z7Kiywq~2VatLYLOBPmmJiXpRnLk*NK%TXnuKP z=ENfSb?JzdNQsnf>DJ5gE+Jh63hjoN!}_O#Sr)37bkuRf^8}nGH%15+>#i4O9P?7m zb2zf;OzPXgt$|tQYy3kiO*oy&DvyqCI$V>|9Fs;%XNIyA~*_F1lmhRTnXgf~x$z;VXcOYfO1@vYLmDn6*efmZ{ z5@a?H@;W;s-8(rBJ>8cbxso4?LsO9MzZ;IioncX|WllvE!5Ki>pn|T=4R#69#7h_k zE*1sm$!_qAGXL_m?Opd0vD8S%BvgxU=dPG1aCPl)YPecma87sQc(EUT;e-pX-fc6I zk%{hS-ML;T6|UMn*{ZL%ShBjAVhFyeMBG~g|N4jT(Ol4GH|jx?xyq3-axlBX+-s67 zsTneLbt^}1bB*P9l6Q=6y4AR`zftzGHRwL?k;}2m``Gj}zzgNnWYgYg(LDN=@zIUm zG5YQz&HjlY!jQl%)-B#Acy#I3ts60EU7c;h!#g+DFO+VN1WSuWVsxD|TI2VM>}_QS zphS;S@cR~t1ttXwBGVuhhD(pYb-pO7tJeDm2W#MRkOD1CYU3Qm&?2FH7xT3~{33 zykzn&X{&Ae8qc%aYDtky$ogDS(*m%kN|r7~^K|x-v7Yb>E5B8)ms#Hj%|^QB&O%wF zU#BEsz*i`H&7|H52Pt~yjkotuUpPpv#=d!rj=-2Bg`6&P7t*2_eLqGac8hf9^NJ*Q zM}DE1hIoe6LF@P}7FKov`WrSr9j}v%g(l>65?b9(wFF5%t z%bAj$f#25WRmI6@uHUxvvSs6^rG5pMg+5y>YDXE@BD5FArm$^C3?|>&`EJ?i=>9D4 zkXX=c;6`Y!rFzN9C?(oTXQ+@Ue|xy23Iicd=0?deBSoC^BZcV3(J!+s<;};VVYtzI z`c%s_Q8qrGsFG&5U-Rt{eMlgYKk_!2exON3@|nIvrvMKyMWz+d5M*kp+U&yGO#9I# zvg#f_uuJ;kEPMJz-y7scDa=|brKX{B*pq;&8oKSd=K94?}Rzs7;5C@$~oQevh*%Qb^4D!@FHiO)Y$N6 zes9LeAmO-;pwXlodrsKA5aphNM!uO_*S#ODJO{#AZa8N>MuPAwTPFs4U`^L>@7Iql zX?X-$;Ysl;>nR0HgquJIN|yI+*3zgKhdvQi$Bd@x1b`CXvEFYwb!bwUbh&_7>5ROw z@&5LWIWlv~GV_Wt6k7QPS>XIgZd}!v0MbHsD%Sfmd9u~TDSbC<9WC)o1TeFXfT z-zj3Qq+l*)`@|#-JA06u(?8RhRr}lj0DV~6unnNm0AS~&f75=IB4;F`gM2O^ru_@i z*(eFo%KExUI+A5uSD&m6jh`3kuk6b23Z;(?>R+()b{Z#Z7VfX??G4@D-V4A`qo$Hl;oUBSBz>6mb z+QS6GG7p48SpSQr))beY&es`H7Y*tku{N{m7mYi{Z762R+9uH}OFi_v5F4qK7eCVa zR7(JWa|tB9mT=Ip%R%=wI>OF8tTJtBJTI})2d3qB(oQqK>TzW6(RaoV9QL8e8v=L9 zKJD?-2b`mtpQQCO_vlqkOBd;6Bv4#|GLaZg}XPf-8XwE$P!nN`!BrX1czZ0qKd83WhS zyEhX?BjLu@7zi)t$~)E2hh=%eWn``cn-=(O;+syR_{UEYiCN=w5`mVPd5R%yiNU(|f|t zKO-}C+_GBEYb>b+Evc0R!`IA|I>O%8X-IZV-X|S5|6miZ1N_VQ6Ze)iZnrOAx5|LV}?)Pf_WxGgbkv-Gm=lCjo z%##c6B$5ZqGQ?cwIn=GwRo)JoT#XvmIjZ#^u#2_8if7KF%orRcxADE_cuySs=dgY4 zJqn!VAx;gFm%M&-w!NaZ^+H*3Jv43UkoVXt-m#N-WE$~J+jYs&Jcv6?-4e4UB~h6& z43@1#F4(a-tBAa!F)YVhvn|f6*q^{B(vmzZOh{%dUvO(o7P@T>Y$svFLYkO~46v$h z#oQ9|*RJs#S(#38KZS#V^FtESFJ$OVLd1PaH$%dKnJ9^CWM=vs&B0+?G+c0df z^BIXXOG;TYOfc>>>J2Hafh(ISNLrNH7qy!1Ay(ND5~k>{8az$Y&C&E*=b14e^3wT- z9kIM?JJ|niy$}rdMEXEy1k~Gr$7k0EV5tsu+wyn+9Ai|QtX3VjS)S_FQ6{&=>wFDe zJ5D6JkvAK{*@rt$D2?vNkAC-mRt0ryCM-u7#th_pMd$tP+`YXf=PNCV*f{2 zdXf;D-J5q3tk#@g83%y~%PdlfV9A)I7Powi^G0qP1TV161RA6ow8>Q;BmP#+rlJq6 z+>(ntJHlnYvc*cIE|)pNk=wZ;h1I&4{@RCThzp>;SzsOq1zJu_y5UvE0)e8L@eqH?1W zv!<5wL?WPSQnhz`F*JT1-}TW$Q*g<0!O3c@XQsO0uJO8jHDg3jXRq2PLn$v> zy>ox69mrdUdFfxwn@4Zgd@xx?z7-g+i&?r=JMfa?Pw#E_!imLH{S! zbYk)wq+GcaS5a%XwybE`Oeq0ZeaSQ{S1z()>R&m9HuLiCMECf{r>xFP4j$`(cBlgQ zQQ7U3>>F%^ynaTmxi+lH@}CW&y?V8IB7f?CCeTw7CM&dWR$FZx`Gic`BoPhc;i^Hc zO2$lIB{}(?n2z6e&HUr+!EIhyJmZHDZPucma_o$OxvoWJHk;Hf(m38C(?=;LsysTK z-TiLl)eK@9)>E>dW1sCAw0@@?@vQJ*jCpsw9`A(l67$!n5-GWI+io+an3+nuq!dP$ z$bbvf9EGtJ1`6uZ-5BuJ-{v^6A`xLCa;IE0;i)mmHpxs+WAf5}NQ(~^_^8L98#;o_ zTCo0+U+_XeA> zwZ^Ma+Y7N<=?l(V>x<@F?Tfe$8LU>B>bSQDQP=J+`OWg`c%);Eed10D=`t9h$6Is6 z+_ijj2vWAT`S^+>A|_^T!RmIWv~<@jM%__m$xoE{!8$+VF5kbIe3H$i#FWbiw;PjO zTZ%TzY0+-MyUnwG06o-s!h)HN&QK@*In++{$nFYg#e@_K`qig>gt(}YbVv^{vlLu|^sSYJ?>PXHKkdj_ulkSo4KRm3I_MEu z(!DTFuUEH${}4VybTB6lAvPFL@S*&9dTDH~h)@_Vxh#-r1FjD~20w2x7zi8X=%#F8 z3}{E|6Je}4>^1WS=EcVb$*YWy+UCJukJ=_=IT5DN4&f1^qxQuq%|;#$##=vocR;@3 z0dtF+n_W3ts<*XCO$ZnFa2qeaa@|%cE6uIHYSPxwt)maA?$mzL3BXZb4AxBwkr(hI z&!QTkga=Mg+N~}W&dQD+3h5mNMRGbFt}Zz@J2g~KSy^_PUo2=bNF=f{?C#2dN{z0S z5X@_@^L*R1T{pcPJmmXlzI8IbCs3<7ox(9}b^0Tw|j3+26*LZqZ?mR|hNf}Eb`qC3{er<15U?=#~l zc%35?J_PY}Tt#7y@o+cE4bym~WeRCmr)vrzYz*8JD(~SM&)$2byE{s|J3N06CXfAi zFmBVbHu;6aL?t}-`+&OQyOR};CzU>*FUzCm^}h%)0JzxH>ELD=14LnYK7yK_*IvW@ zPO#vFT$s8Q7}NV-{E$!K7*f(At#wAHlfTW+{S-pu>`W=OX!f%)Gj==zq0M*jlOIkG zaNo1)M!Q+D_TOh~kn!l1r(q|F@IoGUe|gUk)xLNVm(@v}jfCjXlp8wN-}WCpdn7>70d5f#JIiHM_q+|*i|Qnb5n6KnZn^C=?X$EOb=J%6BtXV z#Eg=DwVsm~3G#oT-r2C|kk#|uqlV90j@|-Sc>+E_lOs$J6~3TDC;H|G$2tN_+lG|T z=m32k%&4jTWT#wSSKs^1U07P`m=d#ejTRrzsfn{H2kwm#S#8`iUrt#U?6VS~jS%CN z*HZi0%9v5411L==MLR+qLu#;arq>-(+@>%2g+Aaa2%#jiz^8~k{2C@b(nYARxEyy0 ziq#st7g^C%B@z&Emw)+17Mv7>GGN+~j-M3yPg?F9bIkQuuJ>WOQOBE5LJ$re!8F~X ze?-`)KOWHgc9(T|WR<7pf4uQo$nr;}wQ{AnIUyio%4Hp>ufojq7-$Zw_gNaV5^yc^ zO;|4OAPdg(RwM7Z38ke;8|%?n5gP5euwUy{UK3l%QgA713d?S7VF2<_~Fs) zCjWd*xb^%v$;;*s<;*QRmTvPK-x2Ja_`w?Qk+5obid>t3n(yCc#+OKENWkdfV^5DE zJ6#Jqe#-TU-ozec^k|%K5HM*uUth;OU5i+^9A4&s$Wq?SiT9AF{YRqBwPP^+B6Jje z@X;~yrsOC9u}+7eISC>ev2H$`20QYw?t+NEceT>cGEE-q&j|vxGDlkR^0S=0Q2Udk zYwfmlI9B@hqBaECJsT_Eo6orl7SgCTE8Y?`U=zi7u@QZV|0w3rJ0Gi5*By0utj&PS zorL9kc5Rx!=QyiG53;zjkC;W94VjQz#KGwA&OencSSAZJ0ay)}r>-j9LHpC?%8$nN za5w3}?%YioH+P+66QZAofgPrTsR@zpH(-{gH+1DHU#%@piFStTH1o{dF_kdC7Vz^J zko6qQ#=j~_n6!rrRO&l*F&-UV*;u7%A}M~+rhKZ{p|eDGseC-^AkeK-RnIRE ztJ0Xx%t$Yj`)^uFB(Z)xI?4m42!+xCm(>C?48d^B-bDQCAVU1aApb+i@$b{iV9sw* zJa@HqoT#}#19#!AB(HcS^WWq7$!)MwS%*adF8=u*(b>12n|o02Xn=iBFEY8!By>Qm=w|HQODWqOYin3{ zJo~%Qs;df*tIX@O`^p&L58!GH`HRlTi`w~?wl&&2*5o;nZ@AjX&pTP=8R>=Ni`wQ+ z=QjGi`8{ZB1m<%Xd6U!l);IPrV5YC2R&l@-t^XK#?ih2tMM*OMXOnHQaD+R#@j7MI zjZr9`OsGY~-%e%**2v_--sh+Zj?Dz_A>KHSPbFNbSXX0B<8;=-(F}U5lsh9|>0`0d zBYDXnUu)6(vxI56K4J!f+5Qk3@uBhM1V@D42}ukv)_$re8f4=j z0>MmX*0#qKx1zAzLKElRlFzY;V}0z!`pmLxoaz~@W8EmVaRz*RW!!GW^ZbQpa_1f7 z-!19xG>&H+B;t_lsfJ}D{LFKFW1YnqOfb0Fw0`jmpvtU9tn3OL3jeie(=IbtSEyAx z$)p)h4>|6{!BI%$QHq}~X!$D00A+T_JEDJTM>;=1}bAyePnkf^I>Me6Gkb!M&cC z@m~0651dr947=)ZX)`lP?4BlWgVcB_$O~JPM-c9cRHsLhnjO*Km440EYzkK&h+9{N zSSYhZ##w3|{rd9*%$Kph+S6tur}1+!7|$7(ztNxZpOku>>w_Wbcx)Zf(ED~i%a*oC z^4#yv%DhV4MEg}zFg9stqfx}8W%8v@jx}SwKshtr+T<}PU6}YI`J)apev)&Dx+(qO z|Bb$HCUgrQ6(PsyJwW$ja5!eqHku9eeWy+y%eJlLtIpL%#a0P))57>B%$3-WnyOMf zc$9%I?1X!iqTXzwDjRG$;zIGbxpCVR>*Vbd@Qp z2%tA6(Wl6R5p!J7V|>TfW8}+{2Q!)^5Ud@m!Q=F2^?@ zr;p7XN4Zx|lBA0uhf3;~I}jM2DmX!yQ~s5{8Z&E;clr8KB1p34i&+X8JDVSKP9?SZ zN490)`#t&L8ee$(yY7}$c|=2#+NNIJYeMt|M$0Z@@)i;7mi02GyO0iWMEC;XzCY|C zxH(7M0hbIiwXh;~brvu5)nl32U=(Zo#9W+3)sfu_@{*%lX35xIX=RKuLSg z`ZK1Hi_JFJ`aQqm(2a1>b#kX?evY#VMd2#SU=A?IhSIliy|$occ#6WMBub`)g~M8( zWKxK9!#*tzP$TYC8W}1ci2*u{{c*h!{xc!GEGdlIloxQ;8iso5(l<(m_Ne#hdXsO- z=enUtRyyr6lYpgSW8qdkE9NT4F6@66rf5!Av2HNByzhgRPBHgmicD?cgiI#7rLu$X zZ-IEo90$gOaYYf9Oe2noKoR1Uc-Qnx+ArQe{v9%k0y)ZFiXZhb+hgd5aG(q%lOnjGRJDq%4-Zn36LyjW4 z2dx~m;BUIh(bcpeBx5yE)eUQ@c5<(KN;9c>Q#P+hF&x%83QTs24MY2*b#D7h{-@99 zmlwPmNx7ODS~!HKhc0-Xu^iyPd;XJ)cDY`Qpe*=&>2_Jy1vB1H?PEv^Az<}=A3qSz z7w-~-qhH#fku5;z###=zU*q#vlj$+NzN895j5fM#iq+&y(6#fvLfuQXijNwu3SLPn z21ik?TA&Jg2uh)GY;ow2sP&?(zLA)TabZznK}xLV*^H=vC+`OzIq0n>uf-J z5q_3l8UL~Oi^opuj>xT7UQGEKD82d?`rz+wfu9qG&t-sEm$rd!Qk|+zq0H$^41|Cj zzW1F(OLo6S$Bl{{_^qYcYtt4XjO2Vq6dG?dHwbBJ@ECXvmJGK|@I1IAXDG-xq&lCD zGJG2hYZbNhy>taEB~y9zmY84}5K(uSDEpV&BG}>5k+Y>NZL7=sk7uiTO}DVj(K6*? zv5iyNOV;+_LnNj49;b)eiVg2G{?D#1(uyZD7d+WjT$m46hJC(ovY)t)ZXSx4_c)SjGxja$H z;+J`*-lzd&u`#@qR5dFND?K^85ztOLGhrekVLl=wcEu4jIC|nTX&u1N&O0kVb_@TP zFj158+ZI?hbKvv0yn-DGy@ne3XQztQrl49NRKfoJo(!)020Mm%nH#c{@d#Ce0@S6d`(KMO0%+ZeN5>Wmqf9puv_PDWxHKNo9e_3JcY zzo>C>;XB~5BqcLGE%6nQeW3I9E^|cvu{Cv<-AyIYSWjeLxGl0vLoAhPHIi%xiMa=d2Qu#cD8oiD zQbg(6FyifZ-j?-z-qeYK-nvP~f0nMEzs`KC1NFc<%l5rGy}Y>IIF&=`3bsw(UR7A^ ziwtW4;dDC?0~(-q1!|mDLjuPMOd*>4-mzPh?Am%OnUA^FSAU=OR|32c*N14^dmacr zkgdZ*R9mcg-*%kV*$}Ol^so9Zm`mZ-1(ea(6IM31iTIE^dv-t_)#}jLP(}oDd>)EuD~f=HrnXwPhv6I0w(-RnO+zq2g7_y z(bEtV3XgbF%9_V|6tnNhB_nA#b|!1NTx5- zGFgEk>8*NtV-$5d6H5k@19}`fZfPa+crlCaGF+Md>MZ%4s52uLX_#|N+~I}wI&=de zio{;tm_7@5nD~ng`|nr1&<_Wz!~5^OmO+bb0tuNuIxh6$+BbqvvN^yhjLyfIz_cIx z3Z}HdSb^FM6FxSHuET0Y8khXD4_#_w%2OlacxKB-KnjwvuYW+|Z$UjeCHtQf|-tw~I+ z3r@ZJMbrMH8*UI3Psxr+)`)=`#*Q*A*;eJyX#6$M>wH(j0fdTlFmt<= zuFyI-1Q5-SlO(2#dNY3lOdKyFuJKgnY=PpX{H9JoQ@UH{M{ls)wr)P55;uK<0C|8` zfk zW7Kf(McWBhK$e6eu)D#ge?QvVA6VYL2D}dCMBDbVE5Srv&wMdW;y~y}{;^4cSY_mNd>hQqY7_M1ELwc+EcBENB?)03i?Aq#1wk)A&{;P*VRQ%d@eWteK}U* z5B$)-%2R7h!1+^ByD8}P60a2tpsypIxGzN0o7#LN`8+?Gfo53kCh8S`(R&u3vI*Qy z+*ycmt~vedLaNOh*wHIR`4d}>4X!uE4g-1XdXFBOUZ53pClHV=V!E-t0=>k29Gvd# zO0cf+fV$1m`S2rGA%CftY&u%#GcR{R@0La}p#9*`HGt8x6%(rZsVy*oKqLR({Y=yw zv;Y-5c<*3y83~u8E&{l_c31Rv^BfH+c9#ZfZ)^90&?b_`D(U>~sVKPj2sV_n-nnvs zw57B^qYEEuu1IMj%Hx+EdhcHFC27LSlYPKeMg~m%&rWRAReY_`?T%9@2I=LGaaZ_Vy-I zRmv9p)*2-5gr6n*87Ib%5$_c8y2t9A&iw(8R~YJfYl#nuG4b|xnf4}v(7AVpLbj~e zgY*baBH!!r*GNR6YX`C;o~ySa^`598^*r@%7NeYApG-q9QsE&eyasmfoUPU|tXFCr z_1$*>F^iO2H=(sp?BHMg*RF(*)4FMd7`s}*U>4puecgATAfUVXojE-kJ%@MNRZ7S_ zc0P-@+oLhBF|@iNb5r1GcW9XpF#W8q5`ApUB1NwYIk7>u{AsmN&fScOgyK!;{iqd+ zG1lcjQGiR29|YE4)iOU7o#qf*IzK|8FWz~5jEN+@eSnwqjZC(a;k((r!fC%k*XM=Bzd6{gBGI~Pfnw+qCaGqWDe{v(4lO_yhCU8WZ;xLy_9v{LBPhkM;i`_#bkBB`P~tZr<6Ud=E6=m5Kg>u+y;Q`%o3NP)HK zM+@G;(>}+(l|FYuiAZTe>q<`?CYdi*r)())U;9oBK3M&rSb~4Lw9o5-FF95EA}8Yb z0oA_P0fRt;KlE< z%XSK={z}xlzD#Fge+HbPGiCm;Ua$S47?qnX zD1MzI*V1h+Pr7Z(;X>%w)zGtpUL0RYw+2NMLe~v0ku$Saxd*ZY7m|#v%)cEL&~FjH zu%hKAgqCxz&NEr6pkZk@{|bK99#!~h;xiiJJURW_)W74I#&0}rbFgNI8m`CVmh`!( zHz3et;%Sku&i};ehUL>Uw_jMiRUeUGG1eARaqHk}(GXH-X{;^!{cW)h<`w=|B*Zjh zLezt|B7y-YbgIw`oPW44^}?HEua}!FSTtKXNN$qfpnlK1XcF6>IwhQhvu20R{k^;% z@SA27 zn7I454SDfBP5uUU+kx--dFjPD;bA67|3wD#aI=|*a=#=lppUonfj(5;H;1BWj+6AN zuuPAL+Ym}leW8jTIbkJ44{rr(U-hYs{fPxh+(>M;B+XpF+I zXG^s9wI|vkez&jHILm6j;a*k0q3+d^b`xC*?#DQzPp`rKeweRxW{qb={yj@=Y3iOt z$reUCG~lh>9750e3tw@|>4i<}r%^=3Z5@$f9&EEIVJ<)V;^932-)rO(+q6?bxUGf{ zvf^JXOA~>kZ?KCcGd!6m5hy`tNiXz@KaLqqeBZh7N{xR!vAywH^r7$xKv?bVr?G{s zS`46^xe!^M#sS#|IeH?-`91@zytB-SnP&$rsNW${gv%)v;{)iY#!BbeijhQv2|Vm+ zrcM#zO-3}QA_y9LMW@zyz>h_wU(h*grExM{46sKsVj>7cpAe>=HB|Z(%l%-iB&;Yi z5j&mw6x){Jt<1LX*|6aa!?N0b8fHexdJQUe;XtMk;X$Wtb}=bl1uC<(Yp4t!*7`uC zeBI;C+?w5u81HUCrZF)LK}^j>!!GB6r4?E*<#)V1JZl%uE7HUy1xhd z3t__ZI;qyde55Q9sjxTb7Jt+nHz7@^QJ-*S4L0TezL=QJ)QfjQqyCmRy=QSWwjYI2WNv@GN)??ZCQe%7OtKJ znw*w)6q+qTMV<`WML{<81^0xjfJG@)nU~6p{J}LWQH=XEaaLOLh5)nhvhTnGF4H7~ zY1+{d_GH6^D>Ei;OEf|ZE?bAm*ZSb=;TkLnmHwy9;7eu5ia_eHgwG|_3+W9R`spP# z94qG9>+et9OriyTE#7Gp>Q6|M4d=QO>gkp^l`plA&uIVFjch+_huT-$^;&(_eh?MZ z#i^!cnv8B>_;;~4T98K6_>*NwH|37vwMBz|9Gx`GTk0nA5Oa8ta#y&a|9&=ofFov% ziGfqkial%CGClFkg@N`(m|Z!Is&~|-lIBJDP*dUVtGvK+%4@#*ObXCn#kNc)c~@hk zBJ1#Xs)rr*i*N$J3OGN?EdwLq897wFv?~=UhrfsTJ-`K{dDh9V`AEv$RJ|vNW&U8# zdE3Op-JO0u?Rm?dRZxlE&d9A9j| zlak4&=#Nsl`kE4R4wPS8($^$oT6gepMGClxLh@Rkmf#>QjVwB>a$ma!#o- zud^d2>Z3D$hxT`}Qz@xcKy1gNvTHEt&JliG@DmfKQVU9wal}Oand=f8zhrnWv&M{& zK`o!e6@$W+kbXY3?3E8_Ym=@$W!|;b{4i={LL(u?nwWK#L;T98NJzR?$hNN{rD;+= zvi=_iESEVfmo;pY32c)EY?B#m6E18MCTtT9Y!f!D5G|4oE7B<$(kUI%DHW0&0M;EB zmMRLWBND138mc1-DjyHl9S^n(43Hz;#6W@f4)cwIG6KLp;KDv&!am@@K48OA#X$Xu zfl`-(gqDJ=C<+WJ3KTC2>@N!BQtQJ|>r+(|>!35qq$86AB+?_{vmoJRMPEHtMyG5 z1=Iypd{E}%{d zP^SsFsiZT>qBCiyGYO+JDWTirR_kL>>$6kqyC@3eE(&Ze3gnf7ypV!)iiTQ=f#QjT z;)#ahiGtd}g0;tmwa0|D$APuShV5cTT4O=-mIc&F0_rpXbqatweLx-fr4HbxmTpg2 ztxrU)&tI(%QcWzMj*JcoAqr{$_z(X}a>{JxFJcQt7c}-#foo19R}qu0Uw&hm$HZ2O zULs~w&hczU;NxPf1V-^2a}Q$IXGUZBXJ}*FXUbxIW)MgGPN>X-?g`8b-J_Z#oKi%?Xj%(>@n}U@|)E?$hEHa z@Hgq&H!!Jo^S9_aGq9-k@;9@0_P4Tk_cyh7WntfOW#Qxz?B!_T)4|uztBQ4)af)rt z+a=h{`x5JwD~d0edl8#AgF3=;LSx=~Pivmw7E{0a5_4PYmUEl$7EwRjKDlH-Y#GB;}!yMQEOEte-mWJsJJ5kd!>iW=1PF;8Jtf-2Uy32wCsY$~ zPggN8We$pFOGsguc+J%0y2n-@&MZh~m=O}Mgt@1pN5AJ(XP?pl5g*&C554AU0*~=P z^6b4-TG>9~ngqu>pb3s%nn(P5rV7_7H_!xUFFDTSYq}=!y`XvmXD_W*kWc;+_S7di zEej(ut*95uiixQhP$gRcg;v@NXNBFAv7DB*5yd0bJx2xMlreDG!iZce#wTq_V`^7U zc=|O@)8V-J6l7Rg8*vx?d?^v-FGceQ*@pt_4Ku%7Dgaa_S0p-top<_M$~&6&k8l#H zO3^O%5q;L_Z@^Qk(!M=6Ke1b&OKZzv2ZiF5qfbow=gM=T1^g40LRk-O@xJgyG zX;m_lS~25VF_T&fV_L$l%lPe;lseS2nc(OavCTB|*Yr5%B*3i_!l80h`)m;SQ&jwX zohpD_Judkb6GTY+LJ8ys-pMAJaVC%r^HU`QB9iIUb5)U2ezvKHrkcJ}rS-wdR}u)) zRUF$Fg7oSllI_N6F8U`BLIKdlguPpfYBuF0Q#201<+c`WTKe{i$b*F3%k1g zfnsoT#l z%hk*3&<@kQQPF#z5rWoAza*O#)JjLk{h?R?wWN|_R#mGM-Q9sk&vVfMTB|7_ANDj% z0Q~j%rf$E6DpzmLOEsMS#zg=0O9r&oM3iE->L?NI&`D4Kbm^^bzh$KUYfD7kew&5< z$x$+TS}+LE>BXsTzdH@A4`?MDhTBO72zoQB+wa!^>mypphiSmG5IVgD)$I>vlgvIj zsYJ(hLDPHQ#e>!+1e45IRj7uocCrASK3McE_bi~b+0JA$$!nQtk~bf9`?GCeeOa$q zv{E-by{CsLeamA$Xl?atl9@t465y+^le+!+H@W(%-_*k`JK#I;<)G(z`UhHD*O04k zMkgEI$(N6w{zgXc`CA;cwgaDH7N9~o3?~{25PVftx4%6DtsO)pnWfB<4YL#gqaFPD z=$~FNL2IXta`lVW;9t`$`LK~_G9c%TPW{(YF|d9+fqd9sG#x7x+7 z0D&^zA*rFE9v~{}E}*>GfUkNoHcw*m_qwE1sxT!G6+@S_e8Yg1Iu>qAVscYmTIx`k z1Bi;XOGzGT&{I7be}|kp$rPS`97Pa3H*8H>UVYF}9gFBGF?p*F+};Q;Akfu2Ayq2k z8;DBq7cKSvJ_J1w9efueFhHO`LQ*mWCJi+rMM0`mWC(~#l9+;;{O33IWC{^7YWAO! z>dBO7DamBFnDjs_Svg=TpS*m-5W6}SO?*l^+bz2-B6dL{SkQw7t(-z8A5d>#$Qneg zm`lNI`jhL!{K3J3g>iB^n@f08Xw(ld_nZwDjUOB(m?K)i0#CvQ3&9UT3l>6P2T^cf zmmo0r38;|SCI=3z0(N*+1PfNMF!-o}1I+b)1P%jpRUc*Aw$e90t3D=$4$6D>g}lro zIa-d%l&h&&>b#*?%I&ZhzO&jXBv2=N0oj{SBgNU(lsw4TM4M(i{Og&l&Cv_XG>jS&wq) zW-GM9nd^b>gpK59g~2SN17jQTPlv zg$APK6im(^_$B4bz?t-*Ff{`*wxUVOANeKWE6~VzMlj_FGBy=a@ug`LJo`L_CpT;L zL?#?@Mk}1Lp7J1M#kz2x#hPr?_e;r_yb=9Oda4J6$N4wOXh4ysJ9WL_p=t`SFqsK0 z$7)@gY}8LI=S%H|akiQn0{mfCnq)LhEb+(VSasn`<{4;}BO=K^Bum_vgfrzKXKEj` z$|;+;(>F!Yos^~Ii_IDFpg)xa;^mZ0+8H2L@?~^GIdhn*2klzLQ+DU^=RXKeA%eWv zXp?uwr>MJQ2*{@Y{h&#*de=z-HojNUgVx`dH5Y!ppHqKimf*~e(Do^SJCEycZ?<^$ zn{l@UIGd&dds%&WHGX*Ue|Q;uu%sVs0hrYj17pk|814ra^MO%+VCo-nwLVw^Fx#B_ z!G6T8`CyGG!I}1lL)C}F>PN=?;idQCh5F$|0`_{O`EbpDSO*#Y$w6RI${)pgyGfOM zz+*^lQwZ=9EBM`86|hzkuvHNdyH*^qGhWcMSsajrzWZxF!>qd4z&+Y^dOoB5_|zDj z7!BMWv}*bP@K*5u@dBspCE~Y;CE{;}cJV#r+_Jl=*~RbRXRhFHNzOL^0=_VFkA^Q1cP1_o3rg6EM)r8swr7G<8#sk75pPn0nWSuUa2@twG$R$9KCWPw3~+HqTDG|;4fiMu zEjY1)QSj?gaGjqrvdwi8!8UU4(ONq0(c`dg?*<>#H3c5l^FL$9+{PL9Mr=G5_X5sP z>s?EmvGzu^j>K2A}B;&h@U?JSm z_Jkfkh7*beix9BLl>u|)Uq5G!+2AH z&9X^g!37qhA0_hE+nFf&>-=IL>cgUwb+)1G$I|C^EgU@|@!(htV(BLwURi2MQK zet^s$pq>O6Y)%D(7g`^TG5Qd_)zi{ZsIR4wZsT*G>JO&si&W?w5(TYI4Xm{m?o3$C+1&9&)R4LdaKbhHHSZ|T_tki#yhlTzs7l}%U$c}J*$~{d;p3RTUWKru<#l`mF zaLEuZ+w0pndH-gzX!$Nu=V2|vb_XJUe*N?=;=J?jD%~>{K*|@Jv4n(Xa1+o@VN5OI z`A-y$c>IeyEIbPXpb78qrGy{Xy27)Km%5pbC{hd4+iJSu6UV;{Q|fn)t*txVbgk_b z?UaFO=74=e?Q4p->Yx%<{rv^>YDr6q8uUp(D_RD<`8UmD#0&3V^cO}3Y8Pq-3Sn(g zmCjp6S_|q=3@;I<694Z+E>!(79dB$1h!{hWg7XX##O)@R&MuhGSc zU9!2}11anK*6T5QR%~vcKbf_DY2COSc3kz`^r%oSxEAG15nHG3n0@-3&vqiZd+GP? z_5NOF{Qgr1f=lg_smqu>KI+vc_TsP8a)Uj(-gCsnh%`iS=JVp5*~BVb51w9?WWirm zoQ>yruQNI&I(N1S$= zaDkC!fkEKy;y;;=6m>ETH!*4${4`9V3(tULDXReB{$6q=H1-LS`VF`Zr zkqZ5Adq$^9J}!@D>nDgE4S|OKF?%8D|U3s z@u_YgL1S~~%NjaAKO=&=tGhj1DE$*g(|uMdd(~GZ9SBalkqC5*nW-Wu_o1hp!ha?f zTMyDHHSfEpUVl9QR5KX9kML=26%P~-aC73dIITKwMJN1q+dp)=K476+jWqfTq0IJl z5Za+|a`9aL9^Mu}C6ubk4y41p!#XGq8bZAl3*HYce0RgM=o}n;4n;=aPYK=c9inaA zedP+c=Y&~CYEKKrani)^XR&YQU@c*Xx3if0C(bx!9nZ{&(3GLtH@1BssqKXU>Ku(= zvW_l%h+)}^Va1H57_aXu=g%&%>9MDN(m}WnAGnp`F!9LRQ(cIK|0xt{_na+#pBYZC zyul$HWouBTB8Q zTkPOuO=fQjZSKMez()%&h7tTSaP}L^|9BwgS;tn`8)e!KJ07m>=lep##1AXG@f&0P zn*c%9MM19DPS}93JqtV-tWtu78^JI3Z|D-Yu|1e;D{hzRET{o>-v3he&IyQAnrN}C zgvKG8LoOeT`9{}7v3}LxT8us?hOe$OTaHaxE%gcz1G8^K<)!FmH!1N^WzeVwqWTiW zu%p)qR|=fbfmEGiGDxPidv^|JyLHpOrdsAE#%w)Wlv;F3XtstlDdWFqoHdJ~kc*Xa zN;|)Og(u3D{>#Ns#ILw_OhZ{c-&3McjHL!^%Tnk(5@n%PEYm?<7c04Po~M-SN|+V{ zAg8omd8(}?u)nXF)x;tmz@adfHaq;I%UMW9JbnDT5+}4s_1B0^Z5fA{yD%nKQJxz= z0xU(psX}JRG6CupI;W|Vb$sGi8!A4<#DT&$iL)LfHTIz|`*Lg|0+P_o#M`tI996+M zJd4vhXJhF_uRAsMsU=7_e|(vP7yKAW<70EQU4R%HJ6lrug5>}DQa2sWnr!99%JQUKPRBn#ls|*gc~7IQ@2h+p3GT zP0$QWzQa7EUoL=+^!PVZ-CO|*+SN8O@nlcuYyIu>cOMTvv!AYOWYCFfkb=)MmdM7% zeL+Yp+Yk(GA~9t&`DlSo5@Jix-yw&}Z0Yi4_eJO(O?)BOV4V>iV84Hcp_7R+DTrBM zx)+Ho=3DVrFTVk)9%(P?a)lB4s}w3TeBMbhoLDdEbVp+JE>tvKe)z5HV}i3~GvLQ% zPTytIXIDLvO(0M$j-4HbW>h_M&IU_>6v(53#Jn=9mryvAGNSdlMz3_Pa#EIkRzqJW zO{VkY51`{Ph~8akV824i9Q%TNo~K@+qS64Dffg3G7JU2K&pmWE~2mxagJWQZTRXIRL325 zsj)_Gm}ba0TJiagq2niTzlO4z9>rT7VWRL4;xBCQV!k!ndRaY2A4@||#l42g4S)o0 zT5TvXWrxt5P~B6aVoDZXC4-8I(z4cx28i8$O#?rP*j5Vl?}My6wdS>_ZoV*R&f@se zrvs!*pC=CxbPeKc< zTwndMzB0sY&gA!*xNLs*nkP!tbk7G(q6&8I8V;0K|69ynExmDUS2OD)9|u1Xwi^cQ zjRDZWW#l{ESZ2WjKuq11e*o=BX*Qxh?Y*s#0Tf&@EwxfJyj_(FT_}V6pj>#Y&wa2u zR^MLLy(-gp4vya!_eDr?$3l-X5D1lU z?;nbgZm}P7B*t97`{sRvS+44WYqSN4gC>NY5LP06v!^_=&_$e{eq5(3hWbpWIioI+ zHVIDC3+?VGUgBY>o__%GMZ}(b-oY)dDWriUgn^ld9`qgG4x1WF#O?$<$~YhkhUzOe zY3FPJr!3p-CSx6vUgzh5SPPew(2wCof)|UKd#8e#BO$VX(D`jR+_b&Uo*;i*B&N`C zCivRLL2c)cl%1#F2WJ%Ip;eQQ5dg$BT&`n#|7vc@rk^CZaPhGylTlpZ&*cU^iN;`% z|CA;V{2?*0sv1bE8twF*P^Ab~#grs}NX8F3#|7@2H>N)g#e;s8($!`#mqlbI=ec91gKHkQ>*S~l_)l|>Uk9w}Qm zfQX0*DjW!d3cZ27b-!sYKB^1G+v~Fo{P~7;)otVpDASL=tKxr26YOPp0^KYx&fta= zYz@LGcj~n{Xf{phfCWRG{CMUp_4geIl>?ImHToDY{=Zki{R>&Op*qRr&1vrXF=rw- zl=Rn7wQ=r{NohhALTUP3_Gk^hlo4@rwBELw3`EVSAJxf{ue$8&v0h;d&-zZ|R1?fo zu+IJ@wppVI)?JomHzeyR5;}yt4o|q=>T89>vS;){yr|1GYJNz&Igl6(ZbytS{)D1d z&)ePsx4zz!4Nx1d%PpF$oX2ObZl{s0ikhp&IA5$E8@T=r>z8KK=MKKyT`=cJ$r`y6 zivHG4dktnT(J8rYXze(}qab=X=kh$=#%4+`aby9!}Ykw{(@~8_7|z05cDqShzmG@#!w}ChAQ;y9Y4py?$^?#^--xZu% z+P^SO>03?VY2%3ww`?wGP8lvjbttqI9Cz3fvLY`vC7`X_-aVeIM>~3r>0bfW!YnjT zk8*L;S{gPz-kUmIN2;>FJ1BB~pM>6Fph@9JkbhJ!miS?If#`&!VG$&cOE(L%(I{p~ zqdEV?jp`F7I@3XY|SNeWvZx6kgkN?|wR8mBD+Tze(I?ot zIC@+vpwG?Rx~$q=6Gmt+QrY@Am)4TEWQVMl;}E;Dj@7jDWMtR6El$z`Ja76I)M39{ zgxcb?NVC~^*w`($x;8VfZ~sFhhe{(sQ?7eK;ylT2jJ2lJzapnaVbDD<^*dt;bd$a> zde*`v7t^+i>DgkFj&G_=$tWFzuq^vo1{Y0;W1>g&B&qz^1wFk}nG3)C-^1VYad*N^ z#{QXTW5#7~cf4ocUxj@$UcVwu27n|dh�CiwEU#wo92xHq+oblx$1U@1GUE*5Rv& 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 FALLBACK_TRANSLATIONS; + static { + Map translations = new HashMap<>(); +''') + translations.each { key, value -> + def k = key.toString().replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"') + def v = value.toString().replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"') + output.append(" translations.put(\"${k}\", \"${v}\");\n") + } + output.append(''' FALLBACK_TRANSLATIONS = Collections.unmodifiableMap(translations); + } +} +''') + outputFile.get().asFile.parentFile.mkdirs() + outputFile.get().asFile.text = output.toString() + } +} +compileJava.dependsOn tasks.named('generateFallbackTranslations') + +processResources { + from('plugin.yml') { + filter { String line -> + line.startsWith('version:') ? "version: '${project.version}'" : line + } + } +} + +tasks.named('jar') { + archiveClassifier = 'dev' +} + +shadowJar { + configurations = [project.configurations.shadow] + archiveClassifier = '' + archiveFileName = "AsminVoiceChat-${project.version}.jar" + from('LICENSE-upstream.txt') { + rename { 'LICENSE_SimpleVoiceChat' } + } + relocate 'org.json', 'de.maxhenkel.voicechat.org.json' + relocate 'me.lucko.commodore', 'de.maxhenkel.voicechat.commodore' + relocate 'org.concentus', 'de.maxhenkel.voicechat.concentus' + relocate 'de.maxhenkel.configbuilder', 'de.maxhenkel.voicechat.configbuilder' + dependencies { + exclude(dependency('com.mojang:brigadier:.*')) + exclude(dependency('com.google.code.findbugs:jsr305:.*')) + } +} + +tasks.named('build') { + dependsOn 'shadowJar' + dependsOn 'cryptoTest' +} + +tasks.register('cryptoTest', JavaExec) { + dependsOn tasks.named('testClasses') + classpath = sourceSets.test.runtimeClasspath + files(shadowJar.archiveFile) + mainClass = 'ProtocolCryptoSelfTest' +} + +tasks.withType(Test).configureEach { + failOnNoDiscoveredTests = false +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..07a952b --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.jvmargs=-Xmx2G +org.gradle.daemon=false diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..b1b8ef56b44f16b14dc800fa8103a6d89abb526f GIT binary patch literal 48462 zcma&NV{|3jwk;gnwr$(CRk3Z`Sy9Ed?Nn^ruGlsztklcC=e7I2x9>aqJFB(1eyu-q z%|3b`eLzVT6buar3JMAc2#EOW{C^)LAZQ?YaW!FjX$1*JIcZUG1yyl%HEd!6f#E+}*Jo*NafvM<-FbE0;-_L#rp}qdn%JEoAVNlEB#J^Oq`mU_#*ev4HLmc> zjXz_hFft^><#omb;Zer-%wm4hxo!wjuX3hBldg(^-RiOleKin`>KHfL3P*{k?(rji(#j2Cc0K509#>qu=-T&B!-5EBi(+ zIuTD-qfcAYgS@`Fb2^-p)4#o6A3z0&fp?~cV=CRsAeCmO4ZQ5kKgC%0el=Q&Rhd#k zaGmAbUW8uKC}-C0s~2);d{;mpsNBx9rn__66W{AhaSvJEK+c0b6ARO+l(CI7E|S5x zhaYP--@F<|99X&)9`q^2(^-Zu^Tzfm)v|gkTJHQ!G*zIg5hzoygeXZoYUEJ;iFkE# zq^r$*c|>Hmn3GapzcDYnjgSFiO^NFyTR5AH#mh%zRToMpEi(r)1$5)h455DuV}0al z!*psWuL@Ke-2gvftfMEGf9YEi^<{B@qru zINgo+YsE&LN?)1qItJoNhISp-fZ86`XR#*6xcvM~_7=JHUX;K9*=Gu5X~ zix|O2d=&C#u_w{=B$eCpJ4L*6i7={j+{Og~`Emz@&98}6s<-p^)`0fXE4cJBP{>)Ltb>JwcqI>yz z0-r-SEhC@p)XOoh|1|XgjFaREHfsu4dAGVz*k#m+V<4 zHqvlud6=;#QWHUoTR_a8Y8+heN?M%n1@0YLiaN@GuOPNd26tik7eKulTx?mM-R!1H znB6+H{^krFXg_b{y=QeCT~qR3T4}l+b!Oz9;~|3*6F<3?#|DYYW&1RtFE)ILZ!`85 zVmvrZkLTzf31unH7Cc5E0iFShqlBE9hgEnRJH1juII*vyp&xd!g`q}X_6WT6E$hhQ`Vdp9k^<)VS?lj!cTh z7FQcQAVA@jL^cXod8cnhKG2TS9+;QU6Kq>}UOY3&TL9gXbl{Fv8@WsF=z7>X0To@$ zY@Oi1uc|MdJ$>Kn{@!g_e`-I&Tpwfg9cr>(iakDX1qciCG_1y!Di#4_)lE!bWJbrp z5aUonb6m-?tiQyR_`P#~SOu+tb_ev6JO>EbEhHK@KbeT0_FDo>dl9bMg)>xmCNB*g zG5NC8ABavuTEZVGW6jP*nAqRt3W?7Iigc-EE~zpNJXRAE z>`~RO9$892j&I1kV;9U)xT8^}IeV`n{}QDtj2o-RBt`DGZUOO;O*lFCb_vpyGh*;95PfeGu!dyrmZ9VJ3Z*upg z6R-3Lr%_55$Hw1^{+KWx0#z`T7O6sXo1h;m?B_ur`X2bFz-SzDrL zpk^@B<+I6imc@7vip za%1jMB7q@1j# zz{u?YojZMW{5j$@h=v4iu2mTu7IzI|)Sxn!74=*J>1a&?Xjt z2%JhSi#4huEcD9qdR9Lj4vwmfnL{%+vQ{f-KgYeqin(OPd8+(g*Uq#TLxQjD4 zLCL%ul(V&PAPlAx8D`@K8Rc`{GPecQ<)d=KWel0ejFeeXGQ6o7601B!!I@RY&eDriADD6wP6DcFKDLZ|lO#YwnrNCZ)zRJpdxX_nPZa4j#$j6v!h|6p!dH}MY6#B`@%6=) z-HigguDACKBULnon^FKzazF|Y1{t(U5rUGnEU|}djVsWT-F>@@mNx?_$kF51QF4C5 zStKR$^3(fw85(4HGs9{mUTtn1)3PwxTN?6}j;32&vJ^BiPHfndLkdU5sOemXKGyCZ z@<7j(k>DNeo~QXyJkFWk!7(y1SB%nA3{v~P2c8ooKa4auM!el!Q_=;lJ$c5ADqE+^ zX8*|A99v;jWPrm(8=h;2ZAj|(vVbx~wQ{N%v;eYLD_BB2LAEWCs@xauyBDl(_HIBvA(XJ7B1E;O zJYCJ8xFJh7f5sr;Y#Wp_`$4Z_H4e9bGiBp?Qu&2!@%Bl2dT5evfFO*^hLDiBu2%Jl z*WAlL5PaQ7skJa(qVysky}DQquZ8U?2@UyJ8zB#=U_E>MgE%XA$CtfL31m$rATJvC zs@!crc0=128PM=Zp zW_5Czv9))n_8Ru?{pxM2F8^r%*O41}RnONbSj*piG%`nyF>6ky=|;B&k8iot(J=kyoU3p<_zaAX(1ijzf*uXA zZ_5jeC{Lks+&QeFIlmzZi3+fsF4fNW^~kvC4Q*T-vrNP!x9xnen12lZQM=1_MdW76LKX(GuW`%T~dM^YX6+ras|Xy4Qhfcq=D+z-P-ea z`T;^gj3+grr3^hwqcNTJErl$z+k>{bYFm6QV%7Opth?9+>|Dn)O@`7F@=j-XSqGPW zjUAu%b3Er@;j1%RZxVDhI3sakg-gvTLOSV7;FV6ED=(5;UG??=WADZw^=$4AyFh#}VMe3afM^pF zFa}-nM8X=K?Jy02*o02@6k{ z%O!hBhjXlXKdhy3A{xGB<##e|j3^dFv~~%v2_H{t(mN7NVeS~51?D&Ozbxa`qwZ_4 z;C#Q#fL1sua%ggucgIEHZtcY=Ag&GgE|h7Q{77D!WUq`;SSGEE0pU;aoj<7-JCAvf zduN=(tx3Mb+EUXKoax|v;8b@#HJ&Q|!g4ryrl|R>WlAv?IH`bk)I24;eE4NIq@SLK31LD4+w~#3iN{=<`<1R!t^$@K5>U6%W=%8_ANuR5 zs(IDuI18ftirTDARnGmF%;iz+4{MlMihJw_l!0Y)NttXC_t+s)V<EY>=Xin*nGX79k6vQ?beRk zy_J>@YSC_gMIG$yjO-y&o>S6xtfT27aSs>e|`x(f2R1bM}*518~%x>1Yct=18b&Z>GiS*>VB$+i2876zL)1cT zN33g=g|>xWE2)dds5m2+8Vy)m-u@NHOlGYxxjam21r1;xWtT0TgqKZrl}*LSkqFt4 zNTI1=3o%C*!-i;iWnlca$stRdwITA1?#fD~5OIqIQAM18BwO_u>hqL&OAANiF|8rG z_IZ9mp?FA-{Gq9+Ky<#NgL1gWJixfO0ziP$4T4G>vsvqC-NQh+A64F4! z-(t<=AbPSG%`mTl6BJtH~3RmvPhQlE-EUkEoBIP(_WMN zK~Fe!siee{M*ns1hkp5(2}vX#%u+T!Abh=<_gEx_QW?h4V@B>uOCEetEe01tl)^`V z(=cOLmuOB;8&&m%_6pcyrt83UXkJ`f9I&0KxY09}RTTs!l^_7~8$tPA%Hm#&$k0;# zF;O0zCGo0IN)X~SyKDoY1DW{Ulce|V9w=ld;U`z$t$>8U!Gu8V?_LAJAudt3eI#*! z2i9~F=kP5m>!bmb%1e~b1!1gz01Py(Yw5gOsFN#o1a&d|=PpgN(#UVreY9^99I0iG zaYE@>(C^V7pnoB~#w$2C1_TIb1N5Je&iao?S2A*TF>@vpHg`31{uk<9{zf_}s&z%dL-Fo)C$yl$%pAdqU!HJgp zh_{m1imk{&{ScyeuziqZHu5cto0{S}^BlXu% z0~;>_yHGd#?Kt8ErxK)z6ojj5SacQobw)-8`c!$HOI*V6eyqou{1Upm%_p!BY^t(D zDtn(oQ!jff`ddGSD;P8Hes!v)OKW-*>mS&#i0ow87;h>(=Cu0>b4)|=EegbN5=Xkh z9Ge13=3z#sk+fT<)PuUUf_%Nx@l!P?t*mni^94p^Ax6b2SVL5U>9dHH!H4DL4}@?@ z?Gpq$C**OmWliYA{5s<|EZ@QI2{-K#brFxfA~AIqq&-WSALHWQ8}%mvaNFasrtnE{ zg=sB4-RF!?)nf{>Wo~kNFgYefoFHBcSr*;iF9B!R=5Np|jv>Uf+mcarG-XGy*kP{z zISVyoPcl_9cOg-@613Qx16OGF#sH&2NTHDa_}vyidmxS~pMfY#AeQvu?AXpWNzi7A z*6&7a7!C9HRU+N{>WYTh0GXoBnXw{lQby^XShgDOw@e8TP}9Y*oFV4MVF#@Ds2A+A zXBEt3a@-IIl)TOcXx;0P;|ihR%Tq@DXeG5p-O{!T7Sg$s1 z8OA4iOx-!>6eK^x{jU-0SvByimK|nZik5zKIvvWVGE)4=x^&5Nx%Qgje!k3VoizaB zip#?$u(R8u{wUFC>tVR8oA%7fs?xEu(gYn>y6BB%vwPR9&RoZE%%RK! zl#Qnkl^+Y*Y4L{Xk(YX&aGj|zSpqO_;C3CTepA!L#4EXO|(eA`Fi+2EQ3!C zo^SpVP?{chQ3uaxu7y>w213e22cdA#l-M2kStPE%sq6vE4M*?3At!S7tIp(tQg(Ml zECjeJw8)*#LYYk_+Txv3rxsH9jJZBRrHp29yJ(^;_PEdn%#U1q`r89}38;XeF{ee& zsZEsUbJ{LtwOjU{vjL(Wvs2!Bx;#^Mzld&TjS@oo3kk=0P36MC-Ie6eHNN&{8b^s z0@jcbdejrrj!>r#Wu=3H1dgjeOI}NkhmE}K+UK&M>%7b!n&{0Zixk%^)6#@=V~IZN zxG>9kl&STQth}qScidfg58d2dF|v_U<@+V^eE@$4x;7oS3)MvWusA?9+%rN>aY#eA_6 zic@S(@e9$9tQM-&-7>X8~#n{5G}nuOu=dSyN+b~jA;_SExZ1H9Q1A}}Rz;XtXUIOP0~ zZzS|~T+%de-nGI$s?wxaJoe+99vmo%xm8o8SNEsAqAE)4LNvHc-1AX24C4k4u3vZmov^_VcxgGxapV(8)_K(^8= z2d{xCrmk(x&514Ly?e{Mf6}h3=oeP7+ZE{%B^c-kK8g0W{tYw3q%zty_Rd@1nbnyHMwabNp-sSyzpV4v>QsnKcQjF67%g~n&3t^1MesVxCzfJ5b=SOI#YfPP^^JGQw=9L1RCMFbrU{8O0LWOUdBK#j&{`tzXX zpe2_{+-8$a+o#%8MUlL4$yK`*--z&3{@Y?jP!m{g5nM+Ht=bD3o}Ok~sBQ_!^!->! z?NDVtyLXzmGYCEmjSCDK*q?Aq1;8fz9l9|z@~l{)R6GfKELc^(nV+TjjI^n0M+S0i z@YOu*Tk>|M6a0_n$(E;#^1Zgif<-CpYiMvyT+Y*9Z?&~IKSwsLa5Q#p_?FqK3lKIw zlp6Hk%lio6)yq>m-`QT2Nj-q!aX7~Hlm^Xh6FNbw z$#ri(Kk*GUHXORu@`aYQU@ zB~S-oIO^~abRPocemkm!W73dbb!j^_xgo_@#W#6p12>w^{){VfeX?U71Xyn9&E zHa1#*!4c;?r}jv7dMN`g#&R_S215)dccDOJr=uz%LIz@zia+LIFjRakROr?P zQ|Xw0Pa8o7&W=fw17`+SqepsQ-Os5v3ncD5|N?N(AHH&`>hLY+CLOluJ z_ErpaT49zK(UcdNmQ%iA-`jS`A_1c|$W86{d_T_T2V-HH3xUqpX0QJSH%i>1i>#vK z&y{;5)^pMB=u;&_DEWakQU>j&+opIrBf~2GUh{`kG{|Z&2Z}5dwG}>Y{W_uQHaR$_ zYH%}$c`CGC-FGCetRdQ@RZ2-%ucC_|R?mHzYEnqC%u9zRBH8wx7po`=EVPMpq+hL2 zTdjVhQn$)++17^cn;<3=bxJy0Z$U;i3AqJMPJO&SuieU&0eVX?eLEEI7Av@#PV_ZQ zsa>I>B5HE996O$z6HyJfhEt^aC><@AnzeN`xs@lv>^pPFtcodrcGyqPSB?#C`Piu0 zh5=hAW|OtT9hs*G?7}@*mG_f7ae@-Nz4{qvne66kco^uD$(JbCo2ttqUm-SMy@kx% z!eDt?5>w5)M!E#C!b#Iu9GqyhUs|QoYWHtR{4espRS-LUt=viY2iygF=-j3kcU#uF z{ka2=zsOuLR}s;&PbbrB`zty&NfZpV*Y;~i*W$EH0JOGS&FMS%VK@)f*%OOrcU3P9 zq4zjhMpx}oc`PWtP!o5Bdlp=(A***TZwVwuZbuB1Pibv5uiHvW{PsE-k5IfCgUz~l z0nMeZU0R>(ajoQ0G%Il)z0BgRR*bsdz5NcqJ<)niF6|PUO0i}<4)q>6wx4K(5>Y_I z4$WMkbCOQFs(krBnl zx85i0*7%Zm(&nKNP?AQ}d~6@?D9dO%@}ouN2paSR;zyUqJuw)1SRy=g%o;g(BD|Bh ztnKV(4fcBgDJ~M@%}n-6ow3xOhnC>C^d?PbS(9=TnO)k5p+W;pu2F4eiG7ts zJVL4M(NiZPQDy*9`H>-P0GWY#=UTnh8feiNF}hCs`8^ZDKy;XIL^9K4Ps&y^#DQSE z-?J z@YOQ9NQi>ZP>^ix5K`R07kWj?`R(B?E*OyR1$Vd;8p%2Y2zEYt4CJM~gVX%MO(E1B zzXhsHn~R1ifq9~dtzuH!*3&W;r`D(Sjrc)m#EI%`Car;CMWcU0c+0r?O!)HpjEvyP zb^;pO-Bn6e-+>dS^o{q&8yEH9v}vuXX`W;NPRlwJdX|59`z?~z{pFE!^u{3k{KkJ55^ zD;F0ldy9W*`d5YP|0(E6|K%}9|D^SIq>wO)4^cJ+yCa&xl*3}hpvcQ1eP_k;@>tz= zOZnw)#fxHc81jPcTM#)jgy|0?n0(jd3IPu-lJ&Tm`#F1)o$GTwYp@dlqy-qiHFCHS zKgikMUx|%x=_%B)>n_y^+HvD2=nP`}-G_0A7)I$yc4`tXS-On8qOkNp>Q^$|Ew%Jm zYx34*(*Z3SF}xw$CA?nG9O3ZH7l)@Dp4EyH>8eXDb}AFz)k*T53iA~gRu&e15u@|% z9Rw?69nQOeJhv^^unjd-VGFwbDzf9K{i(U{xxHyM@-aI+0qP{TU0G~w+Fs>taL#Ik z4+92(Z7n%+okd478;__0GkE`&(C`k8h@?UNnM=F%A~2|TKo)q9F<5`s)KwxJRw~k; z4giS~|8AIVG;rde6I^W6m9fliR^7YT*>&x7wv^?xu(5p45n{|2F>x%?9Jq+~Tqo9# zChbeGm@9!(s;uIKae_4h@`~yIj`Tqct+-M>d>~2PCiQ?UmFUioyy&~h_DTBQ--W|q zqA^UaJMTz4tEggQ*_cQ_LA7j7bLyz8#cpGggy;YBVk!%oSdufoh5-FYAQ)v=d$Bi`G$^~ zm!O;En#M9uCykPzLZ5SHa%?hDHP5P;T4HN0L6J*r9DAvC1WWPOrd{*obfr3yJ?Kl3 z^_6dnXRoi4<$Tr!=4mhHg6ig~BatHR zv%ZMJr-`8w_JyFEzUSQdp0HT>|9QQG?IXj$7Rbx4E)%HauDyY!tedHP ztIbq;D)ckd-eirAHOG7icBH23*ApHA@nG*Jdh}~G?L5C^Xw^+nLWG+>hRi&(fnpY5 z?^hj4si6I{m1u^%i_yk$tco}28X8|}g5*tAEZYF37$f(+xT%XvO^`i^Ig}%cydrwF zlpL!xdO->&@q|8MiJrAxt;z2CP*a+EvV`_2& z<1=p{zjhmmYVkpx#RV=#zuy&7^2Trn=H$nT{OBVF*0z|QH!NxBF%gbqT!BEx zKB!SsSUwSo1Zr?kMM%N)@hG=&m`vRQ6QK6=oIvnUI+|C)dGKM@jNwqG2Xi8;YCUHYRh? zbl@DN-za)+0F9kw>Yv=ioL)01uFp7@AVEB0AH-nmB%j$RC_totFy4BKd;OPCMUMBb zu3oUUK`|{AvkM+@KPZD4Tn$(VlQi&aWV*Uf@DO|FQjLOoVw&C@z~Um*h%Ka-C=n4H z@(Lf&MDJXNS{3Hs@J)11(zo9tGp>wS^b9{Q1WN=Ktn>ZieRZS?k`gb7P4n?cl^7^* zG5-oARAG#i<*z`J0ski%;QCLD-T$AbOHq<{KxIb4=QJRn@MGj=ns0WhZX+uX z=oTjz`o-VviMt1mB0W1vA*7oq1ENz{<*-EU)U;r*ODfV!G-?hdnzhM@rRZ=|qaFTN zX*t~$gc-)M7GS{#34R-n`B)eAPfebN46~61R?j^(Pg3TXR1PyQrO7Mf@xf<3VL0`4 zh(i?-SktJu8Oj?KIy4p@%5ZH;P&p5LB8 z^}7P)9h}vUP+1Hd3nNzNcbR`%1>dSZbWhiXe-CcB+s9e)_w<{bypZ(@cQT`P@ch=d zSOPhExgI31MVFPsClEXe>$~qYQ+d}7(!BE*9y%AjQ47BMDt=#>`1ie)|ES{pFFdHa zI)CK`f3x>)DtZnm!f5=e@g;3iK^jf!RU6hpjYu^V#q0uWLuJ-6={Ua3gDi9#*P7;- z`rm*5)n{2QE{UZ01PVy@_9(amogzzOwYcVgp2>LsJ(}hKbX_!ayZ7=U{!p{BHussVj(W z2z3$zu7h$KK<%}P0YBJ+)0unV*xD&6GusXqs=M=Cl&fP@Ttzfq?>H9TW#qDId+C7? zhD;;HOxDJR4dc_xI7-b6N6nZ@bUWueDk<_9Rju2I*o(i)M0&~%C^ zc)a<25M<^NrsjAccydV2HJu_-1W>b;xrB~Mi@c7FrW-94$-GnKXvF7( zA68!d!gkIo8(URS{(u{zRtrF}B$9@*)KH9POqOW-B$za4Sg-A&PM*on$>$o#L7pH~ z&YW8oJX3T!!@2r4Rr6ac0ZDbtB1b5yc$5}7oZSDvGF0FWTpZ#r7@GfM^MmC-p{9Qj z_JmmlTxO(^(NHqBc$ECU$jQp^;)%xnyr$qvNTd`R@j$8JppDCGQAHQ7?fja9McCUZ^;``VW$1+G#=<;K{_OfH- z_$fp~S3K`;jPNNZnkB@=DFQy3{6+Bq9nOf3~dr4q8zD_t{P4-^%<4kj!U z0aj`=#@G*w?!4fpM? z8Pwb15(Ka*TtDN-2aWK>*hh{R_C}*e*vSTkHdM(ETM!JrJ=1h?(_WL}2p#QXjrKZ_ z0k_yu^;~)#*r>sQP7d_4VBRvWJCzw#TxA{*hktwQI3ST{8{>3$KHJIgMGK6I!d}Q zinmfq&RLRxX8P)_@@vVr0gPu7*)uU<%xS{|Eg;*w1}2=C&?7B zSX?OLt-gZO+<4@tLeF+K0~*|xwMD__KxWgGfsUpj)KyeCM3J-f*uxe|xk;Dlqq%1< zL(PaY@U(>Z#k!C!B45JlmE^~wHSH;r1c^kWTG9_VT~1LN6$a6Yg@kNF?&b0hs+5Dw=0j zR(wcEYmdfgojx+Hzu89*C}4$I7^?^vYKhF(`>=MC)VeeFR}}?j#XeLnp8OhW9%9ND zt6utD8DHnQj5@YJv+$USdN{8apQir2)Z{8_s!BABmG2O#pz5lSh|gf#CI8X4I|U4g zhQwk=VEV+j+-KNxuIk96Bi%^(Sf9}A7o$zHJ5mV~)qP))QQY&^>9}z9z9)PWpw>8T z7#NWNEtnUoUl{DP5(lmy<3;tpLJ3hG|;CGB`3**uH0tf9>;7w;Aq9SRVg1FDpI5y~rY#B|eCNpAXD z9692@_%$t2^nu&4lU~(~_iVf|Cs|mXs-xKlY$-~FZB$!oDK#)JgHZCG)ySDURM=@(i zCpd{Er89|l&)(&5>L6LuWY3yC6)`jPz(Po8pY=AYIBnx3y2Qx6*sT42mpR$zwx!!< zHHCc~tbF^-bje?bo#~Q59Dmw_-VcliCn^FfI*EV)U1NkNA`6Cm=^%j`%M?1Zxa=1U zn#DPNc32&XHHfUfmPx*J+3_GA&g-_pd#wO=Q^5bdhzmm)>s@yO0q|>ROV(hkhJWf@ zqWjI#+9Wx%C+!kp&kxX|XPS5m9CBC&3r>}SwdFd#YF_W78A*CN6mFC)qzOjM);Z&v z#MjdXXMw63v*tbvY+$tDmuHNFunOlRM#qe|eV&|$98!xy{n)-=N?lrkr0_}U^sz|x zs0y);(2Dooa;(9zHzRi=I{GSVcv!6jl%ck@)>JODfR? z%aI)0HvbhzY9K7eYsntq#JvWzj$WCuoyGoPY7;LSPfZlFiWU)X?(-p}s4FXQcpIp00;%Jv;k0t@2vBu4i;rh-?{z}cHTLL9Rz zT8r(1Ws*H~EyH+adP$cGv|7HkeS9p6eOEI*`idH3twkEJ*72|ey4JgISglGV0Vo@qe#)f-=|g%l$S&Onwl@mmdn|sjXXYaQ4MlfzjiK1* zY&hWQyc9?G2}2s1fYnQ}LXpq{!&Kr97d?=a?_xXAU0SXrZE?T+=9os2*v9%Csph*M zW{}m4+PIRmHEI;<=c5$PMrfg#MTs);4Tb_0**o}*cimSWRcxo(;G&&NV+-?W7v*%4ACG#t5J zQP=$g-(mN*;B6s)d9JNkF0#Zz_WA>J;{=2a!IJsiqCV!YLjJ(wUJ`3b$>qcZ!HjDT z2xm;fMSbtJ|3o~tc!jJ+U8a)vX@NcxU8y#u!Puq%R~{sps0msRFO2!GM4}786S7* zxgNmf{q@|Sdnf6_he>gEGX7Hn)uih5nL&&t4`O{?V;;bdl1U~9RAnjNmt~1UPC3mh zrR8ZtHzz1(yOYSK$OjKf;InJ+7mH$WfqI^OG3dhA+S!YmIgRv>2H78?<6A=~%E{ug^P+^b*+f=j32&Nv&Ypq?DcH&Busg^AUDE|p; z8(tQxZs1+0gUX<5~Ah zT0cGckI5%nM~d`uaMJ$o%2bt^##I0UdaQ2>-bpsP4P1Vk8r7EOSr+a!D*Z4shiKFL z35Lvs^i;#;G{%ksUUo8(Nj2DY?u5->J8kqS_#{B`HqS(UkzR|K5&6XI_#FH4?$ znMXeTb$nmr1`|{n*#5H1T%vtU4-H)vrtAchme!ZG#@c+Hrf4uxx$;VU(Dr~N-ich4 zMKpdwot^bPY#kBILFgi?i3W_kV%vn2J+%R5x}TL8I?B~o#VXlmr?i=y`yJi-><;X* zPCDrsU51x;mkr+t18lPs=6)r^gEh2$saaA!qv_< zKQP13J}ptHaUjT_(*x+P}wfV-}57aU3rp#3AB&~e3%y}0ju#22u5@mUIT!GA{* zd%-e2DTmr#$(P6^$&N0oCgR)F9IPR~!Q!x6YI*7dx6LR6n8tj(#1~!0rofeMtT#g* zW%-p@V09>&o>iz0j66K^soJWg(o9#T(8Xx-P3?;J|t~nIDSGPq(?-B zOoNnc5HZhsW(m6!J+yj~kjmjV6GKvhO>%^v5`O2I@4B$Z!~DgelYWdC4P>YfmI$TR zq`atDEhIt5ua)PS;Yz1`FX@3Na6j^uBx_rNKTmgboWGwE6O5;iQiN6Q8>ZX%ApVJS zTEf6oj=@?7klS(JaijG|(gO@dTgxB3#H)4&?+@VWkTc)dl;qK|uv;WRI*cG2`6PiF z4+svy+Bfn&Fs57Jz6i!C(w$w@VWPAbRGak~oN>3vUg|Mmk0NpfURt0*DSJ_e*Gi8I zqshW4F}L&aS8x~4*#{4vOc`gKW99cx*L^69fgPj#?++q9LidItd}<@&#E{ZGz7g|c zFX$uKJ;Qv^NpN*e&EL;l@1br8j8oxO3e`g<911L_jr~Xb0)t$x$A~dFay9(}gt4&L zyb=1<`|)_7(!^xJ14xLBGKXO3`R^_;F01 zG70TiF<5(=pRsJYj!^XjLl_vFJOQPhN#Pkr#G0-m#xG>q)GAHjE4WFhe7Zi83;gte zdDv6+)qrgh3F0}$gPmtb9-Ff1m|xDD$6jX)Dcd5Ms-(@nKM_3)2+hfh6@Cs@-=%Z_ zIinf|ck6rN{EOadGmJ-rzvxZnAL)(mf108HL2v&m)%=a*?3CnX2ZfOQY?ha_11m@UzRqlkhrVbQ@0M(tSSTerx}IH@Dn2={w$iGqU#`v}PuV7I&A9JYNP%sqMn z1bTq*Ok{V>SlVH8H*4X-lO?VzaDQzAaLvc1tTL+To)YOuj^V8mQ?)K-FT(s_!ds-O zeb$rKRR-~g^+_aiGtH6kbJ)!K^ie;ipJ8e;>iy2}73i(1RY-~!(tk2zPj;pwB4k1a zVa~7lF^EE`UH=#eb**88zBH%!WkO0S?_Zu0KpRtXN+XMsAwfT56IZI}&cs+R5N~p3 zlQH7o$(zsQQBPIRmD)i>TfdcgCSKbVVD;VCmO3l1VNbV&rWc9o>Pk>ex!)Nap%NtP z&kKIFMm@k9-HeXj2$((SmG+a-dXvl7q(7n=8)cELHf!@Le+X)=++(}pKC*dcns?>G zVa*fV{2FDIJNaK_jq)WE9MvxiTm6sI%YUn|S=oP0Z`vE#GMZa`4V5byxmv0@8@Zb~ zyBOJuTAG>Im^uIL@!ZrWJy6xL{%n;pEwY87Y^xYSfmmgRcgcEDfz4TJ#{;n|g>8(> zv$(RLnp4oD1Mj>H@ar|0RCy}E{GwvuKOf1FS}O&z-Q)MmCVEK{p~b2xFj@lTn}#s4xg7h+r;n$TZDlT2AXAv z7R^$J?R|*xL^>7HI}e>7{HszA#Y_e8=~8*3zy_J$ejuhByeI0I!w-&%MW7Q-FGMKU z8qPm&IdU3w#^#`d%Vcn&q^w;EEr|w2F@ax^`R;a@p>l`U-T%~f&^`#zG}qdSV)A<0 z^*U=#=#o&gd{o+*s#j$xf+2y^t1Wj9_h}(DNi^aK#jI}z)v1rk-H)gocbgc`wB*?$ zfg~22r!^VEN+n>U8|3{Ebe#!9k|dF8lV*9c&9H~&g|$Ymc-2O^j9w$Q^I)ldd}5zv zQkBFDS2TxDn`p}-{-`br?tUCgyfr0Wbf3QeATbp=9sN|e90U^eVOu0~VT$1A5))@C zPcwzUn7bP^Gd~hLA@8EwiklMmlc^(;uPE%tLecC-iZ$_~jNJnZYn1A%r}=VE(-LG; znh6Q+b;zKz_N7)0SH7t~u#)e>Pr194w7xp;V&CpmJw5j6zBO%yB zjVf*iveYaWlrE~+p8YYym=-QmTd_F!`)ATishn6(oD}hTE2AqnVPF_os`ca^ET@@Z zoo~4YJASOBn<;8#(#3G>n1E)&@JA^3LV7mK^kaJ$((~ASWup3G(%#8O%xFX8XSiN~ zUF0&gDyT`FzIjtA`<-+9RXEKbwu%RtcrG!#-aoN0aj)i z(G|=#b_!z{o1}cIyw#n=j~Ac|NnR@<-CW$c%JFBFTi5JW0BX#4k2o2w{L0EglSN7E zFUcmFVF&U6NBA7!t`Lut>faDk>pW>Lz9BSzsqWvnI<+L#wg=zw+aeL6=70S773#Rq zG@fVM9=1ZibB`>L>hKz>rHG}`pX;dZD>I!_x~u>jsx3;0d$`Q%t7d<8^lkl8w0WZ3 z(HGiok6h^#G2EzIH}G*;!U8FW>@|C+wE+z{@e{wwWEkzUEiT0aDJo2JwZR{zcX$Bz ze2pzE&vKCc6@vE*GIv1LZ=qSg~HR)Jf|ljt#^m2hZF4z|32*7{hd|u`C7{C zjG>}`{SC3Dnc~5%D4yBa!V@}xSBtQ$ZWY^qs3)9jTuIXYMgPF5E0*&A0B(=JEntcVgC%ZO4UKHyuzuSblKNHWJ}OzVpeS z?8|{P8FtkJ=~%YMf1h*@o-YsZkLVQU!43cY~nWEmBt#&Ar%7WClZK8 zSe-!M)B8((tj^wSIm3?e5oe&mQs6BAE#Y7K*^boU^Z#aITL%-H zul5Gx*FKM}n~RnE*Ko3}nXrk8nTw0Ok-d?{|KMda<$n9cFHzkfb4wa&Dp0x>XjayP zg-KZ^Ayey*gb`NecHls@$a-2|Z!Xe^@P`uYYo`Q*jKzDQGPFf^GDQ5rd(-X3n)&f|bD>?`-DktKL<0hWK!cPS>L^@|VH6## zG*0#NtGfzpZpt+e{yL@K$|Lg*JfO%I+hp&kR;NxOJ+y2H49xZA7=^RKObPZi6 zL&R70!l_{PTFcxI#h+WsO^Y<`hE*z1vg9n7nG-6n0xBU8F8yDd}=?${Kl$qim3(S98@^W*vvSs{l zU}!oUIXap-i#nT`er(?avm4Q4-snuM&-cwu#-M{K8n;l1gP$ z3sw?`ls1z%eb%&mNBvLuEci8}-Q`|kUw6;F0-pHb?+A)+BLSn7_@my}6u%J=Ub~(* zU1n~wcfO|73IBZF;|Bhy$0FeO^>lmmZz?ZuZC8$p6<>B{Lsp-*mS05IVU00ergKWv z(LIsLS=?(>QLLQQ?bdTpyO?iiEL`;>(XJw^lA*7FCd|$g@c3VRy#tUf-Lfs*_HNs@ zZQC|>+qT`k+qP}nwz1o`ZNC1_y*J{2=fCentcZ%LwW?M`<;L&dcdwa@4GT@LCkltq=Xfy+OasOLT!lXrqy` zEW9YuDcfQtJ$oJ|Ln|b|q*_a|YPgCbBBfQ|5;-1(P3R`sK~3T`TtVV6yrtDbioJKI zPDV1BAaj#O~V^ll>$# zNC?nv_r5RiH^A2t<)qzcvns9Qd$_UU$`jN;KUSNqMCQiCFCi3A$*D#(v=FXCqz$SB zyC8vjHyJhMy$5kCi}FBy0NdSCJa6{q(|*9I^zwX1NHX*dHOIDB8bsI3_{(*-kkQV@ng|lWd*nWx!(xQ1stGMcRDjH=YUQvY2^uCZuO%-0Jw5az*F1nW_|h zR~z5DT4j&Z7527|#z9b}pmRW}p^|OrU(TWox^&Kn>YUn%%JlZJ^16vzy|O|GnZsf3 zSXEMjOhuYZlh*ikE0&zHt5va@6&GI{1&D+NPop@Tss&f!V4;}nqX@iOvdonoDa}J_ zE-u%qrrUpYVYSGU5NeXJr?#B#3dkObD8uk*U|u*zS;T2YgAk;_kdF0s4A6A*YGO4)#dKwYLQi+*i=C3N85d93 zAe#Lng7EX?@}-FPvIdp0y!`J@^1tg|IHwZ=C-i6LW7u!d>#==7<(?=6?caFCo;)AM zwwV6XHIU7}%D3 z75#&7SiVq=f6k4N*gy{?o~K9`+fsId8Co*62ksPHLm=SB>G)@44I(Fbs1stfE==|e z5WM)k7Hs~OwT#*$%<~0|BEb_6HV0F0=kYy;P zdAZbN(@{*9FL}4bSi-&#J^2;N`G{J?KFD@i^8BEXQq3$Q#~shvw_cx5r%ZlgHz2&Y z*cU<9UD1(G6qg=Yx{LRix``xh^Yi7@j|r7hm00t{(0ei78ZQbt`JV={$XlXvX91YH zxbI<;-YQG@9xrY>Ar~yWklR>hQ-X6TUxD-S!;~b9lu;Tu@f59S=euifnkTO2C*G;S z@TJZ5{$VG<^ThBbq_74=9q9r7DxC6VBngr@olJ}~W87-NEagn(;M*)7Oj2!(TG+}U zsLu!TV4B7DH{}gtanAHawLkpH5_$jk$0~;0`rM1Hjkl;4D-KsjXTl<*z|E`_8Nlb6 zroi&vNu(socja8wZ}9J>;D}esqgs4BR?_u7ZyELz2k%GQjtG%Vx+yeS&QI*AK1Q~e z;1-8)WjT?WqB>et(n%42u5UPI+!F^B7Hx#oW{i;??}{9#vpvk}lwvHPB$=-+pnIAL zGBd3sTO%TRGFw?`Nh>DzU#VeO7C?`w!-QT4ZgBE!WsS1clJ&i=m$ zHn^;?BNx^_wESMCsSKfxi542WFvUJUh%GpT-JP-b+D|wh`H$h4?*AT6uKyK)=>%&^oOXr5Al10+ld z9x<66pEk?hlV|$s!otJ~_Kz3DcB~XFzWq<@HMwvNFc2}VQuS$6g{U$+nN4G0`E zua0)-H1D8k;mm6E{(!pNomCz*qxv$pI3NvG>(+Q4AcJvK#K8 zb9SOKS@GC!pN|JW#<}*37GFj>D1wi~_)k#-N5izNy0%(q7hMm?oL_Ju8jMFGA9bKb zv$!gbC9lC0>Unx?+*3GF(6ZZH<(4j|5-Om02Y2z2IG_&xn+2Z`6;N1An(~^lQwwUQ zOiKj)?fuj7EGlb8nv@wDs4us&o=Bt%l*TAhB{h=R+Pddpm83-ms{V0T&ofYt=D7dS=Kr=V{~wzR|1=j_+3Fh+3mcp0J6k#Z&$+yVt*OJ$s$BYK zRx!5u|IH#%N;9@dV#r@$o(;Dy3GBon{2-)SK+R!>`0yL(nq~lFeelQy_)_BZt2i}m z8rSXb0|MpaMQpG<_IaUCD@=+=`KtLmC}H1)-vV;8Y!fw&`K2B6oou$QOj%XL`Ye$dX*5~GV? zjoCc8{4m*B_lFn=K@#mp@(*Vga>;sjA3Ds|(a_aGGbuFi)9-z>)&hY^h=PM>jvvAt z$Q7Zfbr%lPeu2OFHW3uNyavs`ezAXnB`OuCGx+U1e%!gwF?S3T3XLaG+BzOfiLB-f zLsTI!R2nT{#3)Z+EHpqiKXE$CK-~2S!*Tvgi)l{*o7SZiuHQf&N=jK$gt6|+nF)`Gm z!Txq?dNfctW^}=z-436nDud8w974=Iuf~cqED93ykXqf1w8FZK9fiO>iyHhGH6`Xa zy99CYP)x3@)FSqPdVt-Br1$H%x6;EwpuBzZ?#_D^RUI0KPMzf^_Q2rPhK)0jFB8Xm zlV*;2seylEHqM|s4!E5>k-zx$17R0R2*LcwM(ea^%K>Rf92id$mc6SChy+Lhh?+zh zvO6({dx7GOFjsuW1#TIks9C3Y1NS^K;IL#Bmt5WRAnNcc>QhlO{Vj2vmon)s*asQd z33&IEDekAAXHibwHHW4Kjin6FB;UgbL))#+*%fRgjq!Uy)J$xt^A4P* z=wpGU$DPMXW)DL%DW!nu39E+G5tKB@YM$r#?rOf~PwEaIWOZ?-rZteokPGZsqWYS4;B z|0LjjIbp)2Q9#;HApIi0rAAv&MKYgXU3KhsoOYe|YT)zr{({<}EXL67@nFgE$g8n) zlwsHK7H3m?1l)9j7MVEeKIFU&$Urel=||l_I+%2%vpEWGJ4%Ae=4~9emV-GN((dey zu%{X&7)-JZ@$2L0Yqtni7;-H%fWs%8= z=kT2S6oOA<-_q!hTShh=6tYB`my{cf^+Lx>yzS~3hAy^=8Fn4^M9*a;F$7-pPb`5WTTi>BH<(hQt<2d>L}bEO@qeR~R5CV6M#}U~hOs$t?sI z7o&N-naKA!$TJ z>&^XTo(>zGjv|b*XTI$ut5?7&&KtRH*Xif1`>gBEp7*Joo(B{{&6%EYr?;2euFLC6 zyxINGDCvA&Z9Ke6+p?I9Q!BMcUI`b0h}(?yqWH@VsM zQOR!?^5j*fLK3_B=$34i3+r{u7IgD)M~W2q7y3L-307k;BupXtBuqlRxD3=-rhwa9 z?bS^@iS*Hnd^;p2cOp}nC~VDSN?;3$3z!yI^$)`1W?UAhtCjjqn>M&ph0;8EaiL{z zu|C4KQm1Ko&6~iXk*x&^ph_a+*qDsevtmcT;T0k>1Tvc@2_|YU#phijBjGm~(FAS> zlUlF>J!lV+cX^mbgNt|q+%c)}o#I2L8tL)BII4PpHABevx1oqq4Fk=enLf)lPJppehzt;iO9UQ2qK{ycJZ}25$Em8#QCj@IGeY)Ih;t1C_j5#Indn9> z?q%Mr*&t<`FGYDnXUw!Q9F(&(vc=j2NyA|}`{O%(aBk4&ic|F*CyG^zcJTh7Jbkku znj-MdZ0aPz3?=kXncCW=-<;dP;J9T1y-C;{aJj^)J(P2N6H-0wO?ZvS=U!GHKVCK< z=aWv?u%5>H&8MwXa49`eLmGW<%;nt}*#2=)K*`axE(dLvH|fGa6F34#8tRY?cr_y0 ze3Ys0rp;JgADiP65s|!r+v;Bhhv}`Vm{n>M24Hc%zOJ&UhG2A;(vSJbsM4>fU{u2_ z-6VIhEcV`qxROML_k8tmxBr)-{ z0Nki4Ka!>@`U^UZ)eJ*+dVEKh%hU52puWKbEG44AD>zWsBPQobQCa)OTlz41wS`U5 zA(_e!#MIkQ_D?<^L@2G~TpSiQGc{2i*D?M}9=ed6<%52)rPN_&_Zz}kJyQ*xrss+n z+*}R)Uzw_8MN}8>Nin$jkrHrz;R3n*HT*JD&M9fIRS?wRHq#A#i(f4q5+z;_5Ij)k z55fi>(u^$A=GCiS!o_k6hWVWf;@9>(C^LB-^lw%JYn+7v`}UC04jw=#dbI?>PxGb< z^hYM;a|^$Xv8HwRyEFBlC0EGDeVFD zsI=F15ChE=aHP6tL~Ao9#WHh`H@ZcicgWiJi5Wg12JkaFg6%fLuw^#2^+FGSBYJC) zcLQaBfXhJJeIf<*h>U>kVP9*cRCfKc<$@qO~wd*)<>-)SK6P zJ@I^4#us1Hf$yt#&=?VaIkhDY^^W;!&OFd#L5S3wEK(42b#OVRSI3Yn=DLC>djb3m zOx*FMX7ymI4;B56>=L7Cv?Opmx_j#kUAIX{b-S2c8Z$v=gOMvo?-ij^Qg7+-IsiMdRFM)v7G{O9O zb{zD!lmDA*H)}70ZFQ4xTkLM$F*jknM@CK!9fA;1rEyA1T;kT|rRhl7MQ@3Z8K3<$ zthbXo^c6w1sy3usEhrD|+wtJ{DqW>!SzzMAYG&n5P_48!FI7^!mt^UsJ=Ii%VFz|f zC`{_0n8zVxPB%8P&U9wpG3=awF3lq(pY)ZY+X0iPX>u?nXvOVKqHlZ!kPr!p?==9sB_~DS`Wz) z-C{l?ZU7>v`xhem*b=STWhZXwe7a@WUN>CeYu(sj2^yMe+X__p(O0XKfx z%AXEQxVFsfTzy)ozm#eCQhr*;4iF$jVCn@40VgXeH%1E z29UQ3y$aVZ3TOp-E~*g`Gz^slv`Lf|RO$MFBa@P)tKRuI=cc?XxIqzmXgmw~OWv_3 z79M~sk*g{jtNxD4ShkFGO@d3`N{)-(L`+B$P3o{T)|L%BE`c71nj=koezdtBY4~a%t^5r3-m!3Kj%V`9dB?v%w?BxOI$&~!jUNWa z@o8Q~I6n%f3*aDLLYK<|4FU2X@*``7jnlDRq5+VebLwb4vJVL_1XDYFTUc;$dW3relP0}p?81NZ&{!uRJU{&9)O%uEL4Mkts~ z&T=;)Kjl_c^Tc3YX*8y9Lb`*cpyU^wFHkn{Z--k1SA~|n0bO2_YwyEVv91paW(>>D z5A?fn$`0!!94mEWTUFmE5+yocu&wZDj;aE3+jOFJ95*T%`pKWaqKNiaixt!T^#`@p zHlA$6Fj^5&7!Hb19 zHyE9zQWe<12XmH)8IDIOtwPeM zHRd&LKn-qMRQRtyy5LYzR9#*8JDBD2K-E^^INa=#S{XA+rW5XKtg>7Nn^Of&Vhir! z+P>KycTUF|e~Hw_vAX%ap<+u9o9)jcAVaw~|4zkmS zZa8>nl~i|D8zjQ^%<{;ZR6cbVD>%?nlBzUD&(9h}VOpBkVW!AuVW!MGuz;OfTWE_| z{yi!0mE#74$DH%4$iv357s-5PS(g3aXJUS?=I-+Jz4Y{Czu2{VMepL1!wV0l8b0k) zSH~&|HJ~YYm{WKY&gKO*WNzB=l|JE3C?T`VIh$Fi$wHFx68QWYRy%ziF%z4Zc<{>B zjkGSyv*i{+F*O@tKQ!EDM%7xw!z{Yx)~Woo$kr{Z7+t7ve;X$MoE{R-LVe22TZY;% zOIFYRqSw}4;Mcno^z?O*G8Q`&wbgNV%>E*DX{fnqK*lP#K0dvcU3endLW%GugLOH< z>Y{oG#ECe$UPvO#$t@?@GA5JFE*6oY@?+$jRxnx(BiZ8q{AuRkwymR+;{*D6-bh*) z-5@PC8lo`?K**Ec9*n$U>OJRjK0H$J@vnMoQZa4ti zMegzJ2oft=1Y+aEG$4JE9{t_I{tH*SwKVixk$IyL|hvQq*qu&_4C6X zp>36)v+qAXl|OfXL8koN-RrhNjjA36)N;pjmTkOO>jg}c>35j<2gH)fb7QYv#8VV2-AXJ1-O{Vpi$uIz3lMp3dl`?Wwpp>|6_$}|ROmbQ- z+O3VID2pdMNR%dc(_#%+-P-%bNIb5Irk&d>rOY(_mq8%P;dkWuH0mR4vhl=r?rV5g z%=n2Yz2%@f5#I6!(KxF>D%1-3IyJU|VW-!(l$}cWBQtobb>#9D+>HlD>@kp+qgiCj zU_Y+2nP+9m^gw~vIRygs?R~aXBZ*Vk8cFZj_&b8(pTaY{Y}cTT z*fRuKeL3=89rk16#2TNQ%KL}Ryx)%5M0MHy=A(uL9M*f_;^wBL-FO~J+@|(7I)GQF zGxu8y$fzRDE)xoI0MCR3S^FKd3Mzir$&35HZu)9V$~5*Kk^r{%vt!7ISD#%fswRS1 z7x8ugQ&u(usOPXbN5Z5URhEFc|NLc;g}f4JzVjlUxu&$T#yH-Omy4s=$~b=B<)v}= z;R7RHY}oe#TExRVjM2_)jF*Q3%G{)3ZZqgSTa^}wnjk_InITrx)tW> zN_A5pLZ9CogVv`5^1_9Jm_n4I&Od-1kC6YSPp-Oxyt0!D zIplg&zC_?4NKvoQui_?BUY3EYOP5n0W0#hYf21a%4Fg1xeEs;w-CE2d_X6pd9A`2e zuiIRY)}Lqe0J(eXdpq{`UG}5w@h=I2qwDlnybY&n3-F)3(mWK*z~Y1=sqQ352UCF4 zQlI=T^y5Lp>gG~>1T94`()}Z4=w<|*zIWTL=+#(!PT$k6nPOoI-RVk#s?iWB=$tTc z;v`#9_oLoCy7W1j8Mn^hfr?}kDKcERb3jxH4>hafqve(?N%m6{o48;*Aj`VQb5)Ul zHK-31_Fm*+OH8EXSzh8{$7fljqN=ahTv<75(Rp-SR$Zz#EMGFOcXfT5%J^HHx8x@r zP2)nIWHes~>%OVy%4>O3(0{X?N*ukyQv5>kKb>M|32-D&p%1(V8j7s?3w|Lp63nOV z937ts^a~AioVI92W$?353}~XMK~{A}5JkKH5b=n9Ciq@IDBAB;Z!IUAV+ciiDvH*j zMD^3Dk+a${QM5$azio{#f^OHOx>LnJ+5kbRm4^N`5ii4(4>XD|b?3s1jrWv1Z}MFy zT9v+!?Ds9SiLUpcRnr?JG+C=^SKkC=BwXt~F8Tyir)=)czcAl$Z)2R5pR!H;e=OVl z8*}D=$~ONscK(|=^G~^sSitaqkw<2U?vov$hY7)fa=I8~62|7IuK10w(qZq9BnSjK zt$S9yI^QU{77(-&cteiu27n8-8*tNC&-dMPS#upD2hi$Q=J$O0#Os?xwTN{WtSzZC zp0+5nsTrDO-C3RykP7Y)6z8U{uiQ@973Pg|STBrbPO4R4VU>jA3ZJD%OK)mD`u%Bq zjUA|-$B9L(11X}nY*naJ%@8ESe`WsFWU8vR= z2;2}9@)$?_zbc_riw26%Kg!e8Kd<=z-OEDxpIr0*^LqcyFQ+uzy_6rD_)MF*+Au)L zK+sV!gc8RX!}1A93BeHY86igj>{s@tCS@2Inb@Wg|3Ir$G(TxPHZ`*>y-_zsskEEv zlcqu`YL%;Yn6XuOyEIg6vQ;HLymz>grb&Gw(*q#A5?6USh=@|D2=%(`I*cmsk7f^9^}}P? z?OW5EW$5ivagZURMyiQ!)dSTd0?Cq6Pu{r&OKRfiuu+&nj(M|bhppFk4ze_}sSz1;);PvKNiaE=q^G|5w^Vy2SN zBs0Xts91C^d0dq<=JmXesd8D;1K5UvF9?WTYl6d%lJqXxN`Pj}5LxPgSRE$%)Se9Nn;^;MLmXCiH$)23AiNRlj3 zB5S`@U11=y{xj(rqgS3zSUD^dhUILAwb|IZt>UN#gv=Rm63ig{MK*6HQPQQC{?1ODO*flB7}Q(AO3hFI}(g&O+0tS_v* zssss=fjAF6c7M%h{bJFcbm>-<=R>Xa4X{qGb3|a97zk+R8pO+p(k2^QM<;%(sz0y~ zRB?%#!Lct8vXEtAzqvF2#xo$NsieLB9TCSs^E_?X{@2BD7<@uv#vvJzQhJD^v3!dT zl|$vIA|g+p5nMz|Au5{UAyp|$2kfI)S~hhN0%yOnr(#(o-&bKg$Y+VeF{*sx3Du~N znZWwrE{QHx{GA?2J*uLTQ+AKA)Nbt+N2AXvftlF`pev3SOJ$4`MSDf=HiGkA5i0UO zd~$T7PLbVXMt2^U57wmD5}@X1U>&QO#B&jZ0J18_+exP+Z@5Me9xd0Jbq&L^e7(>X zNNZ(5fx4(0i?cEE=!j+2!b@EfJXIo&j};GwfS*019h#N=Yt|*|0J4`!D5 zN_q7;3^d-)FNmK&7&H^rwGK+yh}q{Hpt?|PFC?Fm#mlG5xknmlrQ>IgB05c3KF~=a zh6K*nAvP~CiOXlXY$wlxYQ8_)WN;>NeiQS5Mb-&Nuox?GER-8$-`li(QhmzUy}Keq zW@+_RPM`C|bx|r{2{VLpv4kQKehI>QOprT%3zknCxVb_F`5u!3W#trOn>06Z6D*XH z=M)M2!jWK4RGLfuttE%E2P@F6hVZljI&jmjn43^ zPJ~{D)br75_H1XB8(ej-Emk3-$#Qk8x9>hEB<9vjxJQ=EG&)&*v=3TD&pvVnxeR-) z?Lb+YlOky39f%jYERz8;%h7@zQH?O%8>!r^nUZ(>IPqq+lbCHA8Ax24#IZ@dwzGe_ zNr{+ocSoD-L2*Xdg%@t^OiJbgq#@1W&4(>T_SLJKpM5HrJSQaRRfbG&uyI9+T~>My zyWR{C12~~%bhg$$vJk%xRx<*^v~v)B^3%hV33i~-tUvA5Sfb|5i=rmc9n>)2!GqKa z^P&<_F>DtK$|77CJ5xuKX-Q%!OtxP3n%EsDQrn82M%6F*?l55XtzSVcMPQG0ZuQjl zmq*Ic&aackwk$S6PqbQ!TT;VJDSX~x&h0RoXfrD8&a{@qUZfVn6$ilU9V(GVzCpk^ zP$Zf;Ui%dnVGK2;ueF6kZ zFhW{mY7j^Tftei%owFtP`AO&4M?tOT( z;Htw$hS6rDA9#f<0l{2DA~U)NOfScqg!^m^q#5Caibizsnh)JfGIIAiSiC=S%J|_X-AWeS|ich7A5v3!>zaS0qG@+}6 zF+61ADkXR}zFbZ1mX?PdOp=@C9DI^|;2Tz^0qedK3>_4z?WYMY85qL(rt=Zq14q`G zmX)L~hGa0K_F1zeK5O`YjYkt&x-#C=rX%}-v%xC}Z95zssU#Mk{YR8Je z@U4Wha=tl!xo6aPg=VsfWT-Uw*s!bATd!Jrcam6JES#?b>09?3j3HtW9zjdZo{@vm z;Qsw!K~TU*LK!uvRJbS;OkNH2Wt%Y^x3I4&v!zodO!!r6#`%hm7yl~tBXG|sE%(t= zztYj^vC$ivB^+7S$l7s@do8-L_omu&g;hi4Q7^#p%DB);DAqKLC_yf{M--fbVCW4Q zpLSAJpyR=Jw|FpZ7!OY9&`o&H;FE5C-006%H7z?V^+c?EUl19l4m+%pxM%W-d$e~- zt(|&Ex@CFK^ihfbnmM|@OUuO+x=YOaa6Up`MZSv=z+ zj&v;Xfs>|(JoZyyf*n#2H&qEvkEBqz1th01TIY?cy1siJEZd%upf04|88q_e^UcqIJI$qO^tX{0Q=;ytn*d0;d>W zpbMg2hvsXQ_P18QOkwPq?4dM+V|(uRBPZ<<$bpw08v0vS$9$VUpbm=Fv(IMqMe~ij zM>0rOq>iZMoC}d%y?jB;97(AMLyv&6Zzi(5LIvB?<#Ywf0)mZ_~Rdangdl z&@8jcCHuwoEo63_;{rqY2HFx=n@YZylX9a} zl&P9Yv{)Lgc|b3Q1o2l|SANshLidoYfmF5?I`bsF`E$9kGP};}K?$qva#L^~CH` z!TFGfb4WF(Bq_ENC#V_OREgx>tR!Qa(Jg2?b%7g;M5AE-&>&(JHfZkcmN2s4eJeN!nCrcl9Way`gTk=o|nGo|BD1pGHLvB0ih$H-WM^@K##RBrgEQ`4$CSNzg z8QjInTy|bpvXE2PqeM9*$mGvZ!Ps7Fn?$@*V_0OIlsGq$7xq#m0A&oC)8WX5OB{I{& z&m4D92ULj=J&5P>4A>lRn(KPS@|aiq-&TfHnOC`uYpkgbZ!za!sgrKX&HmC&DR$Qw znLUwmqe#(ab!;OBsne)NG--Cm>qV#<+25uf(vCyt?AGIMoJse#4t}n3bFn42(girok)X zsLlF0m3f3uPV@^VjN3J zs7vW$dREOUH=t;vnxK-_6qp*ejG&zM*m*>v9wu&xniWe@+eJ-67VZtoVET-b0X5{6 zr(c*Y=7z@KB`=B#zMR8)M_(&sn@t?LtNkyD`lrk0nJapT+`Ued`PVEyOY{v7f2Alh zxP{mY>C3kmqt~@Sx9=weAH3PUD&9e;-4Z?DM%u2JrA~7?nOo3Fg!@?ilHRb~Q9Vh0 zS~k)vttP$Xy9A>{?$-j{oKIM^!~^qOk9nFfO9U;uX<{Z}MGPU&T0}pPw4d7EHF*^c z(1Qo888T#p5hW(|Q-(yg#r6vVzhg0gpd>56bb9oH0wu}%3M)p2fxFLEy>QG4R_-h8 zU+Al?!eBv?3%sHzLA?4>j0E@%7$S|RYf_S$ylY+ z4n%*ot_mG#p83HvVERPUjJRH!Ay-9T%yQe2biJr+b%|?XeE(`??bZyWEqp{h5`F<$ z|26&q>X&o$0crC>TI-zNN~}*w7-kFnefLs z2fQs{{%-wM-9ryBgJ*Iuv&{5yuKy+Eoc^si>??Jju|gyAn_Uf`ajXB1%g`EBtwiQ1 zx^awk%lc*V?-yf2mx&<2oHk?3d{TaxpMu&Sc>d+t2h>+*DNg;iw%P+Pbq56MHt1{8 zuC!j;1YlpBL2hXi-rks7|L=db0Mz7?nWiEF08stMZRP$Sn6!kAqm#as74d%`|J5u1 zZ`hY{-1iNNl z1=2bj@r1^~3~TeQTAAId%fY2ha|!FRU6VMpiAkkk@VViqVwhBxz8SBI0v70InyyD6 z3Bn|Jj3nVomoatTh{xa7jx;yvi_UnW_#l*M<|9E)rOc4j#iVycL>cKHTtp3#k-nKL z+7?|mS#aSINetxl?nE8)%Zyk>!C1k`<{`huyPwZD2`YbK4!99|Okznl56^r1}88nU&cpyn*~f zRP2FGaX0@#FpvKuii!WfqnQ6~#DBA2l_uoxjK6W&?wmdns)%IKg2?m;9KE4d3H+J4 z{P-@21_oU4WQ76zv4`7rf2c8VBqkLlTWX8sn;VP7*r9$|Zvr<123Vyh&st-dNnOt) zxtL4AjW-w3bde9fPrdt&)f0toUJ2&UdD?Duy5Ap7dEF=0V82i93p+Kxkri{*^!QAa z`)V#?MO?Egc}EaN?0rV`N9>*U}noU~6E-WouZiR;Mgh z;i}OVBurvrDpRj7!i%ICbMj)VT&(w5JB7dEWs8$MSfbZaa1D^jw$rlh41JSI!*+g5 zc`HjldKt~dEdKiq-t`OW#SHiFi#h4kU3|pR`S;CF5SvpIp|Cl8#>|qEO zL6o_yj`uN0$wSqXQfj)_qWIKrnS3$j-u8y`GrF8k5xy*m3E_xC>4xG+3@28lsi2dl zG->G?bNPxG)$u+RlKOK*4722EnDvKFTfCP}MVn#i1AP7T_HVVXeMTs4JO zpT_!OPG@)cEQ+es9a7Q~8ZJxuwg`RN6PqI_ZGrR{=g#vc28nWQy+I8dcb5dFR^-u; z&&P%sTVJJ;F`R;9s*$hDbF31St>mkHWdp=P*}5fF!x?lQhPw$TMi}e=#xDm^PWJok zBklIX+F!cN8)z!@No~Er@9ywmEwj?-&7I}xh?Aw0SPtK(3EQ+5LHqwwu+}k1p;#vH zrvh`dw3QgL-4@kIQ!Av--?{@#~s8|+dQ;(;Mo#ndpY6spn{3TJBv8{Ee0%vgX2)N zCCV1=Y(p9TH+hpYR^mG9QF6nF>tHb9wDPpXRlL7F+QvVV*IK(W=+D|wiR-*I;elS7 zY`O=x^{a5b-2CDtug6c%+y!Jb>;Y$1|5k+KbP-$ndnLz+PK~0IJ6_kenCmP!NG!nT z0oX@l4sD#DBU$@kjnc{sh4baeOf!mqY{x0?+@X-P%tFTkGt+fK8Xnl}SW!g#bX7&^ z+2;eo?q}&im*rirs}E*eubvzp8ZZ##(eDL0O^$sfaX!0;rmj^d#vG<0v5$vbadqkM z;c@S>jXq)Rz%lvuo_XtEk0U!0-X%0LG%_Oo&y;sC!y!Vzbv!1e%gjo7+E(!P5CXQg zglw~&%zv|GAITU4^EUXYL*ba5L|+fG{n2f#<$P`;XXQzw!rFG>1xIQtjYXPCx$0Tg z_y1H9*k8*NMu;cG(T9I5k|_z+!6-KvLctWLG?awCF`Wto6>5{_B*kX_J!#TlRfW|Q zTxT2;H#0}=YR;55U1N;$dTp5H%;k}GCmbbyfA00QK5!SnK;wWT_=y7G3YX(F_2ej zekKG-;-FFYlnsInfBS-ue-l(=JyzlnCV;dv+bFa!pd>$1xZyr37BgGGzr|0+^O~0j z15^}t&e-E6dU|#)QNVmuka5beLq1^$=n5hx6Mg@fLV!rjf(f07zjUyE!{MRr^$O81 z9c&-SdtEZ{pn(T}h6ZnUS7wPMBn?d!5HMe!BHRBbb05=@24O?2h_`+1 zSkky=Y6p<;hK&MFs_UV3Pi4-ZFlQ5qOdAaJ4>=1O04Q<~*!bCF?FPS~o{er4?b z@BAktYAQF=_~SF#TF%vAsN~HdgBetV+7Sn}tl<@KS7SOg0f&fC(;da%oL1YWSL+*m zGM#5P_te#*^#`lcd2E#Bzrd<*Ozyihcs6GM{UIN@;iOnS-MRs~qr?3IfIIow<-ibm z1axfeXk3WdOtrvL9~RrkL@RPE27Wm{vO5xg=Y{Si6xRMyB}nHWVL(7VUs(tiyCf+=eFX z^v*e{k1Tj6MkZdZ0LiaYY^zFpCUo+Dxx=bBlNeU*IS#VeeOAzI)Vt^$zh$j^EZMHM z**h+Kz~xZ6N@mz-#ETTbxO`K|Nr-N;@=2jQ#7ZgkFx(W;GWygjB|Jx@jU+qS`t!IrL_@Mh#X_TZx%@ z^4p_*L+-*ol_Bw(5gpCY^}j0qLkVl4eKqJivQEuSwK~_wQU=a?(Pr}B&EB% zySux)K|s1&x?55}O1is2>5>k~O$h(?yyyFj*W>Z~9|mI&_Fz2Mnsd!nbFSyU4NmP* zk_r34gxePNOJ$h6cykvyCw$qW0>}3|r&9U*AFcQWu@^Z90;YM#zVCO^+rx zNH@pXoqevqr|SqP@$wvXr8J@&d_JP>=uXmMSW8G@sN0shx}NXhJ^U;k3^P3*Y9*{X zT_){Q>`WUL%w79gi?=u4Dq=QB^rnC>Qexc!1mCKET58qi_4>ylhJterN@VVP&{9R} zf`VGjgzL=<92XlYXsi4V{!C1%tpasaKFas6LJV)K-=vfm;P_v(pq!FX4Y?&YsVKhO zR%%faHzRDbQ!M3E;64T2WnRzcuczPxKYjJ4E?oK+r6|}!&xa}zY4)CB2A?|sZ9Z0a z|7}5bo3I!eu5axh5J}j*49lzaa_Zc8rw3g>pdb(cSDK@($H8DyJ~4-_*`cwZ$s? ze5h6-?o%Yb`5-tXa|0?FF6Y2tk6?PhbB~VSfa6cTW01)6;9^4dE+jka44m<(+qOx| zS7+%A4{cV1vYAlL_6DE@7TAVxXLfPEJy)0APHnPc=nL6sYxCkc(#=FY#J=VU)@bgA z0_~_L;7&Dz1PtGWxfn&<4}Ma94p>_udw=f*7k4kv58VQ0lC!J^kehlmGtWV4Mi6UiYHz1L*lE`k@;g5_yK$-= zZtu<-NFGqxlm4JpB#T7g%Ex-iNmQO!&y7g$cHfwbO|=&7md}4l4Mn9|n24rEQ^>Ux zYO+gTedMAD(2~_1Q6k*FOpy38A*yn7gLcbXj?+s+U;2tl$BG4xn$@hHmfNzSfuA*V zDR8OI{FbT?yi6r34Q}@hSTAGKo2ggB19-#DmV2x|Zadz2|rHCQV8f=qYq3S-XQKr)V!L{fbjC(JB{i1oZ ziF#JsGKmxT>@0|5a3}*}b2#dWUIr!i`8n>4;r7E*)&qvB!SvEbZkC%_T$i>HF_iTK znSw(apn9nYdcK)KaXd!E__$?es}T}>(H*ztldjGo3~FxJOQHIwDEbA;V7L2u0y+iR zI z`Ta|+1SVzj1fro-ACvhOxw!`lkeVnt+5zUv+2Q>l6W3DEHS!?GkLeUc=jF=*DYi;4 zgAmXvqwtL98S&@oBP*(OL2;6Q!{jJ!x!SIzc(UKP=n25KVnzea3MJKb=3u8Cm>iLlc zo>?@$-95+WQf~)EAZt_5R=Kx&-+eesXf5(h%iWVsgV-k<5sR4Bt?SzA!_Si!Vs17{ z{6tvfF)5Sptk|88Zta~Yi^wNgFB3D>72<4rA$j}O^elvaJgTjo4ShF~YmiNpHeGbr zyKXGp)-!&Ibd!z^zbI+4QbF?)fGbwcwDyLFza9Z}=ghoEC1>_-5DRf*_-4`0`D_3% z-j$9^NUELnMfu|?&hgFGHu3n@;Oi!chfyGFC1tj zysM2L<;pVB&eZILeivP-DG6^E!_0P@Pv$*0)yMcNP8S ztipdgy#t~iDVyOeruzZb?;xzt0NZ53utk9^3ZvN}(iFQco`XI5+!2~Bt*g7s$UI9V zqTk}E=N|5KTZK~u!6+3ngR++0rc2UcL~b2^1ySOpH^5EkBa;19dk^IoLT_D(^eYV? zh)u!~KjQmm97L8GO!T6q$6zM-+4)P@I(QCal||#8B$YWzh+EnD6~{;lGD;KM(2Z~x zbfm^>#(c>3<`9QS(Mb$0_NoT37Om8`p*ft5u4+)-eY&scXqIdG8ph(=r%k3w~PVLOXd zvY%SJgzTUS)}20bSmIE#Ku2ArE#^+hFkz~5s)Jq}y~;DcyBxahE*PlD`+}A(u^rn<&8zczVDn%^A5dk-Vy_mr0qL*uM z+kH(G>dhnCDc>o`r?(AIs+^*rfe)ECTkV3CYD3Q#19fXQhe<>BD4P`WFJ{4fglrGp zMC#o(hLNzR_6BG%EOWFS0kBYlhLR^aX`ly0}L;y&ATq9Kgir+g(JSTR7eC^Kd70rtk@Qwh@u3M8?jc zvgkQ+ER2q@6iY?Es?2yUOPXy52HHmmw09OlCy8i1JSX$cFQ?Kz?WxLaD*;xXXdOZ= zBkjariS2=U=4{ztOD4WdLby%7@-N=%81G7r_onmAC}*~wh&dH`ElcXAaT1YCg!*3c zydPyIQxoLY1}B)t!AYV-sVm|=v@yqXQI~?W4Le?d1`+uZEGOQ|ee*VGf zrT|&74wW?}lFB{`V02N9RseY6=RHwR+vczuOFPU6KW$IutXl`cwNkIGa12qG zrJ%bP3TNk7J?}yS3x6XEWxoN1EKl;n-Jr)OR82@8A-lLcqJ0m!DhivFnJu)P!CIZozRj3Dupfu>UuxP6njtRWN0x(t)#GPjJ(W*QX;@KZebajIc;dm zCW~hL0jRsrD=aVq-P|3Oy{?-lW2lzd!ihrjVFr)oLbOS5oQOiE*S-!;?Lbx&bB@wB zIBCNkoH#5Y8I#5PlHx>EpLUEIfBnTV;pU3R%nfkZ z!YFhE-!>M@7lKEDX})s?nHWmd;*DDNM6GEm7PaY{ePtQ7vU*E6^Yo7t_xmKXg?pIw zLetbL($kGYR?TwDFJ{6?y@??DP->A;k*WI-u5h`r_Fj=a1?c8CaYv_fx+w3Y&sz)# z5l!Eerg8T>?FtY$ym)%@xf}a@V)bx@rCghzp-=;#(K|s@NOO*IZA)NzB23n8Oyp`N z6Y_)!pjq5GpOl;|9mspLVAjuk4Swf>dB>Z+oWGfksTiJHt6LL8{)`TN&}5mlo&S@f zn?k$j;4E88b8ms}U06xznINvR%znonws$*X0nXu~KR;D&0=; zq1MxLBj~1VFmZ3_rpJ&0B|edG0LL4z$TA%JtOE-~IHfCXompV+wy z8-&6rt-RaR;6BG2HZ5IoYkQ!W1K80!*5H1C5|T&@US7!VmLWU9nG%2IR0sf%g(q;p zir%R2#OCiM-FRbfu?u|_l)-Q7I{}F_K#B)nXF9wXSLm-9xO`&}clEL58GaMK6`1Uo zQKob~3zs=o{h-kD;27bhfCkdw{8=X?mD$rB(iIfJLV2z}Inma$btemM>{3VY_dH`c zRmH*W_;0{4Bi*0y!=kq3gCg}!KzsqQv(?<&2%Y|52_E_JZZE7axCF6;pWKz-h9;(1 zFEg|lBDp{TkLtU9pc8X{8!)$h;lT}wYiX`cFvH{sCC$IJ1nrkGsX1R-c54t zLc9jBHVaK(PZqQAK)*w|rQxaCi@4yDsR;BKp_0+QMY4^V@oQdty=y?g5jigp7$EqZ zjDUR~x@7qfAlguTFi<0JZx{E(?05$3ZrE!(`+7JwC(6-O)0zPfL-;9#k~GMZLtGy?nM#)>2+T`kNj ze-Cd%!Vd{3rx0cOIo+1L-plN7F!@)*0?vWum?{xsvwILKF<=UycOWzqNrt^1DAHo{ z&>l4+Ab^}}aY{#leq4;cq6#<-V$Ho7UKVZ81@Wh+CFOY)SxBEZUOMd5^n&4mJBI5y zhiL&%RP$EK=dU%dsx>v_%dKWSAnH{~OU>To6_twC8@+RTFwOV zjN#5sZh{G`WWFrn$+vV8xa_EdxGegTh$iG5fdf8|IkR2eF_u{^F!2%tv7EYty{ytY zfTzxF4)ngPoP_WTG|Fer08u&Q$%>o}_7yWw_VUke{^I-nDIPLL`#{~ep5)0hW*8ez z$=vvIc7ys0bTt^Z4cC$pSAr8jP+)*}S0n5;J4~41b{%cIM*fv_$1_a{7~CzEGF*%a zmo!~DyV(mH=a!>N6aTXY|l>8fd_G+w#(nF|q5jcLBA z13?#dl>PPCA}RNzqD6oVO(@OKym{I-Pa5JmLRwqW$FBiUBnL+P2)@~J(ec|s_sm!R2@$OKicGYN*2GqU(J&T z{Lqn)*=vxuAX1Gv0Dk!C`pCTtlDrGq_gKcHI?^jian>rS^UL?G0{-ilaNK#DTyw56 z{Mo5FbQ?Hew~5Kllovle5o!-n7?EA%~9 z%jQnBip8H@%a9KGo;gZW59-6s%P>_Y62@fk&z9tt_3vec<8wZNl}y-DPVJOG|Iin_ z626Fx(_8z21@R?Y6h3=m$wyZ(m0~u^gGm$C_>_E9bIWd}w}}Fi6`vO0&SEgSdVWB! z70oGSTwI5)%Dq)n3w0Upp_=|g;_;3OZw=}>WJUsdX*M=A4EsAwYD>0ZPrKc^Y`%(P zR4QJgyJNu4aNup&3279U6_ zdbsfLmw#jb+-(ai0SJf=$M4ESh--^XS307Zgwt`pJ8{}aNm%u@LRcdGx zw~H)F7#NIpX{7#kW5V(1H5 zz5AdL#5;!Xs~elu2h{fX{pR6_V=3+&^ruJ{iTx$`s^O_)RYD@?{ol+}(o43PDCFcy z>6@z&ig(9lnQ&Je#^YG*qG0nV5izc-nDi1Oya!vptC5L&xq!LbWas62!Jk9@Hgg$u zcf|NzytpAfC_?Eo)ZG&ywyD+)KyrtAk@F|5=o#Mda4t2W8yW1la)U@5zE9jn2t8L( zX81%5B2%>F4iIQQ*!=|^;t?PSN?@8gFwrSJ@S3$#y8xt&xUbuD-u=7}9#eLWR72-qTT@xu+BTcA6}iClYMq3D|3PS&w~_olnHK zbbUG}X3XIIUV2VpcbYSqR^lWK`E;G4pb|N_JYdhO-P9g;3Pq zx#XGZHE!5Xc?m~}&3$AbIXJZLI=xQV><&VT5CXbQ&*Kz10ue(bo$2A61QOcN*>`p;EOKRNXLPtn*{8w3F-Cleb(>;Dq;Q;C(4 zd?J7xq=(1C&}V+H(IjuWE!QWIPhSF^7YZk!fUfOIo+QzqwU^5k7P>3Y8U%-;?GA!O zHYcntF5ohIP^By2K2uO|W-gA~czK@O*61M(U{K*rXX`j+=FR!L5*bC z8%ZNoC}V;XL!Kpb>sP)JkSj_sf;rwMx2$<+g%bK77T7~8tSw-VD@GV=JA)2g5Hs@& zN(X^2sMAj;J;5fpbBvQ$s%Wr@mKo`t|+60qbQv%_fRc(1N8*2fDS zc~Y)?i3pyo`Y`?2GK=TmHMB1Sk?@)-KhzR}Oj=qWo(Ut-uUx}_lC%xNatZzBfmEBJ zSB2ILfPtS-VxP5RivoeD?|F1}MKFC}S2DXwe+>&i*)@^(pNc<0Ylm@t;ENoizkQkG z#jnpbKyf#qNVcsT*VPwT{GWW9AfDFmg(z^eN2;&JR3~wRYIg?8~`b z6w+Q}ETeZ#j>1Z?z5425VK$AnXI=J;)o?YW1AC@*n=7rc0xy8rmLo~Jcb!bgn3ceG zv1@S2g~rpP*}ia;hD~CRV%Kn2XA_Ux$o_4-22CZ*sM5r!eGy6Peeyw==5WHgAUBr! zfvRYibkq^Pj~pB0`BIi)Xx#xu3H)+%OM`sS+HY@3+2tFUh{#~*CgyA#2A6>lqfn z6S5O{6{Wk3D3`MS+HG^VfwulGBaN;h`#huNIg<4%zjQE;0edb^GBt_26eM9Eg~2<= z%x&8wNd;sz2J(b`T`Vn+b%GZu!pg_&@u44I_b|jc_M^Ast*GX% z~cER`C{E`DzN*%y4r>@ti4A$Le2~6EEK|BE&%nFopIQQ zN!-D9pX<=ija}?3M}Wur)SnR4!Q^=N{TZI>K-5OX+PuZ@ecEdP)O|3 z;Z49IgbEtgSJg(*(Aa^$Aoi=5ZV6^_E4HzP)mn?bbRzqSk-Q@}P! zU^@l7uS{R0FQ1#*uh%#!jP+VDBI7|deK+xz-o;cMwsFQa_N6oU`m|HL^uTLD=QXI? zqFiDND9*>fT!W9Zuh{5;R})jH-(6Au;dQ~kD`bIM)20??E{+DjC_(m7K9a=~L+3%m zmtNX7LSUw(wb78YdD4gQYKDwb0w6BK=Xyc%RRPAvWSvJs>w0h2R385!%w)PxhWr&M01bMie zx>a1ez2u_4;Q$qR#^a%(z`bD;W}PcbW;gZp$;XJ(jj16;20aY3xp5(V_)^EWM`}Gr zK#ADYB0DVWY&9JP_oH)FDL~K(Y0HNT%jo5+7MAC6`q*B*BqP)IfOA zSs1}p4ht#5?g87B?XYTl`HxLvWh($kg4e|Fz2Zvohr;hXR?n)(=s&V%ugp%$J_YTVFooJk<#&j9b704}aM+b!QM* zY2B{6NUDF@2GpzM?B-{6Ghg#rk|qw*Qr=FO%CA^HN`cxwni?*?^I8;o%^2I|#b!@H z!~kFZVrVLm*xR}zG$0!nJB)j{!+gufR3EieNl0$mvb9e%%PXc-huMH^XTw*p?1 zYyBDhW(uaF%N2hMyCTWakzvUi@hY_+R8p{u`b*vcrP^U z_*g|+yWK|d2olI`sQ^ThBwo*25*7;P@yH3tB(f9HU$-isz0RnuWHIEzUyNIb?n@Re zv$Du(b|ul3b3Fq0U>?6%DxBrqHZ@M!(Q9Sr<$XXSD&RZR=lmi8#WaVOpR03FJ!gJX7}xq)vi!L65L~h`COI7w7PQN!xMG^TmKZsOTAK%u z#7EYSymBa>Y&`4@Ffm&lxog|JGhG>BPx$u;Ig zhanra)@5TBV{@8(le)od=MZScTHK2=8cikHIuNW>^0PQLiQ-@U95r?P0sc?spnX8XB-Fwp8ZN9nk*gQNY==j2)0kCP> zDS3wH9LV%ani_3bU2|xy#zAU$rwL<`uAe~6y>{(&G8kQVUiZh>m`rur~bZ0XVL~QQ(q<_ClM)5o8+`+95hA?X0lOj&2f6?i%}xEm~y3R zZA1w3h^*;MJ*GFdRrP9o(a}EeSy$0MRB1H>ND#EI?o(ILX|D1yXsML7Jz;PiQelZ+ zp!i9t0BZQ}Y0c!zH|4A21GdDR7i)Cpg{XY}^=@lm1vWb9>y^p4F^Fj{5|XH~U(`1y zf0U&kUb4c0uQ(#`!MNRwE;%*DP}`saRhM}Q@8)WSInEKkDq_N)ih@A^4cDIuzpTR1 zg1^TRqQx;vVRq~}7XnA(a3&`_p-X}Rp+M!R82&a9yRuU2)qbcH!*(OuBG-ZxL$7^3 zk&b$I^~5I@OdQRRR`nvwa|Z8Ax*#R#RSH|9#$u7?>1oDhG*RHFDlwSr4bi&61QLwz zDLzl|vh{cbR+{+2Riced&uLkYy9`dK_ScE8u`N&ueqg2cUruA%=)P)#35CF58vwV> zIFPBlmMmvWShXzwjAC;X9Q9dnE`&F@@U8Utn=nx1ySEfLX(0((;LiiMhO*{o z332vyIVs;A+_1A?y(oW|?Fl2oUa(^_iON_+oYqiYgd}-iq2eyFl8e*2C7b|Q$7#)w zm1s2=sH^Fdv2u>d+BWU{?4KqFr-5CP>KbEH1xpYDVVij6M-c8AG=ym^@?d!I(P`9u z(W@77VDq{wy0<#R`)C@Tr;x*YPD61$^u=U&KnFrtLk+}c7XYQ}!}&%5t49-o8#I6j z8$BWc@|_PmISg)MZFq}`=(Tu&Y0*gn=!zUT%R6}HnzGC1I3zr#o#GHqMQG@>OzQj7okNAF z(psjhjkl6sE-6TI^GhnVg0K&Qnd~;28l$D{!$=pSZL9m)_hz5f__8{k;McQxsl7yL zoV4+ZL@DetHhsB+u&|Sr*#=j%+t!eitu!F$RMK>tLL_&GeKR_!oe^eQ=FnS3U9fs4 zI?FrCXlH>RT``+eW}G!(+Yec7JR&Y?WJi( zmoa%r*|6?kWI2MyMWFR&UR94W?=gsTJxJ}_*g_YkdUWL!owBrj-lX=Hx;)8+BIbFr zftcCqOWQ7{96mH7cGBrD==xgg7+$j^gyKT_a)O9QZ?{T>TX!jrkd>J#Cm|;2;tO2| z=43{SY5NJhTQKQ*&oeNy$u#WO!de&b$r+usOzH|f+vA&o_9PCcYXVad((7s>b=O!Z zxvTY)LL%1i&SDV@+C7(o`!I)3_ln}{m?q?=Y~@fKh>zj!lY5>N_O3$Ml2U5KPx+(7 zN0LYrf4JaN?NRvbXSVht{+PCc8`(XyfG??_f2D8e;jKH>`WI|T!;WbjqP9zrm*ZR7KW`bM%aMZ4>;lijsSslVlc+pT}&WfxFuQSMv0}uM1%mqJA$7GWa z6pIIode$f6LrBHlm1tMmunGE`=P4W`HIGYvT#t8kYINF0AA{{c=jGrCMA7YO`<&7m znPRW=3T+R(iyAEZD5LAgt+0a^)JQ95Y} zArV<65fxQBr;(Bl?f2HlYs0 ziGdJ%;O|#epl^W;RG_kRG@~>7OHhi=$l8MLJ1b@ZM>7{2pdviba?Qm47dPlXx4gn5 zAS((u#k2^#&-gl#^es}6f5-WyC+g41pS(8g(F7)M06uYiwe0*BfoQ)={+9!*<1+zM zpe4zFKtG#={Y zWh|VWfPQ@cp#n$BpCHi$Fq3A1NJ*f0`j5@bc=iX#zgcbujwXNJ%$8|Sv|Ql8_W^R* zf9Tq6-~sy2ga7Yw^MCDC&}KYbVj#*CIDmc}rk9j|j8g*IG1;2^%l?~tkPAUa! zoPSK-#rj{#|LUpVSk(V~Fn@15{M8crTjX;6d-DGbxPRIH@BK7?9A#=eKOijruWrUa zH|Ben#;-;|-(p?xH>CfwTj$T*@7>LQyk=br|G@pFquD<@LjKJ8-uCLNSK7B=k^Fbg zA3CS~4E^4B>8qpGw|FJ}1N48^U;fBn>u1XM)-XTrI(OM$QvTNt=KtpC^fUK+i;S=aQLge^)V~~G-zzMBoxuDS=O(|*`v;1gKX3c@GJ`*k za60qfF#ev4`Df+EpE=)Gb$=Bt{1(v`f5!Qj&icO6_{Yu)@%|;?4@$*8G>EADkeqE{m7WL`BO#91q`=2-V`_;N1uP(+}zs&l(<<*~)e?RN~b;0jj z5a;|l`5!F*{S5hjw(!SY+EDOI$ls&#chmVlGroU@`a19UEsRQj$M}a?NO>s;-~$;5 R2np~f1o-$>Q}y+){|A@R9n$~+ literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..df6a6ad --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,9 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip +networkTimeout=10000 +retries=0 +retryBackOffMs=500 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..b9bb139 --- /dev/null +++ b/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# 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 +# +# https://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. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..24c62d5 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,82 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..0beebd9 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,8 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { url = 'https://repo.papermc.io/repository/maven-public/' } + } +} + +rootProject.name = 'AsminVoicechat' diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/BukkitVoicechatService.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/BukkitVoicechatService.java new file mode 100644 index 0000000..9667d1f --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/BukkitVoicechatService.java @@ -0,0 +1,12 @@ +package de.maxhenkel.voicechat.api; + +public interface BukkitVoicechatService { + + /** + * Registers the voice chat plugin on bukkit based servers. + * + * @param plugin the voicechat plugin + */ + void registerPlugin(VoicechatPlugin plugin); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/ClientVoicechatSocket.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/ClientVoicechatSocket.java new file mode 100644 index 0000000..7192210 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/ClientVoicechatSocket.java @@ -0,0 +1,21 @@ +package de.maxhenkel.voicechat.api; + +import java.net.SocketAddress; + +/** + * A socket used for client side voice chat traffic. + * Can be set using {@link de.maxhenkel.voicechat.api.events.ClientVoicechatInitializationEvent#setSocketImplementation(ClientVoicechatSocket)}. + */ +public interface ClientVoicechatSocket { + + void open() throws Exception; + + RawUdpPacket read() throws Exception; + + void send(byte[] data, SocketAddress address) throws Exception; + + void close(); + + boolean isClosed(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/Entity.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/Entity.java new file mode 100644 index 0000000..669cf42 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/Entity.java @@ -0,0 +1,22 @@ +package de.maxhenkel.voicechat.api; + +import java.util.UUID; + +public interface Entity { + + /** + * @return the UUID of the entity + */ + UUID getUuid(); + + /** + * @return the actual entity object + */ + Object getEntity(); + + /** + * @return the current position of the entity + */ + Position getPosition(); + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/api/ForgeVoicechatPlugin.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/ForgeVoicechatPlugin.java similarity index 67% rename from source/decompiled/de/maxhenkel/voicechat/api/ForgeVoicechatPlugin.java rename to source/api/src/main/java/de/maxhenkel/voicechat/api/ForgeVoicechatPlugin.java index 3c66d36..4ada9f6 100644 --- a/source/decompiled/de/maxhenkel/voicechat/api/ForgeVoicechatPlugin.java +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/ForgeVoicechatPlugin.java @@ -1,12 +1,8 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.api; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -@Retention(value=RetentionPolicy.RUNTIME) +@Retention(RetentionPolicy.RUNTIME) public @interface ForgeVoicechatPlugin { } - diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/Group.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/Group.java new file mode 100644 index 0000000..105e966 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/Group.java @@ -0,0 +1,115 @@ +package de.maxhenkel.voicechat.api; + +import javax.annotation.Nullable; +import java.util.UUID; + +/** + * Groups can be created using {@link VoicechatServerApi#groupBuilder()}. + */ +public interface Group { + + /** + * @return the visual name of the group + */ + String getName(); + + /** + * @return if the group has a password + */ + boolean hasPassword(); + + /** + * @return the ID of the group + */ + UUID getId(); + + /** + * @return if the group is persistent + */ + boolean isPersistent(); + + /** + * @return if the group is hidden in the group list UI + */ + boolean isHidden(); + + /** + * @return the group type + */ + Type getType(); + + public interface Type { + + /** + * Players in a group can hear nearby players that are not in a group + */ + public static final Type NORMAL = new Type() { + }; + + /** + * Players in a group can hear nearby players and nearby players can hear players in the group + */ + public static final Type OPEN = new Type() { + }; + + /** + * Players in a group can only hear other players in the group + */ + public static final Type ISOLATED = new Type() { + }; + } + + public interface Builder { + + /** + * Sets the ID of the group. + * If this is not set, the ID will be randomly generated. + *
+ * NOTE: If there is already a group with the same ID, the group will be overwritten. + * + * @param id the group ID or null if the ID should be randomly generated + * @return the builder + */ + Builder setId(@Nullable UUID id); + + /** + * NOTE: The name might be stripped of special characters and whitespace. + * + * @param name the name of the group + * @return the builder + */ + Builder setName(String name); + + /** + * @param password the group password + * @return the builder + */ + Builder setPassword(@Nullable String password); + + /** + * @param persistent if the group should be persistent + * @return the builder + */ + Builder setPersistent(boolean persistent); + + /** + * @param hidden if the group should be hidden in the group list UI + * @return the builder + */ + Builder setHidden(boolean hidden); + + /** + * @param type the group type + * @return the builder + */ + Builder setType(Type type); + + /** + * @return the built group + * @throws IllegalStateException if the name is not set or invalid + */ + Group build(); + + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/Player.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/Player.java new file mode 100644 index 0000000..686fe2c --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/Player.java @@ -0,0 +1,10 @@ +package de.maxhenkel.voicechat.api; + +public interface Player extends Entity { + + /** + * @return the actual player object + */ + Object getPlayer(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/Position.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/Position.java new file mode 100644 index 0000000..b59d6ea --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/Position.java @@ -0,0 +1,20 @@ +package de.maxhenkel.voicechat.api; + +public interface Position { + + /** + * @return the X position + */ + double getX(); + + /** + * @return the Y position + */ + double getY(); + + /** + * @return the Z position + */ + double getZ(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/RawUdpPacket.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/RawUdpPacket.java new file mode 100644 index 0000000..4866639 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/RawUdpPacket.java @@ -0,0 +1,13 @@ +package de.maxhenkel.voicechat.api; + +import java.net.SocketAddress; + +public interface RawUdpPacket { + + byte[] getData(); + + long getTimestamp(); + + SocketAddress getSocketAddress(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/ServerLevel.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/ServerLevel.java new file mode 100644 index 0000000..6cf21f3 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/ServerLevel.java @@ -0,0 +1,10 @@ +package de.maxhenkel.voicechat.api; + +public interface ServerLevel { + + /** + * @return the actual level object + */ + Object getServerLevel(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/ServerPlayer.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/ServerPlayer.java new file mode 100644 index 0000000..d0ef08b --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/ServerPlayer.java @@ -0,0 +1,10 @@ +package de.maxhenkel.voicechat.api; + +public interface ServerPlayer extends Player { + + /** + * @return the level of the player + */ + ServerLevel getServerLevel(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatApi.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatApi.java new file mode 100644 index 0000000..9c17758 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatApi.java @@ -0,0 +1,116 @@ +package de.maxhenkel.voicechat.api; + +import de.maxhenkel.voicechat.api.audio.AudioConverter; +import de.maxhenkel.voicechat.api.mp3.Mp3Decoder; +import de.maxhenkel.voicechat.api.mp3.Mp3Encoder; +import de.maxhenkel.voicechat.api.opus.OpusDecoder; +import de.maxhenkel.voicechat.api.opus.OpusEncoder; +import de.maxhenkel.voicechat.api.opus.OpusEncoderMode; + +import javax.annotation.Nullable; +import javax.sound.sampled.AudioFormat; +import java.io.InputStream; +import java.io.OutputStream; + +public interface VoicechatApi { + + /** + * Creates a new opus encoder. + * Note that the encoder needs to be closed after you are finished using it. + */ + OpusEncoder createEncoder(); + + /** + * Creates a new opus encoder. + * Note that the encoder needs to be closed after you are finished using it. + * + * @param mode the opus encoder mode + * @return the opus encoder + */ + OpusEncoder createEncoder(OpusEncoderMode mode); + + /** + * Creates a new opus decoder. + * Note that the decoder needs to be closed after you are finished using it. + * + * @return the opus decoder + */ + OpusDecoder createDecoder(); + + /** + * NOTE: This is not available for Bukkit! It will always return null. + * + * @param audioFormat the audio format + * @param bitrate the bitrate in kbps + * @param quality the quality from 0 (highest) to 9 (lowest) + * @param outputStream the output stream to write the mp3 to + * @return the mp3 encoder or null if the encoder could not be initialized or is not available + */ + @Nullable + Mp3Encoder createMp3Encoder(AudioFormat audioFormat, int bitrate, int quality, OutputStream outputStream); + + /** + * NOTE: This is not available for Bukkit! It will always return null. + * + * @param inputStream the input stream to read the mp3 from + * @return the mp3 decoder or null if the decoder could not be initialized or is not available + */ + @Nullable + Mp3Decoder createMp3Decoder(InputStream inputStream); + + /** + * @return the audio converter + */ + AudioConverter getAudioConverter(); + + /** + * Creates an entity object from an actual entity. + * + * @param entity the entity implementation of your mod/plugin loader + * @return the entity object + */ + Entity fromEntity(Object entity); + + /** + * Creates a level object from an actual level. + * + * @param serverLevel the level implementation of your mod/plugin loader + * @return the level + */ + ServerLevel fromServerLevel(Object serverLevel); + + /** + * Creates a player object from an actual player. + * + * @param serverPlayer the player implementation of your mod/plugin loader + * @return the player + */ + ServerPlayer fromServerPlayer(Object serverPlayer); + + /** + * Creates a new position object. + * + * @param x the X position + * @param y the Y position + * @param z the Z position + * @return the position with the provided coordinates + */ + Position createPosition(double x, double y, double z); + + /** + * Don't forget to register your category with {@link VoicechatServerApi#registerVolumeCategory(VolumeCategory)} or {@link VoicechatClientApi#registerClientVolumeCategory(VolumeCategory)} + * + * @return a builder to build a category + */ + VolumeCategory.Builder volumeCategoryBuilder(); + + /** + * NOTE: Voice chat plugins can change this. + * This is only the default value. + * This value might not be correct if you are not connected to a server. + * + * @return the default distance, audio from voice chat is heard from + */ + double getVoiceChatDistance(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatClientApi.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatClientApi.java new file mode 100644 index 0000000..ba9f48a --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatClientApi.java @@ -0,0 +1,166 @@ +package de.maxhenkel.voicechat.api; + +import de.maxhenkel.voicechat.api.audiochannel.ClientEntityAudioChannel; +import de.maxhenkel.voicechat.api.audiochannel.ClientLocationalAudioChannel; +import de.maxhenkel.voicechat.api.audiochannel.ClientStaticAudioChannel; +import de.maxhenkel.voicechat.api.config.ConfigAccessor; +import de.maxhenkel.voicechat.api.config.VolumeConfigAccessor; + +import javax.annotation.Nullable; +import java.util.UUID; + +public interface VoicechatClientApi extends VoicechatApi { + + /** + * @return if the local voice chat is muted + */ + boolean isMuted(); + + /** + * Does the same as {@link #isDisabled(UUID)} with null as the player UUID. + * + * @return if the local voice chat is disabled + */ + default boolean isDisabled() { + return isDisabled(null); + } + + /** + * @param playerId the UUID of the player or null for the local player + * @return if the player with the provided UUID has the voice chat disabled + */ + boolean isDisabled(@Nullable UUID playerId); + + /** + * Does the same as {@link #isDisconnected(UUID)} with null as the player UUID. + * + * @return if the voice chat is disconnected from the server + */ + default boolean isDisconnected() { + return isDisconnected(null); + } + + /** + * @param playerId the UUID of the player or null for the local player + * @return if the player with the provided UUID is disconnected from voice chat + */ + boolean isDisconnected(@Nullable UUID playerId); + + /** + * Does the same as {@link #isTalking(UUID)} with null as the player UUID. + * + * @return if the local player is talking + */ + default boolean isTalking() { + return isTalking(null); + } + + /** + * @param playerId the UUID of the player or null for the local player + * @return if the player with the provided UUID is currently talking + */ + boolean isTalking(@Nullable UUID playerId); + + /** + * Does the same as {@link #isWhispering(UUID)} with null as the player UUID. + * + * @return if the local player is whispering + */ + default boolean isWhispering() { + return isWhispering(null); + } + + /** + * @param playerId the UUID of the player or null for the local player + * @return if the player with the provided UUID is currently whispering + */ + boolean isWhispering(@Nullable UUID playerId); + + /** + * This method returns if the push to talk key is pressed, even when using voice activation. + * + * @return if the push to talk key is pressed + */ + boolean isPushToTalkKeyPressed(); + + /** + * @return if the whisper key is pressed + */ + boolean isWhisperKeyPressed(); + + @Nullable + Group getGroup(); + + /** + * Creates a client side entity audio channel. + * + * @param uuid the UUID of the entity + * @return the audio channel + * @deprecated use {@link #createEntityAudioChannel(UUID, Entity)} + */ + @Deprecated + ClientEntityAudioChannel createEntityAudioChannel(UUID uuid); + + /** + * Creates a client side entity audio channel. + * + * @param uuid the ID of the channel + * @param entity the entity to attach the channel to + * @return the audio channel + */ + ClientEntityAudioChannel createEntityAudioChannel(UUID uuid, Entity entity); + + /** + * Creates a client side locational audio channel. + * + * @param uuid the ID of the channel + * @return the audio channel + */ + ClientLocationalAudioChannel createLocationalAudioChannel(UUID uuid, Position position); + + /** + * Creates a client side static audio channel. + * + * @param uuid the ID of the channel + * @return the audio channel + */ + ClientStaticAudioChannel createStaticAudioChannel(UUID uuid); + + /** + * Registers a volume category just for this client. + * A category can be created with {@link VoicechatApi#volumeCategoryBuilder()}. + * The category can be unregistered with {@link #unregisterClientVolumeCategory}. + * + * @param category the category to register + */ + void registerClientVolumeCategory(VolumeCategory category); + + /** + * Unregisters a category on this client. + * This will release the texture ID for the icon if one exists. + * + * @param category the category to remove + */ + default void unregisterClientVolumeCategory(VolumeCategory category) { + unregisterClientVolumeCategory(category.getId()); + } + + /** + * Unregisters a category on this client. + * This will release the texture ID for the icon if one exists. + * + * @param categoryId the category ID to remove + */ + void unregisterClientVolumeCategory(String categoryId); + + /** + * @return a read-only config accessor for the mods client config + */ + ConfigAccessor getClientConfig(); + + /** + * @return a read-only accessor for player and category volumes + */ + VolumeConfigAccessor getVolumeConfig(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatConnection.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatConnection.java new file mode 100644 index 0000000..241aa7c --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatConnection.java @@ -0,0 +1,80 @@ +package de.maxhenkel.voicechat.api; + +import javax.annotation.Nullable; + +/** + * Note: It is not guaranteed that the state of this connection object is up to date. + * Please re-fetch the connection object to get the latest state. + */ +public interface VoicechatConnection { + + /** + * Note: This only returns the group the player was in when fetching this connection object. + * Calling {@link #setGroup(Group)} won't update the return value of this method. + * + * @return the group of the player - null if the player is not in a group + */ + @Nullable + Group getGroup(); + + /** + * Note: This only returns if the player was in a group when fetching this connection object. + * Calling {@link #setGroup(Group)} won't update the return value of this method. + * + * @return if the player is in a group + */ + boolean isInGroup(); + + /** + * Joins this player to the provided group. + * + * @param group the group to join or null to leave the current group + */ + void setGroup(@Nullable Group group); + + /** + * This might not represent the actual state of the voice chat connection, since other voice chat plugins can fake having a player connected. + *
+ * Note: This only returns if the player was connected fetching this connection object. + * Calling {@link #setConnected(boolean)} won't update the return value of this method. + * + * @return if the player is connected to voice chat + */ + boolean isConnected(); + + /** + * The players disconnected state will reset if its actual disconnected state changes or if the player reconnects. + *
+ * NOTE: This method will only work for players that don't have the mod installed. See {@link #isInstalled()}. + * + * @param connected if the player should be shown as connected to voice chat + */ + void setConnected(boolean connected); + + /** + * Note: This only returns if the player has the voice chat disabled when fetching this connection object. + * Calling {@link #setDisabled(boolean)} won't update the return value of this method. + * + * @return If the player muted the sound + */ + boolean isDisabled(); + + /** + * Sets the players disabled state. + * NOTE: This method will only work for players that don't have the mod installed. See {@link #isInstalled()}. + * + * @param disabled if the player should have the voice chat disabled icon + */ + void setDisabled(boolean disabled); + + /** + * @return if the player has a version of voice chat installed that is compatible with the server + */ + boolean isInstalled(); + + /** + * @return the player + */ + ServerPlayer getPlayer(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatPlugin.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatPlugin.java new file mode 100644 index 0000000..9dc77a8 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatPlugin.java @@ -0,0 +1,26 @@ +package de.maxhenkel.voicechat.api; + +import de.maxhenkel.voicechat.api.events.EventRegistration; + +public interface VoicechatPlugin { + + /** + * @return the ID of this plugin - Has to be unique + */ + String getPluginId(); + + /** + * Called after loading the plugin. + */ + default void initialize(VoicechatApi api) { + } + + /** + * Register your events here - Only here! + * + * @param registration the event registration object, used to register events + */ + default void registerEvents(EventRegistration registration) { + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatServerApi.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatServerApi.java new file mode 100644 index 0000000..02ddac4 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatServerApi.java @@ -0,0 +1,343 @@ +package de.maxhenkel.voicechat.api; + +import de.maxhenkel.voicechat.api.audiochannel.*; +import de.maxhenkel.voicechat.api.audiolistener.AudioListener; +import de.maxhenkel.voicechat.api.audiolistener.PlayerAudioListener; +import de.maxhenkel.voicechat.api.audiosender.AudioSender; +import de.maxhenkel.voicechat.api.config.ConfigAccessor; +import de.maxhenkel.voicechat.api.opus.OpusEncoder; +import de.maxhenkel.voicechat.api.packets.ConvertablePacket; +import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; +import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; +import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.UUID; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public interface VoicechatServerApi extends VoicechatApi { + + /** + * Sends the sound packet to the provided connection. + * + * @param connection the connection to send the packet to + * @param packet the packet to send + */ + void sendEntitySoundPacketTo(VoicechatConnection connection, EntitySoundPacket packet); + + /** + * Sends the sound packet to the provided connection. + * + * @param connection the connection to send the packet to + * @param packet the packet to send + */ + void sendLocationalSoundPacketTo(VoicechatConnection connection, LocationalSoundPacket packet); + + /** + * Sends the sound packet to the provided connection. + * + * @param connection the connection to send the packet to + * @param packet the packet to send + */ + void sendStaticSoundPacketTo(VoicechatConnection connection, StaticSoundPacket packet); + + /** + * Creates a sound packet that can be converted to any type. + * NOTE: When creating a packet using this method, the sequence number must be set manually using {@link de.maxhenkel.voicechat.api.packets.SoundPacket.Builder#sequenceNumber(long)}. + * + * @return a convertable packet without any data + */ + ConvertablePacket createPacket(); + + /** + * Creates a sound channel for the specified entity. + * + * @param channelId the ID of the channel - Has to be unique + * @param entity the entity to attach the channel to + * @return the channel + */ + @Nullable + EntityAudioChannel createEntityAudioChannel(UUID channelId, Entity entity); + + /** + * Creates a sound channel at the provided location. + * + * @param channelId the ID of the channel - Has to be unique + * @param level the world + * @param initialPosition the position where the sound should be played + * @return the channel + */ + @Nullable + LocationalAudioChannel createLocationalAudioChannel(UUID channelId, ServerLevel level, Position initialPosition); + + /** + * Creates a static audio channel. + * + * @param channelId the ID of the channel - Has to be unique + * @param level the level + * @param connection the connection that should hear the audio + * @return the channel + * @deprecated use {@link #createStaticAudioChannel(UUID)} and add a target using {@link StaticAudioChannel#addTarget(VoicechatConnection)} + */ + @Deprecated + @Nullable + StaticAudioChannel createStaticAudioChannel(UUID channelId, ServerLevel level, VoicechatConnection connection); + + /** + * Creates a static audio channel. + * + * @param channelId the ID of the channel - Has to be unique + * @return the channel + */ + @Nullable + StaticAudioChannel createStaticAudioChannel(UUID channelId); + + /** + * Creates a new audio player. + *
+ *
+ * NOTE: Never use more than one audio player for every audio channel. + * + * @param audioChannel the channel where the audio player should send the audio to + * @param encoder the opus encoder used to encode the audio data + * @param audioSupplier this gets called whenever a new audio frame needs to be sent. The size of the array always needs to be 960. To end the playback, return null + * @return the audio player + */ + AudioPlayer createAudioPlayer(AudioChannel audioChannel, OpusEncoder encoder, Supplier audioSupplier); + + /** + * Creates a new audio player. + *
+ *
+ * NOTE: Never use more than one audio player for every audio channel. + * + * @param audioChannel the channel where the audio player should send the audio to + * @param encoder the opus encoder used to encode the audio data + * @param audio the audio data + * @return the audio player + */ + AudioPlayer createAudioPlayer(AudioChannel audioChannel, OpusEncoder encoder, short[] audio); + + /** + * Creates a new audio sender. + *
+ * This can be used to simulate a player sending microphone packets. + * This needs to be registered using {@link #registerAudioSender(AudioSender)} and unregistered using {@link #unregisterAudioSender(AudioSender)}. + * + * @param connection the connection of the player + * @return the audio sender + */ + AudioSender createAudioSender(VoicechatConnection connection); + + /** + * NOTE: Only one instance of this can exist per player. This will return false if an audio sender for this player already exists. + *
+ * NOTE: The audio sender will only work for players that are connected to the server and don't have the mod installed. Otherwise, it will return false. + * + * @param sender the sender to register + * @return if the sender was registered + */ + boolean registerAudioSender(AudioSender sender); + + /** + * Unregisters an audio sender. + * + * @param sender the sender to unregister + * @return false if the audio sender was not registered. + */ + boolean unregisterAudioSender(AudioSender sender); + + /** + * @return a {@link PlayerAudioListener} builder + */ + PlayerAudioListener.Builder playerAudioListenerBuilder(); + + /** + * Registers a new {@link AudioListener}. + *
+ * Returns false if the listener is already registered. + * + * @param listener the listener to register + * @return if the listener was registered + */ + boolean registerAudioListener(AudioListener listener); + + /** + * Unregisters an {@link AudioListener}. + *
+ * Returns false if the listener is already unregistered. + * + * @param listener the listener to unregister + * @return if the listener was unregistered + */ + boolean unregisterAudioListener(AudioListener listener); + + /** + * Unregisters an {@link AudioListener}. + *
+ * Returns false if the listener is already unregistered. + * + * @param listenerId the {@link AudioListener#getListenerId()} of the listener to unregister + * @return if the listener was unregistered + */ + boolean unregisterAudioListener(UUID listenerId); + + /** + * Gets the connection of the player with this UUID. + * + * @param playerUuid the players UUID + * @return the connection or null if the player is not connected + */ + @Nullable + VoicechatConnection getConnectionOf(UUID playerUuid); + + /** + * Gets the connection of the player. + * + * @param player the player + * @return the connection or null if the player is not connected + */ + @Nullable + default VoicechatConnection getConnectionOf(ServerPlayer player) { + return getConnectionOf(player.getUuid()); + } + + /** + * Creates a new group. + * + * @param name the name of the group + * @param password the password of the group - null for no password + * @return the group + * @deprecated use {@link #groupBuilder()} instead + */ + @Deprecated + Group createGroup(String name, @Nullable String password); + + /** + * Creates a new group. + * + * @param name the name of the group + * @param password the password of the group - null for no password + * @param persistent if the group should be persistent + * @return the group + * @deprecated use {@link #groupBuilder()} instead + */ + @Deprecated + Group createGroup(String name, @Nullable String password, boolean persistent); + + /** + * @return a new group builder + */ + Group.Builder groupBuilder(); + + /** + * Removes a persistent group. + * + * NOTE: You can't remove a group that is not persistent or has players in it. + * + * @param groupId the ID of the group + * @return if the group was removed + */ + boolean removeGroup(UUID groupId); + + /** + * Gets a group by its ID. + * + * @param groupId the ID of the group + * @return the group or null if the group doesn't exist + */ + @Nullable + Group getGroup(UUID groupId); + + /** + * @return all groups + */ + Collection getGroups(); + + /** + * Gets the secret for the user with this userId. + * Calling this function with a players UUID, that is already connected, this will return the secret of that player. + * Calling it with a new random UUID this will return a new secret. + * Use this with caution - Keep this secret confidential, as this allows connecting to the voice chat as this person. + * Note that if this userId is a players UUID and this player disconnects, the secret will get removed and thus is no longer valid to connect with. + * + * @param userId the user ID + * @return the secret or null if no server is running + * @deprecated this will just return null + */ + @Nullable + @Deprecated + UUID getSecret(UUID userId); + + /** + * A convenience method to get all players in the range of a specific location. + * + * @param level the world + * @param pos the location + * @param range the range + * @param filter the filter to exclude specific players + * @return all players in the provided location + */ + Collection getPlayersInRange(ServerLevel level, Position pos, double range, Predicate filter); + + /** + * The distance at which audio packets are broadcast. + * NOTE: This is not the distance it can be heard. + * + * @return the maximum distance, voice chat audio packets can be received + */ + double getBroadcastRange(); + + /** + * A convenience method to get all players in the range of a specific location. + * + * @param level the world + * @param pos the location + * @param range the range + * @return all players in the provided location + */ + default Collection getPlayersInRange(ServerLevel level, Position pos, double range) { + return getPlayersInRange(level, pos, range, null); + } + + /** + * Registers a volume category. + * This will get synchronized to all connected clients and all future clients that will connect. + * A category can be created with {@link VoicechatApi#volumeCategoryBuilder()}. + * The category can be unregistered with {@link #unregisterVolumeCategory}. + * + * @param category the category to register + */ + void registerVolumeCategory(VolumeCategory category); + + /** + * Unregisters a category for all connected players. + * This will release the texture ID for the icon if one exists on all clients. + * + * @param category the category to remove + */ + default void unregisterVolumeCategory(VolumeCategory category) { + unregisterVolumeCategory(category.getId()); + } + + /** + * Unregisters a category for all connected players. + * This will release the texture ID for the icon if one exists on all clients. + * + * @param categoryId the category ID to remove + */ + void unregisterVolumeCategory(String categoryId); + + /** + * @return all registered volume categories + */ + Collection getVolumeCategories(); + + /** + * @return a read-only config accessor for the mods server config + */ + ConfigAccessor getServerConfig(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatSocket.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatSocket.java new file mode 100644 index 0000000..e14a003 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/VoicechatSocket.java @@ -0,0 +1,23 @@ +package de.maxhenkel.voicechat.api; + +import java.net.SocketAddress; + +/** + * A socket used for server side voice chat traffic. + * Can be set using {@link de.maxhenkel.voicechat.api.events.VoicechatServerStartingEvent#setSocketImplementation(VoicechatSocket)}. + */ +public interface VoicechatSocket { + + void open(int port, String bindAddress) throws Exception; + + RawUdpPacket read() throws Exception; + + void send(byte[] data, SocketAddress address) throws Exception; + + int getLocalPort(); + + void close(); + + boolean isClosed(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/VolumeCategory.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/VolumeCategory.java new file mode 100644 index 0000000..9950149 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/VolumeCategory.java @@ -0,0 +1,97 @@ +package de.maxhenkel.voicechat.api; + +import javax.annotation.Nullable; + +/** + * A custom volume category for the "adjust volumes screen". + * Create it with {@link VoicechatApi#volumeCategoryBuilder()}. + * Register it with {@link VoicechatServerApi#registerVolumeCategory(VolumeCategory)} or {@link VoicechatClientApi#registerClientVolumeCategory(VolumeCategory)}. + * Unregister it with {@link VoicechatServerApi#unregisterVolumeCategory} or {@link VoicechatClientApi#unregisterClientVolumeCategory}. + */ +public interface VolumeCategory { + + /** + * @return the unique ID of the category + */ + String getId(); + + /** + * @return the full name of the category, that is displayed for the end user + */ + String getName(); + + /** + * @return the translation key for the full name of the category + */ + @Nullable + String getNameTranslationKey(); + + /** + * @return the hover tooltip that is shown for this category + */ + @Nullable + String getDescription(); + + /** + * @return the translation key for the hover tooltip of the category + */ + @Nullable + String getDescriptionTranslationKey(); + + /** + * @return the icon that is shown for this category + */ + @Nullable + int[][] getIcon(); + + public interface Builder { + + /** + * This ID has to be between 1 and 16 characters and can only contain lowercase a-z and _. + * + * @param id the unique ID of the category + * @return the builder + */ + Builder setId(String id); + + /** + * @param name the full name of the category, that is displayed for the end user if no translation is present + * @return the builder + */ + Builder setName(String name); + + /** + * @param translationKey the translation key for the full name of the category + * @return the builder + */ + Builder setNameTranslationKey(@Nullable String translationKey); + + /** + * @param description the hover tooltip that is shown for this category if no translation is present + * @return the builder + */ + Builder setDescription(@Nullable String description); + + /** + * @param translationKey the translation key for the hover tooltip + * @return the builder + */ + Builder setDescriptionTranslationKey(@Nullable String translationKey); + + /** + * The array has to be 16x16. + * Each integer represents a pixel in the RGBA format. + * + * @param icon the icon that is shown for this category + * @return the builder + */ + Builder setIcon(@Nullable int[][] icon); + + /** + * @return the built category + */ + VolumeCategory build(); + + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audio/AudioConverter.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audio/AudioConverter.java new file mode 100644 index 0000000..df19afb --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audio/AudioConverter.java @@ -0,0 +1,27 @@ +package de.maxhenkel.voicechat.api.audio; + +import de.maxhenkel.voicechat.api.VoicechatApi; + +/** + * A utility class to convert audio between different representations. + *
+ * Can be obtained by calling {@link VoicechatApi#getAudioConverter()}. + *
+ *
+ * NOTE: Everything is assumed to be 16 bit PCM audio. + */ +public interface AudioConverter { + + short[] bytesToShorts(byte[] bytes); + + byte[] shortsToBytes(short[] shorts); + + short[] floatsToShorts(float[] floats); + + float[] shortsToFloats(short[] shorts); + + byte[] floatsToBytes(float[] floats); + + float[] bytesToFloats(byte[] bytes); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audio/package-info.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audio/package-info.java new file mode 100644 index 0000000..8379386 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audio/package-info.java @@ -0,0 +1,4 @@ +/** + * Everything related to audio conversion and manipulation. + */ +package de.maxhenkel.voicechat.api.audio; \ No newline at end of file diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/AudioChannel.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/AudioChannel.java new file mode 100644 index 0000000..eaff8e0 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/AudioChannel.java @@ -0,0 +1,65 @@ +package de.maxhenkel.voicechat.api.audiochannel; + +import de.maxhenkel.voicechat.api.ServerPlayer; +import de.maxhenkel.voicechat.api.VolumeCategory; +import de.maxhenkel.voicechat.api.packets.MicrophonePacket; + +import javax.annotation.Nullable; +import java.util.UUID; +import java.util.function.Predicate; + +public interface AudioChannel { + + /** + * Sends the audio data to this audio channel. + * + * @param opusData Opus encoded audio data + */ + void send(byte[] opusData); + + /** + * Forwards the provided microphone packet to this audio channel. + * + * @param packet the microphone packet containing the audio data + */ + void send(MicrophonePacket packet); + + /** + * Applies a filter to the audio channel. + * + * @param filter only sends the data to players where the filter applies + */ + void setFilter(Predicate filter); + + /** + * Call this if you are finished sending data. + * You can still use this audio channel after calling this function, + * just don't call it after every packet, only after you are finished sending data. + */ + void flush(); + + /** + * @return if the audio channel is closed + */ + boolean isClosed(); + + /** + * @return the ID of the audio channel + */ + UUID getId(); + + /** + * @return the category ID of the audio channel + */ + @Nullable + String getCategory(); + + /** + * Make sure you registered your category before using it. + * See {@link de.maxhenkel.voicechat.api.VoicechatServerApi#registerVolumeCategory(VolumeCategory)}. + * + * @param category the category ID of the audio channel + */ + void setCategory(@Nullable String category); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/AudioPlayer.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/AudioPlayer.java new file mode 100644 index 0000000..bddaba0 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/AudioPlayer.java @@ -0,0 +1,39 @@ +package de.maxhenkel.voicechat.api.audiochannel; + +/** + * Streams audio data from the server to clients. + * A player instance can be obtained by calling {@link de.maxhenkel.voicechat.api.VoicechatServerApi#createAudioPlayer}. + */ +public interface AudioPlayer { + + /** + * Starts playing/streaming the audio. + */ + void startPlaying(); + + /** + * Stops playing/streaming the audio. + */ + void stopPlaying(); + + /** + * @return if the player has been started + */ + boolean isStarted(); + + /** + * @return if the audio is still playing + */ + boolean isPlaying(); + + /** + * @return if the player stopped playing + */ + boolean isStopped(); + + /** + * @param onStopped a runnable that's called when the player is finished playing + */ + void setOnStopped(Runnable onStopped); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientAudioChannel.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientAudioChannel.java new file mode 100644 index 0000000..bc2ca16 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientAudioChannel.java @@ -0,0 +1,38 @@ +package de.maxhenkel.voicechat.api.audiochannel; + +import de.maxhenkel.voicechat.api.VolumeCategory; + +import javax.annotation.Nullable; +import java.util.UUID; + +public interface ClientAudioChannel { + + /** + * @return the ID of the channel + */ + UUID getId(); + + /** + * Plays this audio data on this audio channel. + *
+ * Providing audio that's not 960 samples will be ignored. + * + * @param rawAudio the raw 16 bit PCM audio frame + */ + void play(short[] rawAudio); + + /** + * @return the category ID of the audio channel + */ + @Nullable + String getCategory(); + + /** + * Make sure you registered your category before using it. + * See {@link de.maxhenkel.voicechat.api.VoicechatServerApi#registerVolumeCategory(VolumeCategory)}. + * + * @param category the category of the audio channel + */ + void setCategory(@Nullable String category); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientEntityAudioChannel.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientEntityAudioChannel.java new file mode 100644 index 0000000..91b8878 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientEntityAudioChannel.java @@ -0,0 +1,32 @@ +package de.maxhenkel.voicechat.api.audiochannel; + +import java.util.UUID; + +public interface ClientEntityAudioChannel extends ClientAudioChannel { + + /** + * @return the UUID of the entity + */ + UUID getEntityId(); + + /** + * @param whispering if the entity should whisper + */ + void setWhispering(boolean whispering); + + /** + * @return if the entity is whispering + */ + boolean isWhispering(); + + /** + * @return the distance, the audio can be heard + */ + float getDistance(); + + /** + * @param distance the distance, the audio can be heard + */ + void setDistance(float distance); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientLocationalAudioChannel.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientLocationalAudioChannel.java new file mode 100644 index 0000000..f99ff20 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientLocationalAudioChannel.java @@ -0,0 +1,29 @@ +package de.maxhenkel.voicechat.api.audiochannel; + +import de.maxhenkel.voicechat.api.Position; + +public interface ClientLocationalAudioChannel extends ClientAudioChannel { + + /** + * @return the current location of the audio channel + */ + Position getLocation(); + + /** + * Updates the location of the audio channel. + * + * @param position the location of the audio channel + */ + void setLocation(Position position); + + /** + * @return the distance, the audio can be heard + */ + float getDistance(); + + /** + * @param distance the distance, the audio can be heard + */ + void setDistance(float distance); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientStaticAudioChannel.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientStaticAudioChannel.java new file mode 100644 index 0000000..fffab3a --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/ClientStaticAudioChannel.java @@ -0,0 +1,5 @@ +package de.maxhenkel.voicechat.api.audiochannel; + +public interface ClientStaticAudioChannel extends ClientAudioChannel { + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/EntityAudioChannel.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/EntityAudioChannel.java new file mode 100644 index 0000000..bcf1014 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/EntityAudioChannel.java @@ -0,0 +1,43 @@ +package de.maxhenkel.voicechat.api.audiochannel; + +import de.maxhenkel.voicechat.api.Entity; + +/** + * An audio channel that is bound to an entity. + * NOTE: If you are using this for a player, you need to use {@link #updateEntity(Entity)} to update the player after it died. + */ +public interface EntityAudioChannel extends AudioChannel { + + /** + * @return if the entity is whispering + */ + boolean isWhispering(); + + /** + * @param whispering if the entity should whisper + */ + void setWhispering(boolean whispering); + + /** + * Sets a new entity where this channel is attached to. + * + * @param entity the entity to attach the channel to + */ + void updateEntity(Entity entity); + + /** + * @return the entity where the channel is attached to + */ + Entity getEntity(); + + /** + * @return the distance, the audio can be heard + */ + float getDistance(); + + /** + * @param distance the distance, the audio can be heard + */ + void setDistance(float distance); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/LocationalAudioChannel.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/LocationalAudioChannel.java new file mode 100644 index 0000000..686bb8c --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/LocationalAudioChannel.java @@ -0,0 +1,29 @@ +package de.maxhenkel.voicechat.api.audiochannel; + +import de.maxhenkel.voicechat.api.Position; + +public interface LocationalAudioChannel extends AudioChannel { + + /** + * Updates the location of the audio. + * + * @param position the audio location + */ + void updateLocation(Position position); + + /** + * @return the current location of this channel + */ + Position getLocation(); + + /** + * @return the distance, the audio can be heard + */ + float getDistance(); + + /** + * @param distance the distance, the audio can be heard + */ + void setDistance(float distance); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/StaticAudioChannel.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/StaticAudioChannel.java new file mode 100644 index 0000000..eabb086 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/StaticAudioChannel.java @@ -0,0 +1,38 @@ +package de.maxhenkel.voicechat.api.audiochannel; + +import de.maxhenkel.voicechat.api.VoicechatConnection; + +public interface StaticAudioChannel extends AudioChannel { + + /** + * Sets whether this audio channel should be received by targets in isolated groups. + * + * @param bypassGroupIsolation if group isolation should be bypassed + */ + void setBypassGroupIsolation(boolean bypassGroupIsolation); + + /** + * @return if this audio channel is received by targets in isolated groups + */ + boolean bypassesGroupIsolation(); + + /** + * Adds a target to the audio channel. + * + * @param target the target to add + */ + void addTarget(VoicechatConnection target); + + /** + * Removes a target from the audio channel. + * + * @param target the target to remove + */ + void removeTarget(VoicechatConnection target); + + /** + * Removes all targets from the audio channel. + */ + void clearTargets(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/package-info.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/package-info.java new file mode 100644 index 0000000..7987a0b --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiochannel/package-info.java @@ -0,0 +1,4 @@ +/** + * Everything related to audio channels and serverside audio. + */ +package de.maxhenkel.voicechat.api.audiochannel; \ No newline at end of file diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiolistener/AudioListener.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/AudioListener.java similarity index 57% rename from source/decompiled/de/maxhenkel/voicechat/api/audiolistener/AudioListener.java rename to source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/AudioListener.java index d50e83a..7747e2d 100644 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiolistener/AudioListener.java +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/AudioListener.java @@ -1,11 +1,12 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.api.audiolistener; import java.util.UUID; public interface AudioListener { - public UUID getListenerId(); -} + /** + * @return the ID of the listener + */ + UUID getListenerId(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/PlayerAudioListener.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/PlayerAudioListener.java new file mode 100644 index 0000000..1adb317 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/PlayerAudioListener.java @@ -0,0 +1,47 @@ +package de.maxhenkel.voicechat.api.audiolistener; + +import de.maxhenkel.voicechat.api.ServerPlayer; +import de.maxhenkel.voicechat.api.packets.SoundPacket; + +import java.util.UUID; +import java.util.function.Consumer; + +public interface PlayerAudioListener extends AudioListener { + + /** + * @return the {@link UUID} of the player that is listened to + */ + UUID getPlayerUuid(); + + public interface Builder { + + /** + * Note: It is required to either set a player with this method or with {@link #setPlayer(UUID)} + * + * @param player the player that should be listened to + */ + Builder setPlayer(ServerPlayer player); + + /** + * Note: It is required to either set a player with this method or with {@link #setPlayer(ServerPlayer)} + * + * @param playerUuid the player UUID that should be listened to + */ + Builder setPlayer(UUID playerUuid); + + /** + * Note: It is required to set a listener + * + * @param listener the listener + */ + Builder setPacketListener(Consumer listener); + + /** + * @return the built listener + * @throws IllegalStateException if the player or the listener is not set + */ + PlayerAudioListener build(); + + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/package-info.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/package-info.java new file mode 100644 index 0000000..4e09114 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiolistener/package-info.java @@ -0,0 +1,6 @@ +/** + * Utilities for listening to all audio a player would theoretically receive. + *

+ * Can be obtained by calling {@link de.maxhenkel.voicechat.api.VoicechatServerApi#playerAudioListenerBuilder()}. + */ +package de.maxhenkel.voicechat.api.audiolistener; \ No newline at end of file diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiosender/AudioSender.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiosender/AudioSender.java new file mode 100644 index 0000000..95728fc --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiosender/AudioSender.java @@ -0,0 +1,52 @@ +package de.maxhenkel.voicechat.api.audiosender; + +public interface AudioSender { + + /** + * @param whispering if the player should whisper + * @return the audio sender itself + */ + AudioSender whispering(boolean whispering); + + /** + * @return if the player is whispering + */ + boolean isWhispering(); + + /** + * Sets the sequence number of the packet. + *
+ * Setting this will override the automatic sequence numbering. + *
+ * If you set this value, consequent calls to {@link AudioSender#send(byte[])} will increase this number by 1. + * If you don't intend this, you need to set the sequence number every time before calling {@link AudioSender#send(byte[])}. + *
+ * Calling {@link AudioSender#reset()} will also reset the sequence number to start with 0 again. + * + * @param sequenceNumber the sequence number (Must be >= 0) + * @return the audio sender itself + */ + AudioSender sequenceNumber(long sequenceNumber); + + /** + * @return if a microphone packet can be sent. This will return false if the player has the mod installed or the {@link AudioSender} is not registered. + */ + boolean canSend(); + + /** + * Acts as if the player has sent a microphone packet. + * + * @param opusEncodedAudioData the opus encoded audio data + * @return true if the packet was sent, false if the sender does have the mod installed or the {@link AudioSender} is not registered + */ + boolean send(byte[] opusEncodedAudioData); + + /** + * Resets the sequence number and indicates to clients that the current audio stream is paused/stopped. + *
+ * This method should be called when the sending of audio is paused or stopped. + * You can still send audio after this method is called. + */ + boolean reset(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/audiosender/package-info.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiosender/package-info.java new file mode 100644 index 0000000..ec73628 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/audiosender/package-info.java @@ -0,0 +1,6 @@ +/** + * Utilities for simulating players sending audio without the mod. + *

+ * Can be obtained by calling {@link de.maxhenkel.voicechat.api.VoicechatServerApi#createAudioSender(de.maxhenkel.voicechat.api.VoicechatConnection)}. + */ +package de.maxhenkel.voicechat.api.audiosender; \ No newline at end of file diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/config/ConfigAccessor.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/config/ConfigAccessor.java new file mode 100644 index 0000000..81dc9d3 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/config/ConfigAccessor.java @@ -0,0 +1,100 @@ +package de.maxhenkel.voicechat.api.config; + +import de.maxhenkel.voicechat.api.VoicechatClientApi; +import de.maxhenkel.voicechat.api.VoicechatServerApi; + +import javax.annotation.Nullable; + +/** + * An interface to access a config. + * This is kept very generic, so it can be used for any config type. + *
+ * This contains a few default methods to get primitive values from the config. + *
+ * NOTE: You need to implement more complex values yourself (e.g. enums). + *
+ * Can be obtained by calling {@link VoicechatServerApi#getServerConfig()} or {@link VoicechatClientApi#getClientConfig()}. + */ +public interface ConfigAccessor { + + /** + * Checks if the config has the given key. + * + * @param key the key + * @return true if the config has the key, false otherwise + */ + boolean hasKey(String key); + + /** + * Gets the raw value of the given key. + * NOTE: This gets the raw value from the config, so it will be a {@link String} even if the value is a number, a boolean or an enum. + * + * @param key the key + * @return the value or null if the key doesn't exist + */ + @Nullable + String getValue(String key); + + /** + * Gets the string value of the given key. + * + * @param key the key + * @param def the default value + * @return the value or the default value if the key doesn't exist + */ + default String getString(String key, String def) { + String value = getValue(key); + if (value == null) { + return def; + } + return value; + } + + /** + * Gets the boolean value of the given key. + * + * @param key the key + * @param def the default value + * @return the boolean value, false if the value is not "true" or the default value if the key doesn't exist + */ + default boolean getBoolean(String key, boolean def) { + String value = getValue(key); + if (value == null) { + return def; + } + return Boolean.parseBoolean(value); + } + + /** + * Gets the integer value of the given key. + * + * @param key the key + * @param def the default value + * @return the value or the default value if the key doesn't exist + * @throws NumberFormatException if the value is not an integer + */ + default int getInt(String key, int def) { + String value = getValue(key); + if (value == null) { + return def; + } + return Integer.parseInt(value); + } + + /** + * Gets the double value of the given key. + * + * @param key the key + * @param def the default value + * @return the value or the default value if the key doesn't exist + * @throws NumberFormatException if the value is not a double + */ + default double getDouble(String key, double def) { + String value = getValue(key); + if (value == null) { + return def; + } + return Double.parseDouble(value); + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/config/VolumeConfigAccessor.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/config/VolumeConfigAccessor.java new file mode 100644 index 0000000..2842330 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/config/VolumeConfigAccessor.java @@ -0,0 +1,51 @@ +package de.maxhenkel.voicechat.api.config; + +import de.maxhenkel.voicechat.api.VoicechatClientApi; + +import java.util.UUID; + +/** + * An interface to access client side adjusted volumes. + *
+ * Can be obtained by calling {@link VoicechatClientApi#getVolumeConfig()}. + */ +public interface VolumeConfigAccessor { + + /** + * Gets the volume of a player by its UUID. + *
+ *
+ * This will always return a value, even if the player is not in the volume config. + *
+ * By default, the volume will be 1.0. + * A volume of 0.0 means this player is muted. + * Can be larger than 1.0. + * Also works for players that are not online. + *
+ *
+ * If you want the Other volume (All volumes that are not covered by categories or players), use the UUID 00000000-0000-0000-0000-000000000000. + * + * @param uuid the UUID of the player + * @return the volume of the player + * @throws NullPointerException if the UUID is null + */ + double getVolume(UUID uuid); + + /** + * Gets the volume of a category by its UUID. + *
+ *
+ * This will always return a value, even if the category doesn't exist. + *
+ * By default, the volume will be 1.0. + * A volume of 0.0 means this category is muted. + * Can be larger than 1.0. + * Also works for categories that are currently not registered. + * + * @param category the category + * @return the volume of the category + * @throws NullPointerException if the category is null + */ + double getCategoryVolume(String category); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/config/package-info.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/config/package-info.java new file mode 100644 index 0000000..1a56bd4 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/config/package-info.java @@ -0,0 +1,4 @@ +/** + * Everything configuration related. + */ +package de.maxhenkel.voicechat.api.config; \ No newline at end of file diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientEvent.java new file mode 100644 index 0000000..f92a6d3 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientEvent.java @@ -0,0 +1,12 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.VoicechatClientApi; + +public interface ClientEvent extends Event { + + /** + * @return the voice chat client API + */ + VoicechatClientApi getVoicechat(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientReceiveSoundEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientReceiveSoundEvent.java new file mode 100644 index 0000000..0f33b9f --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientReceiveSoundEvent.java @@ -0,0 +1,73 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.Position; + +import javax.annotation.Nullable; +import java.util.UUID; + +/** + * This event is emitted before the sound is played on the client. + */ +public interface ClientReceiveSoundEvent extends ClientEvent { + + /** + * @return the ID of the channel + */ + UUID getId(); + + /** + * The unencoded audio data. + *
+ * Returns an empty array in case of the end of transmission + * + * @return the raw 16 bit PCM audio frame + */ + short[] getRawAudio(); + + /** + * Overrides the actual audio data that is played. + *

+ * This is ignored, if the {@link #getRawAudio} array is empty + *
+ * Providing audio that's not 960 samples will be ignored. + * An empty array skips this frame, which adds latency. To mute the audio, use an array filled with zeros instead. + * + * @param rawAudio the raw 16 bit PCM audio frame + */ + void setRawAudio(@Nullable short[] rawAudio); + + public static interface EntitySound extends ClientReceiveSoundEvent { + + /** + * @return the UUID of the entity + */ + UUID getEntityId(); + + /** + * @return if the player is whispering + */ + boolean isWhispering(); + + /** + * @return the distance, the audio can be heard + */ + float getDistance(); + } + + public static interface LocationalSound extends ClientReceiveSoundEvent { + /** + * @return the position of the sound + */ + Position getPosition(); + + /** + * @return the distance, the audio can be heard + */ + float getDistance(); + } + + public static interface StaticSound extends ClientReceiveSoundEvent { + + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientSoundEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientSoundEvent.java new file mode 100644 index 0000000..115eb2d --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientSoundEvent.java @@ -0,0 +1,29 @@ +package de.maxhenkel.voicechat.api.events; + +/** + * This event is emitted before the client encodes the audio and sends it to the server. + */ +public interface ClientSoundEvent extends ClientEvent { + + /** + * The unencoded audio data. + *
+ * Returns an empty array in case of the end of transmission + * + * @return the raw 16 bit PCM audio frame + */ + short[] getRawAudio(); + + /** + * Overrides the actual audio data that's sent to the server. + * + * @param rawAudio the raw 16 bit PCM audio frame + */ + void setRawAudio(short[] rawAudio); + + /** + * @return if the player is whispering + */ + boolean isWhispering(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientVoicechatConnectionEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientVoicechatConnectionEvent.java new file mode 100644 index 0000000..c266c28 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientVoicechatConnectionEvent.java @@ -0,0 +1,13 @@ +package de.maxhenkel.voicechat.api.events; + +/** + * This event is emitted on the client when the voice chat connects/disconnects. + */ +public interface ClientVoicechatConnectionEvent extends ClientEvent { + + /** + * @return if the voice chat is connected to the server + */ + boolean isConnected(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientVoicechatInitializationEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientVoicechatInitializationEvent.java new file mode 100644 index 0000000..6c99766 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ClientVoicechatInitializationEvent.java @@ -0,0 +1,22 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.ClientVoicechatSocket; + +import javax.annotation.Nullable; + +public interface ClientVoicechatInitializationEvent extends ClientEvent { + + /** + * Sets a custom implementation of the socket used for client side voice chat traffic. + * + * @param socket the custom socket implementation + */ + void setSocketImplementation(ClientVoicechatSocket socket); + + /** + * @return the custom socket implementation or null to use voice chats default one + */ + @Nullable + ClientVoicechatSocket getSocketImplementation(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/CreateGroupEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/CreateGroupEvent.java new file mode 100644 index 0000000..2c3ab73 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/CreateGroupEvent.java @@ -0,0 +1,21 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.Group; +import de.maxhenkel.voicechat.api.VoicechatConnection; + +import javax.annotation.Nullable; + +public interface CreateGroupEvent extends GroupEvent { + + /** + * @return the group that was created + */ + Group getGroup(); + + /** + * @return the connection of the player that created the group or null if the group was not created by a player + */ + @Nullable + VoicechatConnection getConnection(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/CreateOpenALContextEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/CreateOpenALContextEvent.java new file mode 100644 index 0000000..ff71878 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/CreateOpenALContextEvent.java @@ -0,0 +1,18 @@ +package de.maxhenkel.voicechat.api.events; + +/** + * This event is emitted when the voice chats OpenAL context is created. + */ +public interface CreateOpenALContextEvent extends ClientEvent { + + /** + * @return the OpenAL context + */ + long getContext(); + + /** + * @return the OpenAL device + */ + long getDevice(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/DestroyOpenALContextEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/DestroyOpenALContextEvent.java new file mode 100644 index 0000000..076dbe0 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/DestroyOpenALContextEvent.java @@ -0,0 +1,18 @@ +package de.maxhenkel.voicechat.api.events; + +/** + * This event is emitted when the voice chats OpenAL context is destroyed. + */ +public interface DestroyOpenALContextEvent extends ClientEvent { + + /** + * @return the OpenAL context - Might be 0L in some cases + */ + long getContext(); + + /** + * @return the OpenAL device - Might be 0L in some cases + */ + long getDevice(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/EntitySoundPacketEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/EntitySoundPacketEvent.java new file mode 100644 index 0000000..8d1748c --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/EntitySoundPacketEvent.java @@ -0,0 +1,10 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; + +/** + * This event is emitted when an entity sound packet is about to get sent to a client. + */ +public interface EntitySoundPacketEvent extends SoundPacketEvent { + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/Event.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/Event.java new file mode 100644 index 0000000..9cfeef5 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/Event.java @@ -0,0 +1,23 @@ +package de.maxhenkel.voicechat.api.events; + +public interface Event { + + /** + * @return if this event can be cancelled + */ + boolean isCancellable(); + + /** + * Cancels this event. + * Does nothing if the event isn't cancellable. + * + * @return if the event was actually cancelled + */ + boolean cancel(); + + /** + * @return if the event was cancelled + */ + boolean isCancelled(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/EventRegistration.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/EventRegistration.java new file mode 100644 index 0000000..ec00a2c --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/EventRegistration.java @@ -0,0 +1,28 @@ +package de.maxhenkel.voicechat.api.events; + +import java.util.function.Consumer; + +public interface EventRegistration { + + /** + * Registers an event. + * + * @param eventClass the class of the event you want to receive + * @param onPacket the consumer that is called when the event was dispatched + * @param priority the event priority - Higher values mean a higher priority + * @param the event type + */ + void registerEvent(Class eventClass, Consumer onPacket, int priority); + + /** + * Registers an event. + * + * @param eventClass the class of the event you want to receive + * @param onPacket the consumer that is called when the event was dispatched + * @param the event type + */ + default void registerEvent(Class eventClass, Consumer onPacket) { + registerEvent(eventClass, onPacket, 0); + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/GroupEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/GroupEvent.java new file mode 100644 index 0000000..5cda398 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/GroupEvent.java @@ -0,0 +1,22 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.Group; +import de.maxhenkel.voicechat.api.VoicechatConnection; + +import javax.annotation.Nullable; + +public interface GroupEvent extends ServerEvent { + + /** + * @return the group - null if there is no group + */ + @Nullable + Group getGroup(); + + /** + * @return the connection of the player + */ + @Nullable + VoicechatConnection getConnection(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/JoinGroupEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/JoinGroupEvent.java new file mode 100644 index 0000000..f89608a --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/JoinGroupEvent.java @@ -0,0 +1,18 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.Group; +import de.maxhenkel.voicechat.api.VoicechatConnection; + +public interface JoinGroupEvent extends GroupEvent { + + /** + * @return the group that was joined + */ + Group getGroup(); + + /** + * @return the connection of the player + */ + VoicechatConnection getConnection(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/LeaveGroupEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/LeaveGroupEvent.java new file mode 100644 index 0000000..c116665 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/LeaveGroupEvent.java @@ -0,0 +1,21 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.Group; +import de.maxhenkel.voicechat.api.VoicechatConnection; + +import javax.annotation.Nullable; + +public interface LeaveGroupEvent extends GroupEvent { + + /** + * @return the group that was left or null if the player was not in a group + */ + @Nullable + Group getGroup(); + + /** + * @return the connection of the player + */ + VoicechatConnection getConnection(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/LocationalSoundPacketEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/LocationalSoundPacketEvent.java new file mode 100644 index 0000000..4d1549e --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/LocationalSoundPacketEvent.java @@ -0,0 +1,10 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; + +/** + * This event is emitted when a locational sound packet is about to get sent to a client. + */ +public interface LocationalSoundPacketEvent extends SoundPacketEvent { + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/MergeClientSoundEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/MergeClientSoundEvent.java new file mode 100644 index 0000000..cd47395 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/MergeClientSoundEvent.java @@ -0,0 +1,22 @@ +package de.maxhenkel.voicechat.api.events; + +/** + * This event is emitted before the {@link ClientSoundEvent} is getting called. + * It allows you to merge audio into the audio that is captured from the microphone. + *
+ * This is called even when the player is muted or not talking. + *
+ * When the voice chat it disabled, this event is not called. + */ +public interface MergeClientSoundEvent extends ClientEvent { + + /** + * Merges the audio into the audio that is captured from the microphone. + *
+ * Calling this multiple times will merge the audio multiple times into the same audio frame. + * + * @param audio the audio that should get merged + */ + void mergeAudio(short[] audio); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/MicrophoneMuteEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/MicrophoneMuteEvent.java new file mode 100644 index 0000000..87d46c8 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/MicrophoneMuteEvent.java @@ -0,0 +1,13 @@ +package de.maxhenkel.voicechat.api.events; + +/** + * This event is emitted on the client when the state of the microphone changes. + */ +public interface MicrophoneMuteEvent extends ClientEvent { + + /** + * @return if the microphone is muted + */ + boolean isDisabled(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/MicrophonePacketEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/MicrophonePacketEvent.java new file mode 100644 index 0000000..c1d0e97 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/MicrophonePacketEvent.java @@ -0,0 +1,10 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.packets.MicrophonePacket; + +/** + * This event is emitted when a microphone packet arrives at the server. + */ +public interface MicrophonePacketEvent extends PacketEvent { + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/NameTagIconRenderEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/NameTagIconRenderEvent.java new file mode 100644 index 0000000..7e493eb --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/NameTagIconRenderEvent.java @@ -0,0 +1,30 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.VoicechatClientApi; + +import java.util.UUID; + +/** + * This event is emitted when an icon is getting rendered. + *
+ * This event should not be used to do any actual rendering. + * Just use this event to cancel the rendering of the icon. + *
+ * Warning: Don't do heavy operations in this event, as it will block the render thread! + *
+ *
+ * Note: Don't keep references to this event. It will be reused for every icon render to avoid allocations. + *
+ *
+ * Use {@link VoicechatClientApi#isTalking(UUID)}, {@link VoicechatClientApi#isWhispering(UUID)}, + * {@link VoicechatClientApi#isDisabled(UUID)} and {@link VoicechatClientApi#isDisconnected(UUID)} + * to get the status of the player and render it using your mod loaders render event system. + */ +public interface NameTagIconRenderEvent extends ClientEvent { + + /** + * @return the UUID of the entity the icon is being rendered for + */ + UUID getEntityId(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/OpenALSoundEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/OpenALSoundEvent.java new file mode 100644 index 0000000..e77dca6 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/OpenALSoundEvent.java @@ -0,0 +1,59 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.Position; + +import javax.annotation.Nullable; +import java.util.UUID; + +/** + * This event is emitted for every audio chunk for every audio channel. + * These events are meant to be used to modify OpenAL effects. + *
+ * This specific event is emitted after the position of the sound is set, but before the any other OpenAL calls. + * Use {@link Pre} or {@link Post} get earlier or later events respectively. + */ +public interface OpenALSoundEvent extends ClientEvent { + + /** + * Returns the position of the sound. + * This returns null for static sounds. + * + * @return the position of the sound + */ + @Nullable + Position getPosition(); + + /** + * This returns null for non audio channel sounds, like microphone testing. + * + * @return the unique ID of the audio channel + */ + @Nullable + UUID getChannelId(); + + /** + * @return the OpenAL source + */ + int getSource(); + + /** + * @return the category of the sound + */ + @Nullable + String getCategory(); + + /** + * This event is emitted before any OpenAL calls were made by the voice chat. + */ + public interface Pre extends OpenALSoundEvent { + + } + + /** + * This event is emitted after all OpenAL calls by the voice chat and the audio is added to the buffer queue. + */ + public interface Post extends OpenALSoundEvent { + + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PacketEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PacketEvent.java new file mode 100644 index 0000000..f53d9be --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PacketEvent.java @@ -0,0 +1,27 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.VoicechatConnection; +import de.maxhenkel.voicechat.api.packets.Packet; + +import javax.annotation.Nullable; + +public interface PacketEvent extends ServerEvent { + + /** + * @return the packet + */ + T getPacket(); + + /** + * @return the connection of the player that should receive this packet + */ + @Nullable + VoicechatConnection getReceiverConnection(); + + /** + * @return the connection of the player that sent this packet or null if it wasn't sent by a player + */ + @Nullable + VoicechatConnection getSenderConnection(); + +} \ No newline at end of file diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerConnectedEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerConnectedEvent.java new file mode 100644 index 0000000..247aed5 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerConnectedEvent.java @@ -0,0 +1,12 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.VoicechatConnection; + +public interface PlayerConnectedEvent extends ServerEvent { + + /** + * @return the connection of the player + */ + VoicechatConnection getConnection(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerDisconnectedEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerDisconnectedEvent.java new file mode 100644 index 0000000..7c02278 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerDisconnectedEvent.java @@ -0,0 +1,12 @@ +package de.maxhenkel.voicechat.api.events; + +import java.util.UUID; + +public interface PlayerDisconnectedEvent extends ServerEvent { + + /** + * @return the UUID of the player + */ + UUID getPlayerUuid(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerStateChangedEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerStateChangedEvent.java new file mode 100644 index 0000000..6bd3833 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/PlayerStateChangedEvent.java @@ -0,0 +1,35 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.VoicechatConnection; + +import javax.annotation.Nullable; +import java.util.UUID; + +/** + * Called when a player changes its state. + * For example if voice chat connects/disconnects, the player joins/leaves a group or disables voice chat. + */ +public interface PlayerStateChangedEvent extends ServerEvent { + + /** + * @return if the player disabled voice chat + */ + boolean isDisabled(); + + /** + * @return if the player is disconnected from voice chat + */ + boolean isDisconnected(); + + /** + * @return the uuid of the player + */ + UUID getPlayerUuid(); + + /** + * @return the connection of the player + */ + @Nullable + VoicechatConnection getConnection(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/RegisterVolumeCategoryEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/RegisterVolumeCategoryEvent.java new file mode 100644 index 0000000..f1f0a45 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/RegisterVolumeCategoryEvent.java @@ -0,0 +1,5 @@ +package de.maxhenkel.voicechat.api.events; + +public interface RegisterVolumeCategoryEvent extends VolumeCategoryEvent { + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/RemoveGroupEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/RemoveGroupEvent.java new file mode 100644 index 0000000..4ea6166 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/RemoveGroupEvent.java @@ -0,0 +1,25 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.Group; +import de.maxhenkel.voicechat.api.VoicechatConnection; + +import javax.annotation.Nullable; + +/** + * This event is only cancellable if the group is persistent + */ +public interface RemoveGroupEvent extends GroupEvent { + + /** + * @return the group that was removed + */ + Group getGroup(); + + /** + * @return null + */ + @Nullable + @Deprecated + VoicechatConnection getConnection(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ServerEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ServerEvent.java new file mode 100644 index 0000000..c95e318 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/ServerEvent.java @@ -0,0 +1,12 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.VoicechatServerApi; + +public interface ServerEvent extends Event { + + /** + * @return the voice chat server API + */ + VoicechatServerApi getVoicechat(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/SoundPacketEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/SoundPacketEvent.java new file mode 100644 index 0000000..f857cf2 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/SoundPacketEvent.java @@ -0,0 +1,23 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.packets.Packet; + +public interface SoundPacketEvent extends PacketEvent { + + String SOURCE_GROUP = "group"; + String SOURCE_PROXIMITY = "proximity"; + String SOURCE_SPECTATOR = "spectator"; + String SOURCE_PLUGIN = "plugin"; + + /** + * Where the packet originated from. + * It can be either {@value SOURCE_GROUP} for group chats, + * {@value SOURCE_PROXIMITY} for proximity sound, + * {@value SOURCE_SPECTATOR} for spectator sound + * or {@value SOURCE_PLUGIN} if the packet was sent from a plugin. + * + * @return the source of the packet + */ + String getSource(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/StaticSoundPacketEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/StaticSoundPacketEvent.java new file mode 100644 index 0000000..6e5306b --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/StaticSoundPacketEvent.java @@ -0,0 +1,10 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; + +/** + * This event is emitted when a static sound packet is about to get sent to a client. + */ +public interface StaticSoundPacketEvent extends SoundPacketEvent { + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/UnregisterVolumeCategoryEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/UnregisterVolumeCategoryEvent.java new file mode 100644 index 0000000..8c7bb3c --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/UnregisterVolumeCategoryEvent.java @@ -0,0 +1,5 @@ +package de.maxhenkel.voicechat.api.events; + +public interface UnregisterVolumeCategoryEvent extends VolumeCategoryEvent { + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoiceDistanceEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoiceDistanceEvent.java new file mode 100644 index 0000000..fdaf86c --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoiceDistanceEvent.java @@ -0,0 +1,39 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.VoicechatConnection; +import de.maxhenkel.voicechat.api.packets.MicrophonePacket; + +/** + * This event is emitted after a microphone packet arrives at the server and the distance is processed. + * This can be used to modify the distance at which other players can hear this packet. + */ +public interface VoiceDistanceEvent extends ServerEvent { + + /** + * @return the microphone packet + */ + MicrophonePacket getPacket(); + + /** + * @return the connection of the player + */ + VoicechatConnection getSenderConnection(); + + /** + * This returns either the default distance that's set on the server or the modified distance if another subscriber changed it already. + * In case a player is whispering, this will return the whisper distance. + * The whisper state can be obtained by calling {@link #getPacket()} and getting {@link MicrophonePacket#isWhispering()}. + * + * @return the distance in blocks + */ + float getDistance(); + + /** + * Sets the distance this player sends audio at. + * Note that this also includes the whisper distance, if the player is whispering. + * + * @param distance the distance in blocks + */ + void setDistance(float distance); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoiceHostEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoiceHostEvent.java new file mode 100644 index 0000000..39ffb73 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoiceHostEvent.java @@ -0,0 +1,24 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.ServerPlayer; + +public interface VoiceHostEvent extends ServerEvent { + + /** + * @return the voice host string + */ + String getVoiceHost(); + + /** + * Overwrites voice chats voice host - This is sent to the client and used by it to connect to the server. + * + * @param voiceHost the voice host string + */ + void setVoiceHost(String voiceHost); + + /** + * @return the player that is connecting + */ + ServerPlayer getPlayer(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatDisableEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatDisableEvent.java new file mode 100644 index 0000000..df9f62b --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatDisableEvent.java @@ -0,0 +1,13 @@ +package de.maxhenkel.voicechat.api.events; + +/** + * This event is emitted on the client when the voice chat is getting enabled/disabled. + */ +public interface VoicechatDisableEvent extends ClientEvent { + + /** + * @return if the voice chat is disabled + */ + boolean isDisabled(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStartedEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStartedEvent.java new file mode 100644 index 0000000..492d2f8 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStartedEvent.java @@ -0,0 +1,5 @@ +package de.maxhenkel.voicechat.api.events; + +public interface VoicechatServerStartedEvent extends ServerEvent { + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStartingEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStartingEvent.java new file mode 100644 index 0000000..3dc4caa --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStartingEvent.java @@ -0,0 +1,22 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.VoicechatSocket; + +import javax.annotation.Nullable; + +public interface VoicechatServerStartingEvent extends ServerEvent { + + /** + * Sets a custom implementation of the socket used for voice chat traffic. + * + * @param socket the custom socket implementation + */ + void setSocketImplementation(VoicechatSocket socket); + + /** + * @return the custom socket implementation or null to use voice chats default one + */ + @Nullable + VoicechatSocket getSocketImplementation(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStoppedEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStoppedEvent.java new file mode 100644 index 0000000..8988fbe --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VoicechatServerStoppedEvent.java @@ -0,0 +1,5 @@ +package de.maxhenkel.voicechat.api.events; + +public interface VoicechatServerStoppedEvent extends ServerEvent { + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VolumeCategoryEvent.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VolumeCategoryEvent.java new file mode 100644 index 0000000..f30e58f --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/VolumeCategoryEvent.java @@ -0,0 +1,12 @@ +package de.maxhenkel.voicechat.api.events; + +import de.maxhenkel.voicechat.api.VolumeCategory; + +public interface VolumeCategoryEvent extends ServerEvent { + + /** + * @return the volume category + */ + VolumeCategory getVolumeCategory(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/events/package-info.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/package-info.java new file mode 100644 index 0000000..01260d4 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/events/package-info.java @@ -0,0 +1,6 @@ +/** + * All registerable events. + *

+ * Events can be registered by calling {@link de.maxhenkel.voicechat.api.events.EventRegistration#registerEvent}. + */ +package de.maxhenkel.voicechat.api.events; \ No newline at end of file diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/Mp3Decoder.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/Mp3Decoder.java new file mode 100644 index 0000000..a49f6fe --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/Mp3Decoder.java @@ -0,0 +1,37 @@ +package de.maxhenkel.voicechat.api.mp3; + +import de.maxhenkel.voicechat.api.VoicechatApi; + +import javax.sound.sampled.AudioFormat; +import java.io.IOException; + +/** + * You can obtain an instance of this class by calling {@link VoicechatApi#createMp3Decoder}. + */ +public interface Mp3Decoder { + + /** + * Decodes the MP3 file and returns the decoded audio data as PCM samples. + * + * @return the decoded audio data as PCM samples + * @throws IOException if an I/O error occurs + */ + short[] decode() throws IOException; + + /** + * Decodes the MP3 file if {@link #decode()} has not been called before. + * + * @return the audio format of the decoded audio data + * @throws IOException if an I/O error occurs + */ + AudioFormat getAudioFormat() throws IOException; + + /** + * Decodes the MP3 file if {@link #decode()} has not been called before. + * + * @return the bitrate of the mp3 file + * @throws IOException if an I/O error occurs + */ + int getBitrate() throws IOException; + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/Mp3Encoder.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/Mp3Encoder.java new file mode 100644 index 0000000..550c386 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/Mp3Encoder.java @@ -0,0 +1,30 @@ +package de.maxhenkel.voicechat.api.mp3; + +import de.maxhenkel.voicechat.api.VoicechatApi; + +import java.io.IOException; + +/** + * You can obtain an instance of this class by calling {@link VoicechatApi#createMp3Encoder}. + */ +public interface Mp3Encoder { + + /** + * Encodes the given PCM samples and writes it to the provided output stream. + * + * @param samples the PCM samples to encode + * @throws IOException if an I/O error occurs + */ + void encode(short[] samples) throws IOException; + + /** + * Closes the encoder and flushes the output stream. + * Also writes leftover mp3 data to the output stream. + * + * NOTE: Not closing encoders will cause a memory leak in voice chat versions <2.6.3! + * + * @throws IOException if an I/O error occurs + */ + void close() throws IOException; + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/package-info.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/package-info.java new file mode 100644 index 0000000..d0db587 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/mp3/package-info.java @@ -0,0 +1,4 @@ +/** + * Wrappers for mp3 encoding and decoding. + */ +package de.maxhenkel.voicechat.api.mp3; \ No newline at end of file diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusDecoder.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusDecoder.java new file mode 100644 index 0000000..2a3068c --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusDecoder.java @@ -0,0 +1,45 @@ +package de.maxhenkel.voicechat.api.opus; + +import de.maxhenkel.voicechat.api.VoicechatApi; + +import javax.annotation.Nullable; + +/** + * Instances can be obtained by calling {@link VoicechatApi#createDecoder()}. + */ +public interface OpusDecoder { + + /** + * Decodes opus encoded audio data to 16 bit PCM audio. + * + * @param data the opus encoded data or null to do PLC + * @return the 16 bit PCM audio data + */ + short[] decode(@Nullable byte[] data); + + /** + * Decodes the provided packet and recovers previous lost frames using FEC. + * + * @param input the input packet + * @param frames the number of frames to return (min 1 for just the current frame) + * @return an array containing the decoded frames - the length of the array is equal to {@param frames} + */ + short[][] decode(byte[] input, int frames); + + /** + * Resets the decoders state. + */ + void resetState(); + + /** + * @return if the decoder is closed + */ + boolean isClosed(); + + /** + * Closes the decoder. + * NOTE: Not closing encoders will cause a memory leak in voice chat versions <2.6.3! + */ + void close(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusEncoder.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusEncoder.java new file mode 100644 index 0000000..70bdaff --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusEncoder.java @@ -0,0 +1,34 @@ +package de.maxhenkel.voicechat.api.opus; + +import de.maxhenkel.voicechat.api.VoicechatApi; + +/** + * Instances can be obtained by calling {@link VoicechatApi#createEncoder()}. + */ +public interface OpusEncoder { + + /** + * Encodes 16 bit PCM audio with opus. + * + * @param rawAudio the raw 16 bit PCM audio + * @return the opus encoded data + */ + byte[] encode(short[] rawAudio); + + /** + * Resets the encoders state. + */ + void resetState(); + + /** + * @return if the encoder is closed + */ + boolean isClosed(); + + /** + * Closes the encoder. + * NOTE: Not closing encoders will cause a memory leak in voice chat versions <2.6.3! + */ + void close(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusEncoderMode.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusEncoderMode.java new file mode 100644 index 0000000..3351104 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/OpusEncoderMode.java @@ -0,0 +1,8 @@ +package de.maxhenkel.voicechat.api.opus; + +/** + * The different Opus encoder modes + */ +public enum OpusEncoderMode { + VOIP, AUDIO, RESTRICTED_LOWDELAY; +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/package-info.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/package-info.java new file mode 100644 index 0000000..2be6d37 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/opus/package-info.java @@ -0,0 +1,4 @@ +/** + * Wrappers for the Opus codec. + */ +package de.maxhenkel.voicechat.api.opus; \ No newline at end of file diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/package-info.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/package-info.java new file mode 100644 index 0000000..4554d9f --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/package-info.java @@ -0,0 +1,4 @@ +/** + * The main Simple Voice Chat API package. + */ +package de.maxhenkel.voicechat.api; \ No newline at end of file diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/ConvertablePacket.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/ConvertablePacket.java new file mode 100644 index 0000000..2434d3f --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/ConvertablePacket.java @@ -0,0 +1,64 @@ +package de.maxhenkel.voicechat.api.packets; + +import de.maxhenkel.voicechat.api.Position; +import de.maxhenkel.voicechat.api.VoicechatServerApi; + +import java.util.UUID; + +public interface ConvertablePacket { + + /** + * NOTE: Make sure to set {@link SoundPacket.Builder#channelId(UUID)} to avoid conflicts with other channels. + * + * @return a builder to build an entity sound packet based on this packet + */ + EntitySoundPacket.Builder entitySoundPacketBuilder(); + + /** + * NOTE: Make sure to set {@link SoundPacket.Builder#channelId(UUID)} to avoid conflicts with other channels. + * + * @return a builder to build a locational sound packet based on this packet + */ + LocationalSoundPacket.Builder locationalSoundPacketBuilder(); + + /** + * NOTE: Make sure to set {@link SoundPacket.Builder#channelId(UUID)} to avoid conflicts with other channels. + * + * @return a builder to build a static sound packet based on this packet + */ + StaticSoundPacket.Builder staticSoundPacketBuilder(); + + /** + * Converts this packet to an entity sound packet. + * + * @param entityUuid the UUID of the entity + * @param whispering if the entity is whispering + * @return the entity sound packet + * @throws UnsupportedOperationException if this is called on a packet created by {@link VoicechatServerApi#createPacket()} + * @deprecated use {@link #entitySoundPacketBuilder()} + */ + @Deprecated + EntitySoundPacket toEntitySoundPacket(UUID entityUuid, boolean whispering); + + /** + * Converts this packet to a locational sound packet. + * + * @param position the position of the audio + * @return the locational sound packet + * @throws UnsupportedOperationException if this is called on a packet created by {@link VoicechatServerApi#createPacket()} + * @deprecated use {@link #locationalSoundPacketBuilder()} + */ + @Deprecated + LocationalSoundPacket toLocationalSoundPacket(Position position); + + /** + * Converts this packet to a static sound packet. + * + * @return the static sound packet + * @throws UnsupportedOperationException if this is called on a packet created by {@link VoicechatServerApi#createPacket()} + * @deprecated use {@link #staticSoundPacketBuilder()} + */ + @Deprecated + StaticSoundPacket toStaticSoundPacket(); + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/EntitySoundPacket.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/EntitySoundPacket.java new file mode 100644 index 0000000..8d264f6 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/EntitySoundPacket.java @@ -0,0 +1,60 @@ +package de.maxhenkel.voicechat.api.packets; + +import java.util.UUID; + +/** + * The receiver of this event will hear the sound from the specified entity. + * This can be done for all entities, but only players will show the speaker icon. + * If the entity is further away than the maximum voice distance, the receiving player won't actually hear the sound. + */ +public interface EntitySoundPacket extends SoundPacket { + + /** + * @return the UUID of the entity + */ + UUID getEntityUuid(); + + /** + * @return if the entity is whispering + */ + boolean isWhispering(); + + /** + * @return the distance, the audio can be heard + */ + float getDistance(); + + /** + * A builder to build an entity sound packet. + * + * NOTE: Some values are required to be set. + * + * @param the builder itself + */ + public interface Builder> extends SoundPacket.Builder { + + /** + * This is required to be set! + *
+ * The entity UUID is also used as the sender of the packet. + * + * @param entityUuid the UUID of the entity + * @return the builder + */ + T entityUuid(UUID entityUuid); + + /** + * @param whispering if the entity should be whispering + * @return the builder + */ + T whispering(boolean whispering); + + /** + * @param distance the distance, this packet can be heard + * @return the builder + */ + T distance(float distance); + + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/LocationalSoundPacket.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/LocationalSoundPacket.java new file mode 100644 index 0000000..da029ff --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/LocationalSoundPacket.java @@ -0,0 +1,46 @@ +package de.maxhenkel.voicechat.api.packets; + +import de.maxhenkel.voicechat.api.Position; + +/** + * The receiver of this event will hear the sound from the specified location. + * If the location is further away than the maximum voice distance, the receiving player won't actually hear the sound. + */ +public interface LocationalSoundPacket extends SoundPacket { + + /** + * @return the audio location + */ + Position getPosition(); + + /** + * @return the distance, the audio can be heard + */ + float getDistance(); + + /** + * A builder to build a locational sound packet. + * + * NOTE: Some values are required to be set. + * + * @param the builder itself + */ + public interface Builder> extends SoundPacket.Builder { + + /** + * This is required to be set! + * + * @param position the position of the sound + * @return the builder + */ + T position(Position position); + + /** + * @param distance the distance, this packet can be heard + * @return the builder + */ + T distance(float distance); + + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/MicrophonePacket.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/MicrophonePacket.java new file mode 100644 index 0000000..4f9daf4 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/MicrophonePacket.java @@ -0,0 +1,22 @@ +package de.maxhenkel.voicechat.api.packets; + +public interface MicrophonePacket extends Packet, ConvertablePacket { + + /** + * @return if the player is whispering + */ + boolean isWhispering(); + + /** + * @return the opus encoded audio data from the player + */ + byte[] getOpusEncodedData(); + + /** + * Allows you to modify or replace the opus encoded audio data. + * + * @param data the opus encoded audio data to replace + */ + void setOpusEncodedData(byte[] data); + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/api/packets/Packet.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/Packet.java similarity index 65% rename from source/decompiled/de/maxhenkel/voicechat/api/packets/Packet.java rename to source/api/src/main/java/de/maxhenkel/voicechat/api/packets/Packet.java index 3c586be..6185e0f 100644 --- a/source/decompiled/de/maxhenkel/voicechat/api/packets/Packet.java +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/Packet.java @@ -1,8 +1,4 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.api.packets; public interface Packet { } - diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/SoundPacket.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/SoundPacket.java new file mode 100644 index 0000000..4956916 --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/SoundPacket.java @@ -0,0 +1,100 @@ +package de.maxhenkel.voicechat.api.packets; + +import de.maxhenkel.voicechat.api.VoicechatServerApi; +import de.maxhenkel.voicechat.api.VolumeCategory; + +import javax.annotation.Nullable; +import java.util.UUID; + +public interface SoundPacket extends Packet, ConvertablePacket { + + /** + * @return the channel ID of the sound packet + */ + UUID getChannelId(); + + /** + * @return the sender of this packet - doesn't necessarily need to be a player's UUID + */ + UUID getSender(); + + /** + * @return the opus encoded audio data + */ + byte[] getOpusEncodedData(); + + /** + * @return the sequence number of the packet + */ + long getSequenceNumber(); + + /** + * @return the category ID of the sound packet + */ + @Nullable + String getCategory(); + + /** + * A builder to build a sound packet. + * + * @param the builder itself + * @param

the packet, the builder builds + */ + public interface Builder, P extends SoundPacket> { + + /** + * NOTE: Make sure to set this to a unique value to avoid conflicts with other channels. + * This value needs to be the same when sending multiple packets of the same channel. + * + * @param channelId the channel ID of the sound packet + * @return the builder + */ + T channelId(UUID channelId); + + /** + * Sets the sender of the sound packet. + * This must be set if this is created using {@link VoicechatServerApi#createPacket()}. + * + * @param sender the sender of the sound packet + * @return the builder + */ + T sender(UUID sender); + + /** + * @param data the opus encoded audio data + * @return the builder + */ + T opusEncodedData(byte[] data); + + /** + * Sets the sequence number of the sound packet. + * The sequence number is set automatically for everything except when using {@link VoicechatServerApi#createPacket()}. + *
+ *
+ * NOTE: You should only change this when using {@link VoicechatServerApi#createPacket()}. + * + * @param sequenceNumber the sequence number of the sound packet + * @return the builder + */ + T sequenceNumber(long sequenceNumber); + + /** + * Make sure you registered your category before using it. + * See {@link de.maxhenkel.voicechat.api.VoicechatServerApi#registerVolumeCategory(VolumeCategory)}. + * + * @param category the category ID of the sound packet + * @return the builder + */ + T category(@Nullable String category); + + /** + * Builds the packet. + * NOTE: If you are missing required values, this will throw an {@link IllegalStateException}. + * + * @return the packet + */ + P build(); + + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/StaticSoundPacket.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/StaticSoundPacket.java new file mode 100644 index 0000000..3f1698d --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/StaticSoundPacket.java @@ -0,0 +1,18 @@ +package de.maxhenkel.voicechat.api.packets; + +/** + * The receiver of this event will hear the sound non-directional. + * This is what is basically used for group chats. + */ +public interface StaticSoundPacket extends SoundPacket { + + /** + * A builder to build a static sound packet. + * + * @param the builder itself + */ + public interface Builder> extends SoundPacket.Builder { + + } + +} diff --git a/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/package-info.java b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/package-info.java new file mode 100644 index 0000000..f28d51a --- /dev/null +++ b/source/api/src/main/java/de/maxhenkel/voicechat/api/packets/package-info.java @@ -0,0 +1,4 @@ +/** + * All voice chat UDP packets. + */ +package de.maxhenkel.voicechat.api.packets; \ No newline at end of file diff --git a/source/decompiled/de/maxhenkel/voicechat/BukkitVersion.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/BukkitVersion.java similarity index 71% rename from source/decompiled/de/maxhenkel/voicechat/BukkitVersion.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/BukkitVersion.java index db4e732..13ad954 100644 --- a/source/decompiled/de/maxhenkel/voicechat/BukkitVersion.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/BukkitVersion.java @@ -1,19 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat; -import de.maxhenkel.voicechat.Version; +import javax.annotation.Nullable; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.Nullable; -public class BukkitVersion -extends Version { +public class BukkitVersion extends Version { + public static final Pattern BUKKIT_VERSION_REGEX = Pattern.compile("^(?\\d+)\\.(?\\d+)(?:\\.(?\\d+))?-R(?[\\d.-]+)(?:-SNAPSHOT)?$"); + protected final String revision; public BukkitVersion(int major, int minor, int patch, String revision) { @@ -35,15 +29,17 @@ extends Version { @Nullable public static BukkitVersion parseBukkitVersion(String bukkitVersion) { Matcher targetMatcher = BUKKIT_VERSION_REGEX.matcher(bukkitVersion); + if (!targetMatcher.matches()) { return null; } + return BukkitVersion.fromRegex(targetMatcher); } @Nullable public static BukkitVersion getTargetVersion() { - return BukkitVersion.parseBukkitVersion("1.8.8-R0.1-SNAPSHOT"); + return parseBukkitVersion(BuildConstants.TARGET_BUKKIT_VERSION); } @Override @@ -54,24 +50,26 @@ extends Version { if (!(o instanceof BukkitVersion)) { return false; } - BukkitVersion that = (BukkitVersion)o; - if (this.major != that.major) { + + BukkitVersion that = (BukkitVersion) o; + + if (major != that.major) { return false; } - if (this.minor != that.minor) { + if (minor != that.minor) { return false; } - if (this.patch != that.patch) { + if (patch != that.patch) { return false; } - return this.revision.equals(that.revision); + return revision.equals(that.revision); } + @Override public String toString() { - if (this.patch <= 0) { - return this.major + "." + this.minor + "-R" + this.revision; + if (patch <= 0) { + return major + "." + minor + "-R" + revision; } - return this.major + "." + this.minor + "." + this.patch + "-R" + this.revision; + return major + "." + minor + "." + patch + "-R" + revision; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/PaperVersion.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/PaperVersion.java similarity index 77% rename from source/decompiled/de/maxhenkel/voicechat/PaperVersion.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/PaperVersion.java index 4896e6d..ae6303c 100644 --- a/source/decompiled/de/maxhenkel/voicechat/PaperVersion.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/PaperVersion.java @@ -1,20 +1,15 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat; -import de.maxhenkel.voicechat.Version; import de.maxhenkel.voicechat.compatibility.ReflectionUtils; + +import javax.annotation.Nullable; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.Nullable; -public class PaperVersion -extends Version { +public class PaperVersion extends Version { + public static final Pattern PAPER_VERSION_REGEX = Pattern.compile("^(?\\d+)\\.(?\\d+)(?:\\.(?\\d+))?\\.(?.*)$"); + private final String build; public PaperVersion(int major, int minor, int patch, String build) { @@ -39,21 +34,24 @@ extends Version { @Nullable public static PaperVersion parsePaperVersion(String version) { - if (!PaperVersion.isPaper()) { + if (!isPaper()) { return null; } + Matcher targetMatcher = PAPER_VERSION_REGEX.matcher(version); + if (!targetMatcher.matches()) { return null; } + return PaperVersion.fromRegex(targetMatcher); } + @Override public String toString() { - if (this.patch <= 0) { - return this.major + "." + this.minor + "." + this.build; + if (patch <= 0) { + return major + "." + minor + "." + build; } - return this.major + "." + this.minor + "." + this.patch + "." + this.build; + return major + "." + minor + "." + patch + "." + build; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/Version.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/Version.java similarity index 59% rename from source/decompiled/de/maxhenkel/voicechat/Version.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/Version.java index 6c517e4..37bdda0 100644 --- a/source/decompiled/de/maxhenkel/voicechat/Version.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/Version.java @@ -1,18 +1,11 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.Bukkit - */ package de.maxhenkel.voicechat; -import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.PaperVersion; -import javax.annotation.Nullable; import org.bukkit.Bukkit; +import javax.annotation.Nullable; + public class Version { + protected final int major; protected final int minor; protected final int patch; @@ -34,43 +27,46 @@ public class Version { @Nullable public static Version getVersion() { - return Version.parse(Bukkit.getBukkitVersion()); + return parse(Bukkit.getBukkitVersion()); } public int getMajor() { - return this.major; + return major; } public int getMinor() { - return this.minor; + return minor; } public int getPatch() { - return this.patch; + return patch; } + @Override public boolean equals(Object o) { if (this == o) { return true; } - if (o == null || this.getClass() != o.getClass()) { + if (o == null || getClass() != o.getClass()) { return false; } - Version that = (Version)o; - if (this.major != that.major) { + + Version that = (Version) o; + + if (major != that.major) { return false; } - if (this.minor != that.minor) { + if (minor != that.minor) { return false; } - return this.patch == that.patch; + return patch == that.patch; } + @Override public int hashCode() { - int result = this.major; - result = 31 * result + this.minor; - result = 31 * result + this.patch; + int result = major; + result = 31 * result + minor; + result = 31 * result + patch; return result; } } - diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/Voicechat.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/Voicechat.java new file mode 100644 index 0000000..cb5588c --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/Voicechat.java @@ -0,0 +1,157 @@ +package de.maxhenkel.voicechat; + +import de.maxhenkel.configbuilder.ConfigBuilder; +import de.maxhenkel.voicechat.api.BukkitVoicechatService; +import de.maxhenkel.voicechat.command.VoiceChatCommands; +import de.maxhenkel.voicechat.compatibility.BukkitCompatibilityManager; +import de.maxhenkel.voicechat.compatibility.Compatibility; +import de.maxhenkel.voicechat.config.ServerConfig; +import de.maxhenkel.voicechat.config.Translations; +import de.maxhenkel.voicechat.integration.commodore.CommodoreCommands; +import de.maxhenkel.voicechat.integration.commodore.MissingArgumentTypeException; +import de.maxhenkel.voicechat.integration.placeholderapi.VoicechatExpansion; +import de.maxhenkel.voicechat.integration.viaversion.ViaVersionCompatibility; +import de.maxhenkel.voicechat.logging.JavaLoggingLogger; +import de.maxhenkel.voicechat.logging.VoicechatLogger; +import de.maxhenkel.voicechat.net.NetManager; +import de.maxhenkel.voicechat.plugins.PluginManager; +import de.maxhenkel.voicechat.plugins.impl.BukkitVoicechatServiceImpl; +import de.maxhenkel.voicechat.voice.server.ServerVoiceEvents; +import de.maxhenkel.voicechat.voice.server.ServerPlayerManager; +import me.lucko.commodore.Commodore; +import me.lucko.commodore.CommodoreProvider; +import org.bukkit.Bukkit; +import org.bukkit.command.PluginCommand; +import org.bukkit.plugin.ServicePriority; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.regex.Pattern; + +public final class Voicechat extends JavaPlugin { + + public static Voicechat INSTANCE; + + public static final String MODID = "voicechat"; + public static VoicechatLogger LOGGER; + + public static int COMPATIBILITY_VERSION = BuildConstants.COMPATIBILITY_VERSION; + + public static ServerConfig SERVER_CONFIG; + public static Translations TRANSLATIONS; + public static ServerVoiceEvents SERVER; + + public static BukkitVoicechatServiceImpl apiService; + public static NetManager netManager; + public static Compatibility compatibility; + + public static final int MAX_GROUP_NAME_LENGTH = 24; + public static final Pattern GROUP_REGEX = Pattern.compile("^[^\\p{C}\\s][^\\p{C}]{0,23}$"); + + @Override + public void onEnable() { + INSTANCE = this; + LOGGER = new JavaLoggingLogger(getLogger()); + + if (debugMode()) { + LOGGER.warn("Running in debug mode - Don't leave this enabled in production!"); + } + + try { + compatibility = BukkitCompatibilityManager.loadCompatibility(); + if (compatibility == null) { + disablePlugin(); + return; + } + } catch (Throwable t) { + LOGGER.fatal("An unexpected error occurred while loading compatibility", t); + disablePlugin(); + return; + } + + LOGGER.info("Compatibility version {}", COMPATIBILITY_VERSION); + + SERVER_CONFIG = ConfigBuilder.builder(ServerConfig::new).path(getDataFolder().toPath().resolve("voicechat-server.properties")).build(); + TRANSLATIONS = ConfigBuilder.builder(Translations::new).path(getDataFolder().toPath().resolve("translations.properties")).build(); + + netManager = new NetManager(); + netManager.onEnable(); + + apiService = new BukkitVoicechatServiceImpl(); + getServer().getServicesManager().register(BukkitVoicechatService.class, apiService, this, ServicePriority.Normal); + + PluginCommand voicechatCommand = getCommand(VoiceChatCommands.VOICECHAT_COMMAND); + if (voicechatCommand != null) { + VoiceChatCommands voiceChatCommands = new VoiceChatCommands(); + voicechatCommand.setExecutor(voiceChatCommands); + voicechatCommand.setTabCompleter(voiceChatCommands); + try { + if (CommodoreProvider.isSupported()) { + Commodore commodore = CommodoreProvider.getCommodore(this); + CommodoreCommands.registerCompletions(commodore); + LOGGER.info("Successfully initialized commodore command completion"); + } else { + LOGGER.warn("Commodore command completion is not supported"); + } + } catch (MissingArgumentTypeException t) { + LOGGER.warn("Failed to initialize commodore command completion: {}", t.getMessage()); + } catch (Throwable t) { + LOGGER.warn("Failed to initialize commodore command completion", t); + } + } else { + LOGGER.error("Failed to register commands"); + } + + try { + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { + new VoicechatExpansion().register(); + LOGGER.info("Successfully registered PlaceholderAPI expansion"); + } + } catch (Throwable t) { + LOGGER.error("Failed to register PlaceholderAPI expansion", t); + } + + try { + if (Bukkit.getPluginManager().getPlugin("ViaVersion") != null) { + ViaVersionCompatibility.register(); + LOGGER.info("Successfully added ViaVersion mappings"); + } + } catch (Throwable t) { + LOGGER.error("Failed to add ViaVersion mappings", t); + } + + if (System.getProperty("VOICECHAT_RELOADED") != null) { + LOGGER.error("{} does not support reloads! Expect that things will break!", BuildConstants.PLUGIN_NAME); + } + System.setProperty("VOICECHAT_RELOADED", "true"); + + compatibility.runTask(() -> { + SERVER = new ServerVoiceEvents(); + PluginManager.instance().init(); + SERVER.init(); + + Bukkit.getPluginManager().registerEvents(SERVER, this); + ServerPlayerManager.init(this); + }); + } + + private void disablePlugin() { + LOGGER.fatal("Disabling {}", BuildConstants.PLUGIN_NAME); + Bukkit.getPluginManager().disablePlugin(this); + } + + @Override + public void onDisable() { + if (netManager != null) { + netManager.onDisable(); + } + getServer().getServicesManager().unregister(apiService); + if (SERVER != null) { + SERVER.getServer().close(); + } + } + + public static boolean debugMode() { + return System.getProperty("voicechat.debug") != null; + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/command/VoiceChatCommands.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/command/VoiceChatCommands.java similarity index 70% rename from source/decompiled/de/maxhenkel/voicechat/command/VoiceChatCommands.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/command/VoiceChatCommands.java index 6d74d14..086a3d3 100644 --- a/source/decompiled/de/maxhenkel/voicechat/command/VoiceChatCommands.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/command/VoiceChatCommands.java @@ -1,16 +1,6 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.command.Command - * org.bukkit.command.CommandExecutor - * org.bukkit.command.CommandSender - * org.bukkit.command.TabCompleter - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.command; +import de.maxhenkel.voicechat.BuildConstants; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.net.NetManager; import de.maxhenkel.voicechat.permission.PermissionManager; @@ -19,72 +9,76 @@ import de.maxhenkel.voicechat.voice.server.ClientConnection; import de.maxhenkel.voicechat.voice.server.Group; import de.maxhenkel.voicechat.voice.server.PingManager; import de.maxhenkel.voicechat.voice.server.Server; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; -import javax.annotation.Nullable; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; import org.bukkit.entity.Player; -public class VoiceChatCommands -implements CommandExecutor, -TabCompleter { +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class VoiceChatCommands implements CommandExecutor, TabCompleter { + public static final String VOICECHAT_COMMAND = "voicechat"; + @Override public boolean onCommand(CommandSender commandSender, Command command, String label, String[] args) { - if (VoiceChatCommands.checkNoVoicechat(commandSender)) { + if (checkNoVoicechat(commandSender)) { return true; } if (!(commandSender instanceof Player)) { return true; } - Player sender = (Player)commandSender; + Player sender = (Player) commandSender; + if (args.length >= 1) { if (args[0].equalsIgnoreCase("help")) { - return this.helpCommand(sender, command, label, args); - } - if (args[0].equalsIgnoreCase("test")) { + return helpCommand(sender, command, label, args); + } else if (args[0].equalsIgnoreCase("test")) { if (commandSender.hasPermission(PermissionManager.ADMIN_PERMISSION)) { - return this.testCommand(sender, command, label, args); + return testCommand(sender, command, label, args); + } else { + return true; } - return true; - } - if (args[0].equalsIgnoreCase("invite")) { - return this.inviteCommand(sender, command, label, args); - } - if (args[0].equalsIgnoreCase("join")) { - return this.joinCommand(sender, command, label, args); - } - if (args[0].equalsIgnoreCase("leave")) { - return this.leaveCommand(sender, command, label, args); + } else if (args[0].equalsIgnoreCase("invite")) { + return inviteCommand(sender, command, label, args); + } else if (args[0].equalsIgnoreCase("join")) { + return joinCommand(sender, command, label, args); + } else if (args[0].equalsIgnoreCase("leave")) { + return leaveCommand(sender, command, label, args); } } - return this.helpCommand(sender, command, label, args); + return helpCommand(sender, command, label, args); } @Nullable + @Override public List onTabComplete(CommandSender commandSender, Command command, String label, String[] args) { - String arg; if (args.length == 1) { - return this.tabCompleteList(args[0], Arrays.asList("help", "test", "invite", "join", "leave")); + return tabCompleteList(args[0], Arrays.asList("help", "test", "invite", "join", "leave")); } + if (args.length == 2) { - arg = args[0]; + String arg = args[0]; if (arg.equals("test") || arg.equals("invite")) { return null; + } else if (arg.startsWith("join")) { + return Collections.emptyList(); } + } + + if (args.length == 3) { + String arg = args[0]; if (arg.startsWith("join")) { return Collections.emptyList(); } } - if (args.length == 3 && (arg = args[0]).startsWith("join")) { - return Collections.emptyList(); - } + return Collections.emptyList(); } @@ -101,31 +95,33 @@ TabCompleter { return true; } - private boolean testCommand(final Player commandSender, Command command, String label, String[] args) { + private boolean testCommand(Player commandSender, Command command, String label, String[] args) { if (args.length < 2) { return false; } - Player player = VoiceChatCommands.parsePlayer((CommandSender)commandSender, args[1]); + + Player player = parsePlayer(commandSender, args[1]); + if (player == null) { - NetManager.sendMessage(commandSender, "argument.entity.notfound.player", new String[0]); + NetManager.sendMessage(commandSender, "argument.entity.notfound.player"); return true; } + if (!Voicechat.SERVER.isCompatible(player)) { - NetManager.sendMessage(commandSender, "message.voicechat.player_no_voicechat", player.getDisplayName(), "Simple Voice Chat"); + NetManager.sendMessage(commandSender, "message.voicechat.player_no_voicechat", player.getDisplayName(), BuildConstants.PLUGIN_NAME); return true; } + ClientConnection clientConnection = Voicechat.SERVER.getServer().getConnections().get(player.getUniqueId()); + if (clientConnection == null) { - NetManager.sendMessage(commandSender, "message.voicechat.client_not_connected", new String[0]); + NetManager.sendMessage(commandSender, "message.voicechat.client_not_connected"); return true; } + try { - NetManager.sendMessage(commandSender, "message.voicechat.sending_ping", new String[0]); - Voicechat.SERVER.getServer().getPingManager().sendPing(clientConnection, 500L, 10, new PingManager.PingListener(){ - final /* synthetic */ VoiceChatCommands this$0; - { - this.this$0 = this$0; - } + NetManager.sendMessage(commandSender, "message.voicechat.sending_ping"); + Voicechat.SERVER.getServer().getPingManager().sendPing(clientConnection, 500, 10, new PingManager.PingListener() { @Override public void onPong(int attempts, long pingMilliseconds) { @@ -138,7 +134,7 @@ TabCompleter { @Override public void onFailedAttempt(int attempts) { - NetManager.sendMessage(commandSender, "message.voicechat.ping_retry", new String[0]); + NetManager.sendMessage(commandSender, "message.voicechat.ping_retry"); } @Override @@ -146,9 +142,8 @@ TabCompleter { NetManager.sendMessage(commandSender, "message.voicechat.ping_timed_out", String.valueOf(attempts)); } }); - NetManager.sendMessage(commandSender, "message.voicechat.ping_sent_waiting", new String[0]); - } - catch (Exception e) { + NetManager.sendMessage(commandSender, "message.voicechat.ping_sent_waiting"); + } catch (Exception e) { NetManager.sendMessage(commandSender, "message.voicechat.failed_to_send_ping", e.getMessage()); Voicechat.LOGGER.warn("Failed to send ping", e); } @@ -159,128 +154,156 @@ TabCompleter { if (args.length < 2) { return false; } - Player player = VoiceChatCommands.parsePlayer((CommandSender)commandSender, args[1]); + + Player player = parsePlayer(commandSender, args[1]); + if (player == null || !Voicechat.compatibility.canSee(commandSender, player)) { - NetManager.sendMessage(commandSender, "argument.entity.notfound.player", new String[0]); + NetManager.sendMessage(commandSender, "argument.entity.notfound.player"); return true; } + PlayerState state = Voicechat.SERVER.getServer().getPlayerStateManager().getState(commandSender.getUniqueId()); + if (state == null || !state.hasGroup()) { - NetManager.sendMessage(commandSender, "message.voicechat.not_in_group", new String[0]); + NetManager.sendMessage(commandSender, "message.voicechat.not_in_group"); return true; } + Group group = Voicechat.SERVER.getServer().getGroupManager().getGroup(state.getGroup()); if (group == null) { return true; } + if (!Voicechat.SERVER.isCompatible(player)) { - NetManager.sendMessage(commandSender, "message.voicechat.player_no_voicechat", player.getDisplayName(), "Simple Voice Chat"); + NetManager.sendMessage(commandSender, "message.voicechat.player_no_voicechat", player.getDisplayName(), BuildConstants.PLUGIN_NAME); return true; } + String passwordSuffix = group.getPassword() == null ? "" : " \"" + group.getPassword() + "\""; String cmd = "/voicechat join " + group.getId().toString() + passwordSuffix; Voicechat.compatibility.sendInviteMessage(player, commandSender, group.getName(), cmd); + NetManager.sendMessage(commandSender, "message.voicechat.invite_successful", player.getName()); + return true; } private boolean joinCommand(Player commandSender, Command command, String label, String[] args) { - UUID groupUUID; - int argIndex; if (args.length < 2) { return false; } + + int argIndex = 1; + UUID groupUUID; try { groupUUID = UUID.fromString(args[argIndex]); - } - catch (Exception e) { + } catch (Exception e) { String groupName; if (args[argIndex].startsWith("\"")) { - String[] split; StringBuilder sb = new StringBuilder(); - for (argIndex = 1; argIndex < args.length; ++argIndex) { + for (; argIndex < args.length; argIndex++) { sb.append(args[argIndex]).append(" "); - if (args[argIndex].endsWith("\"") && !args[argIndex].endsWith("\\\"")) break; + if (args[argIndex].endsWith("\"") && !args[argIndex].endsWith("\\\"")) { + break; + } } - if ((split = (groupName = sb.toString().trim()).split("\"")).length > 1) { + groupName = sb.toString().trim(); + String[] split = groupName.split("\""); + if (split.length > 1) { groupName = split[1]; } } else { groupName = args[argIndex]; } - groupUUID = this.getGroupUUID(commandSender, Voicechat.SERVER.getServer(), groupName); + groupUUID = getGroupUUID(commandSender, Voicechat.SERVER.getServer(), groupName); } + if (groupUUID == null) { return true; } + + argIndex++; + String password = null; - if (args.length >= ++argIndex + 1) { - String[] split; + if (args.length >= argIndex + 1) { StringBuilder sb = new StringBuilder(); - while (argIndex < args.length) { + for (; argIndex < args.length; argIndex++) { sb.append(args[argIndex]).append(" "); - ++argIndex; } password = sb.toString().trim(); - if (password.startsWith("\"") && (split = password.split("\"")).length > 1) { - password = split[1]; + if (password.startsWith("\"")) { + String[] split = password.split("\""); + if (split.length > 1) { + password = split[1]; + } } } - VoiceChatCommands.joinGroup(commandSender, groupUUID, password); + + joinGroup(commandSender, groupUUID, password); return true; } private UUID getGroupUUID(Player commandSender, Server server, String groupName) { - List groups = server.getGroupManager().getGroups().values().stream().filter(group -> group.getName().equals(groupName)).collect(Collectors.toList()); + List groups = server.getGroupManager().getGroups().values().stream().filter(group -> group.getName().equals(groupName)).collect(Collectors.toList()); + if (groups.isEmpty()) { - NetManager.sendMessage(commandSender, "message.voicechat.group_does_not_exist", new String[0]); + NetManager.sendMessage(commandSender, "message.voicechat.group_does_not_exist"); return null; } + if (groups.size() > 1) { - NetManager.sendMessage(commandSender, "message.voicechat.group_name_not_unique", new String[0]); + NetManager.sendMessage(commandSender, "message.voicechat.group_name_not_unique"); return null; } - return ((Group)groups.get(0)).getId(); + + return groups.get(0).getId(); } private static void joinGroup(Player commandSender, UUID groupID, @Nullable String password) { - if (!Voicechat.SERVER_CONFIG.groupsEnabled.get().booleanValue()) { - NetManager.sendMessage(commandSender, "message.voicechat.groups_disabled", new String[0]); + if (!Voicechat.SERVER_CONFIG.groupsEnabled.get()) { + NetManager.sendMessage(commandSender, "message.voicechat.groups_disabled"); return; } + Server server = Voicechat.SERVER.getServer(); + if (!commandSender.hasPermission(PermissionManager.GROUPS_PERMISSION)) { - NetManager.sendMessage(commandSender, "message.voicechat.no_group_permission", new String[0]); + NetManager.sendMessage(commandSender, "message.voicechat.no_group_permission"); return; } + Group group = server.getGroupManager().getGroup(groupID); + if (group == null) { - NetManager.sendMessage(commandSender, "message.voicechat.group_does_not_exist", new String[0]); + NetManager.sendMessage(commandSender, "message.voicechat.group_does_not_exist"); return; } + server.getGroupManager().joinGroup(group, commandSender, password); - NetManager.sendMessage(commandSender, "message.voicechat.join_successful", group.getName()); + NetManager.sendMessage(commandSender, "message.voicechat.join_successful", group.getName()); //TODO Make group name green } private boolean leaveCommand(Player commandSender, Command command, String label, String[] args) { - if (!Voicechat.SERVER_CONFIG.groupsEnabled.get().booleanValue()) { - NetManager.sendMessage(commandSender, "message.voicechat.groups_disabled", new String[0]); + if (!Voicechat.SERVER_CONFIG.groupsEnabled.get()) { + NetManager.sendMessage(commandSender, "message.voicechat.groups_disabled"); return true; } + Server server = Voicechat.SERVER.getServer(); PlayerState state = server.getPlayerStateManager().getState(commandSender.getUniqueId()); if (state == null || !state.hasGroup()) { - NetManager.sendMessage(commandSender, "message.voicechat.not_in_group", new String[0]); + NetManager.sendMessage(commandSender, "message.voicechat.not_in_group"); return true; } + server.getGroupManager().leaveGroup(commandSender); - NetManager.sendMessage(commandSender, "message.voicechat.leave_successful", new String[0]); + NetManager.sendMessage(commandSender, "message.voicechat.leave_successful"); return true; } private static boolean checkNoVoicechat(CommandSender commandSender) { if (commandSender instanceof Player) { - if (Voicechat.SERVER.isCompatible((Player)commandSender)) { + if (Voicechat.SERVER.isCompatible((Player) commandSender)) { return false; } commandSender.sendMessage(String.format(Voicechat.TRANSLATIONS.voicechatNeededForCommandMessage.get(), "Simple Voice Chat")); @@ -299,10 +322,8 @@ TabCompleter { try { UUID uuid = UUID.fromString(playerArg); return commandSender.getServer().getPlayer(uuid); - } - catch (IllegalArgumentException e) { + } catch (IllegalArgumentException e) { return null; } } -} - +} \ No newline at end of file diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/BaseCompatibility.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/BaseCompatibility.java new file mode 100644 index 0000000..056f2d4 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/BaseCompatibility.java @@ -0,0 +1,217 @@ +package de.maxhenkel.voicechat.compatibility; + +import de.maxhenkel.voicechat.Voicechat; +import de.maxhenkel.voicechat.util.Key; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.plugin.Plugin; + +import javax.annotation.Nullable; +import java.lang.reflect.Method; +import java.util.function.Consumer; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public abstract class BaseCompatibility implements Compatibility { + + private String baseBukkitPackage; + private String baseServerPackage; + + private Method addChannel; + private Method removeChannel; + @Nullable + private Class playerHideEntityEvent; + @Nullable + private Method playerHideEntityEventGetEntity; + @Nullable + private Class playerShowEntityEvent; + @Nullable + private Method playerShowEntityEventGetEntity; + private Consumer runTask; + private TaskScheduler taskScheduler; + + @Override + public void init() throws Exception { + Compatibility.super.init(); + + baseBukkitPackage = Bukkit.getServer().getClass().getPackage().getName(); + baseServerPackage = callMethod(Bukkit.getServer(), "getServer").getClass().getPackage().getName(); + + Class craftPlayer = getBukkitClass("entity.CraftPlayer"); + addChannel = getMethod(craftPlayer, new String[]{"addChannel"}, new Class[]{String.class}); + removeChannel = getMethod(craftPlayer, new String[]{"removeChannel"}, new Class[]{String.class}); + + try { + if (doesClassExist("org.bukkit.event.player.PlayerHideEntityEvent") && doesClassExist("org.bukkit.event.player.PlayerShowEntityEvent")) { + Class hide = ReflectionUtils.getClazz("org.bukkit.event.player.PlayerHideEntityEvent"); + if (!PlayerEvent.class.isAssignableFrom(hide)) { + throw new CompatibilityReflectionException("PlayerHideEntityEvent is not a subclass of PlayerEvent"); + } + + Class show = ReflectionUtils.getClazz("org.bukkit.event.player.PlayerShowEntityEvent"); + if (!PlayerEvent.class.isAssignableFrom(show)) { + throw new CompatibilityReflectionException("PlayerShowEntityEvent is not a subclass of PlayerEvent"); + } + playerShowEntityEventGetEntity = getMethod(show, "getEntity"); + playerHideEntityEventGetEntity = getMethod(hide, "getEntity"); + playerShowEntityEvent = (Class) show; + playerHideEntityEvent = (Class) hide; + } else { + Voicechat.LOGGER.warn("Vanish plugin integration is not supported"); + } + } catch (CompatibilityReflectionException e) { + Voicechat.LOGGER.warn("Vanish plugin integration is disabled"); + Voicechat.LOGGER.warn("Failed to load vanish compatibility", e); + playerHideEntityEvent = null; + playerShowEntityEvent = null; + } + + runTask = runnable -> Bukkit.getScheduler().runTask(Voicechat.INSTANCE, runnable); + taskScheduler = new TaskScheduler() { + @Override + public void scheduleSyncRepeatingTask(Runnable runnable, long delay, long period) { + Bukkit.getScheduler().scheduleSyncRepeatingTask(Voicechat.INSTANCE, runnable, delay, period); + } + + @Override + public void runTaskLater(Runnable runnable, long delay) { + Bukkit.getScheduler().runTaskLater(Voicechat.INSTANCE, runnable, delay); + } + }; + if (doesMethodExist(Bukkit.class, "getGlobalRegionScheduler")) { + Object globalRegionScheduler = callMethod(Bukkit.class, "getGlobalRegionScheduler"); + + Method run = getMethod(globalRegionScheduler.getClass(), new String[]{"run"}, new Class[]{Plugin.class, Consumer.class}); + runTask = runnable -> call(run, globalRegionScheduler, Voicechat.INSTANCE, (Consumer) (task) -> runnable.run()); + + if ( + doesMethodExist(globalRegionScheduler.getClass(), "runAtFixedRate", Plugin.class, Consumer.class, long.class, long.class) + && doesMethodExist(globalRegionScheduler.getClass(), "runDelayed", Plugin.class, Consumer.class, long.class) + ) { + Method runAtFixedRate = getMethod(globalRegionScheduler.getClass(), new String[]{"runAtFixedRate"}, new Class[]{Plugin.class, Consumer.class, long.class, long.class}); + Method runDelayed = getMethod(globalRegionScheduler.getClass(), new String[]{"runDelayed"}, new Class[]{Plugin.class, Consumer.class, long.class}); + taskScheduler = new TaskScheduler() { + @Override + public void scheduleSyncRepeatingTask(Runnable runnable, long delay, long period) { + call(runAtFixedRate, globalRegionScheduler, Voicechat.INSTANCE, (Consumer) (task) -> runnable.run(), delay <= 0 ? 1 : delay, period); + } + + @Override + public void runTaskLater(Runnable runnable, long delay) { + call(runDelayed, globalRegionScheduler, Voicechat.INSTANCE, (Consumer) (task) -> runnable.run(), delay <= 0 ? 1 : delay); + } + }; + } + } + } + + @Override + public void addChannel(Player player, String channel) { + call(addChannel, player, channel); + } + + @Override + public void removeChannel(Player player, String channel) { + call(removeChannel, player, channel); + } + + @Override + public Key createNamespacedKey(String key) { + return Key.of(key); + } + + @Override + public void runTask(Runnable runnable) { + runTask.accept(runnable); + } + + @Override + public void scheduleSyncRepeatingTask(Runnable runnable, long delay, long period) { + taskScheduler.scheduleSyncRepeatingTask(runnable, delay, period); + } + + @Override + public void runTaskLater(Runnable runnable, long delay) { + taskScheduler.runTaskLater(runnable, delay); + } + + @Override + public boolean canSee(Player player, Player other) { + if (playerHideEntityEvent == null || playerShowEntityEvent == null) { + // Don't use canSee if hide and show events are missing + // This avoids state desyncs on older versions that have canSee but not the events + return true; + } + return player.canSee(other); + } + + @Override + public void registerPlayerHideEvent(Consumer event) { + if (playerHideEntityEvent == null) { + return; + } + Bukkit.getPluginManager().registerEvent( + playerHideEntityEvent, + new Listener() { + }, + EventPriority.NORMAL, + (listener, evt) -> { + if (!evt.getClass().isAssignableFrom(playerHideEntityEvent)) { + return; + } + PlayerEvent playerEvent = (PlayerEvent) evt; + Object entityObj = call(playerHideEntityEventGetEntity, playerEvent); + if (!(entityObj instanceof Player)) { + return; + } + event.accept(new PlayerHideEvent((Player) entityObj, playerEvent.getPlayer())); + }, + Voicechat.INSTANCE + ); + } + + @Override + public void registerPlayerShowEvent(Consumer event) { + if (playerShowEntityEvent == null) { + return; + } + Bukkit.getPluginManager().registerEvent( + playerShowEntityEvent, + new Listener() { + }, + EventPriority.NORMAL, + (listener, evt) -> { + if (!evt.getClass().isAssignableFrom(playerShowEntityEvent)) { + return; + } + PlayerEvent playerEvent = (PlayerEvent) evt; + Object entityObj = call(playerShowEntityEventGetEntity, playerEvent); + if (!(entityObj instanceof Player)) { + return; + } + event.accept(new PlayerShowEvent((Player) entityObj, playerEvent.getPlayer())); + }, + Voicechat.INSTANCE + ); + } + + @Override + public String getBaseBukkitPackage() { + return baseBukkitPackage; + } + + @Override + public String getBaseServerPackage() { + return baseServerPackage; + } + + private interface TaskScheduler { + void scheduleSyncRepeatingTask(Runnable runnable, long delay, long period); + + void runTaskLater(Runnable runnable, long delay); + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/BukkitCompatibilityManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/BukkitCompatibilityManager.java similarity index 78% rename from source/decompiled/de/maxhenkel/voicechat/compatibility/BukkitCompatibilityManager.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/BukkitCompatibilityManager.java index 33b7e90..7fec88d 100644 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/BukkitCompatibilityManager.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/BukkitCompatibilityManager.java @@ -1,123 +1,16 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.Bukkit - */ package de.maxhenkel.voicechat.compatibility; import de.maxhenkel.voicechat.Version; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.compatibility.Compatibility; -import de.maxhenkel.voicechat.compatibility.Compatibility1_12; -import de.maxhenkel.voicechat.compatibility.Compatibility1_16; -import de.maxhenkel.voicechat.compatibility.Compatibility1_17; -import de.maxhenkel.voicechat.compatibility.Compatibility1_18; -import de.maxhenkel.voicechat.compatibility.Compatibility1_19; -import de.maxhenkel.voicechat.compatibility.Compatibility1_19_1; -import de.maxhenkel.voicechat.compatibility.Compatibility1_20; -import de.maxhenkel.voicechat.compatibility.Compatibility1_20_2; -import de.maxhenkel.voicechat.compatibility.Compatibility1_20_3; -import de.maxhenkel.voicechat.compatibility.Compatibility1_21_5; -import de.maxhenkel.voicechat.compatibility.Compatibility1_8; -import de.maxhenkel.voicechat.compatibility.CompatibilityReflectionException; -import de.maxhenkel.voicechat.compatibility.FallbackCompatibility; -import de.maxhenkel.voicechat.compatibility.SpigotCompatibility; -import java.util.HashMap; -import java.util.Map; -import javax.annotation.Nullable; import org.bukkit.Bukkit; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + public class BukkitCompatibilityManager { - private static final Map COMPATIBILITIES = new HashMap(); - @Nullable - public static Compatibility loadCompatibility() { - Version forcedVersion = BukkitCompatibilityManager.getForcedVersion(); - Version version = forcedVersion != null ? forcedVersion : Version.getVersion(); - if (version == null) { - Voicechat.LOGGER.info("Failed to parse version {}, trying to fall back to Spigot API compatibility mode", Bukkit.getBukkitVersion()); - return BukkitCompatibilityManager.tryLoadSpigot(); - } - Voicechat.LOGGER.info("Initializing compatibility for version {}", version); - if (version.getMajor() == 1 && version.getMinor() <= 7) { - Voicechat.LOGGER.fatal("You are running a server that's too old to be able to join with any voice chat client", new Object[0]); - return null; - } - Compatibility compatibility = COMPATIBILITIES.get(version); - if (compatibility != null) { - try { - compatibility.init(); - } - catch (Throwable t) { - compatibility = null; - Voicechat.LOGGER.warn("Failed to load compatibility for version {}", version, t); - } - } - if (compatibility == null) { - Voicechat.LOGGER.warn("Incompatible version {}, trying to fall back to Spigot API compatibility mode", version); - compatibility = BukkitCompatibilityManager.tryLoadSpigot(); - } - if (compatibility == null) { - compatibility = FallbackCompatibility.INSTANCE; - try { - compatibility.init(); - Voicechat.LOGGER.warn("Falling back to Bukkit compatibility mode, expect issues and lack of features", new Object[0]); - Voicechat.LOGGER.warn("Chat messages won't be translatable", new Object[0]); - } - catch (CompatibilityReflectionException e) { - compatibility = null; - Voicechat.LOGGER.warn("Failed to load Bukkit compatibility mode: {}", e.getMessage()); - } - catch (Throwable t) { - compatibility = null; - Voicechat.LOGGER.warn("Failed to load Bukkit compatibility mode", t); - } - } - if (compatibility == null) { - Voicechat.LOGGER.fatal("Could not load any compatibility for {}", version); - } - return compatibility; - } - - @Nullable - private static Compatibility tryLoadSpigot() { - if (!SpigotCompatibility.isSpigotCompatible()) { - Voicechat.LOGGER.warn("Spigot API not found", new Object[0]); - return null; - } - SpigotCompatibility compatibility = SpigotCompatibility.INSTANCE; - try { - compatibility.init(); - Voicechat.LOGGER.warn("Falling back to Spigot API compatibility mode, expect issues and lack of features", new Object[0]); - } - catch (CompatibilityReflectionException e) { - compatibility = null; - Voicechat.LOGGER.warn("Failed to load Spigot API compatibility mode: {}", e.getMessage()); - } - catch (Throwable t) { - compatibility = null; - Voicechat.LOGGER.warn("Failed to load Spigot API compatibility mode", t); - } - return compatibility; - } - - @Nullable - public static Version getForcedVersion() { - String property = System.getProperty("voicechat.compatibility"); - if (property == null) { - return null; - } - Version forcedVersion = Version.parse(property); - if (forcedVersion == null) { - Voicechat.LOGGER.warn("Failed to parse forced compatibility version: {}", property); - return null; - } - Voicechat.LOGGER.info("Forcing compatibility for {}", forcedVersion); - Voicechat.LOGGER.warn("Forcing version compatibility could lead to issues - use with caution!", new Object[0]); - return forcedVersion; - } + private static final Map COMPATIBILITIES = new HashMap<>(); static { COMPATIBILITIES.put(Compatibility1_21_5.VERSION_PAPER_26_3, Compatibility1_21_5.INSTANCE); @@ -169,5 +62,102 @@ public class BukkitCompatibilityManager { COMPATIBILITIES.put(Compatibility1_12.VERSION_1_12, Compatibility1_12.INSTANCE); COMPATIBILITIES.put(Compatibility1_8.VERSION_1_8_8, Compatibility1_8.INSTANCE); } -} + @Nullable + public static Compatibility loadCompatibility() { + Version version; + + Version forcedVersion = getForcedVersion(); + if (forcedVersion != null) { + version = forcedVersion; + } else { + version = Version.getVersion(); + } + + if (version == null) { + Voicechat.LOGGER.info("Failed to parse version {}, trying to fall back to Spigot API compatibility mode", Bukkit.getBukkitVersion()); + return tryLoadSpigot(); + } + + Voicechat.LOGGER.info("Initializing compatibility for version {}", version); + + if (version.getMajor() == 1 && version.getMinor() <= 7) { + Voicechat.LOGGER.fatal("You are running a server that's too old to be able to join with any voice chat client"); + return null; + } + + Compatibility compatibility = COMPATIBILITIES.get(version); + if (compatibility != null) { + try { + compatibility.init(); + } catch (Throwable t) { + compatibility = null; + Voicechat.LOGGER.warn("Failed to load compatibility for version {}", version, t); + } + } + if (compatibility == null) { + Voicechat.LOGGER.warn("Incompatible version {}, trying to fall back to Spigot API compatibility mode", version); + compatibility = tryLoadSpigot(); + } + + if (compatibility == null) { + compatibility = FallbackCompatibility.INSTANCE; + try { + compatibility.init(); + Voicechat.LOGGER.warn("Falling back to Bukkit compatibility mode, expect issues and lack of features"); + Voicechat.LOGGER.warn("Chat messages won't be translatable"); + } catch (CompatibilityReflectionException e) { + compatibility = null; + // Only log the message in case reflection fails + Voicechat.LOGGER.warn("Failed to load Bukkit compatibility mode: {}", e.getMessage()); + } catch (Throwable t) { + compatibility = null; + Voicechat.LOGGER.warn("Failed to load Bukkit compatibility mode", t); + } + } + + if (compatibility == null) { + Voicechat.LOGGER.fatal("Could not load any compatibility for {}", version); + } + + return compatibility; + } + + @Nullable + private static Compatibility tryLoadSpigot() { + if (!SpigotCompatibility.isSpigotCompatible()) { + Voicechat.LOGGER.warn("Spigot API not found"); + return null; + } + Compatibility compatibility = SpigotCompatibility.INSTANCE; + try { + compatibility.init(); + Voicechat.LOGGER.warn("Falling back to Spigot API compatibility mode, expect issues and lack of features"); + } catch (CompatibilityReflectionException e) { + compatibility = null; + // Only log the message in case reflection fails + Voicechat.LOGGER.warn("Failed to load Spigot API compatibility mode: {}", e.getMessage()); + } catch (Throwable t) { + compatibility = null; + Voicechat.LOGGER.warn("Failed to load Spigot API compatibility mode", t); + } + return compatibility; + } + + @Nullable + public static Version getForcedVersion() { + String property = System.getProperty("voicechat.compatibility"); + if (property == null) { + return null; + } + Version forcedVersion = Version.parse(property); + if (forcedVersion == null) { + Voicechat.LOGGER.warn("Failed to parse forced compatibility version: {}", property); + return null; + } + Voicechat.LOGGER.info("Forcing compatibility for {}", forcedVersion); + Voicechat.LOGGER.warn("Forcing version compatibility could lead to issues - use with caution!"); + return forcedVersion; + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility.java new file mode 100644 index 0000000..df2993d --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility.java @@ -0,0 +1,76 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import de.maxhenkel.voicechat.util.Key; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import java.util.function.Consumer; + +public interface Compatibility { + + default void init() throws Exception { + + } + + void addChannel(Player player, String channel); + + void removeChannel(Player player, String channel); + + Key createNamespacedKey(String key); + + void sendTranslationMessage(Player player, String key, String... args); + + void sendStatusMessage(Player player, String key, String... args); + + void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand); + + void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName); + + void runTask(Runnable runnable); + + void scheduleSyncRepeatingTask(Runnable runnable, long delay, long period); + + void runTaskLater(Runnable runnable, long delay); + + boolean canSee(Player player, Player other); + + void registerPlayerHideEvent(Consumer event); + + void registerPlayerShowEvent(Consumer event); + + @Nullable + ArgumentType playerArgument(); + + @Nullable + ArgumentType uuidArgument(); + + String getBaseBukkitPackage(); + + String getBaseServerPackage(); + + /** + * @param classNames the class names including the package name, starting after the bukkit the base package e.g. org.bukkit.craftbukkit.v1_20_R3.CraftServer would be CraftServer + * @return the class + */ + default Class getBukkitClass(String... classNames) { + for (String className : classNames) { + try { + return Class.forName(String.format("%s.%s", getBaseBukkitPackage(), className)); + } catch (Throwable ignored) { + } + } + throw new CompatibilityReflectionException(String.format("Could not find any of the following classes: %s", String.join(", ", classNames))); + } + + default Class getServerClass(String... classNames) { + for (String className : classNames) { + try { + return Class.forName(String.format("%s.%s", getBaseServerPackage(), className)); + } catch (Throwable ignored) { + } + } + throw new CompatibilityReflectionException(String.format("Could not find any of the following classes: %s", String.join(", ", classNames))); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_12.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_12.java new file mode 100644 index 0000000..95a2ace --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_12.java @@ -0,0 +1,82 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import de.maxhenkel.voicechat.BukkitVersion; +import de.maxhenkel.voicechat.util.Key; +import org.bukkit.entity.Player; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class Compatibility1_12 extends JsonMessageBaseCompatibility { + + public static final String CHANNEL = "vc"; + + public static final BukkitVersion VERSION_1_12_2 = BukkitVersion.parseBukkitVersion("1.12.2-R0.1"); + public static final BukkitVersion VERSION_1_12_1 = BukkitVersion.parseBukkitVersion("1.12.1-R0.1"); + public static final BukkitVersion VERSION_1_12 = BukkitVersion.parseBukkitVersion("1.12-R0.1"); + + public static final Compatibility1_12 INSTANCE = new Compatibility1_12(); + + @Override + public Key createNamespacedKey(String key) { + return Key.of(CHANNEL, key); + } + + @Override + public void sendJsonMessage(Player player, String json) { + Class chatMessageTypeClass = getServerClass("ChatMessageType"); + Object b = getField(chatMessageTypeClass, "CHAT"); + send(player, json, b); + } + + @Override + public void sendJsonStatusMessage(Player player, String json) { + Class chatMessageTypeClass = getServerClass("ChatMessageType"); + Object b = getField(chatMessageTypeClass, "GAME_INFO"); + send(player, json, b); + } + + @Override + public String createTranslationMessage(String key, String... args) { + return Compatibility1_8.constructTranslationMessage(key, args); + } + + @Override + public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { + sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); + } + + @Override + public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { + sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); + } + + @Override + public ArgumentType playerArgument() { + return null; + } + + @Override + public ArgumentType uuidArgument() { + return null; + } + + private void send(Player player, String json, Object chatMessageType) { + Object entityPlayer = callMethod(player, "getHandle"); + Object playerConnection = getField(entityPlayer, "playerConnection"); + Class packet = getServerClass("Packet"); + Class chatSerializer = getServerClass("IChatBaseComponent$ChatSerializer"); + + Class iChatBaseComponentClass = getServerClass("IChatBaseComponent"); + Object iChatBaseComponent = callMethod(chatSerializer, "a", new Class[]{String.class}, json); + + Class packetPlayOutChatClass = getServerClass("PacketPlayOutChat"); + + Class chatMessageTypeClass = getServerClass("ChatMessageType"); + + Object clientboundSystemChatPacket = callConstructor(packetPlayOutChatClass, new Class[]{iChatBaseComponentClass, chatMessageTypeClass}, iChatBaseComponent, chatMessageType); + + callMethod(playerConnection, "sendPacket", new Class[]{packet}, clientboundSystemChatPacket); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_16.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_16.java new file mode 100644 index 0000000..cdb4e86 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_16.java @@ -0,0 +1,84 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import de.maxhenkel.voicechat.BukkitVersion; +import org.bukkit.entity.Player; + +import java.util.UUID; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class Compatibility1_16 extends JsonMessageBaseCompatibility { + + public static final BukkitVersion VERSION_1_16_5 = BukkitVersion.parseBukkitVersion("1.16.5-R0.1"); + public static final BukkitVersion VERSION_1_16_4 = BukkitVersion.parseBukkitVersion("1.16.4-R0.1"); + public static final BukkitVersion VERSION_1_16_3 = BukkitVersion.parseBukkitVersion("1.16.3-R0.1"); + public static final BukkitVersion VERSION_1_16_2 = BukkitVersion.parseBukkitVersion("1.16.2-R0.1"); + public static final BukkitVersion VERSION_1_16_1 = BukkitVersion.parseBukkitVersion("1.16.1-R0.1"); + public static final BukkitVersion VERSION_1_16 = BukkitVersion.parseBukkitVersion("1.16-R0.1"); + + public static final Compatibility1_16 INSTANCE = new Compatibility1_16(); + + @Override + public void sendJsonMessage(Player player, String json) { + Class chatMessageTypeClass = getServerClass("ChatMessageType"); + Object b = getField(chatMessageTypeClass, "CHAT"); + send(player, json, b); + } + + @Override + public void sendJsonStatusMessage(Player player, String json) { + Class chatMessageTypeClass = getServerClass("ChatMessageType"); + Object b = getField(chatMessageTypeClass, "GAME_INFO"); + send(player, json, b); + } + + @Override + public String createTranslationMessage(String key, String... args) { + return Compatibility1_8.constructTranslationMessage(key, args); + } + + @Override + public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { + sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); + } + + @Override + public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { + sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); + } + + @Override + public ArgumentType playerArgument() { + Class argumentEntity = getServerClass("ArgumentEntity"); + return callMethod(argumentEntity, "c"); + } + + @Override + public ArgumentType uuidArgument() { + Class argumentEntity = getServerClass("ArgumentUUID"); + return callMethod(argumentEntity, "a"); + } + + private static final UUID NUL_UUID = new UUID(0L, 0L); + + private void send(Player player, String json, Object chatMessageType) { + Object entityPlayer = callMethod(player, "getHandle"); + Object playerConnection = getField(entityPlayer, "playerConnection"); + Class packet = getServerClass("Packet"); + Class chatSerializer = getServerClass("IChatBaseComponent$ChatSerializer"); + + Class iChatBaseComponentClass = getServerClass("IChatBaseComponent"); + + Object iChatBaseComponent = callMethod(chatSerializer, "a", new Class[]{String.class}, json); + + Class packetPlayOutChatClass = getServerClass("PacketPlayOutChat"); + + Class chatMessageTypeClass = getServerClass("ChatMessageType"); + + Object clientboundSystemChatPacket = callConstructor(packetPlayOutChatClass, new Class[]{iChatBaseComponentClass, chatMessageTypeClass, UUID.class}, iChatBaseComponent, chatMessageType, NUL_UUID); + + callMethod(playerConnection, "sendPacket", new Class[]{packet}, clientboundSystemChatPacket); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_17.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_17.java new file mode 100644 index 0000000..a14acfa --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_17.java @@ -0,0 +1,77 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import de.maxhenkel.voicechat.BukkitVersion; +import org.bukkit.entity.Player; + +import java.util.UUID; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class Compatibility1_17 extends JsonMessageBaseCompatibility { + + public static final BukkitVersion VERSION_1_17_1 = BukkitVersion.parseBukkitVersion("1.17.1-R0.1"); + public static final BukkitVersion VERSION_1_17 = BukkitVersion.parseBukkitVersion("1.17-R0.1"); + + public static final Compatibility1_17 INSTANCE = new Compatibility1_17(); + + @Override + public void sendJsonMessage(Player player, String json) { + Class chatMessageTypeClass = getClazz("net.minecraft.network.chat.ChatMessageType"); + Object b = getField(chatMessageTypeClass, "b"); + send(player, json, b); + } + + @Override + public void sendJsonStatusMessage(Player player, String json) { + Class chatMessageTypeClass = getClazz("net.minecraft.network.chat.ChatMessageType"); + Object b = getField(chatMessageTypeClass, "c"); + send(player, json, b); + } + + @Override + public String createTranslationMessage(String key, String... args) { + return Compatibility1_8.constructTranslationMessage(key, args); + } + + @Override + public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { + sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); + } + + @Override + public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { + sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); + } + + @Override + public ArgumentType playerArgument() { + return Compatibility1_19.INSTANCE.playerArgument(); + } + + @Override + public ArgumentType uuidArgument() { + return Compatibility1_19.INSTANCE.uuidArgument(); + } + + private static final UUID NUL_UUID = new UUID(0L, 0L); + + private void send(Player player, String json, Object chatMessageType) { + Object entityPlayer = callMethod(player, "getHandle"); + Object playerConnection = getField(entityPlayer, "b"); + Class packet = getClazz("net.minecraft.network.protocol.Packet"); + Class craftChatMessage = getBukkitClass("util.CraftChatMessage"); + + Class iChatBaseComponentClass = getClazz("net.minecraft.network.chat.IChatBaseComponent"); + Object iChatBaseComponent = callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); + + Class packetPlayOutChatClass = getClazz("net.minecraft.network.protocol.game.PacketPlayOutChat"); + + Class chatMessageTypeClass = getClazz("net.minecraft.network.chat.ChatMessageType"); + + Object clientboundSystemChatPacket = callConstructor(packetPlayOutChatClass, new Class[]{iChatBaseComponentClass, chatMessageTypeClass, UUID.class}, iChatBaseComponent, chatMessageType, NUL_UUID); + + callMethod(playerConnection, "sendPacket", new Class[]{packet}, clientboundSystemChatPacket); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_18.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_18.java new file mode 100644 index 0000000..d3dcf0c --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_18.java @@ -0,0 +1,78 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import de.maxhenkel.voicechat.BukkitVersion; +import org.bukkit.entity.Player; + +import java.util.UUID; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class Compatibility1_18 extends JsonMessageBaseCompatibility { + + public static final BukkitVersion VERSION_1_18_2 = BukkitVersion.parseBukkitVersion("1.18.2-R0.1"); + public static final BukkitVersion VERSION_1_18_1 = BukkitVersion.parseBukkitVersion("1.18.1-R0.1"); + public static final BukkitVersion VERSION_1_18 = BukkitVersion.parseBukkitVersion("1.18-R0.1"); + + public static final Compatibility1_18 INSTANCE = new Compatibility1_18(); + + @Override + public void sendJsonMessage(Player player, String json) { + Class chatMessageTypeClass = getClazz("net.minecraft.network.chat.ChatMessageType"); + Object b = getField(chatMessageTypeClass, "b"); + send(player, json, b); + } + + @Override + public void sendJsonStatusMessage(Player player, String json) { + Class chatMessageTypeClass = getClazz("net.minecraft.network.chat.ChatMessageType"); + Object b = getField(chatMessageTypeClass, "c"); + send(player, json, b); + } + + @Override + public String createTranslationMessage(String key, String... args) { + return Compatibility1_8.constructTranslationMessage(key, args); + } + + @Override + public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { + sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); + } + + @Override + public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { + sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); + } + + @Override + public ArgumentType playerArgument() { + return Compatibility1_19.INSTANCE.playerArgument(); + } + + @Override + public ArgumentType uuidArgument() { + return Compatibility1_19.INSTANCE.uuidArgument(); + } + + private static final UUID NUL_UUID = new UUID(0L, 0L); + + private void send(Player player, String json, Object chatMessageType) { + Object entityPlayer = callMethod(player, "getHandle"); + Object playerConnection = getField(entityPlayer, "b"); + Class packet = getClazz("net.minecraft.network.protocol.Packet"); + Class craftChatMessage = getBukkitClass("util.CraftChatMessage"); + + Class iChatBaseComponentClass = getClazz("net.minecraft.network.chat.IChatBaseComponent"); + Object iChatBaseComponent = callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); + + Class packetPlayOutChatClass = getClazz("net.minecraft.network.protocol.game.PacketPlayOutChat"); + + Class chatMessageTypeClass = getClazz("net.minecraft.network.chat.ChatMessageType"); + + Object clientboundSystemChatPacket = callConstructor(packetPlayOutChatClass, new Class[]{iChatBaseComponentClass, chatMessageTypeClass, UUID.class}, iChatBaseComponent, chatMessageType, NUL_UUID); + + callMethod(playerConnection, "a", new Class[]{packet}, clientboundSystemChatPacket); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_19.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_19.java new file mode 100644 index 0000000..82f603a --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_19.java @@ -0,0 +1,91 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import de.maxhenkel.voicechat.BukkitVersion; +import org.bukkit.entity.Player; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class Compatibility1_19 extends JsonMessageBaseCompatibility { + + public static final BukkitVersion VERSION_1_19 = BukkitVersion.parseBukkitVersion("1.19-R0.1"); + + public static final Compatibility1_19 INSTANCE = new Compatibility1_19(); + + @Override + public void sendJsonMessage(Player player, String json) { + send(player, json, false); + } + + @Override + public void sendJsonStatusMessage(Player player, String json) { + send(player, json, true); + } + + @Override + public String createTranslationMessage(String key, String... args) { + return Compatibility1_8.constructTranslationMessage(key, args); + } + + @Override + public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { + sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); + } + + @Override + public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { + sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); + } + + @Override + public ArgumentType playerArgument() { + return Compatibility1_19_1.INSTANCE.playerArgument(); + } + + @Override + public ArgumentType uuidArgument() { + return Compatibility1_19_1.INSTANCE.uuidArgument(); + } + + private void send(Player player, String json, boolean status) { + Object entityPlayer = callMethod(player, "getHandle"); + Object playerConnection = getField(entityPlayer, "b"); + Class packet = getClazz("net.minecraft.network.protocol.Packet"); + Class craftChatMessage = getBukkitClass("util.CraftChatMessage"); + + Class iChatBaseComponentClass = getClazz("net.minecraft.network.chat.IChatBaseComponent"); + Object iChatBaseComponent = callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); + + Class clientboundSystemChatPacketClass = getClazz("net.minecraft.network.protocol.game.ClientboundSystemChatPacket"); + + Object clientboundSystemChatPacket = callConstructor(clientboundSystemChatPacketClass, new Class[]{iChatBaseComponentClass, int.class}, iChatBaseComponent, getId(player, status)); + + callMethod(playerConnection, "a", new Class[]{packet}, clientboundSystemChatPacket); + } + + private int getId(Player player, boolean status) { + Object world = callMethod(player.getWorld(), "getHandle"); + Class iRegistryCustomClass = getClazz("net.minecraft.core.IRegistryCustom"); + Object iRegistryCustom = callMethod(world, "s"); + + Class resourceKeyClass = getClazz("net.minecraft.resources.ResourceKey"); + + Class iRegistry = getClazz("net.minecraft.core.IRegistry"); + Object resourceKey = getField(iRegistry, "bI"); + + Object registry = callMethod(iRegistryCustomClass, iRegistryCustom, "d", new Class[]{resourceKeyClass}, resourceKey); + + Class chatMessageTypeClass = getClazz("net.minecraft.network.chat.ChatMessageType"); + Object chatMessageType; + if (status) { + chatMessageType = getField(chatMessageTypeClass, "d"); + } else { + chatMessageType = getField(chatMessageTypeClass, "c"); + } + + Object messageType = callMethod(registry, "a", new Class[]{resourceKeyClass}, chatMessageType); + + return callMethod(registry, "a", new Class[]{Object.class}, messageType); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_19_1.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_19_1.java new file mode 100644 index 0000000..6ea4be7 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_19_1.java @@ -0,0 +1,71 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import de.maxhenkel.voicechat.BukkitVersion; +import org.bukkit.entity.Player; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class Compatibility1_19_1 extends JsonMessageBaseCompatibility { + + public static final BukkitVersion VERSION_1_19_4 = BukkitVersion.parseBukkitVersion("1.19.4-R0.1"); + public static final BukkitVersion VERSION_1_19_3 = BukkitVersion.parseBukkitVersion("1.19.3-R0.1"); + public static final BukkitVersion VERSION_1_19_2 = BukkitVersion.parseBukkitVersion("1.19.2-R0.1"); + public static final BukkitVersion VERSION_1_19_1 = BukkitVersion.parseBukkitVersion("1.19.1-R0.1"); + + public static final Compatibility1_19_1 INSTANCE = new Compatibility1_19_1(); + + @Override + public void sendJsonMessage(Player player, String json) { + send(player, json, false); + } + + @Override + public void sendJsonStatusMessage(Player player, String json) { + send(player, json, true); + } + + @Override + public String createTranslationMessage(String key, String... args) { + return Compatibility1_8.constructTranslationMessage(key, args); + } + + @Override + public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { + sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); + } + + @Override + public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { + sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); + } + + @Override + public ArgumentType playerArgument() { + Class argumentEntity = getClazz("net.minecraft.commands.arguments.ArgumentEntity"); + return callMethod(argumentEntity, "c"); + } + + @Override + public ArgumentType uuidArgument() { + Class argumentEntity = getClazz("net.minecraft.commands.arguments.ArgumentUUID"); + return callMethod(argumentEntity, "a"); + } + + private void send(Player player, String json, boolean status) { + Object entityPlayer = callMethod(player, "getHandle"); + Object playerConnection = getField(entityPlayer, "b"); + Class packet = getClazz("net.minecraft.network.protocol.Packet"); + Class craftChatMessage = getBukkitClass("util.CraftChatMessage"); + + Class iChatBaseComponentClass = getClazz("net.minecraft.network.chat.IChatBaseComponent"); + Object iChatBaseComponent = callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); + + Class clientboundSystemChatPacketClass = getClazz("net.minecraft.network.protocol.game.ClientboundSystemChatPacket"); + + Object clientboundSystemChatPacket = callConstructor(clientboundSystemChatPacketClass, new Class[]{iChatBaseComponentClass, boolean.class}, iChatBaseComponent, status); + + callMethod(playerConnection, "a", new Class[]{packet}, clientboundSystemChatPacket); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20.java new file mode 100644 index 0000000..0a74585 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20.java @@ -0,0 +1,69 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import de.maxhenkel.voicechat.BukkitVersion; +import org.bukkit.entity.Player; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class Compatibility1_20 extends JsonMessageBaseCompatibility { + + public static final BukkitVersion VERSION_1_20 = BukkitVersion.parseBukkitVersion("1.20-R0.1"); + public static final BukkitVersion VERSION_1_20_1 = BukkitVersion.parseBukkitVersion("1.20.1-R0.1"); + + public static final Compatibility1_20 INSTANCE = new Compatibility1_20(); + + @Override + public void sendJsonMessage(Player player, String json) { + send(player, json, false); + } + + @Override + public void sendJsonStatusMessage(Player player, String json) { + send(player, json, true); + } + + @Override + public String createTranslationMessage(String key, String... args) { + return Compatibility1_8.constructTranslationMessage(key, args); + } + + @Override + public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { + sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); + } + + @Override + public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { + sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); + } + + @Override + public ArgumentType playerArgument() { + Class argumentEntity = getClazz("net.minecraft.commands.arguments.ArgumentEntity"); + return callMethod(argumentEntity, "c"); + } + + @Override + public ArgumentType uuidArgument() { + Class argumentEntity = getClazz("net.minecraft.commands.arguments.ArgumentUUID"); + return callMethod(argumentEntity, "a"); + } + + private void send(Player player, String json, boolean status) { + Object entityPlayer = callMethod(player, "getHandle"); + Object playerConnection = getField(entityPlayer, "c"); + Class packet = getClazz("net.minecraft.network.protocol.Packet"); + Class craftChatMessage = getBukkitClass("util.CraftChatMessage"); + + Class iChatBaseComponentClass = getClazz("net.minecraft.network.chat.IChatBaseComponent"); + Object iChatBaseComponent = callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); + + Class clientboundSystemChatPacketClass = getClazz("net.minecraft.network.protocol.game.ClientboundSystemChatPacket"); + + Object clientboundSystemChatPacket = callConstructor(clientboundSystemChatPacketClass, new Class[]{iChatBaseComponentClass, boolean.class}, iChatBaseComponent, status); + + callMethod(playerConnection, "a", new Class[]{packet}, clientboundSystemChatPacket); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20_2.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20_2.java new file mode 100644 index 0000000..ce11b0b --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20_2.java @@ -0,0 +1,60 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import de.maxhenkel.voicechat.BukkitVersion; +import org.bukkit.entity.Player; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class Compatibility1_20_2 extends JsonMessageBaseCompatibility { + + public static final BukkitVersion VERSION_1_20_2 = BukkitVersion.parseBukkitVersion("1.20.2-R0.1"); + + public static final Compatibility1_20_2 INSTANCE = new Compatibility1_20_2(); + + @Override + public void sendJsonMessage(Player player, String json) { + send(player, json, false); + } + + @Override + public void sendJsonStatusMessage(Player player, String json) { + send(player, json, true); + } + + @Override + public String createTranslationMessage(String key, String... args) { + return Compatibility1_8.constructTranslationMessage(key, args); + } + + @Override + public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { + sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); + } + + @Override + public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { + sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); + } + + @Override + public ArgumentType playerArgument() { + Class argumentEntity = getClazz("net.minecraft.commands.arguments.ArgumentEntity"); + return callMethod(argumentEntity, "c"); + } + + @Override + public ArgumentType uuidArgument() { + Class argumentEntity = getClazz("net.minecraft.commands.arguments.ArgumentUUID"); + return callMethod(argumentEntity, "a"); + } + + private void send(Player player, String json, boolean status) { + Object entityPlayer = callMethod(player, "getHandle"); + Class iChatBaseComponentClass = getClazz("net.minecraft.network.chat.IChatBaseComponent"); + Class craftChatMessage = getBukkitClass("util.CraftChatMessage"); + Object iChatBaseComponent = callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); + callMethod(entityPlayer, "a", new Class[]{iChatBaseComponentClass, boolean.class}, iChatBaseComponent, status); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20_3.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20_3.java new file mode 100644 index 0000000..f5b7106 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_20_3.java @@ -0,0 +1,97 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import de.maxhenkel.voicechat.BukkitVersion; +import org.bukkit.entity.Player; + +import java.lang.reflect.Method; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class Compatibility1_20_3 extends JsonMessageBaseCompatibility { + + public static final BukkitVersion VERSION_1_20_3 = BukkitVersion.parseBukkitVersion("1.20.3-R0.1"); + public static final BukkitVersion VERSION_1_20_4 = BukkitVersion.parseBukkitVersion("1.20.4-R0.1"); + public static final BukkitVersion VERSION_1_20_5 = BukkitVersion.parseBukkitVersion("1.20.5-R0.1"); + public static final BukkitVersion VERSION_1_20_6 = BukkitVersion.parseBukkitVersion("1.20.6-R0.1"); + public static final BukkitVersion VERSION_1_21 = BukkitVersion.parseBukkitVersion("1.21-R0.1"); + public static final BukkitVersion VERSION_1_21_1 = BukkitVersion.parseBukkitVersion("1.21.1-R0.1"); + public static final BukkitVersion VERSION_1_21_2 = BukkitVersion.parseBukkitVersion("1.21.2-R0.1"); + public static final BukkitVersion VERSION_1_21_3 = BukkitVersion.parseBukkitVersion("1.21.3-R0.1"); + public static final BukkitVersion VERSION_1_21_4 = BukkitVersion.parseBukkitVersion("1.21.4-R0.1"); + + public static final Compatibility1_20_3 INSTANCE = new Compatibility1_20_3(); + + private Method playerArgument; + private Method uuidArgument; + private Method fromJson; + private Method getHandle; + private Method sendSystemMessage; + + public void init() throws Exception { + super.init(); + + Class argumentEntityClass = getClazz( + "net.minecraft.commands.arguments.ArgumentEntity", + "net.minecraft.commands.arguments.EntityArgument" + ); + playerArgument = getMethod(argumentEntityClass, "c", "entity"); + + Class argumentUuidClass = getClazz( + "net.minecraft.commands.arguments.ArgumentUUID", + "net.minecraft.commands.arguments.UuidArgument" + ); + uuidArgument = getMethod(argumentUuidClass, "a", "uuid"); + + Class craftPlayer = getBukkitClass("entity.CraftPlayer"); + getHandle = getMethod(craftPlayer, "getHandle"); + Class componentClass = getClazz( + "net.minecraft.network.chat.IChatBaseComponent", + "net.minecraft.network.chat.Component" + ); + Class craftChatMessageClass = getBukkitClass("util.CraftChatMessage"); + fromJson = getMethod(craftChatMessageClass, new String[]{"fromJSON"}, new Class[]{String.class}); + Class player = getClazz("net.minecraft.server.level.EntityPlayer", "net.minecraft.server.level.ServerPlayer"); + sendSystemMessage = getMethod(player, new String[]{"a", "sendSystemMessage"}, new Class[]{componentClass, boolean.class}); + } + + @Override + public void sendJsonMessage(Player player, String json) { + send(player, json, false); + } + + @Override + public void sendJsonStatusMessage(Player player, String json) { + send(player, json, true); + } + + @Override + public String createTranslationMessage(String key, String... args) { + return Compatibility1_8.constructTranslationMessage(key, args); + } + + @Override + public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { + sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); + } + + @Override + public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { + sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); + } + + @Override + public ArgumentType playerArgument() { + return call(playerArgument, null); + } + + @Override + public ArgumentType uuidArgument() { + return call(uuidArgument, null); + } + + protected void send(Player player, String json, boolean status) { + call(sendSystemMessage, call(getHandle, player), call(fromJson, null, json), status); + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_21_5.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_21_5.java similarity index 88% rename from source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_21_5.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_21_5.java index 76588af..ec2a68e 100644 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_21_5.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_21_5.java @@ -1,20 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.compatibility; import de.maxhenkel.voicechat.BukkitVersion; import de.maxhenkel.voicechat.PaperVersion; -import de.maxhenkel.voicechat.compatibility.Compatibility1_20_3; -import de.maxhenkel.voicechat.org.json.JSONArray; -import de.maxhenkel.voicechat.org.json.JSONObject; import org.bukkit.entity.Player; +import org.json.JSONArray; +import org.json.JSONObject; + +public class Compatibility1_21_5 extends Compatibility1_20_3 { -public class Compatibility1_21_5 -extends Compatibility1_20_3 { public static final BukkitVersion VERSION_1_21_5 = BukkitVersion.parseBukkitVersion("1.21.5-R0.1"); public static final BukkitVersion VERSION_1_21_6 = BukkitVersion.parseBukkitVersion("1.21.6-R0.1"); public static final BukkitVersion VERSION_1_21_7 = BukkitVersion.parseBukkitVersion("1.21.7-R0.1"); @@ -31,43 +24,55 @@ extends Compatibility1_20_3 { public static final PaperVersion VERSION_PAPER_26_2 = PaperVersion.parsePaperVersion("26.2.build.0"); public static final BukkitVersion VERSION_26_3 = BukkitVersion.parseBukkitVersion("26.3-R0.1"); public static final PaperVersion VERSION_PAPER_26_3 = PaperVersion.parsePaperVersion("26.3.build.0"); + public static final Compatibility1_21_5 INSTANCE = new Compatibility1_21_5(); @Override public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_21_5.constructInviteMessage(commandSender, groupName, joinCommand)); + sendJsonMessage(player, constructInviteMessage(commandSender, groupName, joinCommand)); } public static String constructInviteMessage(Player commandSender, String groupName, String joinCommand) { JSONObject msg = new JSONObject(); msg.put("translate", "message.voicechat.invite"); + JSONArray args = new JSONArray(); + args.put(commandSender.getName()); + JSONObject groupNameObj = new JSONObject(); groupNameObj.put("color", "gray"); groupNameObj.put("text", groupName); args.put(groupNameObj); + JSONObject acceptInBrackets = new JSONObject(); acceptInBrackets.put("translate", "chat.square_brackets"); acceptInBrackets.put("color", "green"); JSONArray withBrackets = new JSONArray(); + JSONObject accept = new JSONObject(); accept.put("translate", "message.voicechat.accept_invite"); + JSONObject clickEvent = new JSONObject(); clickEvent.put("action", "run_command"); clickEvent.put("command", joinCommand); accept.put("click_event", clickEvent); + JSONObject hoverEvent = new JSONObject(); hoverEvent.put("action", "show_text"); JSONObject contents = new JSONObject(); contents.put("translate", "message.voicechat.accept_invite.hover"); hoverEvent.put("value", contents); accept.put("hover_event", hoverEvent); + withBrackets.put(accept); + acceptInBrackets.put("with", withBrackets); args.put(acceptInBrackets); + msg.put("with", args); + return msg.toString(); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_8.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_8.java similarity index 64% rename from source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_8.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_8.java index afecbcc..0240a7d 100644 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_8.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/Compatibility1_8.java @@ -1,47 +1,41 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.compatibility; import com.mojang.brigadier.arguments.ArgumentType; import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.compatibility.JsonMessageBaseCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import de.maxhenkel.voicechat.org.json.JSONArray; -import de.maxhenkel.voicechat.org.json.JSONObject; import de.maxhenkel.voicechat.util.Key; import org.bukkit.entity.Player; +import org.json.JSONArray; +import org.json.JSONObject; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class Compatibility1_8 extends JsonMessageBaseCompatibility { -public class Compatibility1_8 -extends JsonMessageBaseCompatibility { public static final BukkitVersion VERSION_1_8_8 = BukkitVersion.parseBukkitVersion("1.8.8-R0.1"); + public static final Compatibility1_8 INSTANCE = new Compatibility1_8(); @Override public Key createNamespacedKey(String key) { - return Key.of("vc", key); + return Key.of(Compatibility1_12.CHANNEL, key); } @Override public void sendJsonMessage(Player player, String json) { - this.send(player, json, (byte)0); + send(player, json, (byte) 0); } @Override public void sendJsonStatusMessage(Player player, String json) { - this.send(player, json, (byte)2); + send(player, json, (byte) 2); } @Override - public String createTranslationMessage(String key, String ... args) { - return Compatibility1_8.constructTranslationMessage(key, args); + public String createTranslationMessage(String key, String... args) { + return constructTranslationMessage(key, args); } - public static String constructTranslationMessage(String key, String ... args) { + public static String constructTranslationMessage(String key, String... args) { JSONObject msg = new JSONObject(); msg.put("translate", key); msg.put("with", args); @@ -50,45 +44,56 @@ extends JsonMessageBaseCompatibility { @Override public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); + sendJsonMessage(player, constructInviteMessage(commandSender, groupName, joinCommand)); } @Override public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); + sendJsonMessage(player, constructIncompatibleMessage(pluginVersion, pluginName)); } public static String constructInviteMessage(Player commandSender, String groupName, String joinCommand) { JSONObject msg = new JSONObject(); msg.put("translate", "message.voicechat.invite"); + JSONArray args = new JSONArray(); + args.put(commandSender.getName()); + JSONObject groupNameObj = new JSONObject(); groupNameObj.put("color", "gray"); groupNameObj.put("text", groupName); args.put(groupNameObj); + JSONObject acceptInBrackets = new JSONObject(); acceptInBrackets.put("text", "["); acceptInBrackets.put("color", "green"); JSONArray extra = new JSONArray(); + JSONObject accept = new JSONObject(); accept.put("translate", "message.voicechat.accept_invite"); accept.put("color", "green"); + JSONObject clickEvent = new JSONObject(); clickEvent.put("action", "run_command"); clickEvent.put("value", joinCommand); accept.put("clickEvent", clickEvent); + JSONObject hoverEvent = new JSONObject(); hoverEvent.put("action", "show_text"); JSONObject contents = new JSONObject(); contents.put("translate", "message.voicechat.accept_invite.hover"); hoverEvent.put("contents", contents); accept.put("hoverEvent", hoverEvent); + extra.put(accept); extra.put("]"); + acceptInBrackets.put("extra", extra); args.put(acceptInBrackets); + msg.put("with", args); + return msg.toString(); } @@ -96,14 +101,17 @@ extends JsonMessageBaseCompatibility { JSONObject msg = new JSONObject(); msg.put("translate", "message.voicechat.incompatible_version"); JSONArray with = new JSONArray(); + JSONObject version = new JSONObject(); version.put("text", pluginVersion); version.put("bold", true); with.put(version); + JSONObject name = new JSONObject(); name.put("text", pluginName); name.put("bold", true); with.put(name); + msg.put("with", with); return msg.toString(); } @@ -119,15 +127,19 @@ extends JsonMessageBaseCompatibility { } private void send(Player player, String json, byte chatMessageType) { - Object entityPlayer = ReflectionUtils.callMethod((Object)player, "getHandle"); - Object playerConnection = ReflectionUtils.getField(entityPlayer, "playerConnection"); - Class packet = this.getServerClass("Packet"); - Class chatSerializer = this.getServerClass("IChatBaseComponent$ChatSerializer"); - Class iChatBaseComponentClass = this.getServerClass("IChatBaseComponent"); - Object iChatBaseComponent = ReflectionUtils.callMethod(chatSerializer, "a", new Class[]{String.class}, json); - Class packetPlayOutChatClass = this.getServerClass("PacketPlayOutChat"); - Object clientboundSystemChatPacket = ReflectionUtils.callConstructor(packetPlayOutChatClass, new Class[]{iChatBaseComponentClass, Byte.TYPE}, iChatBaseComponent, chatMessageType); - ReflectionUtils.callMethod(playerConnection, "sendPacket", new Class[]{packet}, clientboundSystemChatPacket); - } -} + Object entityPlayer = callMethod(player, "getHandle"); + Object playerConnection = getField(entityPlayer, "playerConnection"); + Class packet = getServerClass("Packet"); + Class chatSerializer = getServerClass("IChatBaseComponent$ChatSerializer"); + Class iChatBaseComponentClass = getServerClass("IChatBaseComponent"); + Object iChatBaseComponent = callMethod(chatSerializer, "a", new Class[]{String.class}, json); + + Class packetPlayOutChatClass = getServerClass("PacketPlayOutChat"); + + Object clientboundSystemChatPacket = callConstructor(packetPlayOutChatClass, new Class[]{iChatBaseComponentClass, byte.class}, iChatBaseComponent, chatMessageType); + + callMethod(playerConnection, "sendPacket", new Class[]{packet}, clientboundSystemChatPacket); + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/CompatibilityReflectionException.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/CompatibilityReflectionException.java similarity index 70% rename from source/decompiled/de/maxhenkel/voicechat/compatibility/CompatibilityReflectionException.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/CompatibilityReflectionException.java index 2b8465f..c225a90 100644 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/CompatibilityReflectionException.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/CompatibilityReflectionException.java @@ -1,10 +1,7 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.compatibility; -public class CompatibilityReflectionException -extends RuntimeException { +public class CompatibilityReflectionException extends RuntimeException { + public CompatibilityReflectionException(String message) { super(message); } @@ -12,5 +9,5 @@ extends RuntimeException { public CompatibilityReflectionException(String message, Throwable cause) { super(message, cause); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/FallbackCompatibility.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/FallbackCompatibility.java similarity index 64% rename from source/decompiled/de/maxhenkel/voicechat/compatibility/FallbackCompatibility.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/FallbackCompatibility.java index b310e63..e8962fd 100644 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/FallbackCompatibility.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/FallbackCompatibility.java @@ -1,43 +1,35 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * javax.annotation.Nullable - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.compatibility; import com.mojang.brigadier.arguments.ArgumentType; import de.maxhenkel.voicechat.FallbackTranslations; import de.maxhenkel.voicechat.Version; -import de.maxhenkel.voicechat.compatibility.BaseCompatibility; import de.maxhenkel.voicechat.util.Key; -import javax.annotation.Nullable; import org.bukkit.entity.Player; -public class FallbackCompatibility -extends BaseCompatibility { +import javax.annotation.Nullable; + +public class FallbackCompatibility extends BaseCompatibility { + public static final FallbackCompatibility INSTANCE = new FallbackCompatibility(); @Override - public void sendTranslationMessage(Player player, String key, String ... args) { - player.sendMessage(FallbackCompatibility.fallbackTranslation(key, args)); + public void sendTranslationMessage(Player player, String key, String... args) { + player.sendMessage(fallbackTranslation(key, args)); } @Override - public void sendStatusMessage(Player player, String key, String ... args) { - this.sendTranslationMessage(player, key, args); + public void sendStatusMessage(Player player, String key, String... args) { + sendTranslationMessage(player, key, args); } @Override public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendTranslationMessage(player, "message.voicechat.invite", commandSender.getName(), groupName, ""); + sendTranslationMessage(player, "message.voicechat.invite", commandSender.getName(), groupName, ""); } @Override public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendTranslationMessage(player, "message.voicechat.incompatible_version", pluginVersion, pluginName); + sendTranslationMessage(player, "message.voicechat.incompatible_version", pluginVersion, pluginName); } @Override @@ -52,7 +44,8 @@ extends BaseCompatibility { if (version.getMinor() > 12) { return super.createNamespacedKey(key); } - return Key.of("vc", key); + // Use old channels for versions older than 1.13 + return Key.of(Compatibility1_12.CHANNEL, key); } @Override @@ -67,12 +60,13 @@ extends BaseCompatibility { return null; } - public static String fallbackTranslation(String key, String ... args) { + public static String fallbackTranslation(String key, String... args) { String rawTranslation = FallbackTranslations.FALLBACK_TRANSLATIONS.get(key); if (rawTranslation == null) { return key; } - return String.format(rawTranslation, args); - } -} + return String.format(rawTranslation, (Object[]) args); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/JsonMessageBaseCompatibility.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/JsonMessageBaseCompatibility.java new file mode 100644 index 0000000..388e1d7 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/JsonMessageBaseCompatibility.java @@ -0,0 +1,23 @@ +package de.maxhenkel.voicechat.compatibility; + +import org.bukkit.entity.Player; + +public abstract class JsonMessageBaseCompatibility extends BaseCompatibility { + + @Override + public void sendTranslationMessage(Player player, String key, String... args) { + sendJsonMessage(player, createTranslationMessage(key, args)); + } + + @Override + public void sendStatusMessage(Player player, String key, String... args) { + sendJsonStatusMessage(player, createTranslationMessage(key, args)); + } + + public abstract void sendJsonMessage(Player player, String json); + + public abstract void sendJsonStatusMessage(Player player, String json); + + public abstract String createTranslationMessage(String key, String... args); + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/PlayerHideEvent.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/PlayerHideEvent.java similarity index 70% rename from source/decompiled/de/maxhenkel/voicechat/compatibility/PlayerHideEvent.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/PlayerHideEvent.java index 26f061f..fbdc3b4 100644 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/PlayerHideEvent.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/PlayerHideEvent.java @@ -1,14 +1,9 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.compatibility; import org.bukkit.entity.Player; public class PlayerHideEvent { + private final Player hiddenPlayer; private final Player observer; @@ -18,11 +13,11 @@ public class PlayerHideEvent { } public Player getHiddenPlayer() { - return this.hiddenPlayer; + return hiddenPlayer; } public Player getObserver() { - return this.observer; + return observer; } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/PlayerShowEvent.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/PlayerShowEvent.java similarity index 70% rename from source/decompiled/de/maxhenkel/voicechat/compatibility/PlayerShowEvent.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/PlayerShowEvent.java index 4996235..46c0918 100644 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/PlayerShowEvent.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/PlayerShowEvent.java @@ -1,14 +1,9 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.compatibility; import org.bukkit.entity.Player; public class PlayerShowEvent { + private final Player shownPlayer; private final Player observer; @@ -18,11 +13,11 @@ public class PlayerShowEvent { } public Player getShownPlayer() { - return this.shownPlayer; + return shownPlayer; } public Player getObserver() { - return this.observer; + return observer; } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/ReflectionUtils.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/ReflectionUtils.java similarity index 56% rename from source/decompiled/de/maxhenkel/voicechat/compatibility/ReflectionUtils.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/ReflectionUtils.java index 39da3db..3b5b4fd 100644 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/ReflectionUtils.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/ReflectionUtils.java @@ -1,72 +1,64 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.compatibility; -import de.maxhenkel.voicechat.compatibility.CompatibilityReflectionException; +import javax.annotation.Nullable; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; -import javax.annotation.Nullable; public class ReflectionUtils { - public static T callMethod(Object object, String ... methodNames) { - return ReflectionUtils.callMethod(object, methodNames, new Class[0], new Object[0]); + + public static T callMethod(Object object, String... methodNames) { + return callMethod(object, methodNames, new Class[]{}); } - public static T callMethod(Object object, String[] methodNames, Class[] parameterTypes, Object ... args) { - return ReflectionUtils.callMethod(object.getClass(), object, methodNames, parameterTypes, args); + public static T callMethod(Object object, String[] methodNames, Class[] parameterTypes, Object... args) { + return callMethod(object.getClass(), object, methodNames, parameterTypes, args); } - public static T callMethod(Object object, String methodName, Class[] parameterTypes, Object ... args) { - return ReflectionUtils.callMethod(object.getClass(), object, new String[]{methodName}, parameterTypes, args); + public static T callMethod(Object object, String methodName, Class[] parameterTypes, Object... args) { + return callMethod(object.getClass(), object, new String[]{methodName}, parameterTypes, args); } - public static T callMethod(Class clazz, Object object, String ... methodNames) { - return ReflectionUtils.callMethod(clazz, object, methodNames, new Class[0], new Object[0]); + public static T callMethod(Class clazz, Object object, String... methodNames) { + return callMethod(clazz, object, methodNames, new Class[]{}); } - public static T callMethod(Class clazz, Object object, String methodName, Class[] parameterTypes, Object ... args) { - return ReflectionUtils.callMethod(clazz, object, new String[]{methodName}, parameterTypes, args); + public static T callMethod(Class clazz, Object object, String methodName, Class[] parameterTypes, Object... args) { + return callMethod(clazz, object, new String[]{methodName}, parameterTypes, args); } - public static T callMethod(Class clazz, Object object, String[] methodNames, Class[] parameterTypes, Object ... args) { + public static T callMethod(Class clazz, Object object, String[] methodNames, Class[] parameterTypes, Object... args) { for (String name : methodNames) { try { Method method = clazz.getDeclaredMethod(name, parameterTypes); method.setAccessible(true); - return (T)method.invoke(object, args); - } - catch (Throwable ignored) { + return (T) method.invoke(object, args); + } catch (Throwable ignored) { try { Method method = clazz.getMethod(name, parameterTypes); method.setAccessible(true); - return (T)method.invoke(object, args); - } - catch (Throwable throwable) { + return (T) method.invoke(object, args); + } catch (Throwable ignored2) { } } } - throw new CompatibilityReflectionException(String.format("Could not find any of the following methods in the class %s: %s", clazz.getSimpleName(), String.join((CharSequence)", ", methodNames))); + throw new CompatibilityReflectionException(String.format("Could not find any of the following methods in the class %s: %s", clazz.getSimpleName(), String.join(", ", methodNames))); } - public static T callMethod(Class object, String ... methodNames) { - return ReflectionUtils.callMethod(object, methodNames, new Class[0], new Object[0]); + public static T callMethod(Class object, String... methodNames) { + return callMethod(object, methodNames, new Class[]{}); } - public static T callMethod(Class object, String[] methodNames, Class[] parameterTypes, Object ... args) { - return ReflectionUtils.callMethod(object, null, methodNames, parameterTypes, args); + public static T callMethod(Class object, String[] methodNames, Class[] parameterTypes, Object... args) { + return callMethod(object, null, methodNames, parameterTypes, args); } - public static T callMethod(Class object, String methodName, Class[] parameterTypes, Object ... args) { - return ReflectionUtils.callMethod(object, null, new String[]{methodName}, parameterTypes, args); + public static T callMethod(Class object, String methodName, Class[] parameterTypes, Object... args) { + return callMethod(object, null, new String[]{methodName}, parameterTypes, args); } - public static Method getMethod(Class clazz, String ... methodNames) { - return ReflectionUtils.getMethod(clazz, methodNames, new Class[0]); + public static Method getMethod(Class clazz, String... methodNames) { + return getMethod(clazz, methodNames, new Class[]{}); } public static Method getMethod(Class clazz, String[] methodNames, Class[] parameterTypes) { @@ -75,141 +67,131 @@ public class ReflectionUtils { Method method = clazz.getDeclaredMethod(name, parameterTypes); method.setAccessible(true); return method; - } - catch (Throwable ignored) { + } catch (Throwable ignored) { try { Method method = clazz.getMethod(name, parameterTypes); method.setAccessible(true); return method; - } - catch (Throwable throwable) { + } catch (Throwable ignored2) { } } } - throw new CompatibilityReflectionException(String.format("Could not find any of the following methods in the class %s: %s", clazz.getSimpleName(), String.join((CharSequence)", ", methodNames))); + throw new CompatibilityReflectionException(String.format("Could not find any of the following methods in the class %s: %s", clazz.getSimpleName(), String.join(", ", methodNames))); } - public static T call(Method method, @Nullable Object instance, Object ... args) { + public static T call(Method method, @Nullable Object instance, Object... args) { try { - return (T)method.invoke(instance, args); - } - catch (Throwable t) { + return (T) method.invoke(instance, args); + } catch (Throwable t) { throw new CompatibilityReflectionException(String.format("Failed to invoke method %s", method.getName()), t); } } public static T callConstructor(Class object) { - return ReflectionUtils.callConstructor(object, new Class[0], new Object[0]); + return callConstructor(object, new Class[]{}); } - public static T callConstructor(Class object, Class[] parameterTypes, Object ... args) { + public static T callConstructor(Class object, Class[] parameterTypes, Object... args) { try { Constructor constructor = object.getDeclaredConstructor(parameterTypes); constructor.setAccessible(true); - return (T)constructor.newInstance(args); - } - catch (Throwable t) { + return (T) constructor.newInstance(args); + } catch (Throwable t) { throw new CompatibilityReflectionException(String.format("Failed to invoke constructor of %s", object.getName()), t); } } - public static Constructor getConstructor(Class object, Class ... parameterTypes) { + public static Constructor getConstructor(Class object, Class... parameterTypes) { try { Constructor constructor = object.getDeclaredConstructor(parameterTypes); constructor.setAccessible(true); return constructor; - } - catch (Throwable t) { + } catch (Throwable t) { throw new CompatibilityReflectionException(String.format("Failed to get constructor of %s", object.getName()), t); } } - public static T newInstance(Constructor constructor, Object ... args) { + public static T newInstance(Constructor constructor, Object... args) { try { return constructor.newInstance(args); - } - catch (Throwable t) { + } catch (Throwable t) { throw new CompatibilityReflectionException(String.format("Failed to invoke constructor of %s", constructor.getDeclaringClass().getName()), t); } } - public static T getField(Object object, String ... fieldNames) { + public static T getField(Object object, String... fieldNames) { for (String fieldName : fieldNames) { try { Field field = object.getClass().getDeclaredField(fieldName); field.setAccessible(true); - return (T)field.get(object); - } - catch (Throwable ignored) { + return (T) field.get(object); + } catch (Throwable ignored) { try { Field field = object.getClass().getField(fieldName); field.setAccessible(true); - return (T)field.get(object); - } - catch (Throwable throwable) { + return (T) field.get(object); + } catch (Throwable ignored2) { } } } - throw new CompatibilityReflectionException(String.format("Could not find any of the following fields in the class %s: %s", object.getClass().getSimpleName(), String.join((CharSequence)", ", fieldNames))); + throw new CompatibilityReflectionException(String.format("Could not find any of the following fields in the class %s: %s", object.getClass().getSimpleName(), String.join(", ", fieldNames))); } - public static T getField(Class clazz, String ... fieldNames) { + public static T getField(Class clazz, String... fieldNames) { for (String fieldName : fieldNames) { try { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); - return (T)field.get(null); - } - catch (Throwable ignored) { + return (T) field.get(null); + } catch (Throwable ignored) { try { Field field = clazz.getField(fieldName); field.setAccessible(true); - return (T)field.get(null); - } - catch (Throwable throwable) { + return (T) field.get(null); + } catch (Throwable ignored2) { } } } - throw new CompatibilityReflectionException(String.format("Could not find any of the following fields in the class %s: %s", clazz.getSimpleName(), String.join((CharSequence)", ", fieldNames))); + throw new CompatibilityReflectionException(String.format("Could not find any of the following fields in the class %s: %s", clazz.getSimpleName(), String.join(", ", fieldNames))); } - public static Class getClazz(String ... classNames) { + /** + * @param classNames the class names including the package name + * @return the class + */ + public static Class getClazz(String... classNames) { for (String className : classNames) { try { return Class.forName(className); - } - catch (Throwable throwable) { + } catch (Throwable ignored) { } } - throw new CompatibilityReflectionException(String.format("Could not find any of the following classes: %s", String.join((CharSequence)", ", classNames))); + throw new CompatibilityReflectionException(String.format("Could not find any of the following classes: %s", String.join(", ", classNames))); } - public static boolean doesClassExist(String ... classNames) { + public static boolean doesClassExist(String... classNames) { for (String className : classNames) { try { Class.forName(className); return true; - } - catch (Throwable throwable) { + } catch (Throwable ignored) { } } return false; } - public static boolean doesMethodExist(Class clazz, String methodName, Class ... parameterTypes) { + public static boolean doesMethodExist(Class clazz, String methodName, Class... parameterTypes) { try { clazz.getDeclaredMethod(methodName, parameterTypes); return true; - } - catch (Throwable ignored) { + } catch (Throwable ignored) { try { clazz.getMethod(methodName, parameterTypes); return true; - } - catch (Throwable throwable) { - return false; + } catch (Throwable ignored2) { } } + return false; } -} +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/SpigotCompatibility.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/SpigotCompatibility.java new file mode 100644 index 0000000..5bc0052 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/compatibility/SpigotCompatibility.java @@ -0,0 +1,72 @@ +package de.maxhenkel.voicechat.compatibility; + +import com.mojang.brigadier.arguments.ArgumentType; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import static de.maxhenkel.voicechat.compatibility.ReflectionUtils.*; + +public class SpigotCompatibility extends FallbackCompatibility { + + public static final SpigotCompatibility INSTANCE = new SpigotCompatibility(); + + private MessageSender messageSender; + + @Override + public void init() throws Exception { + super.init(); + + Class playerSpigotClass = getClazz("org.bukkit.entity.Player$Spigot"); + Class baseComponentClass = getClazz("net.md_5.bungee.api.chat.BaseComponent"); + + Class chatMessageTypeClass = getClazz("net.md_5.bungee.api.ChatMessageType"); + Object systemType = getField(chatMessageTypeClass, "SYSTEM"); + Object actionBarType = getField(chatMessageTypeClass, "ACTION_BAR"); + + Method playerSpigot = getMethod(Player.class, "spigot"); + Method sendMessage = getMethod(playerSpigotClass, new String[]{"sendMessage"}, new Class[]{chatMessageTypeClass, baseComponentClass}); + + Class translatableComponentClass = getClazz("net.md_5.bungee.api.chat.TranslatableComponent"); + Constructor translatableComponentConstructor = getConstructor(translatableComponentClass, String.class, Object[].class); + + messageSender = ((player, actionBar, key, args) -> { + Object messageType = actionBar ? actionBarType : systemType; + call(sendMessage, call(playerSpigot, player), messageType, newInstance(translatableComponentConstructor, key, args)); + }); + } + + public static boolean isSpigotCompatible() { + return doesMethodExist(Bukkit.class, "spigot"); + } + + @Override + public void sendTranslationMessage(Player player, String key, String... args) { + messageSender.send(player, false, key, args); + } + + @Override + public void sendStatusMessage(Player player, String key, String... args) { + messageSender.send(player, true, key, args); + } + + @Override + @Nullable + public ArgumentType playerArgument() { + return null; + } + + @Override + @Nullable + public ArgumentType uuidArgument() { + return null; + } + + private interface MessageSender { + void send(Player player, boolean actionBar, String key, String... args); + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/config/ServerConfig.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/config/ServerConfig.java new file mode 100644 index 0000000..a0c97b7 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/config/ServerConfig.java @@ -0,0 +1,129 @@ +package de.maxhenkel.voicechat.config; + +import de.maxhenkel.configbuilder.ConfigBuilder; +import de.maxhenkel.configbuilder.entry.ConfigEntry; +import de.maxhenkel.voicechat.BuildConstants; +import de.maxhenkel.voicechat.Voicechat; +import de.maxhenkel.voicechat.voice.common.AudioUtils; + +public class ServerConfig { + + public final ConfigEntry voiceChatPort; + public final ConfigEntry voiceChatBindAddress; + public final ConfigEntry voiceChatDistance; + public ConfigEntry whisperDistance; + public final ConfigEntry voiceChatCodec; + public final ConfigEntry voiceChatMtuSize; + public final ConfigEntry tcpRateLimit; + public final ConfigEntry keepAlive; + public final ConfigEntry groupsEnabled; + public final ConfigEntry voiceHost; + public final ConfigEntry allowRecording; + public final ConfigEntry spectatorInteraction; + public ConfigEntry spectatorPlayerPossession; + public ConfigEntry forceVoiceChat; + public ConfigEntry loginTimeout; + public ConfigEntry broadcastRange; + public ConfigEntry allowPings; + public ConfigEntry threadedServerSupport; + + public ServerConfig(ConfigBuilder builder) { + builder.header(String.format("%s server config v%s", BuildConstants.PLUGIN_NAME, Voicechat.INSTANCE.getDescription().getVersion())); + + voiceChatPort = builder + .integerEntry("port", 24454, -1, 65535, + "The port number to use for the voice chat communication.", + "Audio packets are always transmitted via the UDP protocol on the port number", + "specified here, independently of other networking used for the game server.", + "Set this to '-1' to use the same port number that is used by the Minecraft server.", + "However, it is strongly recommended NOT to use the same port number because UDP on", + "it is also used by default for the server query. Doing so may crash the server!" + ); + voiceChatBindAddress = builder + .stringEntry("bind_address", "", + "The server IP address to bind the voice chat to", + "Leave blank to use the 'server-ip' property from the 'server.properties' config file", + "To bind to the wildcard IP address, use '*'" + ); + voiceChatDistance = builder + .doubleEntry("max_voice_distance", 48D, 1D, 1_000_000D, + "The distance to which the voice can be heard" + ); + whisperDistance = builder + .doubleEntry("whisper_distance", 24D, 1D, 1_000_000D, + "The distance to which the voice can be heard when whispering" + ); + voiceChatCodec = builder + .enumEntry("codec", Codec.VOIP, + "The Opus codec", + "Valid values are 'VOIP', 'AUDIO', and 'RESTRICTED_LOWDELAY'" + ); + voiceChatMtuSize = builder + .integerEntry("mtu_size", AudioUtils.MAX_OPUS_PAYLOAD_SIZE, 512, 2048, + "The maximum size that audio packets are allowed to have (in bytes)", + "Setting this to lower values might cause issues" + ); + tcpRateLimit = builder + .integerEntry("tcp_rate_limit", 16, -1, 1024, + "The maximum number of packets a player can send per second", + "Set this to -1 to disable the rate limit - This must be greater than 0 in all other cases", + "This only applies to voice chat packets that are sent through Minecrafts networking", + "This affects actions like opening/joining/leaving voice chat groups or general state changes like disabling/enabling the voice chat" + ); + keepAlive = builder + .integerEntry("keep_alive", 1000, 1000, Integer.MAX_VALUE, + "The frequency at which keep-alive packets are sent (in milliseconds)", + "Setting this to a higher value may result in timeouts" + ); + groupsEnabled = builder + .booleanEntry("enable_groups", true, + "If group chats are allowed" + ); + voiceHost = builder + .stringEntry("voice_host", "", + "The hostname that clients should use to connect to the voice chat", + "This may also include a port, e.g. 'example.com:24454'", + "Do NOT change this value if you don't know what you're doing" + ); + allowRecording = builder + .booleanEntry("allow_recording", true, + "If players are allowed to record the voice chat audio" + ); + spectatorInteraction = builder + .booleanEntry("spectator_interaction", false, + "If spectators are allowed to talk to other players" + ); + spectatorPlayerPossession = builder + .booleanEntry("spectator_player_possession", false, + "If spectators can talk to players they are spectating" + ); + forceVoiceChat = builder + .booleanEntry("force_voice_chat", false, + "If players without the voice chat mod should be kicked from the server" + ); + loginTimeout = builder + .integerEntry("login_timeout", 10_000, 100, Integer.MAX_VALUE, + "The amount of time the server should wait to check if a player has the mod installed (in milliseconds)", + "Only relevant when 'force_voice_chat' is set to 'true'" + ); + broadcastRange = builder + .doubleEntry("broadcast_range", -1D, -1D, Double.MAX_VALUE, + "The range in which the voice chat should broadcast audio", + "A value less than 0 means 'max_voice_distance'" + ); + allowPings = builder + .booleanEntry("allow_pings", true, + "If the voice chat server should reply to external pings" + ); + threadedServerSupport = builder + .booleanEntry("threaded_server_support", true, + "If the voice chat should support servers that run multiple threads, like Folia", + "Disabling this may slightly improve performance, but can cause issues on servers that don't run everything on a single thread" + ); + } + + public enum Codec { + VOIP, AUDIO, RESTRICTED_LOWDELAY; + } + +} \ No newline at end of file diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/config/Translations.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/config/Translations.java new file mode 100644 index 0000000..104570c --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/config/Translations.java @@ -0,0 +1,68 @@ +package de.maxhenkel.voicechat.config; + +import de.maxhenkel.configbuilder.ConfigBuilder; +import de.maxhenkel.configbuilder.entry.ConfigEntry; + +public class Translations { + + public final ConfigEntry forceVoicechatKickMessage; + public final ConfigEntry rateLimitKickMessage; + public final ConfigEntry voicechatNotCompatibleMessage; + public final ConfigEntry voicechatNeededForCommandMessage; + public final ConfigEntry playerCommandMessage; + public final ConfigEntry placeholderVoicechatInstalled; + public final ConfigEntry placeholderVoicechatNotInstalled; + public final ConfigEntry placeholderVoicechatDisabled; + + public Translations(ConfigBuilder builder) { + builder.header( + "Simple Voice Chat translations", + "This file contains all server-side translations for the Simple Voice Chat plugin" + ); + + forceVoicechatKickMessage = builder.stringEntry( + "force_voicechat_kick_message", + "You need %s %s to play on this server", + "The message a player gets when kicked for not having voice chat installed and the server has force_voicechat enabled", + "The first parameter is the mod/plugin name and the second parameter is the mod/plugin version" + ); + rateLimitKickMessage = builder.stringEntry( + "rate_limit_kick_message", + "Kicked for exceeding packet rate limit", + "The message a player gets when kicked for sending too many voice chat packets" + ); + voicechatNotCompatibleMessage = builder.stringEntry( + "voicechat_not_compatible_message", + "Your voice chat client version is not compatible with the server-side version.\\nPlease install version %s of %s.", + "The message a player gets when joining a server with an incompatible voice chat version", + "The first parameter is the mod/plugin version and the second parameter is the mod/plugin name" + ); + voicechatNeededForCommandMessage = builder.stringEntry( + "voicechat_needed_for_command_message", + "You need to have %s installed on your client to use this command", + "The message a player gets when trying to execute a command that requires the voice chat mod installed on the client side.", + "The first parameter is the mod/plugin name" + ); + playerCommandMessage = builder.stringEntry( + "player_command_message", + "This command can only be executed as a player", + "The message a player gets when trying to execute a command that can only be executed as a player" + ); + placeholderVoicechatInstalled = builder.stringEntry( + "placeholder_api_voicechat_installed", + "", + "The Placeholder API string for '%voicechat_installed%'" + ); + placeholderVoicechatNotInstalled = builder.stringEntry( + "placeholder_api_voicechat_not_installed", + "", + "The Placeholder API string for '%voicechat_not_installed%'" + ); + placeholderVoicechatDisabled = builder.stringEntry( + "placeholder_api_voicechat_disabled", + "", + "The Placeholder API string for '%voicechat_disabled%'" + ); + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/debug/CooldownTimer.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/debug/CooldownTimer.java similarity index 71% rename from source/decompiled/de/maxhenkel/voicechat/debug/CooldownTimer.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/debug/CooldownTimer.java index 6fb3052..da1ec77 100644 --- a/source/decompiled/de/maxhenkel/voicechat/debug/CooldownTimer.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/debug/CooldownTimer.java @@ -1,12 +1,14 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.debug; import java.util.concurrent.ConcurrentHashMap; public class CooldownTimer { - private static ConcurrentHashMap cooldowns = new ConcurrentHashMap(); + + private static ConcurrentHashMap cooldowns; + + static { + cooldowns = new ConcurrentHashMap<>(); + } public static void run(String id, long time, Runnable runnable) { if (System.currentTimeMillis() - cooldowns.getOrDefault(id, 0L) > time) { @@ -16,7 +18,7 @@ public class CooldownTimer { } public static void run(String id, Runnable runnable) { - CooldownTimer.run(id, 10000L, runnable); + run(id, 10_000L, runnable); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/debug/PingHandler.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/debug/PingHandler.java similarity index 80% rename from source/decompiled/de/maxhenkel/voicechat/debug/PingHandler.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/debug/PingHandler.java index 6ca7263..6159803 100644 --- a/source/decompiled/de/maxhenkel/voicechat/debug/PingHandler.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/debug/PingHandler.java @@ -1,46 +1,44 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * io.netty.buffer.Unpooled - */ package de.maxhenkel.voicechat.debug; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.voice.server.Server; import io.netty.buffer.Unpooled; + import java.net.SocketAddress; import java.util.UUID; public class PingHandler { + public static final UUID PING_V1 = UUID.fromString("58bc9ae9-c7a8-45e4-a11c-efbb67199425"); private static final int PAYLOAD_SIZE = 24; public static boolean onPacket(Server server, SocketAddress socketAddress, UUID playerID, FriendlyByteBuf buf) { - if (!Voicechat.SERVER_CONFIG.allowPings.get().booleanValue()) { + if (!Voicechat.SERVER_CONFIG.allowPings.get()) { return false; } if (!PING_V1.equals(playerID)) { return false; } try { - byte[] payload = buf.readByteArray(24); - FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.wrappedBuffer((byte[])payload)); + byte[] payload = buf.readByteArray(PAYLOAD_SIZE); + FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.wrappedBuffer(payload)); UUID id = buffer.readUUID(); long timestamp = buffer.readLong(); Voicechat.LOGGER.debug("Received ping {} from {}", id, socketAddress); - FriendlyByteBuf responseBuffer = new FriendlyByteBuf(Unpooled.buffer((int)24)); + + FriendlyByteBuf responseBuffer = new FriendlyByteBuf(Unpooled.buffer(PAYLOAD_SIZE)); + responseBuffer.writeUUID(id); responseBuffer.writeLong(timestamp); + byte[] response = new byte[responseBuffer.readableBytes()]; responseBuffer.readBytes(response); + server.getSocket().send(response, socketAddress); - } - catch (Exception e) { + } catch (Exception e) { Voicechat.LOGGER.debug("Failed to send ping to {}: {}", socketAddress, e.getMessage()); } return true; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/debug/VoicechatUncaughtExceptionHandler.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/debug/VoicechatUncaughtExceptionHandler.java similarity index 65% rename from source/decompiled/de/maxhenkel/voicechat/debug/VoicechatUncaughtExceptionHandler.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/debug/VoicechatUncaughtExceptionHandler.java index 398af6f..e4bc91c 100644 --- a/source/decompiled/de/maxhenkel/voicechat/debug/VoicechatUncaughtExceptionHandler.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/debug/VoicechatUncaughtExceptionHandler.java @@ -1,15 +1,12 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.debug; import de.maxhenkel.voicechat.Voicechat; -public class VoicechatUncaughtExceptionHandler -implements Thread.UncaughtExceptionHandler { +public class VoicechatUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { + @Override public void uncaughtException(Thread t, Throwable e) { Voicechat.LOGGER.error("Uncaught exception in thread {}", t.getName(), e); } -} +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/commodore/CommodoreCommands.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/commodore/CommodoreCommands.java new file mode 100644 index 0000000..d8b60cb --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/commodore/CommodoreCommands.java @@ -0,0 +1,40 @@ +package de.maxhenkel.voicechat.integration.commodore; + +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import de.maxhenkel.voicechat.Voicechat; +import de.maxhenkel.voicechat.command.VoiceChatCommands; +import me.lucko.commodore.Commodore; + +public class CommodoreCommands { + + public static void registerCompletions(Commodore commodore) throws MissingArgumentTypeException { + ArgumentType playerArgument = playerArgument(); + ArgumentType uuidArgument = uuidArgument(); + if (playerArgument == null || uuidArgument == null) { + throw new MissingArgumentTypeException("Could not acquire argument types"); + } + LiteralArgumentBuilder literalBuilder = LiteralArgumentBuilder.literal(VoiceChatCommands.VOICECHAT_COMMAND) + .then(LiteralArgumentBuilder.literal("help")) + .then(LiteralArgumentBuilder.literal("test").then(RequiredArgumentBuilder.argument("target", playerArgument))) + .then(LiteralArgumentBuilder.literal("invite").then(RequiredArgumentBuilder.argument("target", playerArgument))) + .then(LiteralArgumentBuilder.literal("join").then(RequiredArgumentBuilder.argument("group_id", uuidArgument))) + .then(LiteralArgumentBuilder.literal("join").then(RequiredArgumentBuilder.argument("group_id", uuidArgument).then(RequiredArgumentBuilder.argument("password", StringArgumentType.string())))) + .then(LiteralArgumentBuilder.literal("join").then(RequiredArgumentBuilder.argument("group_name", StringArgumentType.string()).suggests(GroupNameSuggestionProvider.INSTANCE))) + .then(LiteralArgumentBuilder.literal("join").then(RequiredArgumentBuilder.argument("group_name", StringArgumentType.string()).suggests(GroupNameSuggestionProvider.INSTANCE).then(RequiredArgumentBuilder.argument("password", StringArgumentType.string())))) + .then(LiteralArgumentBuilder.literal("leave")); + + commodore.register(literalBuilder); + } + + private static ArgumentType playerArgument() { + return Voicechat.compatibility.playerArgument(); + } + + private static ArgumentType uuidArgument() { + return Voicechat.compatibility.uuidArgument(); + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/integration/commodore/GroupNameSuggestionProvider.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/commodore/GroupNameSuggestionProvider.java similarity index 71% rename from source/decompiled/de/maxhenkel/voicechat/integration/commodore/GroupNameSuggestionProvider.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/commodore/GroupNameSuggestionProvider.java index b7c6f07..88a75ca 100644 --- a/source/decompiled/de/maxhenkel/voicechat/integration/commodore/GroupNameSuggestionProvider.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/commodore/GroupNameSuggestionProvider.java @@ -1,12 +1,3 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.context.CommandContext - * com.mojang.brigadier.suggestion.SuggestionProvider - * com.mojang.brigadier.suggestion.Suggestions - * com.mojang.brigadier.suggestion.SuggestionsBuilder - */ package de.maxhenkel.voicechat.integration.commodore; import com.mojang.brigadier.context.CommandContext; @@ -16,12 +7,14 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.voice.server.Group; import de.maxhenkel.voicechat.voice.server.Server; + import java.util.concurrent.CompletableFuture; -public class GroupNameSuggestionProvider -implements SuggestionProvider { +public class GroupNameSuggestionProvider implements SuggestionProvider { + public static final GroupNameSuggestionProvider INSTANCE = new GroupNameSuggestionProvider(); + @Override public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { Server server = Voicechat.SERVER.getServer(); if (server == null) { @@ -32,8 +25,7 @@ implements SuggestionProvider { return String.format("\"%s\"", s); } return s; - }).forEach(arg_0 -> ((SuggestionsBuilder)builder).suggest(arg_0)); + }).forEach(builder::suggest); return builder.buildFuture(); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/integration/commodore/MissingArgumentTypeException.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/commodore/MissingArgumentTypeException.java similarity index 59% rename from source/decompiled/de/maxhenkel/voicechat/integration/commodore/MissingArgumentTypeException.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/commodore/MissingArgumentTypeException.java index fda7735..7a66e29 100644 --- a/source/decompiled/de/maxhenkel/voicechat/integration/commodore/MissingArgumentTypeException.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/commodore/MissingArgumentTypeException.java @@ -1,12 +1,9 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.integration.commodore; -public class MissingArgumentTypeException -extends Exception { +public class MissingArgumentTypeException extends Exception { + public MissingArgumentTypeException(String message) { super(message); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/integration/placeholderapi/VoicechatExpansion.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/placeholderapi/VoicechatExpansion.java similarity index 71% rename from source/decompiled/de/maxhenkel/voicechat/integration/placeholderapi/VoicechatExpansion.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/placeholderapi/VoicechatExpansion.java index 6f7e6b5..97dd903 100644 --- a/source/decompiled/de/maxhenkel/voicechat/integration/placeholderapi/VoicechatExpansion.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/placeholderapi/VoicechatExpansion.java @@ -1,50 +1,46 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * me.clip.placeholderapi.expansion.PlaceholderExpansion - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.integration.placeholderapi; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.voice.common.PlayerState; import de.maxhenkel.voicechat.voice.server.Server; -import javax.annotation.Nullable; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import org.bukkit.entity.Player; -public class VoicechatExpansion -extends PlaceholderExpansion { +import javax.annotation.Nullable; + +public class VoicechatExpansion extends PlaceholderExpansion { + + @Override public String getIdentifier() { - return "voicechat"; + return Voicechat.MODID; } + @Override public String getAuthor() { - return String.join((CharSequence)", ", Voicechat.INSTANCE.getDescription().getAuthors()); + return String.join(", ", Voicechat.INSTANCE.getDescription().getAuthors()); } + @Override public String getVersion() { return Voicechat.INSTANCE.getDescription().getVersion(); } + @Override public boolean persist() { return true; } - @Nullable - public String onPlaceholderRequest(Player player, String params) { + @Override + public @Nullable String onPlaceholderRequest(Player player, String params) { if (player == null) { return super.onPlaceholderRequest(player, params); } + if (params.equalsIgnoreCase("installed")) { return Voicechat.SERVER.isCompatible(player) ? Voicechat.TRANSLATIONS.placeholderVoicechatInstalled.get() : ""; - } - if (params.equalsIgnoreCase("not_installed")) { + } else if (params.equalsIgnoreCase("not_installed")) { return !Voicechat.SERVER.isCompatible(player) ? Voicechat.TRANSLATIONS.placeholderVoicechatNotInstalled.get() : ""; - } - if (params.equalsIgnoreCase("disabled")) { + } else if (params.equalsIgnoreCase("disabled")) { Server server = Voicechat.SERVER.getServer(); if (server == null) { return ""; @@ -58,7 +54,7 @@ extends PlaceholderExpansion { } return Voicechat.TRANSLATIONS.placeholderVoicechatDisabled.get(); } + return super.onPlaceholderRequest(player, params); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/integration/viaversion/ViaVersionCompatibility.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/viaversion/ViaVersionCompatibility.java similarity index 56% rename from source/decompiled/de/maxhenkel/voicechat/integration/viaversion/ViaVersionCompatibility.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/viaversion/ViaVersionCompatibility.java index 24aaef4..3d3de7d 100644 --- a/source/decompiled/de/maxhenkel/voicechat/integration/viaversion/ViaVersionCompatibility.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/integration/viaversion/ViaVersionCompatibility.java @@ -1,27 +1,26 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.integration.viaversion; import de.maxhenkel.voicechat.Voicechat; +import de.maxhenkel.voicechat.compatibility.Compatibility1_12; import de.maxhenkel.voicechat.util.Key; + +import javax.annotation.Nullable; import java.lang.reflect.Field; import java.lang.reflect.Method; -import javax.annotation.Nullable; public class ViaVersionCompatibility { + public static void register() throws Exception { - Class protocol113to1122 = ViaVersionCompatibility.getClass("com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2"); + // ViaVersion 4.x.x + Class protocol113to1122 = getClass("com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2"); if (protocol113to1122 != null) { - ViaVersionCompatibility.registerPackets(protocol113to1122); + registerPackets(protocol113to1122); return; } - Class protocol1122to113 = ViaVersionCompatibility.getClass("com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13"); + //ViaVersion 5.x.x + Class protocol1122to113 = getClass("com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13"); if (protocol1122to113 != null) { - ViaVersionCompatibility.registerPackets(protocol1122to113); + registerPackets(protocol1122to113); return; } } @@ -29,12 +28,12 @@ public class ViaVersionCompatibility { private static void registerPackets(Class protocolClass) throws Exception { Field mappingsField = protocolClass.getDeclaredField("MAPPINGS"); Object mappings = mappingsField.get(null); - Method getChannelMappings = mappings.getClass().getDeclaredMethod("getChannelMappings", new Class[0]); - Object mappingMap = getChannelMappings.invoke(mappings, new Object[0]); + Method getChannelMappings = mappings.getClass().getDeclaredMethod("getChannelMappings"); + Object mappingMap = getChannelMappings.invoke(mappings); Method put = mappingMap.getClass().getDeclaredMethod("put", Object.class, Object.class); for (String id : Voicechat.netManager.getPackets()) { Key key = Key.parse(id); - put.invoke(mappingMap, String.format("%s:%s", "vc", key.getValue()), String.format("%s:%s", "voicechat", key.getValue())); + put.invoke(mappingMap, String.format("%s:%s", Compatibility1_12.CHANNEL, key.getValue()), String.format("%s:%s", Voicechat.MODID, key.getValue())); } } @@ -42,10 +41,9 @@ public class ViaVersionCompatibility { private static Class getClass(String name) { try { return Class.forName(name); - } - catch (ClassNotFoundException e) { + } catch (ClassNotFoundException e) { return null; } } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/logging/JavaLoggingLogger.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/logging/JavaLoggingLogger.java similarity index 52% rename from source/decompiled/de/maxhenkel/voicechat/logging/JavaLoggingLogger.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/logging/JavaLoggingLogger.java index 21a31ff..d8e9f81 100644 --- a/source/decompiled/de/maxhenkel/voicechat/logging/JavaLoggingLogger.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/logging/JavaLoggingLogger.java @@ -1,19 +1,14 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.logging; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.logging.LogLevel; -import de.maxhenkel.voicechat.logging.VoicechatLogger; + import java.util.logging.Level; import java.util.logging.Logger; -public class JavaLoggingLogger -implements VoicechatLogger { +public class JavaLoggingLogger implements VoicechatLogger { + private final boolean debugMode; private final Logger logger; - private static final String PLACEHOLDER = "{}"; public JavaLoggingLogger(Logger logger) { this.logger = logger; @@ -21,74 +16,77 @@ implements VoicechatLogger { } @Override - public void log(LogLevel level, String message, Object ... args) { - if (!this.isEnabled(level)) { + public void log(LogLevel level, String message, Object... args) { + if (!isEnabled(level)) { return; } Throwable throwable = null; - if (args.length > 0 && args[args.length - 1] instanceof Throwable) { - throwable = (Throwable)args[args.length - 1]; - Object[] newArgs = new Object[args.length - 1]; - System.arraycopy(args, 0, newArgs, 0, newArgs.length); - args = newArgs; + if (args.length > 0) { + if (args[args.length - 1] instanceof Throwable) { + throwable = (Throwable) args[args.length - 1]; + Object[] newArgs = new Object[args.length - 1]; + System.arraycopy(args, 0, newArgs, 0, newArgs.length); + args = newArgs; + } } - this.logger.log(this.fromLogLevel(level), this.replacePlaceholders(message, args), throwable); + logger.log(fromLogLevel(level), replacePlaceholders(message, args), throwable); } - private String replacePlaceholders(String message, Object ... args) { + private static final String PLACEHOLDER = "{}"; + + private String replacePlaceholders(String message, Object... args) { StringBuilder formattedMessage = new StringBuilder(); + int argIndex = 0; int placeholderStart = message.indexOf(PLACEHOLDER); - for (int argIndex = 0; placeholderStart >= 0 && argIndex < args.length; ++argIndex) { + + while (placeholderStart >= 0 && argIndex < args.length) { formattedMessage.append(message, 0, placeholderStart); formattedMessage.append(args[argIndex]); message = message.substring(placeholderStart + PLACEHOLDER.length()); + argIndex++; placeholderStart = message.indexOf(PLACEHOLDER); } + formattedMessage.append(message); return formattedMessage.toString(); } @Override public boolean isEnabled(LogLevel level) { - return this.logger.isLoggable(this.fromLogLevel(level)); + return logger.isLoggable(fromLogLevel(level)); } private Level fromLogLevel(LogLevel level) { - if (this.debugMode) { + if (debugMode) { switch (level) { - case TRACE: { + case TRACE: return Level.ALL; - } - case WARN: { + case WARN: return Level.WARNING; - } - case ERROR: - case FATAL: { + case ERROR: + case FATAL: return Level.SEVERE; - } + default: + return Level.INFO; } - return Level.INFO; } switch (level) { - case TRACE: { + case TRACE: return Level.ALL; - } - case DEBUG: { + case DEBUG: return Level.CONFIG; - } - case WARN: { + case WARN: return Level.WARNING; - } - case ERROR: - case FATAL: { + case ERROR: + case FATAL: return Level.SEVERE; - } + default: + return Level.INFO; } - return Level.INFO; } public Logger getLogger() { - return this.logger; + return logger; } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/logging/LogLevel.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/logging/LogLevel.java similarity index 71% rename from source/decompiled/de/maxhenkel/voicechat/logging/LogLevel.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/logging/LogLevel.java index c671af6..267255f 100644 --- a/source/decompiled/de/maxhenkel/voicechat/logging/LogLevel.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/logging/LogLevel.java @@ -1,15 +1,12 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.logging; public enum LogLevel { + TRACE, DEBUG, INFO, WARN, ERROR, - FATAL; + FATAL } - diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/logging/VoicechatLogger.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/logging/VoicechatLogger.java new file mode 100644 index 0000000..e85191b --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/logging/VoicechatLogger.java @@ -0,0 +1,33 @@ +package de.maxhenkel.voicechat.logging; + +public interface VoicechatLogger { + + void log(LogLevel level, String message, Object... args); + + boolean isEnabled(LogLevel level); + + default void trace(String message, Object... args){ + log(LogLevel.TRACE, message, args); + } + + default void debug(String message, Object... args){ + log(LogLevel.DEBUG, message, args); + } + + default void info(String message, Object... args){ + log(LogLevel.INFO, message, args); + } + + default void warn(String message, Object... args){ + log(LogLevel.WARN, message, args); + } + + default void error(String message, Object... args){ + log(LogLevel.ERROR, message, args); + } + + default void fatal(String message, Object... args){ + log(LogLevel.FATAL, message, args); + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/AddCategoryPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/AddCategoryPacket.java similarity index 75% rename from source/decompiled/de/maxhenkel/voicechat/net/AddCategoryPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/AddCategoryPacket.java index 08f6954..ed6e775 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/AddCategoryPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/AddCategoryPacket.java @@ -1,20 +1,18 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.plugins.impl.VolumeCategoryImpl; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; -public class AddCategoryPacket -implements Packet { +public class AddCategoryPacket implements Packet { + public static final Key ADD_CATEGORY = Voicechat.compatibility.createNamespacedKey("add_category"); + private VolumeCategoryImpl category; public AddCategoryPacket() { + } public AddCategoryPacket(VolumeCategoryImpl category) { @@ -22,7 +20,7 @@ implements Packet { } public VolumeCategoryImpl getCategory() { - return this.category; + return category; } @Override @@ -32,13 +30,13 @@ implements Packet { @Override public AddCategoryPacket fromBytes(FriendlyByteBuf buf) { - this.category = VolumeCategoryImpl.fromBytes(buf); + category = VolumeCategoryImpl.fromBytes(buf); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - this.category.toBytes(buf); + category.toBytes(buf); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/AddGroupPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/AddGroupPacket.java similarity index 75% rename from source/decompiled/de/maxhenkel/voicechat/net/AddGroupPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/AddGroupPacket.java index 7980f57..ef37d22 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/AddGroupPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/AddGroupPacket.java @@ -1,20 +1,18 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; import de.maxhenkel.voicechat.voice.common.ClientGroup; -public class AddGroupPacket -implements Packet { +public class AddGroupPacket implements Packet { + public static final Key ADD_ADD_GROUP = Voicechat.compatibility.createNamespacedKey("add_group"); + private ClientGroup group; public AddGroupPacket() { + } public AddGroupPacket(ClientGroup group) { @@ -22,7 +20,7 @@ implements Packet { } public ClientGroup getGroup() { - return this.group; + return group; } @Override @@ -32,13 +30,13 @@ implements Packet { @Override public AddGroupPacket fromBytes(FriendlyByteBuf buf) { - this.group = ClientGroup.fromBytes(buf); + group = ClientGroup.fromBytes(buf); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - this.group.toBytes(buf); + group.toBytes(buf); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/CreateGroupPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/CreateGroupPacket.java similarity index 64% rename from source/decompiled/de/maxhenkel/voicechat/net/CreateGroupPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/CreateGroupPacket.java index 392e20b..e7d17b7 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/CreateGroupPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/CreateGroupPacket.java @@ -1,30 +1,25 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.api.Group; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.plugins.impl.GroupImpl; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; -import javax.annotation.Nullable; import org.bukkit.entity.Player; -public class CreateGroupPacket -implements Packet { +import javax.annotation.Nullable; + +public class CreateGroupPacket implements Packet { + public static final Key CREATE_GROUP = Voicechat.compatibility.createNamespacedKey("create_group"); + private String name; @Nullable private String password; private Group.Type type; public CreateGroupPacket() { + } public CreateGroupPacket(String name, @Nullable String password, Group.Type type) { @@ -34,16 +29,16 @@ implements Packet { } public String getName() { - return this.name; + return name; } @Nullable public String getPassword() { - return this.password; + return password; } public Group.Type getType() { - return this.type; + return type; } @Override @@ -58,23 +53,23 @@ implements Packet { @Override public CreateGroupPacket fromBytes(FriendlyByteBuf buf) { - this.name = buf.readUtf(24); - this.password = null; + name = buf.readUtf(Voicechat.MAX_GROUP_NAME_LENGTH); + password = null; if (buf.readBoolean()) { - this.password = buf.readUtf(24); + password = buf.readUtf(Voicechat.MAX_GROUP_NAME_LENGTH); } - this.type = GroupImpl.TypeImpl.fromInt(buf.readShort()); + type = GroupImpl.TypeImpl.fromInt(buf.readShort()); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeUtf(this.name, 24); - buf.writeBoolean(this.password != null); - if (this.password != null) { - buf.writeUtf(this.password, 24); + buf.writeUtf(name, Voicechat.MAX_GROUP_NAME_LENGTH); + buf.writeBoolean(password != null); + if (password != null) { + buf.writeUtf(password, Voicechat.MAX_GROUP_NAME_LENGTH); } - buf.writeShort(GroupImpl.TypeImpl.toInt(this.type)); + buf.writeShort(GroupImpl.TypeImpl.toInt(type)); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/JoinGroupPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/JoinGroupPacket.java similarity index 67% rename from source/decompiled/de/maxhenkel/voicechat/net/JoinGroupPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/JoinGroupPacket.java index 53df9b9..dea102c 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/JoinGroupPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/JoinGroupPacket.java @@ -1,28 +1,23 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; -import java.util.UUID; -import javax.annotation.Nullable; import org.bukkit.entity.Player; -public class JoinGroupPacket -implements Packet { +import javax.annotation.Nullable; +import java.util.UUID; + +public class JoinGroupPacket implements Packet { + public static final Key SET_GROUP = Voicechat.compatibility.createNamespacedKey("set_group"); + private UUID group; @Nullable private String password; public JoinGroupPacket() { + } public JoinGroupPacket(UUID group, @Nullable String password) { @@ -31,12 +26,12 @@ implements Packet { } public UUID getGroup() { - return this.group; + return group; } @Nullable public String getPassword() { - return this.password; + return password; } @Override @@ -51,20 +46,20 @@ implements Packet { @Override public JoinGroupPacket fromBytes(FriendlyByteBuf buf) { - this.group = buf.readUUID(); + group = buf.readUUID(); if (buf.readBoolean()) { - this.password = buf.readUtf(512); + password = buf.readUtf(512); } return this; } @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeUUID(this.group); - buf.writeBoolean(this.password != null); - if (this.password != null) { - buf.writeUtf(this.password, 512); + buf.writeUUID(group); + buf.writeBoolean(password != null); + if (password != null) { + buf.writeUtf(password, 512); } } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/JoinedGroupPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/JoinedGroupPacket.java similarity index 64% rename from source/decompiled/de/maxhenkel/voicechat/net/JoinedGroupPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/JoinedGroupPacket.java index aa4ebda..1d6b81c 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/JoinedGroupPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/JoinedGroupPacket.java @@ -1,26 +1,22 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; -import java.util.UUID; -import javax.annotation.Nullable; -public class JoinedGroupPacket -implements Packet { +import javax.annotation.Nullable; +import java.util.UUID; + +public class JoinedGroupPacket implements Packet { + public static final Key JOINED_GROUP = Voicechat.compatibility.createNamespacedKey("joined_group"); + @Nullable private UUID group; private boolean wrongPassword; public JoinedGroupPacket() { + } public JoinedGroupPacket(@Nullable UUID group, boolean wrongPassword) { @@ -30,11 +26,11 @@ implements Packet { @Nullable public UUID getGroup() { - return this.group; + return group; } public boolean isWrongPassword() { - return this.wrongPassword; + return wrongPassword; } @Override @@ -45,19 +41,19 @@ implements Packet { @Override public JoinedGroupPacket fromBytes(FriendlyByteBuf buf) { if (buf.readBoolean()) { - this.group = buf.readUUID(); + group = buf.readUUID(); } - this.wrongPassword = buf.readBoolean(); + wrongPassword = buf.readBoolean(); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeBoolean(this.group != null); - if (this.group != null) { - buf.writeUUID(this.group); + buf.writeBoolean(group != null); + if (group != null) { + buf.writeUUID(group); } - buf.writeBoolean(this.wrongPassword); + buf.writeBoolean(wrongPassword); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/LeaveGroupPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/LeaveGroupPacket.java similarity index 76% rename from source/decompiled/de/maxhenkel/voicechat/net/LeaveGroupPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/LeaveGroupPacket.java index f7f8fdb..95d39fa 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/LeaveGroupPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/LeaveGroupPacket.java @@ -1,21 +1,18 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; import org.bukkit.entity.Player; -public class LeaveGroupPacket -implements Packet { +public class LeaveGroupPacket implements Packet { + public static final Key LEAVE_GROUP = Voicechat.compatibility.createNamespacedKey("leave_group"); + public LeaveGroupPacket() { + + } + @Override public Key getID() { return LEAVE_GROUP; @@ -33,6 +30,7 @@ implements Packet { @Override public void toBytes(FriendlyByteBuf buf) { - } -} + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/NetManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/NetManager.java new file mode 100644 index 0000000..da80ef5 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/NetManager.java @@ -0,0 +1,132 @@ +package de.maxhenkel.voicechat.net; + +import de.maxhenkel.voicechat.Voicechat; +import de.maxhenkel.voicechat.util.FriendlyByteBuf; +import io.netty.buffer.Unpooled; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.HashSet; +import java.util.Set; + +public class NetManager implements Listener { + + private final Set packets = new HashSet<>(); + + public void onEnable() { + packets.clear(); + Bukkit.getPluginManager().registerEvents(this, Voicechat.INSTANCE); + try { + registerIncomingPacket(UpdateStatePacket.class); + registerIncomingPacket(RequestSecretPacket.class); + registerIncomingPacket(CreateGroupPacket.class); + registerIncomingPacket(JoinGroupPacket.class); + registerIncomingPacket(LeaveGroupPacket.class); + + registerOutgoingPacket(SecretPacket.class); + registerOutgoingPacket(PlayerStatesPacket.class); + registerOutgoingPacket(PlayerStatePacket.class); + registerOutgoingPacket(RemovePlayerStatePacket.class); + registerOutgoingPacket(AddGroupPacket.class); + registerOutgoingPacket(RemoveGroupPacket.class); + registerOutgoingPacket(JoinedGroupPacket.class); + registerOutgoingPacket(AddCategoryPacket.class); + registerOutgoingPacket(RemoveCategoryPacket.class); + } catch (Exception e) { + throw new IllegalStateException("Failed to register voice chat packets", e); + } + } + + public void onDisable() { + Set incomingChannels = Bukkit.getMessenger().getIncomingChannels(Voicechat.INSTANCE); + Set outgoingChannels = Bukkit.getMessenger().getOutgoingChannels(Voicechat.INSTANCE); + for (String channel : incomingChannels) { + Bukkit.getMessenger().unregisterIncomingPluginChannel(Voicechat.INSTANCE, channel); + } + for (String channel : outgoingChannels) { + Bukkit.getMessenger().unregisterOutgoingPluginChannel(Voicechat.INSTANCE, channel); + } + packets.clear(); + } + + public Set getPackets() { + return packets; + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Set outgoingChannels = Bukkit.getMessenger().getOutgoingChannels(Voicechat.INSTANCE); + for (String channel : outgoingChannels) { + Voicechat.compatibility.addChannel(event.getPlayer(), channel); + } + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + Set outgoingChannels = Bukkit.getMessenger().getOutgoingChannels(Voicechat.INSTANCE); + for (String channel : outgoingChannels) { + Voicechat.compatibility.removeChannel(event.getPlayer(), channel); + } + } + + private > void registerIncomingPacket(Class packetClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Constructor c = packetClass.getDeclaredConstructor(); + String id = c.newInstance().getID().toString(); + packets.add(id); + Bukkit.getMessenger().registerIncomingPluginChannel(Voicechat.INSTANCE, id, (s, player, bytes) -> { + if (!Voicechat.SERVER.getRateLimiter().allow(player.getUniqueId())) { + Voicechat.LOGGER.warn("Player {} exceeded packet rate limit", player.getDisplayName()); + player.kickPlayer(Voicechat.TRANSLATIONS.rateLimitKickMessage.get()); + return; + } + T packet; + try { + packet = c.newInstance(); + } catch (Exception e) { + Voicechat.LOGGER.error("Failed to create new packet instance of {}", packetClass.getSimpleName(), e); + return; + } + FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes)); + packet.fromBytes(buffer); + packet.onPacket(player); + }); + } + + private > void registerOutgoingPacket(Class packetClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + String id = packetClass.getDeclaredConstructor().newInstance().getID().toString(); + packets.add(id); + Bukkit.getMessenger().registerOutgoingPluginChannel(Voicechat.INSTANCE, id); + } + + public static void sendToClient(Player player, Packet p) { + Voicechat.compatibility.runTask(() -> { + if (!Voicechat.SERVER.isCompatible(player)) { + return; + } + try { + FriendlyByteBuf buf = new FriendlyByteBuf(); + p.toBytes(buf); + byte[] bytes = new byte[buf.readableBytes()]; + buf.readBytes(bytes); + player.sendPluginMessage(Voicechat.INSTANCE, p.getID().toString(), bytes); + } catch (Exception e) { + Voicechat.LOGGER.error("Failed to send packet to '{}'", player.getName(), e); + } + }); + } + + public static void sendMessage(Player player, String key, String... args) { + Voicechat.compatibility.sendTranslationMessage(player, key, args); + } + + public static void sendStatusMessage(Player player, String key, String... args) { + Voicechat.compatibility.sendStatusMessage(player, key, args); + } + +} \ No newline at end of file diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/Packet.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/Packet.java new file mode 100644 index 0000000..0100c4b --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/Packet.java @@ -0,0 +1,19 @@ +package de.maxhenkel.voicechat.net; + +import de.maxhenkel.voicechat.util.FriendlyByteBuf; +import de.maxhenkel.voicechat.util.Key; +import org.bukkit.entity.Player; + +public interface Packet { + + Key getID(); + + T fromBytes(FriendlyByteBuf buf); + + void toBytes(FriendlyByteBuf buf); + + default void onPacket(Player player) { + + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/PacketRateLimiter.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/PacketRateLimiter.java similarity index 57% rename from source/decompiled/de/maxhenkel/voicechat/net/PacketRateLimiter.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/PacketRateLimiter.java index eed6ec2..84f009b 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/PacketRateLimiter.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/PacketRateLimiter.java @@ -1,17 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.net; +import org.bukkit.entity.Player; + import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import org.bukkit.entity.Player; public class PacketRateLimiter { - private final ConcurrentHashMap rateLimiters = new ConcurrentHashMap(); + + private final ConcurrentHashMap rateLimiters = new ConcurrentHashMap<>(); private final int maxPacketsPerSecond; private final int timeWindowSeconds = 5; @@ -20,15 +16,15 @@ public class PacketRateLimiter { } public boolean allow(UUID player) { - if (this.maxPacketsPerSecond <= 0) { + if (maxPacketsPerSecond <= 0) { return true; } - RateLimiter limiter = this.rateLimiters.computeIfAbsent(player, id -> new RateLimiter(this.maxPacketsPerSecond * 5, 5000L)); + RateLimiter limiter = rateLimiters.computeIfAbsent(player, id -> new RateLimiter(maxPacketsPerSecond * timeWindowSeconds, 1000 * timeWindowSeconds)); return limiter.tryAcquire(); } public void onPlayerLoggedOut(Player player) { - this.rateLimiters.remove(player.getUniqueId()); + rateLimiters.remove(player.getUniqueId()); } private static class RateLimiter { @@ -39,28 +35,31 @@ public class PacketRateLimiter { public RateLimiter(int threshold, long windowMillis) { this.threshold = threshold; - this.timePerTokenNanos = windowMillis * 1000000L / (long)threshold; + this.timePerTokenNanos = (windowMillis * 1_000_000L) / threshold; this.lastLeakNanos = System.nanoTime(); this.amount = 0L; } public boolean tryAcquire() { long currentTime = System.nanoTime(); - long elapsed = currentTime - this.lastLeakNanos; - long leakedTokens = elapsed / this.timePerTokenNanos; - if (leakedTokens > 0L) { - this.amount -= leakedTokens; - if (this.amount < 0L) { - this.amount = 0L; + long elapsed = currentTime - lastLeakNanos; + long leakedTokens = elapsed / timePerTokenNanos; + + if (leakedTokens > 0) { + amount -= leakedTokens; + if (amount < 0) { + amount = 0; } - this.lastLeakNanos += leakedTokens * this.timePerTokenNanos; + lastLeakNanos += leakedTokens * timePerTokenNanos; } - if (this.amount >= (long)this.threshold) { + + if (amount >= threshold) { return false; } - ++this.amount; + + amount++; return true; } } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/PlayerStatePacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/PlayerStatePacket.java similarity index 74% rename from source/decompiled/de/maxhenkel/voicechat/net/PlayerStatePacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/PlayerStatePacket.java index fb93cbc..434bf93 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/PlayerStatePacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/PlayerStatePacket.java @@ -1,20 +1,18 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; import de.maxhenkel.voicechat.voice.common.PlayerState; -public class PlayerStatePacket -implements Packet { +public class PlayerStatePacket implements Packet { + public static final Key PLAYER_STATE = Voicechat.compatibility.createNamespacedKey("state"); + private PlayerState playerState; public PlayerStatePacket() { + } public PlayerStatePacket(PlayerState playerState) { @@ -22,7 +20,7 @@ implements Packet { } public PlayerState getPlayerState() { - return this.playerState; + return playerState; } @Override @@ -32,13 +30,13 @@ implements Packet { @Override public PlayerStatePacket fromBytes(FriendlyByteBuf buf) { - this.playerState = PlayerState.fromBytes(buf); + playerState = PlayerState.fromBytes(buf); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - this.playerState.toBytes(buf); + playerState.toBytes(buf); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/PlayerStatesPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/PlayerStatesPacket.java similarity index 66% rename from source/decompiled/de/maxhenkel/voicechat/net/PlayerStatesPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/PlayerStatesPacket.java index 5a4b730..d436e47 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/PlayerStatesPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/PlayerStatesPacket.java @@ -1,22 +1,20 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; import de.maxhenkel.voicechat.voice.common.PlayerState; -import java.util.ArrayList; -import java.util.Collection; -public class PlayerStatesPacket -implements Packet { +import java.util.*; + +public class PlayerStatesPacket implements Packet { + public static final Key PLAYER_STATES = Voicechat.compatibility.createNamespacedKey("states"); + private Collection playerStates; public PlayerStatesPacket() { + } public PlayerStatesPacket(Collection playerStates) { @@ -24,7 +22,7 @@ implements Packet { } public Collection getPlayerStates() { - return this.playerStates; + return playerStates; } @Override @@ -35,20 +33,21 @@ implements Packet { @Override public PlayerStatesPacket fromBytes(FriendlyByteBuf buf) { int count = buf.readInt(); - this.playerStates = new ArrayList(count); - for (int i = 0; i < count; ++i) { + playerStates = new ArrayList<>(count); + for (int i = 0; i < count; i++) { PlayerState playerState = PlayerState.fromBytes(buf); - this.playerStates.add(playerState); + playerStates.add(playerState); } + return this; } @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeInt(this.playerStates.size()); - for (PlayerState state : this.playerStates) { + buf.writeInt(playerStates.size()); + for (PlayerState state : playerStates) { state.toBytes(buf); } } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/RemoveCategoryPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RemoveCategoryPacket.java similarity index 73% rename from source/decompiled/de/maxhenkel/voicechat/net/RemoveCategoryPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RemoveCategoryPacket.java index e4e7c6d..3358189 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/RemoveCategoryPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RemoveCategoryPacket.java @@ -1,19 +1,17 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; -public class RemoveCategoryPacket -implements Packet { +public class RemoveCategoryPacket implements Packet { + public static final Key REMOVE_CATEGORY = Voicechat.compatibility.createNamespacedKey("remove_category"); + private String categoryId; public RemoveCategoryPacket() { + } public RemoveCategoryPacket(String categoryId) { @@ -21,7 +19,7 @@ implements Packet { } public String getCategoryId() { - return this.categoryId; + return categoryId; } @Override @@ -31,13 +29,13 @@ implements Packet { @Override public RemoveCategoryPacket fromBytes(FriendlyByteBuf buf) { - this.categoryId = buf.readUtf(16); + categoryId = buf.readUtf(16); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeUtf(this.categoryId, 16); + buf.writeUtf(categoryId, 16); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/RemoveGroupPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RemoveGroupPacket.java similarity index 74% rename from source/decompiled/de/maxhenkel/voicechat/net/RemoveGroupPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RemoveGroupPacket.java index cdbd61d..26e8829 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/RemoveGroupPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RemoveGroupPacket.java @@ -1,20 +1,19 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; + import java.util.UUID; -public class RemoveGroupPacket -implements Packet { +public class RemoveGroupPacket implements Packet { + public static final Key REMOVE_GROUP = Voicechat.compatibility.createNamespacedKey("remove_group"); + private UUID groupId; public RemoveGroupPacket() { + } public RemoveGroupPacket(UUID groupId) { @@ -22,7 +21,7 @@ implements Packet { } public UUID getGroupId() { - return this.groupId; + return groupId; } @Override @@ -32,13 +31,13 @@ implements Packet { @Override public RemoveGroupPacket fromBytes(FriendlyByteBuf buf) { - this.groupId = buf.readUUID(); + groupId = buf.readUUID(); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeUUID(this.groupId); + buf.writeUUID(groupId); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/RemovePlayerStatePacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RemovePlayerStatePacket.java similarity index 74% rename from source/decompiled/de/maxhenkel/voicechat/net/RemovePlayerStatePacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RemovePlayerStatePacket.java index 4a5d4b0..351962c 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/RemovePlayerStatePacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RemovePlayerStatePacket.java @@ -1,20 +1,19 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; + import java.util.UUID; -public class RemovePlayerStatePacket -implements Packet { +public class RemovePlayerStatePacket implements Packet { + public static final Key REMOVE_PLAYER_STATE = Voicechat.compatibility.createNamespacedKey("remove_state"); + private UUID id; public RemovePlayerStatePacket() { + } public RemovePlayerStatePacket(UUID id) { @@ -22,7 +21,7 @@ implements Packet { } public UUID getId() { - return this.id; + return id; } @Override @@ -32,13 +31,13 @@ implements Packet { @Override public RemovePlayerStatePacket fromBytes(FriendlyByteBuf buf) { - this.id = buf.readUUID(); + id = buf.readUUID(); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeUUID(this.id); + buf.writeUUID(id); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/RequestSecretPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RequestSecretPacket.java similarity index 71% rename from source/decompiled/de/maxhenkel/voicechat/net/RequestSecretPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RequestSecretPacket.java index d59f0e0..66247d3 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/RequestSecretPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/RequestSecretPacket.java @@ -1,23 +1,18 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; import org.bukkit.entity.Player; -public class RequestSecretPacket -implements Packet { +public class RequestSecretPacket implements Packet { + public static final Key REQUEST_SECRET = Voicechat.compatibility.createNamespacedKey("request_secret"); + private int compatibilityVersion; public RequestSecretPacket() { + } public RequestSecretPacket(int compatibilityVersion) { @@ -25,7 +20,7 @@ implements Packet { } public int getCompatibilityVersion() { - return this.compatibilityVersion; + return compatibilityVersion; } @Override @@ -40,13 +35,13 @@ implements Packet { @Override public RequestSecretPacket fromBytes(FriendlyByteBuf buf) { - this.compatibilityVersion = buf.readInt(); + compatibilityVersion = buf.readInt(); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeInt(this.compatibilityVersion); + buf.writeInt(compatibilityVersion); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/SecretPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/SecretPacket.java similarity index 59% rename from source/decompiled/de/maxhenkel/voicechat/net/SecretPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/SecretPacket.java index 93f0071..0670c37 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/SecretPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/SecretPacket.java @@ -1,23 +1,18 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.config.ServerConfig; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; import de.maxhenkel.voicechat.voice.common.Secret; -import java.util.UUID; import org.bukkit.entity.Player; -public class SecretPacket -implements Packet { +import java.util.UUID; + +public class SecretPacket implements Packet { + public static final Key SECRET = Voicechat.compatibility.createNamespacedKey("secret"); + private Secret secret; private int serverPort; private UUID playerUUID; @@ -30,6 +25,7 @@ implements Packet { private boolean allowRecording; public SecretPacket() { + } public SecretPacket(Player player, Secret secret, int port, ServerConfig serverConfig, String voiceHost) { @@ -46,39 +42,39 @@ implements Packet { } public Secret getSecret() { - return this.secret; + return secret; } public int getServerPort() { - return this.serverPort; + return serverPort; } public UUID getPlayerUUID() { - return this.playerUUID; + return playerUUID; } public ServerConfig.Codec getCodec() { - return this.codec; + return codec; } public int getMtuSize() { - return this.mtuSize; + return mtuSize; } public double getVoiceChatDistance() { - return this.voiceChatDistance; + return voiceChatDistance; } public int getKeepAlive() { - return this.keepAlive; + return keepAlive; } public boolean groupsEnabled() { - return this.groupsEnabled; + return groupsEnabled; } public String getVoiceHost() { - return this.voiceHost; + return voiceHost; } @Override @@ -87,36 +83,36 @@ implements Packet { } public boolean allowRecording() { - return this.allowRecording; + return allowRecording; } @Override public SecretPacket fromBytes(FriendlyByteBuf buf) { - this.secret = Secret.fromBytes(buf); - this.serverPort = buf.readInt(); - this.playerUUID = buf.readUUID(); - this.codec = ServerConfig.Codec.values()[buf.readByte()]; - this.mtuSize = buf.readInt(); - this.voiceChatDistance = buf.readDouble(); - this.keepAlive = buf.readInt(); - this.groupsEnabled = buf.readBoolean(); - this.voiceHost = buf.readUtf(); - this.allowRecording = buf.readBoolean(); + secret = Secret.fromBytes(buf); + serverPort = buf.readInt(); + playerUUID = buf.readUUID(); + codec = ServerConfig.Codec.values()[buf.readByte()]; + mtuSize = buf.readInt(); + voiceChatDistance = buf.readDouble(); + keepAlive = buf.readInt(); + groupsEnabled = buf.readBoolean(); + voiceHost = buf.readUtf(); + allowRecording = buf.readBoolean(); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - this.secret.toBytes(buf); - buf.writeInt(this.serverPort); - buf.writeUUID(this.playerUUID); - buf.writeByte(this.codec.ordinal()); - buf.writeInt(this.mtuSize); - buf.writeDouble(this.voiceChatDistance); - buf.writeInt(this.keepAlive); - buf.writeBoolean(this.groupsEnabled); - buf.writeUtf(this.voiceHost); - buf.writeBoolean(this.allowRecording); + secret.toBytes(buf); + buf.writeInt(serverPort); + buf.writeUUID(playerUUID); + buf.writeByte(codec.ordinal()); + buf.writeInt(mtuSize); + buf.writeDouble(voiceChatDistance); + buf.writeInt(keepAlive); + buf.writeBoolean(groupsEnabled); + buf.writeUtf(voiceHost); + buf.writeBoolean(allowRecording); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/net/UpdateStatePacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/UpdateStatePacket.java similarity index 73% rename from source/decompiled/de/maxhenkel/voicechat/net/UpdateStatePacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/net/UpdateStatePacket.java index 0f467c6..45fdcad 100644 --- a/source/decompiled/de/maxhenkel/voicechat/net/UpdateStatePacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/net/UpdateStatePacket.java @@ -1,23 +1,18 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.net; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.Packet; import de.maxhenkel.voicechat.util.FriendlyByteBuf; import de.maxhenkel.voicechat.util.Key; import org.bukkit.entity.Player; -public class UpdateStatePacket -implements Packet { +public class UpdateStatePacket implements Packet { + public static final Key PLAYER_STATE = Voicechat.compatibility.createNamespacedKey("update_state"); + private boolean disabled; public UpdateStatePacket() { + } public UpdateStatePacket(boolean disabled) { @@ -25,7 +20,7 @@ implements Packet { } public boolean isDisabled() { - return this.disabled; + return disabled; } @Override @@ -40,13 +35,13 @@ implements Packet { @Override public UpdateStatePacket fromBytes(FriendlyByteBuf buf) { - this.disabled = buf.readBoolean(); + disabled = buf.readBoolean(); return this; } @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeBoolean(this.disabled); + buf.writeBoolean(disabled); } -} +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/permission/PermissionManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/permission/PermissionManager.java new file mode 100644 index 0000000..8e28e69 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/permission/PermissionManager.java @@ -0,0 +1,14 @@ +package de.maxhenkel.voicechat.permission; + +import de.maxhenkel.voicechat.Voicechat; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; + +public class PermissionManager { + + public static Permission LISTEN_PERMISSION = new Permission(Voicechat.MODID + ".listen", PermissionDefault.TRUE); + public static Permission SPEAK_PERMISSION = new Permission(Voicechat.MODID + ".speak", PermissionDefault.TRUE); + public static Permission GROUPS_PERMISSION = new Permission(Voicechat.MODID + ".groups", PermissionDefault.TRUE); + public static Permission ADMIN_PERMISSION = new Permission(Voicechat.MODID + ".admin", PermissionDefault.OP); + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/CategoryManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/CategoryManager.java similarity index 56% rename from source/decompiled/de/maxhenkel/voicechat/plugins/CategoryManager.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/CategoryManager.java index 11a1939..b22eef1 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/CategoryManager.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/CategoryManager.java @@ -1,31 +1,30 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins; import de.maxhenkel.voicechat.plugins.impl.VolumeCategoryImpl; + +import javax.annotation.Nullable; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import javax.annotation.Nullable; public class CategoryManager { - protected final Map categories = new ConcurrentHashMap(); + + protected final Map categories; + + public CategoryManager() { + categories = new ConcurrentHashMap<>(); + } public void addCategory(VolumeCategoryImpl category) { - this.categories.put(category.getId(), category); + categories.put(category.getId(), category); } @Nullable public VolumeCategoryImpl removeCategory(String categoryId) { - return this.categories.remove(categoryId); + return categories.remove(categoryId); } public Collection getCategories() { - return this.categories.values(); + return categories.values(); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/EventBuilder.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/EventBuilder.java similarity index 62% rename from source/decompiled/de/maxhenkel/voicechat/plugins/EventBuilder.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/EventBuilder.java index bfaf2a4..766a00e 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/EventBuilder.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/EventBuilder.java @@ -1,9 +1,7 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins; import de.maxhenkel.voicechat.api.events.Event; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -12,22 +10,24 @@ import java.util.function.Consumer; import java.util.stream.Collectors; public class EventBuilder { - private final Map, List>>> events = new HashMap, List>>>(); + + private final Map, List>>> events; private EventBuilder() { + events = new HashMap<>(); } public EventBuilder addEvent(Class eventClass, Consumer event, int priority) { - List eventList = this.events.getOrDefault(eventClass, new ArrayList()); - eventList.add(new Tuple>(priority, event)); + List>> eventList = this.events.getOrDefault(eventClass, new ArrayList<>()); + eventList.add(new Tuple<>(priority, event)); this.events.put(eventClass, eventList); return this; } public Map, List>> build() { - HashMap, List>> result = new HashMap, List>>(); - for (Map.Entry, List>>> entry : this.events.entrySet()) { - result.put(entry.getKey(), entry.getValue().stream().sorted((o1, o2) -> Integer.compare((Integer)o2.getA(), (Integer)o1.getA())).map(Tuple::getB).collect(Collectors.toList())); + Map, List>> result = new HashMap<>(); + for (Map.Entry, List>>> entry : events.entrySet()) { + result.put(entry.getKey(), entry.getValue().stream().sorted((o1, o2) -> Integer.compare(o2.getA(), o1.getA())).map(Tuple::getB).collect(Collectors.toList())); } return result; } @@ -46,12 +46,12 @@ public class EventBuilder { } public A getA() { - return this.a; + return a; } public B getB() { - return this.b; + return b; } } -} +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/PluginManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/PluginManager.java new file mode 100644 index 0000000..d769775 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/PluginManager.java @@ -0,0 +1,300 @@ +package de.maxhenkel.voicechat.plugins; + +import de.maxhenkel.voicechat.Voicechat; +import de.maxhenkel.voicechat.api.VoicechatConnection; +import de.maxhenkel.voicechat.api.VoicechatPlugin; +import de.maxhenkel.voicechat.api.VoicechatSocket; +import de.maxhenkel.voicechat.api.VolumeCategory; +import de.maxhenkel.voicechat.api.audiolistener.AudioListener; +import de.maxhenkel.voicechat.api.audiolistener.PlayerAudioListener; +import de.maxhenkel.voicechat.api.events.*; +import de.maxhenkel.voicechat.plugins.impl.GroupImpl; +import de.maxhenkel.voicechat.plugins.impl.VoicechatConnectionImpl; +import de.maxhenkel.voicechat.plugins.impl.VoicechatServerApiImpl; +import de.maxhenkel.voicechat.plugins.impl.VoicechatSocketImpl; +import de.maxhenkel.voicechat.plugins.impl.audiolistener.PlayerAudioListenerImpl; +import de.maxhenkel.voicechat.plugins.impl.events.*; +import de.maxhenkel.voicechat.plugins.impl.packets.*; +import de.maxhenkel.voicechat.voice.common.*; +import de.maxhenkel.voicechat.voice.server.Group; +import de.maxhenkel.voicechat.voice.server.Server; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; + +public class PluginManager { + + private List plugins; + private Map, List>> events; + private final Map> playerAudioListeners = new ConcurrentHashMap<>(); + + public void init() { + Voicechat.LOGGER.info("Loading plugins"); + plugins = Voicechat.apiService.getPlugins(); + Voicechat.LOGGER.info("Loaded {} plugin(s)", plugins.size()); + Voicechat.LOGGER.info("Initializing plugins"); + for (VoicechatPlugin plugin : plugins) { + try { + plugin.initialize(VoicechatServerApiImpl.instance()); + } catch (Exception e) { + Voicechat.LOGGER.error("Failed to initialize plugin '{}'", plugin.getPluginId(), e); + } + } + Voicechat.LOGGER.info("Initialized {} plugin(s)", plugins.size()); + gatherEvents(); + } + + private void gatherEvents() { + EventBuilder eventBuilder = EventBuilder.create(); + EventRegistration registration = eventBuilder::addEvent; + for (VoicechatPlugin plugin : plugins) { + Voicechat.LOGGER.info("Registering events for '{}'", plugin.getPluginId()); + try { + plugin.registerEvents(registration); + } catch (Throwable t) { + Voicechat.LOGGER.error("Failed to register events for '{}'", plugin.getPluginId(), t); + } + } + events = eventBuilder.build(); + } + + public synchronized boolean registerAudioListener(AudioListener l) { + if (!(l instanceof PlayerAudioListener)) { + return false; + } + PlayerAudioListener listener = (PlayerAudioListener) l; + boolean exists = playerAudioListeners + .values() + .stream() + .anyMatch(listeners -> + listeners + .stream() + .anyMatch(playerAudioListener -> playerAudioListener.getListenerId().equals(listener.getListenerId())) + ); + + if (exists) { + return false; + } + + playerAudioListeners.computeIfAbsent(listener.getPlayerUuid(), k -> new CopyOnWriteArrayList<>()).add(listener); + return true; + } + + public synchronized boolean unregisterAudioListener(UUID listenerId) { + boolean removed = playerAudioListeners + .values() + .stream() + .anyMatch(listeners -> + listeners.removeIf(listener -> listener.getListenerId().equals(listenerId)) + ); + if (!removed) { + return false; + } + playerAudioListeners.values().removeIf(List::isEmpty); + return true; + } + + public List getPlayerAudioListeners(UUID playerUuid) { + return playerAudioListeners.getOrDefault(playerUuid, Collections.emptyList()); + } + + public void onListenerAudio(UUID playerUuid, SoundPacket packet) { + if (playerUuid.equals(packet.getSender())) { + return; + } + List listeners = getPlayerAudioListeners(playerUuid); + if (listeners.isEmpty()) { + return; + } + + SoundPacketImpl soundPacket; + if (packet instanceof GroupSoundPacket) { + soundPacket = new StaticSoundPacketImpl((GroupSoundPacket) packet); + } else if (packet instanceof PlayerSoundPacket) { + soundPacket = new EntitySoundPacketImpl((PlayerSoundPacket) packet); + } else if (packet instanceof LocationSoundPacket) { + soundPacket = new LocationalSoundPacketImpl((LocationSoundPacket) packet); + } else { + soundPacket = new SoundPacketImpl(packet); + } + + for (PlayerAudioListener l : listeners) { + if (l instanceof PlayerAudioListenerImpl) { + try { + ((PlayerAudioListenerImpl) l).getListener().accept(soundPacket); + } catch (Throwable t) { + Voicechat.LOGGER.error("Failed to process audio listener", t); + } + } + } + } + + public boolean dispatchEvent(Class eventClass, T event) { + List> events = this.events.get(eventClass); + if (events == null) { + return false; + } + for (Consumer evt : events) { + try { + Consumer e = (Consumer) evt; + e.accept(event); + if (event.isCancelled()) { + break; + } + } catch (Throwable t) { + Voicechat.LOGGER.error("Failed to dispatch event '{}'", eventClass.getSimpleName(), t); + } + } + return event.isCancelled(); + } + + public VoicechatSocket getSocketImplementation() { + VoicechatServerStartingEventImpl event = new VoicechatServerStartingEventImpl(); + dispatchEvent(VoicechatServerStartingEvent.class, event); + VoicechatSocket socket = event.getSocketImplementation(); + if (socket == null) { + socket = new VoicechatSocketImpl(); + Voicechat.LOGGER.debug("Using default voicechat socket implementation"); + } else { + Voicechat.LOGGER.info("Using custom voicechat socket implementation: {}", socket.getClass().getName()); + } + return socket; + } + + public String getVoiceHost(Player player, String voiceHost) { + VoiceHostEventImpl event = new VoiceHostEventImpl(player, voiceHost); + dispatchEvent(VoiceHostEvent.class, event); + return event.getVoiceHost(); + } + + public void onRegisterVolumeCategory(VolumeCategory category) { + dispatchEvent(RegisterVolumeCategoryEvent.class, new RegisterVolumeCategoryEventImpl(category)); + } + + public void onUnregisterVolumeCategory(VolumeCategory category) { + dispatchEvent(UnregisterVolumeCategoryEvent.class, new UnregisterVolumeCategoryEventImpl(category)); + } + + public void onServerStarted() { + dispatchEvent(VoicechatServerStartedEvent.class, new VoicechatServerStartedEventImpl()); + } + + public void onServerStopped() { + dispatchEvent(VoicechatServerStoppedEvent.class, new VoicechatServerStoppedEventImpl()); + } + + public void onPlayerConnected(@Nullable Player player) { + if (player == null) { + return; + } + dispatchEvent(PlayerConnectedEvent.class, new PlayerConnectedEventImpl(VoicechatConnectionImpl.fromPlayer(player))); + } + + public void onPlayerDisconnected(UUID player) { + dispatchEvent(PlayerDisconnectedEvent.class, new PlayerDisconnectedEventImpl(player)); + } + + public void onPlayerStateChanged(PlayerState state) { + dispatchEvent(PlayerStateChangedEvent.class, new PlayerStateChangedEventImpl(state)); + } + + public boolean onJoinGroup(Player player, @Nullable Group group) { + if (group == null) { + return onLeaveGroup(player); + } + return dispatchEvent(JoinGroupEvent.class, new JoinGroupEventImpl(new GroupImpl(group), VoicechatConnectionImpl.fromPlayer(player))); + } + + public boolean onCreateGroup(@Nullable Player player, @Nullable Group group) { + if (group == null) { + if (player == null) { + return false; + } + return onLeaveGroup(player); + } + return dispatchEvent(CreateGroupEvent.class, new CreateGroupEventImpl(new GroupImpl(group), VoicechatConnectionImpl.fromPlayer(player))); + } + + public boolean onLeaveGroup(Player player) { + Server server = Voicechat.SERVER.getServer(); + if (server == null) { + return false; + } + @Nullable GroupImpl group = null; + PlayerState state = server.getPlayerStateManager().getState(player.getUniqueId()); + if (state != null) { + UUID groupUUID = state.getGroup(); + if (groupUUID != null) { + Group g = server.getGroupManager().getGroup(groupUUID); + if (g != null) { + group = new GroupImpl(g); + } + } + } + + return dispatchEvent(LeaveGroupEvent.class, new LeaveGroupEventImpl(group, VoicechatConnectionImpl.fromPlayer(player))); + } + + public boolean onRemoveGroup(Group group) { + return dispatchEvent(RemoveGroupEvent.class, new RemoveGroupEventImpl(new GroupImpl(group))); + } + + public boolean onMicPacket(Player sender, PlayerState senderState, MicPacket packet) { + return dispatchEvent(MicrophonePacketEvent.class, new MicrophonePacketEventImpl( + new MicrophonePacketImpl(packet, sender.getUniqueId()), + new VoicechatConnectionImpl(sender, senderState) + )); + } + + public float getDistance(Player sender, PlayerState senderState, MicPacket packet, float originalDistance) { + VoiceDistanceEventImpl event = new VoiceDistanceEventImpl(new MicrophonePacketImpl(packet, sender.getUniqueId()), new VoicechatConnectionImpl(sender, senderState), originalDistance); + dispatchEvent(VoiceDistanceEvent.class, event); + return event.getDistance(); + } + + public boolean onSoundPacket(@Nullable Player sender, @Nullable PlayerState senderState, Player receiver, PlayerState receiverState, SoundPacket p, String source) { + VoicechatConnection senderConnection = null; + if (sender != null && senderState != null) { + senderConnection = new VoicechatConnectionImpl(sender, senderState); + } + + VoicechatConnection receiverConnection = new VoicechatConnectionImpl(receiver, receiverState); + if (p instanceof LocationSoundPacket) { + return dispatchEvent(LocationalSoundPacketEvent.class, new LocationalSoundPacketEventImpl( + new LocationalSoundPacketImpl((LocationSoundPacket) p), + senderConnection, + receiverConnection, + source + )); + } else if (p instanceof PlayerSoundPacket) { + return dispatchEvent(EntitySoundPacketEvent.class, new EntitySoundPacketEventImpl( + new EntitySoundPacketImpl((PlayerSoundPacket) p), + senderConnection, + receiverConnection, + source + )); + } else if (p instanceof GroupSoundPacket) { + return dispatchEvent(StaticSoundPacketEvent.class, new StaticSoundPacketEventImpl( + new StaticSoundPacketImpl((GroupSoundPacket) p), + senderConnection, + receiverConnection, + source + )); + } + return false; + } + + private static PluginManager instance; + + public static synchronized PluginManager instance() { + if (instance == null) { + instance = new PluginManager(); + } + return instance; + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/BukkitVoicechatServiceImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/BukkitVoicechatServiceImpl.java similarity index 56% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/BukkitVoicechatServiceImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/BukkitVoicechatServiceImpl.java index 69e22ba..30439de 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/BukkitVoicechatServiceImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/BukkitVoicechatServiceImpl.java @@ -1,24 +1,25 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl; import de.maxhenkel.voicechat.api.BukkitVoicechatService; import de.maxhenkel.voicechat.api.VoicechatPlugin; + import java.util.ArrayList; import java.util.List; -public class BukkitVoicechatServiceImpl -implements BukkitVoicechatService { - private final List plugins = new ArrayList(); +public class BukkitVoicechatServiceImpl implements BukkitVoicechatService { + + private final List plugins; + + public BukkitVoicechatServiceImpl() { + plugins = new ArrayList<>(); + } @Override public void registerPlugin(VoicechatPlugin plugin) { - this.plugins.add(plugin); + plugins.add(plugin); } public List getPlugins() { - return this.plugins; + return plugins; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/EntityImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/EntityImpl.java similarity index 54% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/EntityImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/EntityImpl.java index 371815c..cdb3463 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/EntityImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/EntityImpl.java @@ -1,19 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Entity - */ package de.maxhenkel.voicechat.plugins.impl; import de.maxhenkel.voicechat.api.Entity; import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.plugins.impl.PositionImpl; + import java.util.Objects; import java.util.UUID; -public class EntityImpl -implements Entity { +public class EntityImpl implements Entity { + protected org.bukkit.entity.Entity entity; public EntityImpl(org.bukkit.entity.Entity entity) { @@ -22,36 +16,38 @@ implements Entity { @Override public UUID getUuid() { - return this.entity.getUniqueId(); + return entity.getUniqueId(); } @Override public Object getEntity() { - return this.entity; + return entity; } @Override public Position getPosition() { - return new PositionImpl(this.entity.getLocation()); + return new PositionImpl(entity.getLocation()); } public org.bukkit.entity.Entity getRealEntity() { - return this.entity; + return entity; } + @Override public boolean equals(Object object) { if (this == object) { return true; } - if (object == null || this.getClass() != object.getClass()) { + if (object == null || getClass() != object.getClass()) { return false; } - EntityImpl entity1 = (EntityImpl)object; - return Objects.equals(this.entity, entity1.entity); + EntityImpl entity1 = (EntityImpl) object; + return Objects.equals(entity, entity1.entity); } + @Override public int hashCode() { - return this.entity != null ? this.entity.hashCode() : 0; + return entity != null ? entity.hashCode() : 0; } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/GroupImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/GroupImpl.java similarity index 58% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/GroupImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/GroupImpl.java index 27f02da..9617ca6 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/GroupImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/GroupImpl.java @@ -1,113 +1,88 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.api.Group; import de.maxhenkel.voicechat.voice.common.PlayerState; -import de.maxhenkel.voicechat.voice.server.Group; import de.maxhenkel.voicechat.voice.server.Server; + +import javax.annotation.Nullable; import java.util.Objects; import java.util.UUID; -import javax.annotation.Nullable; -public class GroupImpl -implements de.maxhenkel.voicechat.api.Group { - private final Group group; +public class GroupImpl implements Group { - public GroupImpl(Group group) { + private final de.maxhenkel.voicechat.voice.server.Group group; + + public GroupImpl(de.maxhenkel.voicechat.voice.server.Group group) { this.group = group; } @Override public String getName() { - return this.group.getName(); + return group.getName(); } @Override public boolean hasPassword() { - return this.group.getPassword() != null; + return group.getPassword() != null; } @Override public UUID getId() { - return this.group.getId(); + return group.getId(); } @Override public boolean isPersistent() { - return this.group.isPersistent(); + return group.isPersistent(); } @Override public boolean isHidden() { - return this.group.isHidden(); + return group.isHidden(); } @Override - public Group.Type getType() { - return this.group.getType(); + public Type getType() { + return group.getType(); } - public Group getGroup() { - return this.group; + public de.maxhenkel.voicechat.voice.server.Group getGroup() { + return group; } @Nullable public static GroupImpl create(PlayerState state) { - Group g; UUID groupId = state.getGroup(); Server server = Voicechat.SERVER.getServer(); - if (server != null && groupId != null && (g = server.getGroupManager().getGroup(groupId)) != null) { - return new GroupImpl(g); + if (server != null && groupId != null) { + de.maxhenkel.voicechat.voice.server.Group g = server.getGroupManager().getGroup(groupId); + if (g != null) { + return new GroupImpl(g); + } } return null; } + @Override public boolean equals(Object object) { if (this == object) { return true; } - if (object == null || this.getClass() != object.getClass()) { + if (object == null || getClass() != object.getClass()) { return false; } - GroupImpl group1 = (GroupImpl)object; - return Objects.equals(this.group.getId(), group1.group.getId()); + GroupImpl group1 = (GroupImpl) object; + return Objects.equals(group.getId(), group1.group.getId()); } + @Override public int hashCode() { - return this.group != null ? this.group.getId().hashCode() : 0; + return group != null ? group.getId().hashCode() : 0; } - public static class TypeImpl - implements Group.Type { - public static short toInt(Group.Type type) { - if (type == OPEN) { - return 1; - } - if (type == ISOLATED) { - return 2; - } - return 0; - } + public static class BuilderImpl implements Group.Builder { - public static Group.Type fromInt(short i) { - if (i == 1) { - return OPEN; - } - if (i == 2) { - return ISOLATED; - } - return NORMAL; - } - } - - public static class BuilderImpl - implements Group.Builder { @Nullable private UUID id; private String name; @@ -115,10 +90,14 @@ implements de.maxhenkel.voicechat.api.Group { private String password; private boolean persistent; private boolean hidden; - private Group.Type type = Group.Type.NORMAL; + private Type type; + + public BuilderImpl() { + type = Type.NORMAL; + } @Override - public Group.Builder setId(@Nullable UUID id) { + public Builder setId(@Nullable UUID id) { this.id = id; return this; } @@ -126,12 +105,13 @@ implements de.maxhenkel.voicechat.api.Group { @Override public Group.Builder setName(String name) { this.name = name; - this.name = BuilderImpl.convertGroupName(name); + this.name = convertGroupName(name); return this; } private static String convertGroupName(String name) { - if ((name = name.replaceAll("[\\n\\r\\t]", "")).matches("^\\s.*")) { + name = name.replaceAll("[\\n\\r\\t]", ""); + if (name.matches("^\\s.*")) { name = name.replaceFirst("^\\s+", ""); } if (name.length() > 16) { @@ -153,32 +133,55 @@ implements de.maxhenkel.voicechat.api.Group { } @Override - public Group.Builder setHidden(boolean hidden) { + public Builder setHidden(boolean hidden) { this.hidden = hidden; return this; } @Override - public Group.Builder setType(Group.Type type) { + public Group.Builder setType(Type type) { this.type = type; return this; } @Override - public de.maxhenkel.voicechat.api.Group build() { - if (this.name == null) { + public Group build() { + if (name == null) { throw new IllegalStateException("Group is missing a name"); } - if (!Voicechat.GROUP_REGEX.matcher(this.name).matches()) { - throw new IllegalStateException(String.format("Invalid group name: %s", this.name)); + if (!Voicechat.GROUP_REGEX.matcher(name).matches()) { + throw new IllegalStateException(String.format("Invalid group name: %s", name)); } - GroupImpl group = new GroupImpl(new Group(this.id == null ? UUID.randomUUID() : this.id, this.name, this.password, this.persistent, this.hidden, this.type)); + GroupImpl group = new GroupImpl(new de.maxhenkel.voicechat.voice.server.Group(id == null ? UUID.randomUUID() : id, name, password, persistent, hidden, type)); Server server = Voicechat.SERVER.getServer(); - if (server != null && this.persistent) { + if (server != null && persistent) { server.getGroupManager().addGroup(group.getGroup(), null); } return group; } } -} + public static class TypeImpl implements Group.Type { + + public static short toInt(Group.Type type) { + if (type == OPEN) { + return 1; + } else if (type == ISOLATED) { + return 2; + } else { + return 0; + } + } + + public static Group.Type fromInt(short i) { + if (i == 1) { + return OPEN; + } else if (i == 2) { + return ISOLATED; + } else { + return NORMAL; + } + } + } + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/PlayerImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/PlayerImpl.java new file mode 100644 index 0000000..7fbbf77 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/PlayerImpl.java @@ -0,0 +1,20 @@ +package de.maxhenkel.voicechat.plugins.impl; + +import de.maxhenkel.voicechat.api.Player; + +public class PlayerImpl extends EntityImpl implements Player { + + public PlayerImpl(org.bukkit.entity.Player entity) { + super(entity); + } + + @Override + public Object getPlayer() { + return entity; + } + + public org.bukkit.entity.Player getRealPlayer() { + return (org.bukkit.entity.Player) entity; + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/PositionImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/PositionImpl.java similarity index 57% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/PositionImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/PositionImpl.java index 2dc6695..3a5d403 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/PositionImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/PositionImpl.java @@ -1,17 +1,12 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.Location - */ package de.maxhenkel.voicechat.plugins.impl; import de.maxhenkel.voicechat.api.Position; -import java.util.Objects; import org.bukkit.Location; -public class PositionImpl -implements Position { +import java.util.Objects; + +public class PositionImpl implements Position { + private final Location position; public PositionImpl(Location position) { @@ -24,36 +19,37 @@ implements Position { @Override public double getX() { - return this.position.getX(); + return position.getX(); } @Override public double getY() { - return this.position.getY(); + return position.getY(); } @Override public double getZ() { - return this.position.getZ(); + return position.getZ(); } public Location getPosition() { - return this.position; + return position; } + @Override public boolean equals(Object object) { if (this == object) { return true; } - if (object == null || this.getClass() != object.getClass()) { + if (object == null || getClass() != object.getClass()) { return false; } - PositionImpl position1 = (PositionImpl)object; - return Objects.equals(this.position, position1.position); + PositionImpl position1 = (PositionImpl) object; + return Objects.equals(position, position1.position); } + @Override public int hashCode() { - return this.position != null ? this.position.hashCode() : 0; + return position != null ? position.hashCode() : 0; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/RawUdpPacketImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/RawUdpPacketImpl.java similarity index 78% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/RawUdpPacketImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/RawUdpPacketImpl.java index 7454bfe..2e4ad42 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/RawUdpPacketImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/RawUdpPacketImpl.java @@ -1,14 +1,13 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl; import de.maxhenkel.voicechat.api.RawUdpPacket; + import java.net.SocketAddress; -public class RawUdpPacketImpl -implements RawUdpPacket { +public class RawUdpPacketImpl implements RawUdpPacket { + private static final byte[] BUFFER = new byte[4096]; + private final byte[] data; private final SocketAddress socketAddress; private final long timestamp; @@ -21,17 +20,16 @@ implements RawUdpPacket { @Override public byte[] getData() { - return this.data; + return data; } @Override public long getTimestamp() { - return this.timestamp; + return timestamp; } @Override public SocketAddress getSocketAddress() { - return this.socketAddress; + return socketAddress; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/ServerLevelImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/ServerLevelImpl.java similarity index 53% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/ServerLevelImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/ServerLevelImpl.java index 8300659..4b8fc73 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/ServerLevelImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/ServerLevelImpl.java @@ -1,17 +1,12 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.World - */ package de.maxhenkel.voicechat.plugins.impl; import de.maxhenkel.voicechat.api.ServerLevel; -import java.util.Objects; import org.bukkit.World; -public class ServerLevelImpl -implements ServerLevel { +import java.util.Objects; + +public class ServerLevelImpl implements ServerLevel { + private final World serverLevel; public ServerLevelImpl(World serverLevel) { @@ -20,22 +15,23 @@ implements ServerLevel { @Override public Object getServerLevel() { - return this.serverLevel; + return serverLevel; } + @Override public boolean equals(Object object) { if (this == object) { return true; } - if (object == null || this.getClass() != object.getClass()) { + if (object == null || getClass() != object.getClass()) { return false; } - ServerLevelImpl that = (ServerLevelImpl)object; - return Objects.equals(this.serverLevel, that.serverLevel); + ServerLevelImpl that = (ServerLevelImpl) object; + return Objects.equals(serverLevel, that.serverLevel); } + @Override public int hashCode() { - return this.serverLevel != null ? this.serverLevel.hashCode() : 0; + return serverLevel != null ? serverLevel.hashCode() : 0; } } - diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/ServerPlayerImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/ServerPlayerImpl.java new file mode 100644 index 0000000..9672924 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/ServerPlayerImpl.java @@ -0,0 +1,21 @@ +package de.maxhenkel.voicechat.plugins.impl; + +import de.maxhenkel.voicechat.api.ServerLevel; +import de.maxhenkel.voicechat.api.ServerPlayer; +import org.bukkit.entity.Player; + +public class ServerPlayerImpl extends PlayerImpl implements ServerPlayer { + + public ServerPlayerImpl(Player entity) { + super(entity); + } + + public Player getRealServerPlayer() { + return (Player) entity; + } + + @Override + public ServerLevel getServerLevel() { + return new ServerLevelImpl(entity.getWorld()); + } +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatApiImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatApiImpl.java similarity index 62% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatApiImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatApiImpl.java index 392892e..cac8199 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatApiImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatApiImpl.java @@ -1,43 +1,24 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.World - * org.bukkit.entity.Entity - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.plugins.impl; -import de.maxhenkel.voicechat.api.Entity; -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.ServerLevel; -import de.maxhenkel.voicechat.api.ServerPlayer; -import de.maxhenkel.voicechat.api.VoicechatApi; -import de.maxhenkel.voicechat.api.VolumeCategory; +import de.maxhenkel.voicechat.api.*; import de.maxhenkel.voicechat.api.audio.AudioConverter; import de.maxhenkel.voicechat.api.mp3.Mp3Decoder; import de.maxhenkel.voicechat.api.mp3.Mp3Encoder; import de.maxhenkel.voicechat.api.opus.OpusDecoder; import de.maxhenkel.voicechat.api.opus.OpusEncoder; import de.maxhenkel.voicechat.api.opus.OpusEncoderMode; -import de.maxhenkel.voicechat.plugins.impl.EntityImpl; -import de.maxhenkel.voicechat.plugins.impl.PositionImpl; -import de.maxhenkel.voicechat.plugins.impl.ServerLevelImpl; -import de.maxhenkel.voicechat.plugins.impl.ServerPlayerImpl; -import de.maxhenkel.voicechat.plugins.impl.VolumeCategoryImpl; import de.maxhenkel.voicechat.plugins.impl.audio.AudioConverterImpl; import de.maxhenkel.voicechat.plugins.impl.opus.OpusManager; import de.maxhenkel.voicechat.voice.common.Utils; -import java.io.InputStream; -import java.io.OutputStream; +import org.bukkit.World; + import javax.annotation.Nullable; import javax.sound.sampled.AudioFormat; -import org.bukkit.World; -import org.bukkit.entity.Player; +import java.io.InputStream; +import java.io.OutputStream; + +public abstract class VoicechatApiImpl implements VoicechatApi { -public abstract class VoicechatApiImpl -implements VoicechatApi { private static final AudioConverter AUDIO_CONVERTER = new AudioConverterImpl(); @Override @@ -50,14 +31,14 @@ implements VoicechatApi { return OpusManager.createEncoder(mode); } - @Override @Nullable + @Override public Mp3Encoder createMp3Encoder(AudioFormat audioFormat, int bitrate, int quality, OutputStream outputStream) { return null; } - @Override @Nullable + @Override public Mp3Decoder createMp3Decoder(InputStream inputStream) { return null; } @@ -67,7 +48,6 @@ implements VoicechatApi { return OpusManager.createDecoder(); } - @Override public AudioConverter getAudioConverter() { return AUDIO_CONVERTER; } @@ -75,25 +55,28 @@ implements VoicechatApi { @Override public Entity fromEntity(Object entity) { if (entity instanceof org.bukkit.entity.Entity) { - return new EntityImpl((org.bukkit.entity.Entity)entity); + return new EntityImpl((org.bukkit.entity.Entity) entity); + } else { + throw new IllegalArgumentException("entity is not an instance of Entity"); } - throw new IllegalArgumentException("entity is not an instance of Entity"); } @Override public ServerLevel fromServerLevel(Object serverLevel) { if (serverLevel instanceof World) { - return new ServerLevelImpl((World)serverLevel); + return new ServerLevelImpl((World) serverLevel); + } else { + throw new IllegalArgumentException("serverLevel is not an instance of World"); } - throw new IllegalArgumentException("serverLevel is not an instance of World"); } @Override public ServerPlayer fromServerPlayer(Object serverPlayer) { - if (serverPlayer instanceof Player) { - return new ServerPlayerImpl((Player)serverPlayer); + if (serverPlayer instanceof org.bukkit.entity.Player) { + return new ServerPlayerImpl((org.bukkit.entity.Player) serverPlayer); + } else { + throw new IllegalArgumentException("serverPlayer is not an instance of Player"); } - throw new IllegalArgumentException("serverPlayer is not an instance of Player"); } @Override @@ -110,5 +93,5 @@ implements VoicechatApi { public double getVoiceChatDistance() { return Utils.getDefaultDistance(); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatConnectionImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatConnectionImpl.java similarity index 69% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatConnectionImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatConnectionImpl.java index a564bcd..2b727ca 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatConnectionImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatConnectionImpl.java @@ -1,31 +1,23 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.plugins.impl; import de.maxhenkel.voicechat.Voicechat; +import de.maxhenkel.voicechat.api.Group; import de.maxhenkel.voicechat.api.ServerPlayer; import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.plugins.impl.GroupImpl; -import de.maxhenkel.voicechat.plugins.impl.ServerPlayerImpl; import de.maxhenkel.voicechat.voice.common.PlayerState; -import de.maxhenkel.voicechat.voice.server.Group; import de.maxhenkel.voicechat.voice.server.PlayerStateManager; import de.maxhenkel.voicechat.voice.server.Server; -import javax.annotation.Nullable; import org.bukkit.entity.Player; -public class VoicechatConnectionImpl -implements VoicechatConnection { +import javax.annotation.Nullable; + +public class VoicechatConnectionImpl implements VoicechatConnection { + private final ServerPlayer player; private final Player serverPlayer; private final PlayerState state; @Nullable - private final de.maxhenkel.voicechat.api.Group group; + private final Group group; public VoicechatConnectionImpl(Player player, PlayerState state) { this.serverPlayer = player; @@ -50,46 +42,46 @@ implements VoicechatConnection { return new VoicechatConnectionImpl(player, state); } - @Override @Nullable - public de.maxhenkel.voicechat.api.Group getGroup() { - return this.group; + @Override + public Group getGroup() { + return group; } @Override public boolean isInGroup() { - return this.group != null; + return group != null; } @Override - public void setGroup(@Nullable de.maxhenkel.voicechat.api.Group group) { + public void setGroup(@Nullable Group group) { Server server = Voicechat.SERVER.getServer(); if (server == null) { return; } if (group == null) { - server.getGroupManager().leaveGroup((Player)this.player.getPlayer()); + server.getGroupManager().leaveGroup((Player) player.getPlayer()); return; } if (group instanceof GroupImpl) { - GroupImpl g = (GroupImpl)group; - Group actualGroup = server.getGroupManager().getGroup(g.getGroup().getId()); + GroupImpl g = (GroupImpl) group; + de.maxhenkel.voicechat.voice.server.Group actualGroup = server.getGroupManager().getGroup(g.getGroup().getId()); if (actualGroup == null) { - server.getGroupManager().addGroup(g.getGroup(), this.serverPlayer); + server.getGroupManager().addGroup(g.getGroup(), serverPlayer); actualGroup = g.getGroup(); } - server.getGroupManager().joinGroup(actualGroup, this.serverPlayer, g.getGroup().getPassword()); + server.getGroupManager().joinGroup(actualGroup, serverPlayer, g.getGroup().getPassword()); } } @Override public boolean isConnected() { - return !this.state.isDisconnected(); + return !state.isDisconnected(); } @Override public void setConnected(boolean connected) { - if (this.isInstalled()) { + if (isInstalled()) { return; } Server server = Voicechat.SERVER.getServer(); @@ -97,7 +89,7 @@ implements VoicechatConnection { return; } PlayerStateManager manager = server.getPlayerStateManager(); - PlayerState actualState = manager.getState(this.state.getUuid()); + PlayerState actualState = manager.getState(state.getUuid()); if (actualState == null) { return; } @@ -110,12 +102,12 @@ implements VoicechatConnection { @Override public boolean isDisabled() { - return this.state.isDisabled(); + return state.isDisabled(); } @Override public void setDisabled(boolean disabled) { - if (this.isInstalled()) { + if (isInstalled()) { return; } Server server = Voicechat.SERVER.getServer(); @@ -123,7 +115,7 @@ implements VoicechatConnection { return; } PlayerStateManager manager = server.getPlayerStateManager(); - PlayerState actualState = manager.getState(this.state.getUuid()); + PlayerState actualState = manager.getState(state.getUuid()); if (actualState == null) { return; } @@ -136,12 +128,12 @@ implements VoicechatConnection { @Override public boolean isInstalled() { - return Voicechat.SERVER.isCompatible(this.serverPlayer); + return Voicechat.SERVER.isCompatible(serverPlayer); } @Override public ServerPlayer getPlayer() { - return this.player; + return player; } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatServerApiImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatServerApiImpl.java similarity index 72% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatServerApiImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatServerApiImpl.java index 871551c..cf06911 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatServerApiImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatServerApiImpl.java @@ -1,49 +1,20 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.Bukkit - * org.bukkit.World - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.plugins.impl; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.api.Entity; -import de.maxhenkel.voicechat.api.Group; -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.ServerLevel; -import de.maxhenkel.voicechat.api.ServerPlayer; -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.VoicechatServerApi; -import de.maxhenkel.voicechat.api.VolumeCategory; -import de.maxhenkel.voicechat.api.audiochannel.AudioChannel; -import de.maxhenkel.voicechat.api.audiochannel.AudioPlayer; -import de.maxhenkel.voicechat.api.audiochannel.EntityAudioChannel; -import de.maxhenkel.voicechat.api.audiochannel.LocationalAudioChannel; -import de.maxhenkel.voicechat.api.audiochannel.StaticAudioChannel; +import de.maxhenkel.voicechat.api.*; +import de.maxhenkel.voicechat.api.audiochannel.*; import de.maxhenkel.voicechat.api.audiolistener.AudioListener; import de.maxhenkel.voicechat.api.audiolistener.PlayerAudioListener; import de.maxhenkel.voicechat.api.audiosender.AudioSender; import de.maxhenkel.voicechat.api.config.ConfigAccessor; +import de.maxhenkel.voicechat.api.events.SoundPacketEvent; import de.maxhenkel.voicechat.api.opus.OpusEncoder; import de.maxhenkel.voicechat.api.packets.ConvertablePacket; import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; import de.maxhenkel.voicechat.plugins.PluginManager; -import de.maxhenkel.voicechat.plugins.impl.GroupImpl; -import de.maxhenkel.voicechat.plugins.impl.PositionImpl; -import de.maxhenkel.voicechat.plugins.impl.ServerPlayerImpl; -import de.maxhenkel.voicechat.plugins.impl.VoicechatApiImpl; -import de.maxhenkel.voicechat.plugins.impl.VoicechatConnectionImpl; -import de.maxhenkel.voicechat.plugins.impl.VolumeCategoryImpl; -import de.maxhenkel.voicechat.plugins.impl.audiochannel.AudioPlayerImpl; -import de.maxhenkel.voicechat.plugins.impl.audiochannel.AudioSupplier; -import de.maxhenkel.voicechat.plugins.impl.audiochannel.EntityAudioChannelImpl; -import de.maxhenkel.voicechat.plugins.impl.audiochannel.LocationalAudioChannelImpl; -import de.maxhenkel.voicechat.plugins.impl.audiochannel.StaticAudioChannelImpl; +import de.maxhenkel.voicechat.plugins.impl.audiochannel.*; import de.maxhenkel.voicechat.plugins.impl.audiolistener.PlayerAudioListenerImpl; import de.maxhenkel.voicechat.plugins.impl.audiosender.AudioSenderImpl; import de.maxhenkel.voicechat.plugins.impl.config.ConfigAccessorImpl; @@ -54,50 +25,50 @@ import de.maxhenkel.voicechat.plugins.impl.packets.StaticSoundPacketImpl; import de.maxhenkel.voicechat.voice.common.PlayerState; import de.maxhenkel.voicechat.voice.common.SoundPacket; import de.maxhenkel.voicechat.voice.server.ClientConnection; -import de.maxhenkel.voicechat.voice.server.Group; import de.maxhenkel.voicechat.voice.server.Server; import de.maxhenkel.voicechat.voice.server.ServerPlayerManager; +import org.bukkit.Bukkit; +import org.bukkit.World; + +import javax.annotation.Nullable; import java.util.Collection; import java.util.Collections; import java.util.UUID; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.entity.Player; -public class VoicechatServerApiImpl -extends VoicechatApiImpl -implements VoicechatServerApi { +public class VoicechatServerApiImpl extends VoicechatApiImpl implements VoicechatServerApi { + private static final VoicechatServerApiImpl INSTANCE = new VoicechatServerApiImpl(); private VoicechatServerApiImpl() { + } public static VoicechatServerApiImpl instance() { return INSTANCE; } + @Override public void sendEntitySoundPacketTo(VoicechatConnection connection, EntitySoundPacket p) { if (p instanceof EntitySoundPacketImpl) { - VoicechatServerApiImpl.sendPacket(connection, ((EntitySoundPacketImpl)p).getPacket()); + sendPacket(connection, ((EntitySoundPacketImpl) p).getPacket()); } } @Override public void sendLocationalSoundPacketTo(VoicechatConnection connection, LocationalSoundPacket p) { if (p instanceof LocationalSoundPacketImpl) { - VoicechatServerApiImpl.sendPacket(connection, ((LocationalSoundPacketImpl)p).getPacket()); + sendPacket(connection, ((LocationalSoundPacketImpl) p).getPacket()); } } @Override public void sendStaticSoundPacketTo(VoicechatConnection connection, StaticSoundPacket p) { if (p instanceof StaticSoundPacketImpl) { - VoicechatServerApiImpl.sendPacket(connection, ((StaticSoundPacketImpl)p).getPacket()); + sendPacket(connection, ((StaticSoundPacketImpl) p).getPacket()); } } @@ -106,8 +77,8 @@ implements VoicechatServerApi { return new ConvertablePacketImpl(); } - @Override @Nullable + @Override public EntityAudioChannel createEntityAudioChannel(UUID channelId, Entity entity) { Server server = Voicechat.SERVER.getServer(); if (server == null) { @@ -116,21 +87,22 @@ implements VoicechatServerApi { return new EntityAudioChannelImpl(channelId, server, entity); } - @Override @Nullable + @Override public LocationalAudioChannel createLocationalAudioChannel(UUID channelId, ServerLevel level, Position initialPosition) { Server server = Voicechat.SERVER.getServer(); if (server == null) { return null; } if (initialPosition instanceof PositionImpl) { - return new LocationalAudioChannelImpl(channelId, server, level, (PositionImpl)initialPosition); + return new LocationalAudioChannelImpl(channelId, server, level, (PositionImpl) initialPosition); + } else { + throw new IllegalArgumentException("initialPosition is not an instance of PositionImpl"); } - throw new IllegalArgumentException("initialPosition is not an instance of PositionImpl"); } - @Override @Nullable + @Override public StaticAudioChannel createStaticAudioChannel(UUID channelId, ServerLevel level, VoicechatConnection connection) { Server server = Voicechat.SERVER.getServer(); if (server == null) { @@ -141,8 +113,8 @@ implements VoicechatServerApi { return staticAudioChannel; } - @Override @Nullable + @Override public StaticAudioChannel createStaticAudioChannel(UUID channelId) { Server server = Voicechat.SERVER.getServer(); if (server == null) { @@ -171,7 +143,7 @@ implements VoicechatServerApi { if (!(sender instanceof AudioSenderImpl)) { return false; } - return AudioSenderImpl.registerAudioSender((AudioSenderImpl)sender); + return AudioSenderImpl.registerAudioSender((AudioSenderImpl) sender); } @Override @@ -179,7 +151,7 @@ implements VoicechatServerApi { if (!(sender instanceof AudioSenderImpl)) { return false; } - return AudioSenderImpl.unregisterAudioSender((AudioSenderImpl)sender); + return AudioSenderImpl.unregisterAudioSender((AudioSenderImpl) sender); } @Override @@ -194,7 +166,7 @@ implements VoicechatServerApi { @Override public boolean unregisterAudioListener(AudioListener listener) { - return this.unregisterAudioListener(listener.getListenerId()); + return unregisterAudioListener(listener.getListenerId()); } @Override @@ -206,10 +178,10 @@ implements VoicechatServerApi { if (!(receiver.getPlayer() instanceof ServerPlayerImpl)) { throw new IllegalArgumentException("ServerPlayer is not an instance of ServerPlayerImpl"); } - VoicechatServerApiImpl.sendPacket(((ServerPlayerImpl)receiver.getPlayer()).getRealServerPlayer(), soundPacket); + sendPacket(((ServerPlayerImpl) receiver.getPlayer()).getRealServerPlayer(), soundPacket); } - public static void sendPacket(Player receiver, SoundPacket soundPacket) { + public static void sendPacket(org.bukkit.entity.Player receiver, SoundPacket soundPacket) { Server server = Voicechat.SERVER.getServer(); if (server == null) { return; @@ -218,14 +190,14 @@ implements VoicechatServerApi { if (state == null) { return; } - ClientConnection c = server.getConnections().get(receiver.getUniqueId()); - server.sendSoundPacket(null, null, receiver, state, c, soundPacket, "plugin"); + @Nullable ClientConnection c = server.getConnections().get(receiver.getUniqueId()); + server.sendSoundPacket(null, null, receiver, state, c, soundPacket, SoundPacketEvent.SOURCE_PLUGIN); } - @Override @Nullable + @Override public VoicechatConnection getConnectionOf(UUID playerUuid) { - Player player = Bukkit.getPlayer((UUID)playerUuid); + org.bukkit.entity.Player player = Bukkit.getPlayer(playerUuid); if (player == null) { return null; } @@ -233,13 +205,13 @@ implements VoicechatServerApi { } @Override - public de.maxhenkel.voicechat.api.Group createGroup(String name, @Nullable String password) { - return this.createGroup(name, password, false); + public Group createGroup(String name, @Nullable String password) { + return createGroup(name, password, false); } @Override - public de.maxhenkel.voicechat.api.Group createGroup(String name, @Nullable String password, boolean persistent) { - return this.groupBuilder().setName(name).setPassword(password).setPersistent(persistent).build(); + public Group createGroup(String name, @Nullable String password, boolean persistent) { + return groupBuilder().setName(name).setPassword(password).setPersistent(persistent).build(); } @Override @@ -256,9 +228,9 @@ implements VoicechatServerApi { return server.getGroupManager().removeGroup(groupId); } - @Override @Nullable - public de.maxhenkel.voicechat.api.Group getGroup(UUID groupId) { + @Override + public Group getGroup(UUID groupId) { Server server = Voicechat.SERVER.getServer(); if (server == null) { return null; @@ -267,16 +239,16 @@ implements VoicechatServerApi { } @Override - public Collection getGroups() { + public Collection getGroups() { Server server = Voicechat.SERVER.getServer(); if (server == null) { return Collections.emptyList(); } - return server.getGroupManager().getGroups().values().stream().map(group -> new GroupImpl((Group)group)).collect(Collectors.toList()); + return server.getGroupManager().getGroups().values().stream().map(group -> (Group) new GroupImpl(group)).collect(Collectors.toList()); } - @Override @Nullable + @Override public UUID getSecret(UUID userId) { return null; } @@ -284,9 +256,10 @@ implements VoicechatServerApi { @Override public Collection getPlayersInRange(ServerLevel level, Position pos, double range, @Nullable Predicate filter) { if (pos instanceof PositionImpl) { - return ServerPlayerManager.getPlayersInRange((World)level.getServerLevel(), ((PositionImpl)pos).getPosition(), range, filter == null ? null : player -> filter.test(new ServerPlayerImpl((Player)player))).stream().map(ServerPlayerImpl::new).collect(Collectors.toList()); + return ServerPlayerManager.getPlayersInRange((World) level.getServerLevel(), ((PositionImpl) pos).getPosition(), range, filter == null ? null : player -> filter.test(new ServerPlayerImpl(player))).stream().map(ServerPlayerImpl::new).collect(Collectors.toList()); + } else { + throw new IllegalArgumentException("Position is not an instance of PositionImpl"); } - throw new IllegalArgumentException("Position is not an instance of PositionImpl"); } @Override @@ -303,7 +276,7 @@ implements VoicechatServerApi { if (server == null) { return; } - server.getCategoryManager().addCategory((VolumeCategoryImpl)category); + server.getCategoryManager().addCategory((VolumeCategoryImpl) category); PluginManager.instance().onRegisterVolumeCategory(category); } @@ -332,5 +305,5 @@ implements VoicechatServerApi { public ConfigAccessor getServerConfig() { return new ConfigAccessorImpl(Voicechat.SERVER_CONFIG.voiceChatDistance.getConfig()); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketBase.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketBase.java similarity index 68% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketBase.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketBase.java index f19dd3a..5a2e21d 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketBase.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketBase.java @@ -1,29 +1,30 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.debug.CooldownTimer; -import de.maxhenkel.voicechat.plugins.impl.RawUdpPacketImpl; + import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; public class VoicechatSocketBase { + private final byte[] BUFFER = new byte[4096]; public RawUdpPacketImpl read(DatagramSocket socket) throws IOException { - DatagramPacket packet = new DatagramPacket(this.BUFFER, this.BUFFER.length); + DatagramPacket packet = new DatagramPacket(BUFFER, BUFFER.length); socket.receive(packet); - if (packet.getLength() >= this.BUFFER.length) { - CooldownTimer.run("udp_packet_too_large", () -> Voicechat.LOGGER.warn("Packet from {} is too large", packet.getSocketAddress())); + if (packet.getLength() >= BUFFER.length) { + CooldownTimer.run("udp_packet_too_large", () -> { + Voicechat.LOGGER.warn("Packet from {} is too large", packet.getSocketAddress()); + }); throw new IOException(String.format("Packet from %s is too large", packet.getSocketAddress())); } + // Setting the timestamp after receiving the packet long timestamp = System.currentTimeMillis(); byte[] data = new byte[packet.getLength()]; System.arraycopy(packet.getData(), packet.getOffset(), data, 0, packet.getLength()); return new RawUdpPacketImpl(data, packet.getSocketAddress(), timestamp); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketImpl.java similarity index 57% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketImpl.java index 9ba0b85..8e09034 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VoicechatSocketImpl.java @@ -1,65 +1,49 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.Bukkit - * org.bukkit.plugin.Plugin - */ package de.maxhenkel.voicechat.plugins.impl; +import de.maxhenkel.voicechat.BuildConstants; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.api.RawUdpPacket; import de.maxhenkel.voicechat.api.VoicechatSocket; -import de.maxhenkel.voicechat.plugins.impl.VoicechatSocketBase; -import java.net.BindException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketAddress; -import java.net.URI; -import java.net.URISyntaxException; import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; -public class VoicechatSocketImpl -extends VoicechatSocketBase -implements VoicechatSocket { +import java.net.*; + +public class VoicechatSocketImpl extends VoicechatSocketBase implements VoicechatSocket { + private DatagramSocket socket; @Override public void open(int port, String bindAddress) throws Exception { - if (this.socket != null) { + if (socket != null) { throw new IllegalStateException("Socket already opened"); } - this.checkCorrectHost(); + checkCorrectHost(); InetAddress address = null; try { if (!bindAddress.isEmpty()) { address = InetAddress.getByName(bindAddress); } - } - catch (Exception e) { + } catch (Exception e) { bindAddress = ""; Voicechat.LOGGER.error("Failed to parse bind IP address '{}'", bindAddress, e); } + try { try { - this.socket = new DatagramSocket(port, address); - } - catch (BindException e) { + socket = new DatagramSocket(port, address); + } catch (BindException e) { if (address == null || bindAddress.equals("0.0.0.0")) { throw e; } Voicechat.LOGGER.error("Failed to bind to address '{}', binding to wildcard IP instead", bindAddress); - this.socket = new DatagramSocket(port); + socket = new DatagramSocket(port); } - this.socket.setTrafficClass(4); - } - catch (BindException e) { + socket.setTrafficClass(0x04); // IPTOS_RELIABILITY + } catch (BindException e) { Voicechat.LOGGER.fatal("Failed to run voice chat at UDP port {}, make sure no other application is running at that port", port); - Bukkit.getScheduler().runTask((Plugin)Voicechat.INSTANCE, () -> { - Voicechat.LOGGER.fatal("Disabling {}", "Simple Voice Chat"); - Bukkit.getPluginManager().disablePlugin((Plugin)Voicechat.INSTANCE); + Bukkit.getScheduler().runTask(Voicechat.INSTANCE, () -> { + Voicechat.LOGGER.fatal("Disabling {}", BuildConstants.PLUGIN_NAME); + Bukkit.getPluginManager().disablePlugin(Voicechat.INSTANCE); }); throw e; } @@ -77,13 +61,11 @@ implements VoicechatSocket { } else { Voicechat.LOGGER.info("Voice host port is {}", port); } - } - catch (NumberFormatException ignored) { + } catch (NumberFormatException ignored) { try { new URI("voicechat://" + host); Voicechat.LOGGER.info("Voice host is '{}'", host); - } - catch (URISyntaxException e) { + } catch (URISyntaxException e) { Voicechat.LOGGER.warn("Failed to parse voice host", e); Bukkit.shutdown(); throw e; @@ -93,46 +75,44 @@ implements VoicechatSocket { @Override public RawUdpPacket read() throws Exception { - if (this.socket == null) { + if (socket == null) { throw new IllegalStateException("Socket not opened yet"); } - return this.read(this.socket); + return read(socket); } @Override public void send(byte[] data, SocketAddress address) throws Exception { - if (this.socket == null || this.socket.isClosed()) { - return; + if (socket == null || socket.isClosed()) { + return; // Ignoring packet sending when socket isn't open yet or already closed } - this.socket.send(new DatagramPacket(data, data.length, address)); + socket.send(new DatagramPacket(data, data.length, address)); } @Override public int getLocalPort() { - if (this.socket == null) { + if (socket == null) { return -1; } - return this.socket.getLocalPort(); + return socket.getLocalPort(); } @Override public void close() { - if (this.socket != null) { + if (socket != null) { try { - this.socket.close(); - } - catch (Throwable throwable) { - // empty catch block + socket.close(); + } catch (Throwable ignored) { + // Apparently some JDKs throw an "Error" when closing a datagram socket } } } @Override public boolean isClosed() { - if (this.socket == null) { + if (socket == null) { return true; } - return this.socket.isClosed(); + return socket.isClosed(); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VolumeCategoryImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VolumeCategoryImpl.java similarity index 61% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/VolumeCategoryImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VolumeCategoryImpl.java index 5d3ab99..bd49b5e 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/VolumeCategoryImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/VolumeCategoryImpl.java @@ -1,19 +1,15 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl; import de.maxhenkel.voicechat.api.VolumeCategory; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import java.util.regex.Pattern; -import javax.annotation.Nullable; -public class VolumeCategoryImpl -implements VolumeCategory { +import javax.annotation.Nullable; +import java.util.regex.Pattern; + +public class VolumeCategoryImpl implements VolumeCategory { + public static final Pattern ID_REGEX = Pattern.compile("^[a-z_]{1,16}$"); + private final String id; private final String name; @Nullable @@ -39,49 +35,49 @@ implements VolumeCategory { @Override public String getId() { - return this.id; + return id; } @Override public String getName() { - return this.name; + return name; } @Override @Nullable public String getNameTranslationKey() { - return this.nameTranslationKey; + return nameTranslationKey; } - @Override @Nullable + @Override public String getDescription() { - return this.description; + return description; } @Override @Nullable public String getDescriptionTranslationKey() { - return this.descriptionTranslationKey; + return descriptionTranslationKey; } - @Override @Nullable + @Override public int[][] getIcon() { - return this.icon; + return icon; } public static VolumeCategoryImpl fromBytes(FriendlyByteBuf buf) { String id = buf.readUtf(16); String name = buf.readUtf(16); - String nameTranslationKey = VolumeCategoryImpl.readOptionalString(buf); - String description = VolumeCategoryImpl.readOptionalString(buf); - String descriptionTranslationKey = VolumeCategoryImpl.readOptionalString(buf); + String nameTranslationKey = readOptionalString(buf); + String description = readOptionalString(buf); + String descriptionTranslationKey = readOptionalString(buf); int[][] icon = null; if (buf.readBoolean()) { icon = new int[16][16]; - for (int x = 0; x < icon.length; ++x) { - for (int y = 0; y < icon.length; ++y) { + for (int x = 0; x < icon.length; x++) { + for (int y = 0; y < icon.length; y++) { icon[x][y] = buf.readInt(); } } @@ -92,28 +88,28 @@ implements VolumeCategory { @Nullable private static String readOptionalString(FriendlyByteBuf buf) { if (buf.readBoolean()) { - return buf.readUtf(Short.MAX_VALUE); + return buf.readUtf(32767); } return null; } public void toBytes(FriendlyByteBuf buf) { - buf.writeUtf(this.id, 16); - buf.writeUtf(this.name, 16); - VolumeCategoryImpl.writeOptionalString(buf, this.nameTranslationKey); - VolumeCategoryImpl.writeOptionalString(buf, this.description); - VolumeCategoryImpl.writeOptionalString(buf, this.descriptionTranslationKey); - buf.writeBoolean(this.icon != null); - if (this.icon != null) { - if (this.icon.length != 16) { + buf.writeUtf(id, 16); + buf.writeUtf(name, 16); + writeOptionalString(buf, nameTranslationKey); + writeOptionalString(buf, description); + writeOptionalString(buf, descriptionTranslationKey); + buf.writeBoolean(icon != null); + if (icon != null) { + if (icon.length != 16) { throw new IllegalStateException("Icon is not 16x16"); } - for (int x = 0; x < this.icon.length; ++x) { - if (this.icon[x].length != 16) { + for (int x = 0; x < icon.length; x++) { + if (icon[x].length != 16) { throw new IllegalStateException("Icon is not 16x16"); } - for (int y = 0; y < this.icon.length; ++y) { - buf.writeInt(this.icon[x][y]); + for (int y = 0; y < icon.length; y++) { + buf.writeInt(icon[x][y]); } } } @@ -122,27 +118,29 @@ implements VolumeCategory { private static void writeOptionalString(FriendlyByteBuf buf, @Nullable String string) { buf.writeBoolean(string != null); if (string != null) { - buf.writeUtf(string, Short.MAX_VALUE); + buf.writeUtf(string, 32767); } } + @Override public boolean equals(Object object) { if (this == object) { return true; } - if (object == null || this.getClass() != object.getClass()) { + if (object == null || getClass() != object.getClass()) { return false; } - VolumeCategoryImpl that = (VolumeCategoryImpl)object; - return this.id.equals(that.id); + VolumeCategoryImpl that = (VolumeCategoryImpl) object; + return id.equals(that.id); } + @Override public int hashCode() { - return this.id.hashCode(); + return id.hashCode(); } - public static class BuilderImpl - implements VolumeCategory.Builder { + public static class BuilderImpl implements VolumeCategory.Builder { + private String id; private String name; @Nullable @@ -155,51 +153,51 @@ implements VolumeCategory { private int[][] icon; @Override - public VolumeCategory.Builder setId(String id) { + public Builder setId(String id) { this.id = id; return this; } @Override - public VolumeCategory.Builder setName(String name) { + public Builder setName(String name) { this.name = name; return this; } @Override - public VolumeCategory.Builder setNameTranslationKey(@Nullable String translationKey) { + public Builder setNameTranslationKey(@Nullable String translationKey) { this.nameTranslationKey = translationKey; return this; } @Override - public VolumeCategory.Builder setDescription(@Nullable String description) { + public Builder setDescription(@Nullable String description) { this.description = description; return this; } @Override - public VolumeCategory.Builder setDescriptionTranslationKey(@Nullable String translationKey) { + public Builder setDescriptionTranslationKey(@Nullable String translationKey) { this.descriptionTranslationKey = translationKey; return this; } @Override - public VolumeCategory.Builder setIcon(@Nullable int[][] icon) { + public Builder setIcon(@Nullable int[][] icon) { this.icon = icon; return this; } @Override public VolumeCategory build() { - if (this.id == null) { + if (id == null) { throw new IllegalStateException("id missing"); } - if (this.name == null) { + if (name == null) { throw new IllegalStateException("name missing"); } - return new VolumeCategoryImpl(this.id, this.name, this.nameTranslationKey, this.description, this.descriptionTranslationKey, this.icon); + return new VolumeCategoryImpl(id, name, nameTranslationKey, description, descriptionTranslationKey, icon); } } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audio/AudioConverterImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audio/AudioConverterImpl.java similarity index 90% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/audio/AudioConverterImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audio/AudioConverterImpl.java index 3cfdd10..f56eb7b 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audio/AudioConverterImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audio/AudioConverterImpl.java @@ -1,13 +1,10 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.audio; import de.maxhenkel.voicechat.api.audio.AudioConverter; import de.maxhenkel.voicechat.voice.common.AudioUtils; -public class AudioConverterImpl -implements AudioConverter { +public class AudioConverterImpl implements AudioConverter { + @Override public short[] bytesToShorts(byte[] bytes) { return AudioUtils.bytesToShorts(bytes); @@ -38,4 +35,3 @@ implements AudioConverter { return AudioUtils.bytesToFloats(bytes); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioChannelImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioChannelImpl.java similarity index 80% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioChannelImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioChannelImpl.java index 3a32f19..459e46b 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioChannelImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioChannelImpl.java @@ -1,21 +1,16 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.audiochannel; import de.maxhenkel.voicechat.api.ServerPlayer; import de.maxhenkel.voicechat.api.audiochannel.AudioChannel; import de.maxhenkel.voicechat.voice.server.Server; + +import javax.annotation.Nullable; import java.util.UUID; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Predicate; -import javax.annotation.Nullable; -public abstract class AudioChannelImpl -implements AudioChannel { +public abstract class AudioChannelImpl implements AudioChannel { + protected UUID channelId; protected Server server; protected AtomicLong sequenceNumber; @@ -37,18 +32,18 @@ implements AudioChannel { @Override public UUID getId() { - return this.channelId; + return channelId; } @Override public boolean isClosed() { - return this.server.isClosed(); + return server.isClosed(); } - @Override @Nullable + @Override public String getCategory() { - return this.category; + return category; } @Override @@ -56,4 +51,3 @@ implements AudioChannel { this.category = category; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioPlayerImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioPlayerImpl.java similarity index 57% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioPlayerImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioPlayerImpl.java index a43fa9a..946754f 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioPlayerImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioPlayerImpl.java @@ -1,10 +1,3 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nonnull - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.audiochannel; import de.maxhenkel.voicechat.Voicechat; @@ -12,15 +5,16 @@ import de.maxhenkel.voicechat.api.audiochannel.AudioChannel; import de.maxhenkel.voicechat.api.audiochannel.AudioPlayer; import de.maxhenkel.voicechat.api.opus.OpusEncoder; import de.maxhenkel.voicechat.debug.VoicechatUncaughtExceptionHandler; -import java.util.function.Supplier; + import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.function.Supplier; -public class AudioPlayerImpl -extends Thread -implements AudioPlayer { - private static final long FRAME_SIZE_NS = 20000000L; +public class AudioPlayerImpl extends Thread implements AudioPlayer { + + private static final long FRAME_SIZE_NS = 20_000_000; public static final int FRAME_SIZE = 960; + private final AudioChannel audioChannel; private final OpusEncoder encoder; private final Supplier audioSupplier; @@ -32,38 +26,38 @@ implements AudioPlayer { this.audioChannel = audioChannel; this.encoder = encoder; this.audioSupplier = audioSupplier; - this.setDaemon(true); - this.setName(String.format("AudioPlayer-%s", audioChannel.getId())); - this.setUncaughtExceptionHandler(new VoicechatUncaughtExceptionHandler()); + setDaemon(true); + setName(String.format("AudioPlayer-%s", audioChannel.getId())); + setUncaughtExceptionHandler(new VoicechatUncaughtExceptionHandler()); } @Override public void startPlaying() { - if (this.started) { + if (started) { return; } - this.start(); - this.started = true; + start(); + started = true; } @Override public void stopPlaying() { - this.interrupt(); + interrupt(); } @Override public boolean isStarted() { - return this.started; + return started; } @Override public boolean isPlaying() { - return this.isAlive(); + return isAlive(); } @Override public boolean isStopped() { - return this.started && !this.isAlive(); + return started && !isAlive(); } @Override @@ -73,30 +67,38 @@ implements AudioPlayer { @Override public void run() { - short[] frame; int framePosition = 0; + long startTime = System.nanoTime(); - while ((frame = this.audioSupplier.get()) != null) { - if (frame.length != 960) { - Voicechat.LOGGER.error("Got invalid audio frame size {}!={}", frame.length, 960); + + short[] frame; + + while ((frame = audioSupplier.get()) != null) { + if (frame.length != FRAME_SIZE) { + Voicechat.LOGGER.error("Got invalid audio frame size {}!={}", frame.length, FRAME_SIZE); break; } - this.audioChannel.send(this.encoder.encode(frame)); - long waitTimestamp = startTime + (long)(++framePosition) * 20000000L; + audioChannel.send(encoder.encode(frame)); + framePosition++; + long waitTimestamp = startTime + framePosition * FRAME_SIZE_NS; + long waitNanos = waitTimestamp - System.nanoTime(); + try { - if (waitNanos <= 0L) continue; - Thread.sleep(waitNanos / 1000000L, (int)(waitNanos % 1000000L)); - } - catch (InterruptedException e) { + if (waitNanos > 0L) { + Thread.sleep(waitNanos / 1_000_000L, (int) (waitNanos % 1_000_000)); + } + } catch (InterruptedException e) { break; } } - this.encoder.close(); - this.audioChannel.flush(); - if (this.onStopped != null) { - this.onStopped.run(); + + encoder.close(); + audioChannel.flush(); + + if (onStopped != null) { + onStopped.run(); } } -} +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioSupplier.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioSupplier.java new file mode 100644 index 0000000..97b5df1 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioSupplier.java @@ -0,0 +1,28 @@ +package de.maxhenkel.voicechat.plugins.impl.audiochannel; + +import java.util.Arrays; +import java.util.function.Supplier; + +public class AudioSupplier implements Supplier { + + private final short[] audioData; + private final short[] frame; + private int framePosition; + + public AudioSupplier(short[] audioData) { + this.audioData = audioData; + this.frame = new short[AudioPlayerImpl.FRAME_SIZE]; + } + + @Override + public short[] get() { + if (framePosition >= audioData.length) { + return null; + } + + Arrays.fill(frame, (short) 0); + System.arraycopy(audioData, framePosition, frame, 0, Math.min(frame.length, audioData.length - framePosition)); + framePosition += frame.length; + return frame; + } +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/EntityAudioChannelImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/EntityAudioChannelImpl.java similarity index 54% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/EntityAudioChannelImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/EntityAudioChannelImpl.java index 7354d1f..8147bef 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/EntityAudioChannelImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/EntityAudioChannelImpl.java @@ -1,27 +1,19 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Entity - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.plugins.impl.audiochannel; import de.maxhenkel.voicechat.api.Entity; import de.maxhenkel.voicechat.api.audiochannel.EntityAudioChannel; +import de.maxhenkel.voicechat.api.events.SoundPacketEvent; import de.maxhenkel.voicechat.api.packets.MicrophonePacket; import de.maxhenkel.voicechat.plugins.impl.ServerPlayerImpl; -import de.maxhenkel.voicechat.plugins.impl.audiochannel.AudioChannelImpl; import de.maxhenkel.voicechat.voice.common.PlayerSoundPacket; import de.maxhenkel.voicechat.voice.common.Utils; import de.maxhenkel.voicechat.voice.server.Server; import de.maxhenkel.voicechat.voice.server.ServerPlayerManager; -import java.util.UUID; -import org.bukkit.entity.Player; -public class EntityAudioChannelImpl -extends AudioChannelImpl -implements EntityAudioChannel { +import java.util.UUID; + +public class EntityAudioChannelImpl extends AudioChannelImpl implements EntityAudioChannel { + protected Entity entity; protected boolean whispering; protected float distance; @@ -40,7 +32,7 @@ implements EntityAudioChannel { @Override public boolean isWhispering() { - return this.whispering; + return whispering; } @Override @@ -50,12 +42,12 @@ implements EntityAudioChannel { @Override public Entity getEntity() { - return this.entity; + return entity; } @Override public float getDistance() { - return this.distance; + return distance; } @Override @@ -65,24 +57,24 @@ implements EntityAudioChannel { @Override public void send(byte[] opusData) { - this.broadcast(new PlayerSoundPacket(this.channelId, this.entity.getUuid(), opusData, this.sequenceNumber.getAndIncrement(), this.whispering, this.distance, this.category)); + broadcast(new PlayerSoundPacket(channelId, entity.getUuid(), opusData, sequenceNumber.getAndIncrement(), whispering, distance, category)); } @Override public void send(MicrophonePacket microphonePacket) { - this.broadcast(new PlayerSoundPacket(this.channelId, this.entity.getUuid(), microphonePacket.getOpusEncodedData(), this.sequenceNumber.getAndIncrement(), this.whispering, this.distance, this.category)); + broadcast(new PlayerSoundPacket(channelId, entity.getUuid(), microphonePacket.getOpusEncodedData(), sequenceNumber.getAndIncrement(), whispering, distance, category)); } @Override public void flush() { - this.broadcast(new PlayerSoundPacket(this.channelId, this.entity.getUuid(), new byte[0], this.sequenceNumber.getAndIncrement(), this.whispering, this.distance, this.category)); + broadcast(new PlayerSoundPacket(channelId, entity.getUuid(), new byte[0], sequenceNumber.getAndIncrement(), whispering, distance, category)); } private void broadcast(PlayerSoundPacket packet) { - if (this.entity.getEntity() instanceof org.bukkit.entity.Entity) { - org.bukkit.entity.Entity entity = (org.bukkit.entity.Entity)this.entity.getEntity(); - this.server.broadcast(ServerPlayerManager.getPlayersInRange(entity.getWorld(), entity.getLocation(), this.server.getBroadcastRange(this.distance), this.filter == null ? null : player -> this.filter.test(new ServerPlayerImpl((Player)player))), packet, null, null, null, "plugin"); + if (entity.getEntity() instanceof org.bukkit.entity.Entity) { + org.bukkit.entity.Entity entity = (org.bukkit.entity.Entity) this.entity.getEntity(); + server.broadcast(ServerPlayerManager.getPlayersInRange(entity.getWorld(), entity.getLocation(), server.getBroadcastRange(distance), filter == null ? null : player -> filter.test(new ServerPlayerImpl(player))), packet, null, null, null, SoundPacketEvent.SOURCE_PLUGIN); } } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/LocationalAudioChannelImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/LocationalAudioChannelImpl.java similarity index 57% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/LocationalAudioChannelImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/LocationalAudioChannelImpl.java index fb8cc3e..66d9097 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/LocationalAudioChannelImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/LocationalAudioChannelImpl.java @@ -1,30 +1,22 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.World - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.plugins.impl.audiochannel; import de.maxhenkel.voicechat.api.Position; import de.maxhenkel.voicechat.api.ServerLevel; import de.maxhenkel.voicechat.api.audiochannel.LocationalAudioChannel; +import de.maxhenkel.voicechat.api.events.SoundPacketEvent; import de.maxhenkel.voicechat.api.packets.MicrophonePacket; import de.maxhenkel.voicechat.plugins.impl.PositionImpl; import de.maxhenkel.voicechat.plugins.impl.ServerPlayerImpl; -import de.maxhenkel.voicechat.plugins.impl.audiochannel.AudioChannelImpl; import de.maxhenkel.voicechat.voice.common.LocationSoundPacket; import de.maxhenkel.voicechat.voice.common.Utils; import de.maxhenkel.voicechat.voice.server.Server; import de.maxhenkel.voicechat.voice.server.ServerPlayerManager; -import java.util.UUID; import org.bukkit.World; -import org.bukkit.entity.Player; -public class LocationalAudioChannelImpl -extends AudioChannelImpl -implements LocationalAudioChannel { +import java.util.UUID; + +public class LocationalAudioChannelImpl extends AudioChannelImpl implements LocationalAudioChannel { + protected ServerLevel level; protected PositionImpl position; protected float distance; @@ -38,20 +30,21 @@ implements LocationalAudioChannel { @Override public void updateLocation(Position position) { - if (!(position instanceof PositionImpl)) { + if (position instanceof PositionImpl) { + this.position = (PositionImpl) position; + } else { throw new IllegalArgumentException("position is not an instance of PositionImpl"); } - this.position = (PositionImpl)position; } @Override public Position getLocation() { - return this.position; + return position; } @Override public float getDistance() { - return this.distance; + return distance; } @Override @@ -61,21 +54,21 @@ implements LocationalAudioChannel { @Override public void send(byte[] opusData) { - this.broadcast(new LocationSoundPacket(this.channelId, this.channelId, this.position.getPosition(), opusData, this.sequenceNumber.getAndIncrement(), this.distance, this.category)); + broadcast(new LocationSoundPacket(channelId, channelId, position.getPosition(), opusData, sequenceNumber.getAndIncrement(), distance, category)); } @Override public void send(MicrophonePacket packet) { - this.send(packet.getOpusEncodedData()); + send(packet.getOpusEncodedData()); } @Override public void flush() { - this.broadcast(new LocationSoundPacket(this.channelId, this.channelId, this.position.getPosition(), new byte[0], this.sequenceNumber.getAndIncrement(), this.distance, this.category)); + broadcast(new LocationSoundPacket(channelId, channelId, position.getPosition(), new byte[0], sequenceNumber.getAndIncrement(), distance, category)); } private void broadcast(LocationSoundPacket packet) { - this.server.broadcast(ServerPlayerManager.getPlayersInRange((World)this.level.getServerLevel(), this.position.getPosition(), this.server.getBroadcastRange(this.distance), this.filter == null ? null : player -> this.filter.test(new ServerPlayerImpl((Player)player))), packet, null, null, null, "plugin"); + server.broadcast(ServerPlayerManager.getPlayersInRange((World) level.getServerLevel(), position.getPosition(), server.getBroadcastRange(distance), filter == null ? null : player -> filter.test(new ServerPlayerImpl(player))), packet, null, null, null, SoundPacketEvent.SOURCE_PLUGIN); } -} +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/StaticAudioChannelImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/StaticAudioChannelImpl.java new file mode 100644 index 0000000..a4535a9 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiochannel/StaticAudioChannelImpl.java @@ -0,0 +1,102 @@ +package de.maxhenkel.voicechat.plugins.impl.audiochannel; + +import de.maxhenkel.voicechat.api.VoicechatConnection; +import de.maxhenkel.voicechat.api.audiochannel.StaticAudioChannel; +import de.maxhenkel.voicechat.api.packets.MicrophonePacket; +import de.maxhenkel.voicechat.plugins.impl.ServerPlayerImpl; +import de.maxhenkel.voicechat.plugins.impl.VoicechatServerApiImpl; +import de.maxhenkel.voicechat.voice.common.GroupSoundPacket; +import de.maxhenkel.voicechat.voice.server.ClientConnection; +import de.maxhenkel.voicechat.voice.server.Group; +import de.maxhenkel.voicechat.voice.server.Server; +import de.maxhenkel.voicechat.voice.server.ServerGroupManager; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.*; + +public class StaticAudioChannelImpl extends AudioChannelImpl implements StaticAudioChannel { + + protected boolean bypassGroupIsolation; + protected final Set targets; + + public StaticAudioChannelImpl(UUID channelId, Server server) { + super(channelId, server); + this.targets = new HashSet<>(); + } + + @Override + public void send(byte[] opusData) { + broadcast(new GroupSoundPacket(channelId, channelId, opusData, sequenceNumber.getAndIncrement(), category)); + } + + @Override + public void send(MicrophonePacket packet) { + send(packet.getOpusEncodedData()); + } + + @Override + public void flush() { + GroupSoundPacket packet = new GroupSoundPacket(channelId, channelId, new byte[0], sequenceNumber.getAndIncrement(), category); + broadcast(packet); + } + + private void broadcast(GroupSoundPacket packet) { + synchronized (targets) { + ServerGroupManager groupManager = server.getGroupManager(); + for (UUID target : targets) { + ClientConnection connection = server.getConnection(target); + if (connection == null) { + continue; + } + Player player = Bukkit.getPlayer(target); + if (player == null) { + continue; + } + if (!bypassGroupIsolation) { + Group playerGroup = groupManager.getPlayerGroup(player); + if (playerGroup != null && playerGroup.isIsolated()) { + continue; + } + } + if (filter != null) { + if (!filter.test(new ServerPlayerImpl(player))) { + continue; + } + } + VoicechatServerApiImpl.sendPacket(player, packet); + } + } + } + + @Override + public void setBypassGroupIsolation(boolean bypassGroupIsolation) { + this.bypassGroupIsolation = bypassGroupIsolation; + } + + @Override + public boolean bypassesGroupIsolation() { + return bypassGroupIsolation; + } + + @Override + public void addTarget(VoicechatConnection target) { + synchronized (targets) { + targets.add(target.getPlayer().getUuid()); + } + } + + @Override + public void removeTarget(VoicechatConnection target) { + synchronized (targets) { + targets.remove(target.getPlayer().getUuid()); + } + } + + @Override + public void clearTargets() { + synchronized (targets) { + targets.clear(); + } + } +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiolistener/PlayerAudioListenerImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiolistener/PlayerAudioListenerImpl.java similarity index 66% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiolistener/PlayerAudioListenerImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiolistener/PlayerAudioListenerImpl.java index 7c65b76..59dc352 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiolistener/PlayerAudioListenerImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiolistener/PlayerAudioListenerImpl.java @@ -1,20 +1,15 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.audiolistener; import de.maxhenkel.voicechat.api.ServerPlayer; import de.maxhenkel.voicechat.api.audiolistener.PlayerAudioListener; import de.maxhenkel.voicechat.api.packets.SoundPacket; + +import javax.annotation.Nullable; import java.util.UUID; import java.util.function.Consumer; -import javax.annotation.Nullable; -public class PlayerAudioListenerImpl -implements PlayerAudioListener { +public class PlayerAudioListenerImpl implements PlayerAudioListener { + private final UUID playerUuid; private final Consumer listener; private final UUID listenerId; @@ -27,53 +22,57 @@ implements PlayerAudioListener { @Override public UUID getListenerId() { - return this.listenerId; + return listenerId; } @Override public UUID getPlayerUuid() { - return this.playerUuid; + return playerUuid; } public Consumer getListener() { - return this.listener; + return listener; } - public static class BuilderImpl - implements PlayerAudioListener.Builder { + public static class BuilderImpl implements Builder { + @Nullable private UUID playerUuid; @Nullable private Consumer listener; + public BuilderImpl() { + + } + @Override - public PlayerAudioListener.Builder setPlayer(ServerPlayer player) { + public Builder setPlayer(ServerPlayer player) { this.playerUuid = player.getUuid(); return this; } @Override - public PlayerAudioListener.Builder setPlayer(UUID playerUuid) { + public Builder setPlayer(UUID playerUuid) { this.playerUuid = playerUuid; return this; } @Override - public PlayerAudioListener.Builder setPacketListener(Consumer listener) { + public Builder setPacketListener(Consumer listener) { this.listener = listener; return this; } @Override public PlayerAudioListener build() { - if (this.playerUuid == null) { + if (playerUuid == null) { throw new IllegalStateException("No player provided"); } - if (this.listener == null) { + if (listener == null) { throw new IllegalStateException("No listener provided"); } - return new PlayerAudioListenerImpl(this.playerUuid, this.listener); + return new PlayerAudioListenerImpl(playerUuid, listener); } } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiosender/AudioSenderImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiosender/AudioSenderImpl.java similarity index 79% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiosender/AudioSenderImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiosender/AudioSenderImpl.java index 5c6734c..85d2c44 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiosender/AudioSenderImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/audiosender/AudioSenderImpl.java @@ -1,19 +1,18 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.audiosender; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.api.audiosender.AudioSender; import de.maxhenkel.voicechat.voice.common.MicPacket; import de.maxhenkel.voicechat.voice.server.Server; + import java.util.HashMap; import java.util.Map; import java.util.UUID; -public class AudioSenderImpl -implements AudioSender { - private static final Map AUDIO_SENDERS = new HashMap(); +public class AudioSenderImpl implements AudioSender { + + private static final Map AUDIO_SENDERS = new HashMap<>(); + private final UUID uuid; private boolean whispering; private long nextSequenceNumber; @@ -45,7 +44,7 @@ implements AudioSender { @Override public boolean isWhispering() { - return this.whispering; + return whispering; } @Override @@ -59,24 +58,24 @@ implements AudioSender { @Override public boolean canSend() { - return !Voicechat.SERVER.isCompatible(this.uuid) && AUDIO_SENDERS.get(this.uuid) == this; + return !Voicechat.SERVER.isCompatible(uuid) && AUDIO_SENDERS.get(uuid) == this; } @Override public boolean send(byte[] opusEncodedAudioData) { - return this.sendMicrophonePacket(opusEncodedAudioData); + return sendMicrophonePacket(opusEncodedAudioData); } @Override public boolean reset() { - return this.sendMicrophonePacket(new byte[0]); + return sendMicrophonePacket(new byte[0]); } public boolean sendMicrophonePacket(byte[] data) { if (data == null) { throw new IllegalStateException("opusEncodedData is not set"); } - if (!this.canSend()) { + if (!canSend()) { return false; } Server server = Voicechat.SERVER.getServer(); @@ -84,16 +83,15 @@ implements AudioSender { return true; } try { - MicPacket packet = new MicPacket(data, data.length > 0 && this.whispering, this.nextSequenceNumber++); + MicPacket packet = new MicPacket(data, data.length > 0 && whispering, nextSequenceNumber++); if (data.length <= 0) { - this.nextSequenceNumber = 0L; + nextSequenceNumber = 0L; } - server.onMicPacket(this.uuid, packet); - } - catch (Exception e) { + server.onMicPacket(uuid, packet); + } catch (Exception e) { Voicechat.LOGGER.error("Failed to send audio", e); } return true; } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/config/ConfigAccessorImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/config/ConfigAccessorImpl.java similarity index 54% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/config/ConfigAccessorImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/config/ConfigAccessorImpl.java index 8c1bda8..9ba928b 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/config/ConfigAccessorImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/config/ConfigAccessorImpl.java @@ -1,17 +1,12 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.config; +import de.maxhenkel.configbuilder.Config; import de.maxhenkel.voicechat.api.config.ConfigAccessor; -import de.maxhenkel.voicechat.configbuilder.Config; + import javax.annotation.Nullable; -public class ConfigAccessorImpl -implements ConfigAccessor { +public class ConfigAccessorImpl implements ConfigAccessor { + private Config config; public ConfigAccessorImpl(Config config) { @@ -20,13 +15,13 @@ implements ConfigAccessor { @Override public boolean hasKey(String key) { - return this.config.getEntries().containsKey(key); + return config.getEntries().containsKey(key); } - @Override @Nullable + @Override public String getValue(String key) { - return this.config.getEntries().get(key); + return config.getEntries().get(key); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/CreateGroupEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/CreateGroupEventImpl.java similarity index 58% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/CreateGroupEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/CreateGroupEventImpl.java index cf84f0e..a9db267 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/CreateGroupEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/CreateGroupEventImpl.java @@ -1,22 +1,14 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.Group; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.CreateGroupEvent; -import de.maxhenkel.voicechat.plugins.impl.events.GroupEventImpl; + import javax.annotation.Nullable; -public class CreateGroupEventImpl -extends GroupEventImpl -implements CreateGroupEvent { +public class CreateGroupEventImpl extends GroupEventImpl implements CreateGroupEvent { + public CreateGroupEventImpl(Group group, @Nullable VoicechatConnection connection) { super(group, connection); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/EntitySoundPacketEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/EntitySoundPacketEventImpl.java similarity index 62% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/EntitySoundPacketEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/EntitySoundPacketEventImpl.java index 099623a..088d46a 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/EntitySoundPacketEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/EntitySoundPacketEventImpl.java @@ -1,22 +1,14 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.EntitySoundPacketEvent; import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; -import de.maxhenkel.voicechat.plugins.impl.events.SoundPacketEventImpl; + import javax.annotation.Nullable; -public class EntitySoundPacketEventImpl -extends SoundPacketEventImpl -implements EntitySoundPacketEvent { +public class EntitySoundPacketEventImpl extends SoundPacketEventImpl implements EntitySoundPacketEvent { + public EntitySoundPacketEventImpl(EntitySoundPacket packet, @Nullable VoicechatConnection senderConnection, VoicechatConnection receiverConnection, String source) { super(packet, senderConnection, receiverConnection, source); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/EventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/EventImpl.java similarity index 68% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/EventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/EventImpl.java index d91a360..31141c5 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/EventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/EventImpl.java @@ -1,12 +1,9 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.events.Event; -public class EventImpl -implements Event { +public class EventImpl implements Event { + private boolean cancelled; @Override @@ -16,16 +13,15 @@ implements Event { @Override public boolean cancel() { - if (!this.isCancellable()) { + if (!isCancellable()) { return false; } - this.cancelled = true; + cancelled = true; return true; } @Override public boolean isCancelled() { - return this.cancelled; + return cancelled; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/GroupEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/GroupEventImpl.java similarity index 66% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/GroupEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/GroupEventImpl.java index 482a10f..154baa0 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/GroupEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/GroupEventImpl.java @@ -1,20 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.Group; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.GroupEvent; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; + import javax.annotation.Nullable; -public class GroupEventImpl -extends ServerEventImpl -implements GroupEvent { +public class GroupEventImpl extends ServerEventImpl implements GroupEvent { + @Nullable protected Group group; protected VoicechatConnection connection; @@ -24,15 +17,14 @@ implements GroupEvent { this.connection = connection; } - @Override @Nullable + @Override public Group getGroup() { - return this.group; + return group; } @Override public VoicechatConnection getConnection() { - return this.connection; + return connection; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/JoinGroupEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/JoinGroupEventImpl.java similarity index 63% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/JoinGroupEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/JoinGroupEventImpl.java index 0bd560f..fa1a997 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/JoinGroupEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/JoinGroupEventImpl.java @@ -1,18 +1,12 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.Group; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.JoinGroupEvent; -import de.maxhenkel.voicechat.plugins.impl.events.GroupEventImpl; -public class JoinGroupEventImpl -extends GroupEventImpl -implements JoinGroupEvent { +public class JoinGroupEventImpl extends GroupEventImpl implements JoinGroupEvent { + public JoinGroupEventImpl(Group group, VoicechatConnection connection) { super(group, connection); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/LeaveGroupEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/LeaveGroupEventImpl.java similarity index 58% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/LeaveGroupEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/LeaveGroupEventImpl.java index 9edf8e4..0b10b19 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/LeaveGroupEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/LeaveGroupEventImpl.java @@ -1,22 +1,14 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.Group; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.LeaveGroupEvent; -import de.maxhenkel.voicechat.plugins.impl.events.GroupEventImpl; + import javax.annotation.Nullable; -public class LeaveGroupEventImpl -extends GroupEventImpl -implements LeaveGroupEvent { +public class LeaveGroupEventImpl extends GroupEventImpl implements LeaveGroupEvent { + public LeaveGroupEventImpl(@Nullable Group group, VoicechatConnection connection) { super(group, connection); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/LocationalSoundPacketEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/LocationalSoundPacketEventImpl.java similarity index 62% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/LocationalSoundPacketEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/LocationalSoundPacketEventImpl.java index 5d8f86c..8544915 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/LocationalSoundPacketEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/LocationalSoundPacketEventImpl.java @@ -1,22 +1,14 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.LocationalSoundPacketEvent; import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; -import de.maxhenkel.voicechat.plugins.impl.events.SoundPacketEventImpl; + import javax.annotation.Nullable; -public class LocationalSoundPacketEventImpl -extends SoundPacketEventImpl -implements LocationalSoundPacketEvent { +public class LocationalSoundPacketEventImpl extends SoundPacketEventImpl implements LocationalSoundPacketEvent { + public LocationalSoundPacketEventImpl(LocationalSoundPacket packet, @Nullable VoicechatConnection senderConnection, VoicechatConnection receiverConnection, String source) { super(packet, senderConnection, receiverConnection, source); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/MicrophonePacketEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/MicrophonePacketEventImpl.java similarity index 63% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/MicrophonePacketEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/MicrophonePacketEventImpl.java index 7513910..b130ff9 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/MicrophonePacketEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/MicrophonePacketEventImpl.java @@ -1,18 +1,12 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.MicrophonePacketEvent; import de.maxhenkel.voicechat.api.packets.MicrophonePacket; -import de.maxhenkel.voicechat.plugins.impl.events.PacketEventImpl; -public class MicrophonePacketEventImpl -extends PacketEventImpl -implements MicrophonePacketEvent { +public class MicrophonePacketEventImpl extends PacketEventImpl implements MicrophonePacketEvent { + public MicrophonePacketEventImpl(MicrophonePacket packet, VoicechatConnection connection) { super(packet, connection, null); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PacketEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PacketEventImpl.java similarity index 70% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PacketEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PacketEventImpl.java index 8de98f1..4c44e1d 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PacketEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PacketEventImpl.java @@ -1,20 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.PacketEvent; import de.maxhenkel.voicechat.api.packets.Packet; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; + import javax.annotation.Nullable; -public class PacketEventImpl -extends ServerEventImpl -implements PacketEvent { +public class PacketEventImpl extends ServerEventImpl implements PacketEvent { + private final T packet; @Nullable private final VoicechatConnection receiverConnection; @@ -29,19 +22,18 @@ implements PacketEvent { @Override public T getPacket() { - return this.packet; + return packet; } - @Override @Nullable + @Override public VoicechatConnection getReceiverConnection() { - return this.receiverConnection; + return receiverConnection; } - @Override @Nullable + @Override public VoicechatConnection getSenderConnection() { - return this.senderConnection; + return senderConnection; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PlayerConnectedEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PlayerConnectedEventImpl.java similarity index 67% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PlayerConnectedEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PlayerConnectedEventImpl.java index 7125f6c..84da473 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PlayerConnectedEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PlayerConnectedEventImpl.java @@ -1,16 +1,11 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.PlayerConnectedEvent; import de.maxhenkel.voicechat.plugins.impl.VoicechatConnectionImpl; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; -public class PlayerConnectedEventImpl -extends ServerEventImpl -implements PlayerConnectedEvent { +public class PlayerConnectedEventImpl extends ServerEventImpl implements PlayerConnectedEvent { + protected VoicechatConnectionImpl connection; public PlayerConnectedEventImpl(VoicechatConnectionImpl connection) { @@ -19,7 +14,6 @@ implements PlayerConnectedEvent { @Override public VoicechatConnection getConnection() { - return this.connection; + return connection; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PlayerDisconnectedEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PlayerDisconnectedEventImpl.java similarity index 57% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PlayerDisconnectedEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PlayerDisconnectedEventImpl.java index 5626075..0d17bdb 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PlayerDisconnectedEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PlayerDisconnectedEventImpl.java @@ -1,15 +1,11 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.events.PlayerDisconnectedEvent; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; + import java.util.UUID; -public class PlayerDisconnectedEventImpl -extends ServerEventImpl -implements PlayerDisconnectedEvent { +public class PlayerDisconnectedEventImpl extends ServerEventImpl implements PlayerDisconnectedEvent { + protected UUID player; public PlayerDisconnectedEventImpl(UUID player) { @@ -18,7 +14,6 @@ implements PlayerDisconnectedEvent { @Override public UUID getPlayerUuid() { - return this.player; + return player; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PlayerStateChangedEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PlayerStateChangedEventImpl.java similarity index 63% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PlayerStateChangedEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PlayerStateChangedEventImpl.java index 7e57322..7bd3d00 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/PlayerStateChangedEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/PlayerStateChangedEventImpl.java @@ -1,25 +1,17 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.PlayerStateChangedEvent; import de.maxhenkel.voicechat.plugins.impl.VoicechatConnectionImpl; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; import de.maxhenkel.voicechat.voice.common.PlayerState; -import java.util.UUID; -import javax.annotation.Nullable; import org.bukkit.entity.Player; -public class PlayerStateChangedEventImpl -extends ServerEventImpl -implements PlayerStateChangedEvent { +import javax.annotation.Nullable; +import java.util.UUID; + +public class PlayerStateChangedEventImpl extends ServerEventImpl implements PlayerStateChangedEvent { + protected final PlayerState state; @Nullable protected VoicechatConnectionImpl connection; @@ -30,30 +22,29 @@ implements PlayerStateChangedEvent { @Override public boolean isDisabled() { - return this.state.isDisabled(); + return state.isDisabled(); } @Override public boolean isDisconnected() { - return this.state.isDisconnected(); + return state.isDisconnected(); } @Override public UUID getPlayerUuid() { - return this.state.getUuid(); + return state.getUuid(); } @Override @Nullable public VoicechatConnection getConnection() { - if (this.connection == null) { - Player player = Voicechat.INSTANCE.getServer().getPlayer(this.state.getUuid()); + if (connection == null) { + Player player = Voicechat.INSTANCE.getServer().getPlayer(state.getUuid()); if (player == null) { return null; } - this.connection = VoicechatConnectionImpl.fromPlayer(player); + connection = VoicechatConnectionImpl.fromPlayer(player); } - return this.connection; + return connection; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/RegisterVolumeCategoryEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/RegisterVolumeCategoryEventImpl.java similarity index 54% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/RegisterVolumeCategoryEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/RegisterVolumeCategoryEventImpl.java index 436d0f1..c7709cd 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/RegisterVolumeCategoryEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/RegisterVolumeCategoryEventImpl.java @@ -1,17 +1,12 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VolumeCategory; import de.maxhenkel.voicechat.api.events.RegisterVolumeCategoryEvent; -import de.maxhenkel.voicechat.plugins.impl.events.VolumeCategoryEventImpl; -public class RegisterVolumeCategoryEventImpl -extends VolumeCategoryEventImpl -implements RegisterVolumeCategoryEvent { +public class RegisterVolumeCategoryEventImpl extends VolumeCategoryEventImpl implements RegisterVolumeCategoryEvent { + public RegisterVolumeCategoryEventImpl(VolumeCategory category) { super(category); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/RemoveGroupEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/RemoveGroupEventImpl.java similarity index 53% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/RemoveGroupEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/RemoveGroupEventImpl.java index 994dcf6..c97e1b1 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/RemoveGroupEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/RemoveGroupEventImpl.java @@ -1,22 +1,16 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.Group; import de.maxhenkel.voicechat.api.events.RemoveGroupEvent; -import de.maxhenkel.voicechat.plugins.impl.events.GroupEventImpl; -public class RemoveGroupEventImpl -extends GroupEventImpl -implements RemoveGroupEvent { +public class RemoveGroupEventImpl extends GroupEventImpl implements RemoveGroupEvent { + public RemoveGroupEventImpl(Group group) { super(group, null); } @Override public boolean isCancellable() { - return super.isCancellable() && this.group.isPersistent(); + return super.isCancellable() && group.isPersistent(); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/ServerEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/ServerEventImpl.java similarity index 67% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/ServerEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/ServerEventImpl.java index c412f9d..ebd9289 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/ServerEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/ServerEventImpl.java @@ -1,19 +1,14 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VoicechatServerApi; import de.maxhenkel.voicechat.api.events.ServerEvent; import de.maxhenkel.voicechat.plugins.impl.VoicechatServerApiImpl; -import de.maxhenkel.voicechat.plugins.impl.events.EventImpl; -public class ServerEventImpl -extends EventImpl -implements ServerEvent { +public class ServerEventImpl extends EventImpl implements ServerEvent { + @Override public VoicechatServerApi getVoicechat() { return VoicechatServerApiImpl.instance(); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/SoundPacketEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/SoundPacketEventImpl.java similarity index 65% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/SoundPacketEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/SoundPacketEventImpl.java index 9ea9745..1871270 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/SoundPacketEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/SoundPacketEventImpl.java @@ -1,20 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.SoundPacketEvent; import de.maxhenkel.voicechat.api.packets.Packet; -import de.maxhenkel.voicechat.plugins.impl.events.PacketEventImpl; + import javax.annotation.Nullable; -public class SoundPacketEventImpl -extends PacketEventImpl -implements SoundPacketEvent { +public class SoundPacketEventImpl extends PacketEventImpl implements SoundPacketEvent { + private final String source; public SoundPacketEventImpl(T packet, @Nullable VoicechatConnection senderConnection, @Nullable VoicechatConnection receiverConnection, String source) { @@ -24,7 +17,7 @@ implements SoundPacketEvent { @Override public String getSource() { - return this.source; + return source; } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/StaticSoundPacketEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/StaticSoundPacketEventImpl.java similarity index 62% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/StaticSoundPacketEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/StaticSoundPacketEventImpl.java index 107734c..415b0d5 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/StaticSoundPacketEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/StaticSoundPacketEventImpl.java @@ -1,22 +1,14 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.StaticSoundPacketEvent; import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; -import de.maxhenkel.voicechat.plugins.impl.events.SoundPacketEventImpl; + import javax.annotation.Nullable; -public class StaticSoundPacketEventImpl -extends SoundPacketEventImpl -implements StaticSoundPacketEvent { +public class StaticSoundPacketEventImpl extends SoundPacketEventImpl implements StaticSoundPacketEvent { + public StaticSoundPacketEventImpl(StaticSoundPacket packet, @Nullable VoicechatConnection senderConnection, VoicechatConnection receiverConnection, String source) { super(packet, senderConnection, receiverConnection, source); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/UnregisterVolumeCategoryEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/UnregisterVolumeCategoryEventImpl.java similarity index 54% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/UnregisterVolumeCategoryEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/UnregisterVolumeCategoryEventImpl.java index 1d0228a..911978f 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/UnregisterVolumeCategoryEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/UnregisterVolumeCategoryEventImpl.java @@ -1,17 +1,12 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VolumeCategory; import de.maxhenkel.voicechat.api.events.UnregisterVolumeCategoryEvent; -import de.maxhenkel.voicechat.plugins.impl.events.VolumeCategoryEventImpl; -public class UnregisterVolumeCategoryEventImpl -extends VolumeCategoryEventImpl -implements UnregisterVolumeCategoryEvent { +public class UnregisterVolumeCategoryEventImpl extends VolumeCategoryEventImpl implements UnregisterVolumeCategoryEvent { + public UnregisterVolumeCategoryEventImpl(VolumeCategory category) { super(category); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoiceDistanceEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoiceDistanceEventImpl.java similarity index 73% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoiceDistanceEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoiceDistanceEventImpl.java index fd14989..e08f16c 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoiceDistanceEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoiceDistanceEventImpl.java @@ -1,20 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VoicechatConnection; import de.maxhenkel.voicechat.api.events.VoiceDistanceEvent; import de.maxhenkel.voicechat.api.packets.MicrophonePacket; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; + import javax.annotation.Nullable; -public class VoiceDistanceEventImpl -extends ServerEventImpl -implements VoiceDistanceEvent { +public class VoiceDistanceEventImpl extends ServerEventImpl implements VoiceDistanceEvent { + private final MicrophonePacket packet; private final VoicechatConnection senderConnection; private float distance; @@ -32,18 +25,18 @@ implements VoiceDistanceEvent { @Override public MicrophonePacket getPacket() { - return this.packet; + return packet; } - @Override @Nullable + @Override public VoicechatConnection getSenderConnection() { - return this.senderConnection; + return senderConnection; } @Override public float getDistance() { - return this.distance; + return distance; } @Override @@ -51,4 +44,3 @@ implements VoiceDistanceEvent { this.distance = distance; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoiceHostEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoiceHostEventImpl.java similarity index 68% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoiceHostEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoiceHostEventImpl.java index cb62b56..11181b4 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoiceHostEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoiceHostEventImpl.java @@ -1,20 +1,12 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.ServerPlayer; import de.maxhenkel.voicechat.api.events.VoiceHostEvent; import de.maxhenkel.voicechat.plugins.impl.ServerPlayerImpl; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; import org.bukkit.entity.Player; -public class VoiceHostEventImpl -extends ServerEventImpl -implements VoiceHostEvent { +public class VoiceHostEventImpl extends ServerEventImpl implements VoiceHostEvent { + private final ServerPlayerImpl player; private String voiceHost; @@ -25,7 +17,7 @@ implements VoiceHostEvent { @Override public String getVoiceHost() { - return this.voiceHost; + return voiceHost; } @Override @@ -35,7 +27,7 @@ implements VoiceHostEvent { @Override public ServerPlayer getPlayer() { - return this.player; + return player; } -} +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartedEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartedEventImpl.java new file mode 100644 index 0000000..b7664d7 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartedEventImpl.java @@ -0,0 +1,11 @@ +package de.maxhenkel.voicechat.plugins.impl.events; + +import de.maxhenkel.voicechat.api.events.VoicechatServerStartedEvent; + +public class VoicechatServerStartedEventImpl extends ServerEventImpl implements VoicechatServerStartedEvent { + + @Override + public boolean isCancellable() { + return false; + } +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartingEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartingEventImpl.java similarity index 63% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartingEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartingEventImpl.java index a91c6fd..a829392 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartingEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartingEventImpl.java @@ -1,19 +1,12 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VoicechatSocket; import de.maxhenkel.voicechat.api.events.VoicechatServerStartingEvent; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; + import javax.annotation.Nullable; -public class VoicechatServerStartingEventImpl -extends ServerEventImpl -implements VoicechatServerStartingEvent { +public class VoicechatServerStartingEventImpl extends ServerEventImpl implements VoicechatServerStartingEvent { + @Nullable private VoicechatSocket socketImplementation; @@ -22,10 +15,10 @@ implements VoicechatServerStartingEvent { this.socketImplementation = socket; } - @Override @Nullable + @Override public VoicechatSocket getSocketImplementation() { - return this.socketImplementation; + return socketImplementation; } @Override @@ -33,4 +26,3 @@ implements VoicechatServerStartingEvent { return false; } } - diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStoppedEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStoppedEventImpl.java new file mode 100644 index 0000000..5886407 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStoppedEventImpl.java @@ -0,0 +1,11 @@ +package de.maxhenkel.voicechat.plugins.impl.events; + +import de.maxhenkel.voicechat.api.events.VoicechatServerStoppedEvent; + +public class VoicechatServerStoppedEventImpl extends ServerEventImpl implements VoicechatServerStoppedEvent { + + @Override + public boolean isCancellable() { + return false; + } +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VolumeCategoryEventImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VolumeCategoryEventImpl.java similarity index 67% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VolumeCategoryEventImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VolumeCategoryEventImpl.java index 2487233..fff0643 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VolumeCategoryEventImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/events/VolumeCategoryEventImpl.java @@ -1,15 +1,10 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.events; import de.maxhenkel.voicechat.api.VolumeCategory; import de.maxhenkel.voicechat.api.events.VolumeCategoryEvent; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; -public class VolumeCategoryEventImpl -extends ServerEventImpl -implements VolumeCategoryEvent { +public class VolumeCategoryEventImpl extends ServerEventImpl implements VolumeCategoryEvent { + private final VolumeCategory category; public VolumeCategoryEventImpl(VolumeCategory category) { @@ -18,7 +13,7 @@ implements VolumeCategoryEvent { @Override public VolumeCategory getVolumeCategory() { - return this.category; + return category; } @Override @@ -26,4 +21,3 @@ implements VolumeCategoryEvent { return false; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusDecoderImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusDecoderImpl.java similarity index 54% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusDecoderImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusDecoderImpl.java index 8854eb2..8a85f8d 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusDecoderImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusDecoderImpl.java @@ -1,61 +1,60 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.opus; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.api.opus.OpusDecoder; -import de.maxhenkel.voicechat.concentus.OpusException; +import org.concentus.OpusDecoder; +import org.concentus.OpusException; + import javax.annotation.Nullable; -public class JavaOpusDecoderImpl -implements OpusDecoder { - protected de.maxhenkel.voicechat.concentus.OpusDecoder opusDecoder; +public class JavaOpusDecoderImpl implements de.maxhenkel.voicechat.api.opus.OpusDecoder { + + protected OpusDecoder opusDecoder; protected short[] buffer; protected int sampleRate; public JavaOpusDecoderImpl(int sampleRate, int frameSize) { this.sampleRate = sampleRate; this.buffer = new short[frameSize]; - this.open(); + open(); } private void open() { - if (this.opusDecoder != null) { + if (opusDecoder != null) { return; } try { - this.opusDecoder = new de.maxhenkel.voicechat.concentus.OpusDecoder(this.sampleRate, 1); - } - catch (OpusException e) { + opusDecoder = new OpusDecoder(sampleRate, 1); + } catch (OpusException e) { throw new IllegalStateException("Failed to create Opus decoder", e); } - Voicechat.LOGGER.debug("Initializing Java Opus decoder with sample rate {} Hz, frame size {} bytes", this.sampleRate, this.buffer.length); + Voicechat.LOGGER.debug("Initializing Java Opus decoder with sample rate {} Hz, frame size {} bytes", sampleRate, buffer.length); } @Override public short[] decode(@Nullable byte[] data) { - int result; - if (this.isClosed()) { + if (isClosed()) { throw new IllegalStateException("Decoder is closed"); } + int result; + try { - result = data == null || data.length == 0 ? this.opusDecoder.decode(null, 0, 0, this.buffer, 0, this.buffer.length, true) : this.opusDecoder.decode(data, 0, data.length, this.buffer, 0, this.buffer.length, false); - } - catch (Exception e) { + if (data == null || data.length == 0) { + result = opusDecoder.decode(null, 0, 0, buffer, 0, buffer.length, true); + } else { + result = opusDecoder.decode(data, 0, data.length, buffer, 0, buffer.length, false); + } + } catch (Exception e) { throw new RuntimeException("Failed to decode audio", e); } + short[] audio = new short[result]; - System.arraycopy(this.buffer, 0, audio, 0, result); + System.arraycopy(buffer, 0, audio, 0, result); return audio; } @Override public short[][] decode(byte[] data, int frames) { - if (this.isClosed()) { + if (isClosed()) { throw new IllegalStateException("Decoder is closed"); } if (frames <= 0) { @@ -64,53 +63,55 @@ implements OpusDecoder { if (data == null || data.length == 0) { throw new IllegalArgumentException("Data must not be null or empty"); } + short[][] recovered = new short[frames][]; try { int result; if (frames > 2) { - for (int i = 0; i < frames - 2; ++i) { - result = this.opusDecoder.decode(null, 0, 0, this.buffer, 0, this.buffer.length, true); + for (int i = 0; i < frames - 2; i++) { + result = opusDecoder.decode(null, 0, 0, buffer, 0, buffer.length, true); short[] audio = new short[result]; - System.arraycopy(this.buffer, 0, audio, 0, result); + System.arraycopy(buffer, 0, audio, 0, result); recovered[i] = audio; } } if (frames > 1) { - result = this.opusDecoder.decode(data, 0, data.length, this.buffer, 0, this.buffer.length, true); + result = opusDecoder.decode(data, 0, data.length, buffer, 0, buffer.length, true); short[] audio = new short[result]; - System.arraycopy(this.buffer, 0, audio, 0, result); + System.arraycopy(buffer, 0, audio, 0, result); recovered[frames - 2] = audio; } - result = this.opusDecoder.decode(data, 0, data.length, this.buffer, 0, this.buffer.length, false); + + result = opusDecoder.decode(data, 0, data.length, buffer, 0, buffer.length, false); short[] audio = new short[result]; - System.arraycopy(this.buffer, 0, audio, 0, result); + System.arraycopy(buffer, 0, audio, 0, result); recovered[frames - 1] = audio; - } - catch (Exception e) { + } catch (Exception e) { throw new RuntimeException("Failed to decode audio", e); } + return recovered; } @Override public boolean isClosed() { - return this.opusDecoder == null; + return opusDecoder == null; } @Override public void close() { - if (this.isClosed()) { + if (isClosed()) { return; } - this.opusDecoder = null; + opusDecoder = null; } @Override public void resetState() { - if (this.isClosed()) { + if (isClosed()) { throw new IllegalStateException("Decoder is closed"); } - this.opusDecoder.resetState(); + opusDecoder.resetState(); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusEncoderImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusEncoderImpl.java similarity index 60% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusEncoderImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusEncoderImpl.java index 39b2ac8..ca7d824 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusEncoderImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/opus/JavaOpusEncoderImpl.java @@ -1,13 +1,10 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.opus; -import de.maxhenkel.voicechat.concentus.OpusApplication; -import de.maxhenkel.voicechat.concentus.OpusEncoder; +import org.concentus.OpusApplication; +import org.concentus.OpusEncoder; + +public class JavaOpusEncoderImpl implements de.maxhenkel.voicechat.api.opus.OpusEncoder { -public class JavaOpusEncoderImpl -implements de.maxhenkel.voicechat.api.opus.OpusEncoder { protected OpusEncoder opusEncoder; protected byte[] buffer; protected int sampleRate; @@ -21,62 +18,62 @@ implements de.maxhenkel.voicechat.api.opus.OpusEncoder { this.maxPayloadSize = maxPayloadSize; this.application = application; this.buffer = new byte[maxPayloadSize]; - this.open(); + open(); } private void open() { - if (this.opusEncoder != null) { + if (opusEncoder != null) { return; } try { - this.opusEncoder = new OpusEncoder(this.sampleRate, 1, this.application); - this.opusEncoder.setUseInbandFEC(true); - this.opusEncoder.setPacketLossPercent(5); - } - catch (Exception e) { + opusEncoder = new OpusEncoder(sampleRate, 1, application); + opusEncoder.setUseInbandFEC(true); + opusEncoder.setPacketLossPercent(5); + } catch (Exception e) { throw new IllegalStateException("Opus encoder error " + e.getMessage()); } } @Override public byte[] encode(short[] rawAudio) { - int result; - if (this.isClosed()) { + if (isClosed()) { throw new IllegalStateException("Encoder is closed"); } + + int result; try { - result = this.opusEncoder.encode(rawAudio, 0, this.frameSize, this.buffer, 0, this.buffer.length); - } - catch (Exception e) { + result = opusEncoder.encode(rawAudio, 0, frameSize, buffer, 0, buffer.length); + } catch (Exception e) { throw new RuntimeException("Failed to encode audio data: " + e.getMessage()); } + if (result < 0) { throw new RuntimeException("Failed to encode audio data"); } + byte[] audio = new byte[result]; - System.arraycopy(this.buffer, 0, audio, 0, result); + System.arraycopy(buffer, 0, audio, 0, result); return audio; } @Override public void resetState() { - if (this.isClosed()) { + if (isClosed()) { throw new IllegalStateException("Encoder is closed"); } - this.opusEncoder.resetState(); + opusEncoder.resetState(); } @Override public boolean isClosed() { - return this.opusEncoder == null; + return opusEncoder == null; } @Override public void close() { - if (this.isClosed()) { + if (isClosed()) { return; } - this.opusEncoder = null; + opusEncoder = null; } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/opus/OpusManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/opus/OpusManager.java similarity index 69% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/opus/OpusManager.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/opus/OpusManager.java index 2f509b4..7b60ba2 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/opus/OpusManager.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/opus/OpusManager.java @@ -1,18 +1,14 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.plugins.impl.opus; import de.maxhenkel.voicechat.api.opus.OpusDecoder; import de.maxhenkel.voicechat.api.opus.OpusEncoder; import de.maxhenkel.voicechat.api.opus.OpusEncoderMode; -import de.maxhenkel.voicechat.concentus.OpusApplication; -import de.maxhenkel.voicechat.plugins.impl.opus.JavaOpusDecoderImpl; -import de.maxhenkel.voicechat.plugins.impl.opus.JavaOpusEncoderImpl; +import org.concentus.OpusApplication; public class OpusManager { + public static final int SAMPLE_RATE = 48000; - public static final int FRAME_SIZE = 960; + public static final int FRAME_SIZE = (SAMPLE_RATE / 1000) * 20; public static OpusEncoder createEncoder(int sampleRate, int frameSize, int maxPayloadSize, OpusApplication application) { return new JavaOpusEncoderImpl(sampleRate, frameSize, maxPayloadSize, application); @@ -22,17 +18,18 @@ public class OpusManager { OpusApplication application = OpusApplication.OPUS_APPLICATION_VOIP; if (mode != null) { switch (mode) { - case AUDIO: { + case AUDIO: application = OpusApplication.OPUS_APPLICATION_AUDIO; break; - } - case RESTRICTED_LOWDELAY: { + case RESTRICTED_LOWDELAY: application = OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY; break; - } + default: + break; } + } - return OpusManager.createEncoder(48000, 960, 1024, application); + return createEncoder(SAMPLE_RATE, FRAME_SIZE, 1024, application); } public static OpusDecoder createDecoder(int sampleRate, int frameSize) { @@ -40,7 +37,7 @@ public class OpusManager { } public static OpusDecoder createDecoder() { - return OpusManager.createDecoder(48000, 960); + return createDecoder(SAMPLE_RATE, FRAME_SIZE); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/ConvertablePacketImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/ConvertablePacketImpl.java similarity index 59% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/ConvertablePacketImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/ConvertablePacketImpl.java index b86b9fe..3d22d45 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/ConvertablePacketImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/ConvertablePacketImpl.java @@ -1,30 +1,17 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.packets; import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.packets.ConvertablePacket; -import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; -import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; -import de.maxhenkel.voicechat.api.packets.SoundPacket; -import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; +import de.maxhenkel.voicechat.api.packets.*; import de.maxhenkel.voicechat.plugins.impl.PositionImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.EntitySoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.LocationalSoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.StaticSoundPacketImpl; import de.maxhenkel.voicechat.voice.common.GroupSoundPacket; import de.maxhenkel.voicechat.voice.common.LocationSoundPacket; import de.maxhenkel.voicechat.voice.common.PlayerSoundPacket; import de.maxhenkel.voicechat.voice.common.Utils; -import java.util.UUID; -import javax.annotation.Nullable; -public class ConvertablePacketImpl -implements ConvertablePacket { +import javax.annotation.Nullable; +import java.util.UUID; + +public class ConvertablePacketImpl implements ConvertablePacket { @Override public EntitySoundPacket.Builder entitySoundPacketBuilder() { return new GenericEntitySoundPacketBuilder(); @@ -55,13 +42,76 @@ implements ConvertablePacket { throw new UnsupportedOperationException(); } - public static class GenericEntitySoundPacketBuilder - extends GenericSoundPacketBuilder - implements EntitySoundPacket.Builder { + public abstract static class GenericSoundPacketBuilder, P extends SoundPacket> implements SoundPacket.Builder { + + @Nullable + protected UUID channelId; + @Nullable + protected UUID sender; + @Nullable + protected byte[] opusEncodedData; + @Nullable + protected Long sequenceNumber; + @Nullable + protected String category; + + public GenericSoundPacketBuilder() { + + } + + @Override + public T channelId(UUID channelId) { + this.channelId = channelId; + return (T) this; + } + + @Override + public T sender(UUID sender) { + this.sender = sender; + return (T) this; + } + + @Override + public T opusEncodedData(byte[] data) { + this.opusEncodedData = data; + return (T) this; + } + + @Override + public T sequenceNumber(long sequenceNumber) { + this.sequenceNumber = sequenceNumber; + return (T) this; + } + + @Override + public T category(@Nullable String category) { + this.category = category; + return (T) this; + } + + public void checkRequiredFields() { + if (channelId == null) { + throw new IllegalStateException("Channel id must be set"); + } + if (sequenceNumber == null) { + throw new IllegalStateException("Sequence number must be set"); + } + if (opusEncodedData == null) { + throw new IllegalStateException("Opus encoded data must be set"); + } + } + } + + public static class GenericEntitySoundPacketBuilder extends GenericSoundPacketBuilder implements EntitySoundPacket.Builder { + protected UUID entityUuid; protected boolean whispering; protected Float distance; + public GenericEntitySoundPacketBuilder() { + + } + @Override public GenericEntitySoundPacketBuilder entityUuid(UUID entityUuid) { this.entityUuid = entityUuid; @@ -76,117 +126,58 @@ implements ConvertablePacket { @Override public GenericEntitySoundPacketBuilder distance(float distance) { - this.distance = Float.valueOf(distance); + this.distance = distance; return this; } @Override public EntitySoundPacket build() { - this.checkRequiredFields(); - if (this.entityUuid == null) { + checkRequiredFields(); + if (entityUuid == null) { throw new IllegalStateException("Entity UUID must be set"); } - if (this.distance == null) { - this.distance = Float.valueOf(Utils.getDefaultDistance()); + if (distance == null) { + distance = Utils.getDefaultDistance(); } - return new EntitySoundPacketImpl(new PlayerSoundPacket(this.channelId, this.entityUuid, this.opusEncodedData, this.sequenceNumber, this.whispering, this.distance.floatValue(), this.category)); + return new EntitySoundPacketImpl(new PlayerSoundPacket(channelId, entityUuid, opusEncodedData, sequenceNumber, whispering, distance, category)); } } - public static class GenericLocationalSoundPacketBuilder - extends GenericSoundPacketBuilder - implements LocationalSoundPacket.Builder { + public static class GenericLocationalSoundPacketBuilder extends GenericSoundPacketBuilder implements LocationalSoundPacket.Builder { + protected PositionImpl position; protected Float distance; @Override public GenericLocationalSoundPacketBuilder position(Position position) { - this.position = (PositionImpl)position; + this.position = (PositionImpl) position; return this; } @Override public GenericLocationalSoundPacketBuilder distance(float distance) { - this.distance = Float.valueOf(distance); + this.distance = distance; return this; } @Override public LocationalSoundPacket build() { - this.checkRequiredFields(); - if (this.position == null) { + checkRequiredFields(); + if (position == null) { throw new IllegalStateException("Position must be set"); } - if (this.distance == null) { - this.distance = Float.valueOf(Utils.getDefaultDistance()); + if (distance == null) { + distance = Utils.getDefaultDistance(); } - return new LocationalSoundPacketImpl(new LocationSoundPacket(this.channelId, this.sender, this.position.getPosition(), this.opusEncodedData, this.sequenceNumber, this.distance.floatValue(), this.category)); + return new LocationalSoundPacketImpl(new LocationSoundPacket(channelId, sender, position.getPosition(), opusEncodedData, sequenceNumber, distance, category)); } } - public static class GenericStaticSoundPacketBuilder - extends GenericSoundPacketBuilder - implements StaticSoundPacket.Builder { + public static class GenericStaticSoundPacketBuilder extends GenericSoundPacketBuilder implements StaticSoundPacket.Builder { @Override public StaticSoundPacket build() { - return new StaticSoundPacketImpl(new GroupSoundPacket(this.channelId, this.sender, this.opusEncodedData, this.sequenceNumber, this.category)); + return new StaticSoundPacketImpl(new GroupSoundPacket(channelId, sender, opusEncodedData, sequenceNumber, category)); } } - public static abstract class GenericSoundPacketBuilder, P extends SoundPacket> - implements SoundPacket.Builder { - @Nullable - protected UUID channelId; - @Nullable - protected UUID sender; - @Nullable - protected byte[] opusEncodedData; - @Nullable - protected Long sequenceNumber; - @Nullable - protected String category; - - @Override - public T channelId(UUID channelId) { - this.channelId = channelId; - return (T)this; - } - - @Override - public T sender(UUID sender) { - this.sender = sender; - return (T)this; - } - - @Override - public T opusEncodedData(byte[] data) { - this.opusEncodedData = data; - return (T)this; - } - - @Override - public T sequenceNumber(long sequenceNumber) { - this.sequenceNumber = sequenceNumber; - return (T)this; - } - - @Override - public T category(@Nullable String category) { - this.category = category; - return (T)this; - } - - public void checkRequiredFields() { - if (this.channelId == null) { - throw new IllegalStateException("Channel id must be set"); - } - if (this.sequenceNumber == null) { - throw new IllegalStateException("Sequence number must be set"); - } - if (this.opusEncodedData == null) { - throw new IllegalStateException("Opus encoded data must be set"); - } - } - } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/EntitySoundPacketImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/EntitySoundPacketImpl.java similarity index 62% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/EntitySoundPacketImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/EntitySoundPacketImpl.java index e368059..5016eab 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/EntitySoundPacketImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/EntitySoundPacketImpl.java @@ -1,22 +1,14 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.packets; import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; -import de.maxhenkel.voicechat.plugins.impl.packets.LocationalSoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.SoundPacketImpl; import de.maxhenkel.voicechat.voice.common.PlayerSoundPacket; import de.maxhenkel.voicechat.voice.common.Utils; -import java.util.UUID; -import javax.annotation.Nullable; -public class EntitySoundPacketImpl -extends SoundPacketImpl -implements EntitySoundPacket { +import javax.annotation.Nullable; +import java.util.UUID; + +public class EntitySoundPacketImpl extends SoundPacketImpl implements EntitySoundPacket { + private final PlayerSoundPacket packet; public EntitySoundPacketImpl(PlayerSoundPacket packet) { @@ -26,31 +18,31 @@ implements EntitySoundPacket { @Override public UUID getEntityUuid() { - return this.packet.getSender(); + return packet.getSender(); } @Override public boolean isWhispering() { - return this.packet.isWhispering(); + return packet.isWhispering(); } @Override public float getDistance() { - return this.packet.getDistance(); + return packet.getDistance(); } + @Override public PlayerSoundPacket getPacket() { - return this.packet; + return packet; } @Override public UUID getChannelId() { - return this.packet.getChannelId(); + return packet.getChannelId(); } - public static class BuilderImpl - extends SoundPacketImpl.BuilderImpl - implements EntitySoundPacket.Builder { + public static class BuilderImpl extends SoundPacketImpl.BuilderImpl implements EntitySoundPacket.Builder { + protected UUID entityUuid; protected boolean whispering; protected float distance; @@ -58,12 +50,14 @@ implements EntitySoundPacket { public BuilderImpl(SoundPacketImpl soundPacket) { super(soundPacket); if (soundPacket instanceof EntitySoundPacketImpl) { - EntitySoundPacketImpl p = (EntitySoundPacketImpl)soundPacket; - this.entityUuid = p.getEntityUuid(); - this.whispering = p.isWhispering(); - this.distance = p.getDistance(); + EntitySoundPacketImpl p = (EntitySoundPacketImpl) soundPacket; + entityUuid = p.getEntityUuid(); + whispering = p.isWhispering(); + distance = p.getDistance(); + } else if (soundPacket instanceof LocationalSoundPacketImpl) { + distance = ((LocationalSoundPacketImpl) soundPacket).getDistance(); } else { - this.distance = soundPacket instanceof LocationalSoundPacketImpl ? ((LocationalSoundPacketImpl)soundPacket).getDistance() : Utils.getDefaultDistance(); + distance = Utils.getDefaultDistance(); } } @@ -92,11 +86,11 @@ implements EntitySoundPacket { @Override public EntitySoundPacket build() { - if (this.entityUuid == null) { + if (entityUuid == null) { throw new IllegalStateException("entityUuid missing"); } - return new EntitySoundPacketImpl(new PlayerSoundPacket(this.channelId, this.entityUuid, this.opusEncodedData, this.sequenceNumber, this.whispering, this.distance, this.category)); + return new EntitySoundPacketImpl(new PlayerSoundPacket(channelId, entityUuid, opusEncodedData, sequenceNumber, whispering, distance, category)); } + } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/LocationalSoundPacketImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/LocationalSoundPacketImpl.java similarity index 59% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/LocationalSoundPacketImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/LocationalSoundPacketImpl.java index c668b93..ecb5c11 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/LocationalSoundPacketImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/LocationalSoundPacketImpl.java @@ -1,24 +1,16 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.packets; import de.maxhenkel.voicechat.api.Position; import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; import de.maxhenkel.voicechat.plugins.impl.PositionImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.EntitySoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.SoundPacketImpl; import de.maxhenkel.voicechat.voice.common.LocationSoundPacket; import de.maxhenkel.voicechat.voice.common.Utils; -import java.util.UUID; -import javax.annotation.Nullable; -public class LocationalSoundPacketImpl -extends SoundPacketImpl -implements LocationalSoundPacket { +import javax.annotation.Nullable; +import java.util.UUID; + +public class LocationalSoundPacketImpl extends SoundPacketImpl implements LocationalSoundPacket { + private final LocationSoundPacket packet; private final PositionImpl position; @@ -28,61 +20,65 @@ implements LocationalSoundPacket { this.position = new PositionImpl(packet.getLocation()); } - @Override public Position getPosition() { - return this.position; + return position; } @Override public float getDistance() { - return this.packet.getDistance(); + return packet.getDistance(); } + @Override public LocationSoundPacket getPacket() { - return this.packet; + return packet; } - public static class BuilderImpl - extends SoundPacketImpl.BuilderImpl - implements LocationalSoundPacket.Builder { + + public static class BuilderImpl extends SoundPacketImpl.BuilderImpl implements LocationalSoundPacket.Builder { + protected PositionImpl position; protected float distance; public BuilderImpl(SoundPacketImpl soundPacket) { super(soundPacket); if (soundPacket instanceof LocationalSoundPacketImpl) { - LocationalSoundPacketImpl p = (LocationalSoundPacketImpl)soundPacket; - this.position = p.position; - this.distance = p.getDistance(); + LocationalSoundPacketImpl p = (LocationalSoundPacketImpl) soundPacket; + position = p.position; + distance = p.getDistance(); + } else if (soundPacket instanceof EntitySoundPacketImpl) { + distance = ((EntitySoundPacketImpl) soundPacket).getDistance(); } else { - this.distance = soundPacket instanceof EntitySoundPacketImpl ? ((EntitySoundPacketImpl)soundPacket).getDistance() : Utils.getDefaultDistance(); + distance = Utils.getDefaultDistance(); } } public BuilderImpl(UUID channelId, UUID sender, byte[] opusEncodedData, long sequenceNumber, @Nullable String category) { super(channelId, sender, opusEncodedData, sequenceNumber, category); - this.distance = Utils.getDefaultDistance(); + distance = Utils.getDefaultDistance(); } @Override public BuilderImpl position(Position position) { - this.position = (PositionImpl)position; + this.position = (PositionImpl) position; return this; } @Override - public BuilderImpl distance(float distance) { + public LocationalSoundPacketImpl.BuilderImpl distance(float distance) { this.distance = distance; return this; } @Override public LocationalSoundPacket build() { - if (this.position == null) { + if (position == null) { throw new IllegalStateException("position missing"); } - return new LocationalSoundPacketImpl(new LocationSoundPacket(this.channelId, this.sender, this.position.getPosition(), this.opusEncodedData, this.sequenceNumber, this.distance, this.category)); + return new LocationalSoundPacketImpl(new LocationSoundPacket(channelId, sender, position.getPosition(), opusEncodedData, sequenceNumber, distance, category)); } - } -} + } + + +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/MicrophonePacketImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/MicrophonePacketImpl.java new file mode 100644 index 0000000..07a5c61 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/MicrophonePacketImpl.java @@ -0,0 +1,77 @@ +package de.maxhenkel.voicechat.plugins.impl.packets; + +import de.maxhenkel.voicechat.api.Position; +import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; +import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; +import de.maxhenkel.voicechat.api.packets.MicrophonePacket; +import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; +import de.maxhenkel.voicechat.plugins.impl.PositionImpl; +import de.maxhenkel.voicechat.voice.common.*; + +import java.util.Objects; +import java.util.UUID; + +public class MicrophonePacketImpl implements MicrophonePacket { + + private final MicPacket packet; + private final UUID sender; + + public MicrophonePacketImpl(MicPacket packet, UUID sender) { + this.packet = packet; + this.sender = sender; + } + + @Override + public boolean isWhispering() { + return packet.isWhispering(); + } + + @Override + public byte[] getOpusEncodedData() { + return packet.getData(); + } + + @Override + public void setOpusEncodedData(byte[] data) { + packet.setData(Objects.requireNonNull(data)); + } + + @Override + public EntitySoundPacket.Builder entitySoundPacketBuilder() { + return new EntitySoundPacketImpl.BuilderImpl(sender, sender, packet.getData(), packet.getSequenceNumber(), null); + } + + @Override + public LocationalSoundPacket.Builder locationalSoundPacketBuilder() { + return new LocationalSoundPacketImpl.BuilderImpl(sender, sender, packet.getData(), packet.getSequenceNumber(), null); + } + + @Override + public StaticSoundPacket.Builder staticSoundPacketBuilder() { + return new StaticSoundPacketImpl.BuilderImpl(sender, sender, packet.getData(), packet.getSequenceNumber(), null); + } + + @Override + @Deprecated + public EntitySoundPacket toEntitySoundPacket(UUID entityUuid, boolean whispering) { + return new EntitySoundPacketImpl(new PlayerSoundPacket(sender, entityUuid, packet.getData(), packet.getSequenceNumber(), whispering, Utils.getDefaultDistance(), null)); + } + + + @Override + @Deprecated + public LocationalSoundPacket toLocationalSoundPacket(Position position) { + if (position instanceof PositionImpl) { + return new LocationalSoundPacketImpl(new LocationSoundPacket(sender, sender, ((PositionImpl) position).getPosition(), packet.getData(), packet.getSequenceNumber(), Utils.getDefaultDistance(), null)); + } else { + throw new IllegalArgumentException("position is not an instance of PositionImpl"); + } + } + + @Override + @Deprecated + public StaticSoundPacket toStaticSoundPacket() { + return new StaticSoundPacketImpl(new GroupSoundPacket(sender, sender, packet.getData(), packet.getSequenceNumber(), null)); + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/SoundPacketImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/SoundPacketImpl.java similarity index 64% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/SoundPacketImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/SoundPacketImpl.java index f9df157..b2fb157 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/SoundPacketImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/SoundPacketImpl.java @@ -1,9 +1,3 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.packets; import de.maxhenkel.voicechat.api.Position; @@ -12,53 +6,50 @@ import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; import de.maxhenkel.voicechat.api.packets.SoundPacket; import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; import de.maxhenkel.voicechat.plugins.impl.PositionImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.EntitySoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.LocationalSoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.StaticSoundPacketImpl; import de.maxhenkel.voicechat.voice.common.GroupSoundPacket; import de.maxhenkel.voicechat.voice.common.LocationSoundPacket; import de.maxhenkel.voicechat.voice.common.PlayerSoundPacket; -import de.maxhenkel.voicechat.voice.common.SoundPacket; import de.maxhenkel.voicechat.voice.common.Utils; -import java.util.UUID; + import javax.annotation.Nullable; +import java.util.UUID; -public class SoundPacketImpl -implements de.maxhenkel.voicechat.api.packets.SoundPacket { - private final SoundPacket packet; +public class SoundPacketImpl implements SoundPacket { - public SoundPacketImpl(SoundPacket packet) { + private final de.maxhenkel.voicechat.voice.common.SoundPacket packet; + + public SoundPacketImpl(de.maxhenkel.voicechat.voice.common.SoundPacket packet) { this.packet = packet; } @Override public UUID getChannelId() { - return this.packet.getChannelId(); + return packet.getChannelId(); } @Override public UUID getSender() { - return this.packet.getSender(); + return packet.getSender(); } @Override public byte[] getOpusEncodedData() { - return this.packet.getData(); + return packet.getData(); } @Override public long getSequenceNumber() { - return this.packet.getSequenceNumber(); + return packet.getSequenceNumber(); } - @Override @Nullable + @Override public String getCategory() { - return this.packet.getCategory(); + return packet.getCategory(); } - public SoundPacket getPacket() { - return this.packet; + public de.maxhenkel.voicechat.voice.common.SoundPacket getPacket() { + return packet; } @Override @@ -78,34 +69,34 @@ implements de.maxhenkel.voicechat.api.packets.SoundPacket { @Override public EntitySoundPacket toEntitySoundPacket(UUID entityUuid, boolean whispering) { - return new EntitySoundPacketImpl(new PlayerSoundPacket(this.packet.getChannelId(), entityUuid, this.packet.getData(), this.packet.getSequenceNumber(), whispering, this.getDistance(), null)); + return new EntitySoundPacketImpl(new PlayerSoundPacket(packet.getChannelId(), entityUuid, packet.getData(), packet.getSequenceNumber(), whispering, getDistance(), null)); } @Override public LocationalSoundPacket toLocationalSoundPacket(Position position) { if (position instanceof PositionImpl) { - return new LocationalSoundPacketImpl(new LocationSoundPacket(this.packet.getChannelId(), this.packet.getSender(), ((PositionImpl)position).getPosition(), this.packet.getData(), this.packet.getSequenceNumber(), this.getDistance(), null)); + return new LocationalSoundPacketImpl(new LocationSoundPacket(packet.getChannelId(), packet.getSender(), ((PositionImpl) position).getPosition(), packet.getData(), packet.getSequenceNumber(), getDistance(), null)); + } else { + throw new IllegalArgumentException("position is not an instance of PositionImpl"); } - throw new IllegalArgumentException("position is not an instance of PositionImpl"); } private float getDistance() { if (this instanceof EntitySoundPacket) { - return ((EntitySoundPacket)((Object)this)).getDistance(); - } - if (this instanceof LocationalSoundPacket) { - return ((LocationalSoundPacket)((Object)this)).getDistance(); + return ((EntitySoundPacket) this).getDistance(); + } else if (this instanceof LocationalSoundPacket) { + return ((LocationalSoundPacket) this).getDistance(); } return Utils.getDefaultDistance(); } @Override public StaticSoundPacket toStaticSoundPacket() { - return new StaticSoundPacketImpl(new GroupSoundPacket(this.packet.getChannelId(), this.packet.getSender(), this.packet.getData(), this.packet.getSequenceNumber(), null)); + return new StaticSoundPacketImpl(new GroupSoundPacket(packet.getChannelId(), packet.getSender(), packet.getData(), packet.getSequenceNumber(), null)); } - public static abstract class BuilderImpl, P extends de.maxhenkel.voicechat.api.packets.SoundPacket> - implements SoundPacket.Builder { + public abstract static class BuilderImpl, P extends SoundPacket> implements Builder { + protected UUID channelId; protected UUID sender; protected byte[] opusEncodedData; @@ -135,32 +126,32 @@ implements de.maxhenkel.voicechat.api.packets.SoundPacket { throw new IllegalArgumentException("channelId can't be null"); } this.channelId = channelId; - return (T)this; + return (T) this; } @Override public T sender(UUID sender) { this.sender = sender; - return (T)this; + return (T) this; } @Override public T opusEncodedData(byte[] data) { this.opusEncodedData = data; - return (T)this; + return (T) this; } @Override public T sequenceNumber(long sequenceNumber) { this.sequenceNumber = sequenceNumber; - return (T)this; + return (T) this; } @Override public T category(@Nullable String category) { this.category = category; - return (T)this; + return (T) this; } } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/StaticSoundPacketImpl.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/StaticSoundPacketImpl.java similarity index 60% rename from source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/StaticSoundPacketImpl.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/StaticSoundPacketImpl.java index efa1541..c901529 100644 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/StaticSoundPacketImpl.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/plugins/impl/packets/StaticSoundPacketImpl.java @@ -1,27 +1,19 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.plugins.impl.packets; import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; -import de.maxhenkel.voicechat.plugins.impl.packets.SoundPacketImpl; import de.maxhenkel.voicechat.voice.common.GroupSoundPacket; -import java.util.UUID; -import javax.annotation.Nullable; -public class StaticSoundPacketImpl -extends SoundPacketImpl -implements StaticSoundPacket { +import javax.annotation.Nullable; +import java.util.UUID; + +public class StaticSoundPacketImpl extends SoundPacketImpl implements StaticSoundPacket { + public StaticSoundPacketImpl(GroupSoundPacket packet) { super(packet); } - public static class BuilderImpl - extends SoundPacketImpl.BuilderImpl - implements StaticSoundPacket.Builder { + public static class BuilderImpl extends SoundPacketImpl.BuilderImpl implements StaticSoundPacket.Builder { + public BuilderImpl(SoundPacketImpl soundPacket) { super(soundPacket); } @@ -32,8 +24,9 @@ implements StaticSoundPacket { @Override public StaticSoundPacket build() { - return new StaticSoundPacketImpl(new GroupSoundPacket(this.channelId, this.sender, this.opusEncodedData, this.sequenceNumber, this.category)); + return new StaticSoundPacketImpl(new GroupSoundPacket(channelId, sender, opusEncodedData, sequenceNumber, category)); } - } -} + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/util/FriendlyByteBuf.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/util/FriendlyByteBuf.java similarity index 52% rename from source/decompiled/de/maxhenkel/voicechat/util/FriendlyByteBuf.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/util/FriendlyByteBuf.java index e44d97b..841fb20 100644 --- a/source/decompiled/de/maxhenkel/voicechat/util/FriendlyByteBuf.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/util/FriendlyByteBuf.java @@ -1,22 +1,10 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * io.netty.buffer.ByteBuf - * io.netty.buffer.ByteBufAllocator - * io.netty.buffer.Unpooled - * io.netty.handler.codec.DecoderException - * io.netty.handler.codec.EncoderException - * io.netty.util.ByteProcessor - */ package de.maxhenkel.voicechat.util; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; +import io.netty.buffer.*; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.EncoderException; import io.netty.util.ByteProcessor; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -29,12 +17,12 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.UUID; -public class FriendlyByteBuf -extends ByteBuf { +public class FriendlyByteBuf extends ByteBuf { + private final ByteBuf buf; public FriendlyByteBuf(ByteBuf byteBuf) { - this.buf = byteBuf; + buf = byteBuf; } public FriendlyByteBuf() { @@ -42,825 +30,1014 @@ extends ByteBuf { } public ByteBuf getUnderlyingByteBuf() { - return this.buf; + return buf; } public FriendlyByteBuf writeByteArray(byte[] bs) { - this.writeVarInt(bs.length); - this.writeBytes(bs); + writeVarInt(bs.length); + writeBytes(bs); return this; } public byte[] readByteArray() { - return this.readByteArray(this.readableBytes()); + return readByteArray(readableBytes()); } public byte[] readByteArray(int i) { - int j = this.readVarInt(); + int j = readVarInt(); if (j > i) { throw new DecoderException("ByteArray with size " + j + " is bigger than allowed " + i); + } else { + byte[] bs = new byte[j]; + readBytes(bs); + return bs; } - byte[] bs = new byte[j]; - this.readBytes(bs); - return bs; } public int readVarInt() { - byte b; int i = 0; int j = 0; + + byte b; do { - b = this.readByte(); - i |= (b & 0x7F) << j++ * 7; - if (j <= 5) continue; - throw new RuntimeException("VarInt too big"); - } while ((b & 0x80) == 128); + b = readByte(); + i |= (b & 127) << j++ * 7; + if (j > 5) { + throw new RuntimeException("VarInt too big"); + } + } while ((b & 128) == 128); + return i; } public FriendlyByteBuf writeUUID(UUID uUID) { - this.writeLong(uUID.getMostSignificantBits()); - this.writeLong(uUID.getLeastSignificantBits()); + writeLong(uUID.getMostSignificantBits()); + writeLong(uUID.getLeastSignificantBits()); return this; } public UUID readUUID() { - return new UUID(this.readLong(), this.readLong()); + return new UUID(readLong(), readLong()); } public FriendlyByteBuf writeVarInt(int i) { - while ((i & 0xFFFFFF80) != 0) { - this.writeByte(i & 0x7F | 0x80); + while ((i & -128) != 0) { + writeByte(i & 127 | 128); i >>>= 7; } - this.writeByte(i); + + writeByte(i); return this; } public String readUtf(int i) { - int j = this.readVarInt(); + int j = readVarInt(); if (j > i * 4) { throw new DecoderException("The received encoded string buffer length is longer than maximum allowed (" + j + " > " + i * 4 + ')'); - } - if (j < 0) { + } else if (j < 0) { throw new DecoderException("The received encoded string buffer length is less than zero! Weird string!"); + } else { + String string = toString(readerIndex(), j, StandardCharsets.UTF_8); + readerIndex(readerIndex() + j); + if (string.length() > i) { + throw new DecoderException("The received string length is longer than maximum allowed (" + j + " > " + i + ')'); + } else { + return string; + } } - String string = this.toString(this.readerIndex(), j, StandardCharsets.UTF_8); - this.readerIndex(this.readerIndex() + j); - if (string.length() > i) { - throw new DecoderException("The received string length is longer than maximum allowed (" + j + " > " + i + ')'); - } - return string; } public FriendlyByteBuf writeUtf(String string, int i) { byte[] bs = string.getBytes(StandardCharsets.UTF_8); if (bs.length > i) { throw new EncoderException("String too big (was " + bs.length + " bytes encoded, max " + i + ')'); + } else { + writeVarInt(bs.length); + writeBytes(bs); + return this; } - this.writeVarInt(bs.length); - this.writeBytes(bs); - return this; } public String readUtf() { - return this.readUtf(Short.MAX_VALUE); + return readUtf(32767); } public FriendlyByteBuf writeUtf(String string) { - return this.writeUtf(string, Short.MAX_VALUE); + return writeUtf(string, 32767); } + @Override public int capacity() { - return this.buf.capacity(); + return buf.capacity(); } + @Override public ByteBuf capacity(int i) { - return this.buf.capacity(i); + return buf.capacity(i); } + @Override public int maxCapacity() { - return this.buf.maxCapacity(); + return buf.maxCapacity(); } + @Override public ByteBufAllocator alloc() { - return this.buf.alloc(); + return buf.alloc(); } + @Override public ByteOrder order() { - return this.buf.order(); + return buf.order(); } + @Override public ByteBuf order(ByteOrder byteOrder) { - return this.buf.order(byteOrder); + return buf.order(byteOrder); } + @Override public ByteBuf unwrap() { - return this.buf.unwrap(); + return buf.unwrap(); } + @Override public boolean isDirect() { - return this.buf.isDirect(); + return buf.isDirect(); } + @Override public boolean isReadOnly() { - return this.buf.isReadOnly(); + return buf.isReadOnly(); } + @Override public ByteBuf asReadOnly() { - return this.buf.asReadOnly(); + return buf.asReadOnly(); } + @Override public int readerIndex() { - return this.buf.readerIndex(); + return buf.readerIndex(); } + @Override public ByteBuf readerIndex(int i) { - return this.buf.readerIndex(i); + return buf.readerIndex(i); } + @Override public int writerIndex() { - return this.buf.writerIndex(); + return buf.writerIndex(); } + @Override public ByteBuf writerIndex(int i) { - return this.buf.writerIndex(i); + return buf.writerIndex(i); } + @Override public ByteBuf setIndex(int i, int j) { - return this.buf.setIndex(i, j); + return buf.setIndex(i, j); } + @Override public int readableBytes() { - return this.buf.readableBytes(); + return buf.readableBytes(); } + @Override public int writableBytes() { - return this.buf.writableBytes(); + return buf.writableBytes(); } + @Override public int maxWritableBytes() { - return this.buf.maxWritableBytes(); + return buf.maxWritableBytes(); } + @Override public boolean isReadable() { - return this.buf.isReadable(); + return buf.isReadable(); } + @Override public boolean isReadable(int i) { - return this.buf.isReadable(i); + return buf.isReadable(i); } + @Override public boolean isWritable() { - return this.buf.isWritable(); + return buf.isWritable(); } + @Override public boolean isWritable(int i) { - return this.buf.isWritable(i); + return buf.isWritable(i); } + @Override public ByteBuf clear() { - return this.buf.clear(); + return buf.clear(); } + @Override public ByteBuf markReaderIndex() { - return this.buf.markReaderIndex(); + return buf.markReaderIndex(); } + @Override public ByteBuf resetReaderIndex() { - return this.buf.resetReaderIndex(); + return buf.resetReaderIndex(); } + @Override public ByteBuf markWriterIndex() { - return this.buf.markWriterIndex(); + return buf.markWriterIndex(); } + @Override public ByteBuf resetWriterIndex() { - return this.buf.resetWriterIndex(); + return buf.resetWriterIndex(); } + @Override public ByteBuf discardReadBytes() { - return this.buf.discardReadBytes(); + return buf.discardReadBytes(); } + @Override public ByteBuf discardSomeReadBytes() { - return this.buf.discardSomeReadBytes(); + return buf.discardSomeReadBytes(); } + @Override public ByteBuf ensureWritable(int i) { - return this.buf.ensureWritable(i); + return buf.ensureWritable(i); } + @Override public int ensureWritable(int i, boolean bl) { - return this.buf.ensureWritable(i, bl); + return buf.ensureWritable(i, bl); } + @Override public boolean getBoolean(int i) { - return this.buf.getBoolean(i); + return buf.getBoolean(i); } + @Override public byte getByte(int i) { - return this.buf.getByte(i); + return buf.getByte(i); } + @Override public short getUnsignedByte(int i) { - return this.buf.getUnsignedByte(i); + return buf.getUnsignedByte(i); } + @Override public short getShort(int i) { - return this.buf.getShort(i); + return buf.getShort(i); } + @Override public short getShortLE(int i) { - return this.buf.getShortLE(i); + return buf.getShortLE(i); } + @Override public int getUnsignedShort(int i) { - return this.buf.getUnsignedShort(i); + return buf.getUnsignedShort(i); } + @Override public int getUnsignedShortLE(int i) { - return this.buf.getUnsignedShortLE(i); + return buf.getUnsignedShortLE(i); } + @Override public int getMedium(int i) { - return this.buf.getMedium(i); + return buf.getMedium(i); } + @Override public int getMediumLE(int i) { - return this.buf.getMediumLE(i); + return buf.getMediumLE(i); } + @Override public int getUnsignedMedium(int i) { - return this.buf.getUnsignedMedium(i); + return buf.getUnsignedMedium(i); } + @Override public int getUnsignedMediumLE(int i) { - return this.buf.getUnsignedMediumLE(i); + return buf.getUnsignedMediumLE(i); } + @Override public int getInt(int i) { - return this.buf.getInt(i); + return buf.getInt(i); } + @Override public int getIntLE(int i) { - return this.buf.getIntLE(i); + return buf.getIntLE(i); } + @Override public long getUnsignedInt(int i) { - return this.buf.getUnsignedInt(i); + return buf.getUnsignedInt(i); } + @Override public long getUnsignedIntLE(int i) { - return this.buf.getUnsignedIntLE(i); + return buf.getUnsignedIntLE(i); } + @Override public long getLong(int i) { - return this.buf.getLong(i); + return buf.getLong(i); } + @Override public long getLongLE(int i) { - return this.buf.getLongLE(i); + return buf.getLongLE(i); } + @Override public char getChar(int i) { - return this.buf.getChar(i); + return buf.getChar(i); } + @Override public float getFloat(int i) { - return this.buf.getFloat(i); + return buf.getFloat(i); } + @Override public double getDouble(int i) { - return this.buf.getDouble(i); + return buf.getDouble(i); } + @Override public ByteBuf getBytes(int i, ByteBuf byteBuf) { - return this.buf.getBytes(i, byteBuf); + return buf.getBytes(i, byteBuf); } + @Override public ByteBuf getBytes(int i, ByteBuf byteBuf, int j) { - return this.buf.getBytes(i, byteBuf, j); + return buf.getBytes(i, byteBuf, j); } + @Override public ByteBuf getBytes(int i, ByteBuf byteBuf, int j, int k) { - return this.buf.getBytes(i, byteBuf, j, k); + return buf.getBytes(i, byteBuf, j, k); } + @Override public ByteBuf getBytes(int i, byte[] bs) { - return this.buf.getBytes(i, bs); + return buf.getBytes(i, bs); } + @Override public ByteBuf getBytes(int i, byte[] bs, int j, int k) { - return this.buf.getBytes(i, bs, j, k); + return buf.getBytes(i, bs, j, k); } + @Override public ByteBuf getBytes(int i, ByteBuffer byteBuffer) { - return this.buf.getBytes(i, byteBuffer); + return buf.getBytes(i, byteBuffer); } + @Override public ByteBuf getBytes(int i, OutputStream outputStream, int j) throws IOException { - return this.buf.getBytes(i, outputStream, j); + return buf.getBytes(i, outputStream, j); } + @Override public int getBytes(int i, GatheringByteChannel gatheringByteChannel, int j) throws IOException { - return this.buf.getBytes(i, gatheringByteChannel, j); + return buf.getBytes(i, gatheringByteChannel, j); } + @Override public int getBytes(int i, FileChannel fileChannel, long l, int j) throws IOException { - return this.buf.getBytes(i, fileChannel, l, j); + return buf.getBytes(i, fileChannel, l, j); } + @Override public CharSequence getCharSequence(int i, int j, Charset charset) { - return this.buf.getCharSequence(i, j, charset); + return buf.getCharSequence(i, j, charset); } + @Override public ByteBuf setBoolean(int i, boolean bl) { - return this.buf.setBoolean(i, bl); + return buf.setBoolean(i, bl); } + @Override public ByteBuf setByte(int i, int j) { - return this.buf.setByte(i, j); + return buf.setByte(i, j); } + @Override public ByteBuf setShort(int i, int j) { - return this.buf.setShort(i, j); + return buf.setShort(i, j); } + @Override public ByteBuf setShortLE(int i, int j) { - return this.buf.setShortLE(i, j); + return buf.setShortLE(i, j); } + @Override public ByteBuf setMedium(int i, int j) { - return this.buf.setMedium(i, j); + return buf.setMedium(i, j); } + @Override public ByteBuf setMediumLE(int i, int j) { - return this.buf.setMediumLE(i, j); + return buf.setMediumLE(i, j); } + @Override public ByteBuf setInt(int i, int j) { - return this.buf.setInt(i, j); + return buf.setInt(i, j); } + @Override public ByteBuf setIntLE(int i, int j) { - return this.buf.setIntLE(i, j); + return buf.setIntLE(i, j); } + @Override public ByteBuf setLong(int i, long l) { - return this.buf.setLong(i, l); + return buf.setLong(i, l); } + @Override public ByteBuf setLongLE(int i, long l) { - return this.buf.setLongLE(i, l); + return buf.setLongLE(i, l); } + @Override public ByteBuf setChar(int i, int j) { - return this.buf.setChar(i, j); + return buf.setChar(i, j); } + @Override public ByteBuf setFloat(int i, float f) { - return this.buf.setFloat(i, f); + return buf.setFloat(i, f); } + @Override public ByteBuf setDouble(int i, double d) { - return this.buf.setDouble(i, d); + return buf.setDouble(i, d); } + @Override public ByteBuf setBytes(int i, ByteBuf byteBuf) { - return this.buf.setBytes(i, byteBuf); + return buf.setBytes(i, byteBuf); } + @Override public ByteBuf setBytes(int i, ByteBuf byteBuf, int j) { - return this.buf.setBytes(i, byteBuf, j); + return buf.setBytes(i, byteBuf, j); } + @Override public ByteBuf setBytes(int i, ByteBuf byteBuf, int j, int k) { - return this.buf.setBytes(i, byteBuf, j, k); + return buf.setBytes(i, byteBuf, j, k); } + @Override public ByteBuf setBytes(int i, byte[] bs) { - return this.buf.setBytes(i, bs); + return buf.setBytes(i, bs); } + @Override public ByteBuf setBytes(int i, byte[] bs, int j, int k) { - return this.buf.setBytes(i, bs, j, k); + return buf.setBytes(i, bs, j, k); } + @Override public ByteBuf setBytes(int i, ByteBuffer byteBuffer) { - return this.buf.setBytes(i, byteBuffer); + return buf.setBytes(i, byteBuffer); } + @Override public int setBytes(int i, InputStream inputStream, int j) throws IOException { - return this.buf.setBytes(i, inputStream, j); + return buf.setBytes(i, inputStream, j); } + @Override public int setBytes(int i, ScatteringByteChannel scatteringByteChannel, int j) throws IOException { - return this.buf.setBytes(i, scatteringByteChannel, j); + return buf.setBytes(i, scatteringByteChannel, j); } + @Override public int setBytes(int i, FileChannel fileChannel, long l, int j) throws IOException { - return this.buf.setBytes(i, fileChannel, l, j); + return buf.setBytes(i, fileChannel, l, j); } + @Override public ByteBuf setZero(int i, int j) { - return this.buf.setZero(i, j); + return buf.setZero(i, j); } + @Override public int setCharSequence(int i, CharSequence charSequence, Charset charset) { - return this.buf.setCharSequence(i, charSequence, charset); + return buf.setCharSequence(i, charSequence, charset); } + @Override public boolean readBoolean() { - return this.buf.readBoolean(); + return buf.readBoolean(); } + @Override public byte readByte() { - return this.buf.readByte(); + return buf.readByte(); } + @Override public short readUnsignedByte() { - return this.buf.readUnsignedByte(); + return buf.readUnsignedByte(); } + @Override public short readShort() { - return this.buf.readShort(); + return buf.readShort(); } + @Override public short readShortLE() { - return this.buf.readShortLE(); + return buf.readShortLE(); } + @Override public int readUnsignedShort() { - return this.buf.readUnsignedShort(); + return buf.readUnsignedShort(); } + @Override public int readUnsignedShortLE() { - return this.buf.readUnsignedShortLE(); + return buf.readUnsignedShortLE(); } + @Override public int readMedium() { - return this.buf.readMedium(); + return buf.readMedium(); } + @Override public int readMediumLE() { - return this.buf.readMediumLE(); + return buf.readMediumLE(); } + @Override public int readUnsignedMedium() { - return this.buf.readUnsignedMedium(); + return buf.readUnsignedMedium(); } + @Override public int readUnsignedMediumLE() { - return this.buf.readUnsignedMediumLE(); + return buf.readUnsignedMediumLE(); } + @Override public int readInt() { - return this.buf.readInt(); + return buf.readInt(); } + @Override public int readIntLE() { - return this.buf.readIntLE(); + return buf.readIntLE(); } + @Override public long readUnsignedInt() { - return this.buf.readUnsignedInt(); + return buf.readUnsignedInt(); } + @Override public long readUnsignedIntLE() { - return this.buf.readUnsignedIntLE(); + return buf.readUnsignedIntLE(); } + @Override public long readLong() { - return this.buf.readLong(); + return buf.readLong(); } + @Override public long readLongLE() { - return this.buf.readLongLE(); + return buf.readLongLE(); } + @Override public char readChar() { - return this.buf.readChar(); + return buf.readChar(); } + @Override public float readFloat() { - return this.buf.readFloat(); + return buf.readFloat(); } + @Override public double readDouble() { - return this.buf.readDouble(); + return buf.readDouble(); } + @Override public ByteBuf readBytes(int i) { - return this.buf.readBytes(i); + return buf.readBytes(i); } + @Override public ByteBuf readSlice(int i) { - return this.buf.readSlice(i); + return buf.readSlice(i); } + @Override public ByteBuf readRetainedSlice(int i) { - return this.buf.readRetainedSlice(i); + return buf.readRetainedSlice(i); } + @Override public ByteBuf readBytes(ByteBuf byteBuf) { - return this.buf.readBytes(byteBuf); + return buf.readBytes(byteBuf); } + @Override public ByteBuf readBytes(ByteBuf byteBuf, int i) { - return this.buf.readBytes(byteBuf, i); + return buf.readBytes(byteBuf, i); } + @Override public ByteBuf readBytes(ByteBuf byteBuf, int i, int j) { - return this.buf.readBytes(byteBuf, i, j); + return buf.readBytes(byteBuf, i, j); } + @Override public ByteBuf readBytes(byte[] bs) { - return this.buf.readBytes(bs); + return buf.readBytes(bs); } + @Override public ByteBuf readBytes(byte[] bs, int i, int j) { - return this.buf.readBytes(bs, i, j); + return buf.readBytes(bs, i, j); } + @Override public ByteBuf readBytes(ByteBuffer byteBuffer) { - return this.buf.readBytes(byteBuffer); + return buf.readBytes(byteBuffer); } + @Override public ByteBuf readBytes(OutputStream outputStream, int i) throws IOException { - return this.buf.readBytes(outputStream, i); + return buf.readBytes(outputStream, i); } + @Override public int readBytes(GatheringByteChannel gatheringByteChannel, int i) throws IOException { - return this.buf.readBytes(gatheringByteChannel, i); + return buf.readBytes(gatheringByteChannel, i); } + @Override public CharSequence readCharSequence(int i, Charset charset) { - return this.buf.readCharSequence(i, charset); + return buf.readCharSequence(i, charset); } + @Override public int readBytes(FileChannel fileChannel, long l, int i) throws IOException { - return this.buf.readBytes(fileChannel, l, i); + return buf.readBytes(fileChannel, l, i); } + @Override public ByteBuf skipBytes(int i) { - return this.buf.skipBytes(i); + return buf.skipBytes(i); } + @Override public ByteBuf writeBoolean(boolean bl) { - return this.buf.writeBoolean(bl); + return buf.writeBoolean(bl); } + @Override public ByteBuf writeByte(int i) { - return this.buf.writeByte(i); + return buf.writeByte(i); } + @Override public ByteBuf writeShort(int i) { - return this.buf.writeShort(i); + return buf.writeShort(i); } + @Override public ByteBuf writeShortLE(int i) { - return this.buf.writeShortLE(i); + return buf.writeShortLE(i); } + @Override public ByteBuf writeMedium(int i) { - return this.buf.writeMedium(i); + return buf.writeMedium(i); } + @Override public ByteBuf writeMediumLE(int i) { - return this.buf.writeMediumLE(i); + return buf.writeMediumLE(i); } + @Override public ByteBuf writeInt(int i) { - return this.buf.writeInt(i); + return buf.writeInt(i); } + @Override public ByteBuf writeIntLE(int i) { - return this.buf.writeIntLE(i); + return buf.writeIntLE(i); } + @Override public ByteBuf writeLong(long l) { - return this.buf.writeLong(l); + return buf.writeLong(l); } + @Override public ByteBuf writeLongLE(long l) { - return this.buf.writeLongLE(l); + return buf.writeLongLE(l); } + @Override public ByteBuf writeChar(int i) { - return this.buf.writeChar(i); + return buf.writeChar(i); } + @Override public ByteBuf writeFloat(float f) { - return this.buf.writeFloat(f); + return buf.writeFloat(f); } + @Override public ByteBuf writeDouble(double d) { - return this.buf.writeDouble(d); + return buf.writeDouble(d); } + @Override public ByteBuf writeBytes(ByteBuf byteBuf) { - return this.buf.writeBytes(byteBuf); + return buf.writeBytes(byteBuf); } + @Override public ByteBuf writeBytes(ByteBuf byteBuf, int i) { - return this.buf.writeBytes(byteBuf, i); + return buf.writeBytes(byteBuf, i); } + @Override public ByteBuf writeBytes(ByteBuf byteBuf, int i, int j) { - return this.buf.writeBytes(byteBuf, i, j); + return buf.writeBytes(byteBuf, i, j); } + @Override public ByteBuf writeBytes(byte[] bs) { - return this.buf.writeBytes(bs); + return buf.writeBytes(bs); } + @Override public ByteBuf writeBytes(byte[] bs, int i, int j) { - return this.buf.writeBytes(bs, i, j); + return buf.writeBytes(bs, i, j); } + @Override public ByteBuf writeBytes(ByteBuffer byteBuffer) { - return this.buf.writeBytes(byteBuffer); + return buf.writeBytes(byteBuffer); } + @Override public int writeBytes(InputStream inputStream, int i) throws IOException { - return this.buf.writeBytes(inputStream, i); + return buf.writeBytes(inputStream, i); } + @Override public int writeBytes(ScatteringByteChannel scatteringByteChannel, int i) throws IOException { - return this.buf.writeBytes(scatteringByteChannel, i); + return buf.writeBytes(scatteringByteChannel, i); } + @Override public int writeBytes(FileChannel fileChannel, long l, int i) throws IOException { - return this.buf.writeBytes(fileChannel, l, i); + return buf.writeBytes(fileChannel, l, i); } + @Override public ByteBuf writeZero(int i) { - return this.buf.writeZero(i); + return buf.writeZero(i); } + @Override public int writeCharSequence(CharSequence charSequence, Charset charset) { - return this.buf.writeCharSequence(charSequence, charset); + return buf.writeCharSequence(charSequence, charset); } + @Override public int indexOf(int i, int j, byte b) { - return this.buf.indexOf(i, j, b); + return buf.indexOf(i, j, b); } + @Override public int bytesBefore(byte b) { - return this.buf.bytesBefore(b); + return buf.bytesBefore(b); } + @Override public int bytesBefore(int i, byte b) { - return this.buf.bytesBefore(i, b); + return buf.bytesBefore(i, b); } + @Override public int bytesBefore(int i, int j, byte b) { - return this.buf.bytesBefore(i, j, b); + return buf.bytesBefore(i, j, b); } + @Override public int forEachByte(ByteProcessor byteProcessor) { - return this.buf.forEachByte(byteProcessor); + return buf.forEachByte(byteProcessor); } + @Override public int forEachByte(int i, int j, ByteProcessor byteProcessor) { - return this.buf.forEachByte(i, j, byteProcessor); + return buf.forEachByte(i, j, byteProcessor); } + @Override public int forEachByteDesc(ByteProcessor byteProcessor) { - return this.buf.forEachByteDesc(byteProcessor); + return buf.forEachByteDesc(byteProcessor); } + @Override public int forEachByteDesc(int i, int j, ByteProcessor byteProcessor) { - return this.buf.forEachByteDesc(i, j, byteProcessor); + return buf.forEachByteDesc(i, j, byteProcessor); } + @Override public ByteBuf copy() { - return this.buf.copy(); + return buf.copy(); } + @Override public ByteBuf copy(int i, int j) { - return this.buf.copy(i, j); + return buf.copy(i, j); } + @Override public ByteBuf slice() { - return this.buf.slice(); + return buf.slice(); } + @Override public ByteBuf retainedSlice() { - return this.buf.retainedSlice(); + return buf.retainedSlice(); } + @Override public ByteBuf slice(int i, int j) { - return this.buf.slice(i, j); + return buf.slice(i, j); } + @Override public ByteBuf retainedSlice(int i, int j) { - return this.buf.retainedSlice(i, j); + return buf.retainedSlice(i, j); } + @Override public ByteBuf duplicate() { - return this.buf.duplicate(); + return buf.duplicate(); } + @Override public ByteBuf retainedDuplicate() { - return this.buf.retainedDuplicate(); + return buf.retainedDuplicate(); } + @Override public int nioBufferCount() { - return this.buf.nioBufferCount(); + return buf.nioBufferCount(); } + @Override public ByteBuffer nioBuffer() { - return this.buf.nioBuffer(); + return buf.nioBuffer(); } + @Override public ByteBuffer nioBuffer(int i, int j) { - return this.buf.nioBuffer(i, j); + return buf.nioBuffer(i, j); } + @Override public ByteBuffer internalNioBuffer(int i, int j) { - return this.buf.internalNioBuffer(i, j); + return buf.internalNioBuffer(i, j); } + @Override public ByteBuffer[] nioBuffers() { - return this.buf.nioBuffers(); + return buf.nioBuffers(); } + @Override public ByteBuffer[] nioBuffers(int i, int j) { - return this.buf.nioBuffers(i, j); + return buf.nioBuffers(i, j); } + @Override public boolean hasArray() { - return this.buf.hasArray(); + return buf.hasArray(); } + @Override public byte[] array() { - return this.buf.array(); + return buf.array(); } + @Override public int arrayOffset() { - return this.buf.arrayOffset(); + return buf.arrayOffset(); } + @Override public boolean hasMemoryAddress() { - return this.buf.hasMemoryAddress(); + return buf.hasMemoryAddress(); } + @Override public long memoryAddress() { - return this.buf.memoryAddress(); + return buf.memoryAddress(); } + @Override public String toString(Charset charset) { - return this.buf.toString(charset); + return buf.toString(charset); } + @Override public String toString(int i, int j, Charset charset) { - return this.buf.toString(i, j, charset); + return buf.toString(i, j, charset); } + @Override public int hashCode() { - return this.buf.hashCode(); + return buf.hashCode(); } + @Override public boolean equals(Object object) { - return this.buf.equals(object); + return buf.equals(object); } + @Override public int compareTo(ByteBuf byteBuf) { - return this.buf.compareTo(byteBuf); + return buf.compareTo(byteBuf); } + @Override public String toString() { - return this.buf.toString(); + return buf.toString(); } + @Override public ByteBuf retain(int i) { - return this.buf.retain(i); + return buf.retain(i); } + @Override public ByteBuf retain() { - return this.buf.retain(); + return buf.retain(); } + @Override public ByteBuf touch() { - return this.buf.touch(); + return buf.touch(); } + @Override public ByteBuf touch(Object object) { - return this.buf.touch(object); + return buf.touch(object); } + @Override public int refCnt() { - return this.buf.refCnt(); + return buf.refCnt(); } + @Override public boolean release() { - return this.buf.release(); + return buf.release(); } + @Override public boolean release(int i) { - return this.buf.release(i); + return buf.release(i); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/util/Key.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/util/Key.java similarity index 76% rename from source/decompiled/de/maxhenkel/voicechat/util/Key.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/util/Key.java index d77a3e0..d9120f2 100644 --- a/source/decompiled/de/maxhenkel/voicechat/util/Key.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/util/Key.java @@ -1,12 +1,13 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.util; +import de.maxhenkel.voicechat.Voicechat; + public class Key { + private final String namespace; private final String value; + //TODO Validate allowed characters public Key(String namespace, String value) { this.namespace = namespace; this.value = value; @@ -17,7 +18,7 @@ public class Key { } public static Key of(String value) { - return new Key("voicechat", value); + return new Key(Voicechat.MODID, value); } public static Key parse(String value) { @@ -29,15 +30,16 @@ public class Key { } public String getNamespace() { - return this.namespace; + return namespace; } public String getValue() { - return this.value; + return value; } + @Override public String toString() { - return String.format("%s:%s", this.namespace, this.value); + return String.format("%s:%s", namespace, value); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/AudioUtils.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/AudioUtils.java similarity index 65% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/AudioUtils.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/AudioUtils.java index 6e6e3fe..e251a05 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/AudioUtils.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/AudioUtils.java @@ -1,6 +1,3 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.common; import java.nio.ByteBuffer; @@ -8,6 +5,7 @@ import java.nio.ByteOrder; import java.nio.ShortBuffer; public class AudioUtils { + public static final int MAX_OPUS_PAYLOAD_SIZE = 1275; public static short[] bytesToShorts(byte[] bytes) { @@ -30,36 +28,40 @@ public class AudioUtils { public static short[] floatsToShorts(float[] floats) { short[] shorts = new short[floats.length]; - for (int i = 0; i < floats.length; ++i) { - shorts[i] = Float.valueOf(floats[i]).shortValue(); + for (int i = 0; i < floats.length; i++) { + shorts[i] = ((Float) floats[i]).shortValue(); } return shorts; } public static float[] shortsToFloats(short[] shorts) { float[] floats = new float[shorts.length]; - for (int i = 0; i < shorts.length; ++i) { - floats[i] = Short.valueOf(shorts[i]).floatValue(); + for (int i = 0; i < shorts.length; i++) { + floats[i] = ((Short) shorts[i]).floatValue(); } return floats; } public static byte[] floatsToBytes(float[] floats) { byte[] bytes = new byte[floats.length * 2]; - for (int i = 0; i < floats.length; ++i) { - short x = Float.valueOf(floats[i]).shortValue(); - bytes[i * 2] = (byte)(x & 0xFF); - bytes[i * 2 + 1] = (byte)((x & 0xFF00) >> 8); + for (int i = 0; i < floats.length; i++) { + short x = ((Float) floats[i]).shortValue(); + bytes[i * 2] = (byte) (x & 0x00FF); + bytes[i * 2 + 1] = (byte) ((x & 0xFF00) >> 8); } return bytes; } public static float[] bytesToFloats(byte[] bytes) { float[] floats = new float[bytes.length / 2]; - for (int i = 0; i < bytes.length / 2; ++i) { - floats[i] = (bytes[i * 2 + 1] & 0x80) != 0 ? (float)(Short.MIN_VALUE + ((bytes[i * 2 + 1] & 0x7F) << 8) | bytes[i * 2] & 0xFF) : (float)(bytes[i * 2 + 1] << 8 & 0xFF00 | bytes[i * 2] & 0xFF); + for (int i = 0; i < bytes.length / 2; i++) { + if ((bytes[i * 2 + 1] & 0x80) != 0) { + floats[i] = Short.MIN_VALUE + ((bytes[i * 2 + 1] & 0x7F) << 8) | (bytes[i * 2] & 0xFF); + } else { + floats[i] = ((bytes[i * 2 + 1] << 8) & 0xFF00) | (bytes[i * 2] & 0xFF); + } } return floats; } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/AuthenticateAckPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/AuthenticateAckPacket.java similarity index 64% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/AuthenticateAckPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/AuthenticateAckPacket.java index 84130fb..567c4e2 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/AuthenticateAckPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/AuthenticateAckPacket.java @@ -1,13 +1,13 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.Packet; -public class AuthenticateAckPacket -implements Packet { +public class AuthenticateAckPacket implements Packet { + + public AuthenticateAckPacket() { + + } + @Override public AuthenticateAckPacket fromBytes(FriendlyByteBuf buf) { return new AuthenticateAckPacket(); @@ -15,6 +15,6 @@ implements Packet { @Override public void toBytes(FriendlyByteBuf buf) { + } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/AuthenticatePacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/AuthenticatePacket.java similarity index 69% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/AuthenticatePacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/AuthenticatePacket.java index aaa9d50..a050231 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/AuthenticatePacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/AuthenticatePacket.java @@ -1,15 +1,11 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.Packet; -import de.maxhenkel.voicechat.voice.common.Secret; + import java.util.UUID; -public class AuthenticatePacket -implements Packet { +public class AuthenticatePacket implements Packet { + private UUID playerUUID; private Secret secret; @@ -19,14 +15,15 @@ implements Packet { } public AuthenticatePacket() { + } public UUID getPlayerUUID() { - return this.playerUUID; + return playerUUID; } public Secret getSecret() { - return this.secret; + return secret; } @Override @@ -39,8 +36,7 @@ implements Packet { @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeUUID(this.playerUUID); - this.secret.toBytes(buf); + buf.writeUUID(playerUUID); + secret.toBytes(buf); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/ClientGroup.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/ClientGroup.java similarity index 66% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/ClientGroup.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/ClientGroup.java index 73fbb25..aa0ea62 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/ClientGroup.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/ClientGroup.java @@ -1,23 +1,22 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.api.Group; import de.maxhenkel.voicechat.plugins.impl.GroupImpl; import de.maxhenkel.voicechat.util.FriendlyByteBuf; + import java.util.Objects; import java.util.UUID; public class ClientGroup { + private final UUID id; private final String name; private final boolean hasPassword; private final boolean persistent; private final boolean hidden; - private final Group.Type type; + private final de.maxhenkel.voicechat.api.Group.Type type; - public ClientGroup(UUID id, String name, boolean hasPassword, boolean persistent, boolean hidden, Group.Type type) { + public ClientGroup(UUID id, String name, boolean hasPassword, boolean persistent, boolean hidden, de.maxhenkel.voicechat.api.Group.Type type) { this.id = id; this.name = name; this.hasPassword = hasPassword; @@ -27,27 +26,27 @@ public class ClientGroup { } public UUID getId() { - return this.id; + return id; } public String getName() { - return this.name; + return name; } public boolean hasPassword() { - return this.hasPassword; + return hasPassword; } public boolean isPersistent() { - return this.persistent; + return persistent; } public boolean isHidden() { - return this.hidden; + return hidden; } public Group.Type getType() { - return this.type; + return type; } public static ClientGroup fromBytes(FriendlyByteBuf buf) { @@ -55,23 +54,25 @@ public class ClientGroup { } public void toBytes(FriendlyByteBuf buf) { - buf.writeUUID(this.id); - buf.writeUtf(this.name, 512); - buf.writeBoolean(this.hasPassword); - buf.writeBoolean(this.persistent); - buf.writeBoolean(this.hidden); - buf.writeShort(GroupImpl.TypeImpl.toInt(this.type)); + buf.writeUUID(id); + buf.writeUtf(name, 512); + buf.writeBoolean(hasPassword); + buf.writeBoolean(persistent); + buf.writeBoolean(hidden); + buf.writeShort(GroupImpl.TypeImpl.toInt(type)); } + @Override public boolean equals(Object o) { if (this == o) { return true; } - if (o == null || this.getClass() != o.getClass()) { + if (o == null || getClass() != o.getClass()) { return false; } - ClientGroup group = (ClientGroup)o; - return Objects.equals(this.id, group.id); - } -} + ClientGroup group = (ClientGroup) o; + + return Objects.equals(id, group.id); + } +} \ No newline at end of file diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/ConnectionCheckAckPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/ConnectionCheckAckPacket.java similarity index 64% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/ConnectionCheckAckPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/ConnectionCheckAckPacket.java index ba645a7..4181a43 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/ConnectionCheckAckPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/ConnectionCheckAckPacket.java @@ -1,13 +1,13 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.Packet; -public class ConnectionCheckAckPacket -implements Packet { +public class ConnectionCheckAckPacket implements Packet { + + public ConnectionCheckAckPacket() { + + } + @Override public ConnectionCheckAckPacket fromBytes(FriendlyByteBuf buf) { return new ConnectionCheckAckPacket(); @@ -15,6 +15,6 @@ implements Packet { @Override public void toBytes(FriendlyByteBuf buf) { + } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/ConnectionCheckPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/ConnectionCheckPacket.java similarity index 64% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/ConnectionCheckPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/ConnectionCheckPacket.java index dc2aa61..46a3834 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/ConnectionCheckPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/ConnectionCheckPacket.java @@ -1,13 +1,13 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.Packet; -public class ConnectionCheckPacket -implements Packet { +public class ConnectionCheckPacket implements Packet { + + public ConnectionCheckPacket() { + + } + @Override public ConnectionCheckPacket fromBytes(FriendlyByteBuf buf) { return new ConnectionCheckPacket(); @@ -15,6 +15,6 @@ implements Packet { @Override public void toBytes(FriendlyByteBuf buf) { + } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/GroupSoundPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/GroupSoundPacket.java similarity index 57% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/GroupSoundPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/GroupSoundPacket.java index 1aa2505..13f2ddc 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/GroupSoundPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/GroupSoundPacket.java @@ -1,23 +1,18 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.SoundPacket; -import java.util.UUID; -import javax.annotation.Nullable; -public class GroupSoundPacket -extends SoundPacket { +import javax.annotation.Nullable; +import java.util.UUID; + +public class GroupSoundPacket extends SoundPacket { + public GroupSoundPacket(UUID channelId, UUID sender, byte[] data, long sequenceNumber, @Nullable String category) { super(channelId, sender, data, sequenceNumber, category); } public GroupSoundPacket() { + } @Override @@ -25,10 +20,11 @@ extends SoundPacket { GroupSoundPacket soundPacket = new GroupSoundPacket(); soundPacket.channelId = buf.readUUID(); soundPacket.sender = buf.readUUID(); - soundPacket.data = buf.readByteArray(1275); + soundPacket.data = buf.readByteArray(AudioUtils.MAX_OPUS_PAYLOAD_SIZE); soundPacket.sequenceNumber = buf.readLong(); + byte data = buf.readByte(); - if (this.hasFlag(data, (byte)2)) { + if (hasFlag(data, HAS_CATEGORY_MASK)) { soundPacket.category = buf.readUtf(16); } return soundPacket; @@ -36,18 +32,19 @@ extends SoundPacket { @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeUUID(this.channelId); - buf.writeUUID(this.sender); - buf.writeByteArray(this.data); - buf.writeLong(this.sequenceNumber); - byte data = 0; - if (this.category != null) { - data = this.setFlag(data, (byte)2); + buf.writeUUID(channelId); + buf.writeUUID(sender); + buf.writeByteArray(data); + buf.writeLong(sequenceNumber); + + byte data = 0b0; + if (category != null) { + data = setFlag(data, HAS_CATEGORY_MASK); } buf.writeByte(data); - if (this.category != null) { - buf.writeUtf(this.category, 16); + if (category != null) { + buf.writeUtf(category, 16); } } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/KeepAlivePacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/KeepAlivePacket.java similarity index 65% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/KeepAlivePacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/KeepAlivePacket.java index 5cadbd2..fe7ec27 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/KeepAlivePacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/KeepAlivePacket.java @@ -1,13 +1,13 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.Packet; -public class KeepAlivePacket -implements Packet { +public class KeepAlivePacket implements Packet { + + public KeepAlivePacket() { + + } + @Override public KeepAlivePacket fromBytes(FriendlyByteBuf buf) { return new KeepAlivePacket(); @@ -15,6 +15,6 @@ implements Packet { @Override public void toBytes(FriendlyByteBuf buf) { + } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/LocationSoundPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/LocationSoundPacket.java similarity index 59% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/LocationSoundPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/LocationSoundPacket.java index 8054941..02820fa 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/LocationSoundPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/LocationSoundPacket.java @@ -1,20 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.Location - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.SoundPacket; -import java.util.UUID; -import javax.annotation.Nullable; import org.bukkit.Location; -public class LocationSoundPacket -extends SoundPacket { +import javax.annotation.Nullable; +import java.util.UUID; + +public class LocationSoundPacket extends SoundPacket { + protected Location location; protected float distance; @@ -25,14 +18,15 @@ extends SoundPacket { } public LocationSoundPacket() { + } public Location getLocation() { - return this.location; + return location; } public float getDistance() { - return this.distance; + return distance; } @Override @@ -41,34 +35,36 @@ extends SoundPacket { soundPacket.channelId = buf.readUUID(); soundPacket.sender = buf.readUUID(); soundPacket.location = new Location(null, buf.readDouble(), buf.readDouble(), buf.readDouble()); - soundPacket.data = buf.readByteArray(1275); + soundPacket.data = buf.readByteArray(AudioUtils.MAX_OPUS_PAYLOAD_SIZE); soundPacket.sequenceNumber = buf.readLong(); soundPacket.distance = buf.readFloat(); + byte data = buf.readByte(); - if (this.hasFlag(data, (byte)2)) { + if (hasFlag(data, HAS_CATEGORY_MASK)) { soundPacket.category = buf.readUtf(16); } + return soundPacket; } @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeUUID(this.channelId); - buf.writeUUID(this.sender); - buf.writeDouble(this.location.getX()); - buf.writeDouble(this.location.getY()); - buf.writeDouble(this.location.getZ()); - buf.writeByteArray(this.data); - buf.writeLong(this.sequenceNumber); - buf.writeFloat(this.distance); - byte data = 0; - if (this.category != null) { - data = this.setFlag(data, (byte)2); + buf.writeUUID(channelId); + buf.writeUUID(sender); + buf.writeDouble(location.getX()); + buf.writeDouble(location.getY()); + buf.writeDouble(location.getZ()); + buf.writeByteArray(data); + buf.writeLong(sequenceNumber); + buf.writeFloat(distance); + + byte data = 0b0; + if (category != null) { + data = setFlag(data, HAS_CATEGORY_MASK); } buf.writeByte(data); - if (this.category != null) { - buf.writeUtf(this.category, 16); + if (category != null) { + buf.writeUtf(category, 16); } } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/MicPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/MicPacket.java similarity index 70% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/MicPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/MicPacket.java index 43e4096..6d3bae6 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/MicPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/MicPacket.java @@ -1,13 +1,9 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.Packet; -public class MicPacket -implements Packet { +public class MicPacket implements Packet { + private byte[] data; private boolean whispering; private long sequenceNumber; @@ -19,6 +15,7 @@ implements Packet { } public MicPacket() { + } @Override @@ -27,7 +24,7 @@ implements Packet { } public byte[] getData() { - return this.data; + return data; } public void setData(byte[] data) { @@ -35,17 +32,17 @@ implements Packet { } public long getSequenceNumber() { - return this.sequenceNumber; + return sequenceNumber; } public boolean isWhispering() { - return this.whispering; + return whispering; } @Override public MicPacket fromBytes(FriendlyByteBuf buf) { MicPacket soundPacket = new MicPacket(); - soundPacket.data = buf.readByteArray(1275); + soundPacket.data = buf.readByteArray(AudioUtils.MAX_OPUS_PAYLOAD_SIZE); soundPacket.sequenceNumber = buf.readLong(); soundPacket.whispering = buf.readBoolean(); return soundPacket; @@ -53,9 +50,8 @@ implements Packet { @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeByteArray(this.data); - buf.writeLong(this.sequenceNumber); - buf.writeBoolean(this.whispering); + buf.writeByteArray(data); + buf.writeLong(sequenceNumber); + buf.writeBoolean(whispering); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/NetworkMessage.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/NetworkMessage.java similarity index 64% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/NetworkMessage.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/NetworkMessage.java index 78537a8..4f5c2a1 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/NetworkMessage.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/NetworkMessage.java @@ -1,34 +1,19 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * io.netty.buffer.Unpooled - * io.netty.handler.codec.DecoderException - * javax.annotation.Nonnull - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.api.RawUdpPacket; import de.maxhenkel.voicechat.debug.PingHandler; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.AuthenticateAckPacket; -import de.maxhenkel.voicechat.voice.common.AuthenticatePacket; -import de.maxhenkel.voicechat.voice.common.ConnectionCheckAckPacket; -import de.maxhenkel.voicechat.voice.common.ConnectionCheckPacket; -import de.maxhenkel.voicechat.voice.common.GroupSoundPacket; -import de.maxhenkel.voicechat.voice.common.KeepAlivePacket; -import de.maxhenkel.voicechat.voice.common.LocationSoundPacket; -import de.maxhenkel.voicechat.voice.common.MicPacket; -import de.maxhenkel.voicechat.voice.common.Packet; -import de.maxhenkel.voicechat.voice.common.PingPacket; -import de.maxhenkel.voicechat.voice.common.PlayerSoundPacket; -import de.maxhenkel.voicechat.voice.common.Secret; import de.maxhenkel.voicechat.voice.server.ClientConnection; import de.maxhenkel.voicechat.voice.server.Server; import io.netty.buffer.Unpooled; import io.netty.handler.codec.DecoderException; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; import java.lang.reflect.InvocationTargetException; import java.net.SocketAddress; import java.security.InvalidAlgorithmParameterException; @@ -37,18 +22,14 @@ import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; import java.util.UUID; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; public class NetworkMessage { - public static final byte MAGIC_BYTE = -1; + + public static final byte MAGIC_BYTE = (byte) 0b11111111; + private final long timestamp; private Packet packet; private SocketAddress address; - private static final Map> packetRegistry = new HashMap>(); public NetworkMessage(long timestamp, Packet packet) { this(timestamp); @@ -66,27 +47,43 @@ public class NetworkMessage { @Nonnull public Packet getPacket() { - return this.packet; + return packet; } public long getTimestamp() { - return this.timestamp; + return timestamp; } public long getTTL() { - return this.packet.getTTL(); + return packet.getTTL(); } public SocketAddress getAddress() { - return this.address; + return address; + } + + private static final Map> packetRegistry; + + static { + packetRegistry = new HashMap<>(); + packetRegistry.put((byte) 0x1, MicPacket.class); + packetRegistry.put((byte) 0x2, PlayerSoundPacket.class); + packetRegistry.put((byte) 0x3, GroupSoundPacket.class); + packetRegistry.put((byte) 0x4, LocationSoundPacket.class); + packetRegistry.put((byte) 0x5, AuthenticatePacket.class); + packetRegistry.put((byte) 0x6, AuthenticateAckPacket.class); + packetRegistry.put((byte) 0x7, PingPacket.class); + packetRegistry.put((byte) 0x8, KeepAlivePacket.class); + packetRegistry.put((byte) 0x9, ConnectionCheckPacket.class); + packetRegistry.put((byte) 0xA, ConnectionCheckAckPacket.class); } @Nullable public static NetworkMessage readPacketServer(RawUdpPacket packet, Server server) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException { try { byte[] data = packet.getData(); - FriendlyByteBuf b = new FriendlyByteBuf(Unpooled.wrappedBuffer((byte[])data)); - if (b.readByte() != -1) { + FriendlyByteBuf b = new FriendlyByteBuf(Unpooled.wrappedBuffer(data)); + if (b.readByte() != MAGIC_BYTE) { Voicechat.LOGGER.debug("Received invalid packet from {}", packet.getSocketAddress()); return null; } @@ -95,12 +92,12 @@ public class NetworkMessage { if (PingHandler.onPacket(server, packet.getSocketAddress(), playerID, b)) { return null; } + // Ignore packets if they are not from a player that has a secret Voicechat.LOGGER.debug("Player {} does not have a secret", playerID); return null; } - return NetworkMessage.readFromBytes(packet.getSocketAddress(), server.getSecret(playerID), b.readByteArray(2048), packet.getTimestamp()); - } - catch (DecoderException | IndexOutOfBoundsException e) { + return readFromBytes(packet.getSocketAddress(), server.getSecret(playerID), b.readByteArray(Utils.MAX_VOICE_CHAT_PACKET_SIZE), packet.getTimestamp()); + } catch (DecoderException | IndexOutOfBoundsException e) { Voicechat.LOGGER.debug("Received invalid packet from {}", packet.getSocketAddress()); return null; } @@ -111,38 +108,42 @@ public class NetworkMessage { byte[] decrypt; try { decrypt = secret.decrypt(encryptedPayload); - } - catch (Exception e) { + } catch (Exception e) { + // Return null if the encryption fails due to a wrong secret Voicechat.LOGGER.debug("Failed to decrypt packet from {}", socketAddress); return null; } - FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.wrappedBuffer((byte[])decrypt)); + FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.wrappedBuffer(decrypt)); byte packetType = buffer.readByte(); Class packetClass = packetRegistry.get(packetType); if (packetClass == null) { Voicechat.LOGGER.debug("Got invalid packet ID {}", packetType); return null; } - Packet p = packetClass.getDeclaredConstructor(new Class[0]).newInstance(new Object[0]); + Packet> p = packetClass.getDeclaredConstructor().newInstance(); + NetworkMessage message = new NetworkMessage(timestamp); message.address = socketAddress; message.packet = p.fromBytes(buffer); + return message; } private static byte getPacketType(Packet packet) { for (Map.Entry> entry : packetRegistry.entrySet()) { - if (!packet.getClass().equals(entry.getValue())) continue; - return entry.getKey(); + if (packet.getClass().equals(entry.getValue())) { + return entry.getKey(); + } } return -1; } public byte[] writeServer(Server server, ClientConnection connection) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { - byte[] payload = this.write(server.getSecret(connection.getPlayerUUID())); - FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer((int)(1 + payload.length))); - buffer.writeByte(-1); + byte[] payload = write(server.getSecret(connection.getPlayerUUID())); + FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer(1 + payload.length)); + buffer.writeByte(MAGIC_BYTE); buffer.writeByteArray(payload); + byte[] bytes = new byte[buffer.readableBytes()]; buffer.readBytes(bytes); return bytes; @@ -150,26 +151,16 @@ public class NetworkMessage { public byte[] write(Secret secret) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer()); - byte type = NetworkMessage.getPacketType(this.packet); + + byte type = getPacketType(packet); if (type < 0) { throw new IllegalArgumentException("Packet type not found"); } + buffer.writeByte(type); - this.packet.toBytes(buffer); + packet.toBytes(buffer); + return secret.encrypt(buffer.array()); } - static { - packetRegistry.put((byte)1, MicPacket.class); - packetRegistry.put((byte)2, PlayerSoundPacket.class); - packetRegistry.put((byte)3, GroupSoundPacket.class); - packetRegistry.put((byte)4, LocationSoundPacket.class); - packetRegistry.put((byte)5, AuthenticatePacket.class); - packetRegistry.put((byte)6, AuthenticateAckPacket.class); - packetRegistry.put((byte)7, PingPacket.class); - packetRegistry.put((byte)8, KeepAlivePacket.class); - packetRegistry.put((byte)9, ConnectionCheckPacket.class); - packetRegistry.put((byte)10, ConnectionCheckAckPacket.class); - } } - diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/Packet.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/Packet.java new file mode 100644 index 0000000..2d88e9c --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/Packet.java @@ -0,0 +1,15 @@ +package de.maxhenkel.voicechat.voice.common; + +import de.maxhenkel.voicechat.util.FriendlyByteBuf; + +public interface Packet { + + T fromBytes(FriendlyByteBuf buf); + + void toBytes(FriendlyByteBuf buf); + + default long getTTL() { + return 10_000L; + } + +} diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/PingPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/PingPacket.java similarity index 72% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/PingPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/PingPacket.java index 35912b8..eb92b8b 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/PingPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/PingPacket.java @@ -1,14 +1,11 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.Packet; + import java.util.UUID; -public class PingPacket -implements Packet { +public class PingPacket implements Packet { + private UUID id; private long timestamp; @@ -18,14 +15,15 @@ implements Packet { } public PingPacket() { + } public long getTimestamp() { - return this.timestamp; + return timestamp; } public UUID getId() { - return this.id; + return id; } @Override @@ -38,8 +36,7 @@ implements Packet { @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeUUID(this.id); - buf.writeLong(this.timestamp); + buf.writeUUID(id); + buf.writeLong(timestamp); } } - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/PlayerSoundPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/PlayerSoundPacket.java similarity index 56% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/PlayerSoundPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/PlayerSoundPacket.java index 116c09e..06230e4 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/PlayerSoundPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/PlayerSoundPacket.java @@ -1,18 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.voice.common.SoundPacket; -import java.util.UUID; -import javax.annotation.Nullable; -public class PlayerSoundPacket -extends SoundPacket { +import javax.annotation.Nullable; +import java.util.UUID; + +public class PlayerSoundPacket extends SoundPacket { + + // TODO Add a separate entity UUID instead of using the sender as the entity when breaking network compatibility protected boolean whispering; protected float distance; @@ -23,19 +18,19 @@ extends SoundPacket { } public PlayerSoundPacket() { + } - @Override public UUID getSender() { - return this.sender; + return sender; } public boolean isWhispering() { - return this.whispering; + return whispering; } public float getDistance() { - return this.distance; + return distance; } @Override @@ -43,12 +38,13 @@ extends SoundPacket { PlayerSoundPacket soundPacket = new PlayerSoundPacket(); soundPacket.channelId = buf.readUUID(); soundPacket.sender = buf.readUUID(); - soundPacket.data = buf.readByteArray(1275); + soundPacket.data = buf.readByteArray(AudioUtils.MAX_OPUS_PAYLOAD_SIZE); soundPacket.sequenceNumber = buf.readLong(); soundPacket.distance = buf.readFloat(); + byte data = buf.readByte(); - soundPacket.whispering = this.hasFlag(data, (byte)1); - if (this.hasFlag(data, (byte)2)) { + soundPacket.whispering = hasFlag(data, WHISPER_MASK); + if (hasFlag(data, HAS_CATEGORY_MASK)) { soundPacket.category = buf.readUtf(16); } return soundPacket; @@ -56,22 +52,23 @@ extends SoundPacket { @Override public void toBytes(FriendlyByteBuf buf) { - buf.writeUUID(this.channelId); - buf.writeUUID(this.sender); - buf.writeByteArray(this.data); - buf.writeLong(this.sequenceNumber); - buf.writeFloat(this.distance); - byte data = 0; - if (this.whispering) { - data = this.setFlag(data, (byte)1); + buf.writeUUID(channelId); + buf.writeUUID(sender); + buf.writeByteArray(data); + buf.writeLong(sequenceNumber); + buf.writeFloat(distance); + + byte data = 0b0; + if (whispering) { + data = setFlag(data, WHISPER_MASK); } - if (this.category != null) { - data = this.setFlag(data, (byte)2); + if (category != null) { + data = setFlag(data, HAS_CATEGORY_MASK); } buf.writeByte(data); - if (this.category != null) { - buf.writeUtf(this.category, 16); + if (category != null) { + buf.writeUtf(category, 16); } } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/PlayerState.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/PlayerState.java similarity index 69% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/PlayerState.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/PlayerState.java index 97ea9b9..21b9248 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/PlayerState.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/PlayerState.java @@ -1,16 +1,12 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import java.util.UUID; + import javax.annotation.Nullable; +import java.util.UUID; public class PlayerState { + private UUID uuid; private String name; private boolean disabled; @@ -26,7 +22,7 @@ public class PlayerState { } public UUID getUuid() { - return this.uuid; + return uuid; } public void setUuid(UUID uuid) { @@ -34,7 +30,7 @@ public class PlayerState { } public String getName() { - return this.name; + return name; } public void setName(String name) { @@ -42,7 +38,7 @@ public class PlayerState { } public boolean isDisabled() { - return this.disabled; + return disabled; } public void setDisabled(boolean disabled) { @@ -50,7 +46,7 @@ public class PlayerState { } public boolean isDisconnected() { - return this.disconnected; + return disconnected; } public void setDisconnected(boolean disconnected) { @@ -59,7 +55,7 @@ public class PlayerState { @Nullable public UUID getGroup() { - return this.group; + return group; } public void setGroup(@Nullable UUID group) { @@ -67,34 +63,44 @@ public class PlayerState { } public boolean hasGroup() { - return this.group != null; + return group != null; } + @Override public String toString() { - return "{disabled=" + this.disabled + ", disconnected=" + this.disconnected + ", uuid=" + this.uuid + ", name=" + this.name + ", group=" + this.group + '}'; + return "{" + + "disabled=" + disabled + + ", disconnected=" + disconnected + + ", uuid=" + uuid + + ", name=" + name + + ", group=" + group + + '}'; } public static PlayerState fromBytes(FriendlyByteBuf buf) { boolean disabled = buf.readBoolean(); boolean disconnected = buf.readBoolean(); UUID uuid = buf.readUUID(); - String name = buf.readUtf(Short.MAX_VALUE); + String name = buf.readUtf(32767); + PlayerState state = new PlayerState(uuid, name, disabled, disconnected); + if (buf.readBoolean()) { state.setGroup(buf.readUUID()); } + return state; } public void toBytes(FriendlyByteBuf buf) { - buf.writeBoolean(this.disabled); - buf.writeBoolean(this.disconnected); - buf.writeUUID(this.uuid); - buf.writeUtf(this.name); - buf.writeBoolean(this.hasGroup()); - if (this.hasGroup()) { - buf.writeUUID(this.group); + buf.writeBoolean(disabled); + buf.writeBoolean(disconnected); + buf.writeUUID(uuid); + buf.writeUtf(name); + buf.writeBoolean(hasGroup()); + if (hasGroup()) { + buf.writeUUID(group); } } -} +} diff --git a/source/patch/de/maxhenkel/voicechat/voice/common/Secret.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/Secret.java similarity index 84% rename from source/patch/de/maxhenkel/voicechat/voice/common/Secret.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/Secret.java index 9c3e451..f4de0ff 100644 --- a/source/patch/de/maxhenkel/voicechat/voice/common/Secret.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/Secret.java @@ -1,12 +1,7 @@ package de.maxhenkel.voicechat.voice.common; import io.netty.buffer.ByteBuf; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Arrays; + import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; @@ -14,13 +9,21 @@ import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Arrays; public class Secret { public static final int SECRET_SIZE_BYTES = 16; public static final int IV_SIZE_BYTES = 12; public static final int TAG_LEN_BITS = 128; public static final String CIPHER = "AES/GCM/NoPadding"; + private static final SecureRandom RANDOM = new SecureRandom(); + private final byte[] secret; private final SecretKeySpec keySpec; private volatile boolean legacyProtocol; @@ -50,15 +53,15 @@ public class Secret { } public void toBytes(ByteBuf buf) { - buf.writeBytes(this.secret); + buf.writeBytes(secret); } public byte[] getSecret() { - return this.secret.clone(); + return secret.clone(); } public SecretKeySpec getKeySpec() { - return this.keySpec; + return keySpec; } public void setLegacyProtocol(boolean legacyProtocol) { @@ -66,7 +69,7 @@ public class Secret { } public boolean isLegacyProtocol() { - return this.legacyProtocol; + return legacyProtocol; } public static byte[] generateIV() { @@ -83,19 +86,20 @@ public class Secret { public byte[] encrypt(byte[] data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { - if (this.legacyProtocol) { - byte[] iv = Secret.generateLegacyIV(); + if (legacyProtocol) { + byte[] iv = generateLegacyIV(); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(Cipher.ENCRYPT_MODE, (Key) this.keySpec, new IvParameterSpec(iv)); + cipher.init(Cipher.ENCRYPT_MODE, (Key) keySpec, new IvParameterSpec(iv)); byte[] encrypted = cipher.doFinal(data); byte[] payload = new byte[iv.length + encrypted.length]; System.arraycopy(iv, 0, payload, 0, iv.length); System.arraycopy(encrypted, 0, payload, iv.length, encrypted.length); return payload; } - byte[] iv = Secret.generateIV(); + + byte[] iv = generateIV(); Cipher cipher = Cipher.getInstance(CIPHER); - cipher.init(Cipher.ENCRYPT_MODE, (Key) this.keySpec, new GCMParameterSpec(TAG_LEN_BITS, iv)); + cipher.init(Cipher.ENCRYPT_MODE, (Key) keySpec, new GCMParameterSpec(TAG_LEN_BITS, iv)); byte[] encrypted = cipher.doFinal(data); byte[] payload = new byte[iv.length + encrypted.length]; System.arraycopy(iv, 0, payload, 0, iv.length); @@ -105,33 +109,34 @@ public class Secret { public byte[] decrypt(byte[] payload) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { - if (this.legacyProtocol) { + if (legacyProtocol) { if (payload.length < 32 || (payload.length - 16) % 16 != 0) { throw new IllegalBlockSizeException("Invalid legacy AES-CBC packet size"); } byte[] iv = Arrays.copyOfRange(payload, 0, 16); byte[] encrypted = Arrays.copyOfRange(payload, 16, payload.length); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(Cipher.DECRYPT_MODE, (Key) this.keySpec, new IvParameterSpec(iv)); + cipher.init(Cipher.DECRYPT_MODE, (Key) keySpec, new IvParameterSpec(iv)); return cipher.doFinal(encrypted); } + if (payload.length < IV_SIZE_BYTES + 16) { throw new IllegalBlockSizeException("Invalid AES-GCM packet size"); } byte[] iv = Arrays.copyOfRange(payload, 0, IV_SIZE_BYTES); byte[] encrypted = Arrays.copyOfRange(payload, IV_SIZE_BYTES, payload.length); Cipher cipher = Cipher.getInstance(CIPHER); - cipher.init(Cipher.DECRYPT_MODE, (Key) this.keySpec, new GCMParameterSpec(TAG_LEN_BITS, iv)); + cipher.init(Cipher.DECRYPT_MODE, (Key) keySpec, new GCMParameterSpec(TAG_LEN_BITS, iv)); return cipher.doFinal(encrypted); } @Override public boolean equals(Object o) { - return o instanceof Secret && Arrays.equals(this.secret, ((Secret) o).secret); + return o instanceof Secret && Arrays.equals(secret, ((Secret) o).secret); } @Override public int hashCode() { - return Arrays.hashCode(this.secret); + return Arrays.hashCode(secret); } } diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/SoundPacket.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/SoundPacket.java similarity index 62% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/SoundPacket.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/SoundPacket.java index 0b2b432..8e9d360 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/SoundPacket.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/SoundPacket.java @@ -1,19 +1,13 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.voice.common; -import de.maxhenkel.voicechat.voice.common.Packet; -import java.util.UUID; import javax.annotation.Nullable; +import java.util.UUID; + +public abstract class SoundPacket implements Packet { + + public static final byte WHISPER_MASK = 0b1; + public static final byte HAS_CATEGORY_MASK = 0b10; -public abstract class SoundPacket -implements Packet { - public static final byte WHISPER_MASK = 1; - public static final byte HAS_CATEGORY_MASK = 2; protected UUID channelId; protected UUID sender; protected byte[] data; @@ -30,35 +24,36 @@ implements Packet { } public SoundPacket() { + } public UUID getChannelId() { - return this.channelId; + return channelId; } public UUID getSender() { - return this.sender; + return sender; } public byte[] getData() { - return this.data; + return data; } public long getSequenceNumber() { - return this.sequenceNumber; + return sequenceNumber; } @Nullable public String getCategory() { - return this.category; + return category; } protected boolean hasFlag(byte data, byte mask) { - return (data & mask) != 0; + return (data & mask) != 0b0; } protected byte setFlag(byte data, byte mask) { - return (byte)(data | mask); + return (byte) (data | mask); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/Utils.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/Utils.java similarity index 72% rename from source/decompiled/de/maxhenkel/voicechat/voice/common/Utils.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/Utils.java index 4bdd798..68760f1 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/Utils.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/common/Utils.java @@ -1,15 +1,18 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.common; import de.maxhenkel.voicechat.Voicechat; public class Utils { + public static final int MAX_VOICE_CHAT_PACKET_SIZE = 2048; + /** + * Gets the default voice chat distance + * + * @return the default voice chat distance + */ public static float getDefaultDistance() { return Voicechat.SERVER_CONFIG.voiceChatDistance.get().floatValue(); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/server/ClientConnection.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ClientConnection.java similarity index 81% rename from source/decompiled/de/maxhenkel/voicechat/voice/server/ClientConnection.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ClientConnection.java index f5b70b8..b8aa19e 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/server/ClientConnection.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ClientConnection.java @@ -1,14 +1,12 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.server; import de.maxhenkel.voicechat.voice.common.NetworkMessage; -import de.maxhenkel.voicechat.voice.server.Server; + import java.net.SocketAddress; import java.util.UUID; public class ClientConnection { + private UUID playerUUID; private SocketAddress address; private long lastKeepAliveResponse; @@ -20,15 +18,15 @@ public class ClientConnection { } public UUID getPlayerUUID() { - return this.playerUUID; + return playerUUID; } public SocketAddress getAddress() { - return this.address; + return address; } public long getLastKeepAliveResponse() { - return this.lastKeepAliveResponse; + return lastKeepAliveResponse; } public void setLastKeepAliveResponse(long lastKeepAliveResponse) { @@ -36,7 +34,7 @@ public class ClientConnection { } public void send(Server server, NetworkMessage message) throws Exception { - server.getSocket().send(message.writeServer(server, this), this.address); + server.getSocket().send(message.writeServer(server, this), address); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/server/Group.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/Group.java similarity index 62% rename from source/decompiled/de/maxhenkel/voicechat/voice/server/Group.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/Group.java index d0ea554..84e7a67 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/server/Group.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/Group.java @@ -1,26 +1,21 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ package de.maxhenkel.voicechat.voice.server; -import de.maxhenkel.voicechat.api.Group; import de.maxhenkel.voicechat.voice.common.ClientGroup; -import java.util.UUID; + import javax.annotation.Nullable; +import java.util.UUID; public class Group { + private UUID id; private String name; @Nullable private String password; private boolean persistent; private boolean hidden; - private Group.Type type; + private de.maxhenkel.voicechat.api.Group.Type type; - public Group(UUID id, String name, @Nullable String password, boolean persistent, boolean hidden, Group.Type type) { + public Group(UUID id, String name, @Nullable String password, boolean persistent, boolean hidden, de.maxhenkel.voicechat.api.Group.Type type) { this.id = id; this.name = name; this.password = password; @@ -30,7 +25,7 @@ public class Group { } public Group(UUID id, String name, @Nullable String password, boolean persistent) { - this(id, name, password, persistent, false, Group.Type.NORMAL); + this(id, name, password, persistent, false, de.maxhenkel.voicechat.api.Group.Type.NORMAL); } public Group(UUID id, String name, @Nullable String password) { @@ -42,47 +37,48 @@ public class Group { } public Group() { + } public UUID getId() { - return this.id; + return id; } public String getName() { - return this.name; + return name; } @Nullable public String getPassword() { - return this.password; + return password; } public boolean isPersistent() { - return this.persistent; + return persistent; } public boolean isHidden() { - return this.hidden; + return hidden; } - public Group.Type getType() { - return this.type; + public de.maxhenkel.voicechat.api.Group.Type getType() { + return type; } public boolean isOpen() { - return this.type == Group.Type.OPEN; + return type == de.maxhenkel.voicechat.api.Group.Type.OPEN; } public boolean isNormal() { - return this.type == Group.Type.NORMAL; + return type == de.maxhenkel.voicechat.api.Group.Type.NORMAL; } public boolean isIsolated() { - return this.type == Group.Type.ISOLATED; + return type == de.maxhenkel.voicechat.api.Group.Type.ISOLATED; } public ClientGroup toClientGroup() { - return new ClientGroup(this.id, this.name, this.password != null, this.persistent, this.hidden, this.type); + return new ClientGroup(id, name, password != null, persistent, hidden, type); } -} +} \ No newline at end of file diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/server/PingManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/PingManager.java similarity index 53% rename from source/decompiled/de/maxhenkel/voicechat/voice/server/PingManager.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/PingManager.java index ac0a70e..1265c55 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/server/PingManager.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/PingManager.java @@ -1,12 +1,8 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat.voice.server; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.voice.common.PingPacket; -import de.maxhenkel.voicechat.voice.server.ClientConnection; -import de.maxhenkel.voicechat.voice.server.Server; + import java.util.List; import java.util.Map; import java.util.UUID; @@ -14,17 +10,18 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class PingManager { + private final Map listeners; private final Server server; public PingManager(Server server) { this.server = server; - this.listeners = new ConcurrentHashMap(); + listeners = new ConcurrentHashMap<>(); } public void onPongPacket(PingPacket packet) { Voicechat.LOGGER.info("Received pong {}", packet.getId()); - Ping ping = this.listeners.remove(packet.getId()); + Ping ping = listeners.remove(packet.getId()); if (ping == null) { return; } @@ -32,36 +29,35 @@ public class PingManager { } public void checkTimeouts() { - if (this.listeners.isEmpty()) { + if (listeners.isEmpty()) { return; } - List timedOut = this.listeners.entrySet().stream().filter(uuidPingEntry -> ((Ping)uuidPingEntry.getValue()).isTimedOut()).collect(Collectors.toList()); - for (Map.Entry pingEntry : timedOut) { - Ping ping = (Ping)pingEntry.getValue(); + List> timedOut = listeners.entrySet().stream().filter(uuidPingEntry -> uuidPingEntry.getValue().isTimedOut()).collect(Collectors.toList()); + for (Map.Entry pingEntry : timedOut) { + Ping ping = pingEntry.getValue(); if (ping.attempt >= ping.maxAttempts) { - this.listeners.remove(pingEntry.getKey()); + listeners.remove(pingEntry.getKey()); ping.listener.onTimeout(ping.attempt); - continue; - } - ping.listener.onFailedAttempt(ping.attempt); - try { - ping.send(); - } - catch (Exception e) { - ping.listener.onTimeout(ping.attempt); - Voicechat.LOGGER.warn("Failed to send ping {} after attempt {}", ping.id, ping.attempt); + } else { + ping.listener.onFailedAttempt(ping.attempt); + try { + ping.send(); + } catch (Exception e) { + ping.listener.onTimeout(ping.attempt); + Voicechat.LOGGER.warn("Failed to send ping {} after attempt {}", ping.id, ping.attempt); + } } } } public void sendPing(ClientConnection connection, long timeout, int attempts, PingListener listener) throws Exception { Ping ping = new Ping(connection, listener, timeout, attempts); - this.listeners.put(ping.id, ping); + listeners.put(ping.id, ping); ping.send(); } private class Ping { - private final UUID id = UUID.randomUUID(); + private final UUID id; private final ClientConnection connection; private final PingListener listener; private long timestamp; @@ -70,6 +66,7 @@ public class PingManager { private int attempt; public Ping(ClientConnection connection, PingListener listener, long timeout, int maxAttempts) { + this.id = UUID.randomUUID(); this.connection = connection; this.listener = listener; this.timeout = timeout; @@ -78,23 +75,23 @@ public class PingManager { } public boolean isTimedOut() { - return System.currentTimeMillis() - this.timestamp >= this.timeout; + return (System.currentTimeMillis() - timestamp) >= timeout; } public void send() throws Exception { - this.timestamp = System.currentTimeMillis(); - ++this.attempt; - PingManager.this.server.sendPacketRaw(new PingPacket(this.id, this.timestamp), this.connection); - Voicechat.LOGGER.info("Sent ping {} attempt {}", this.id, this.attempt); + timestamp = System.currentTimeMillis(); + attempt++; + server.sendPacketRaw(new PingPacket(id, timestamp), connection); + Voicechat.LOGGER.info("Sent ping {} attempt {}", id, attempt); } } - public static interface PingListener { - public void onPong(int var1, long var2); + public interface PingListener { + void onPong(int attempts, long pingMilliseconds); - public void onFailedAttempt(int var1); + void onFailedAttempt(int attempts); - public void onTimeout(int var1); + void onTimeout(int attempts); } -} +} \ No newline at end of file diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/server/PlayerStateManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/PlayerStateManager.java similarity index 63% rename from source/decompiled/de/maxhenkel/voicechat/voice/server/PlayerStateManager.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/PlayerStateManager.java index e64af4d..2cc4d1f 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/server/PlayerStateManager.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/PlayerStateManager.java @@ -1,62 +1,57 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.Bukkit - * org.bukkit.entity.Player - * org.bukkit.event.Listener - * org.bukkit.event.player.PlayerJoinEvent - * org.bukkit.event.player.PlayerQuitEvent - */ package de.maxhenkel.voicechat.voice.server; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.compatibility.PlayerHideEvent; import de.maxhenkel.voicechat.compatibility.PlayerShowEvent; -import de.maxhenkel.voicechat.net.NetManager; -import de.maxhenkel.voicechat.net.PlayerStatePacket; -import de.maxhenkel.voicechat.net.PlayerStatesPacket; -import de.maxhenkel.voicechat.net.RemovePlayerStatePacket; -import de.maxhenkel.voicechat.net.UpdateStatePacket; +import de.maxhenkel.voicechat.net.*; import de.maxhenkel.voicechat.plugins.PluginManager; import de.maxhenkel.voicechat.voice.common.PlayerState; -import java.util.ArrayList; -import java.util.Collection; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import javax.annotation.Nullable; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; -public class PlayerStateManager -implements Listener { - private final ConcurrentHashMap states = new ConcurrentHashMap(); +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class PlayerStateManager implements Listener { + + private final ConcurrentHashMap states; + + public PlayerStateManager() { + this.states = new ConcurrentHashMap<>(); + } public void onUpdateStatePacket(Player player, UpdateStatePacket packet) { - PlayerState state = this.states.get(player.getUniqueId()); + PlayerState state = states.get(player.getUniqueId()); + if (state == null) { - state = PlayerStateManager.defaultDisconnectedState(player); + state = defaultDisconnectedState(player); } + state.setDisabled(packet.isDisabled()); - this.states.put(player.getUniqueId(), state); - this.broadcastState(player, state); + + states.put(player.getUniqueId(), state); + + broadcastState(player, state); Voicechat.LOGGER.debug("Got state of {}: {}", player.getName(), state); } public void onPlayerQuit(PlayerQuitEvent event) { - this.states.remove(event.getPlayer().getUniqueId()); - this.broadcastRemoveState(event.getPlayer()); + states.remove(event.getPlayer().getUniqueId()); + broadcastRemoveState(event.getPlayer()); Voicechat.LOGGER.debug("Removing state of {}", event.getPlayer().getName()); } public void onPlayerJoin(PlayerJoinEvent event) { - PlayerState state = PlayerStateManager.defaultDisconnectedState(event.getPlayer()); - this.states.put(event.getPlayer().getUniqueId(), state); - this.broadcastState(event.getPlayer(), state); + PlayerState state = defaultDisconnectedState(event.getPlayer()); + states.put(event.getPlayer().getUniqueId(), state); + broadcastState(event.getPlayer(), state); Voicechat.LOGGER.debug("Setting default state of {}: {}", event.getPlayer().getName(), state); } @@ -67,9 +62,9 @@ implements Listener { } public void onPlayerShow(PlayerShowEvent event) { - PlayerState state = this.states.get(event.getShownPlayer().getUniqueId()); + PlayerState state = states.get(event.getShownPlayer().getUniqueId()); if (state == null) { - state = PlayerStateManager.defaultDisconnectedState(event.getShownPlayer()); + state = defaultDisconnectedState(event.getShownPlayer()); } PlayerStatePacket packet = new PlayerStatePacket(state); NetManager.sendToClient(event.getObserver(), packet); @@ -79,7 +74,9 @@ implements Listener { public void broadcastState(@Nullable Player stateOwner, PlayerState state) { PlayerStatePacket packet = new PlayerStatePacket(state); for (Player receiver : Voicechat.INSTANCE.getServer().getOnlinePlayers()) { - if (stateOwner != null && !Voicechat.compatibility.canSee(receiver, stateOwner)) continue; + if (stateOwner != null && !Voicechat.compatibility.canSee(receiver, stateOwner)) { + continue; + } NetManager.sendToClient(receiver, packet); } PluginManager.instance().onPlayerStateChanged(state); @@ -90,14 +87,20 @@ implements Listener { for (Player receiver : Voicechat.INSTANCE.getServer().getOnlinePlayers()) { NetManager.sendToClient(receiver, packet); } - PluginManager.instance().onPlayerStateChanged(PlayerStateManager.defaultDisconnectedState(stateOwner)); + // Send the default disconnected state to the API when disconnecting + PluginManager.instance().onPlayerStateChanged(defaultDisconnectedState(stateOwner)); } public void onPlayerCompatibilityCheckSucceeded(Player player) { - ArrayList stateList = new ArrayList(this.states.size()); - for (PlayerState state : this.states.values()) { + List stateList = new ArrayList<>(states.size()); + for (PlayerState state : states.values()) { Player otherPlayer = Voicechat.INSTANCE.getServer().getPlayer(state.getUuid()); - if (otherPlayer == null || !Voicechat.compatibility.canSee(player, otherPlayer)) continue; + if (otherPlayer == null) { + continue; + } + if (!Voicechat.compatibility.canSee(player, otherPlayer)) { + continue; + } stateList.add(state); } PlayerStatesPacket packet = new PlayerStatesPacket(stateList); @@ -106,30 +109,37 @@ implements Listener { } public void onPlayerVoicechatDisconnect(UUID uuid) { - PlayerState state = this.states.get(uuid); + PlayerState state = states.get(uuid); if (state == null) { return; } + state.setDisconnected(true); - Player player = Bukkit.getPlayer((UUID)uuid); - this.broadcastState(player, state); + + @Nullable Player player = Bukkit.getPlayer(uuid); + + broadcastState(player, state); Voicechat.LOGGER.debug("Set state of {} to disconnected: {}", uuid, state); } public void onPlayerVoicechatConnect(Player player) { - PlayerState state = this.states.get(player.getUniqueId()); + PlayerState state = states.get(player.getUniqueId()); + if (state == null) { - state = PlayerStateManager.defaultDisconnectedState(player); + state = defaultDisconnectedState(player); } + state.setDisconnected(false); - this.states.put(player.getUniqueId(), state); - this.broadcastState(player, state); + + states.put(player.getUniqueId(), state); + + broadcastState(player, state); Voicechat.LOGGER.debug("Set state of {} to connected: {}", player.getName(), state); } @Nullable public PlayerState getState(UUID playerUUID) { - return this.states.get(playerUUID); + return states.get(playerUUID); } public static PlayerState defaultDisconnectedState(Player player) { @@ -137,19 +147,19 @@ implements Listener { } public void setGroup(Player player, @Nullable UUID group) { - PlayerState state = this.states.get(player.getUniqueId()); + PlayerState state = states.get(player.getUniqueId()); if (state == null) { state = PlayerStateManager.defaultDisconnectedState(player); Voicechat.LOGGER.debug("Defaulting to default state for {}: {}", player.getName(), state); } state.setGroup(group); - this.states.put(player.getUniqueId(), state); - this.broadcastState(player, state); + states.put(player.getUniqueId(), state); + broadcastState(player, state); Voicechat.LOGGER.debug("Setting group of {}: {}", player.getName(), state); } public Collection getStates() { - return this.states.values(); + return states.values(); } -} +} diff --git a/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/Server.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/Server.java new file mode 100644 index 0000000..374a027 --- /dev/null +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/Server.java @@ -0,0 +1,559 @@ +package de.maxhenkel.voicechat.voice.server; + +import de.maxhenkel.voicechat.Voicechat; +import de.maxhenkel.voicechat.api.RawUdpPacket; +import de.maxhenkel.voicechat.api.VoicechatSocket; +import de.maxhenkel.voicechat.api.events.SoundPacketEvent; +import de.maxhenkel.voicechat.debug.CooldownTimer; +import de.maxhenkel.voicechat.debug.VoicechatUncaughtExceptionHandler; +import de.maxhenkel.voicechat.net.NetManager; +import de.maxhenkel.voicechat.permission.PermissionManager; +import de.maxhenkel.voicechat.plugins.PluginManager; +import de.maxhenkel.voicechat.voice.common.*; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.nio.channels.AsynchronousCloseException; +import java.security.InvalidKeyException; +import java.util.Collection; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class Server extends Thread { + + private final Map connections; + private final Map unCheckedConnections; + private final Map secrets; + private final int port; + private final org.bukkit.Server server; + private final VoicechatSocket socket; + private final ProcessThread processThread; + private final BlockingQueue packetQueue; + private final PingManager pingManager; + private final PlayerStateManager playerStateManager; + private final ServerGroupManager groupManager; + private final ServerCategoryManager categoryManager; + + public Server() { + int configPort = Voicechat.SERVER_CONFIG.voiceChatPort.get(); + if (configPort < 0) { + Voicechat.LOGGER.info("Using the Minecraft servers port as voice chat port"); + port = Bukkit.getPort(); + } else { + port = configPort; + } + this.server = Bukkit.getServer(); + socket = PluginManager.instance().getSocketImplementation(); + connections = new ConcurrentHashMap<>(); + unCheckedConnections = new ConcurrentHashMap<>(); + secrets = new ConcurrentHashMap<>(); + packetQueue = new LinkedBlockingQueue<>(); + pingManager = new PingManager(this); + playerStateManager = new PlayerStateManager(); + groupManager = new ServerGroupManager(); + categoryManager = new ServerCategoryManager(); + setDaemon(true); + setName("VoiceChatServerThread"); + setUncaughtExceptionHandler(new VoicechatUncaughtExceptionHandler()); + processThread = new ProcessThread(); + processThread.start(); + } + + @Override + public void run() { + try { + String bindAddress = getBindAddress(); + try { + InetAddress.getByName(bindAddress); + } catch (UnknownHostException e) { + Voicechat.LOGGER.error("Failed to parse bind IP address '{}'", bindAddress, e); + Voicechat.LOGGER.info("Binding to wildcard IP address"); + bindAddress = ""; + } + socket.open(port, bindAddress); + + if (bindAddress.isEmpty()) { + Voicechat.LOGGER.info("Voice chat server started at port {}", socket.getLocalPort()); + } else { + Voicechat.LOGGER.info("Voice chat server started at {}:{}", bindAddress, socket.getLocalPort()); + } + + while (!socket.isClosed()) { + try { + packetQueue.add(socket.read()); + } catch (Exception e) { + // Only log an error if the error isn't caused by the socket being closed + if (!(e instanceof SocketException && e.getCause() instanceof AsynchronousCloseException)) { + if (Voicechat.debugMode()) { + Voicechat.LOGGER.error("Failed to read from socket", e); + } + } + } + } + } catch (Exception e) { + Voicechat.LOGGER.error("Voice chat server error", e); + } + } + + private String getBindAddress() { + String bindAddress = Voicechat.SERVER_CONFIG.voiceChatBindAddress.get(); + + if (bindAddress.trim().equals("*")) { + bindAddress = ""; + } else if (bindAddress.trim().isEmpty()) { + try { + bindAddress = Bukkit.getIp(); + if (!bindAddress.trim().isEmpty()) { + try { + InetAddress address = InetAddress.getByName(bindAddress); + if (address.isLoopbackAddress()) { + bindAddress = ""; + } else { + Voicechat.LOGGER.info("Using server-ip as bind address: {}", bindAddress); + } + } catch (Exception e) { + Voicechat.LOGGER.warn("Invalid server-ip", e); + bindAddress = ""; + } + } + } catch (Throwable t) { + Voicechat.LOGGER.warn("Failed to get server-ip from server.properties - binding to wildcard address", t); + } + } + + return bindAddress; + } + + public Secret getSecret(UUID playerUUID) { + if (hasSecret(playerUUID)) { + return secrets.get(playerUUID); + } else { + Secret secret = Secret.generateNewRandomSecret(); + secrets.put(playerUUID, secret); + return secret; + } + } + + /** + * @param playerUUID the player uuid + * @return the new secret or null if the player already has a secret + */ + @Nullable + public Secret generateNewSecret(UUID playerUUID) { + if (hasSecret(playerUUID)) { + return null; + } + return getSecret(playerUUID); + } + + public boolean hasSecret(UUID playerUUID) { + return secrets.containsKey(playerUUID); + } + + public void disconnectClient(UUID playerUUID) { + connections.remove(playerUUID); + unCheckedConnections.remove(playerUUID); + secrets.remove(playerUUID); + PluginManager.instance().onPlayerDisconnected(playerUUID); + } + + public void close() { + socket.close(); + processThread.close(); + + PluginManager.instance().onServerStopped(); + } + + public boolean isClosed() { + return !processThread.running; + } + + private class ProcessThread extends Thread { + private boolean running; + private long lastKeepAlive; + + public ProcessThread() { + running = true; + lastKeepAlive = 0L; + setDaemon(true); + setName("VoiceChatPacketProcessingThread"); + setUncaughtExceptionHandler(new VoicechatUncaughtExceptionHandler()); + } + + @Override + public void run() { + while (running) { + try { + pingManager.checkTimeouts(); + long keepAliveTime = System.currentTimeMillis(); + if (keepAliveTime - lastKeepAlive > Voicechat.SERVER_CONFIG.keepAlive.get()) { + sendKeepAlives(); + lastKeepAlive = keepAliveTime; + } + + RawUdpPacket rawPacket = packetQueue.poll(10, TimeUnit.MILLISECONDS); + if (rawPacket == null) { + continue; + } + + NetworkMessage message; + try { + message = NetworkMessage.readPacketServer(rawPacket, Server.this); + } catch (Exception e) { + CooldownTimer.run("failed_reading_packet", () -> { + Voicechat.LOGGER.warn("Failed to read packet from {}", rawPacket.getSocketAddress()); + }); + continue; + } + + if (message == null) { + continue; + } + + if (System.currentTimeMillis() - message.getTimestamp() > message.getTTL()) { + CooldownTimer.run("ttl", () -> { + Voicechat.LOGGER.error("Dropping voice chat packets! Your Server might be overloaded!"); + Voicechat.LOGGER.error("Packet queue has {} packets", packetQueue.size()); + }); + continue; + } + + if (message.getPacket() instanceof AuthenticatePacket) { + AuthenticatePacket packet = (AuthenticatePacket) message.getPacket(); + Secret secret = secrets.get(packet.getPlayerUUID()); + if (secret != null && secret.equals(packet.getSecret())) { + ClientConnection connection = unCheckedConnections.get(packet.getPlayerUUID()); + if (connection == null) { + connection = connections.get(packet.getPlayerUUID()); + } + if (connection == null) { + connection = new ClientConnection(packet.getPlayerUUID(), message.getAddress()); + unCheckedConnections.put(packet.getPlayerUUID(), connection); + Voicechat.LOGGER.info("Successfully authenticated player {}", packet.getPlayerUUID()); + } + sendPacket(new AuthenticateAckPacket(), connection); + } + } + + if (message.getPacket() instanceof ConnectionCheckPacket) { + ClientConnection connection = getUnconnectedSender(message); + if (connection == null) { + connection = getSender(message); + if (connection != null) { + sendPacket(new ConnectionCheckAckPacket(), connection); + } + continue; + } + // Refresh keepalive, so players who took longer than the timeout can still connect + connection.setLastKeepAliveResponse(System.currentTimeMillis()); + connections.put(connection.getPlayerUUID(), connection); + unCheckedConnections.remove(connection.getPlayerUUID()); + Voicechat.LOGGER.info("Successfully validated connection of player {}", connection.getPlayerUUID()); + Player player = server.getPlayer(connection.getPlayerUUID()); + if (player != null) { + playerStateManager.onPlayerVoicechatConnect(player); + PluginManager.instance().onPlayerConnected(player); + Voicechat.LOGGER.info("Player {} ({}) successfully connected to voice chat", player.getName(), connection.getPlayerUUID()); + } + sendPacket(new ConnectionCheckAckPacket(), connection); + continue; + } + + ClientConnection conn = getSender(message); + if (conn == null) { + continue; + } + + if (message.getPacket() instanceof MicPacket) { + onMicPacket(conn.getPlayerUUID(), (MicPacket) message.getPacket()); + } else if (message.getPacket() instanceof PingPacket) { + PingPacket packet = (PingPacket) message.getPacket(); + pingManager.onPongPacket(packet); + } else if (message.getPacket() instanceof KeepAlivePacket) { + conn.setLastKeepAliveResponse(System.currentTimeMillis()); + } + } catch (Exception e) { + Voicechat.LOGGER.error("Voice chat server error", e); + } + } + } + + public void close() { + running = false; + } + } + + public void onMicPacket(UUID playerUuid, MicPacket packet) { + Player player = server.getPlayer(playerUuid); + if (player == null) { + return; + } + if (!player.hasPermission(PermissionManager.SPEAK_PERMISSION)) { + CooldownTimer.run("no-speak-" + playerUuid, () -> { + NetManager.sendStatusMessage(player, "message.voicechat.no_speak_permission"); + }); + return; + } + PlayerState state = playerStateManager.getState(player.getUniqueId()); + if (state == null) { + return; + } + if (!PluginManager.instance().onMicPacket(player, state, packet)) { + processMicPacket(player, state, packet); + } + } + + private void processMicPacket(Player player, PlayerState state, MicPacket packet) { + if (state.hasGroup()) { + @Nullable Group group = groupManager.getGroup(state.getGroup()); + processGroupPacket(state, player, packet); + if (group == null || group.isOpen()) { + processProximityPacket(state, player, packet); + } + return; + } + processProximityPacket(state, player, packet); + } + + private void processGroupPacket(PlayerState senderState, Player sender, MicPacket packet) { + UUID groupId = senderState.getGroup(); + if (groupId == null) { + return; + } + GroupSoundPacket groupSoundPacket = new GroupSoundPacket(senderState.getUuid(), senderState.getUuid(), packet.getData(), packet.getSequenceNumber(), null); + for (PlayerState state : playerStateManager.getStates()) { + if (!groupId.equals(state.getGroup())) { + continue; + } + if (senderState.getUuid().equals(state.getUuid())) { + continue; + } + Player p = server.getPlayer(state.getUuid()); + if (p == null) { + continue; + } + @Nullable ClientConnection connection = getConnection(state.getUuid()); + sendSoundPacket(sender, senderState, p, state, connection, groupSoundPacket, SoundPacketEvent.SOURCE_GROUP); + } + } + + private void processProximityPacket(PlayerState senderState, Player sender, MicPacket packet) { + @Nullable UUID groupId = senderState.getGroup(); + float distance; + if (packet.isWhispering()) { + distance = Voicechat.SERVER_CONFIG.whisperDistance.get().floatValue(); + } else { + distance = Utils.getDefaultDistance(); + } + + distance = PluginManager.instance().getDistance(sender, senderState, packet, distance); + + SoundPacket soundPacket = null; + String source = null; + if (sender.getGameMode().equals(GameMode.SPECTATOR)) { + if (Voicechat.SERVER_CONFIG.spectatorPlayerPossession.get()) { + Entity camera = sender.getSpectatorTarget(); + if (camera instanceof Player) { + Player spectatingPlayer = (Player) camera; + if (spectatingPlayer != sender) { + PlayerState receiverState = playerStateManager.getState(spectatingPlayer.getUniqueId()); + if (receiverState == null) { + return; + } + GroupSoundPacket groupSoundPacket = new GroupSoundPacket(senderState.getUuid(), senderState.getUuid(), packet.getData(), packet.getSequenceNumber(), null); + @Nullable ClientConnection connection = getConnection(receiverState.getUuid()); + sendSoundPacket(sender, senderState, spectatingPlayer, receiverState, connection, groupSoundPacket, SoundPacketEvent.SOURCE_SPECTATOR); + return; + } + } + } + if (Voicechat.SERVER_CONFIG.spectatorInteraction.get()) { + soundPacket = new LocationSoundPacket(sender.getUniqueId(), sender.getUniqueId(), sender.getLocation(), packet.getData(), packet.getSequenceNumber(), distance, null); + source = SoundPacketEvent.SOURCE_SPECTATOR; + } + } + + if (soundPacket == null) { + soundPacket = new PlayerSoundPacket(sender.getUniqueId(), sender.getUniqueId(), packet.getData(), packet.getSequenceNumber(), packet.isWhispering(), distance, null); + source = SoundPacketEvent.SOURCE_PROXIMITY; + } + + broadcast(ServerPlayerManager.getPlayersInRange(sender.getWorld(), sender.getLocation(), getBroadcastRange(distance), p -> !p.getUniqueId().equals(sender.getUniqueId())), soundPacket, sender, senderState, groupId, source); + } + + public void sendSoundPacket(@Nullable Player sender, @Nullable PlayerState senderState, Player receiver, PlayerState receiverState, @Nullable ClientConnection connection, SoundPacket soundPacket, String source) { + PluginManager.instance().onListenerAudio(receiver.getUniqueId(), soundPacket); + + if (connection == null) { + return; + } + + if (receiverState.isDisabled() || receiverState.isDisconnected()) { + return; + } + + if (PluginManager.instance().onSoundPacket(sender, senderState, receiver, receiverState, soundPacket, source)) { + return; + } + + if (!receiver.hasPermission(PermissionManager.LISTEN_PERMISSION)) { + CooldownTimer.run(String.format("no-listen-%s", receiver.getUniqueId()), 30_000L, () -> { + NetManager.sendStatusMessage(receiver, "message.voicechat.no_listen_permission"); + }); + return; + } + sendPacket(soundPacket, connection); + } + + public double getBroadcastRange(float minRange) { + double broadcastRange = Voicechat.SERVER_CONFIG.broadcastRange.get(); + if (broadcastRange < 0D) { + broadcastRange = Voicechat.SERVER_CONFIG.voiceChatDistance.get() + 1D; + } + return Math.max(broadcastRange, minRange); + } + + public void broadcast(Collection players, SoundPacket packet, @Nullable Player sender, @Nullable PlayerState senderState, @Nullable UUID groupId, String source) { + for (Player player : players) { + PlayerState state = playerStateManager.getState(player.getUniqueId()); + if (state == null) { + continue; + } + if (state.hasGroup() && state.getGroup().equals(groupId)) { + continue; + } + @Nullable Group receiverGroup = null; + if (state.hasGroup()) { + receiverGroup = groupManager.getGroup(state.getGroup()); + } + if (receiverGroup != null && receiverGroup.isIsolated()) { + continue; + } + @Nullable ClientConnection connection = getConnection(state.getUuid()); + sendSoundPacket(sender, senderState, player, state, connection, packet, source); + } + } + + private void sendKeepAlives() { + long timestamp = System.currentTimeMillis(); + + connections.values().removeIf(connection -> { + if (timestamp - connection.getLastKeepAliveResponse() >= Voicechat.SERVER_CONFIG.keepAlive.get() * 10L) { + // Don't call disconnectClient here! + secrets.remove(connection.getPlayerUUID()); + Voicechat.LOGGER.info("Player {} timed out", connection.getPlayerUUID()); + Player player = server.getPlayer(connection.getPlayerUUID()); + if (player != null) { + Voicechat.LOGGER.info("Reconnecting player {}", player.getName()); + Voicechat.SERVER.initializePlayerConnection(player); + } else { + Voicechat.LOGGER.error("Reconnecting player {} failed (Could not find player)", connection.getPlayerUUID()); + } + playerStateManager.onPlayerVoicechatDisconnect(connection.getPlayerUUID()); + PluginManager.instance().onPlayerDisconnected(connection.getPlayerUUID()); + return true; + } + return false; + }); + + for (ClientConnection connection : connections.values()) { + sendPacket(new KeepAlivePacket(), connection); + } + + } + + @Nullable + public ClientConnection getSender(NetworkMessage message) { + return connections + .values() + .stream() + .filter(connection -> connection.getAddress().equals(message.getAddress())) + .findAny() + .orElse(null); + } + + @Nullable + public ClientConnection getUnconnectedSender(NetworkMessage message) { + return unCheckedConnections + .values() + .stream() + .filter(connection -> connection.getAddress().equals(message.getAddress())) + .findAny() + .orElse(null); + } + + public Map getConnections() { + return connections; + } + + @Nullable + public ClientConnection getConnection(UUID playerID) { + return connections.get(playerID); + } + + public VoicechatSocket getSocket() { + return socket; + } + + public int getPort() { + return socket.getLocalPort(); + } + + /** + * Sends the packet and handles potential errors. + * + * @param packet the packet to send + * @param connection the connection to send the packet to + * @return if the packet was sent successfully + */ + public boolean sendPacket(Packet packet, ClientConnection connection) { + try { + sendPacketRaw(packet, connection); + return true; + } catch (Exception e) { + Voicechat.LOGGER.error("Failed to send voice chat packet to {}", connection.getPlayerUUID()); + return false; + } + } + + /** + * Sends the packet. You must handle potential errors + * + * @param packet the packet to send + * @param connection the connection to send the packet to + * @throws Exception if an I/O error occurs + */ + public void sendPacketRaw(Packet packet, ClientConnection connection) throws Exception { + connection.send(this, new NetworkMessage(packet)); + } + + public PingManager getPingManager() { + return pingManager; + } + + public PlayerStateManager getPlayerStateManager() { + return playerStateManager; + } + + public ServerGroupManager getGroupManager() { + return groupManager; + } + + public ServerCategoryManager getCategoryManager() { + return categoryManager; + } + +} \ No newline at end of file diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/server/ServerCategoryManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerCategoryManager.java similarity index 80% rename from source/decompiled/de/maxhenkel/voicechat/voice/server/ServerCategoryManager.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerCategoryManager.java index 3fb712a..04b2330 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/server/ServerCategoryManager.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerCategoryManager.java @@ -1,10 +1,3 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.entity.Player - */ package de.maxhenkel.voicechat.voice.server; import de.maxhenkel.voicechat.Voicechat; @@ -13,14 +6,15 @@ import de.maxhenkel.voicechat.net.NetManager; import de.maxhenkel.voicechat.net.RemoveCategoryPacket; import de.maxhenkel.voicechat.plugins.CategoryManager; import de.maxhenkel.voicechat.plugins.impl.VolumeCategoryImpl; -import javax.annotation.Nullable; import org.bukkit.entity.Player; -public class ServerCategoryManager -extends CategoryManager { +import javax.annotation.Nullable; + +public class ServerCategoryManager extends CategoryManager { + public void onPlayerCompatibilityCheckSucceeded(Player player) { - Voicechat.LOGGER.debug("Synchronizing {} volume categories with {}", this.categories.size(), player.getName()); - for (VolumeCategoryImpl category : this.getCategories()) { + Voicechat.LOGGER.debug("Synchronizing {} volume categories with {}", categories.size(), player.getName()); + for (VolumeCategoryImpl category : getCategories()) { NetManager.sendToClient(player, new AddCategoryPacket(category)); } } @@ -29,7 +23,7 @@ extends CategoryManager { public void addCategory(VolumeCategoryImpl category) { super.addCategory(category); Voicechat.LOGGER.debug("Synchronizing volume category {} with all players", category.getId()); - this.broadcastAddCategory(category); + broadcastAddCategory(category); } @Override @@ -37,7 +31,7 @@ extends CategoryManager { public VolumeCategoryImpl removeCategory(String categoryId) { VolumeCategoryImpl volumeCategory = super.removeCategory(categoryId); Voicechat.LOGGER.debug("Removing volume category {} for all players", categoryId); - this.broadcastRemoveCategory(categoryId); + broadcastRemoveCategory(categoryId); return volumeCategory; } @@ -50,5 +44,5 @@ extends CategoryManager { RemoveCategoryPacket packet = new RemoveCategoryPacket(categoryId); Voicechat.INSTANCE.getServer().getOnlinePlayers().forEach(p -> NetManager.sendToClient(p, packet)); } -} +} diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/server/ServerGroupManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerGroupManager.java similarity index 66% rename from source/decompiled/de/maxhenkel/voicechat/voice/server/ServerGroupManager.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerGroupManager.java index 5f99ea4..b21aa66 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/server/ServerGroupManager.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerGroupManager.java @@ -1,55 +1,45 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.entity.Player - * org.bukkit.event.player.PlayerQuitEvent - */ package de.maxhenkel.voicechat.voice.server; import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.AddGroupPacket; -import de.maxhenkel.voicechat.net.CreateGroupPacket; -import de.maxhenkel.voicechat.net.JoinGroupPacket; -import de.maxhenkel.voicechat.net.JoinedGroupPacket; -import de.maxhenkel.voicechat.net.LeaveGroupPacket; -import de.maxhenkel.voicechat.net.NetManager; -import de.maxhenkel.voicechat.net.RemoveGroupPacket; +import de.maxhenkel.voicechat.net.*; import de.maxhenkel.voicechat.permission.PermissionManager; import de.maxhenkel.voicechat.plugins.PluginManager; import de.maxhenkel.voicechat.voice.common.PlayerState; -import de.maxhenkel.voicechat.voice.server.Group; -import de.maxhenkel.voicechat.voice.server.PlayerStateManager; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerQuitEvent; + +import javax.annotation.Nullable; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerQuitEvent; public class ServerGroupManager { - private final Map groups = new ConcurrentHashMap(); + + private final Map groups; + + public ServerGroupManager() { + groups = new ConcurrentHashMap<>(); + } public void onJoinGroupPacket(Player player, JoinGroupPacket packet) { - if (!Voicechat.SERVER_CONFIG.groupsEnabled.get().booleanValue()) { + if (!Voicechat.SERVER_CONFIG.groupsEnabled.get()) { return; } if (!player.hasPermission(PermissionManager.GROUPS_PERMISSION)) { - NetManager.sendStatusMessage(player, "message.voicechat.no_group_permission", new String[0]); + NetManager.sendStatusMessage(player, "message.voicechat.no_group_permission"); return; } - this.joinGroup(this.groups.get(packet.getGroup()), player, packet.getPassword()); + joinGroup(groups.get(packet.getGroup()), player, packet.getPassword()); } public void onCreateGroupPacket(Player player, CreateGroupPacket packet) { - if (!Voicechat.SERVER_CONFIG.groupsEnabled.get().booleanValue()) { + if (!Voicechat.SERVER_CONFIG.groupsEnabled.get()) { return; } if (!player.hasPermission(PermissionManager.GROUPS_PERMISSION)) { - NetManager.sendStatusMessage(player, "message.voicechat.no_group_permission", new String[0]); + NetManager.sendStatusMessage(player, "message.voicechat.no_group_permission"); return; } if (!Voicechat.GROUP_REGEX.matcher(packet.getName()).matches()) { @@ -61,22 +51,22 @@ public class ServerGroupManager { return; } Group group = new Group(UUID.randomUUID(), packet.getName(), packet.getPassword(), false, false, packet.getType()); - this.addGroup(group, player); + addGroup(group, player); } public void onLeaveGroupPacket(Player player, LeaveGroupPacket packet) { - this.leaveGroup(player); + leaveGroup(player); } public void onPlayerCompatibilityCheckSucceeded(Player player) { - Voicechat.LOGGER.debug("Synchronizing {} groups with {}", this.groups.size(), player.getDisplayName()); - for (Group group : this.groups.values()) { + Voicechat.LOGGER.debug("Synchronizing {} groups with {}", groups.size(), player.getDisplayName()); + for (Group group : groups.values()) { NetManager.sendToClient(player, new AddGroupPacket(group.toClientGroup())); } } public void onPlayerQuit(PlayerQuitEvent event) { - this.cleanupGroups(); + cleanupGroups(); } private PlayerStateManager getStates() { @@ -87,13 +77,16 @@ public class ServerGroupManager { if (PluginManager.instance().onCreateGroup(player, group)) { return; } - this.groups.put(group.getId(), group); - this.broadcastAddGroup(group); + groups.put(group.getId(), group); + broadcastAddGroup(group); + if (player == null) { return; } - PlayerStateManager manager = this.getStates(); + + PlayerStateManager manager = getStates(); manager.setGroup(player, group.getId()); + NetManager.sendToClient(player, new JoinedGroupPacket(group.getId(), false)); } @@ -102,15 +95,19 @@ public class ServerGroupManager { NetManager.sendToClient(player, new JoinedGroupPacket(null, true)); return; } + if (PluginManager.instance().onJoinGroup(player, group)) { return; } + if (group == null) { NetManager.sendToClient(player, new JoinedGroupPacket(null, false)); return; } - PlayerStateManager manager = this.getStates(); + + PlayerStateManager manager = getStates(); manager.setGroup(player, group.getId()); + NetManager.sendToClient(player, new JoinedGroupPacket(group.getId(), false)); } @@ -118,41 +115,47 @@ public class ServerGroupManager { if (PluginManager.instance().onLeaveGroup(player)) { return; } - PlayerStateManager manager = this.getStates(); + + PlayerStateManager manager = getStates(); manager.setGroup(player, null); NetManager.sendToClient(player, new JoinedGroupPacket(null, false)); - this.cleanupGroups(); + + cleanupGroups(); } public void cleanupGroups() { - PlayerStateManager manager = this.getStates(); - List usedGroups = manager.getStates().stream().filter(PlayerState::hasGroup).map(PlayerState::getGroup).distinct().collect(Collectors.toList()); - List groupsToRemove = this.groups.entrySet().stream().filter(entry -> !((Group)entry.getValue()).isPersistent()).map(Map.Entry::getKey).filter(uuid -> !usedGroups.contains(uuid)).collect(Collectors.toList()); - for (UUID uuid2 : groupsToRemove) { - this.removeGroup(uuid2); + PlayerStateManager manager = getStates(); + List usedGroups = manager.getStates().stream().filter(PlayerState::hasGroup).map(PlayerState::getGroup).distinct().collect(Collectors.toList()); + List groupsToRemove = groups.entrySet().stream().filter(entry -> !entry.getValue().isPersistent()).map(Map.Entry::getKey).filter(uuid -> !usedGroups.contains(uuid)).collect(Collectors.toList()); + for (UUID uuid : groupsToRemove) { + removeGroup(uuid); } } public boolean removeGroup(UUID groupId) { - Group group = this.groups.get(groupId); + Group group = groups.get(groupId); if (group == null) { return false; } - PlayerStateManager manager = this.getStates(); + + PlayerStateManager manager = getStates(); if (manager.getStates().stream().anyMatch(state -> state.hasGroup() && state.getGroup().equals(groupId))) { return false; } + if (PluginManager.instance().onRemoveGroup(group)) { return false; } - this.groups.remove(groupId); - this.broadcastRemoveGroup(groupId); + + groups.remove(groupId); + broadcastRemoveGroup(groupId); + // TODO Handle kicking players from group instead of preventing it return true; } @Nullable public Group getGroup(UUID groupID) { - return this.groups.get(groupID); + return groups.get(groupID); } private void broadcastAddGroup(Group group) { @@ -167,7 +170,7 @@ public class ServerGroupManager { @Nullable public Group getPlayerGroup(Player player) { - PlayerState state = this.getStates().getState(player.getUniqueId()); + PlayerState state = getStates().getState(player.getUniqueId()); if (state == null) { return null; } @@ -175,11 +178,11 @@ public class ServerGroupManager { if (groupId == null) { return null; } - return this.getGroup(groupId); + return getGroup(groupId); } public Map getGroups() { - return this.groups; + return groups; } -} +} \ No newline at end of file diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/server/ServerPlayerManager.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerPlayerManager.java similarity index 51% rename from source/decompiled/de/maxhenkel/voicechat/voice/server/ServerPlayerManager.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerPlayerManager.java index 446ebc4..0af0ca3 100644 --- a/source/decompiled/de/maxhenkel/voicechat/voice/server/ServerPlayerManager.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerPlayerManager.java @@ -1,29 +1,6 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.Bukkit - * org.bukkit.Location - * org.bukkit.World - * org.bukkit.entity.Player - * org.bukkit.event.EventHandler - * org.bukkit.event.Listener - * org.bukkit.event.player.PlayerJoinEvent - * org.bukkit.event.player.PlayerQuitEvent - * org.bukkit.plugin.Plugin - */ package de.maxhenkel.voicechat.voice.server; import de.maxhenkel.voicechat.Voicechat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; -import javax.annotation.Nullable; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; @@ -34,39 +11,51 @@ import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.Plugin; -public class ServerPlayerManager -implements Listener { - private static final long REFRESH_INTERVAL_TICKS = 600L; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +public class ServerPlayerManager implements Listener { + + private static final long REFRESH_INTERVAL_TICKS = 20L * 30L; + public static final ServerPlayerManager INSTANCE = new ServerPlayerManager(); - private volatile Set players = Collections.emptySet(); public static void init(Plugin plugin) { - if (!Voicechat.SERVER_CONFIG.threadedServerSupport.get().booleanValue()) { + if (!Voicechat.SERVER_CONFIG.threadedServerSupport.get()) { return; } - Bukkit.getPluginManager().registerEvents((Listener)INSTANCE, plugin); - Voicechat.compatibility.scheduleSyncRepeatingTask(INSTANCE::refresh, 0L, 600L); + Bukkit.getPluginManager().registerEvents(ServerPlayerManager.INSTANCE, plugin); + Voicechat.compatibility.scheduleSyncRepeatingTask(INSTANCE::refresh, 0, REFRESH_INTERVAL_TICKS); } + private volatile Set players; + private ServerPlayerManager() { + players = Collections.emptySet(); } private synchronized void refresh() { - this.players = new HashSet(Bukkit.getOnlinePlayers()); + players = new HashSet<>(Bukkit.getOnlinePlayers()); } @EventHandler public synchronized void onPlayerJoin(PlayerJoinEvent event) { - HashSet newPlayers = new HashSet(this.players); + Set newPlayers = new HashSet<>(players); newPlayers.add(event.getPlayer()); - this.players = newPlayers; + players = newPlayers; } @EventHandler public synchronized void onPlayerQuit(PlayerQuitEvent event) { - HashSet newPlayers = new HashSet(this.players); + Set newPlayers = new HashSet<>(players); newPlayers.remove(event.getPlayer()); - this.players = newPlayers; + players = newPlayers; } public static Collection getPlayersInRange(World level, Location pos, double range, @Nullable Predicate filter) { @@ -74,34 +63,39 @@ implements Listener { } private Collection getPlayersInRangeInternal(World world, Location pos, double range, @Nullable Predicate filter) { - if (!Voicechat.SERVER_CONFIG.threadedServerSupport.get().booleanValue()) { - return ServerPlayerManager.getPlayersInRangeDirect(world, pos, range, filter); + if (!Voicechat.SERVER_CONFIG.threadedServerSupport.get()) { + return getPlayersInRangeDirect(world, pos, range, filter); } - ArrayList nearbyPlayers = new ArrayList(); - for (Player player : this.players) { - if (!world.equals((Object)player.getWorld()) || !ServerPlayerManager.isInRange(player.getLocation(), pos, range) || filter != null && !filter.test(player)) continue; - nearbyPlayers.add(player); + List nearbyPlayers = new ArrayList<>(); + for (Player player : players) { + if (!world.equals(player.getWorld())) { + continue; + } + if (isInRange(player.getLocation(), pos, range) && (filter == null || filter.test(player))) { + nearbyPlayers.add(player); + } } return nearbyPlayers; } private static Collection getPlayersInRangeDirect(World world, Location pos, double range, @Nullable Predicate filter) { - ArrayList nearbyPlayers = new ArrayList(); - List worldPlayers = world.getPlayers(); - for (int i = 0; i < worldPlayers.size(); ++i) { - Player player = (Player)worldPlayers.get(i); - if (!ServerPlayerManager.isInRange(player.getLocation(), pos, range) || filter != null && !filter.test(player)) continue; - nearbyPlayers.add(player); + List nearbyPlayers = new ArrayList<>(); + List worldPlayers = world.getPlayers(); + for (int i = 0; i < worldPlayers.size(); i++) { + Player player = worldPlayers.get(i); + if (isInRange(player.getLocation(), pos, range) && (filter == null || filter.test(player))) { + nearbyPlayers.add(player); + } } return nearbyPlayers; } public static boolean isInRange(Location pos1, Location pos2, double range) { - return ServerPlayerManager.square(pos1.getX() - pos2.getX()) + ServerPlayerManager.square(pos1.getY() - pos2.getY()) + ServerPlayerManager.square(pos1.getZ() - pos2.getZ()) <= ServerPlayerManager.square(range); + return (square(pos1.getX() - pos2.getX()) + square(pos1.getY() - pos2.getY()) + square(pos1.getZ() - pos2.getZ())) <= square(range); } private static double square(double value) { return value * value; } -} +} diff --git a/source/patch/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java similarity index 64% rename from source/patch/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java rename to source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java index 6c4fe38..44bd8da 100644 --- a/source/patch/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java +++ b/source/bukkit/src/main/java/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java @@ -1,5 +1,6 @@ package de.maxhenkel.voicechat.voice.server; +import de.maxhenkel.voicechat.BuildConstants; import de.maxhenkel.voicechat.Voicechat; import de.maxhenkel.voicechat.compatibility.PlayerHideEvent; import de.maxhenkel.voicechat.compatibility.PlayerShowEvent; @@ -9,9 +10,6 @@ import de.maxhenkel.voicechat.net.RequestSecretPacket; import de.maxhenkel.voicechat.net.SecretPacket; import de.maxhenkel.voicechat.plugins.PluginManager; import de.maxhenkel.voicechat.voice.common.Secret; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -19,36 +17,42 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + public class ServerVoiceEvents implements Listener { private static final int LEGACY_COMPATIBILITY_VERSION = 18; - private static final int CURRENT_COMPATIBILITY_VERSION = 20; private final Map clientCompatibilities = new ConcurrentHashMap<>(); private final PacketRateLimiter rateLimiter; private Server server; public ServerVoiceEvents() { - this.rateLimiter = new PacketRateLimiter(Voicechat.SERVER_CONFIG.tcpRateLimit.get()); + rateLimiter = new PacketRateLimiter(Voicechat.SERVER_CONFIG.tcpRateLimit.get()); } public void init() { - if (this.server != null) { + if (server != null) { return; } if (!Bukkit.getOnlineMode()) { - Voicechat.LOGGER.warn("Running in offline mode - Voice chat encryption is not secure!", new Object[0]); + Voicechat.LOGGER.warn("Running in offline mode - Voice chat encryption is not secure!"); } + Voicechat.compatibility.registerPlayerHideEvent(this::onPlayerHide); Voicechat.compatibility.registerPlayerShowEvent(this::onPlayerShow); - this.server = new Server(); - this.server.start(); + + server = new Server(); + server.start(); PluginManager.instance().onServerStarted(); } public void onRequestSecretPacket(Player player, RequestSecretPacket packet) { - UUID playerUUID; int clientVersion = packet.getCompatibilityVersion(); Voicechat.LOGGER.info("Received secret request of {} ({})", player.getName(), clientVersion); + + UUID playerUUID; try { playerUUID = player.getUniqueId(); } catch (UnsupportedOperationException e) { @@ -56,59 +60,64 @@ public class ServerVoiceEvents implements Listener { Voicechat.LOGGER.warn("{} tried to authenticate voice chat while still connecting", player.getName()); return; } - this.clientCompatibilities.put(playerUUID, clientVersion); - if (!ServerVoiceEvents.isSupportedCompatibilityVersion(clientVersion)) { + + clientCompatibilities.put(playerUUID, clientVersion); + if (!isSupportedCompatibilityVersion(clientVersion)) { Voicechat.LOGGER.warn("Connected client {} has incompatible voice chat version (server={}, client={})", player.getName(), Voicechat.COMPATIBILITY_VERSION, clientVersion); - ServerVoiceEvents.sendIncompatibleMessage(player, clientVersion); - return; + sendIncompatibleMessage(player, clientVersion); + } else { + initializePlayerConnection(player); } - this.initializePlayerConnection(player); } private static boolean isSupportedCompatibilityVersion(int version) { - return version == LEGACY_COMPATIBILITY_VERSION || version == CURRENT_COMPATIBILITY_VERSION; + return version == LEGACY_COMPATIBILITY_VERSION || version == BuildConstants.COMPATIBILITY_VERSION; } public boolean isCompatible(Player player) { - return this.isCompatible(player.getUniqueId()); + return isCompatible(player.getUniqueId()); } public boolean isCompatible(UUID playerUuid) { - return ServerVoiceEvents.isSupportedCompatibilityVersion(this.clientCompatibilities.getOrDefault(playerUuid, -1)); + return isSupportedCompatibilityVersion(clientCompatibilities.getOrDefault(playerUuid, -1)); } public static void sendIncompatibleMessage(Player player, int clientCompatibilityVersion) { if (clientCompatibilityVersion <= 6) { - player.sendMessage(String.format(Voicechat.TRANSLATIONS.voicechatNotCompatibleMessage.get(), "2.6.x", "Simple Voice Chat")); + player.sendMessage(String.format(Voicechat.TRANSLATIONS.voicechatNotCompatibleMessage.get(), + BuildConstants.MOD_COMPATIBLE_VERSION, BuildConstants.PLUGIN_NAME)); } else { - Voicechat.compatibility.sendIncompatibleMessage(player, "2.6.x", "Simple Voice Chat"); + Voicechat.compatibility.sendIncompatibleMessage(player, + BuildConstants.MOD_COMPATIBLE_VERSION, BuildConstants.PLUGIN_NAME); } } public void initializePlayerConnection(Player player) { - if (this.server == null) { + if (server == null) { return; } UUID playerUuid = player.getUniqueId(); - this.server.getPlayerStateManager().onPlayerCompatibilityCheckSucceeded(player); - this.server.getCategoryManager().onPlayerCompatibilityCheckSucceeded(player); - this.server.getGroupManager().onPlayerCompatibilityCheckSucceeded(player); - Secret secret = this.server.generateNewSecret(playerUuid); + server.getPlayerStateManager().onPlayerCompatibilityCheckSucceeded(player); + server.getCategoryManager().onPlayerCompatibilityCheckSucceeded(player); + server.getGroupManager().onPlayerCompatibilityCheckSucceeded(player); + + Secret secret = server.generateNewSecret(playerUuid); if (secret == null) { - Voicechat.LOGGER.warn("Player already requested secret - ignoring", new Object[0]); + Voicechat.LOGGER.warn("Player already requested secret - ignoring"); return; } - secret.setLegacyProtocol(this.clientCompatibilities.getOrDefault(playerUuid, -1) == LEGACY_COMPATIBILITY_VERSION); + secret.setLegacyProtocol(clientCompatibilities.getOrDefault(playerUuid, -1) == LEGACY_COMPATIBILITY_VERSION); + String voiceHost = PluginManager.instance().getVoiceHost(player, Voicechat.SERVER_CONFIG.voiceHost.get()); - NetManager.sendToClient(player, new SecretPacket(player, secret, this.server.getPort(), Voicechat.SERVER_CONFIG, voiceHost)); + NetManager.sendToClient(player, new SecretPacket(player, secret, server.getPort(), Voicechat.SERVER_CONFIG, voiceHost)); Voicechat.LOGGER.info("Sent secret to {}", player.getName()); } @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { - this.server.getPlayerStateManager().onPlayerJoin(event); - if (!Voicechat.SERVER_CONFIG.forceVoiceChat.get().booleanValue()) { + server.getPlayerStateManager().onPlayerJoin(event); + if (!Voicechat.SERVER_CONFIG.forceVoiceChat.get()) { return; } Player player = event.getPlayer(); @@ -116,39 +125,42 @@ public class ServerVoiceEvents implements Listener { if (!player.isOnline()) { return; } - if (!this.isCompatible(player)) { - player.kickPlayer(String.format(Voicechat.TRANSLATIONS.forceVoicechatKickMessage.get(), "Simple Voice Chat", Voicechat.INSTANCE.getDescription().getVersion())); + if (!isCompatible(player)) { + player.kickPlayer(String.format(Voicechat.TRANSLATIONS.forceVoicechatKickMessage.get(), + BuildConstants.PLUGIN_NAME, Voicechat.INSTANCE.getDescription().getVersion())); } - }, (long) Voicechat.SERVER_CONFIG.loginTimeout.get().intValue() / 50L); + }, Voicechat.SERVER_CONFIG.loginTimeout.get() / 50L); } @EventHandler public void onPlayerQuit(PlayerQuitEvent event) { - this.server.getPlayerStateManager().onPlayerQuit(event); - this.server.getGroupManager().onPlayerQuit(event); + server.getPlayerStateManager().onPlayerQuit(event); + server.getGroupManager().onPlayerQuit(event); + UUID playerUuid = event.getPlayer().getUniqueId(); - this.clientCompatibilities.remove(playerUuid); - this.rateLimiter.onPlayerLoggedOut(event.getPlayer()); - if (this.server == null) { + clientCompatibilities.remove(playerUuid); + rateLimiter.onPlayerLoggedOut(event.getPlayer()); + if (server == null) { return; } - this.server.disconnectClient(playerUuid); + + server.disconnectClient(playerUuid); Voicechat.LOGGER.info("Disconnecting client {}", event.getPlayer().getName()); } public void onPlayerHide(PlayerHideEvent event) { - this.server.getPlayerStateManager().onPlayerHide(event); + server.getPlayerStateManager().onPlayerHide(event); } public void onPlayerShow(PlayerShowEvent event) { - this.server.getPlayerStateManager().onPlayerShow(event); + server.getPlayerStateManager().onPlayerShow(event); } public PacketRateLimiter getRateLimiter() { - return this.rateLimiter; + return rateLimiter; } public Server getServer() { - return this.server; + return server; } } diff --git a/source/decompiled/de/maxhenkel/voicechat/BuildConstants.java b/source/bukkit/src/template/java/de/maxhenkel/voicechat/BuildConstants.java similarity index 51% rename from source/decompiled/de/maxhenkel/voicechat/BuildConstants.java rename to source/bukkit/src/template/java/de/maxhenkel/voicechat/BuildConstants.java index e44a2f3..0905f25 100644 --- a/source/decompiled/de/maxhenkel/voicechat/BuildConstants.java +++ b/source/bukkit/src/template/java/de/maxhenkel/voicechat/BuildConstants.java @@ -1,24 +1,21 @@ -/* - * Decompiled with CFR 0.152. - */ package de.maxhenkel.voicechat; public class BuildConstants { + public static final int COMPATIBILITY_VERSION; - public static final String PLUGIN_NAME = "Simple Voice Chat"; - public static final String TARGET_BUKKIT_VERSION = "1.8.8-R0.1-SNAPSHOT"; - public static final String MOD_COMPATIBLE_VERSION = "2.6.x"; + public static final String PLUGIN_NAME = "${plugin_name}"; + public static final String TARGET_BUKKIT_VERSION = "${target_bukkit_version}"; + public static final String MOD_COMPATIBLE_VERSION = "${mod_compatible_version}"; static { + String compatibilityVersionString = "${compatibility_version}"; int compatibilityVersion; - String compatibilityVersionString = "20"; try { compatibilityVersion = Integer.parseInt(compatibilityVersionString); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { compatibilityVersion = -1; } COMPATIBILITY_VERSION = compatibilityVersion; } -} +} diff --git a/source/common/src/main/resources/assets/voicechat/lang/en_us.json b/source/common/src/main/resources/assets/voicechat/lang/en_us.json new file mode 100644 index 0000000..a78fe67 --- /dev/null +++ b/source/common/src/main/resources/assets/voicechat/lang/en_us.json @@ -0,0 +1,230 @@ +{ + "key.category.voicechat.voicechat": "Voice Chat", + "key.push_to_talk": "Push to Talk", + "key.whisper": "Whisper", + "key.mute_microphone": "Mute Microphone", + "key.disable_voice_chat": "Disable Voice Chat", + "key.hide_icons": "Hide Voice Chat Icons", + "key.voice_chat_settings": "Voice Chat Settings", + "key.voice_chat": "Voice Chat Menu", + "key.voice_chat_group": "Group Management", + "key.voice_chat_toggle_recording": "Toggle Recording", + "key.voice_chat_adjust_volumes": "Adjust Volumes", + "gui.voicechat.voice_chat.title": "Voice Chat", + "gui.voicechat.voice_chat_settings.title": "Voice Chat Settings", + "gui.voicechat.adjust_volume.title": "Adjust Volumes", + "gui.voicechat.select_microphone.title": "Select Microphone", + "gui.voicechat.select_speaker.title": "Select Speaker", + "gui.voicechat.group.title": "Group Management", + "gui.voicechat.join_create_group.title": "Join or Create Group", + "gui.voicechat.create_group.title": "Create Group", + "gui.voicechat.enter_password.title": "Enter Group Password", + "message.voicechat.settings": "Settings", + "message.voicechat.group": "Group", + "message.voicechat.voice_chat_volume": "Voice Chat Volume: %s", + "message.voicechat.gain": "Gain: %s", + "message.voicechat.gain.auto": "Auto", + "message.voicechat.gain.manual": "Manual", + "message.voicechat.gain.manual.warning": "Please keep automatic microphone gain adjustment enabled to ensure consistent volume levels for everyone hearing you.", + "message.voicechat.microphone_gain": "Microphone Gain: %s dB", + "message.voicechat.microphone_gain.warning": "Exceeding %s dB amplification may produce audio distortion and other issues!", + "message.voicechat.mic_test_unavailable": "Microphone testing unavailable!", + "message.voicechat.mic_test.disabled": "Press to enable microphone testing.", + "message.voicechat.mic_test.enabled": "Press to disable microphone testing.", + "message.voicechat.voice_chat_unavailable": "Voice chat unavailable", + "message.voicechat.voice_chat_not_connected": "Voice chat not connected", + "message.voicechat.activation_type": "Activation Method: %s", + "message.voicechat.activation_type.ptt": "Push to Talk", + "message.voicechat.activation_type.voice": "Voice", + "message.voicechat.voice_activation_detection": "Voice Activation: %s", + "message.voicechat.voice_activation_detection.auto": "Auto", + "message.voicechat.voice_activation_detection.manual": "Manual", + "message.voicechat.voice_activation": "Voice Activation Threshold: %s dB", + "message.voicechat.voice_activation.disabled": "0 dB deactivates the microphone!", + "message.voicechat.adjust_volumes": "Adjust Volumes", + "message.voicechat.volume_amplification": "Amplification: %s", + "message.voicechat.muted": "Muted", + "message.voicechat.no_microphone": "No microphones available", + "message.voicechat.default_microphone": "System Default", + "message.voicechat.no_speaker": "No speakers available", + "message.voicechat.default_speaker": "System Default", + "message.voicechat.test_speaker": "Press to play a test sound.", + "message.voicechat.select_microphone": "Select Microphone", + "message.voicechat.select_speaker": "Select Speaker", + "message.voicechat.back": "Back", + "message.voicechat.client_not_connected": "Client not connected", + "message.voicechat.failed_to_send_ping": "Failed to send ping: %s", + "message.voicechat.sending_ping": "Sending ping...", + "message.voicechat.ping_sent_waiting": "Ping sent. Waiting for response...", + "message.voicechat.ping_received": "Got a response in %s ms", + "message.voicechat.ping_received_attempt": "Got a response in %s ms after %s attempts", + "message.voicechat.ping_retry": "No response. Retrying...", + "message.voicechat.ping_timed_out": "Request timed out after %s attempts", + "message.voicechat.icons_hidden": "Voice chat icons hidden", + "message.voicechat.icons_visible": "Voice chat icons visible", + "message.voicechat.incompatible_version": "Your voice chat client version is not compatible with the server-side version.\nPlease install version %s of %s.", + "message.voicechat.incompatible": "Your voice chat client version is not compatible with the server-side version.", + "message.voicechat.group_members": "Group members:", + "message.voicechat.no_group_members": "Empty group", + "message.voicechat.join_create_group": "Join or Create Group", + "message.voicechat.group_name": "Group Name", + "message.voicechat.leave_group": "Press to leave the group.", + "message.voicechat.not_in_group": "You are not in a group", + "message.voicechat.invite": "%s invited you to the group %s. %s", + "message.voicechat.accept_invite": "ACCEPT", + "message.voicechat.accept_invite.hover": "Click to accept the invitation", + "message.voicechat.join_successful": "Successfully joined the group %s", + "message.voicechat.leave_successful": "Successfully left the group", + "message.voicechat.groups_disabled": "Groups are disabled on this server", + "message.voicechat.recording_disabled": "Recording is disabled on this server", + "message.voicechat.invite_successful": "Successfully invited %s", + "message.voicechat.processing_recording_session": "Processing recording session...", + "message.voicechat.processing_progress": "Processing %s%%", + "message.voicechat.save_session": "Saved session to %s", + "message.voicechat.save_session_failed": "Failed to save recording session: %s", + "message.voicechat.recording_started": "Started Recording", + "message.voicechat.recording_stopped": "Stopped Recording", + "message.voicechat.open_folder": "Open folder", + "message.voicechat.storage_size": "Estimated disk space usage: %s.", + "message.voicechat.microphone_unavailable": "Microphone unavailable", + "message.voicechat.speaker_unavailable": "Speaker unavailable", + "message.voicechat.playback_unavailable": "Playback unavailable", + "message.voicechat.denoiser": "Noise Suppression: %s", + "message.voicechat.denoiser.on": "ON", + "message.voicechat.denoiser.off": "OFF", + "message.voicechat.group_type_title": "%s (%s)", + "message.voicechat.group_title": "%s", + "message.voicechat.group_does_not_exist": "Such a group does not exist", + "message.voicechat.group_name_not_unique": "Group name is ambiguous", + "message.voicechat.create": "Create", + "message.voicechat.create_group": "Create Group", + "message.voicechat.create_group_button": "Create Group", + "message.voicechat.optional_password": "Password (Optional)", + "message.voicechat.group_type": "Group Type", + "message.voicechat.group_type.normal": "Normal", + "message.voicechat.group_type.normal.description": "Players who are not in your group can't hear you, but you can hear them.", + "message.voicechat.group_type.open": "Open", + "message.voicechat.group_type.open.description": "Players who are not in your group can hear you, and you can hear them too.", + "message.voicechat.group_type.isolated": "Isolated", + "message.voicechat.group_type.isolated.description": "Players who are not in your group can't hear you, and you can't hear them either.", + "message.voicechat.join_group": "Join Group", + "message.voicechat.enter_group_password": "Enter Group Password", + "message.voicechat.password": "Password", + "message.voicechat.wrong_password": "Incorrect Password", + "message.voicechat.server_port": "Voice chat server hosted on port %s", + "message.voicechat.macos_no_mic_permission": "No permission to access your microphone. Please open System Settings > Privacy & Security and check the access options there", + "message.voicechat.macos_unsupported_launcher": "Your launcher does not support macOS microphone permissions", + "message.voicechat.player_no_voicechat": "%s does not have %s installed", + "message.voicechat.mute.enabled": "Press to unmute your microphone.", + "message.voicechat.mute.disabled": "Press to mute your microphone.", + "message.voicechat.mute.disabled_ptt": "You can't mute your microphone when using push to talk.", + "message.voicechat.disable.enabled": "Press to enable all voice chat sounds.", + "message.voicechat.disable.disabled": "Press to disable all voice chat sounds.", + "message.voicechat.disable.speaker_unavailable": "Speaker unavailable.", + "message.voicechat.hide_icons.enabled": "Press to show all voice chat icons.", + "message.voicechat.hide_icons.disabled": "Press to hide all voice chat icons.", + "message.voicechat.show_group_hud.enabled": "Press to hide the group chat HUD.", + "message.voicechat.show_group_hud.disabled": "Press to show the group chat HUD.", + "message.voicechat.recording.disabled": "Press to start recording.", + "message.voicechat.recording.enabled": "Press to stop recording.", + "message.voicechat.no_speak_permission": "You do not have permission to speak", + "message.voicechat.no_listen_permission": "You do not have permission to hear the voice chat", + "message.voicechat.no_group_permission": "You do not have permission to join groups", + "message.voicechat.search_hint": "Search...", + "message.voicechat.search_empty": "Couldn't find any players with that name", + "message.voicechat.other_volume": "Other", + "message.voicechat.other_volume.description": "The volume of any sound not listed below.", + "message.voicechat.more_members": "and %s more...", + "message.voicechat.no_groups": "No existing groups", + "message.voicechat.audio_type": "3D Audio: %s", + "message.voicechat.audio_type.normal": "Normal", + "message.voicechat.audio_type.reduced": "Reduced", + "message.voicechat.audio_type.off": "OFF", + "message.voicechat.invite_player": "Press to invite %s to your group.", + "message.voicechat.press_to_reassign_key": "Press to assign a key.", + "message.voicechat.native_error": "Some modules failed to load - Your Operating System might not be supported.", + "message.voicechat.set_up": "Press %s to set up", + "message.voicechat.onboarding.reset": "Onboarding status has been reset", + "message.voicechat.onboarding.next": "Next", + "message.voicechat.onboarding.confirm": "Confirm", + "message.voicechat.onboarding.back": "Back", + "message.voicechat.onboarding.cancel": "Cancel", + "message.voicechat.onboarding.introduction.title": "Set Up %s", + "message.voicechat.onboarding.introduction.description": "This setup guide will help you configure your voice chat.\n\nYou can skip it if you know what you are doing.", + "message.voicechat.onboarding.introduction.skip": "I Know What I Am Doing - Skip", + "message.voicechat.onboarding.skip.title": "Skip Setup", + "message.voicechat.onboarding.skip.description": "Are you sure you want to skip this setup guide?\n\nIf you skip it, you will have to adjust all the settings manually!", + "message.voicechat.onboarding.microphone": "Select Microphone", + "message.voicechat.onboarding.speaker": "Select Speaker", + "message.voicechat.onboarding.activation.title": "Select Activation Method", + "message.voicechat.onboarding.activation": "Please choose the method to activate your microphone.", + "message.voicechat.onboarding.activation.ptt": "When selecting %s, you need to press and hold a button to speak.", + "message.voicechat.onboarding.activation.ptt.name": "Push to Talk", + "message.voicechat.onboarding.activation.voice": "%s automatically activates your microphone when you speak.", + "message.voicechat.onboarding.activation.voice.name": "Voice Activation", + "message.voicechat.onboarding.ptt.title": "Choose Push to Talk Keybind", + "message.voicechat.onboarding.ptt.description": "Please choose the key that should be used to activate your microphone.", + "message.voicechat.onboarding.ptt.button_description": "Press to assign", + "message.voicechat.onboarding.voice.title": "Adjust Voice Activation", + "message.voicechat.onboarding.voice.description": "Enable microphone testing and make sure you can hear your voice when speaking. If this doesn't work, use manual voice activation and adjust the voice activation threshold.", + "message.voicechat.onboarding.final": "Finish Setup", + "message.voicechat.onboarding.final.description.success": "You have successfully configured your voice chat!\n\nOpen the voice chat menu with %s.", + "message.voicechat.onboarding.final.description.ptt": "Hold %s while speaking to use the voice chat.", + "message.voicechat.onboarding.final.description.voice": "You will be muted after exiting this screen. Press %s to unmute.", + "message.voicechat.onboarding.final.description.configuration": "You can always change all the settings in the voice chat menu.\nKeybinds, however, can be changed just like any other keybind in the game.", + "message.voicechat.onboarding.final.finish_setup": "Finish Setup", + "resourcepack.voicechat.classic_icons": "Classic Icons", + "resourcepack.voicechat.classic_icons.description": "Classic voice chat icons", + "resourcepack.voicechat.white_icons": "White Icons", + "resourcepack.voicechat.white_icons.description": "White voice chat icons", + "resourcepack.voicechat.black_icons": "Black Icons", + "resourcepack.voicechat.black_icons.description": "Black voice chat icons", + "cloth_config.voicechat.settings": "Voice Chat Settings", + "cloth_config.voicechat.category.general": "General", + "cloth_config.voicechat.category.audio": "Audio", + "cloth_config.voicechat.category.hud_icons": "HUD Icons", + "cloth_config.voicechat.category.group_chat_icons": "Group Chat Icons", + "cloth_config.voicechat.category.ingame_menu": "In-Game Menu", + "cloth_config.voicechat.config.recording_destination": "Recording destination", + "cloth_config.voicechat.config.recording_destination.description": "The location where recordings should be saved.\nLeave blank to use the default location.", + "cloth_config.voicechat.config.run_local_server": "Run in singleplayer or LAN worlds", + "cloth_config.voicechat.config.run_local_server.description": "If the voice chat should work in singleplayer or in worlds shared over LAN.", + "cloth_config.voicechat.config.offline_player_volume_adjustment": "Offline player volume adjustment", + "cloth_config.voicechat.config.offline_player_volume_adjustment.description": "If the volume adjustment interface should also display offline players.", + "cloth_config.voicechat.config.freecam_mode": "Freecam mode", + "cloth_config.voicechat.config.freecam_mode.description": "How listening to other players should work when using freecam mods.\nCAMERA: You will hear the voice chat around your camera. Whether you will still be able to hear the voice chat when the camera is far away from your character depends on the voice chat broadcast range of the server.\nPLAYER: You will hear the voice chat around your character no matter where your camera is.", + "cloth_config.voicechat.config.freecam_mode.camera": "Camera", + "cloth_config.voicechat.config.freecam_mode.player": "Player", + "cloth_config.voicechat.config.mute_on_join": "Mute on join", + "cloth_config.voicechat.config.mute_on_join.description": "If enabled, you will be automatically muted when joining a world.", + "cloth_config.voicechat.config.audio_packet_threshold": "Audio packet threshold", + "cloth_config.voicechat.config.audio_packet_threshold.description": "The maximum number of audio packets that should be held back if a packet arrives out of order or is dropped.\nThis prevents audio packets that are only slightly out of order from being discarded.\nSet this to 0 to disable.", + "cloth_config.voicechat.config.voice_deactivation_delay": "Microphone deactivation delay", + "cloth_config.voicechat.config.voice_deactivation_delay.description": "The time it takes for the microphone to deactivate when using voice activation.\nA value of 1 means 20 milliseconds, 2=40 ms, 3=60 ms, and so on.", + "cloth_config.voicechat.config.ptt_deactivation_delay": "Push to talk deactivation delay", + "cloth_config.voicechat.config.ptt_deactivation_delay.description": "The time it takes for the microphone to deactivate when using push to talk.\nA value of 1 means 20 milliseconds, 2=40 ms, 3=60 ms, and so on.", + "cloth_config.voicechat.config.output_buffer_size": "Output buffer size", + "cloth_config.voicechat.config.output_buffer_size.description": "The size of the audio output buffer (in packets).\nHigher values mean a higher latency but less crackling.\nIncrease this value if you have an unstable internet connection.", + "cloth_config.voicechat.config.show_nametag_icons": "Show voice chat name tag icons", + "cloth_config.voicechat.config.show_nametag_icons.description": "If the voice chat icons next to player names should be visible", + "cloth_config.voicechat.config.show_hud_icons": "Show voice chat HUD icons", + "cloth_config.voicechat.config.show_hud_icons.description": "If the voice chat icons on the HUD should be visible", + "cloth_config.voicechat.config.hud_icon_scale": "Voice chat HUD icon scale", + "cloth_config.voicechat.config.hud_icon_scale.description": "The scale of the icons in the voice chat HUD, such as microphone or connection status.", + "cloth_config.voicechat.config.hud_icon_pos_x": "Voice chat HUD icon X position", + "cloth_config.voicechat.config.hud_icon_pos_x.description": "The X position of the icons in the voice chat HUD.\nNegative values mean anchoring to the right instead.", + "cloth_config.voicechat.config.hud_icon_pos_y": "Voice chat HUD icon Y position", + "cloth_config.voicechat.config.hud_icon_pos_y.description": "The Y position of the icons in the voice chat HUD.\nNegative values mean anchoring to the bottom instead.", + "cloth_config.voicechat.config.group_player_icon_orientation": "Group chat HUD icon orientation", + "cloth_config.voicechat.config.group_player_icon_orientation.description": "The orientation of the player icons in the group chat HUD.", + "cloth_config.voicechat.config.group_player_icon_orientation.vertical": "Vertical", + "cloth_config.voicechat.config.group_player_icon_orientation.horizontal": "Horizontal", + "cloth_config.voicechat.config.group_hud_icon_scale": "Group chat HUD icon scale", + "cloth_config.voicechat.config.group_hud_icon_scale.description": "The scale of the player icons in the group chat HUD.", + "cloth_config.voicechat.config.group_player_icon_pos_x": "Group chat HUD icon X position", + "cloth_config.voicechat.config.group_player_icon_pos_x.description": "The X position of the player icons in the group chat HUD.\nNegative values mean anchoring to the right instead.", + "cloth_config.voicechat.config.group_player_icon_pos_y": "Group chat HUD icon Y position", + "cloth_config.voicechat.config.group_player_icon_pos_y.description": "The Y position of the player icons in the group chat HUD.\nNegative values mean anchoring to the bottom instead.", + "cloth_config.voicechat.config.show_own_group_icon": "Show yourself in the group chat HUD", + "cloth_config.voicechat.config.show_own_group_icon.description": "If your own player icon should be displayed in the group chat HUD when you are in a group." +} diff --git a/source/decompiled/de/maxhenkel/voicechat/FallbackTranslations.java b/source/decompiled/de/maxhenkel/voicechat/FallbackTranslations.java deleted file mode 100644 index b2e6438..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/FallbackTranslations.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class FallbackTranslations { - public static final Map FALLBACK_TRANSLATIONS; - - static { - HashMap translations = new HashMap(); - translations.put("key.category.voicechat.voicechat", "Voice Chat"); - translations.put("key.push_to_talk", "Push to Talk"); - translations.put("key.whisper", "Whisper"); - translations.put("key.mute_microphone", "Mute Microphone"); - translations.put("key.disable_voice_chat", "Disable Voice Chat"); - translations.put("key.hide_icons", "Hide Voice Chat Icons"); - translations.put("key.voice_chat_settings", "Voice Chat Settings"); - translations.put("key.voice_chat", "Voice Chat Menu"); - translations.put("key.voice_chat_group", "Group Management"); - translations.put("key.voice_chat_toggle_recording", "Toggle Recording"); - translations.put("key.voice_chat_adjust_volumes", "Adjust Volumes"); - translations.put("gui.voicechat.voice_chat.title", "Voice Chat"); - translations.put("gui.voicechat.voice_chat_settings.title", "Voice Chat Settings"); - translations.put("gui.voicechat.adjust_volume.title", "Adjust Volumes"); - translations.put("gui.voicechat.select_microphone.title", "Select Microphone"); - translations.put("gui.voicechat.select_speaker.title", "Select Speaker"); - translations.put("gui.voicechat.group.title", "Group Management"); - translations.put("gui.voicechat.join_create_group.title", "Join or Create Group"); - translations.put("gui.voicechat.create_group.title", "Create Group"); - translations.put("gui.voicechat.enter_password.title", "Enter Group Password"); - translations.put("message.voicechat.settings", "Settings"); - translations.put("message.voicechat.group", "Group"); - translations.put("message.voicechat.voice_chat_volume", "Voice Chat Volume: %s"); - translations.put("message.voicechat.gain", "Gain: %s"); - translations.put("message.voicechat.gain.auto", "Auto"); - translations.put("message.voicechat.gain.manual", "Manual"); - translations.put("message.voicechat.gain.manual.warning", "Please keep automatic microphone gain adjustment enabled to ensure consistent volume levels for everyone hearing you."); - translations.put("message.voicechat.microphone_gain", "Microphone Gain: %s dB"); - translations.put("message.voicechat.microphone_gain.warning", "Exceeding %s dB amplification may produce audio distortion and other issues!"); - translations.put("message.voicechat.mic_test_unavailable", "Microphone testing unavailable!"); - translations.put("message.voicechat.mic_test.disabled", "Press to enable microphone testing."); - translations.put("message.voicechat.mic_test.enabled", "Press to disable microphone testing."); - translations.put("message.voicechat.voice_chat_unavailable", "Voice chat unavailable"); - translations.put("message.voicechat.voice_chat_not_connected", "Voice chat not connected"); - translations.put("message.voicechat.activation_type", "Activation Method: %s"); - translations.put("message.voicechat.activation_type.ptt", "Push to Talk"); - translations.put("message.voicechat.activation_type.voice", "Voice"); - translations.put("message.voicechat.voice_activation_detection", "Voice Activation: %s"); - translations.put("message.voicechat.voice_activation_detection.auto", "Auto"); - translations.put("message.voicechat.voice_activation_detection.manual", "Manual"); - translations.put("message.voicechat.voice_activation", "Voice Activation Threshold: %s dB"); - translations.put("message.voicechat.voice_activation.disabled", "0 dB deactivates the microphone!"); - translations.put("message.voicechat.adjust_volumes", "Adjust Volumes"); - translations.put("message.voicechat.volume_amplification", "Amplification: %s"); - translations.put("message.voicechat.muted", "Muted"); - translations.put("message.voicechat.no_microphone", "No microphones available"); - translations.put("message.voicechat.default_microphone", "System Default"); - translations.put("message.voicechat.no_speaker", "No speakers available"); - translations.put("message.voicechat.default_speaker", "System Default"); - translations.put("message.voicechat.test_speaker", "Press to play a test sound."); - translations.put("message.voicechat.select_microphone", "Select Microphone"); - translations.put("message.voicechat.select_speaker", "Select Speaker"); - translations.put("message.voicechat.back", "Back"); - translations.put("message.voicechat.client_not_connected", "Client not connected"); - translations.put("message.voicechat.failed_to_send_ping", "Failed to send ping: %s"); - translations.put("message.voicechat.sending_ping", "Sending ping..."); - translations.put("message.voicechat.ping_sent_waiting", "Ping sent. Waiting for response..."); - translations.put("message.voicechat.ping_received", "Got a response in %s ms"); - translations.put("message.voicechat.ping_received_attempt", "Got a response in %s ms after %s attempts"); - translations.put("message.voicechat.ping_retry", "No response. Retrying..."); - translations.put("message.voicechat.ping_timed_out", "Request timed out after %s attempts"); - translations.put("message.voicechat.icons_hidden", "Voice chat icons hidden"); - translations.put("message.voicechat.icons_visible", "Voice chat icons visible"); - translations.put("message.voicechat.incompatible_version", "Your voice chat client version is not compatible with the server-side version.\nPlease install version %s of %s."); - translations.put("message.voicechat.incompatible", "Your voice chat client version is not compatible with the server-side version."); - translations.put("message.voicechat.group_members", "Group members:"); - translations.put("message.voicechat.no_group_members", "Empty group"); - translations.put("message.voicechat.join_create_group", "Join or Create Group"); - translations.put("message.voicechat.group_name", "Group Name"); - translations.put("message.voicechat.leave_group", "Press to leave the group."); - translations.put("message.voicechat.not_in_group", "You are not in a group"); - translations.put("message.voicechat.invite", "%s invited you to the group %s. %s"); - translations.put("message.voicechat.accept_invite", "ACCEPT"); - translations.put("message.voicechat.accept_invite.hover", "Click to accept the invitation"); - translations.put("message.voicechat.join_successful", "Successfully joined the group %s"); - translations.put("message.voicechat.leave_successful", "Successfully left the group"); - translations.put("message.voicechat.groups_disabled", "Groups are disabled on this server"); - translations.put("message.voicechat.recording_disabled", "Recording is disabled on this server"); - translations.put("message.voicechat.invite_successful", "Successfully invited %s"); - translations.put("message.voicechat.processing_recording_session", "Processing recording session..."); - translations.put("message.voicechat.processing_progress", "Processing %s%%"); - translations.put("message.voicechat.save_session", "Saved session to %s"); - translations.put("message.voicechat.save_session_failed", "Failed to save recording session: %s"); - translations.put("message.voicechat.recording_started", "Started Recording"); - translations.put("message.voicechat.recording_stopped", "Stopped Recording"); - translations.put("message.voicechat.open_folder", "Open folder"); - translations.put("message.voicechat.storage_size", "Estimated disk space usage: %s."); - translations.put("message.voicechat.microphone_unavailable", "Microphone unavailable"); - translations.put("message.voicechat.speaker_unavailable", "Speaker unavailable"); - translations.put("message.voicechat.playback_unavailable", "Playback unavailable"); - translations.put("message.voicechat.denoiser", "Noise Suppression: %s"); - translations.put("message.voicechat.denoiser.on", "ON"); - translations.put("message.voicechat.denoiser.off", "OFF"); - translations.put("message.voicechat.group_type_title", "%s (%s)"); - translations.put("message.voicechat.group_title", "%s"); - translations.put("message.voicechat.group_does_not_exist", "Such a group does not exist"); - translations.put("message.voicechat.group_name_not_unique", "Group name is ambiguous"); - translations.put("message.voicechat.create", "Create"); - translations.put("message.voicechat.create_group", "Create Group"); - translations.put("message.voicechat.create_group_button", "Create Group"); - translations.put("message.voicechat.optional_password", "Password (Optional)"); - translations.put("message.voicechat.group_type", "Group Type"); - translations.put("message.voicechat.group_type.normal", "Normal"); - translations.put("message.voicechat.group_type.normal.description", "Players who are not in your group can't hear you, but you can hear them."); - translations.put("message.voicechat.group_type.open", "Open"); - translations.put("message.voicechat.group_type.open.description", "Players who are not in your group can hear you, and you can hear them too."); - translations.put("message.voicechat.group_type.isolated", "Isolated"); - translations.put("message.voicechat.group_type.isolated.description", "Players who are not in your group can't hear you, and you can't hear them either."); - translations.put("message.voicechat.join_group", "Join Group"); - translations.put("message.voicechat.enter_group_password", "Enter Group Password"); - translations.put("message.voicechat.password", "Password"); - translations.put("message.voicechat.wrong_password", "Incorrect Password"); - translations.put("message.voicechat.server_port", "Voice chat server hosted on port %s"); - translations.put("message.voicechat.macos_no_mic_permission", "No permission to access your microphone. Please open System Settings > Privacy & Security and check the access options there"); - translations.put("message.voicechat.macos_unsupported_launcher", "Your launcher does not support macOS microphone permissions"); - translations.put("message.voicechat.player_no_voicechat", "%s does not have %s installed"); - translations.put("message.voicechat.mute.enabled", "Press to unmute your microphone."); - translations.put("message.voicechat.mute.disabled", "Press to mute your microphone."); - translations.put("message.voicechat.mute.disabled_ptt", "You can't mute your microphone when using push to talk."); - translations.put("message.voicechat.disable.enabled", "Press to enable all voice chat sounds."); - translations.put("message.voicechat.disable.disabled", "Press to disable all voice chat sounds."); - translations.put("message.voicechat.disable.speaker_unavailable", "Speaker unavailable."); - translations.put("message.voicechat.hide_icons.enabled", "Press to show all voice chat icons."); - translations.put("message.voicechat.hide_icons.disabled", "Press to hide all voice chat icons."); - translations.put("message.voicechat.show_group_hud.enabled", "Press to hide the group chat HUD."); - translations.put("message.voicechat.show_group_hud.disabled", "Press to show the group chat HUD."); - translations.put("message.voicechat.recording.disabled", "Press to start recording."); - translations.put("message.voicechat.recording.enabled", "Press to stop recording."); - translations.put("message.voicechat.no_speak_permission", "You do not have permission to speak"); - translations.put("message.voicechat.no_listen_permission", "You do not have permission to hear the voice chat"); - translations.put("message.voicechat.no_group_permission", "You do not have permission to join groups"); - translations.put("message.voicechat.search_hint", "Search..."); - translations.put("message.voicechat.search_empty", "Couldn't find any players with that name"); - translations.put("message.voicechat.other_volume", "Other"); - translations.put("message.voicechat.other_volume.description", "The volume of any sound not listed below."); - translations.put("message.voicechat.more_members", "and %s more..."); - translations.put("message.voicechat.no_groups", "No existing groups"); - translations.put("message.voicechat.audio_type", "3D Audio: %s"); - translations.put("message.voicechat.audio_type.normal", "Normal"); - translations.put("message.voicechat.audio_type.reduced", "Reduced"); - translations.put("message.voicechat.audio_type.off", "OFF"); - translations.put("message.voicechat.invite_player", "Press to invite %s to your group."); - translations.put("message.voicechat.press_to_reassign_key", "Press to assign a key."); - translations.put("message.voicechat.native_error", "Some modules failed to load - Your Operating System might not be supported."); - translations.put("message.voicechat.set_up", "Press %s to set up"); - translations.put("message.voicechat.onboarding.reset", "Onboarding status has been reset"); - translations.put("message.voicechat.onboarding.next", "Next"); - translations.put("message.voicechat.onboarding.confirm", "Confirm"); - translations.put("message.voicechat.onboarding.back", "Back"); - translations.put("message.voicechat.onboarding.cancel", "Cancel"); - translations.put("message.voicechat.onboarding.introduction.title", "Set Up %s"); - translations.put("message.voicechat.onboarding.introduction.description", "This setup guide will help you configure your voice chat.\n\nYou can skip it if you know what you are doing."); - translations.put("message.voicechat.onboarding.introduction.skip", "I Know What I Am Doing - Skip"); - translations.put("message.voicechat.onboarding.skip.title", "Skip Setup"); - translations.put("message.voicechat.onboarding.skip.description", "Are you sure you want to skip this setup guide?\n\nIf you skip it, you will have to adjust all the settings manually!"); - translations.put("message.voicechat.onboarding.microphone", "Select Microphone"); - translations.put("message.voicechat.onboarding.speaker", "Select Speaker"); - translations.put("message.voicechat.onboarding.activation.title", "Select Activation Method"); - translations.put("message.voicechat.onboarding.activation", "Please choose the method to activate your microphone."); - translations.put("message.voicechat.onboarding.activation.ptt", "When selecting %s, you need to press and hold a button to speak."); - translations.put("message.voicechat.onboarding.activation.ptt.name", "Push to Talk"); - translations.put("message.voicechat.onboarding.activation.voice", "%s automatically activates your microphone when you speak."); - translations.put("message.voicechat.onboarding.activation.voice.name", "Voice Activation"); - translations.put("message.voicechat.onboarding.ptt.title", "Choose Push to Talk Keybind"); - translations.put("message.voicechat.onboarding.ptt.description", "Please choose the key that should be used to activate your microphone."); - translations.put("message.voicechat.onboarding.ptt.button_description", "Press to assign"); - translations.put("message.voicechat.onboarding.voice.title", "Adjust Voice Activation"); - translations.put("message.voicechat.onboarding.voice.description", "Enable microphone testing and make sure you can hear your voice when speaking. If this doesn't work, use manual voice activation and adjust the voice activation threshold."); - translations.put("message.voicechat.onboarding.final", "Finish Setup"); - translations.put("message.voicechat.onboarding.final.description.success", "You have successfully configured your voice chat!\n\nOpen the voice chat menu with %s."); - translations.put("message.voicechat.onboarding.final.description.ptt", "Hold %s while speaking to use the voice chat."); - translations.put("message.voicechat.onboarding.final.description.voice", "You will be muted after exiting this screen. Press %s to unmute."); - translations.put("message.voicechat.onboarding.final.description.configuration", "You can always change all the settings in the voice chat menu.\nKeybinds, however, can be changed just like any other keybind in the game."); - translations.put("message.voicechat.onboarding.final.finish_setup", "Finish Setup"); - translations.put("resourcepack.voicechat.classic_icons", "Classic Icons"); - translations.put("resourcepack.voicechat.classic_icons.description", "Classic voice chat icons"); - translations.put("resourcepack.voicechat.white_icons", "White Icons"); - translations.put("resourcepack.voicechat.white_icons.description", "White voice chat icons"); - translations.put("resourcepack.voicechat.black_icons", "Black Icons"); - translations.put("resourcepack.voicechat.black_icons.description", "Black voice chat icons"); - translations.put("cloth_config.voicechat.settings", "Voice Chat Settings"); - translations.put("cloth_config.voicechat.category.general", "General"); - translations.put("cloth_config.voicechat.category.audio", "Audio"); - translations.put("cloth_config.voicechat.category.hud_icons", "HUD Icons"); - translations.put("cloth_config.voicechat.category.group_chat_icons", "Group Chat Icons"); - translations.put("cloth_config.voicechat.category.ingame_menu", "In-Game Menu"); - translations.put("cloth_config.voicechat.config.recording_destination", "Recording destination"); - translations.put("cloth_config.voicechat.config.recording_destination.description", "The location where recordings should be saved.\nLeave blank to use the default location."); - translations.put("cloth_config.voicechat.config.run_local_server", "Run in singleplayer or LAN worlds"); - translations.put("cloth_config.voicechat.config.run_local_server.description", "If the voice chat should work in singleplayer or in worlds shared over LAN."); - translations.put("cloth_config.voicechat.config.offline_player_volume_adjustment", "Offline player volume adjustment"); - translations.put("cloth_config.voicechat.config.offline_player_volume_adjustment.description", "If the volume adjustment interface should also display offline players."); - translations.put("cloth_config.voicechat.config.freecam_mode", "Freecam mode"); - translations.put("cloth_config.voicechat.config.freecam_mode.description", "How listening to other players should work when using freecam mods.\nCAMERA: You will hear the voice chat around your camera. Whether you will still be able to hear the voice chat when the camera is far away from your character depends on the voice chat broadcast range of the server.\nPLAYER: You will hear the voice chat around your character no matter where your camera is."); - translations.put("cloth_config.voicechat.config.freecam_mode.camera", "Camera"); - translations.put("cloth_config.voicechat.config.freecam_mode.player", "Player"); - translations.put("cloth_config.voicechat.config.mute_on_join", "Mute on join"); - translations.put("cloth_config.voicechat.config.mute_on_join.description", "If enabled, you will be automatically muted when joining a world."); - translations.put("cloth_config.voicechat.config.audio_packet_threshold", "Audio packet threshold"); - translations.put("cloth_config.voicechat.config.audio_packet_threshold.description", "The maximum number of audio packets that should be held back if a packet arrives out of order or is dropped.\nThis prevents audio packets that are only slightly out of order from being discarded.\nSet this to 0 to disable."); - translations.put("cloth_config.voicechat.config.voice_deactivation_delay", "Microphone deactivation delay"); - translations.put("cloth_config.voicechat.config.voice_deactivation_delay.description", "The time it takes for the microphone to deactivate when using voice activation.\nA value of 1 means 20 milliseconds, 2=40 ms, 3=60 ms, and so on."); - translations.put("cloth_config.voicechat.config.ptt_deactivation_delay", "Push to talk deactivation delay"); - translations.put("cloth_config.voicechat.config.ptt_deactivation_delay.description", "The time it takes for the microphone to deactivate when using push to talk.\nA value of 1 means 20 milliseconds, 2=40 ms, 3=60 ms, and so on."); - translations.put("cloth_config.voicechat.config.output_buffer_size", "Output buffer size"); - translations.put("cloth_config.voicechat.config.output_buffer_size.description", "The size of the audio output buffer (in packets).\nHigher values mean a higher latency but less crackling.\nIncrease this value if you have an unstable internet connection."); - translations.put("cloth_config.voicechat.config.show_nametag_icons", "Show voice chat name tag icons"); - translations.put("cloth_config.voicechat.config.show_nametag_icons.description", "If the voice chat icons next to player names should be visible"); - translations.put("cloth_config.voicechat.config.show_hud_icons", "Show voice chat HUD icons"); - translations.put("cloth_config.voicechat.config.show_hud_icons.description", "If the voice chat icons on the HUD should be visible"); - translations.put("cloth_config.voicechat.config.hud_icon_scale", "Voice chat HUD icon scale"); - translations.put("cloth_config.voicechat.config.hud_icon_scale.description", "The scale of the icons in the voice chat HUD, such as microphone or connection status."); - translations.put("cloth_config.voicechat.config.hud_icon_pos_x", "Voice chat HUD icon X position"); - translations.put("cloth_config.voicechat.config.hud_icon_pos_x.description", "The X position of the icons in the voice chat HUD.\nNegative values mean anchoring to the right instead."); - translations.put("cloth_config.voicechat.config.hud_icon_pos_y", "Voice chat HUD icon Y position"); - translations.put("cloth_config.voicechat.config.hud_icon_pos_y.description", "The Y position of the icons in the voice chat HUD.\nNegative values mean anchoring to the bottom instead."); - translations.put("cloth_config.voicechat.config.group_player_icon_orientation", "Group chat HUD icon orientation"); - translations.put("cloth_config.voicechat.config.group_player_icon_orientation.description", "The orientation of the player icons in the group chat HUD."); - translations.put("cloth_config.voicechat.config.group_player_icon_orientation.vertical", "Vertical"); - translations.put("cloth_config.voicechat.config.group_player_icon_orientation.horizontal", "Horizontal"); - translations.put("cloth_config.voicechat.config.group_hud_icon_scale", "Group chat HUD icon scale"); - translations.put("cloth_config.voicechat.config.group_hud_icon_scale.description", "The scale of the player icons in the group chat HUD."); - translations.put("cloth_config.voicechat.config.group_player_icon_pos_x", "Group chat HUD icon X position"); - translations.put("cloth_config.voicechat.config.group_player_icon_pos_x.description", "The X position of the player icons in the group chat HUD.\nNegative values mean anchoring to the right instead."); - translations.put("cloth_config.voicechat.config.group_player_icon_pos_y", "Group chat HUD icon Y position"); - translations.put("cloth_config.voicechat.config.group_player_icon_pos_y.description", "The Y position of the player icons in the group chat HUD.\nNegative values mean anchoring to the bottom instead."); - translations.put("cloth_config.voicechat.config.show_own_group_icon", "Show yourself in the group chat HUD"); - translations.put("cloth_config.voicechat.config.show_own_group_icon.description", "If your own player icon should be displayed in the group chat HUD when you are in a group."); - FALLBACK_TRANSLATIONS = Collections.unmodifiableMap(translations); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/Voicechat.java b/source/decompiled/de/maxhenkel/voicechat/Voicechat.java deleted file mode 100644 index 366a02a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/Voicechat.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.Bukkit - * org.bukkit.command.CommandExecutor - * org.bukkit.command.PluginCommand - * org.bukkit.command.TabCompleter - * org.bukkit.event.Listener - * org.bukkit.plugin.Plugin - * org.bukkit.plugin.ServicePriority - * org.bukkit.plugin.java.JavaPlugin - */ -package de.maxhenkel.voicechat; - -import de.maxhenkel.voicechat.BuildConstants; -import de.maxhenkel.voicechat.api.BukkitVoicechatService; -import de.maxhenkel.voicechat.command.VoiceChatCommands; -import de.maxhenkel.voicechat.commodore.Commodore; -import de.maxhenkel.voicechat.commodore.CommodoreProvider; -import de.maxhenkel.voicechat.compatibility.BukkitCompatibilityManager; -import de.maxhenkel.voicechat.compatibility.Compatibility; -import de.maxhenkel.voicechat.config.ServerConfig; -import de.maxhenkel.voicechat.config.Translations; -import de.maxhenkel.voicechat.configbuilder.ConfigBuilder; -import de.maxhenkel.voicechat.integration.commodore.CommodoreCommands; -import de.maxhenkel.voicechat.integration.commodore.MissingArgumentTypeException; -import de.maxhenkel.voicechat.integration.placeholderapi.VoicechatExpansion; -import de.maxhenkel.voicechat.integration.viaversion.ViaVersionCompatibility; -import de.maxhenkel.voicechat.logging.JavaLoggingLogger; -import de.maxhenkel.voicechat.logging.VoicechatLogger; -import de.maxhenkel.voicechat.net.NetManager; -import de.maxhenkel.voicechat.plugins.PluginManager; -import de.maxhenkel.voicechat.plugins.impl.BukkitVoicechatServiceImpl; -import de.maxhenkel.voicechat.voice.server.ServerPlayerManager; -import de.maxhenkel.voicechat.voice.server.ServerVoiceEvents; -import java.util.regex.Pattern; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.PluginCommand; -import org.bukkit.command.TabCompleter; -import org.bukkit.event.Listener; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.ServicePriority; -import org.bukkit.plugin.java.JavaPlugin; - -public final class Voicechat -extends JavaPlugin { - public static Voicechat INSTANCE; - public static final String MODID = "voicechat"; - public static VoicechatLogger LOGGER; - public static int COMPATIBILITY_VERSION; - public static ServerConfig SERVER_CONFIG; - public static Translations TRANSLATIONS; - public static ServerVoiceEvents SERVER; - public static BukkitVoicechatServiceImpl apiService; - public static NetManager netManager; - public static Compatibility compatibility; - public static final int MAX_GROUP_NAME_LENGTH = 24; - public static final Pattern GROUP_REGEX; - - public void onEnable() { - block17: { - INSTANCE = this; - LOGGER = new JavaLoggingLogger(this.getLogger()); - if (Voicechat.debugMode()) { - LOGGER.warn("Running in debug mode - Don't leave this enabled in production!", new Object[0]); - } - try { - compatibility = BukkitCompatibilityManager.loadCompatibility(); - if (compatibility == null) { - this.disablePlugin(); - return; - } - } - catch (Throwable t) { - LOGGER.fatal("An unexpected error occurred while loading compatibility", t); - this.disablePlugin(); - return; - } - LOGGER.info("Compatibility version {}", COMPATIBILITY_VERSION); - SERVER_CONFIG = ConfigBuilder.builder(ServerConfig::new).path(this.getDataFolder().toPath().resolve("voicechat-server.properties")).build(); - TRANSLATIONS = ConfigBuilder.builder(Translations::new).path(this.getDataFolder().toPath().resolve("translations.properties")).build(); - netManager = new NetManager(); - netManager.onEnable(); - apiService = new BukkitVoicechatServiceImpl(); - this.getServer().getServicesManager().register(BukkitVoicechatService.class, (Object)apiService, (Plugin)this, ServicePriority.Normal); - PluginCommand voicechatCommand = this.getCommand(MODID); - if (voicechatCommand != null) { - VoiceChatCommands voiceChatCommands = new VoiceChatCommands(); - voicechatCommand.setExecutor((CommandExecutor)voiceChatCommands); - voicechatCommand.setTabCompleter((TabCompleter)voiceChatCommands); - try { - if (CommodoreProvider.isSupported()) { - Commodore commodore = CommodoreProvider.getCommodore((Plugin)this); - CommodoreCommands.registerCompletions(commodore); - LOGGER.info("Successfully initialized commodore command completion", new Object[0]); - break block17; - } - LOGGER.warn("Commodore command completion is not supported", new Object[0]); - } - catch (MissingArgumentTypeException t) { - LOGGER.warn("Failed to initialize commodore command completion: {}", t.getMessage()); - } - catch (Throwable t) { - LOGGER.warn("Failed to initialize commodore command completion", t); - } - } else { - LOGGER.error("Failed to register commands", new Object[0]); - } - } - try { - if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { - new VoicechatExpansion().register(); - LOGGER.info("Successfully registered PlaceholderAPI expansion", new Object[0]); - } - } - catch (Throwable t) { - LOGGER.error("Failed to register PlaceholderAPI expansion", t); - } - try { - if (Bukkit.getPluginManager().getPlugin("ViaVersion") != null) { - ViaVersionCompatibility.register(); - LOGGER.info("Successfully added ViaVersion mappings", new Object[0]); - } - } - catch (Throwable t) { - LOGGER.error("Failed to add ViaVersion mappings", t); - } - if (System.getProperty("VOICECHAT_RELOADED") != null) { - LOGGER.error("{} does not support reloads! Expect that things will break!", "Simple Voice Chat"); - } - System.setProperty("VOICECHAT_RELOADED", "true"); - compatibility.runTask(() -> { - SERVER = new ServerVoiceEvents(); - PluginManager.instance().init(); - SERVER.init(); - Bukkit.getPluginManager().registerEvents((Listener)SERVER, (Plugin)this); - ServerPlayerManager.init((Plugin)this); - }); - } - - private void disablePlugin() { - LOGGER.fatal("Disabling {}", "Simple Voice Chat"); - Bukkit.getPluginManager().disablePlugin((Plugin)this); - } - - public void onDisable() { - if (netManager != null) { - netManager.onDisable(); - } - this.getServer().getServicesManager().unregister((Object)apiService); - if (SERVER != null) { - SERVER.getServer().close(); - } - } - - public static boolean debugMode() { - return System.getProperty("voicechat.debug") != null; - } - - static { - COMPATIBILITY_VERSION = BuildConstants.COMPATIBILITY_VERSION; - GROUP_REGEX = Pattern.compile("^[^\\p{C}\\s][^\\p{C}]{0,23}$"); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/BukkitVoicechatService.java b/source/decompiled/de/maxhenkel/voicechat/api/BukkitVoicechatService.java deleted file mode 100644 index 2a519a9..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/BukkitVoicechatService.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.VoicechatPlugin; - -public interface BukkitVoicechatService { - public void registerPlugin(VoicechatPlugin var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/ClientVoicechatSocket.java b/source/decompiled/de/maxhenkel/voicechat/api/ClientVoicechatSocket.java deleted file mode 100644 index b163f31..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/ClientVoicechatSocket.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.RawUdpPacket; -import java.net.SocketAddress; - -public interface ClientVoicechatSocket { - public void open() throws Exception; - - public RawUdpPacket read() throws Exception; - - public void send(byte[] var1, SocketAddress var2) throws Exception; - - public void close(); - - public boolean isClosed(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/Entity.java b/source/decompiled/de/maxhenkel/voicechat/api/Entity.java deleted file mode 100644 index 32c9adc..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/Entity.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.Position; -import java.util.UUID; - -public interface Entity { - public UUID getUuid(); - - public Object getEntity(); - - public Position getPosition(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/Group.java b/source/decompiled/de/maxhenkel/voicechat/api/Group.java deleted file mode 100644 index b80c830..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/Group.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api; - -import java.util.UUID; -import javax.annotation.Nullable; - -public interface Group { - public String getName(); - - public boolean hasPassword(); - - public UUID getId(); - - public boolean isPersistent(); - - public boolean isHidden(); - - public Type getType(); - - public static interface Builder { - public Builder setId(@Nullable UUID var1); - - public Builder setName(String var1); - - public Builder setPassword(@Nullable String var1); - - public Builder setPersistent(boolean var1); - - public Builder setHidden(boolean var1); - - public Builder setType(Type var1); - - public Group build(); - } - - public static interface Type { - public static final Type NORMAL = new Type(){}; - public static final Type OPEN = new Type(){}; - public static final Type ISOLATED = new Type(){}; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/Player.java b/source/decompiled/de/maxhenkel/voicechat/api/Player.java deleted file mode 100644 index c268ecb..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/Player.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.Entity; - -public interface Player -extends Entity { - public Object getPlayer(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/Position.java b/source/decompiled/de/maxhenkel/voicechat/api/Position.java deleted file mode 100644 index 1a9eff9..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/Position.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api; - -public interface Position { - public double getX(); - - public double getY(); - - public double getZ(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/RawUdpPacket.java b/source/decompiled/de/maxhenkel/voicechat/api/RawUdpPacket.java deleted file mode 100644 index dedfd17..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/RawUdpPacket.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api; - -import java.net.SocketAddress; - -public interface RawUdpPacket { - public byte[] getData(); - - public long getTimestamp(); - - public SocketAddress getSocketAddress(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/ServerLevel.java b/source/decompiled/de/maxhenkel/voicechat/api/ServerLevel.java deleted file mode 100644 index ac3d59f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/ServerLevel.java +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api; - -public interface ServerLevel { - public Object getServerLevel(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/ServerPlayer.java b/source/decompiled/de/maxhenkel/voicechat/api/ServerPlayer.java deleted file mode 100644 index 7a2b933..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/ServerPlayer.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.Player; -import de.maxhenkel.voicechat.api.ServerLevel; - -public interface ServerPlayer -extends Player { - public ServerLevel getServerLevel(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatApi.java b/source/decompiled/de/maxhenkel/voicechat/api/VoicechatApi.java deleted file mode 100644 index 54cfc12..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatApi.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.Entity; -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.ServerLevel; -import de.maxhenkel.voicechat.api.ServerPlayer; -import de.maxhenkel.voicechat.api.VolumeCategory; -import de.maxhenkel.voicechat.api.audio.AudioConverter; -import de.maxhenkel.voicechat.api.mp3.Mp3Decoder; -import de.maxhenkel.voicechat.api.mp3.Mp3Encoder; -import de.maxhenkel.voicechat.api.opus.OpusDecoder; -import de.maxhenkel.voicechat.api.opus.OpusEncoder; -import de.maxhenkel.voicechat.api.opus.OpusEncoderMode; -import java.io.InputStream; -import java.io.OutputStream; -import javax.annotation.Nullable; -import javax.sound.sampled.AudioFormat; - -public interface VoicechatApi { - public OpusEncoder createEncoder(); - - public OpusEncoder createEncoder(OpusEncoderMode var1); - - public OpusDecoder createDecoder(); - - @Nullable - public Mp3Encoder createMp3Encoder(AudioFormat var1, int var2, int var3, OutputStream var4); - - @Nullable - public Mp3Decoder createMp3Decoder(InputStream var1); - - public AudioConverter getAudioConverter(); - - public Entity fromEntity(Object var1); - - public ServerLevel fromServerLevel(Object var1); - - public ServerPlayer fromServerPlayer(Object var1); - - public Position createPosition(double var1, double var3, double var5); - - public VolumeCategory.Builder volumeCategoryBuilder(); - - public double getVoiceChatDistance(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatClientApi.java b/source/decompiled/de/maxhenkel/voicechat/api/VoicechatClientApi.java deleted file mode 100644 index 9885918..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatClientApi.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.Entity; -import de.maxhenkel.voicechat.api.Group; -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.VoicechatApi; -import de.maxhenkel.voicechat.api.VolumeCategory; -import de.maxhenkel.voicechat.api.audiochannel.ClientEntityAudioChannel; -import de.maxhenkel.voicechat.api.audiochannel.ClientLocationalAudioChannel; -import de.maxhenkel.voicechat.api.audiochannel.ClientStaticAudioChannel; -import de.maxhenkel.voicechat.api.config.ConfigAccessor; -import de.maxhenkel.voicechat.api.config.VolumeConfigAccessor; -import java.util.UUID; -import javax.annotation.Nullable; - -public interface VoicechatClientApi -extends VoicechatApi { - public boolean isMuted(); - - default public boolean isDisabled() { - return this.isDisabled(null); - } - - public boolean isDisabled(@Nullable UUID var1); - - default public boolean isDisconnected() { - return this.isDisconnected(null); - } - - public boolean isDisconnected(@Nullable UUID var1); - - default public boolean isTalking() { - return this.isTalking(null); - } - - public boolean isTalking(@Nullable UUID var1); - - default public boolean isWhispering() { - return this.isWhispering(null); - } - - public boolean isWhispering(@Nullable UUID var1); - - public boolean isPushToTalkKeyPressed(); - - public boolean isWhisperKeyPressed(); - - @Nullable - public Group getGroup(); - - @Deprecated - public ClientEntityAudioChannel createEntityAudioChannel(UUID var1); - - public ClientEntityAudioChannel createEntityAudioChannel(UUID var1, Entity var2); - - public ClientLocationalAudioChannel createLocationalAudioChannel(UUID var1, Position var2); - - public ClientStaticAudioChannel createStaticAudioChannel(UUID var1); - - public void registerClientVolumeCategory(VolumeCategory var1); - - default public void unregisterClientVolumeCategory(VolumeCategory category) { - this.unregisterClientVolumeCategory(category.getId()); - } - - public void unregisterClientVolumeCategory(String var1); - - public ConfigAccessor getClientConfig(); - - public VolumeConfigAccessor getVolumeConfig(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatConnection.java b/source/decompiled/de/maxhenkel/voicechat/api/VoicechatConnection.java deleted file mode 100644 index 8c01fcc..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatConnection.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.Group; -import de.maxhenkel.voicechat.api.ServerPlayer; -import javax.annotation.Nullable; - -public interface VoicechatConnection { - @Nullable - public Group getGroup(); - - public boolean isInGroup(); - - public void setGroup(@Nullable Group var1); - - public boolean isConnected(); - - public void setConnected(boolean var1); - - public boolean isDisabled(); - - public void setDisabled(boolean var1); - - public boolean isInstalled(); - - public ServerPlayer getPlayer(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatPlugin.java b/source/decompiled/de/maxhenkel/voicechat/api/VoicechatPlugin.java deleted file mode 100644 index 994a104..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatPlugin.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.VoicechatApi; -import de.maxhenkel.voicechat.api.events.EventRegistration; - -public interface VoicechatPlugin { - public String getPluginId(); - - default public void initialize(VoicechatApi api) { - } - - default public void registerEvents(EventRegistration registration) { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatServerApi.java b/source/decompiled/de/maxhenkel/voicechat/api/VoicechatServerApi.java deleted file mode 100644 index 4006362..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatServerApi.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.Entity; -import de.maxhenkel.voicechat.api.Group; -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.ServerLevel; -import de.maxhenkel.voicechat.api.ServerPlayer; -import de.maxhenkel.voicechat.api.VoicechatApi; -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.VolumeCategory; -import de.maxhenkel.voicechat.api.audiochannel.AudioChannel; -import de.maxhenkel.voicechat.api.audiochannel.AudioPlayer; -import de.maxhenkel.voicechat.api.audiochannel.EntityAudioChannel; -import de.maxhenkel.voicechat.api.audiochannel.LocationalAudioChannel; -import de.maxhenkel.voicechat.api.audiochannel.StaticAudioChannel; -import de.maxhenkel.voicechat.api.audiolistener.AudioListener; -import de.maxhenkel.voicechat.api.audiolistener.PlayerAudioListener; -import de.maxhenkel.voicechat.api.audiosender.AudioSender; -import de.maxhenkel.voicechat.api.config.ConfigAccessor; -import de.maxhenkel.voicechat.api.opus.OpusEncoder; -import de.maxhenkel.voicechat.api.packets.ConvertablePacket; -import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; -import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; -import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; -import java.util.Collection; -import java.util.UUID; -import java.util.function.Predicate; -import java.util.function.Supplier; -import javax.annotation.Nullable; - -public interface VoicechatServerApi -extends VoicechatApi { - public void sendEntitySoundPacketTo(VoicechatConnection var1, EntitySoundPacket var2); - - public void sendLocationalSoundPacketTo(VoicechatConnection var1, LocationalSoundPacket var2); - - public void sendStaticSoundPacketTo(VoicechatConnection var1, StaticSoundPacket var2); - - public ConvertablePacket createPacket(); - - @Nullable - public EntityAudioChannel createEntityAudioChannel(UUID var1, Entity var2); - - @Nullable - public LocationalAudioChannel createLocationalAudioChannel(UUID var1, ServerLevel var2, Position var3); - - @Deprecated - @Nullable - public StaticAudioChannel createStaticAudioChannel(UUID var1, ServerLevel var2, VoicechatConnection var3); - - @Nullable - public StaticAudioChannel createStaticAudioChannel(UUID var1); - - public AudioPlayer createAudioPlayer(AudioChannel var1, OpusEncoder var2, Supplier var3); - - public AudioPlayer createAudioPlayer(AudioChannel var1, OpusEncoder var2, short[] var3); - - public AudioSender createAudioSender(VoicechatConnection var1); - - public boolean registerAudioSender(AudioSender var1); - - public boolean unregisterAudioSender(AudioSender var1); - - public PlayerAudioListener.Builder playerAudioListenerBuilder(); - - public boolean registerAudioListener(AudioListener var1); - - public boolean unregisterAudioListener(AudioListener var1); - - public boolean unregisterAudioListener(UUID var1); - - @Nullable - public VoicechatConnection getConnectionOf(UUID var1); - - @Nullable - default public VoicechatConnection getConnectionOf(ServerPlayer player) { - return this.getConnectionOf(player.getUuid()); - } - - @Deprecated - public Group createGroup(String var1, @Nullable String var2); - - @Deprecated - public Group createGroup(String var1, @Nullable String var2, boolean var3); - - public Group.Builder groupBuilder(); - - public boolean removeGroup(UUID var1); - - @Nullable - public Group getGroup(UUID var1); - - public Collection getGroups(); - - @Nullable - @Deprecated - public UUID getSecret(UUID var1); - - public Collection getPlayersInRange(ServerLevel var1, Position var2, double var3, Predicate var5); - - public double getBroadcastRange(); - - default public Collection getPlayersInRange(ServerLevel level, Position pos, double range) { - return this.getPlayersInRange(level, pos, range, null); - } - - public void registerVolumeCategory(VolumeCategory var1); - - default public void unregisterVolumeCategory(VolumeCategory category) { - this.unregisterVolumeCategory(category.getId()); - } - - public void unregisterVolumeCategory(String var1); - - public Collection getVolumeCategories(); - - public ConfigAccessor getServerConfig(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatSocket.java b/source/decompiled/de/maxhenkel/voicechat/api/VoicechatSocket.java deleted file mode 100644 index e975a0e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/VoicechatSocket.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api; - -import de.maxhenkel.voicechat.api.RawUdpPacket; -import java.net.SocketAddress; - -public interface VoicechatSocket { - public void open(int var1, String var2) throws Exception; - - public RawUdpPacket read() throws Exception; - - public void send(byte[] var1, SocketAddress var2) throws Exception; - - public int getLocalPort(); - - public void close(); - - public boolean isClosed(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/VolumeCategory.java b/source/decompiled/de/maxhenkel/voicechat/api/VolumeCategory.java deleted file mode 100644 index f5edbdf..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/VolumeCategory.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api; - -import javax.annotation.Nullable; - -public interface VolumeCategory { - public String getId(); - - public String getName(); - - @Nullable - public String getNameTranslationKey(); - - @Nullable - public String getDescription(); - - @Nullable - public String getDescriptionTranslationKey(); - - @Nullable - public int[][] getIcon(); - - public static interface Builder { - public Builder setId(String var1); - - public Builder setName(String var1); - - public Builder setNameTranslationKey(@Nullable String var1); - - public Builder setDescription(@Nullable String var1); - - public Builder setDescriptionTranslationKey(@Nullable String var1); - - public Builder setIcon(@Nullable int[][] var1); - - public VolumeCategory build(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audio/AudioConverter.java b/source/decompiled/de/maxhenkel/voicechat/api/audio/AudioConverter.java deleted file mode 100644 index 36ac212..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audio/AudioConverter.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.audio; - -public interface AudioConverter { - public short[] bytesToShorts(byte[] var1); - - public byte[] shortsToBytes(short[] var1); - - public short[] floatsToShorts(float[] var1); - - public float[] shortsToFloats(short[] var1); - - public byte[] floatsToBytes(float[] var1); - - public float[] bytesToFloats(byte[] var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/AudioChannel.java b/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/AudioChannel.java deleted file mode 100644 index 8cf5367..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/AudioChannel.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.audiochannel; - -import de.maxhenkel.voicechat.api.ServerPlayer; -import de.maxhenkel.voicechat.api.packets.MicrophonePacket; -import java.util.UUID; -import java.util.function.Predicate; -import javax.annotation.Nullable; - -public interface AudioChannel { - public void send(byte[] var1); - - public void send(MicrophonePacket var1); - - public void setFilter(Predicate var1); - - public void flush(); - - public boolean isClosed(); - - public UUID getId(); - - @Nullable - public String getCategory(); - - public void setCategory(@Nullable String var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/AudioPlayer.java b/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/AudioPlayer.java deleted file mode 100644 index c330938..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/AudioPlayer.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.audiochannel; - -public interface AudioPlayer { - public void startPlaying(); - - public void stopPlaying(); - - public boolean isStarted(); - - public boolean isPlaying(); - - public boolean isStopped(); - - public void setOnStopped(Runnable var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientAudioChannel.java b/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientAudioChannel.java deleted file mode 100644 index a6e3bf3..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientAudioChannel.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.audiochannel; - -import java.util.UUID; -import javax.annotation.Nullable; - -public interface ClientAudioChannel { - public UUID getId(); - - public void play(short[] var1); - - @Nullable - public String getCategory(); - - public void setCategory(@Nullable String var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientEntityAudioChannel.java b/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientEntityAudioChannel.java deleted file mode 100644 index d1d3d39..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientEntityAudioChannel.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.audiochannel; - -import de.maxhenkel.voicechat.api.audiochannel.ClientAudioChannel; -import java.util.UUID; - -public interface ClientEntityAudioChannel -extends ClientAudioChannel { - public UUID getEntityId(); - - public void setWhispering(boolean var1); - - public boolean isWhispering(); - - public float getDistance(); - - public void setDistance(float var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientLocationalAudioChannel.java b/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientLocationalAudioChannel.java deleted file mode 100644 index 33c4e9f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientLocationalAudioChannel.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.audiochannel; - -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.audiochannel.ClientAudioChannel; - -public interface ClientLocationalAudioChannel -extends ClientAudioChannel { - public Position getLocation(); - - public void setLocation(Position var1); - - public float getDistance(); - - public void setDistance(float var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientStaticAudioChannel.java b/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientStaticAudioChannel.java deleted file mode 100644 index 11e7b86..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/ClientStaticAudioChannel.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.audiochannel; - -import de.maxhenkel.voicechat.api.audiochannel.ClientAudioChannel; - -public interface ClientStaticAudioChannel -extends ClientAudioChannel { -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/EntityAudioChannel.java b/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/EntityAudioChannel.java deleted file mode 100644 index d9424b6..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/EntityAudioChannel.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.audiochannel; - -import de.maxhenkel.voicechat.api.Entity; -import de.maxhenkel.voicechat.api.audiochannel.AudioChannel; - -public interface EntityAudioChannel -extends AudioChannel { - public boolean isWhispering(); - - public void setWhispering(boolean var1); - - public void updateEntity(Entity var1); - - public Entity getEntity(); - - public float getDistance(); - - public void setDistance(float var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/LocationalAudioChannel.java b/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/LocationalAudioChannel.java deleted file mode 100644 index 06e1d8b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/LocationalAudioChannel.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.audiochannel; - -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.audiochannel.AudioChannel; - -public interface LocationalAudioChannel -extends AudioChannel { - public void updateLocation(Position var1); - - public Position getLocation(); - - public float getDistance(); - - public void setDistance(float var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/StaticAudioChannel.java b/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/StaticAudioChannel.java deleted file mode 100644 index b14ed16..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiochannel/StaticAudioChannel.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.audiochannel; - -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.audiochannel.AudioChannel; - -public interface StaticAudioChannel -extends AudioChannel { - public void setBypassGroupIsolation(boolean var1); - - public boolean bypassesGroupIsolation(); - - public void addTarget(VoicechatConnection var1); - - public void removeTarget(VoicechatConnection var1); - - public void clearTargets(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiolistener/PlayerAudioListener.java b/source/decompiled/de/maxhenkel/voicechat/api/audiolistener/PlayerAudioListener.java deleted file mode 100644 index 9755797..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiolistener/PlayerAudioListener.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.audiolistener; - -import de.maxhenkel.voicechat.api.ServerPlayer; -import de.maxhenkel.voicechat.api.audiolistener.AudioListener; -import de.maxhenkel.voicechat.api.packets.SoundPacket; -import java.util.UUID; -import java.util.function.Consumer; - -public interface PlayerAudioListener -extends AudioListener { - public UUID getPlayerUuid(); - - public static interface Builder { - public Builder setPlayer(ServerPlayer var1); - - public Builder setPlayer(UUID var1); - - public Builder setPacketListener(Consumer var1); - - public PlayerAudioListener build(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/audiosender/AudioSender.java b/source/decompiled/de/maxhenkel/voicechat/api/audiosender/AudioSender.java deleted file mode 100644 index ed8d313..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/audiosender/AudioSender.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.audiosender; - -public interface AudioSender { - public AudioSender whispering(boolean var1); - - public boolean isWhispering(); - - public AudioSender sequenceNumber(long var1); - - public boolean canSend(); - - public boolean send(byte[] var1); - - public boolean reset(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/config/ConfigAccessor.java b/source/decompiled/de/maxhenkel/voicechat/api/config/ConfigAccessor.java deleted file mode 100644 index e8c488e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/config/ConfigAccessor.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.config; - -import javax.annotation.Nullable; - -public interface ConfigAccessor { - public boolean hasKey(String var1); - - @Nullable - public String getValue(String var1); - - default public String getString(String key, String def) { - String value = this.getValue(key); - if (value == null) { - return def; - } - return value; - } - - default public boolean getBoolean(String key, boolean def) { - String value = this.getValue(key); - if (value == null) { - return def; - } - return Boolean.parseBoolean(value); - } - - default public int getInt(String key, int def) { - String value = this.getValue(key); - if (value == null) { - return def; - } - return Integer.parseInt(value); - } - - default public double getDouble(String key, double def) { - String value = this.getValue(key); - if (value == null) { - return def; - } - return Double.parseDouble(value); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/config/VolumeConfigAccessor.java b/source/decompiled/de/maxhenkel/voicechat/api/config/VolumeConfigAccessor.java deleted file mode 100644 index 466ad3e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/config/VolumeConfigAccessor.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.config; - -import java.util.UUID; - -public interface VolumeConfigAccessor { - public double getVolume(UUID var1); - - public double getCategoryVolume(String var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/ClientEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/ClientEvent.java deleted file mode 100644 index 0e00374..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/ClientEvent.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.VoicechatClientApi; -import de.maxhenkel.voicechat.api.events.Event; - -public interface ClientEvent -extends Event { - public VoicechatClientApi getVoicechat(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/ClientReceiveSoundEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/ClientReceiveSoundEvent.java deleted file mode 100644 index 4806bd9..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/ClientReceiveSoundEvent.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.events.ClientEvent; -import java.util.UUID; -import javax.annotation.Nullable; - -public interface ClientReceiveSoundEvent -extends ClientEvent { - public UUID getId(); - - public short[] getRawAudio(); - - public void setRawAudio(@Nullable short[] var1); - - public static interface StaticSound - extends ClientReceiveSoundEvent { - } - - public static interface LocationalSound - extends ClientReceiveSoundEvent { - public Position getPosition(); - - public float getDistance(); - } - - public static interface EntitySound - extends ClientReceiveSoundEvent { - public UUID getEntityId(); - - public boolean isWhispering(); - - public float getDistance(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/ClientSoundEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/ClientSoundEvent.java deleted file mode 100644 index 494e7ff..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/ClientSoundEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ClientEvent; - -public interface ClientSoundEvent -extends ClientEvent { - public short[] getRawAudio(); - - public void setRawAudio(short[] var1); - - public boolean isWhispering(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/ClientVoicechatConnectionEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/ClientVoicechatConnectionEvent.java deleted file mode 100644 index 994b730..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/ClientVoicechatConnectionEvent.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ClientEvent; - -public interface ClientVoicechatConnectionEvent -extends ClientEvent { - public boolean isConnected(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/ClientVoicechatInitializationEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/ClientVoicechatInitializationEvent.java deleted file mode 100644 index 6134ce7..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/ClientVoicechatInitializationEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.ClientVoicechatSocket; -import de.maxhenkel.voicechat.api.events.ClientEvent; -import javax.annotation.Nullable; - -public interface ClientVoicechatInitializationEvent -extends ClientEvent { - public void setSocketImplementation(ClientVoicechatSocket var1); - - @Nullable - public ClientVoicechatSocket getSocketImplementation(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/CreateGroupEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/CreateGroupEvent.java deleted file mode 100644 index f0cd60d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/CreateGroupEvent.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.Group; -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.events.GroupEvent; -import javax.annotation.Nullable; - -public interface CreateGroupEvent -extends GroupEvent { - @Override - public Group getGroup(); - - @Override - @Nullable - public VoicechatConnection getConnection(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/CreateOpenALContextEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/CreateOpenALContextEvent.java deleted file mode 100644 index 15ea83e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/CreateOpenALContextEvent.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ClientEvent; - -public interface CreateOpenALContextEvent -extends ClientEvent { - public long getContext(); - - public long getDevice(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/DestroyOpenALContextEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/DestroyOpenALContextEvent.java deleted file mode 100644 index 5e8004a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/DestroyOpenALContextEvent.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ClientEvent; - -public interface DestroyOpenALContextEvent -extends ClientEvent { - public long getContext(); - - public long getDevice(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/EntitySoundPacketEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/EntitySoundPacketEvent.java deleted file mode 100644 index fb5c416..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/EntitySoundPacketEvent.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.SoundPacketEvent; -import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; - -public interface EntitySoundPacketEvent -extends SoundPacketEvent { -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/Event.java b/source/decompiled/de/maxhenkel/voicechat/api/events/Event.java deleted file mode 100644 index 81d99fc..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/Event.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -public interface Event { - public boolean isCancellable(); - - public boolean cancel(); - - public boolean isCancelled(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/EventRegistration.java b/source/decompiled/de/maxhenkel/voicechat/api/events/EventRegistration.java deleted file mode 100644 index 784a374..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/EventRegistration.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.Event; -import java.util.function.Consumer; - -public interface EventRegistration { - public void registerEvent(Class var1, Consumer var2, int var3); - - default public void registerEvent(Class eventClass, Consumer onPacket) { - this.registerEvent(eventClass, onPacket, 0); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/GroupEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/GroupEvent.java deleted file mode 100644 index 4405f6d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/GroupEvent.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.Group; -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.events.ServerEvent; -import javax.annotation.Nullable; - -public interface GroupEvent -extends ServerEvent { - @Nullable - public Group getGroup(); - - @Nullable - public VoicechatConnection getConnection(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/JoinGroupEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/JoinGroupEvent.java deleted file mode 100644 index 9912984..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/JoinGroupEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.Group; -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.events.GroupEvent; - -public interface JoinGroupEvent -extends GroupEvent { - @Override - public Group getGroup(); - - @Override - public VoicechatConnection getConnection(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/LeaveGroupEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/LeaveGroupEvent.java deleted file mode 100644 index 7c72c47..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/LeaveGroupEvent.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.Group; -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.events.GroupEvent; -import javax.annotation.Nullable; - -public interface LeaveGroupEvent -extends GroupEvent { - @Override - @Nullable - public Group getGroup(); - - @Override - public VoicechatConnection getConnection(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/LocationalSoundPacketEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/LocationalSoundPacketEvent.java deleted file mode 100644 index d477f6d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/LocationalSoundPacketEvent.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.SoundPacketEvent; -import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; - -public interface LocationalSoundPacketEvent -extends SoundPacketEvent { -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/MergeClientSoundEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/MergeClientSoundEvent.java deleted file mode 100644 index 7d97d4e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/MergeClientSoundEvent.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ClientEvent; - -public interface MergeClientSoundEvent -extends ClientEvent { - public void mergeAudio(short[] var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/MicrophoneMuteEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/MicrophoneMuteEvent.java deleted file mode 100644 index 1d802ed..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/MicrophoneMuteEvent.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ClientEvent; - -public interface MicrophoneMuteEvent -extends ClientEvent { - public boolean isDisabled(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/MicrophonePacketEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/MicrophonePacketEvent.java deleted file mode 100644 index 51f28ea..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/MicrophonePacketEvent.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.PacketEvent; -import de.maxhenkel.voicechat.api.packets.MicrophonePacket; - -public interface MicrophonePacketEvent -extends PacketEvent { -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/NameTagIconRenderEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/NameTagIconRenderEvent.java deleted file mode 100644 index 1e783f7..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/NameTagIconRenderEvent.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ClientEvent; -import java.util.UUID; - -public interface NameTagIconRenderEvent -extends ClientEvent { - public UUID getEntityId(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/OpenALSoundEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/OpenALSoundEvent.java deleted file mode 100644 index a3aa9ab..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/OpenALSoundEvent.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.events.ClientEvent; -import java.util.UUID; -import javax.annotation.Nullable; - -public interface OpenALSoundEvent -extends ClientEvent { - @Nullable - public Position getPosition(); - - @Nullable - public UUID getChannelId(); - - public int getSource(); - - @Nullable - public String getCategory(); - - public static interface Post - extends OpenALSoundEvent { - } - - public static interface Pre - extends OpenALSoundEvent { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/PacketEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/PacketEvent.java deleted file mode 100644 index 4b0fdfd..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/PacketEvent.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.events.ServerEvent; -import de.maxhenkel.voicechat.api.packets.Packet; -import javax.annotation.Nullable; - -public interface PacketEvent -extends ServerEvent { - public T getPacket(); - - @Nullable - public VoicechatConnection getReceiverConnection(); - - @Nullable - public VoicechatConnection getSenderConnection(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/PlayerConnectedEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/PlayerConnectedEvent.java deleted file mode 100644 index e76096f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/PlayerConnectedEvent.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.events.ServerEvent; - -public interface PlayerConnectedEvent -extends ServerEvent { - public VoicechatConnection getConnection(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/PlayerDisconnectedEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/PlayerDisconnectedEvent.java deleted file mode 100644 index d23382f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/PlayerDisconnectedEvent.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ServerEvent; -import java.util.UUID; - -public interface PlayerDisconnectedEvent -extends ServerEvent { - public UUID getPlayerUuid(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/PlayerStateChangedEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/PlayerStateChangedEvent.java deleted file mode 100644 index c29eef5..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/PlayerStateChangedEvent.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.events.ServerEvent; -import java.util.UUID; -import javax.annotation.Nullable; - -public interface PlayerStateChangedEvent -extends ServerEvent { - public boolean isDisabled(); - - public boolean isDisconnected(); - - public UUID getPlayerUuid(); - - @Nullable - public VoicechatConnection getConnection(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/RegisterVolumeCategoryEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/RegisterVolumeCategoryEvent.java deleted file mode 100644 index 6562898..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/RegisterVolumeCategoryEvent.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.VolumeCategoryEvent; - -public interface RegisterVolumeCategoryEvent -extends VolumeCategoryEvent { -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/RemoveGroupEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/RemoveGroupEvent.java deleted file mode 100644 index ffdce3d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/RemoveGroupEvent.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.Group; -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.events.GroupEvent; -import javax.annotation.Nullable; - -public interface RemoveGroupEvent -extends GroupEvent { - @Override - public Group getGroup(); - - @Override - @Nullable - @Deprecated - public VoicechatConnection getConnection(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/ServerEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/ServerEvent.java deleted file mode 100644 index addf083..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/ServerEvent.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.VoicechatServerApi; -import de.maxhenkel.voicechat.api.events.Event; - -public interface ServerEvent -extends Event { - public VoicechatServerApi getVoicechat(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/SoundPacketEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/SoundPacketEvent.java deleted file mode 100644 index 6e15ac6..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/SoundPacketEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.PacketEvent; -import de.maxhenkel.voicechat.api.packets.Packet; - -public interface SoundPacketEvent -extends PacketEvent { - public static final String SOURCE_GROUP = "group"; - public static final String SOURCE_PROXIMITY = "proximity"; - public static final String SOURCE_SPECTATOR = "spectator"; - public static final String SOURCE_PLUGIN = "plugin"; - - public String getSource(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/StaticSoundPacketEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/StaticSoundPacketEvent.java deleted file mode 100644 index af71625..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/StaticSoundPacketEvent.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.SoundPacketEvent; -import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; - -public interface StaticSoundPacketEvent -extends SoundPacketEvent { -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/UnregisterVolumeCategoryEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/UnregisterVolumeCategoryEvent.java deleted file mode 100644 index a4eeefa..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/UnregisterVolumeCategoryEvent.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.VolumeCategoryEvent; - -public interface UnregisterVolumeCategoryEvent -extends VolumeCategoryEvent { -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/VoiceDistanceEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/VoiceDistanceEvent.java deleted file mode 100644 index ecf20c6..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/VoiceDistanceEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.events.ServerEvent; -import de.maxhenkel.voicechat.api.packets.MicrophonePacket; - -public interface VoiceDistanceEvent -extends ServerEvent { - public MicrophonePacket getPacket(); - - public VoicechatConnection getSenderConnection(); - - public float getDistance(); - - public void setDistance(float var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/VoiceHostEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/VoiceHostEvent.java deleted file mode 100644 index ad8053e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/VoiceHostEvent.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.ServerPlayer; -import de.maxhenkel.voicechat.api.events.ServerEvent; - -public interface VoiceHostEvent -extends ServerEvent { - public String getVoiceHost(); - - public void setVoiceHost(String var1); - - public ServerPlayer getPlayer(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatDisableEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatDisableEvent.java deleted file mode 100644 index cbd2981..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatDisableEvent.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ClientEvent; - -public interface VoicechatDisableEvent -extends ClientEvent { - public boolean isDisabled(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStartedEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStartedEvent.java deleted file mode 100644 index 635fdc8..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStartedEvent.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ServerEvent; - -public interface VoicechatServerStartedEvent -extends ServerEvent { -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStartingEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStartingEvent.java deleted file mode 100644 index de62eb2..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStartingEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.VoicechatSocket; -import de.maxhenkel.voicechat.api.events.ServerEvent; -import javax.annotation.Nullable; - -public interface VoicechatServerStartingEvent -extends ServerEvent { - public void setSocketImplementation(VoicechatSocket var1); - - @Nullable - public VoicechatSocket getSocketImplementation(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStoppedEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStoppedEvent.java deleted file mode 100644 index 79185ad..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/VoicechatServerStoppedEvent.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.events.ServerEvent; - -public interface VoicechatServerStoppedEvent -extends ServerEvent { -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/events/VolumeCategoryEvent.java b/source/decompiled/de/maxhenkel/voicechat/api/events/VolumeCategoryEvent.java deleted file mode 100644 index f56e44e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/events/VolumeCategoryEvent.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.events; - -import de.maxhenkel.voicechat.api.VolumeCategory; -import de.maxhenkel.voicechat.api.events.ServerEvent; - -public interface VolumeCategoryEvent -extends ServerEvent { - public VolumeCategory getVolumeCategory(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/mp3/Mp3Decoder.java b/source/decompiled/de/maxhenkel/voicechat/api/mp3/Mp3Decoder.java deleted file mode 100644 index 4252b9a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/mp3/Mp3Decoder.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.mp3; - -import java.io.IOException; -import javax.sound.sampled.AudioFormat; - -public interface Mp3Decoder { - public short[] decode() throws IOException; - - public AudioFormat getAudioFormat() throws IOException; - - public int getBitrate() throws IOException; -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/mp3/Mp3Encoder.java b/source/decompiled/de/maxhenkel/voicechat/api/mp3/Mp3Encoder.java deleted file mode 100644 index 73e4ff1..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/mp3/Mp3Encoder.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.mp3; - -import java.io.IOException; - -public interface Mp3Encoder { - public void encode(short[] var1) throws IOException; - - public void close() throws IOException; -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/opus/OpusDecoder.java b/source/decompiled/de/maxhenkel/voicechat/api/opus/OpusDecoder.java deleted file mode 100644 index b549cab..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/opus/OpusDecoder.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.opus; - -import javax.annotation.Nullable; - -public interface OpusDecoder { - public short[] decode(@Nullable byte[] var1); - - public short[][] decode(byte[] var1, int var2); - - public void resetState(); - - public boolean isClosed(); - - public void close(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/opus/OpusEncoder.java b/source/decompiled/de/maxhenkel/voicechat/api/opus/OpusEncoder.java deleted file mode 100644 index 41032d6..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/opus/OpusEncoder.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.opus; - -public interface OpusEncoder { - public byte[] encode(short[] var1); - - public void resetState(); - - public boolean isClosed(); - - public void close(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/opus/OpusEncoderMode.java b/source/decompiled/de/maxhenkel/voicechat/api/opus/OpusEncoderMode.java deleted file mode 100644 index b324d2d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/opus/OpusEncoderMode.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.opus; - -public enum OpusEncoderMode { - VOIP, - AUDIO, - RESTRICTED_LOWDELAY; - -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/packets/ConvertablePacket.java b/source/decompiled/de/maxhenkel/voicechat/api/packets/ConvertablePacket.java deleted file mode 100644 index b3a3c50..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/packets/ConvertablePacket.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.packets; - -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; -import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; -import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; -import java.util.UUID; - -public interface ConvertablePacket { - public EntitySoundPacket.Builder entitySoundPacketBuilder(); - - public LocationalSoundPacket.Builder locationalSoundPacketBuilder(); - - public StaticSoundPacket.Builder staticSoundPacketBuilder(); - - @Deprecated - public EntitySoundPacket toEntitySoundPacket(UUID var1, boolean var2); - - @Deprecated - public LocationalSoundPacket toLocationalSoundPacket(Position var1); - - @Deprecated - public StaticSoundPacket toStaticSoundPacket(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/packets/EntitySoundPacket.java b/source/decompiled/de/maxhenkel/voicechat/api/packets/EntitySoundPacket.java deleted file mode 100644 index 1aad5df..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/packets/EntitySoundPacket.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.packets; - -import de.maxhenkel.voicechat.api.packets.SoundPacket; -import java.util.UUID; - -public interface EntitySoundPacket -extends SoundPacket { - public UUID getEntityUuid(); - - public boolean isWhispering(); - - public float getDistance(); - - public static interface Builder> - extends SoundPacket.Builder { - public T entityUuid(UUID var1); - - public T whispering(boolean var1); - - public T distance(float var1); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/packets/LocationalSoundPacket.java b/source/decompiled/de/maxhenkel/voicechat/api/packets/LocationalSoundPacket.java deleted file mode 100644 index 6be8ef2..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/packets/LocationalSoundPacket.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.packets; - -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.packets.SoundPacket; - -public interface LocationalSoundPacket -extends SoundPacket { - public Position getPosition(); - - public float getDistance(); - - public static interface Builder> - extends SoundPacket.Builder { - public T position(Position var1); - - public T distance(float var1); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/packets/MicrophonePacket.java b/source/decompiled/de/maxhenkel/voicechat/api/packets/MicrophonePacket.java deleted file mode 100644 index 9d5b236..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/packets/MicrophonePacket.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.packets; - -import de.maxhenkel.voicechat.api.packets.ConvertablePacket; -import de.maxhenkel.voicechat.api.packets.Packet; - -public interface MicrophonePacket -extends Packet, -ConvertablePacket { - public boolean isWhispering(); - - public byte[] getOpusEncodedData(); - - public void setOpusEncodedData(byte[] var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/packets/SoundPacket.java b/source/decompiled/de/maxhenkel/voicechat/api/packets/SoundPacket.java deleted file mode 100644 index 18f0771..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/packets/SoundPacket.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.api.packets; - -import de.maxhenkel.voicechat.api.packets.ConvertablePacket; -import de.maxhenkel.voicechat.api.packets.Packet; -import java.util.UUID; -import javax.annotation.Nullable; - -public interface SoundPacket -extends Packet, -ConvertablePacket { - public UUID getChannelId(); - - public UUID getSender(); - - public byte[] getOpusEncodedData(); - - public long getSequenceNumber(); - - @Nullable - public String getCategory(); - - public static interface Builder, P extends SoundPacket> { - public T channelId(UUID var1); - - public T sender(UUID var1); - - public T opusEncodedData(byte[] var1); - - public T sequenceNumber(long var1); - - public T category(@Nullable String var1); - - public P build(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/api/packets/StaticSoundPacket.java b/source/decompiled/de/maxhenkel/voicechat/api/packets/StaticSoundPacket.java deleted file mode 100644 index 3637202..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/api/packets/StaticSoundPacket.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.api.packets; - -import de.maxhenkel.voicechat.api.packets.SoundPacket; - -public interface StaticSoundPacket -extends SoundPacket { - - public static interface Builder> - extends SoundPacket.Builder { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/AbstractCommodore.java b/source/decompiled/de/maxhenkel/voicechat/commodore/AbstractCommodore.java deleted file mode 100644 index af6f20c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/AbstractCommodore.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.Command - * com.mojang.brigadier.suggestion.SuggestionProvider - * com.mojang.brigadier.tree.ArgumentCommandNode - * com.mojang.brigadier.tree.CommandNode - * com.mojang.brigadier.tree.LiteralCommandNode - * com.mojang.brigadier.tree.RootCommandNode - * org.bukkit.command.Command - * org.bukkit.command.PluginCommand - */ -package de.maxhenkel.voicechat.commodore; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.suggestion.SuggestionProvider; -import com.mojang.brigadier.tree.ArgumentCommandNode; -import com.mojang.brigadier.tree.CommandNode; -import com.mojang.brigadier.tree.LiteralCommandNode; -import com.mojang.brigadier.tree.RootCommandNode; -import de.maxhenkel.voicechat.commodore.Commodore; -import java.lang.reflect.Field; -import java.util.Collection; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.bukkit.command.PluginCommand; - -abstract class AbstractCommodore -implements Commodore { - protected static final Field CUSTOM_SUGGESTIONS_FIELD; - protected static final Field COMMAND_EXECUTE_FUNCTION_FIELD; - protected static final Field CHILDREN_FIELD; - protected static final Field LITERALS_FIELD; - protected static final Field ARGUMENTS_FIELD; - protected static final Field[] CHILDREN_FIELDS; - protected static final Command DUMMY_COMMAND; - protected static final SuggestionProvider DUMMY_SUGGESTION_PROVIDER; - - AbstractCommodore() { - } - - protected static void removeChild(RootCommandNode root, String name) { - try { - for (Field field : CHILDREN_FIELDS) { - Map children = (Map)field.get(root); - children.remove(name); - } - } - catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - protected static void setRequiredHackyFieldsRecursively(CommandNode node, SuggestionProvider suggestionProvider) { - try { - COMMAND_EXECUTE_FUNCTION_FIELD.set(node, DUMMY_COMMAND); - } - catch (IllegalAccessException e) { - e.printStackTrace(); - } - if (suggestionProvider != null && node instanceof ArgumentCommandNode) { - ArgumentCommandNode argumentNode = (ArgumentCommandNode)node; - try { - CUSTOM_SUGGESTIONS_FIELD.set(argumentNode, suggestionProvider); - } - catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - for (CommandNode child : node.getChildren()) { - AbstractCommodore.setRequiredHackyFieldsRecursively(child, suggestionProvider); - } - } - - protected static LiteralCommandNode renameLiteralNode(LiteralCommandNode node, String newLiteral) { - LiteralCommandNode clone = new LiteralCommandNode(newLiteral, node.getCommand(), node.getRequirement(), node.getRedirect(), node.getRedirectModifier(), node.isFork()); - for (CommandNode child : node.getChildren()) { - clone.addChild(child); - } - return clone; - } - - protected static Collection getAliases(org.bukkit.command.Command command) { - Objects.requireNonNull(command, "command"); - Stream aliasesStream = Stream.concat(Stream.of(command.getLabel()), command.getAliases().stream()); - if (command instanceof PluginCommand) { - String fallbackPrefix = ((PluginCommand)command).getPlugin().getName().toLowerCase().trim(); - aliasesStream = aliasesStream.flatMap(alias -> Stream.of(alias, fallbackPrefix + ":" + alias)); - } - return aliasesStream.distinct().collect(Collectors.toList()); - } - - static { - try { - CUSTOM_SUGGESTIONS_FIELD = ArgumentCommandNode.class.getDeclaredField("customSuggestions"); - CUSTOM_SUGGESTIONS_FIELD.setAccessible(true); - COMMAND_EXECUTE_FUNCTION_FIELD = CommandNode.class.getDeclaredField("command"); - COMMAND_EXECUTE_FUNCTION_FIELD.setAccessible(true); - CHILDREN_FIELD = CommandNode.class.getDeclaredField("children"); - LITERALS_FIELD = CommandNode.class.getDeclaredField("literals"); - ARGUMENTS_FIELD = CommandNode.class.getDeclaredField("arguments"); - for (Field field : CHILDREN_FIELDS = new Field[]{CHILDREN_FIELD, LITERALS_FIELD, ARGUMENTS_FIELD}) { - field.setAccessible(true); - } - DUMMY_COMMAND = ctx -> { - throw new UnsupportedOperationException(); - }; - DUMMY_SUGGESTION_PROVIDER = (context, builder) -> { - throw new UnsupportedOperationException(); - }; - } - catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/BrigadierUnsupportedException.java b/source/decompiled/de/maxhenkel/voicechat/commodore/BrigadierUnsupportedException.java deleted file mode 100644 index 5076fa7..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/BrigadierUnsupportedException.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.commodore; - -public final class BrigadierUnsupportedException -extends UnsupportedOperationException { - BrigadierUnsupportedException(String message) { - super(message); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/Commodore.java b/source/decompiled/de/maxhenkel/voicechat/commodore/Commodore.java deleted file mode 100644 index 0ae4c27..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/Commodore.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.builder.LiteralArgumentBuilder - * com.mojang.brigadier.tree.LiteralCommandNode - * org.bukkit.command.Command - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.commodore; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.tree.LiteralCommandNode; -import java.util.Objects; -import java.util.function.Predicate; -import org.bukkit.command.Command; -import org.bukkit.entity.Player; - -public interface Commodore { - public void register(Command var1, LiteralCommandNode var2, Predicate var3); - - default public void register(Command command, LiteralArgumentBuilder argumentBuilder, Predicate permissionTest) { - Objects.requireNonNull(command, "command"); - Objects.requireNonNull(argumentBuilder, "argumentBuilder"); - Objects.requireNonNull(permissionTest, "permissionTest"); - this.register(command, argumentBuilder.build(), permissionTest); - } - - default public void register(Command command, LiteralCommandNode node) { - Objects.requireNonNull(command, "command"); - Objects.requireNonNull(node, "node"); - this.register(command, node, arg_0 -> ((Command)command).testPermissionSilent(arg_0)); - } - - default public void register(Command command, LiteralArgumentBuilder argumentBuilder) { - Objects.requireNonNull(command, "command"); - Objects.requireNonNull(argumentBuilder, "argumentBuilder"); - this.register(command, argumentBuilder.build()); - } - - public void register(LiteralCommandNode var1); - - default public void register(LiteralArgumentBuilder argumentBuilder) { - Objects.requireNonNull(argumentBuilder, "argumentBuilder"); - this.register(argumentBuilder.build()); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/CommodoreProvider.java b/source/decompiled/de/maxhenkel/voicechat/commodore/CommodoreProvider.java deleted file mode 100644 index 87d0f0e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/CommodoreProvider.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.plugin.Plugin - */ -package de.maxhenkel.voicechat.commodore; - -import de.maxhenkel.voicechat.commodore.BrigadierUnsupportedException; -import de.maxhenkel.voicechat.commodore.Commodore; -import de.maxhenkel.voicechat.commodore.PaperCommodore; -import de.maxhenkel.voicechat.commodore.ReflectionCommodore; -import java.util.Objects; -import java.util.function.Function; -import org.bukkit.plugin.Plugin; - -public final class CommodoreProvider { - private static final Function PROVIDER = CommodoreProvider.checkSupported(); - - private CommodoreProvider() { - throw new AssertionError(); - } - - private static Function checkSupported() { - try { - Class.forName("com.mojang.brigadier.CommandDispatcher"); - } - catch (Throwable e) { - CommodoreProvider.printDebugInfo(e); - return null; - } - try { - PaperCommodore.ensureSetup(); - return PaperCommodore::new; - } - catch (Throwable e) { - CommodoreProvider.printDebugInfo(e); - try { - ReflectionCommodore.ensureSetup(); - return ReflectionCommodore::new; - } - catch (Throwable e2) { - CommodoreProvider.printDebugInfo(e2); - return null; - } - } - } - - private static void printDebugInfo(Throwable e) { - if (System.getProperty("commodore.debug") != null) { - System.err.println("Exception while initialising commodore:"); - e.printStackTrace(System.err); - } - } - - public static boolean isSupported() { - return PROVIDER != null; - } - - public static Commodore getCommodore(Plugin plugin) throws BrigadierUnsupportedException { - Objects.requireNonNull(plugin, "plugin"); - if (PROVIDER == null) { - throw new BrigadierUnsupportedException("Brigadier is not supported by the server. Set -Dcommodore.debug=true for debug info."); - } - return PROVIDER.apply(plugin); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/PaperCommodore.java b/source/decompiled/de/maxhenkel/voicechat/commodore/PaperCommodore.java deleted file mode 100644 index be7b331..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/PaperCommodore.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent - * com.mojang.brigadier.builder.LiteralArgumentBuilder - * com.mojang.brigadier.tree.LiteralCommandNode - * com.mojang.brigadier.tree.RootCommandNode - * org.bukkit.command.Command - * org.bukkit.entity.Player - * org.bukkit.event.EventHandler - * org.bukkit.event.Listener - * org.bukkit.plugin.Plugin - */ -package de.maxhenkel.voicechat.commodore; - -import com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.tree.LiteralCommandNode; -import com.mojang.brigadier.tree.RootCommandNode; -import de.maxhenkel.voicechat.commodore.AbstractCommodore; -import de.maxhenkel.voicechat.commodore.Commodore; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.function.Predicate; -import org.bukkit.command.Command; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.plugin.Plugin; - -final class PaperCommodore -extends AbstractCommodore -implements Commodore, -Listener { - private final List commands = new ArrayList(); - - PaperCommodore(Plugin plugin) { - plugin.getServer().getPluginManager().registerEvents((Listener)this, plugin); - } - - @Override - public void register(LiteralCommandNode node) { - Objects.requireNonNull(node, "node"); - this.commands.add(new CommodoreCommand(node, null)); - } - - @Override - public void register(Command command, LiteralCommandNode node, Predicate permissionTest) { - Objects.requireNonNull(command, "command"); - Objects.requireNonNull(node, "node"); - Objects.requireNonNull(permissionTest, "permissionTest"); - try { - PaperCommodore.setRequiredHackyFieldsRecursively(node, DUMMY_SUGGESTION_PROVIDER); - } - catch (Throwable e) { - e.printStackTrace(); - } - Collection aliases = PaperCommodore.getAliases(command); - if (!aliases.contains(node.getLiteral())) { - node = PaperCommodore.renameLiteralNode(node, command.getName()); - } - for (String alias : aliases) { - if (node.getLiteral().equals(alias)) { - this.commands.add(new CommodoreCommand(node, permissionTest)); - continue; - } - LiteralCommandNode redirectNode = ((LiteralArgumentBuilder)LiteralArgumentBuilder.literal((String)alias).redirect(node)).build(); - this.commands.add(new CommodoreCommand(redirectNode, permissionTest)); - } - } - - @EventHandler - public void onPlayerSendCommandsEvent(AsyncPlayerSendCommandsEvent event) { - if (event.isAsynchronous() || !event.hasFiredAsync()) { - for (CommodoreCommand command : this.commands) { - command.apply(event.getPlayer(), event.getCommandNode()); - } - } - } - - static void ensureSetup() { - } - - static { - try { - Class.forName("com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent"); - } - catch (ClassNotFoundException e) { - throw new UnsupportedOperationException("Not running on modern Paper!", e); - } - } - - private static final class CommodoreCommand { - private final LiteralCommandNode node; - private final Predicate permissionTest; - - private CommodoreCommand(LiteralCommandNode node, Predicate permissionTest) { - this.node = node; - this.permissionTest = permissionTest; - } - - public void apply(Player player, RootCommandNode root) { - if (this.permissionTest != null && !this.permissionTest.test((Player)player)) { - return; - } - AbstractCommodore.removeChild(root, this.node.getName()); - root.addChild(this.node); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/ReflectionCommodore.java b/source/decompiled/de/maxhenkel/voicechat/commodore/ReflectionCommodore.java deleted file mode 100644 index 9d7bba5..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/ReflectionCommodore.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.CommandDispatcher - * com.mojang.brigadier.builder.LiteralArgumentBuilder - * com.mojang.brigadier.suggestion.SuggestionProvider - * com.mojang.brigadier.tree.CommandNode - * com.mojang.brigadier.tree.LiteralCommandNode - * com.mojang.brigadier.tree.RootCommandNode - * org.bukkit.Bukkit - * org.bukkit.command.Command - * org.bukkit.entity.Player - * org.bukkit.event.EventHandler - * org.bukkit.event.Listener - * org.bukkit.event.player.PlayerCommandSendEvent - * org.bukkit.event.server.ServerLoadEvent - * org.bukkit.plugin.Plugin - */ -package de.maxhenkel.voicechat.commodore; - -import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.suggestion.SuggestionProvider; -import com.mojang.brigadier.tree.CommandNode; -import com.mojang.brigadier.tree.LiteralCommandNode; -import com.mojang.brigadier.tree.RootCommandNode; -import de.maxhenkel.voicechat.commodore.AbstractCommodore; -import de.maxhenkel.voicechat.commodore.Commodore; -import de.maxhenkel.voicechat.commodore.ReflectionUtil; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import org.bukkit.Bukkit; -import org.bukkit.command.Command; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerCommandSendEvent; -import org.bukkit.event.server.ServerLoadEvent; -import org.bukkit.plugin.Plugin; - -final class ReflectionCommodore -extends AbstractCommodore -implements Commodore { - private static final Field CONSOLE_FIELD; - private static final Method GET_COMMAND_DISPATCHER_METHOD; - private static final Method GET_BRIGADIER_DISPATCHER_METHOD; - private static final Constructor COMMAND_WRAPPER_CONSTRUCTOR; - private final Plugin plugin; - private final List> registeredNodes = new ArrayList(); - - ReflectionCommodore(Plugin plugin) { - this.plugin = plugin; - this.plugin.getServer().getPluginManager().registerEvents((Listener)new ServerReloadListener(this), this.plugin); - } - - private CommandDispatcher getDispatcher() { - try { - Object mcServerObject = CONSOLE_FIELD.get(Bukkit.getServer()); - Object commandDispatcherObject = GET_COMMAND_DISPATCHER_METHOD.invoke(mcServerObject, new Object[0]); - return (CommandDispatcher)GET_BRIGADIER_DISPATCHER_METHOD.invoke(commandDispatcherObject, new Object[0]); - } - catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - @Override - public void register(LiteralCommandNode node) { - Objects.requireNonNull(node, "node"); - CommandDispatcher dispatcher = this.getDispatcher(); - RootCommandNode root = dispatcher.getRoot(); - ReflectionCommodore.removeChild(root, node.getName()); - root.addChild(node); - this.registeredNodes.add(node); - } - - @Override - public void register(Command command, LiteralCommandNode node, Predicate permissionTest) { - Objects.requireNonNull(command, "command"); - Objects.requireNonNull(node, "node"); - Objects.requireNonNull(permissionTest, "permissionTest"); - try { - SuggestionProvider wrapper = (SuggestionProvider)COMMAND_WRAPPER_CONSTRUCTOR.newInstance(this.plugin.getServer(), command); - ReflectionCommodore.setRequiredHackyFieldsRecursively(node, wrapper); - } - catch (Throwable e) { - e.printStackTrace(); - } - Collection aliases = ReflectionCommodore.getAliases(command); - if (!aliases.contains(node.getLiteral())) { - node = ReflectionCommodore.renameLiteralNode(node, command.getName()); - } - for (String alias : aliases) { - if (node.getLiteral().equals(alias)) { - this.register(node); - continue; - } - this.register(((LiteralArgumentBuilder)LiteralArgumentBuilder.literal((String)alias).redirect(node)).build()); - } - this.plugin.getServer().getPluginManager().registerEvents((Listener)new CommandDataSendListener(command, permissionTest), this.plugin); - } - - static void ensureSetup() { - } - - static { - try { - Class commandDispatcher; - Class minecraftServer; - if (ReflectionUtil.minecraftVersion() >= 19) { - throw new UnsupportedOperationException("ReflectionCommodore is not supported on MC 1.19 or above. Switch to Paper :)"); - } - if (ReflectionUtil.minecraftVersion() > 16) { - minecraftServer = ReflectionUtil.mcClass("server.MinecraftServer"); - commandDispatcher = ReflectionUtil.mcClass("commands.CommandDispatcher"); - } else { - minecraftServer = ReflectionUtil.nmsClass("MinecraftServer"); - commandDispatcher = ReflectionUtil.nmsClass("CommandDispatcher"); - } - Class craftServer = ReflectionUtil.obcClass("CraftServer"); - CONSOLE_FIELD = craftServer.getDeclaredField("console"); - CONSOLE_FIELD.setAccessible(true); - GET_COMMAND_DISPATCHER_METHOD = Arrays.stream(minecraftServer.getDeclaredMethods()).filter(method -> method.getParameterCount() == 0).filter(method -> commandDispatcher.isAssignableFrom(method.getReturnType())).findFirst().orElseThrow(NoSuchMethodException::new); - GET_COMMAND_DISPATCHER_METHOD.setAccessible(true); - GET_BRIGADIER_DISPATCHER_METHOD = Arrays.stream(commandDispatcher.getDeclaredMethods()).filter(method -> method.getParameterCount() == 0).filter(method -> CommandDispatcher.class.isAssignableFrom(method.getReturnType())).findFirst().orElseThrow(NoSuchMethodException::new); - GET_BRIGADIER_DISPATCHER_METHOD.setAccessible(true); - Class commandWrapperClass = ReflectionUtil.obcClass("command.BukkitCommandWrapper"); - COMMAND_WRAPPER_CONSTRUCTOR = commandWrapperClass.getConstructor(craftServer, Command.class); - } - catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } - - private static final class ServerReloadListener - implements Listener { - private final ReflectionCommodore commodore; - - private ServerReloadListener(ReflectionCommodore commodore) { - this.commodore = commodore; - } - - @EventHandler - public void onLoad(ServerLoadEvent e) { - CommandDispatcher dispatcher = this.commodore.getDispatcher(); - RootCommandNode root = dispatcher.getRoot(); - for (LiteralCommandNode node : this.commodore.registeredNodes) { - AbstractCommodore.removeChild(root, node.getName()); - root.addChild((CommandNode)node); - } - } - } - - private static final class CommandDataSendListener - implements Listener { - private final Set aliases; - private final Set minecraftPrefixedAliases; - private final Predicate permissionTest; - - CommandDataSendListener(Command pluginCommand, Predicate permissionTest) { - this.aliases = new HashSet(AbstractCommodore.getAliases(pluginCommand)); - this.minecraftPrefixedAliases = this.aliases.stream().map(alias -> "minecraft:" + alias).collect(Collectors.toSet()); - this.permissionTest = permissionTest; - } - - @EventHandler - public void onCommandSend(PlayerCommandSendEvent e) { - e.getCommands().removeAll(this.minecraftPrefixedAliases); - if (!this.permissionTest.test((Player)e.getPlayer())) { - e.getCommands().removeAll(this.aliases); - } - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/ReflectionUtil.java b/source/decompiled/de/maxhenkel/voicechat/commodore/ReflectionUtil.java deleted file mode 100644 index 21469ce..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/ReflectionUtil.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.Bukkit - */ -package de.maxhenkel.voicechat.commodore; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.bukkit.Bukkit; - -final class ReflectionUtil { - private static final String SERVER_VERSION = ReflectionUtil.getServerVersion(); - - private static String getServerVersion() { - Class server = Bukkit.getServer().getClass(); - if (!server.getSimpleName().equals("CraftServer")) { - return "."; - } - if (server.getName().equals("org.bukkit.craftbukkit.CraftServer")) { - return "."; - } - String version = server.getName().substring("org.bukkit.craftbukkit".length()); - return version.substring(0, version.length() - "CraftServer".length()); - } - - public static String mc(String name) { - return "net.minecraft." + name; - } - - public static String nms(String className) { - return "net.minecraft.server" + SERVER_VERSION + className; - } - - public static Class mcClass(String className) throws ClassNotFoundException { - return Class.forName(ReflectionUtil.mc(className)); - } - - public static Class nmsClass(String className) throws ClassNotFoundException { - return Class.forName(ReflectionUtil.nms(className)); - } - - public static String obc(String className) { - return "org.bukkit.craftbukkit" + SERVER_VERSION + className; - } - - public static Class obcClass(String className) throws ClassNotFoundException { - return Class.forName(ReflectionUtil.obc(className)); - } - - public static int minecraftVersion() { - try { - Matcher matcher = Pattern.compile("\\(MC: (\\d)\\.(\\d+)\\.?(\\d+?)?( .*)?\\)").matcher(Bukkit.getVersion()); - if (matcher.find()) { - return Integer.parseInt(matcher.toMatchResult().group(2), 10); - } - throw new IllegalArgumentException(String.format("No match found in '%s'", Bukkit.getVersion())); - } - catch (IllegalArgumentException ex) { - throw new RuntimeException("Failed to determine Minecraft version", ex); - } - } - - private ReflectionUtil() { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/file/AbstractIterator.java b/source/decompiled/de/maxhenkel/voicechat/commodore/file/AbstractIterator.java deleted file mode 100644 index 7143455..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/file/AbstractIterator.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.commodore.file; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -abstract class AbstractIterator -implements Iterator { - private State state = State.NOT_READY; - private T next; - - protected AbstractIterator() { - } - - protected abstract T computeNext() throws Exception; - - protected final T endOfData() { - this.state = State.DONE; - return null; - } - - @Override - public final boolean hasNext() { - if (this.state == State.FAILED) { - throw new IllegalStateException(); - } - switch (this.state) { - case DONE: { - return false; - } - case READY: { - return true; - } - } - return this.tryToComputeNext(); - } - - private boolean tryToComputeNext() { - this.state = State.FAILED; - try { - this.next = this.computeNext(); - } - catch (Exception e) { - throw new RuntimeException("Exception whilst computing next value", e); - } - if (this.state != State.DONE) { - this.state = State.READY; - return true; - } - return false; - } - - @Override - public final T next() { - if (!this.hasNext()) { - throw new NoSuchElementException(); - } - this.state = State.NOT_READY; - T result = this.next; - this.next = null; - return result; - } - - public final T peek() { - if (!this.hasNext()) { - throw new NoSuchElementException(); - } - return this.next; - } - - private static enum State { - READY, - NOT_READY, - DONE, - FAILED; - - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/file/ArgumentTypeParser.java b/source/decompiled/de/maxhenkel/voicechat/commodore/file/ArgumentTypeParser.java deleted file mode 100644 index 3a592f7..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/file/ArgumentTypeParser.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - */ -package de.maxhenkel.voicechat.commodore.file; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.commodore.file.ParseException; -import de.maxhenkel.voicechat.commodore.file.TokenStream; - -public interface ArgumentTypeParser { - public boolean canParse(String var1, String var2); - - public ArgumentType parse(String var1, String var2, TokenStream var3) throws ParseException; -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/file/BrigadierArgumentTypeParser.java b/source/decompiled/de/maxhenkel/voicechat/commodore/file/BrigadierArgumentTypeParser.java deleted file mode 100644 index 558f72b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/file/BrigadierArgumentTypeParser.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * com.mojang.brigadier.arguments.BoolArgumentType - * com.mojang.brigadier.arguments.DoubleArgumentType - * com.mojang.brigadier.arguments.FloatArgumentType - * com.mojang.brigadier.arguments.IntegerArgumentType - * com.mojang.brigadier.arguments.LongArgumentType - * com.mojang.brigadier.arguments.StringArgumentType - */ -package de.maxhenkel.voicechat.commodore.file; - -import com.mojang.brigadier.arguments.ArgumentType; -import com.mojang.brigadier.arguments.BoolArgumentType; -import com.mojang.brigadier.arguments.DoubleArgumentType; -import com.mojang.brigadier.arguments.FloatArgumentType; -import com.mojang.brigadier.arguments.IntegerArgumentType; -import com.mojang.brigadier.arguments.LongArgumentType; -import com.mojang.brigadier.arguments.StringArgumentType; -import de.maxhenkel.voicechat.commodore.file.ArgumentTypeParser; -import de.maxhenkel.voicechat.commodore.file.ParseException; -import de.maxhenkel.voicechat.commodore.file.Token; -import de.maxhenkel.voicechat.commodore.file.TokenStream; - -public class BrigadierArgumentTypeParser -implements ArgumentTypeParser { - public static final BrigadierArgumentTypeParser INSTANCE = new BrigadierArgumentTypeParser(); - - private BrigadierArgumentTypeParser() { - } - - @Override - public boolean canParse(String namespace, String name) { - if (!namespace.equals("brigadier")) { - return false; - } - switch (name) { - case "bool": - case "string": - case "integer": - case "long": - case "float": - case "double": { - return true; - } - } - return false; - } - - @Override - public ArgumentType parse(String namespace, String name, TokenStream tokens) throws ParseException { - switch (name) { - case "bool": { - return BoolArgumentType.bool(); - } - case "string": { - return BrigadierArgumentTypeParser.parseStringArgumentType(tokens); - } - case "integer": { - return BrigadierArgumentTypeParser.parseIntegerArgumentType(tokens); - } - case "long": { - return BrigadierArgumentTypeParser.parseLongArgumentType(tokens); - } - case "float": { - return BrigadierArgumentTypeParser.parseFloatArgumentType(tokens); - } - case "double": { - return BrigadierArgumentTypeParser.parseDoubleArgumentType(tokens); - } - } - throw new AssertionError(); - } - - private static StringArgumentType parseStringArgumentType(TokenStream tokens) throws ParseException { - String stringType; - Token token = tokens.next(); - if (!(token instanceof Token.StringToken)) { - throw tokens.createException("Expected string token for string type but got " + token); - } - switch (stringType = ((Token.StringToken)token).getString()) { - case "single_word": { - return StringArgumentType.word(); - } - case "quotable_phrase": { - return StringArgumentType.string(); - } - case "greedy_phrase": { - return StringArgumentType.greedyString(); - } - } - throw tokens.createException("Unknown string type: " + stringType); - } - - private static IntegerArgumentType parseIntegerArgumentType(TokenStream tokens) throws ParseException { - if (tokens.peek() instanceof Token.StringToken) { - int min = BrigadierArgumentTypeParser.parseInt(tokens); - if (tokens.peek() instanceof Token.StringToken) { - int max = BrigadierArgumentTypeParser.parseInt(tokens); - return IntegerArgumentType.integer((int)min, (int)max); - } - return IntegerArgumentType.integer((int)min); - } - return IntegerArgumentType.integer(); - } - - private static LongArgumentType parseLongArgumentType(TokenStream tokens) throws ParseException { - if (tokens.peek() instanceof Token.StringToken) { - long min = BrigadierArgumentTypeParser.parseLong(tokens); - if (tokens.peek() instanceof Token.StringToken) { - long max = BrigadierArgumentTypeParser.parseLong(tokens); - return LongArgumentType.longArg((long)min, (long)max); - } - return LongArgumentType.longArg((long)min); - } - return LongArgumentType.longArg(); - } - - private static FloatArgumentType parseFloatArgumentType(TokenStream tokens) throws ParseException { - if (tokens.peek() instanceof Token.StringToken) { - float min = BrigadierArgumentTypeParser.parseFloat(tokens); - if (tokens.peek() instanceof Token.StringToken) { - float max = BrigadierArgumentTypeParser.parseFloat(tokens); - return FloatArgumentType.floatArg((float)min, (float)max); - } - return FloatArgumentType.floatArg((float)min); - } - return FloatArgumentType.floatArg(); - } - - private static DoubleArgumentType parseDoubleArgumentType(TokenStream tokens) throws ParseException { - if (tokens.peek() instanceof Token.StringToken) { - double min = BrigadierArgumentTypeParser.parseDouble(tokens); - if (tokens.peek() instanceof Token.StringToken) { - double max = BrigadierArgumentTypeParser.parseDouble(tokens); - return DoubleArgumentType.doubleArg((double)min, (double)max); - } - return DoubleArgumentType.doubleArg((double)min); - } - return DoubleArgumentType.doubleArg(); - } - - private static int parseInt(TokenStream tokens) throws ParseException { - Token token = tokens.next(); - if (!(token instanceof Token.StringToken)) { - throw tokens.createException("Expected string token for integer but got " + token); - } - String value = ((Token.StringToken)token).getString(); - if (value.equals("min")) { - return Integer.MIN_VALUE; - } - if (value.equals("max")) { - return Integer.MAX_VALUE; - } - try { - return Integer.parseInt(value); - } - catch (NumberFormatException e) { - throw tokens.createException("Expected int but got " + value, e); - } - } - - private static long parseLong(TokenStream tokens) throws ParseException { - Token token = tokens.next(); - if (!(token instanceof Token.StringToken)) { - throw tokens.createException("Expected string token for long but got " + token); - } - String value = ((Token.StringToken)token).getString(); - if (value.equals("min")) { - return Long.MIN_VALUE; - } - if (value.equals("max")) { - return Long.MAX_VALUE; - } - try { - return Long.parseLong(value); - } - catch (NumberFormatException e) { - throw tokens.createException("Expected long but got " + value, e); - } - } - - private static float parseFloat(TokenStream tokens) throws ParseException { - Token token = tokens.next(); - if (!(token instanceof Token.StringToken)) { - throw tokens.createException("Expected string token for float but got " + token); - } - String value = ((Token.StringToken)token).getString(); - if (value.equals("min")) { - return Float.MIN_VALUE; - } - if (value.equals("max")) { - return Float.MAX_VALUE; - } - try { - return Float.parseFloat(value); - } - catch (NumberFormatException e) { - throw tokens.createException("Expected float but got " + value, e); - } - } - - private static double parseDouble(TokenStream tokens) throws ParseException { - Token token = tokens.next(); - if (!(token instanceof Token.StringToken)) { - throw tokens.createException("Expected string token for double but got " + token); - } - String value = ((Token.StringToken)token).getString(); - if (value.equals("min")) { - return Double.MIN_VALUE; - } - if (value.equals("max")) { - return Double.MAX_VALUE; - } - try { - return Double.parseDouble(value); - } - catch (NumberFormatException e) { - throw tokens.createException("Expected double but got " + value); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/file/CommodoreFileReader.java b/source/decompiled/de/maxhenkel/voicechat/commodore/file/CommodoreFileReader.java deleted file mode 100644 index 8ded418..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/file/CommodoreFileReader.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.tree.LiteralCommandNode - */ -package de.maxhenkel.voicechat.commodore.file; - -import com.mojang.brigadier.tree.LiteralCommandNode; -import de.maxhenkel.voicechat.commodore.file.ArgumentTypeParser; -import de.maxhenkel.voicechat.commodore.file.BrigadierArgumentTypeParser; -import de.maxhenkel.voicechat.commodore.file.Lexer; -import de.maxhenkel.voicechat.commodore.file.ParseException; -import de.maxhenkel.voicechat.commodore.file.Parser; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -public class CommodoreFileReader { - public static final CommodoreFileReader INSTANCE = CommodoreFileReader.builder().withArgumentTypeParser(BrigadierArgumentTypeParser.INSTANCE).build(); - private final List argumentTypeParsers; - - public static Builder builder() { - return new Builder(); - } - - CommodoreFileReader(List argumentTypeParsers) { - this.argumentTypeParsers = Collections.unmodifiableList(argumentTypeParsers); - } - - public LiteralCommandNode parse(Reader reader) throws IOException { - try { - return new Parser(new Lexer(reader), this.argumentTypeParsers).parse(); - } - catch (ParseException e) { - if (e.getCause() instanceof IOException) { - throw (IOException)e.getCause(); - } - throw new IOException(e); - } - } - - public LiteralCommandNode parse(InputStream inputStream) throws IOException { - try (InputStreamReader reader = new InputStreamReader(inputStream);){ - LiteralCommandNode literalCommandNode = this.parse(reader); - return literalCommandNode; - } - } - - public LiteralCommandNode parse(Path path) throws IOException { - try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);){ - LiteralCommandNode literalCommandNode = this.parse(reader); - return literalCommandNode; - } - } - - public LiteralCommandNode parse(File file) throws IOException { - return this.parse(file.toPath()); - } - - public static final class Builder { - private final List argumentTypeParsers = new ArrayList(); - - Builder() { - } - - public Builder withArgumentTypeParser(ArgumentTypeParser argumentTypeParser) { - Objects.requireNonNull(argumentTypeParser, "argumentTypeParser"); - this.argumentTypeParsers.add(argumentTypeParser); - return this; - } - - public CommodoreFileReader build() { - return new CommodoreFileReader(new ArrayList(this.argumentTypeParsers)); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/file/Lexer.java b/source/decompiled/de/maxhenkel/voicechat/commodore/file/Lexer.java deleted file mode 100644 index fbce218..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/file/Lexer.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.commodore.file; - -import de.maxhenkel.voicechat.commodore.file.AbstractIterator; -import de.maxhenkel.voicechat.commodore.file.ParseException; -import de.maxhenkel.voicechat.commodore.file.Token; -import de.maxhenkel.voicechat.commodore.file.TokenStream; -import java.io.IOException; -import java.io.Reader; -import java.io.StreamTokenizer; - -class Lexer -extends AbstractIterator -implements TokenStream { - private final StreamTokenizer tokenizer; - private boolean end = false; - - Lexer(Reader reader) { - this.tokenizer = new StreamTokenizer(reader); - this.tokenizer.resetSyntax(); - this.tokenizer.wordChars(33, 126); - this.tokenizer.quoteChar(34); - this.tokenizer.whitespaceChars(0, 32); - "{};".chars().forEach(this.tokenizer::ordinaryChar); - this.tokenizer.slashSlashComments(true); - this.tokenizer.slashStarComments(true); - } - - @Override - protected Token computeNext() throws ParseException { - if (this.end) { - return (Token)this.endOfData(); - } - try { - int token = this.tokenizer.nextToken(); - switch (token) { - case -1: { - this.end = true; - return Token.ConstantToken.EOF; - } - case -3: { - return new Token.StringToken(this.tokenizer.sval); - } - case 123: { - return Token.ConstantToken.OPEN_BRACKET; - } - case 125: { - return Token.ConstantToken.CLOSE_BRACKET; - } - case 59: { - return Token.ConstantToken.SEMICOLON; - } - } - throw this.createException("Unknown token: " + (char)token + "(" + token + ")"); - } - catch (IOException e) { - throw this.createException(e); - } - } - - @Override - public ParseException createException(String message) { - return new ParseException(message, this.tokenizer.lineno()); - } - - @Override - public ParseException createException(Throwable cause) { - return new ParseException(cause, this.tokenizer.lineno()); - } - - @Override - public ParseException createException(String message, Throwable cause) { - return new ParseException(message, cause, this.tokenizer.lineno()); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/file/ParseException.java b/source/decompiled/de/maxhenkel/voicechat/commodore/file/ParseException.java deleted file mode 100644 index d8fa1c4..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/file/ParseException.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.commodore.file; - -public final class ParseException -extends Exception { - ParseException(String message, int currentLine) { - super(message + " (at line " + currentLine + ")"); - } - - ParseException(Throwable cause, int currentLine) { - super("At line " + currentLine, cause); - } - - ParseException(String message, Throwable cause, int currentLine) { - super(message + " (at line " + currentLine + ")", cause); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/file/Parser.java b/source/decompiled/de/maxhenkel/voicechat/commodore/file/Parser.java deleted file mode 100644 index 099efeb..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/file/Parser.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * com.mojang.brigadier.builder.LiteralArgumentBuilder - * com.mojang.brigadier.builder.RequiredArgumentBuilder - * com.mojang.brigadier.tree.CommandNode - * com.mojang.brigadier.tree.LiteralCommandNode - */ -package de.maxhenkel.voicechat.commodore.file; - -import com.mojang.brigadier.arguments.ArgumentType; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.builder.RequiredArgumentBuilder; -import com.mojang.brigadier.tree.CommandNode; -import com.mojang.brigadier.tree.LiteralCommandNode; -import de.maxhenkel.voicechat.commodore.file.ArgumentTypeParser; -import de.maxhenkel.voicechat.commodore.file.Lexer; -import de.maxhenkel.voicechat.commodore.file.ParseException; -import de.maxhenkel.voicechat.commodore.file.Token; -import java.util.Arrays; -import java.util.Collection; - -class Parser { - private final Lexer lexer; - private final Collection argumentTypeParsers; - - Parser(Lexer lexer, Collection argumentTypeParsers) { - this.lexer = lexer; - this.argumentTypeParsers = argumentTypeParsers; - } - - LiteralCommandNode parse() throws ParseException { - CommandNode node = this.parseNode(); - if (!(node instanceof LiteralCommandNode)) { - throw this.lexer.createException("Root command node is not a literal command node"); - } - if (this.lexer.peek() != Token.ConstantToken.EOF) { - throw this.lexer.createException("Expected end of file but got " + this.lexer.peek()); - } - return (LiteralCommandNode)node; - } - - private CommandNode parseNode() throws ParseException { - Token token = (Token)this.lexer.next(); - if (!(token instanceof Token.StringToken)) { - throw this.lexer.createException("Expected string token for node name but got " + token); - } - String name = ((Token.StringToken)token).getString(); - Object node = this.lexer.peek() instanceof Token.StringToken ? RequiredArgumentBuilder.argument((String)name, this.parseArgumentType()) : LiteralArgumentBuilder.literal((String)name); - if (this.lexer.peek() == Token.ConstantToken.OPEN_BRACKET) { - this.lexer.next(); - while (this.lexer.peek() != Token.ConstantToken.CLOSE_BRACKET) { - CommandNode child = this.parseNode(); - node.then(child); - } - this.lexer.next(); - } else { - if (this.lexer.peek() != Token.ConstantToken.SEMICOLON) { - throw this.lexer.createException("Node definition not ended with semicolon, got " + this.lexer.peek()); - } - this.lexer.next(); - } - return node.build(); - } - - private ArgumentType parseArgumentType() throws ParseException { - Token token = (Token)this.lexer.next(); - if (!(token instanceof Token.StringToken)) { - throw this.lexer.createException("Expected string token for argument type but got " + token); - } - String argumentType = ((Token.StringToken)token).getString(); - Object[] key = argumentType.split(":"); - if (key.length != 2) { - throw this.lexer.createException("Invalid key for argument type: " + Arrays.toString(key)); - } - for (ArgumentTypeParser parser : this.argumentTypeParsers) { - if (!parser.canParse((String)key[0], (String)key[1])) continue; - return parser.parse((String)key[0], (String)key[1], this.lexer); - } - throw this.lexer.createException("Unable to parse argument type: " + argumentType); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/file/Token.java b/source/decompiled/de/maxhenkel/voicechat/commodore/file/Token.java deleted file mode 100644 index 089158f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/file/Token.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.commodore.file; - -public interface Token { - - public static final class StringToken - implements Token { - private final String string; - - StringToken(String string) { - this.string = string; - } - - public String getString() { - return this.string; - } - } - - public static enum ConstantToken implements Token - { - OPEN_BRACKET, - CLOSE_BRACKET, - SEMICOLON, - EOF; - - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/commodore/file/TokenStream.java b/source/decompiled/de/maxhenkel/voicechat/commodore/file/TokenStream.java deleted file mode 100644 index 73b0c38..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/commodore/file/TokenStream.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.commodore.file; - -import de.maxhenkel.voicechat.commodore.file.ParseException; -import de.maxhenkel.voicechat.commodore.file.Token; - -public interface TokenStream { - public boolean hasNext(); - - public Token next(); - - public Token peek(); - - public ParseException createException(String var1); - - public ParseException createException(Throwable var1); - - public ParseException createException(String var1, Throwable var2); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/BaseCompatibility.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/BaseCompatibility.java deleted file mode 100644 index bcf683a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/BaseCompatibility.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.Bukkit - * org.bukkit.entity.Player - * org.bukkit.event.EventPriority - * org.bukkit.event.Listener - * org.bukkit.event.player.PlayerEvent - * org.bukkit.plugin.Plugin - */ -package de.maxhenkel.voicechat.compatibility; - -import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.compatibility.Compatibility; -import de.maxhenkel.voicechat.compatibility.CompatibilityReflectionException; -import de.maxhenkel.voicechat.compatibility.PlayerHideEvent; -import de.maxhenkel.voicechat.compatibility.PlayerShowEvent; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import de.maxhenkel.voicechat.util.Key; -import java.lang.reflect.Method; -import java.util.function.Consumer; -import javax.annotation.Nullable; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerEvent; -import org.bukkit.plugin.Plugin; - -public abstract class BaseCompatibility -implements Compatibility { - private String baseBukkitPackage; - private String baseServerPackage; - private Method addChannel; - private Method removeChannel; - @Nullable - private Class playerHideEntityEvent; - @Nullable - private Method playerHideEntityEventGetEntity; - @Nullable - private Class playerShowEntityEvent; - @Nullable - private Method playerShowEntityEventGetEntity; - private Consumer runTask; - private TaskScheduler taskScheduler; - - @Override - public void init() throws Exception { - Compatibility.super.init(); - this.baseBukkitPackage = Bukkit.getServer().getClass().getPackage().getName(); - this.baseServerPackage = ReflectionUtils.callMethod((Object)Bukkit.getServer(), "getServer").getClass().getPackage().getName(); - Class craftPlayer = this.getBukkitClass("entity.CraftPlayer"); - this.addChannel = ReflectionUtils.getMethod(craftPlayer, new String[]{"addChannel"}, new Class[]{String.class}); - this.removeChannel = ReflectionUtils.getMethod(craftPlayer, new String[]{"removeChannel"}, new Class[]{String.class}); - try { - if (ReflectionUtils.doesClassExist("org.bukkit.event.player.PlayerHideEntityEvent") && ReflectionUtils.doesClassExist("org.bukkit.event.player.PlayerShowEntityEvent")) { - Class hide = ReflectionUtils.getClazz("org.bukkit.event.player.PlayerHideEntityEvent"); - if (!PlayerEvent.class.isAssignableFrom(hide)) { - throw new CompatibilityReflectionException("PlayerHideEntityEvent is not a subclass of PlayerEvent"); - } - Class show = ReflectionUtils.getClazz("org.bukkit.event.player.PlayerShowEntityEvent"); - if (!PlayerEvent.class.isAssignableFrom(show)) { - throw new CompatibilityReflectionException("PlayerShowEntityEvent is not a subclass of PlayerEvent"); - } - this.playerShowEntityEventGetEntity = ReflectionUtils.getMethod(show, "getEntity"); - this.playerHideEntityEventGetEntity = ReflectionUtils.getMethod(hide, "getEntity"); - this.playerShowEntityEvent = show; - this.playerHideEntityEvent = hide; - } else { - Voicechat.LOGGER.warn("Vanish plugin integration is not supported", new Object[0]); - } - } - catch (CompatibilityReflectionException e) { - Voicechat.LOGGER.warn("Vanish plugin integration is disabled", new Object[0]); - Voicechat.LOGGER.warn("Failed to load vanish compatibility", e); - this.playerHideEntityEvent = null; - this.playerShowEntityEvent = null; - } - this.runTask = runnable -> Bukkit.getScheduler().runTask((Plugin)Voicechat.INSTANCE, runnable); - this.taskScheduler = new TaskScheduler(){ - - @Override - public void scheduleSyncRepeatingTask(Runnable runnable, long delay, long period) { - Bukkit.getScheduler().scheduleSyncRepeatingTask((Plugin)Voicechat.INSTANCE, runnable, delay, period); - } - - @Override - public void runTaskLater(Runnable runnable, long delay) { - Bukkit.getScheduler().runTaskLater((Plugin)Voicechat.INSTANCE, runnable, delay); - } - }; - if (ReflectionUtils.doesMethodExist(Bukkit.class, "getGlobalRegionScheduler", new Class[0])) { - final Object globalRegionScheduler = ReflectionUtils.callMethod(Bukkit.class, "getGlobalRegionScheduler"); - Method run = ReflectionUtils.getMethod(globalRegionScheduler.getClass(), new String[]{"run"}, new Class[]{Plugin.class, Consumer.class}); - this.runTask = runnable -> ReflectionUtils.call(run, globalRegionScheduler, new Object[]{Voicechat.INSTANCE, task -> runnable.run()}); - if (ReflectionUtils.doesMethodExist(globalRegionScheduler.getClass(), "runAtFixedRate", Plugin.class, Consumer.class, Long.TYPE, Long.TYPE) && ReflectionUtils.doesMethodExist(globalRegionScheduler.getClass(), "runDelayed", Plugin.class, Consumer.class, Long.TYPE)) { - final Method runAtFixedRate = ReflectionUtils.getMethod(globalRegionScheduler.getClass(), new String[]{"runAtFixedRate"}, new Class[]{Plugin.class, Consumer.class, Long.TYPE, Long.TYPE}); - final Method runDelayed = ReflectionUtils.getMethod(globalRegionScheduler.getClass(), new String[]{"runDelayed"}, new Class[]{Plugin.class, Consumer.class, Long.TYPE}); - this.taskScheduler = new TaskScheduler(){ - final /* synthetic */ BaseCompatibility this$0; - { - this.this$0 = this$0; - } - - @Override - public void scheduleSyncRepeatingTask(Runnable runnable, long delay, long period) { - ReflectionUtils.call(runAtFixedRate, globalRegionScheduler, new Object[]{Voicechat.INSTANCE, task -> runnable.run(), delay <= 0L ? 1L : delay, period}); - } - - @Override - public void runTaskLater(Runnable runnable, long delay) { - ReflectionUtils.call(runDelayed, globalRegionScheduler, new Object[]{Voicechat.INSTANCE, task -> runnable.run(), delay <= 0L ? 1L : delay}); - } - }; - } - } - } - - @Override - public void addChannel(Player player, String channel) { - ReflectionUtils.call(this.addChannel, player, channel); - } - - @Override - public void removeChannel(Player player, String channel) { - ReflectionUtils.call(this.removeChannel, player, channel); - } - - @Override - public Key createNamespacedKey(String key) { - return Key.of(key); - } - - @Override - public void runTask(Runnable runnable) { - this.runTask.accept(runnable); - } - - @Override - public void scheduleSyncRepeatingTask(Runnable runnable, long delay, long period) { - this.taskScheduler.scheduleSyncRepeatingTask(runnable, delay, period); - } - - @Override - public void runTaskLater(Runnable runnable, long delay) { - this.taskScheduler.runTaskLater(runnable, delay); - } - - @Override - public boolean canSee(Player player, Player other) { - if (this.playerHideEntityEvent == null || this.playerShowEntityEvent == null) { - return true; - } - return player.canSee(other); - } - - @Override - public void registerPlayerHideEvent(Consumer event) { - if (this.playerHideEntityEvent == null) { - return; - } - Bukkit.getPluginManager().registerEvent(this.playerHideEntityEvent, new Listener(){}, EventPriority.NORMAL, (listener, evt) -> { - if (!evt.getClass().isAssignableFrom(this.playerHideEntityEvent)) { - return; - } - PlayerEvent playerEvent = (PlayerEvent)evt; - Object entityObj = ReflectionUtils.call(this.playerHideEntityEventGetEntity, playerEvent, new Object[0]); - if (!(entityObj instanceof Player)) { - return; - } - event.accept(new PlayerHideEvent((Player)entityObj, playerEvent.getPlayer())); - }, (Plugin)Voicechat.INSTANCE); - } - - @Override - public void registerPlayerShowEvent(Consumer event) { - if (this.playerShowEntityEvent == null) { - return; - } - Bukkit.getPluginManager().registerEvent(this.playerShowEntityEvent, new Listener(){}, EventPriority.NORMAL, (listener, evt) -> { - if (!evt.getClass().isAssignableFrom(this.playerShowEntityEvent)) { - return; - } - PlayerEvent playerEvent = (PlayerEvent)evt; - Object entityObj = ReflectionUtils.call(this.playerShowEntityEventGetEntity, playerEvent, new Object[0]); - if (!(entityObj instanceof Player)) { - return; - } - event.accept(new PlayerShowEvent((Player)entityObj, playerEvent.getPlayer())); - }, (Plugin)Voicechat.INSTANCE); - } - - @Override - public String getBaseBukkitPackage() { - return this.baseBukkitPackage; - } - - @Override - public String getBaseServerPackage() { - return this.baseServerPackage; - } - - private static interface TaskScheduler { - public void scheduleSyncRepeatingTask(Runnable var1, long var2, long var4); - - public void runTaskLater(Runnable var1, long var2); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility.java deleted file mode 100644 index 9fb6528..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * javax.annotation.Nullable - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.compatibility.CompatibilityReflectionException; -import de.maxhenkel.voicechat.compatibility.PlayerHideEvent; -import de.maxhenkel.voicechat.compatibility.PlayerShowEvent; -import de.maxhenkel.voicechat.util.Key; -import java.util.function.Consumer; -import javax.annotation.Nullable; -import org.bukkit.entity.Player; - -public interface Compatibility { - default public void init() throws Exception { - } - - public void addChannel(Player var1, String var2); - - public void removeChannel(Player var1, String var2); - - public Key createNamespacedKey(String var1); - - public void sendTranslationMessage(Player var1, String var2, String ... var3); - - public void sendStatusMessage(Player var1, String var2, String ... var3); - - public void sendInviteMessage(Player var1, Player var2, String var3, String var4); - - public void sendIncompatibleMessage(Player var1, String var2, String var3); - - public void runTask(Runnable var1); - - public void scheduleSyncRepeatingTask(Runnable var1, long var2, long var4); - - public void runTaskLater(Runnable var1, long var2); - - public boolean canSee(Player var1, Player var2); - - public void registerPlayerHideEvent(Consumer var1); - - public void registerPlayerShowEvent(Consumer var1); - - @Nullable - public ArgumentType playerArgument(); - - @Nullable - public ArgumentType uuidArgument(); - - public String getBaseBukkitPackage(); - - public String getBaseServerPackage(); - - default public Class getBukkitClass(String ... classNames) { - for (String className : classNames) { - try { - return Class.forName(String.format("%s.%s", this.getBaseBukkitPackage(), className)); - } - catch (Throwable throwable) { - } - } - throw new CompatibilityReflectionException(String.format("Could not find any of the following classes: %s", String.join((CharSequence)", ", classNames))); - } - - default public Class getServerClass(String ... classNames) { - for (String className : classNames) { - try { - return Class.forName(String.format("%s.%s", this.getBaseServerPackage(), className)); - } - catch (Throwable throwable) { - } - } - throw new CompatibilityReflectionException(String.format("Could not find any of the following classes: %s", String.join((CharSequence)", ", classNames))); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_12.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_12.java deleted file mode 100644 index 466446b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_12.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.compatibility.Compatibility1_8; -import de.maxhenkel.voicechat.compatibility.JsonMessageBaseCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import de.maxhenkel.voicechat.util.Key; -import org.bukkit.entity.Player; - -public class Compatibility1_12 -extends JsonMessageBaseCompatibility { - public static final String CHANNEL = "vc"; - public static final BukkitVersion VERSION_1_12_2 = BukkitVersion.parseBukkitVersion("1.12.2-R0.1"); - public static final BukkitVersion VERSION_1_12_1 = BukkitVersion.parseBukkitVersion("1.12.1-R0.1"); - public static final BukkitVersion VERSION_1_12 = BukkitVersion.parseBukkitVersion("1.12-R0.1"); - public static final Compatibility1_12 INSTANCE = new Compatibility1_12(); - - @Override - public Key createNamespacedKey(String key) { - return Key.of(CHANNEL, key); - } - - @Override - public void sendJsonMessage(Player player, String json) { - Class chatMessageTypeClass = this.getServerClass("ChatMessageType"); - Object b = ReflectionUtils.getField(chatMessageTypeClass, "CHAT"); - this.send(player, json, b); - } - - @Override - public void sendJsonStatusMessage(Player player, String json) { - Class chatMessageTypeClass = this.getServerClass("ChatMessageType"); - Object b = ReflectionUtils.getField(chatMessageTypeClass, "GAME_INFO"); - this.send(player, json, b); - } - - @Override - public String createTranslationMessage(String key, String ... args) { - return Compatibility1_8.constructTranslationMessage(key, args); - } - - @Override - public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); - } - - @Override - public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); - } - - @Override - public ArgumentType playerArgument() { - return null; - } - - @Override - public ArgumentType uuidArgument() { - return null; - } - - private void send(Player player, String json, Object chatMessageType) { - Object entityPlayer = ReflectionUtils.callMethod((Object)player, "getHandle"); - Object playerConnection = ReflectionUtils.getField(entityPlayer, "playerConnection"); - Class packet = this.getServerClass("Packet"); - Class chatSerializer = this.getServerClass("IChatBaseComponent$ChatSerializer"); - Class iChatBaseComponentClass = this.getServerClass("IChatBaseComponent"); - Object iChatBaseComponent = ReflectionUtils.callMethod(chatSerializer, "a", new Class[]{String.class}, json); - Class packetPlayOutChatClass = this.getServerClass("PacketPlayOutChat"); - Class chatMessageTypeClass = this.getServerClass("ChatMessageType"); - Object clientboundSystemChatPacket = ReflectionUtils.callConstructor(packetPlayOutChatClass, new Class[]{iChatBaseComponentClass, chatMessageTypeClass}, iChatBaseComponent, chatMessageType); - ReflectionUtils.callMethod(playerConnection, "sendPacket", new Class[]{packet}, clientboundSystemChatPacket); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_16.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_16.java deleted file mode 100644 index 8f7ee8c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_16.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.compatibility.Compatibility1_8; -import de.maxhenkel.voicechat.compatibility.JsonMessageBaseCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import java.util.UUID; -import org.bukkit.entity.Player; - -public class Compatibility1_16 -extends JsonMessageBaseCompatibility { - public static final BukkitVersion VERSION_1_16_5 = BukkitVersion.parseBukkitVersion("1.16.5-R0.1"); - public static final BukkitVersion VERSION_1_16_4 = BukkitVersion.parseBukkitVersion("1.16.4-R0.1"); - public static final BukkitVersion VERSION_1_16_3 = BukkitVersion.parseBukkitVersion("1.16.3-R0.1"); - public static final BukkitVersion VERSION_1_16_2 = BukkitVersion.parseBukkitVersion("1.16.2-R0.1"); - public static final BukkitVersion VERSION_1_16_1 = BukkitVersion.parseBukkitVersion("1.16.1-R0.1"); - public static final BukkitVersion VERSION_1_16 = BukkitVersion.parseBukkitVersion("1.16-R0.1"); - public static final Compatibility1_16 INSTANCE = new Compatibility1_16(); - private static final UUID NUL_UUID = new UUID(0L, 0L); - - @Override - public void sendJsonMessage(Player player, String json) { - Class chatMessageTypeClass = this.getServerClass("ChatMessageType"); - Object b = ReflectionUtils.getField(chatMessageTypeClass, "CHAT"); - this.send(player, json, b); - } - - @Override - public void sendJsonStatusMessage(Player player, String json) { - Class chatMessageTypeClass = this.getServerClass("ChatMessageType"); - Object b = ReflectionUtils.getField(chatMessageTypeClass, "GAME_INFO"); - this.send(player, json, b); - } - - @Override - public String createTranslationMessage(String key, String ... args) { - return Compatibility1_8.constructTranslationMessage(key, args); - } - - @Override - public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); - } - - @Override - public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); - } - - @Override - public ArgumentType playerArgument() { - Class argumentEntity = this.getServerClass("ArgumentEntity"); - return (ArgumentType)ReflectionUtils.callMethod(argumentEntity, "c"); - } - - @Override - public ArgumentType uuidArgument() { - Class argumentEntity = this.getServerClass("ArgumentUUID"); - return (ArgumentType)ReflectionUtils.callMethod(argumentEntity, "a"); - } - - private void send(Player player, String json, Object chatMessageType) { - Object entityPlayer = ReflectionUtils.callMethod((Object)player, "getHandle"); - Object playerConnection = ReflectionUtils.getField(entityPlayer, "playerConnection"); - Class packet = this.getServerClass("Packet"); - Class chatSerializer = this.getServerClass("IChatBaseComponent$ChatSerializer"); - Class iChatBaseComponentClass = this.getServerClass("IChatBaseComponent"); - Object iChatBaseComponent = ReflectionUtils.callMethod(chatSerializer, "a", new Class[]{String.class}, json); - Class packetPlayOutChatClass = this.getServerClass("PacketPlayOutChat"); - Class chatMessageTypeClass = this.getServerClass("ChatMessageType"); - Object clientboundSystemChatPacket = ReflectionUtils.callConstructor(packetPlayOutChatClass, new Class[]{iChatBaseComponentClass, chatMessageTypeClass, UUID.class}, iChatBaseComponent, chatMessageType, NUL_UUID); - ReflectionUtils.callMethod(playerConnection, "sendPacket", new Class[]{packet}, clientboundSystemChatPacket); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_17.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_17.java deleted file mode 100644 index c543a09..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_17.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.compatibility.Compatibility1_19; -import de.maxhenkel.voicechat.compatibility.Compatibility1_8; -import de.maxhenkel.voicechat.compatibility.JsonMessageBaseCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import java.util.UUID; -import org.bukkit.entity.Player; - -public class Compatibility1_17 -extends JsonMessageBaseCompatibility { - public static final BukkitVersion VERSION_1_17_1 = BukkitVersion.parseBukkitVersion("1.17.1-R0.1"); - public static final BukkitVersion VERSION_1_17 = BukkitVersion.parseBukkitVersion("1.17-R0.1"); - public static final Compatibility1_17 INSTANCE = new Compatibility1_17(); - private static final UUID NUL_UUID = new UUID(0L, 0L); - - @Override - public void sendJsonMessage(Player player, String json) { - Class chatMessageTypeClass = ReflectionUtils.getClazz("net.minecraft.network.chat.ChatMessageType"); - Object b = ReflectionUtils.getField(chatMessageTypeClass, "b"); - this.send(player, json, b); - } - - @Override - public void sendJsonStatusMessage(Player player, String json) { - Class chatMessageTypeClass = ReflectionUtils.getClazz("net.minecraft.network.chat.ChatMessageType"); - Object b = ReflectionUtils.getField(chatMessageTypeClass, "c"); - this.send(player, json, b); - } - - @Override - public String createTranslationMessage(String key, String ... args) { - return Compatibility1_8.constructTranslationMessage(key, args); - } - - @Override - public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); - } - - @Override - public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); - } - - @Override - public ArgumentType playerArgument() { - return Compatibility1_19.INSTANCE.playerArgument(); - } - - @Override - public ArgumentType uuidArgument() { - return Compatibility1_19.INSTANCE.uuidArgument(); - } - - private void send(Player player, String json, Object chatMessageType) { - Object entityPlayer = ReflectionUtils.callMethod((Object)player, "getHandle"); - Object playerConnection = ReflectionUtils.getField(entityPlayer, "b"); - Class packet = ReflectionUtils.getClazz("net.minecraft.network.protocol.Packet"); - Class craftChatMessage = this.getBukkitClass("util.CraftChatMessage"); - Class iChatBaseComponentClass = ReflectionUtils.getClazz("net.minecraft.network.chat.IChatBaseComponent"); - Object iChatBaseComponent = ReflectionUtils.callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); - Class packetPlayOutChatClass = ReflectionUtils.getClazz("net.minecraft.network.protocol.game.PacketPlayOutChat"); - Class chatMessageTypeClass = ReflectionUtils.getClazz("net.minecraft.network.chat.ChatMessageType"); - Object clientboundSystemChatPacket = ReflectionUtils.callConstructor(packetPlayOutChatClass, new Class[]{iChatBaseComponentClass, chatMessageTypeClass, UUID.class}, iChatBaseComponent, chatMessageType, NUL_UUID); - ReflectionUtils.callMethod(playerConnection, "sendPacket", new Class[]{packet}, clientboundSystemChatPacket); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_18.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_18.java deleted file mode 100644 index 306d5bc..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_18.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.compatibility.Compatibility1_19; -import de.maxhenkel.voicechat.compatibility.Compatibility1_8; -import de.maxhenkel.voicechat.compatibility.JsonMessageBaseCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import java.util.UUID; -import org.bukkit.entity.Player; - -public class Compatibility1_18 -extends JsonMessageBaseCompatibility { - public static final BukkitVersion VERSION_1_18_2 = BukkitVersion.parseBukkitVersion("1.18.2-R0.1"); - public static final BukkitVersion VERSION_1_18_1 = BukkitVersion.parseBukkitVersion("1.18.1-R0.1"); - public static final BukkitVersion VERSION_1_18 = BukkitVersion.parseBukkitVersion("1.18-R0.1"); - public static final Compatibility1_18 INSTANCE = new Compatibility1_18(); - private static final UUID NUL_UUID = new UUID(0L, 0L); - - @Override - public void sendJsonMessage(Player player, String json) { - Class chatMessageTypeClass = ReflectionUtils.getClazz("net.minecraft.network.chat.ChatMessageType"); - Object b = ReflectionUtils.getField(chatMessageTypeClass, "b"); - this.send(player, json, b); - } - - @Override - public void sendJsonStatusMessage(Player player, String json) { - Class chatMessageTypeClass = ReflectionUtils.getClazz("net.minecraft.network.chat.ChatMessageType"); - Object b = ReflectionUtils.getField(chatMessageTypeClass, "c"); - this.send(player, json, b); - } - - @Override - public String createTranslationMessage(String key, String ... args) { - return Compatibility1_8.constructTranslationMessage(key, args); - } - - @Override - public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); - } - - @Override - public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); - } - - @Override - public ArgumentType playerArgument() { - return Compatibility1_19.INSTANCE.playerArgument(); - } - - @Override - public ArgumentType uuidArgument() { - return Compatibility1_19.INSTANCE.uuidArgument(); - } - - private void send(Player player, String json, Object chatMessageType) { - Object entityPlayer = ReflectionUtils.callMethod((Object)player, "getHandle"); - Object playerConnection = ReflectionUtils.getField(entityPlayer, "b"); - Class packet = ReflectionUtils.getClazz("net.minecraft.network.protocol.Packet"); - Class craftChatMessage = this.getBukkitClass("util.CraftChatMessage"); - Class iChatBaseComponentClass = ReflectionUtils.getClazz("net.minecraft.network.chat.IChatBaseComponent"); - Object iChatBaseComponent = ReflectionUtils.callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); - Class packetPlayOutChatClass = ReflectionUtils.getClazz("net.minecraft.network.protocol.game.PacketPlayOutChat"); - Class chatMessageTypeClass = ReflectionUtils.getClazz("net.minecraft.network.chat.ChatMessageType"); - Object clientboundSystemChatPacket = ReflectionUtils.callConstructor(packetPlayOutChatClass, new Class[]{iChatBaseComponentClass, chatMessageTypeClass, UUID.class}, iChatBaseComponent, chatMessageType, NUL_UUID); - ReflectionUtils.callMethod(playerConnection, "a", new Class[]{packet}, clientboundSystemChatPacket); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_19.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_19.java deleted file mode 100644 index beee97f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_19.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.compatibility.Compatibility1_19_1; -import de.maxhenkel.voicechat.compatibility.Compatibility1_8; -import de.maxhenkel.voicechat.compatibility.JsonMessageBaseCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import org.bukkit.entity.Player; - -public class Compatibility1_19 -extends JsonMessageBaseCompatibility { - public static final BukkitVersion VERSION_1_19 = BukkitVersion.parseBukkitVersion("1.19-R0.1"); - public static final Compatibility1_19 INSTANCE = new Compatibility1_19(); - - @Override - public void sendJsonMessage(Player player, String json) { - this.send(player, json, false); - } - - @Override - public void sendJsonStatusMessage(Player player, String json) { - this.send(player, json, true); - } - - @Override - public String createTranslationMessage(String key, String ... args) { - return Compatibility1_8.constructTranslationMessage(key, args); - } - - @Override - public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); - } - - @Override - public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); - } - - @Override - public ArgumentType playerArgument() { - return Compatibility1_19_1.INSTANCE.playerArgument(); - } - - @Override - public ArgumentType uuidArgument() { - return Compatibility1_19_1.INSTANCE.uuidArgument(); - } - - private void send(Player player, String json, boolean status) { - Object entityPlayer = ReflectionUtils.callMethod((Object)player, "getHandle"); - Object playerConnection = ReflectionUtils.getField(entityPlayer, "b"); - Class packet = ReflectionUtils.getClazz("net.minecraft.network.protocol.Packet"); - Class craftChatMessage = this.getBukkitClass("util.CraftChatMessage"); - Class iChatBaseComponentClass = ReflectionUtils.getClazz("net.minecraft.network.chat.IChatBaseComponent"); - Object iChatBaseComponent = ReflectionUtils.callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); - Class clientboundSystemChatPacketClass = ReflectionUtils.getClazz("net.minecraft.network.protocol.game.ClientboundSystemChatPacket"); - Object clientboundSystemChatPacket = ReflectionUtils.callConstructor(clientboundSystemChatPacketClass, new Class[]{iChatBaseComponentClass, Integer.TYPE}, iChatBaseComponent, this.getId(player, status)); - ReflectionUtils.callMethod(playerConnection, "a", new Class[]{packet}, clientboundSystemChatPacket); - } - - private int getId(Player player, boolean status) { - Object world = ReflectionUtils.callMethod((Object)player.getWorld(), "getHandle"); - Class iRegistryCustomClass = ReflectionUtils.getClazz("net.minecraft.core.IRegistryCustom"); - Object iRegistryCustom = ReflectionUtils.callMethod(world, "s"); - Class resourceKeyClass = ReflectionUtils.getClazz("net.minecraft.resources.ResourceKey"); - Class iRegistry = ReflectionUtils.getClazz("net.minecraft.core.IRegistry"); - Object resourceKey = ReflectionUtils.getField(iRegistry, "bI"); - Object registry = ReflectionUtils.callMethod(iRegistryCustomClass, iRegistryCustom, "d", new Class[]{resourceKeyClass}, resourceKey); - Class chatMessageTypeClass = ReflectionUtils.getClazz("net.minecraft.network.chat.ChatMessageType"); - Object chatMessageType = status ? ReflectionUtils.getField(chatMessageTypeClass, "d") : ReflectionUtils.getField(chatMessageTypeClass, "c"); - Object messageType = ReflectionUtils.callMethod(registry, "a", new Class[]{resourceKeyClass}, chatMessageType); - return (Integer)ReflectionUtils.callMethod(registry, "a", new Class[]{Object.class}, messageType); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_19_1.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_19_1.java deleted file mode 100644 index 042c0e9..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_19_1.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.compatibility.Compatibility1_8; -import de.maxhenkel.voicechat.compatibility.JsonMessageBaseCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import org.bukkit.entity.Player; - -public class Compatibility1_19_1 -extends JsonMessageBaseCompatibility { - public static final BukkitVersion VERSION_1_19_4 = BukkitVersion.parseBukkitVersion("1.19.4-R0.1"); - public static final BukkitVersion VERSION_1_19_3 = BukkitVersion.parseBukkitVersion("1.19.3-R0.1"); - public static final BukkitVersion VERSION_1_19_2 = BukkitVersion.parseBukkitVersion("1.19.2-R0.1"); - public static final BukkitVersion VERSION_1_19_1 = BukkitVersion.parseBukkitVersion("1.19.1-R0.1"); - public static final Compatibility1_19_1 INSTANCE = new Compatibility1_19_1(); - - @Override - public void sendJsonMessage(Player player, String json) { - this.send(player, json, false); - } - - @Override - public void sendJsonStatusMessage(Player player, String json) { - this.send(player, json, true); - } - - @Override - public String createTranslationMessage(String key, String ... args) { - return Compatibility1_8.constructTranslationMessage(key, args); - } - - @Override - public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); - } - - @Override - public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); - } - - @Override - public ArgumentType playerArgument() { - Class argumentEntity = ReflectionUtils.getClazz("net.minecraft.commands.arguments.ArgumentEntity"); - return (ArgumentType)ReflectionUtils.callMethod(argumentEntity, "c"); - } - - @Override - public ArgumentType uuidArgument() { - Class argumentEntity = ReflectionUtils.getClazz("net.minecraft.commands.arguments.ArgumentUUID"); - return (ArgumentType)ReflectionUtils.callMethod(argumentEntity, "a"); - } - - private void send(Player player, String json, boolean status) { - Object entityPlayer = ReflectionUtils.callMethod((Object)player, "getHandle"); - Object playerConnection = ReflectionUtils.getField(entityPlayer, "b"); - Class packet = ReflectionUtils.getClazz("net.minecraft.network.protocol.Packet"); - Class craftChatMessage = this.getBukkitClass("util.CraftChatMessage"); - Class iChatBaseComponentClass = ReflectionUtils.getClazz("net.minecraft.network.chat.IChatBaseComponent"); - Object iChatBaseComponent = ReflectionUtils.callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); - Class clientboundSystemChatPacketClass = ReflectionUtils.getClazz("net.minecraft.network.protocol.game.ClientboundSystemChatPacket"); - Object clientboundSystemChatPacket = ReflectionUtils.callConstructor(clientboundSystemChatPacketClass, new Class[]{iChatBaseComponentClass, Boolean.TYPE}, iChatBaseComponent, status); - ReflectionUtils.callMethod(playerConnection, "a", new Class[]{packet}, clientboundSystemChatPacket); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20.java deleted file mode 100644 index 984330c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.compatibility.Compatibility1_8; -import de.maxhenkel.voicechat.compatibility.JsonMessageBaseCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import org.bukkit.entity.Player; - -public class Compatibility1_20 -extends JsonMessageBaseCompatibility { - public static final BukkitVersion VERSION_1_20 = BukkitVersion.parseBukkitVersion("1.20-R0.1"); - public static final BukkitVersion VERSION_1_20_1 = BukkitVersion.parseBukkitVersion("1.20.1-R0.1"); - public static final Compatibility1_20 INSTANCE = new Compatibility1_20(); - - @Override - public void sendJsonMessage(Player player, String json) { - this.send(player, json, false); - } - - @Override - public void sendJsonStatusMessage(Player player, String json) { - this.send(player, json, true); - } - - @Override - public String createTranslationMessage(String key, String ... args) { - return Compatibility1_8.constructTranslationMessage(key, args); - } - - @Override - public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); - } - - @Override - public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); - } - - @Override - public ArgumentType playerArgument() { - Class argumentEntity = ReflectionUtils.getClazz("net.minecraft.commands.arguments.ArgumentEntity"); - return (ArgumentType)ReflectionUtils.callMethod(argumentEntity, "c"); - } - - @Override - public ArgumentType uuidArgument() { - Class argumentEntity = ReflectionUtils.getClazz("net.minecraft.commands.arguments.ArgumentUUID"); - return (ArgumentType)ReflectionUtils.callMethod(argumentEntity, "a"); - } - - private void send(Player player, String json, boolean status) { - Object entityPlayer = ReflectionUtils.callMethod((Object)player, "getHandle"); - Object playerConnection = ReflectionUtils.getField(entityPlayer, "c"); - Class packet = ReflectionUtils.getClazz("net.minecraft.network.protocol.Packet"); - Class craftChatMessage = this.getBukkitClass("util.CraftChatMessage"); - Class iChatBaseComponentClass = ReflectionUtils.getClazz("net.minecraft.network.chat.IChatBaseComponent"); - Object iChatBaseComponent = ReflectionUtils.callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); - Class clientboundSystemChatPacketClass = ReflectionUtils.getClazz("net.minecraft.network.protocol.game.ClientboundSystemChatPacket"); - Object clientboundSystemChatPacket = ReflectionUtils.callConstructor(clientboundSystemChatPacketClass, new Class[]{iChatBaseComponentClass, Boolean.TYPE}, iChatBaseComponent, status); - ReflectionUtils.callMethod(playerConnection, "a", new Class[]{packet}, clientboundSystemChatPacket); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20_2.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20_2.java deleted file mode 100644 index faa0598..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20_2.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.compatibility.Compatibility1_8; -import de.maxhenkel.voicechat.compatibility.JsonMessageBaseCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import org.bukkit.entity.Player; - -public class Compatibility1_20_2 -extends JsonMessageBaseCompatibility { - public static final BukkitVersion VERSION_1_20_2 = BukkitVersion.parseBukkitVersion("1.20.2-R0.1"); - public static final Compatibility1_20_2 INSTANCE = new Compatibility1_20_2(); - - @Override - public void sendJsonMessage(Player player, String json) { - this.send(player, json, false); - } - - @Override - public void sendJsonStatusMessage(Player player, String json) { - this.send(player, json, true); - } - - @Override - public String createTranslationMessage(String key, String ... args) { - return Compatibility1_8.constructTranslationMessage(key, args); - } - - @Override - public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); - } - - @Override - public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); - } - - @Override - public ArgumentType playerArgument() { - Class argumentEntity = ReflectionUtils.getClazz("net.minecraft.commands.arguments.ArgumentEntity"); - return (ArgumentType)ReflectionUtils.callMethod(argumentEntity, "c"); - } - - @Override - public ArgumentType uuidArgument() { - Class argumentEntity = ReflectionUtils.getClazz("net.minecraft.commands.arguments.ArgumentUUID"); - return (ArgumentType)ReflectionUtils.callMethod(argumentEntity, "a"); - } - - private void send(Player player, String json, boolean status) { - Object entityPlayer = ReflectionUtils.callMethod((Object)player, "getHandle"); - Class iChatBaseComponentClass = ReflectionUtils.getClazz("net.minecraft.network.chat.IChatBaseComponent"); - Class craftChatMessage = this.getBukkitClass("util.CraftChatMessage"); - Object iChatBaseComponent = ReflectionUtils.callMethod(craftChatMessage, "fromJSON", new Class[]{String.class}, json); - ReflectionUtils.callMethod(entityPlayer, "a", new Class[]{iChatBaseComponentClass, Boolean.TYPE}, iChatBaseComponent, status); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20_3.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20_3.java deleted file mode 100644 index e2a968a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/Compatibility1_20_3.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.BukkitVersion; -import de.maxhenkel.voicechat.compatibility.Compatibility1_8; -import de.maxhenkel.voicechat.compatibility.JsonMessageBaseCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import java.lang.reflect.Method; -import org.bukkit.entity.Player; - -public class Compatibility1_20_3 -extends JsonMessageBaseCompatibility { - public static final BukkitVersion VERSION_1_20_3 = BukkitVersion.parseBukkitVersion("1.20.3-R0.1"); - public static final BukkitVersion VERSION_1_20_4 = BukkitVersion.parseBukkitVersion("1.20.4-R0.1"); - public static final BukkitVersion VERSION_1_20_5 = BukkitVersion.parseBukkitVersion("1.20.5-R0.1"); - public static final BukkitVersion VERSION_1_20_6 = BukkitVersion.parseBukkitVersion("1.20.6-R0.1"); - public static final BukkitVersion VERSION_1_21 = BukkitVersion.parseBukkitVersion("1.21-R0.1"); - public static final BukkitVersion VERSION_1_21_1 = BukkitVersion.parseBukkitVersion("1.21.1-R0.1"); - public static final BukkitVersion VERSION_1_21_2 = BukkitVersion.parseBukkitVersion("1.21.2-R0.1"); - public static final BukkitVersion VERSION_1_21_3 = BukkitVersion.parseBukkitVersion("1.21.3-R0.1"); - public static final BukkitVersion VERSION_1_21_4 = BukkitVersion.parseBukkitVersion("1.21.4-R0.1"); - public static final Compatibility1_20_3 INSTANCE = new Compatibility1_20_3(); - private Method playerArgument; - private Method uuidArgument; - private Method fromJson; - private Method getHandle; - private Method sendSystemMessage; - - @Override - public void init() throws Exception { - super.init(); - Class argumentEntityClass = ReflectionUtils.getClazz("net.minecraft.commands.arguments.ArgumentEntity", "net.minecraft.commands.arguments.EntityArgument"); - this.playerArgument = ReflectionUtils.getMethod(argumentEntityClass, "c", "entity"); - Class argumentUuidClass = ReflectionUtils.getClazz("net.minecraft.commands.arguments.ArgumentUUID", "net.minecraft.commands.arguments.UuidArgument"); - this.uuidArgument = ReflectionUtils.getMethod(argumentUuidClass, "a", "uuid"); - Class craftPlayer = this.getBukkitClass("entity.CraftPlayer"); - this.getHandle = ReflectionUtils.getMethod(craftPlayer, "getHandle"); - Class componentClass = ReflectionUtils.getClazz("net.minecraft.network.chat.IChatBaseComponent", "net.minecraft.network.chat.Component"); - Class craftChatMessageClass = this.getBukkitClass("util.CraftChatMessage"); - this.fromJson = ReflectionUtils.getMethod(craftChatMessageClass, new String[]{"fromJSON"}, new Class[]{String.class}); - Class player = ReflectionUtils.getClazz("net.minecraft.server.level.EntityPlayer", "net.minecraft.server.level.ServerPlayer"); - this.sendSystemMessage = ReflectionUtils.getMethod(player, new String[]{"a", "sendSystemMessage"}, new Class[]{componentClass, Boolean.TYPE}); - } - - @Override - public void sendJsonMessage(Player player, String json) { - this.send(player, json, false); - } - - @Override - public void sendJsonStatusMessage(Player player, String json) { - this.send(player, json, true); - } - - @Override - public String createTranslationMessage(String key, String ... args) { - return Compatibility1_8.constructTranslationMessage(key, args); - } - - @Override - public void sendInviteMessage(Player player, Player commandSender, String groupName, String joinCommand) { - this.sendJsonMessage(player, Compatibility1_8.constructInviteMessage(commandSender, groupName, joinCommand)); - } - - @Override - public void sendIncompatibleMessage(Player player, String pluginVersion, String pluginName) { - this.sendJsonMessage(player, Compatibility1_8.constructIncompatibleMessage(pluginVersion, pluginName)); - } - - @Override - public ArgumentType playerArgument() { - return (ArgumentType)ReflectionUtils.call(this.playerArgument, null, new Object[0]); - } - - @Override - public ArgumentType uuidArgument() { - return (ArgumentType)ReflectionUtils.call(this.uuidArgument, null, new Object[0]); - } - - protected void send(Player player, String json, boolean status) { - ReflectionUtils.call(this.sendSystemMessage, ReflectionUtils.call(this.getHandle, player, new Object[0]), ReflectionUtils.call(this.fromJson, null, json), status); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/JsonMessageBaseCompatibility.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/JsonMessageBaseCompatibility.java deleted file mode 100644 index a893428..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/JsonMessageBaseCompatibility.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import de.maxhenkel.voicechat.compatibility.BaseCompatibility; -import org.bukkit.entity.Player; - -public abstract class JsonMessageBaseCompatibility -extends BaseCompatibility { - @Override - public void sendTranslationMessage(Player player, String key, String ... args) { - this.sendJsonMessage(player, this.createTranslationMessage(key, args)); - } - - @Override - public void sendStatusMessage(Player player, String key, String ... args) { - this.sendJsonStatusMessage(player, this.createTranslationMessage(key, args)); - } - - public abstract void sendJsonMessage(Player var1, String var2); - - public abstract void sendJsonStatusMessage(Player var1, String var2); - - public abstract String createTranslationMessage(String var1, String ... var2); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/compatibility/SpigotCompatibility.java b/source/decompiled/de/maxhenkel/voicechat/compatibility/SpigotCompatibility.java deleted file mode 100644 index 110b2fe..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/compatibility/SpigotCompatibility.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * javax.annotation.Nullable - * org.bukkit.Bukkit - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.compatibility; - -import com.mojang.brigadier.arguments.ArgumentType; -import de.maxhenkel.voicechat.compatibility.FallbackCompatibility; -import de.maxhenkel.voicechat.compatibility.ReflectionUtils; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import javax.annotation.Nullable; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -public class SpigotCompatibility -extends FallbackCompatibility { - public static final SpigotCompatibility INSTANCE = new SpigotCompatibility(); - private MessageSender messageSender; - - @Override - public void init() throws Exception { - super.init(); - Class playerSpigotClass = ReflectionUtils.getClazz("org.bukkit.entity.Player$Spigot"); - Class baseComponentClass = ReflectionUtils.getClazz("net.md_5.bungee.api.chat.BaseComponent"); - Class chatMessageTypeClass = ReflectionUtils.getClazz("net.md_5.bungee.api.ChatMessageType"); - Object systemType = ReflectionUtils.getField(chatMessageTypeClass, "SYSTEM"); - Object actionBarType = ReflectionUtils.getField(chatMessageTypeClass, "ACTION_BAR"); - Method playerSpigot = ReflectionUtils.getMethod(Player.class, "spigot"); - Method sendMessage = ReflectionUtils.getMethod(playerSpigotClass, new String[]{"sendMessage"}, new Class[]{chatMessageTypeClass, baseComponentClass}); - Class translatableComponentClass = ReflectionUtils.getClazz("net.md_5.bungee.api.chat.TranslatableComponent"); - Constructor translatableComponentConstructor = ReflectionUtils.getConstructor(translatableComponentClass, String.class, Object[].class); - this.messageSender = (player, actionBar, key, args) -> { - Object messageType = actionBar ? actionBarType : systemType; - ReflectionUtils.call(sendMessage, ReflectionUtils.call(playerSpigot, player, new Object[0]), messageType, ReflectionUtils.newInstance(translatableComponentConstructor, key, args)); - }; - } - - public static boolean isSpigotCompatible() { - return ReflectionUtils.doesMethodExist(Bukkit.class, "spigot", new Class[0]); - } - - @Override - public void sendTranslationMessage(Player player, String key, String ... args) { - this.messageSender.send(player, false, key, args); - } - - @Override - public void sendStatusMessage(Player player, String key, String ... args) { - this.messageSender.send(player, true, key, args); - } - - @Override - @Nullable - public ArgumentType playerArgument() { - return null; - } - - @Override - @Nullable - public ArgumentType uuidArgument() { - return null; - } - - private static interface MessageSender { - public void send(Player var1, boolean var2, String var3, String ... var4); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Analysis.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Analysis.java deleted file mode 100644 index 0c253a3..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Analysis.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.AnalysisInfo; -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.CeltMode; -import de.maxhenkel.voicechat.concentus.Downmix; -import de.maxhenkel.voicechat.concentus.FFTState; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.KissFFT; -import de.maxhenkel.voicechat.concentus.MultiLayerPerceptron; -import de.maxhenkel.voicechat.concentus.OpusTables; -import de.maxhenkel.voicechat.concentus.TonalityAnalysisState; - -class Analysis { - private static final double M_PI = 3.141592653; - private static final float cA = 0.43157974f; - private static final float cB = 0.678484f; - private static final float cC = 0.08595542f; - private static final float cE = 1.5707964f; - private static final int NB_TONAL_SKIP_BANDS = 9; - - Analysis() { - } - - static float fast_atan2f(float y, float x) { - float y2; - float x2; - if (Inlines.ABS16(x) + Inlines.ABS16(y) < 1.0E-9f) { - x *= 1.0E12f; - y *= 1.0E12f; - } - if ((x2 = x * x) < (y2 = y * y)) { - float den = (y2 + 0.678484f * x2) * (y2 + 0.08595542f * x2); - if (den != 0.0f) { - return -x * y * (y2 + 0.43157974f * x2) / den + (y < 0.0f ? -1.5707964f : 1.5707964f); - } - return y < 0.0f ? -1.5707964f : 1.5707964f; - } - float den = (x2 + 0.678484f * y2) * (x2 + 0.08595542f * y2); - if (den != 0.0f) { - return x * y * (x2 + 0.43157974f * y2) / den + (y < 0.0f ? -1.5707964f : 1.5707964f) - (x * y < 0.0f ? -1.5707964f : 1.5707964f); - } - return (y < 0.0f ? -1.5707964f : 1.5707964f) - (x * y < 0.0f ? -1.5707964f : 1.5707964f); - } - - static void tonality_analysis_init(TonalityAnalysisState tonal) { - tonal.Reset(); - } - - static void tonality_get_info(TonalityAnalysisState tonal, AnalysisInfo info_out, int len) { - int i; - int pos = tonal.read_pos; - int curr_lookahead = tonal.write_pos - tonal.read_pos; - if (curr_lookahead < 0) { - curr_lookahead += 200; - } - if (len > 480 && pos != tonal.write_pos && ++pos == 200) { - pos = 0; - } - if (pos == tonal.write_pos) { - --pos; - } - if (pos < 0) { - pos = 199; - } - info_out.Assign(tonal.info[pos]); - tonal.read_subframe += len / 120; - while (tonal.read_subframe >= 4) { - tonal.read_subframe -= 4; - ++tonal.read_pos; - } - if (tonal.read_pos >= 200) { - tonal.read_pos -= 200; - } - curr_lookahead = Inlines.IMAX(curr_lookahead - 10, 0); - float psum = 0.0f; - for (i = 0; i < 200 - curr_lookahead; ++i) { - psum += tonal.pmusic[i]; - } - while (i < 200) { - psum += tonal.pspeech[i]; - ++i; - } - info_out.music_prob = psum = psum * tonal.music_confidence + (1.0f - psum) * tonal.speech_confidence; - } - - static void tonality_analysis(TonalityAnalysisState tonal, CeltMode celt_mode, short[] x, int x_ptr, int len, int offset, int c1, int c2, int C, int lsb_depth) { - float E; - int b; - int i; - int N = 480; - int N2 = 240; - float[] A = tonal.angle; - float[] dA = tonal.d_angle; - float[] d2A = tonal.d2_angle; - float[] band_tonality = new float[18]; - float[] logE = new float[18]; - float[] BFCC = new float[8]; - float[] features = new float[25]; - float pi4 = 97.40909f; - float slope = 0.0f; - float[] frame_probs = new float[2]; - int bandwidth = 0; - float maxE = 0.0f; - ++tonal.last_transition; - float alpha = 1.0f / (float)Inlines.IMIN(20, 1 + tonal.count); - float alphaE = 1.0f / (float)Inlines.IMIN(50, 1 + tonal.count); - float alphaE2 = 1.0f / (float)Inlines.IMIN(1000, 1 + tonal.count); - if (tonal.count < 4) { - tonal.music_prob = 0.5f; - } - FFTState kfft = celt_mode.mdct.kfft[0]; - if (tonal.count == 0) { - tonal.mem_fill = 240; - } - Downmix.downmix_int(x, x_ptr, tonal.inmem, tonal.mem_fill, Inlines.IMIN(len, 720 - tonal.mem_fill), offset, c1, c2, C); - if (tonal.mem_fill + len < 720) { - tonal.mem_fill += len; - return; - } - AnalysisInfo info = tonal.info[tonal.write_pos++]; - if (tonal.write_pos >= 200) { - tonal.write_pos -= 200; - } - int[] input = new int[960]; - int[] output = new int[960]; - float[] tonality = new float[240]; - float[] noisiness = new float[240]; - for (i = 0; i < N2; ++i) { - float w = OpusTables.analysis_window[i]; - input[2 * i] = (int)(w * (float)tonal.inmem[i]); - input[2 * i + 1] = (int)(w * (float)tonal.inmem[N2 + i]); - input[2 * (N - i - 1)] = (int)(w * (float)tonal.inmem[N - i - 1]); - input[2 * (N - i - 1) + 1] = (int)(w * (float)tonal.inmem[N + N2 - i - 1]); - } - Arrays.MemMove(tonal.inmem, 480, 0, 240); - int remaining = len - (720 - tonal.mem_fill); - Downmix.downmix_int(x, x_ptr, tonal.inmem, 240, remaining, offset + 720 - tonal.mem_fill, c1, c2, C); - tonal.mem_fill = 240 + remaining; - KissFFT.opus_fft(kfft, input, output); - for (i = 1; i < N2; ++i) { - float X1r = (float)output[2 * i] + (float)output[2 * (N - i)]; - float X1i = (float)output[2 * i + 1] - (float)output[2 * (N - i) + 1]; - float X2r = (float)output[2 * i + 1] + (float)output[2 * (N - i) + 1]; - float X2i = (float)output[2 * (N - i)] - (float)output[2 * i]; - float angle = 0.15915494f * Analysis.fast_atan2f(X1i, X1r); - float d_angle = angle - A[i]; - float d2_angle = d_angle - dA[i]; - float angle2 = 0.15915494f * Analysis.fast_atan2f(X2i, X2r); - float d_angle2 = angle2 - angle; - float d2_angle2 = d_angle2 - d_angle; - float mod1 = d2_angle - (float)Math.floor(0.5f + d2_angle); - noisiness[i] = Inlines.ABS16(mod1); - mod1 *= mod1; - mod1 *= mod1; - float mod2 = d2_angle2 - (float)Math.floor(0.5f + d2_angle2); - int n = i; - noisiness[n] = noisiness[n] + Inlines.ABS16(mod2); - mod2 *= mod2; - mod2 *= mod2; - float avg_mod = 0.25f * (d2A[i] + 2.0f * mod1 + mod2); - tonality[i] = 1.0f / (1.0f + 640.0f * pi4 * avg_mod) - 0.015f; - A[i] = angle2; - dA[i] = d_angle2; - d2A[i] = mod2; - } - float frame_tonality = 0.0f; - float max_frame_tonality = 0.0f; - info.activity = 0.0f; - float frame_noisiness = 0.0f; - float frame_stationarity = 0.0f; - if (tonal.count == 0) { - for (b = 0; b < 18; ++b) { - tonal.lowE[b] = 1.0E10f; - tonal.highE[b] = -1.0E10f; - } - } - float relativeE = 0.0f; - float frame_loudness = 0.0f; - for (b = 0; b < 18; ++b) { - E = 0.0f; - float tE = 0.0f; - float nE = 0.0f; - for (i = OpusTables.tbands[b]; i < OpusTables.tbands[b + 1]; ++i) { - float binE = (float)output[2 * i] * (float)output[2 * i] + (float)output[2 * (N - i)] * (float)output[2 * (N - i)] + (float)output[2 * i + 1] * (float)output[2 * i + 1] + (float)output[2 * (N - i) + 1] * (float)output[2 * (N - i) + 1]; - E += (binE *= 5.55E-17f); - tE += binE * tonality[i]; - nE += binE * 2.0f * (0.5f - noisiness[i]); - } - tonal.E[tonal.E_count][b] = E; - frame_noisiness += nE / (1.0E-15f + E); - frame_loudness += (float)Math.sqrt(E + 1.0E-10f); - logE[b] = (float)Math.log(E + 1.0E-10f); - tonal.lowE[b] = Inlines.MIN32(logE[b], tonal.lowE[b] + 0.01f); - tonal.highE[b] = Inlines.MAX32(logE[b], tonal.highE[b] - 0.1f); - if (tonal.highE[b] < tonal.lowE[b] + 1.0f) { - int n = b; - tonal.highE[n] = tonal.highE[n] + 0.5f; - int n2 = b; - tonal.lowE[n2] = tonal.lowE[n2] - 0.5f; - } - relativeE += (logE[b] - tonal.lowE[b]) / (1.0E-15f + tonal.highE[b] - tonal.lowE[b]); - float L2 = 0.0f; - float L1 = 0.0f; - for (i = 0; i < 8; ++i) { - L1 += (float)Math.sqrt(tonal.E[i][b]); - L2 += tonal.E[i][b]; - } - float stationarity = Inlines.MIN16(0.99f, L1 / (float)Math.sqrt(1.0E-15 + (double)(8.0f * L2))); - stationarity *= stationarity; - stationarity *= stationarity; - frame_stationarity += stationarity; - band_tonality[b] = Inlines.MAX16(tE / (1.0E-15f + E), stationarity * tonal.prev_band_tonality[b]); - frame_tonality += band_tonality[b]; - if (b >= 9) { - frame_tonality -= band_tonality[b - 18 + 9]; - } - max_frame_tonality = Inlines.MAX16(max_frame_tonality, (1.0f + 0.03f * (float)(b - 18)) * frame_tonality); - slope += band_tonality[b] * (float)(b - 8); - tonal.prev_band_tonality[b] = band_tonality[b]; - } - float bandwidth_mask = 0.0f; - bandwidth = 0; - maxE = 0.0f; - float noise_floor = 5.7E-4f / (float)(1 << Inlines.IMAX(0, lsb_depth - 8)); - noise_floor *= 1.3421773E8f; - noise_floor *= noise_floor; - for (b = 0; b < 21; ++b) { - E = 0.0f; - int band_start = OpusTables.extra_bands[b]; - int band_end = OpusTables.extra_bands[b + 1]; - for (i = band_start; i < band_end; ++i) { - float binE = (float)output[2 * i] * (float)output[2 * i] + (float)output[2 * (N - i)] * (float)output[2 * (N - i)] + (float)output[2 * i + 1] * (float)output[2 * i + 1] + (float)output[2 * (N - i) + 1] * (float)output[2 * (N - i) + 1]; - E += binE; - } - maxE = Inlines.MAX32(maxE, E); - tonal.meanE[b] = Inlines.MAX32((1.0f - alphaE2) * tonal.meanE[b], E); - if (!((double)(E = Inlines.MAX32(E, tonal.meanE[b])) > 0.1 * (double)(bandwidth_mask = Inlines.MAX32(0.05f * bandwidth_mask, E))) || !(E * 1.0E9f > maxE) || !(E > noise_floor * (float)(band_end - band_start))) continue; - bandwidth = b; - } - if (tonal.count <= 2) { - bandwidth = 20; - } - frame_loudness = 20.0f * (float)Math.log10(frame_loudness); - tonal.Etracker = Inlines.MAX32(tonal.Etracker - 0.03f, frame_loudness); - tonal.lowECount *= 1.0f - alphaE; - if (frame_loudness < tonal.Etracker - 30.0f) { - tonal.lowECount += alphaE; - } - for (i = 0; i < 8; ++i) { - float sum = 0.0f; - for (b = 0; b < 16; ++b) { - sum += OpusTables.dct_table[i * 16 + b] * logE[b]; - } - BFCC[i] = sum; - } - frame_stationarity /= 18.0f; - relativeE /= 18.0f; - if (tonal.count < 10) { - relativeE = 0.5f; - } - info.activity = (frame_noisiness /= 18.0f) + (1.0f - frame_noisiness) * relativeE; - frame_tonality = max_frame_tonality / 9.0f; - tonal.prev_tonality = frame_tonality = Inlines.MAX16(frame_tonality, tonal.prev_tonality * 0.8f); - info.tonality_slope = slope /= 64.0f; - tonal.E_count = (tonal.E_count + 1) % 8; - ++tonal.count; - info.tonality = frame_tonality; - for (i = 0; i < 4; ++i) { - features[i] = -0.12299f * (BFCC[i] + tonal.mem[i + 24]) + 0.49195f * (tonal.mem[i] + tonal.mem[i + 16]) + 0.69693f * tonal.mem[i + 8] - 1.4349f * tonal.cmean[i]; - } - for (i = 0; i < 4; ++i) { - tonal.cmean[i] = (1.0f - alpha) * tonal.cmean[i] + alpha * BFCC[i]; - } - for (i = 0; i < 4; ++i) { - features[4 + i] = 0.63246f * (BFCC[i] - tonal.mem[i + 24]) + 0.31623f * (tonal.mem[i] - tonal.mem[i + 16]); - } - for (i = 0; i < 3; ++i) { - features[8 + i] = 0.53452f * (BFCC[i] + tonal.mem[i + 24]) - 0.26726f * (tonal.mem[i] + tonal.mem[i + 16]) - 0.53452f * tonal.mem[i + 8]; - } - if (tonal.count > 5) { - for (i = 0; i < 9; ++i) { - tonal.std[i] = (1.0f - alpha) * tonal.std[i] + alpha * features[i] * features[i]; - } - } - for (i = 0; i < 8; ++i) { - tonal.mem[i + 24] = tonal.mem[i + 16]; - tonal.mem[i + 16] = tonal.mem[i + 8]; - tonal.mem[i + 8] = tonal.mem[i]; - tonal.mem[i] = BFCC[i]; - } - for (i = 0; i < 9; ++i) { - features[11 + i] = (float)Math.sqrt(tonal.std[i]); - } - features[20] = info.tonality; - features[21] = info.activity; - features[22] = frame_stationarity; - features[23] = info.tonality_slope; - features[24] = tonal.lowECount; - if (info.enabled) { - MultiLayerPerceptron.mlp_process(OpusTables.net, features, frame_probs); - frame_probs[0] = 0.5f * (frame_probs[0] + 1.0f); - frame_probs[0] = 0.01f + 1.21f * frame_probs[0] * frame_probs[0] - 0.23f * (float)Math.pow(frame_probs[0], 10.0); - frame_probs[1] = 0.5f * frame_probs[1] + 0.5f; - frame_probs[0] = frame_probs[1] * frame_probs[0] + (1.0f - frame_probs[1]) * 0.5f; - float tau = 5.0E-5f * frame_probs[1]; - float beta = 0.05f; - float p = Inlines.MAX16(0.05f, Inlines.MIN16(0.95f, frame_probs[0])); - float q = Inlines.MAX16(0.05f, Inlines.MIN16(0.95f, tonal.music_prob)); - beta = 0.01f + 0.05f * Inlines.ABS16(p - q) / (p * (1.0f - q) + q * (1.0f - p)); - float p0 = (1.0f - tonal.music_prob) * (1.0f - tau) + tonal.music_prob * tau; - float p1 = tonal.music_prob * (1.0f - tau) + (1.0f - tonal.music_prob) * tau; - info.music_prob = tonal.music_prob = (p1 *= (float)Math.pow(frame_probs[0], beta)) / ((p0 *= (float)Math.pow(1.0f - frame_probs[0], beta)) + p1); - float psum = 1.0E-20f; - float speech0 = (float)Math.pow(1.0f - frame_probs[0], beta); - float music0 = (float)Math.pow(frame_probs[0], beta); - if (tonal.count == 1) { - tonal.pspeech[0] = 0.5f; - tonal.pmusic[0] = 0.5f; - } - float s0 = tonal.pspeech[0] + tonal.pspeech[1]; - float m0 = tonal.pmusic[0] + tonal.pmusic[1]; - tonal.pspeech[0] = s0 * (1.0f - tau) * speech0; - tonal.pmusic[0] = m0 * (1.0f - tau) * music0; - for (i = 1; i < 199; ++i) { - tonal.pspeech[i] = tonal.pspeech[i + 1] * speech0; - tonal.pmusic[i] = tonal.pmusic[i + 1] * music0; - } - tonal.pspeech[199] = m0 * tau * speech0; - tonal.pmusic[199] = s0 * tau * music0; - for (i = 0; i < 200; ++i) { - psum += tonal.pspeech[i] + tonal.pmusic[i]; - } - psum = 1.0f / psum; - i = 0; - while (i < 200) { - int n = i; - tonal.pspeech[n] = tonal.pspeech[n] * psum; - int n3 = i++; - tonal.pmusic[n3] = tonal.pmusic[n3] * psum; - } - psum = tonal.pmusic[0]; - for (i = 1; i < 200; ++i) { - psum += tonal.pspeech[i]; - } - if ((double)frame_probs[1] > 0.75) { - float adapt; - if ((double)tonal.music_prob > 0.9) { - adapt = 1.0f / (float)(++tonal.music_confidence_count); - tonal.music_confidence_count = Inlines.IMIN(tonal.music_confidence_count, 500); - tonal.music_confidence += adapt * Inlines.MAX16(-0.2f, frame_probs[0] - tonal.music_confidence); - } - if ((double)tonal.music_prob < 0.1) { - adapt = 1.0f / (float)(++tonal.speech_confidence_count); - tonal.speech_confidence_count = Inlines.IMIN(tonal.speech_confidence_count, 500); - tonal.speech_confidence += adapt * Inlines.MIN16(0.2f, frame_probs[0] - tonal.speech_confidence); - } - } else { - if (tonal.music_confidence_count == 0) { - tonal.music_confidence = 0.9f; - } - if (tonal.speech_confidence_count == 0) { - tonal.speech_confidence = 0.1f; - } - } - if (tonal.last_music != (tonal.music_prob > 0.5f ? 1 : 0)) { - tonal.last_transition = 0; - } - tonal.last_music = tonal.music_prob > 0.5f ? 1 : 0; - } else { - info.music_prob = 0.0f; - } - info.bandwidth = bandwidth; - info.noisiness = frame_noisiness; - info.valid = 1; - } - - static void run_analysis(TonalityAnalysisState analysis, CeltMode celt_mode, short[] analysis_pcm, int analysis_pcm_ptr, int analysis_frame_size, int frame_size, int c1, int c2, int C, int Fs, int lsb_depth, AnalysisInfo analysis_info) { - if (analysis_pcm != null) { - analysis_frame_size = Inlines.IMIN(195 * Fs / 100, analysis_frame_size); - int pcm_len = analysis_frame_size - analysis.analysis_offset; - int offset = analysis.analysis_offset; - do { - Analysis.tonality_analysis(analysis, celt_mode, analysis_pcm, analysis_pcm_ptr, Inlines.IMIN(480, pcm_len), offset, c1, c2, C, lsb_depth); - offset += 480; - } while ((pcm_len -= 480) > 0); - analysis.analysis_offset = analysis_frame_size; - analysis.analysis_offset -= frame_size; - } - analysis_info.valid = 0; - Analysis.tonality_get_info(analysis, analysis_info, frame_size); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/AnalysisInfo.java b/source/decompiled/de/maxhenkel/voicechat/concentus/AnalysisInfo.java deleted file mode 100644 index 68fb9be..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/AnalysisInfo.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class AnalysisInfo { - boolean enabled = false; - int valid = 0; - float tonality = 0.0f; - float tonality_slope = 0.0f; - float noisiness = 0.0f; - float activity = 0.0f; - float music_prob = 0.0f; - int bandwidth = 0; - - AnalysisInfo() { - } - - void Assign(AnalysisInfo other) { - this.valid = other.valid; - this.tonality = other.tonality; - this.tonality_slope = other.tonality_slope; - this.noisiness = other.noisiness; - this.activity = other.activity; - this.music_prob = other.music_prob; - this.bandwidth = other.bandwidth; - } - - void Reset() { - this.valid = 0; - this.tonality = 0.0f; - this.tonality_slope = 0.0f; - this.noisiness = 0.0f; - this.activity = 0.0f; - this.music_prob = 0.0f; - this.bandwidth = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/ApplySineWindow.java b/source/decompiled/de/maxhenkel/voicechat/concentus/ApplySineWindow.java deleted file mode 100644 index 3768608..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/ApplySineWindow.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; - -class ApplySineWindow { - private static final short[] freq_table_Q16 = new short[]{12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202, 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422, 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702}; - - ApplySineWindow() { - } - - static void silk_apply_sine_window(short[] px_win, int px_win_ptr, short[] px, int px_ptr, int win_type, int length) { - int S1_Q16; - int S0_Q16; - Inlines.OpusAssert(win_type == 1 || win_type == 2); - Inlines.OpusAssert(length >= 16 && length <= 120); - Inlines.OpusAssert((length & 3) == 0); - int k = (length >> 2) - 4; - Inlines.OpusAssert(k >= 0 && k <= 26); - short f_Q16 = freq_table_Q16[k]; - int c_Q16 = Inlines.silk_SMULWB(f_Q16, -f_Q16); - Inlines.OpusAssert(c_Q16 >= Short.MIN_VALUE); - if (win_type == 1) { - S0_Q16 = 0; - S1_Q16 = f_Q16 + Inlines.silk_RSHIFT(length, 3); - } else { - S0_Q16 = 65536; - S1_Q16 = 65536 + Inlines.silk_RSHIFT(c_Q16, 1) + Inlines.silk_RSHIFT(length, 4); - } - for (k = 0; k < length; k += 4) { - int pxwk = px_win_ptr + k; - int pxk = px_ptr + k; - px_win[pxwk] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(S0_Q16 + S1_Q16, 1), px[pxk]); - px_win[pxwk + 1] = (short)Inlines.silk_SMULWB(S1_Q16, px[pxk + 1]); - S0_Q16 = Inlines.silk_SMULWB(S1_Q16, c_Q16) + Inlines.silk_LSHIFT(S1_Q16, 1) - S0_Q16 + 1; - S0_Q16 = Inlines.silk_min(S0_Q16, 65536); - px_win[pxwk + 2] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(S0_Q16 + S1_Q16, 1), px[pxk + 2]); - px_win[pxwk + 3] = (short)Inlines.silk_SMULWB(S0_Q16, px[pxk + 3]); - S1_Q16 = Inlines.silk_SMULWB(S0_Q16, c_Q16) + Inlines.silk_LSHIFT(S0_Q16, 1) - S1_Q16; - S1_Q16 = Inlines.silk_min(S1_Q16, 65536); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Arrays.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Arrays.java deleted file mode 100644 index 5310f34..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Arrays.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class Arrays { - Arrays() { - } - - static int[][] InitTwoDimensionalArrayInt(int x, int y) { - return new int[x][y]; - } - - static float[][] InitTwoDimensionalArrayFloat(int x, int y) { - return new float[x][y]; - } - - static short[][] InitTwoDimensionalArrayShort(int x, int y) { - return new short[x][y]; - } - - static byte[][] InitTwoDimensionalArrayByte(int x, int y) { - return new byte[x][y]; - } - - static byte[][][] InitThreeDimensionalArrayByte(int x, int y, int z) { - return new byte[x][y][z]; - } - - static void MemSet(byte[] array, byte value) { - java.util.Arrays.fill(array, value); - } - - static void MemSet(short[] array, short value) { - java.util.Arrays.fill(array, value); - } - - static void MemSet(int[] array, int value) { - java.util.Arrays.fill(array, value); - } - - static void MemSet(float[] array, float value) { - java.util.Arrays.fill(array, value); - } - - static void MemSet(byte[] array, byte value, int length) { - java.util.Arrays.fill(array, 0, length, value); - } - - static void MemSet(short[] array, short value, int length) { - java.util.Arrays.fill(array, 0, length, value); - } - - static void MemSet(int[] array, int value, int length) { - java.util.Arrays.fill(array, 0, length, value); - } - - static void MemSet(float[] array, float value, int length) { - java.util.Arrays.fill(array, 0, length, value); - } - - static void MemSetWithOffset(byte[] array, byte value, int offset, int length) { - java.util.Arrays.fill(array, offset, offset + length, value); - } - - static void MemSetWithOffset(short[] array, short value, int offset, int length) { - java.util.Arrays.fill(array, offset, offset + length, value); - } - - static void MemSetWithOffset(int[] array, int value, int offset, int length) { - java.util.Arrays.fill(array, offset, offset + length, value); - } - - static void MemMove(byte[] array, int src_idx, int dst_idx, int length) { - System.arraycopy(array, src_idx, array, dst_idx, length); - } - - static void MemMove(short[] array, int src_idx, int dst_idx, int length) { - System.arraycopy(array, src_idx, array, dst_idx, length); - } - - static void MemMove(int[] array, int src_idx, int dst_idx, int length) { - System.arraycopy(array, src_idx, array, dst_idx, length); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Autocorrelation.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Autocorrelation.java deleted file mode 100644 index 42ba397..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Autocorrelation.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltPitchXCorr; -import de.maxhenkel.voicechat.concentus.Inlines; - -class Autocorrelation { - private static final int QC = 10; - private static final int QS = 14; - - Autocorrelation() { - } - - static void silk_autocorr(int[] results, BoxedValueInt scale, short[] inputData, int inputDataSize, int correlationCount) { - int corrCount = Inlines.silk_min_int(inputDataSize, correlationCount); - scale.Val = Autocorrelation._celt_autocorr(inputData, results, corrCount - 1, inputDataSize); - } - - static int _celt_autocorr(short[] x, int[] ac, int lag, int n) { - int shift2; - int i; - int fastN = n - lag; - short[] xx = new short[n]; - Inlines.OpusAssert(n > 0); - short[] xptr = x; - int shift = 0; - int ac0 = 1 + (n << 7); - if ((n & 1) != 0) { - ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[0], xptr[0]), 9); - } - for (i = n & 1; i < n; i += 2) { - ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i], xptr[i]), 9); - ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i + 1], xptr[i + 1]), 9); - } - shift = Inlines.celt_ilog2(ac0) - 30 + 10; - if ((shift /= 2) > 0) { - for (i = 0; i < n; ++i) { - xx[i] = (short)Inlines.PSHR32(xptr[i], shift); - } - xptr = xx; - } else { - shift = 0; - } - CeltPitchXCorr.pitch_xcorr(xptr, xptr, ac, fastN, lag + 1); - int k = 0; - while (k <= lag) { - int d = 0; - for (i = k + fastN; i < n; ++i) { - d = Inlines.MAC16_16(d, xptr[i], xptr[i - k]); - } - int n2 = k++; - ac[n2] = ac[n2] + d; - } - if ((shift = 2 * shift) <= 0) { - ac[0] = ac[0] + Inlines.SHL32(1, -shift); - } - if (ac[0] < 0x10000000) { - shift2 = 29 - Inlines.EC_ILOG(ac[0]); - for (i = 0; i <= lag; ++i) { - ac[i] = Inlines.SHL32(ac[i], shift2); - } - shift -= shift2; - } else if (ac[0] >= 0x20000000) { - shift2 = 1; - if (ac[0] >= 0x40000000) { - ++shift2; - } - for (i = 0; i <= lag; ++i) { - ac[i] = Inlines.SHR32(ac[i], shift2); - } - shift += shift2; - } - return shift; - } - - static int _celt_autocorr(int[] x, int[] ac, int[] window, int overlap, int lag, int n) { - int i; - int[] xptr; - int fastN = n - lag; - int[] xx = new int[n]; - Inlines.OpusAssert(n > 0); - Inlines.OpusAssert(overlap >= 0); - if (overlap == 0) { - xptr = x; - } else { - for (i = 0; i < n; ++i) { - xx[i] = x[i]; - } - for (i = 0; i < overlap; ++i) { - xx[i] = Inlines.MULT16_16_Q15(x[i], window[i]); - xx[n - i - 1] = Inlines.MULT16_16_Q15(x[n - i - 1], window[i]); - } - xptr = xx; - } - int shift = 0; - int ac0 = 1 + (n << 7); - if ((n & 1) != 0) { - ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[0], xptr[0]), 9); - } - for (i = n & 1; i < n; i += 2) { - ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i], xptr[i]), 9); - ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i + 1], xptr[i + 1]), 9); - } - shift = Inlines.celt_ilog2(ac0) - 30 + 10; - if ((shift /= 2) > 0) { - for (i = 0; i < n; ++i) { - xx[i] = Inlines.PSHR32(xptr[i], shift); - } - xptr = xx; - } else { - shift = 0; - } - CeltPitchXCorr.pitch_xcorr(xptr, xptr, ac, fastN, lag + 1); - int k = 0; - while (k <= lag) { - int d = 0; - for (i = k + fastN; i < n; ++i) { - d = Inlines.MAC16_16(d, xptr[i], xptr[i - k]); - } - int n2 = k++; - ac[n2] = ac[n2] + d; - } - if ((shift = 2 * shift) <= 0) { - ac[0] = ac[0] + Inlines.SHL32(1, -shift); - } - if (ac[0] < 0x10000000) { - int shift2 = 29 - Inlines.EC_ILOG(ac[0]); - for (i = 0; i <= lag; ++i) { - ac[i] = Inlines.SHL32(ac[i], shift2); - } - shift -= shift2; - } else if (ac[0] >= 0x20000000) { - int shift2 = 1; - if (ac[0] >= 0x40000000) { - ++shift2; - } - for (i = 0; i <= lag; ++i) { - ac[i] = Inlines.SHR32(ac[i], shift2); - } - shift += shift2; - } - return shift; - } - - static void silk_warped_autocorrelation(int[] corr, BoxedValueInt scale, short[] input, int warping_Q16, int length, int order) { - int i; - int[] state_QS = new int[17]; - long[] corr_QC = new long[17]; - Inlines.OpusAssert((order & 1) == 0); - Inlines.OpusAssert(true); - for (int n = 0; n < length; ++n) { - int tmp1_QS = Inlines.silk_LSHIFT32(input[n], 14); - for (i = 0; i < order; i += 2) { - int tmp2_QS = Inlines.silk_SMLAWB(state_QS[i], state_QS[i + 1] - tmp1_QS, warping_Q16); - state_QS[i] = tmp1_QS; - int n2 = i; - corr_QC[n2] = corr_QC[n2] + Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp1_QS, state_QS[0]), 18); - tmp1_QS = Inlines.silk_SMLAWB(state_QS[i + 1], state_QS[i + 2] - tmp2_QS, warping_Q16); - state_QS[i + 1] = tmp2_QS; - int n3 = i + 1; - corr_QC[n3] = corr_QC[n3] + Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp2_QS, state_QS[0]), 18); - } - state_QS[order] = tmp1_QS; - int n4 = order; - corr_QC[n4] = corr_QC[n4] + Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp1_QS, state_QS[0]), 18); - } - int lsh = Inlines.silk_CLZ64(corr_QC[0]) - 35; - lsh = Inlines.silk_LIMIT(lsh, -22, 20); - scale.Val = -(10 + lsh); - Inlines.OpusAssert(scale.Val >= -30 && scale.Val <= 12); - if (lsh >= 0) { - for (i = 0; i < order + 1; ++i) { - corr[i] = (int)Inlines.silk_LSHIFT64(corr_QC[i], lsh); - } - } else { - for (i = 0; i < order + 1; ++i) { - corr[i] = (int)Inlines.silk_RSHIFT64(corr_QC[i], -lsh); - } - } - Inlines.OpusAssert(corr_QC[0] >= 0L); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/BWExpander.java b/source/decompiled/de/maxhenkel/voicechat/concentus/BWExpander.java deleted file mode 100644 index a0a4036..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/BWExpander.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; - -class BWExpander { - BWExpander() { - } - - static void silk_bwexpander_32(int[] ar, int d, int chirp_Q16) { - int chirp_minus_one_Q16 = chirp_Q16 - 65536; - for (int i = 0; i < d - 1; ++i) { - ar[i] = Inlines.silk_SMULWW(chirp_Q16, ar[i]); - chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, chirp_minus_one_Q16), 16); - } - ar[d - 1] = Inlines.silk_SMULWW(chirp_Q16, ar[d - 1]); - } - - static void silk_bwexpander(short[] ar, int d, int chirp_Q16) { - int chirp_minus_one_Q16 = chirp_Q16 - 65536; - for (int i = 0; i < d - 1; ++i) { - ar[i] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[i]), 16); - chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, chirp_minus_one_Q16), 16); - } - ar[d - 1] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[d - 1]), 16); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Bands.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Bands.java deleted file mode 100644 index 7b7c49d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Bands.java +++ /dev/null @@ -1,986 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltMode; -import de.maxhenkel.voicechat.concentus.CeltTables; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Kernels; -import de.maxhenkel.voicechat.concentus.Rate; -import de.maxhenkel.voicechat.concentus.VQ; - -class Bands { - private static final byte[] bit_interleave_table = new byte[]{0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3}; - private static final short[] bit_deinterleave_table = new short[]{0, 3, 12, 15, 48, 51, 60, 63, 192, 195, 204, 207, 240, 243, 252, 255}; - - Bands() { - } - - static int hysteresis_decision(int val, int[] thresholds, int[] hysteresis, int N, int prev) { - int i; - for (i = 0; i < N && val >= thresholds[i]; ++i) { - } - if (i > prev && val < thresholds[prev] + hysteresis[prev]) { - i = prev; - } - if (i < prev && val > thresholds[prev - 1] - hysteresis[prev - 1]) { - i = prev; - } - return i; - } - - static int celt_lcg_rand(int seed) { - return 1664525 * seed + 1013904223; - } - - static int bitexact_cos(int x) { - int tmp = 4096 + x * x >> 13; - Inlines.OpusAssert(tmp <= Short.MAX_VALUE); - int x2 = tmp; - x2 = Short.MAX_VALUE - x2 + Inlines.FRAC_MUL16(x2, -7651 + Inlines.FRAC_MUL16(x2, 8277 + Inlines.FRAC_MUL16(-626, x2))); - Inlines.OpusAssert(x2 <= 32766); - return 1 + x2; - } - - static int bitexact_log2tan(int isin, int icos) { - int lc = Inlines.EC_ILOG(icos); - int ls = Inlines.EC_ILOG(isin); - return (ls - lc) * 2048 + Inlines.FRAC_MUL16(isin <<= 15 - ls, Inlines.FRAC_MUL16(isin, -2597) + 7932) - Inlines.FRAC_MUL16(icos <<= 15 - lc, Inlines.FRAC_MUL16(icos, -2597) + 7932); - } - - static void compute_band_energies(CeltMode m, int[][] X, int[][] bandE, int end, int C, int LM) { - short[] eBands = m.eBands; - int N = m.shortMdctSize << LM; - int c = 0; - do { - for (int i = 0; i < end; ++i) { - int maxval = 0; - int sum = 0; - maxval = Inlines.celt_maxabs32(X[c], eBands[i] << LM, eBands[i + 1] - eBands[i] << LM); - if (maxval > 0) { - int shift = Inlines.celt_ilog2(maxval) - 14 + ((m.logN[i] >> 3) + LM + 1 >> 1); - int j = eBands[i] << LM; - if (shift > 0) { - do { - sum = Inlines.MAC16_16(sum, Inlines.EXTRACT16(Inlines.SHR32(X[c][j], shift)), Inlines.EXTRACT16(Inlines.SHR32(X[c][j], shift))); - } while (++j < eBands[i + 1] << LM); - } else { - do { - sum = Inlines.MAC16_16(sum, Inlines.EXTRACT16(Inlines.SHL32(X[c][j], -shift)), Inlines.EXTRACT16(Inlines.SHL32(X[c][j], -shift))); - } while (++j < eBands[i + 1] << LM); - } - bandE[c][i] = 1 + Inlines.VSHR32(Inlines.celt_sqrt(sum), -shift); - continue; - } - bandE[c][i] = 1; - } - } while (++c < C); - } - - static void normalise_bands(CeltMode m, int[][] freq, int[][] X, int[][] bandE, int end, int C, int M) { - short[] eBands = m.eBands; - int c = 0; - do { - int i = 0; - do { - int shift = Inlines.celt_zlog2(bandE[c][i]) - 13; - int E = Inlines.VSHR32(bandE[c][i], shift); - short g = Inlines.EXTRACT16(Inlines.celt_rcp(Inlines.SHL32(E, 3))); - int j = M * eBands[i]; - do { - X[c][j] = Inlines.MULT16_16_Q15(Inlines.VSHR32(freq[c][j], shift - 1), (int)g); - } while (++j < M * eBands[i + 1]); - } while (++i < end); - } while (++c < C); - } - - static void denormalise_bands(CeltMode m, int[] X, int[] freq, int freq_ptr, int[] bandLogE, int bandLogE_ptr, int start, int end, int M, int downsample, int silence) { - int i; - short[] eBands = m.eBands; - int N = M * m.shortMdctSize; - int bound = M * eBands[end]; - if (downsample != 1) { - bound = Inlines.IMIN(bound, N / downsample); - } - if (silence != 0) { - bound = 0; - end = 0; - start = 0; - } - int f = freq_ptr; - int x = M * eBands[start]; - for (i = 0; i < M * eBands[start]; ++i) { - freq[f++] = 0; - } - for (i = start; i < end; ++i) { - int g; - int j = M * eBands[i]; - int band_end = M * eBands[i + 1]; - int lg = Inlines.ADD16(bandLogE[bandLogE_ptr + i], (int)Inlines.SHL16(CeltTables.eMeans[i], 6)); - int shift = 16 - (lg >> 10); - if (shift > 31) { - shift = 0; - g = 0; - } else { - g = Inlines.celt_exp2_frac(lg & 0x3FF); - } - if (shift < 0) { - if (shift < -2) { - g = Short.MAX_VALUE; - shift = -2; - } - do { - freq[f] = Inlines.SHR32(Inlines.MULT16_16(X[x], g), -shift); - } while (++j < band_end); - continue; - } - do { - freq[f++] = Inlines.SHR32(Inlines.MULT16_16(X[x++], g), shift); - } while (++j < band_end); - } - Inlines.OpusAssert(start <= end); - Arrays.MemSetWithOffset(freq, 0, freq_ptr + bound, N - bound); - } - - static void anti_collapse(CeltMode m, int[][] X_, short[] collapse_masks, int LM, int C, int size, int start, int end, int[] logE, int[] prev1logE, int[] prev2logE, int[] pulses, int seed) { - for (int i = start; i < end; ++i) { - int N0 = m.eBands[i + 1] - m.eBands[i]; - Inlines.OpusAssert(pulses[i] >= 0); - int depth = Inlines.celt_udiv(1 + pulses[i], m.eBands[i + 1] - m.eBands[i]) >> LM; - int thresh32 = Inlines.SHR32(Inlines.celt_exp2(0 - Inlines.SHL16(depth, 7)), 1); - int thresh = Inlines.MULT16_32_Q15((short)16384, Inlines.MIN32(Short.MAX_VALUE, thresh32)); - int t = N0 << LM; - int shift = Inlines.celt_ilog2(t) >> 1; - t = Inlines.SHL32(t, 7 - shift << 1); - int sqrt_1 = Inlines.celt_rsqrt_norm(t); - int c = 0; - do { - int r; - boolean renormalize = false; - int prev1 = prev1logE[c * m.nbEBands + i]; - int prev2 = prev2logE[c * m.nbEBands + i]; - if (C == 1) { - prev1 = Inlines.MAX16(prev1, prev1logE[m.nbEBands + i]); - prev2 = Inlines.MAX16(prev2, prev2logE[m.nbEBands + i]); - } - int Ediff = Inlines.EXTEND32(logE[c * m.nbEBands + i]) - Inlines.EXTEND32(Inlines.MIN16(prev1, prev2)); - if ((Ediff = Inlines.MAX32(0, Ediff)) < 16384) { - int r32 = Inlines.SHR32(Inlines.celt_exp2((short)(0 - Inlines.EXTRACT16(Ediff))), 1); - r = 2 * Inlines.MIN16(16383, r32); - } else { - r = 0; - } - if (LM == 3) { - r = Inlines.MULT16_16_Q14(23170, Inlines.MIN32(23169, r)); - } - r = Inlines.SHR16(Inlines.MIN16(thresh, r), 1); - r = Inlines.SHR32(Inlines.MULT16_16_Q15(sqrt_1, r), shift); - int X = m.eBands[i] << LM; - for (int k = 0; k < 1 << LM; ++k) { - if ((collapse_masks[i * C + c] & 1 << k) != 0) continue; - int Xk = X + k; - for (int j = 0; j < N0; ++j) { - seed = Bands.celt_lcg_rand(seed); - X_[c][Xk + (j << LM)] = (seed & 0x8000) != 0 ? r : 0 - r; - } - renormalize = true; - } - if (!renormalize) continue; - VQ.renormalise_vector(X_[c], X, N0 << LM, Short.MAX_VALUE); - } while (++c < C); - } - } - - static void intensity_stereo(CeltMode m, int[] X, int X_ptr, int[] Y, int Y_ptr, int[][] bandE, int bandID, int N) { - int i = bandID; - int shift = Inlines.celt_zlog2(Inlines.MAX32(bandE[0][i], bandE[1][i])) - 13; - int left = Inlines.VSHR32(bandE[0][i], shift); - int right = Inlines.VSHR32(bandE[1][i], shift); - int norm = 1 + Inlines.celt_sqrt(1 + Inlines.MULT16_16(left, left) + Inlines.MULT16_16(right, right)); - int a1 = Inlines.DIV32_16(Inlines.SHL32(left, 14), norm); - int a2 = Inlines.DIV32_16(Inlines.SHL32(right, 14), norm); - for (int j = 0; j < N; ++j) { - int l = X[X_ptr + j]; - int r = Y[Y_ptr + j]; - X[X_ptr + j] = Inlines.EXTRACT16(Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(a1, l), a2, r), 14)); - } - } - - static void stereo_split(int[] X, int X_ptr, int[] Y, int Y_ptr, int N) { - for (int j = 0; j < N; ++j) { - int l = Inlines.MULT16_16(23170, X[X_ptr + j]); - int r = Inlines.MULT16_16(23170, Y[Y_ptr + j]); - X[X_ptr + j] = Inlines.EXTRACT16(Inlines.SHR32(Inlines.ADD32(l, r), 15)); - Y[Y_ptr + j] = Inlines.EXTRACT16(Inlines.SHR32(Inlines.SUB32(r, l), 15)); - } - } - - static void stereo_merge(int[] X, int X_ptr, int[] Y, int Y_ptr, int mid, int N) { - BoxedValueInt xp = new BoxedValueInt(0); - BoxedValueInt side = new BoxedValueInt(0); - Kernels.dual_inner_prod(Y, Y_ptr, X, X_ptr, Y, Y_ptr, N, xp, side); - xp.Val = Inlines.MULT16_32_Q15(mid, xp.Val); - int mid2 = Inlines.SHR16(mid, 1); - int El = Inlines.MULT16_16(mid2, mid2) + side.Val - 2 * xp.Val; - int Er = Inlines.MULT16_16(mid2, mid2) + side.Val + 2 * xp.Val; - if (Er < 161061 || El < 161061) { - System.arraycopy(X, X_ptr, Y, Y_ptr, N); - return; - } - int kl = Inlines.celt_ilog2(El) >> 1; - int kr = Inlines.celt_ilog2(Er) >> 1; - int t = Inlines.VSHR32(El, kl - 7 << 1); - int lgain = Inlines.celt_rsqrt_norm(t); - t = Inlines.VSHR32(Er, kr - 7 << 1); - int rgain = Inlines.celt_rsqrt_norm(t); - if (kl < 7) { - kl = 7; - } - if (kr < 7) { - kr = 7; - } - for (int j = 0; j < N; ++j) { - int l = Inlines.MULT16_16_P15(mid, X[X_ptr + j]); - int r = Y[Y_ptr + j]; - X[X_ptr + j] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(lgain, Inlines.SUB16(l, r)), kl + 1)); - Y[Y_ptr + j] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(rgain, Inlines.ADD16(l, r)), kr + 1)); - } - } - - static int spreading_decision(CeltMode m, int[][] X, BoxedValueInt average, int last_decision, BoxedValueInt hf_average, BoxedValueInt tapset_decision, int update_hf, int end, int C, int M) { - int sum = 0; - int nbBands = 0; - short[] eBands = m.eBands; - int hf_sum = 0; - Inlines.OpusAssert(end > 0); - if (M * (eBands[end] - eBands[end - 1]) <= 8) { - return 0; - } - int c = 0; - do { - for (int i = 0; i < end; ++i) { - int tmp = 0; - int[] tcount = new int[]{0, 0, 0}; - int[] x = X[c]; - int x_ptr = M * eBands[i]; - int N = M * (eBands[i + 1] - eBands[i]); - if (N <= 8) continue; - for (int j = x_ptr; j < N + x_ptr; ++j) { - int x2N = Inlines.MULT16_16(Inlines.MULT16_16_Q15(x[j], x[j]), N); - if (x2N < 2048) { - tcount[0] = tcount[0] + 1; - } - if (x2N < 512) { - tcount[1] = tcount[1] + 1; - } - if (x2N >= 128) continue; - tcount[2] = tcount[2] + 1; - } - if (i > m.nbEBands - 4) { - hf_sum += Inlines.celt_udiv(32 * (tcount[1] + tcount[0]), N); - } - tmp = (2 * tcount[2] >= N ? 1 : 0) + (2 * tcount[1] >= N ? 1 : 0) + (2 * tcount[0] >= N ? 1 : 0); - sum += tmp * 256; - ++nbBands; - } - } while (++c < C); - if (update_hf != 0) { - if (hf_sum != 0) { - hf_sum = Inlines.celt_udiv(hf_sum, C * (4 - m.nbEBands + end)); - } - hf_sum = hf_average.Val = hf_average.Val + hf_sum >> 1; - if (tapset_decision.Val == 2) { - hf_sum += 4; - } else if (tapset_decision.Val == 0) { - hf_sum -= 4; - } - tapset_decision.Val = hf_sum > 22 ? 2 : (hf_sum > 18 ? 1 : 0); - } - Inlines.OpusAssert(nbBands > 0); - Inlines.OpusAssert(sum >= 0); - sum = Inlines.celt_udiv(sum, nbBands); - average.Val = sum = sum + average.Val >> 1; - sum = 3 * sum + ((3 - last_decision << 7) + 64) + 2 >> 2; - int decision = sum < 80 ? 3 : (sum < 256 ? 2 : (sum < 384 ? 1 : 0)); - return decision; - } - - static void deinterleave_hadamard(int[] X, int X_ptr, int N0, int stride, int hadamard) { - int N = N0 * stride; - int[] tmp = new int[N]; - Inlines.OpusAssert(stride > 0); - if (hadamard != 0) { - int ordery = stride - 2; - for (int i = 0; i < stride; ++i) { - for (int j = 0; j < N0; ++j) { - tmp[CeltTables.ordery_table[ordery + i] * N0 + j] = X[j * stride + i + X_ptr]; - } - } - } else { - for (int i = 0; i < stride; ++i) { - for (int j = 0; j < N0; ++j) { - tmp[i * N0 + j] = X[j * stride + i + X_ptr]; - } - } - } - System.arraycopy(tmp, 0, X, X_ptr, N); - } - - static void interleave_hadamard(int[] X, int X_ptr, int N0, int stride, int hadamard) { - int N = N0 * stride; - int[] tmp = new int[N]; - if (hadamard != 0) { - int ordery = stride - 2; - for (int i = 0; i < stride; ++i) { - for (int j = 0; j < N0; ++j) { - tmp[j * stride + i] = X[CeltTables.ordery_table[ordery + i] * N0 + j + X_ptr]; - } - } - } else { - for (int i = 0; i < stride; ++i) { - for (int j = 0; j < N0; ++j) { - tmp[j * stride + i] = X[i * N0 + j + X_ptr]; - } - } - } - System.arraycopy(tmp, 0, X, X_ptr, N); - } - - static void haar1(int[] X, int X_ptr, int N0, int stride) { - N0 >>= 1; - for (int i = 0; i < stride; ++i) { - for (int j = 0; j < N0; ++j) { - int tmpidx = X_ptr + i + stride * 2 * j; - int tmp1 = Inlines.MULT16_16(23170, X[tmpidx]); - int tmp2 = Inlines.MULT16_16(23170, X[tmpidx + stride]); - X[tmpidx] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.ADD32(tmp1, tmp2), 15)); - X[tmpidx + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.SUB32(tmp1, tmp2), 15)); - } - } - } - - static void haar1ZeroOffset(int[] X, int N0, int stride) { - N0 >>= 1; - for (int i = 0; i < stride; ++i) { - for (int j = 0; j < N0; ++j) { - int tmpidx = i + stride * 2 * j; - int tmp1 = Inlines.MULT16_16(23170, X[tmpidx]); - int tmp2 = Inlines.MULT16_16(23170, X[tmpidx + stride]); - X[tmpidx] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.ADD32(tmp1, tmp2), 15)); - X[tmpidx + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.SUB32(tmp1, tmp2), 15)); - } - } - } - - static int compute_qn(int N, int b, int offset, int pulse_cap, int stereo) { - int qn; - short[] exp2_table8 = new short[]{16384, 17866, 19483, 21247, 23170, 25267, 27554, 30048}; - int N2 = 2 * N - 1; - if (stereo != 0 && N == 2) { - --N2; - } - int qb = Inlines.celt_sudiv(b + N2 * offset, N2); - qb = Inlines.IMIN(b - pulse_cap - 32, qb); - if ((qb = Inlines.IMIN(64, qb)) < 4) { - qn = 1; - } else { - qn = exp2_table8[qb & 7] >> 14 - (qb >> 3); - qn = qn + 1 >> 1 << 1; - } - Inlines.OpusAssert(qn <= 256); - return qn; - } - - static void compute_theta(band_ctx ctx, split_ctx sctx, int[] X, int X_ptr, int[] Y, int Y_ptr, int N, BoxedValueInt b, int B, int B0, int LM, int stereo, BoxedValueInt fill) { - int delta; - int iside; - int imid; - int itheta = 0; - int inv = 0; - int encode = ctx.encode; - CeltMode m = ctx.m; - int i = ctx.i; - int intensity = ctx.intensity; - EntropyCoder ec = ctx.ec; - int[][] bandE = ctx.bandE; - int pulse_cap = m.logN[i] + LM * 8; - int offset = (pulse_cap >> 1) - (stereo != 0 && N == 2 ? 16 : 4); - int qn = Bands.compute_qn(N, b.Val, offset, pulse_cap, stereo); - if (stereo != 0 && i >= intensity) { - qn = 1; - } - if (encode != 0) { - itheta = VQ.stereo_itheta(X, X_ptr, Y, Y_ptr, stereo, N); - } - int tell = ec.tell_frac(); - if (qn != 1) { - if (encode != 0) { - itheta = itheta * qn + 8192 >> 14; - } - if (stereo != 0 && N > 2) { - int p0 = 3; - int x = itheta; - int x0 = qn / 2; - long ft = Inlines.CapToUInt32(p0 * (x0 + 1) + x0); - if (encode != 0) { - ec.encode(x <= x0 ? p0 * x : x - 1 - x0 + (x0 + 1) * p0, x <= x0 ? p0 * (x + 1) : x - x0 + (x0 + 1) * p0, ft); - } else { - int fs = (int)ec.decode(ft); - x = fs < (x0 + 1) * p0 ? fs / p0 : x0 + 1 + (fs - (x0 + 1) * p0); - ec.dec_update(x <= x0 ? p0 * x : x - 1 - x0 + (x0 + 1) * p0, x <= x0 ? p0 * (x + 1) : x - x0 + (x0 + 1) * p0, ft); - itheta = x; - } - } else if (B0 > 1 || stereo != 0) { - if (encode != 0) { - ec.enc_uint(itheta, qn + 1); - } else { - itheta = (int)ec.dec_uint(qn + 1); - } - } else { - int fs = 1; - int ft = ((qn >> 1) + 1) * ((qn >> 1) + 1); - if (encode != 0) { - fs = itheta <= qn >> 1 ? itheta + 1 : qn + 1 - itheta; - int fl = itheta <= qn >> 1 ? itheta * (itheta + 1) >> 1 : ft - ((qn + 1 - itheta) * (qn + 2 - itheta) >> 1); - ec.encode(fl, fl + fs, ft); - } else { - int fl = 0; - int fm = (int)ec.decode(ft); - if (fm < (qn >> 1) * ((qn >> 1) + 1) >> 1) { - itheta = Inlines.isqrt32(8 * fm + 1) - 1 >> 1; - fs = itheta + 1; - fl = itheta * (itheta + 1) >> 1; - } else { - itheta = 2 * (qn + 1) - Inlines.isqrt32(8 * (ft - fm - 1) + 1) >> 1; - fs = qn + 1 - itheta; - fl = ft - ((qn + 1 - itheta) * (qn + 2 - itheta) >> 1); - } - ec.dec_update(fl, fl + fs, ft); - } - } - Inlines.OpusAssert(itheta >= 0); - itheta = Inlines.celt_udiv(itheta * 16384, qn); - if (encode != 0 && stereo != 0) { - if (itheta == 0) { - Bands.intensity_stereo(m, X, X_ptr, Y, Y_ptr, bandE, i, N); - } else { - Bands.stereo_split(X, X_ptr, Y, Y_ptr, N); - } - } - } else if (stereo != 0) { - if (encode != 0) { - int n = inv = itheta > 8192 ? 1 : 0; - if (inv != 0) { - for (int j = 0; j < N; ++j) { - Y[Y_ptr + j] = 0 - Y[Y_ptr + j]; - } - } - Bands.intensity_stereo(m, X, X_ptr, Y, Y_ptr, bandE, i, N); - } - if (b.Val > 16 && ctx.remaining_bits > 16) { - if (encode != 0) { - ec.enc_bit_logp(inv, 2); - } else { - inv = ec.dec_bit_logp(2L); - } - } else { - inv = 0; - } - itheta = 0; - } - int qalloc = ec.tell_frac() - tell; - b.Val -= qalloc; - if (itheta == 0) { - imid = Short.MAX_VALUE; - iside = 0; - fill.Val &= (1 << B) - 1; - delta = -16384; - } else if (itheta == 16384) { - imid = 0; - iside = Short.MAX_VALUE; - fill.Val &= (1 << B) - 1 << B; - delta = 16384; - } else { - imid = Bands.bitexact_cos((short)itheta); - iside = Bands.bitexact_cos((short)(16384 - itheta)); - delta = Inlines.FRAC_MUL16(N - 1 << 7, Bands.bitexact_log2tan(iside, imid)); - } - sctx.inv = inv; - sctx.imid = imid; - sctx.iside = iside; - sctx.delta = delta; - sctx.itheta = itheta; - sctx.qalloc = qalloc; - } - - static int quant_band_n1(band_ctx ctx, int[] X, int X_ptr, int[] Y, int Y_ptr, int b, int[] lowband_out, int lowband_out_ptr) { - boolean resynth = ctx.encode == 0; - int[] x = X; - int x_ptr = X_ptr; - int encode = ctx.encode; - EntropyCoder ec = ctx.ec; - int stereo = Y != null ? 1 : 0; - int c = 0; - do { - int sign = 0; - if (ctx.remaining_bits >= 8) { - if (encode != 0) { - sign = x[x_ptr] < 0 ? 1 : 0; - ec.enc_bits(sign, 1); - } else { - sign = ec.dec_bits(1); - } - ctx.remaining_bits -= 8; - b -= 8; - } - if (resynth) { - x[x_ptr] = sign != 0 ? -16384 : 16384; - } - x = Y; - x_ptr = Y_ptr; - } while (++c < 1 + stereo); - if (lowband_out != null) { - lowband_out[lowband_out_ptr] = Inlines.SHR16(X[X_ptr], 4); - } - return 1; - } - - static int quant_partition(band_ctx ctx, int[] X, int X_ptr, int N, int b, int B, int[] lowband, int lowband_ptr, int LM, int gain, int fill) { - int imid = 0; - int iside = 0; - int B0 = B; - int mid = 0; - int side = 0; - int cm = 0; - boolean resynth = ctx.encode == 0; - int Y = 0; - int encode = ctx.encode; - CeltMode m = ctx.m; - int i = ctx.i; - int spread = ctx.spread; - EntropyCoder ec = ctx.ec; - short[] cache = m.cache.bits; - short cache_ptr = m.cache.index[(LM + 1) * m.nbEBands + i]; - if (LM != -1 && b > cache[cache_ptr + cache[cache_ptr]] + 12 && N > 2) { - split_ctx sctx = new split_ctx(); - int next_lowband2 = 0; - Y = X_ptr + (N >>= 1); - --LM; - if (B == 1) { - fill = fill & 1 | fill << 1; - } - B = B + 1 >> 1; - BoxedValueInt boxed_b = new BoxedValueInt(b); - BoxedValueInt boxed_fill = new BoxedValueInt(fill); - Bands.compute_theta(ctx, sctx, X, X_ptr, X, Y, N, boxed_b, B, B0, LM, 0, boxed_fill); - b = boxed_b.Val; - fill = boxed_fill.Val; - imid = sctx.imid; - iside = sctx.iside; - int delta = sctx.delta; - int itheta = sctx.itheta; - int qalloc = sctx.qalloc; - mid = imid; - side = iside; - if (B0 > 1 && (itheta & 0x3FFF) != 0) { - delta = itheta > 8192 ? (delta -= delta >> 4 - LM) : Inlines.IMIN(0, delta + (N << 3 >> 5 - LM)); - } - int mbits = Inlines.IMAX(0, Inlines.IMIN(b, (b - delta) / 2)); - int sbits = b - mbits; - ctx.remaining_bits -= qalloc; - if (lowband != null) { - next_lowband2 = lowband_ptr + N; - } - int rebalance = ctx.remaining_bits; - if (mbits >= sbits) { - cm = Bands.quant_partition(ctx, X, X_ptr, N, mbits, B, lowband, lowband_ptr, LM, Inlines.MULT16_16_P15(gain, mid), fill); - if ((rebalance = mbits - (rebalance - ctx.remaining_bits)) > 24 && itheta != 0) { - sbits += rebalance - 24; - } - cm |= Bands.quant_partition(ctx, X, Y, N, sbits, B, lowband, next_lowband2, LM, Inlines.MULT16_16_P15(gain, side), fill >> B) << (B0 >> 1); - } else { - cm = Bands.quant_partition(ctx, X, Y, N, sbits, B, lowband, next_lowband2, LM, Inlines.MULT16_16_P15(gain, side), fill >> B) << (B0 >> 1); - if ((rebalance = sbits - (rebalance - ctx.remaining_bits)) > 24 && itheta != 16384) { - mbits += rebalance - 24; - } - cm |= Bands.quant_partition(ctx, X, X_ptr, N, mbits, B, lowband, lowband_ptr, LM, Inlines.MULT16_16_P15(gain, mid), fill); - } - } else { - int q = Rate.bits2pulses(m, i, LM, b); - int curr_bits = Rate.pulses2bits(m, i, LM, q); - ctx.remaining_bits -= curr_bits; - while (ctx.remaining_bits < 0 && q > 0) { - ctx.remaining_bits += curr_bits; - curr_bits = Rate.pulses2bits(m, i, LM, --q); - ctx.remaining_bits -= curr_bits; - } - if (q != 0) { - int K = Rate.get_pulses(q); - cm = encode != 0 ? VQ.alg_quant(X, X_ptr, N, K, spread, B, ec) : VQ.alg_unquant(X, X_ptr, N, K, spread, B, ec, gain); - } else if (resynth) { - int cm_mask = (1 << B) - 1; - if ((fill &= cm_mask) == 0) { - Arrays.MemSetWithOffset(X, 0, X_ptr, N); - } else { - if (lowband == null) { - for (int j = 0; j < N; ++j) { - ctx.seed = Bands.celt_lcg_rand(ctx.seed); - X[X_ptr + j] = ctx.seed >> 20; - } - cm = cm_mask; - } else { - for (int j = 0; j < N; ++j) { - ctx.seed = Bands.celt_lcg_rand(ctx.seed); - int tmp = 4; - tmp = (ctx.seed & 0x8000) != 0 ? tmp : 0 - tmp; - X[X_ptr + j] = lowband[lowband_ptr + j] + tmp; - } - cm = fill; - } - VQ.renormalise_vector(X, X_ptr, N, gain); - } - } - } - return cm; - } - - static int quant_band(band_ctx ctx, int[] X, int X_ptr, int N, int b, int B, int[] lowband, int lowband_ptr, int LM, int[] lowband_out, int lowband_out_ptr, int gain, int[] lowband_scratch, int lowband_scratch_ptr, int fill) { - int k; - int N0 = N; - int N_B = N; - int B0 = B; - int time_divide = 0; - int recombine = 0; - int cm = 0; - boolean resynth = ctx.encode == 0; - int encode = ctx.encode; - int tf_change = ctx.tf_change; - int longBlocks = B0 == 1 ? 1 : 0; - N_B = Inlines.celt_udiv(N_B, B); - if (N == 1) { - return Bands.quant_band_n1(ctx, X, X_ptr, null, 0, b, lowband_out, lowband_out_ptr); - } - if (tf_change > 0) { - recombine = tf_change; - } - if (lowband_scratch != null && lowband != null && (recombine != 0 || (N_B & 1) == 0 && tf_change < 0 || B0 > 1)) { - System.arraycopy(lowband, lowband_ptr, lowband_scratch, lowband_scratch_ptr, N); - lowband = lowband_scratch; - lowband_ptr = lowband_scratch_ptr; - } - for (k = 0; k < recombine; ++k) { - if (encode != 0) { - Bands.haar1(X, X_ptr, N >> k, 1 << k); - } - if (lowband != null) { - Bands.haar1(lowband, lowband_ptr, N >> k, 1 << k); - } - int idx1 = fill & 0xF; - int idx2 = fill >> 4; - if (idx1 < 0) { - System.out.println("e"); - } - if (idx2 < 0) { - System.out.println("e"); - } - fill = bit_interleave_table[fill & 0xF] | bit_interleave_table[fill >> 4] << 2; - } - B >>= recombine; - N_B <<= recombine; - while ((N_B & 1) == 0 && tf_change < 0) { - if (encode != 0) { - Bands.haar1(X, X_ptr, N_B, B); - } - if (lowband != null) { - Bands.haar1(lowband, lowband_ptr, N_B, B); - } - fill |= fill << B; - B <<= 1; - N_B >>= 1; - ++time_divide; - ++tf_change; - } - B0 = B; - int N_B0 = N_B; - if (B0 > 1) { - if (encode != 0) { - Bands.deinterleave_hadamard(X, X_ptr, N_B >> recombine, B0 << recombine, longBlocks); - } - if (lowband != null) { - Bands.deinterleave_hadamard(lowband, lowband_ptr, N_B >> recombine, B0 << recombine, longBlocks); - } - } - cm = Bands.quant_partition(ctx, X, X_ptr, N, b, B, lowband, lowband_ptr, LM, gain, fill); - if (resynth) { - if (B0 > 1) { - Bands.interleave_hadamard(X, X_ptr, N_B >> recombine, B0 << recombine, longBlocks); - } - N_B = N_B0; - B = B0; - for (k = 0; k < time_divide; ++k) { - cm |= cm >> (B >>= 1); - Bands.haar1(X, X_ptr, N_B <<= 1, B); - } - for (k = 0; k < recombine; ++k) { - cm = bit_deinterleave_table[cm]; - Bands.haar1(X, X_ptr, N0 >> k, 1 << k); - } - B <<= recombine; - if (lowband_out != null) { - int n = Inlines.celt_sqrt(Inlines.SHL32(N0, 22)); - for (int j = 0; j < N0; ++j) { - lowband_out[lowband_out_ptr + j] = Inlines.MULT16_16_Q15(n, X[X_ptr + j]); - } - } - cm &= (1 << B) - 1; - } - return cm; - } - - static int quant_band_stereo(band_ctx ctx, int[] X, int X_ptr, int[] Y, int Y_ptr, int N, int b, int B, int[] lowband, int lowband_ptr, int LM, int[] lowband_out, int lowband_out_ptr, int[] lowband_scratch, int lowband_scratch_ptr, int fill) { - int sbits; - int mbits; - int imid = 0; - int iside = 0; - int inv = 0; - int mid = 0; - int side = 0; - int cm = 0; - boolean resynth = ctx.encode == 0; - split_ctx sctx = new split_ctx(); - int encode = ctx.encode; - EntropyCoder ec = ctx.ec; - if (N == 1) { - return Bands.quant_band_n1(ctx, X, X_ptr, Y, Y_ptr, b, lowband_out, lowband_out_ptr); - } - int orig_fill = fill; - BoxedValueInt boxed_b = new BoxedValueInt(b); - BoxedValueInt boxed_fill = new BoxedValueInt(fill); - Bands.compute_theta(ctx, sctx, X, X_ptr, Y, Y_ptr, N, boxed_b, B, B, LM, 1, boxed_fill); - b = boxed_b.Val; - fill = boxed_fill.Val; - inv = sctx.inv; - imid = sctx.imid; - iside = sctx.iside; - int delta = sctx.delta; - int itheta = sctx.itheta; - int qalloc = sctx.qalloc; - mid = imid; - side = iside; - if (N == 2) { - int y2_ptr; - int[] y2; - int x2_ptr; - int[] x2; - int sign = 0; - mbits = b; - sbits = 0; - if (itheta != 0 && itheta != 16384) { - sbits = 8; - } - mbits -= sbits; - boolean c = itheta > 8192; - ctx.remaining_bits -= qalloc + sbits; - if (c) { - x2 = Y; - x2_ptr = Y_ptr; - y2 = X; - y2_ptr = X_ptr; - } else { - x2 = X; - x2_ptr = X_ptr; - y2 = Y; - y2_ptr = Y_ptr; - } - if (sbits != 0) { - if (encode != 0) { - sign = x2[x2_ptr] * y2[Y_ptr + 1] - x2[x2_ptr + 1] * y2[Y_ptr] < 0 ? 1 : 0; - ec.enc_bits(sign, 1); - } else { - sign = ec.dec_bits(1); - } - } - sign = 1 - 2 * sign; - cm = Bands.quant_band(ctx, x2, x2_ptr, N, mbits, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, Short.MAX_VALUE, lowband_scratch, lowband_scratch_ptr, orig_fill); - y2[Y_ptr] = (0 - sign) * x2[x2_ptr + 1]; - y2[Y_ptr + 1] = sign * x2[x2_ptr]; - if (resynth) { - X[X_ptr] = Inlines.MULT16_16_Q15(mid, X[X_ptr]); - X[X_ptr + 1] = Inlines.MULT16_16_Q15(mid, X[X_ptr + 1]); - Y[Y_ptr] = Inlines.MULT16_16_Q15(side, Y[Y_ptr]); - Y[Y_ptr + 1] = Inlines.MULT16_16_Q15(side, Y[Y_ptr + 1]); - int tmp = X[X_ptr]; - X[X_ptr] = Inlines.SUB16(tmp, Y[Y_ptr]); - Y[Y_ptr] = Inlines.ADD16(tmp, Y[Y_ptr]); - tmp = X[X_ptr + 1]; - X[X_ptr + 1] = Inlines.SUB16(tmp, Y[Y_ptr + 1]); - Y[Y_ptr + 1] = Inlines.ADD16(tmp, Y[Y_ptr + 1]); - } - } else { - mbits = Inlines.IMAX(0, Inlines.IMIN(b, (b - delta) / 2)); - sbits = b - mbits; - ctx.remaining_bits -= qalloc; - int rebalance = ctx.remaining_bits; - if (mbits >= sbits) { - cm = Bands.quant_band(ctx, X, X_ptr, N, mbits, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, Short.MAX_VALUE, lowband_scratch, lowband_scratch_ptr, fill); - if ((rebalance = mbits - (rebalance - ctx.remaining_bits)) > 24 && itheta != 0) { - sbits += rebalance - 24; - } - cm |= Bands.quant_band(ctx, Y, Y_ptr, N, sbits, B, null, 0, LM, null, 0, side, null, 0, fill >> B); - } else { - cm = Bands.quant_band(ctx, Y, Y_ptr, N, sbits, B, null, 0, LM, null, 0, side, null, 0, fill >> B); - if ((rebalance = sbits - (rebalance - ctx.remaining_bits)) > 24 && itheta != 16384) { - mbits += rebalance - 24; - } - cm |= Bands.quant_band(ctx, X, X_ptr, N, mbits, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, Short.MAX_VALUE, lowband_scratch, lowband_scratch_ptr, fill); - } - } - if (resynth) { - if (N != 2) { - Bands.stereo_merge(X, X_ptr, Y, Y_ptr, mid, N); - } - if (inv != 0) { - for (int j = Y_ptr; j < N + Y_ptr; ++j) { - Y[j] = (short)(0 - Y[j]); - } - } - } - return cm; - } - - static void quant_all_bands(int encode, CeltMode m, int start, int end, int[] X_, int[] Y_, short[] collapse_masks, int[][] bandE, int[] pulses, int shortBlocks, int spread, int dual_stereo, int intensity, int[] tf_res, int total_bits, int balance, EntropyCoder ec, int LM, int codedBands, BoxedValueInt seed) { - short[] eBands = m.eBands; - boolean update_lowband = true; - int C = Y_ != null ? 2 : 1; - boolean resynth = encode == 0; - band_ctx ctx = new band_ctx(); - int M = 1 << LM; - int B = shortBlocks != 0 ? M : 1; - int norm_offset = M * eBands[start]; - int[] norm = new int[C * (M * eBands[m.nbEBands - 1] - norm_offset)]; - int norm2 = M * eBands[m.nbEBands - 1] - norm_offset; - int[] lowband_scratch = X_; - int lowband_scratch_ptr = M * eBands[m.nbEBands - 1]; - int lowband_offset = 0; - ctx.bandE = bandE; - ctx.ec = ec; - ctx.encode = encode; - ctx.intensity = intensity; - ctx.m = m; - ctx.seed = seed.Val; - ctx.spread = spread; - for (int i = start; i < end; ++i) { - long x_cm; - long y_cm; - int b; - int remaining_bits; - int[] Y; - int effective_lowband = -1; - int Y_ptr = 0; - int tf_change = 0; - ctx.i = i; - boolean last = i == end - 1; - int[] X = X_; - int X_ptr = M * eBands[i]; - if (Y_ != null) { - Y = Y_; - Y_ptr = M * eBands[i]; - } else { - Y = null; - } - int N = M * eBands[i + 1] - M * eBands[i]; - int tell = ec.tell_frac(); - if (i != start) { - balance -= tell; - } - ctx.remaining_bits = remaining_bits = total_bits - tell - 1; - if (i <= codedBands - 1) { - int curr_balance = Inlines.celt_sudiv(balance, Inlines.IMIN(3, codedBands - i)); - b = Inlines.IMAX(0, Inlines.IMIN(16383, Inlines.IMIN(remaining_bits + 1, pulses[i] + curr_balance))); - } else { - b = 0; - } - if (resynth && M * eBands[i] - N >= M * eBands[start] && (update_lowband || lowband_offset == 0)) { - lowband_offset = i; - } - ctx.tf_change = tf_change = tf_res[i]; - if (i >= m.effEBands) { - X = norm; - X_ptr = 0; - if (Y_ != null) { - Y = norm; - Y_ptr = 0; - } - lowband_scratch = null; - } - if (i == end - 1) { - lowband_scratch = null; - } - if (lowband_offset != 0 && (spread != 3 || B > 1 || tf_change < 0)) { - effective_lowband = Inlines.IMAX(0, M * eBands[lowband_offset] - norm_offset - N); - int fold_start = lowband_offset; - while (M * eBands[--fold_start] > effective_lowband + norm_offset) { - } - int fold_end = lowband_offset - 1; - while (M * eBands[++fold_end] < effective_lowband + norm_offset + N) { - } - y_cm = 0L; - x_cm = 0L; - int fold_i = fold_start; - do { - x_cm |= (long)collapse_masks[fold_i * C + 0]; - y_cm |= (long)collapse_masks[fold_i * C + C - 1]; - } while (++fold_i < fold_end); - } else { - x_cm = y_cm = (long)((1 << B) - 1); - } - if (dual_stereo != 0 && i == intensity) { - dual_stereo = 0; - if (resynth) { - for (int j = 0; j < M * eBands[i] - norm_offset; ++j) { - norm[j] = Inlines.HALF32(norm[j] + norm[norm2 + j]); - } - } - } - if (dual_stereo != 0) { - x_cm = Bands.quant_band(ctx, X, X_ptr, N, b / 2, B, (int[])(effective_lowband != -1 ? norm : null), effective_lowband, LM, last ? null : norm, M * eBands[i] - norm_offset, Short.MAX_VALUE, lowband_scratch, lowband_scratch_ptr, (int)x_cm); - y_cm = Bands.quant_band(ctx, Y, Y_ptr, N, b / 2, B, (int[])(effective_lowband != -1 ? norm : null), norm2 + effective_lowband, LM, last ? null : norm, norm2 + (M * eBands[i] - norm_offset), Short.MAX_VALUE, lowband_scratch, lowband_scratch_ptr, (int)y_cm); - } else { - x_cm = Y != null ? (long)Bands.quant_band_stereo(ctx, X, X_ptr, Y, Y_ptr, N, b, B, (int[])(effective_lowband != -1 ? norm : null), effective_lowband, LM, last ? null : norm, M * eBands[i] - norm_offset, lowband_scratch, lowband_scratch_ptr, (int)(x_cm | y_cm)) : (long)Bands.quant_band(ctx, X, X_ptr, N, b, B, (int[])(effective_lowband != -1 ? norm : null), effective_lowband, LM, last ? null : norm, M * eBands[i] - norm_offset, Short.MAX_VALUE, lowband_scratch, lowband_scratch_ptr, (int)(x_cm | y_cm)); - y_cm = x_cm; - } - collapse_masks[i * C + 0] = (short)(x_cm & 0xFFL); - collapse_masks[i * C + C - 1] = (short)(y_cm & 0xFFL); - balance += pulses[i] + tell; - update_lowband = b > N << 3; - } - seed.Val = ctx.seed; - } - - public static class band_ctx { - public int encode; - public CeltMode m; - public int i; - public int intensity; - public int spread; - public int tf_change; - public EntropyCoder ec; - public int remaining_bits; - public int[][] bandE; - public int seed; - } - - public static class split_ctx { - public int inv; - public int imid; - public int iside; - public int delta; - public int itheta; - public int qalloc; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueByte.java b/source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueByte.java deleted file mode 100644 index a799b4e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueByte.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class BoxedValueByte { - public byte Val; - - public BoxedValueByte(byte v) { - this.Val = v; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueInt.java b/source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueInt.java deleted file mode 100644 index 64ae46c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueInt.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class BoxedValueInt { - public int Val; - - public BoxedValueInt(int v) { - this.Val = v; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueShort.java b/source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueShort.java deleted file mode 100644 index 1881674..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/BoxedValueShort.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class BoxedValueShort { - public short Val; - - public BoxedValueShort(short v) { - this.Val = v; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/BurgModified.java b/source/decompiled/de/maxhenkel/voicechat/concentus/BurgModified.java deleted file mode 100644 index 59ee3ab..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/BurgModified.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltPitchXCorr; -import de.maxhenkel.voicechat.concentus.Inlines; - -class BurgModified { - private static final int MAX_FRAME_SIZE = 384; - private static final int QA = 25; - private static final int N_BITS_HEAD_ROOM = 2; - private static final int MIN_RSHIFTS = -16; - private static final int MAX_RSHIFTS = 7; - - BurgModified() { - } - - static void silk_burg_modified(BoxedValueInt res_nrg, BoxedValueInt res_nrg_Q, int[] A_Q16, short[] x, int x_ptr, int minInvGain_Q30, int subfr_length, int nb_subfr, int D) { - int nrg; - int Atmp1; - int k; - int tmp1; - int n; - int x_offset; - int s; - int[] C_first_row = new int[16]; - int[] C_last_row = new int[16]; - int[] Af_QA = new int[16]; - int[] CAf = new int[17]; - int[] CAb = new int[17]; - int[] xcorr = new int[16]; - Inlines.OpusAssert(subfr_length * nb_subfr <= 384); - long C0_64 = Inlines.silk_inner_prod16_aligned_64(x, x_ptr, x, x_ptr, subfr_length * nb_subfr); - int lz = Inlines.silk_CLZ64(C0_64); - int rshifts = 35 - lz; - if (rshifts > 7) { - rshifts = 7; - } - if (rshifts < -16) { - rshifts = -16; - } - int C0 = rshifts > 0 ? (int)Inlines.silk_RSHIFT64(C0_64, rshifts) : Inlines.silk_LSHIFT32((int)C0_64, -rshifts); - CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(42950, C0) + 1; - Arrays.MemSet(C_first_row, 0, 16); - if (rshifts > 0) { - for (s = 0; s < nb_subfr; ++s) { - x_offset = x_ptr + s * subfr_length; - for (n = 1; n < D + 1; ++n) { - int n2 = n - 1; - C_first_row[n2] = C_first_row[n2] + (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, x_offset, x, x_offset + n, subfr_length - n), rshifts); - } - } - } else { - for (s = 0; s < nb_subfr; ++s) { - x_offset = x_ptr + s * subfr_length; - CeltPitchXCorr.pitch_xcorr(x, x_offset, x, x_offset + 1, xcorr, subfr_length - D, D); - for (n = 1; n < D + 1; ++n) { - int d = 0; - for (int i = n + subfr_length - D; i < subfr_length; ++i) { - d = Inlines.MAC16_16(d, x[x_offset + i], x[x_offset + i - n]); - } - int n3 = n - 1; - xcorr[n3] = xcorr[n3] + d; - } - for (n = 1; n < D + 1; ++n) { - int n4 = n - 1; - C_first_row[n4] = C_first_row[n4] + Inlines.silk_LSHIFT32(xcorr[n - 1], -rshifts); - } - } - } - System.arraycopy(C_first_row, 0, C_last_row, 0, 16); - CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(42950, C0) + 1; - int invGain_Q30 = 0x40000000; - boolean reached_max_gain = false; - for (n = 0; n < D; ++n) { - int Atmp_QA; - int tmp2; - int x2; - int x1; - if (rshifts > -2) { - for (s = 0; s < nb_subfr; ++s) { - x_offset = x_ptr + s * subfr_length; - x1 = -Inlines.silk_LSHIFT32(x[x_offset + n], 16 - rshifts); - x2 = -Inlines.silk_LSHIFT32(x[x_offset + subfr_length - n - 1], 16 - rshifts); - tmp1 = Inlines.silk_LSHIFT32(x[x_offset + n], 9); - tmp2 = Inlines.silk_LSHIFT32(x[x_offset + subfr_length - n - 1], 9); - for (k = 0; k < n; ++k) { - C_first_row[k] = Inlines.silk_SMLAWB(C_first_row[k], x1, x[x_offset + n - k - 1]); - C_last_row[k] = Inlines.silk_SMLAWB(C_last_row[k], x2, x[x_offset + subfr_length - n + k]); - Atmp_QA = Af_QA[k]; - tmp1 = Inlines.silk_SMLAWB(tmp1, Atmp_QA, x[x_offset + n - k - 1]); - tmp2 = Inlines.silk_SMLAWB(tmp2, Atmp_QA, x[x_offset + subfr_length - n + k]); - } - tmp1 = Inlines.silk_LSHIFT32(-tmp1, 7 - rshifts); - tmp2 = Inlines.silk_LSHIFT32(-tmp2, 7 - rshifts); - for (k = 0; k <= n; ++k) { - CAf[k] = Inlines.silk_SMLAWB(CAf[k], tmp1, x[x_offset + n - k]); - CAb[k] = Inlines.silk_SMLAWB(CAb[k], tmp2, x[x_offset + subfr_length - n + k - 1]); - } - } - } else { - for (s = 0; s < nb_subfr; ++s) { - x_offset = x_ptr + s * subfr_length; - x1 = -Inlines.silk_LSHIFT32(x[x_offset + n], -rshifts); - x2 = -Inlines.silk_LSHIFT32(x[x_offset + subfr_length - n - 1], -rshifts); - tmp1 = Inlines.silk_LSHIFT32(x[x_offset + n], 17); - tmp2 = Inlines.silk_LSHIFT32(x[x_offset + subfr_length - n - 1], 17); - for (k = 0; k < n; ++k) { - C_first_row[k] = Inlines.silk_MLA(C_first_row[k], x1, x[x_offset + n - k - 1]); - C_last_row[k] = Inlines.silk_MLA(C_last_row[k], x2, x[x_offset + subfr_length - n + k]); - Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], 8); - tmp1 = Inlines.silk_MLA(tmp1, x[x_offset + n - k - 1], Atmp1); - tmp2 = Inlines.silk_MLA(tmp2, x[x_offset + subfr_length - n + k], Atmp1); - } - tmp1 = -tmp1; - tmp2 = -tmp2; - for (k = 0; k <= n; ++k) { - CAf[k] = Inlines.silk_SMLAWW(CAf[k], tmp1, Inlines.silk_LSHIFT32(x[x_offset + n - k], -rshifts - 1)); - CAb[k] = Inlines.silk_SMLAWW(CAb[k], tmp2, Inlines.silk_LSHIFT32(x[x_offset + subfr_length - n + k - 1], -rshifts - 1)); - } - } - } - tmp1 = C_first_row[n]; - tmp2 = C_last_row[n]; - int num = 0; - nrg = Inlines.silk_ADD32(CAb[0], CAf[0]); - for (k = 0; k < n; ++k) { - Atmp_QA = Af_QA[k]; - lz = Inlines.silk_CLZ32(Inlines.silk_abs(Atmp_QA)) - 1; - lz = Inlines.silk_min(7, lz); - Atmp1 = Inlines.silk_LSHIFT32(Atmp_QA, lz); - tmp1 = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(C_last_row[n - k - 1], Atmp1), 7 - lz); - tmp2 = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(C_first_row[n - k - 1], Atmp1), 7 - lz); - num = Inlines.silk_ADD_LSHIFT32(num, Inlines.silk_SMMUL(CAb[n - k], Atmp1), 7 - lz); - nrg = Inlines.silk_ADD_LSHIFT32(nrg, Inlines.silk_SMMUL(Inlines.silk_ADD32(CAb[k + 1], CAf[k + 1]), Atmp1), 7 - lz); - } - CAf[n + 1] = tmp1; - CAb[n + 1] = tmp2; - num = Inlines.silk_ADD32(num, tmp2); - int rc_Q31 = Inlines.silk_abs(num = Inlines.silk_LSHIFT32(-num, 1)) < nrg ? Inlines.silk_DIV32_varQ(num, nrg, 31) : (num > 0 ? Integer.MAX_VALUE : Integer.MIN_VALUE); - tmp1 = 0x40000000 - Inlines.silk_SMMUL(rc_Q31, rc_Q31); - if ((tmp1 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, tmp1), 2)) <= minInvGain_Q30) { - tmp2 = 0x40000000 - Inlines.silk_DIV32_varQ(minInvGain_Q30, invGain_Q30, 30); - rc_Q31 = Inlines.silk_SQRT_APPROX(tmp2); - rc_Q31 = Inlines.silk_RSHIFT32(rc_Q31 + Inlines.silk_DIV32(tmp2, rc_Q31), 1); - rc_Q31 = Inlines.silk_LSHIFT32(rc_Q31, 16); - if (num < 0) { - rc_Q31 = -rc_Q31; - } - invGain_Q30 = minInvGain_Q30; - reached_max_gain = true; - } else { - invGain_Q30 = tmp1; - } - for (k = 0; k < n + 1 >> 1; ++k) { - tmp1 = Af_QA[k]; - tmp2 = Af_QA[n - k - 1]; - Af_QA[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); - Af_QA[n - k - 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); - } - Af_QA[n] = Inlines.silk_RSHIFT32(rc_Q31, 6); - if (reached_max_gain) { - for (k = n + 1; k < D; ++k) { - Af_QA[k] = 0; - } - break; - } - for (k = 0; k <= n + 1; ++k) { - tmp1 = CAf[k]; - tmp2 = CAb[n - k + 1]; - CAf[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); - CAb[n - k + 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); - } - } - if (reached_max_gain) { - for (k = 0; k < D; ++k) { - A_Q16[k] = -Inlines.silk_RSHIFT_ROUND(Af_QA[k], 9); - } - if (rshifts > 0) { - for (s = 0; s < nb_subfr; ++s) { - x_offset = x_ptr + s * subfr_length; - C0 -= (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, x_offset, x, x_offset, D), rshifts); - } - } else { - for (s = 0; s < nb_subfr; ++s) { - x_offset = x_ptr + s * subfr_length; - C0 -= Inlines.silk_LSHIFT32(Inlines.silk_inner_prod_self(x, x_offset, D), -rshifts); - } - } - res_nrg.Val = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, C0), 2); - res_nrg_Q.Val = 0 - rshifts; - } else { - nrg = CAf[0]; - tmp1 = 65536; - for (k = 0; k < D; ++k) { - Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], 9); - nrg = Inlines.silk_SMLAWW(nrg, CAf[k + 1], Atmp1); - tmp1 = Inlines.silk_SMLAWW(tmp1, Atmp1, Atmp1); - A_Q16[k] = -Atmp1; - } - res_nrg.Val = Inlines.silk_SMLAWW(nrg, Inlines.silk_SMMUL(42950, C0), -tmp1); - res_nrg_Q.Val = -rshifts; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CNG.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CNG.java deleted file mode 100644 index 80155ba..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CNG.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CNGState; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.NLSF; -import de.maxhenkel.voicechat.concentus.SilkChannelDecoder; -import de.maxhenkel.voicechat.concentus.SilkDecoderControl; - -class CNG { - CNG() { - } - - static void silk_CNG_exc(int[] exc_Q10, int exc_Q10_ptr, int[] exc_buf_Q14, int Gain_Q16, int length, BoxedValueInt rand_seed) { - int exc_mask = 255; - while (exc_mask > length) { - exc_mask = Inlines.silk_RSHIFT(exc_mask, 1); - } - int seed = rand_seed.Val; - for (int i = exc_Q10_ptr; i < exc_Q10_ptr + length; ++i) { - int idx = Inlines.silk_RSHIFT(seed = Inlines.silk_RAND(seed), 24) & exc_mask; - Inlines.OpusAssert(idx >= 0); - Inlines.OpusAssert(idx <= 255); - exc_Q10[i] = (short)Inlines.silk_SAT16(Inlines.silk_SMULWW(exc_buf_Q14[idx], Gain_Q16 >> 4)); - } - rand_seed.Val = seed; - } - - static void silk_CNG_Reset(SilkChannelDecoder psDec) { - int NLSF_step_Q15 = Inlines.silk_DIV32_16(Short.MAX_VALUE, (short)(psDec.LPC_order + 1)); - int NLSF_acc_Q15 = 0; - for (int i = 0; i < psDec.LPC_order; ++i) { - psDec.sCNG.CNG_smth_NLSF_Q15[i] = (short)(NLSF_acc_Q15 += NLSF_step_Q15); - } - psDec.sCNG.CNG_smth_Gain_Q16 = 0; - psDec.sCNG.rand_seed = 3176576; - } - - static void silk_CNG(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, short[] frame, int frame_ptr, int length) { - int i; - short[] A_Q12 = new short[psDec.LPC_order]; - CNGState psCNG = psDec.sCNG; - if (psDec.fs_kHz != psCNG.fs_kHz) { - CNG.silk_CNG_Reset(psDec); - psCNG.fs_kHz = psDec.fs_kHz; - } - if (psDec.lossCnt == 0 && psDec.prevSignalType == 0) { - for (i = 0; i < psDec.LPC_order; ++i) { - int n = i; - psCNG.CNG_smth_NLSF_Q15[n] = (short)(psCNG.CNG_smth_NLSF_Q15[n] + (short)Inlines.silk_SMULWB(psDec.prevNLSF_Q15[i] - psCNG.CNG_smth_NLSF_Q15[i], 16348)); - } - int max_Gain_Q16 = 0; - int subfr = 0; - for (i = 0; i < psDec.nb_subfr; ++i) { - if (psDecCtrl.Gains_Q16[i] <= max_Gain_Q16) continue; - max_Gain_Q16 = psDecCtrl.Gains_Q16[i]; - subfr = i; - } - Arrays.MemMove(psCNG.CNG_exc_buf_Q14, 0, psDec.subfr_length, (psDec.nb_subfr - 1) * psDec.subfr_length); - for (i = 0; i < psDec.nb_subfr; ++i) { - psCNG.CNG_smth_Gain_Q16 += Inlines.silk_SMULWB(psDecCtrl.Gains_Q16[i] - psCNG.CNG_smth_Gain_Q16, 4634); - } - } - if (psDec.lossCnt != 0) { - int[] CNG_sig_Q10 = new int[length + 16]; - int gain_Q16 = Inlines.silk_SMULWW(psDec.sPLC.randScale_Q14, psDec.sPLC.prevGain_Q16[1]); - if (gain_Q16 >= 0x200000 || psCNG.CNG_smth_Gain_Q16 > 0x800000) { - gain_Q16 = Inlines.silk_SMULTT(gain_Q16, gain_Q16); - gain_Q16 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULTT(psCNG.CNG_smth_Gain_Q16, psCNG.CNG_smth_Gain_Q16), gain_Q16, 5); - gain_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(gain_Q16), 16); - } else { - gain_Q16 = Inlines.silk_SMULWW(gain_Q16, gain_Q16); - gain_Q16 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULWW(psCNG.CNG_smth_Gain_Q16, psCNG.CNG_smth_Gain_Q16), gain_Q16, 5); - gain_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(gain_Q16), 8); - } - BoxedValueInt boxed_rand_seed = new BoxedValueInt(psCNG.rand_seed); - CNG.silk_CNG_exc(CNG_sig_Q10, 16, psCNG.CNG_exc_buf_Q14, gain_Q16, length, boxed_rand_seed); - psCNG.rand_seed = boxed_rand_seed.Val; - NLSF.silk_NLSF2A(A_Q12, psCNG.CNG_smth_NLSF_Q15, psDec.LPC_order); - System.arraycopy(psCNG.CNG_synth_state, 0, CNG_sig_Q10, 0, 16); - for (i = 0; i < length; ++i) { - int lpci = 16 + i; - Inlines.OpusAssert(psDec.LPC_order == 10 || psDec.LPC_order == 16); - int sum_Q6 = Inlines.silk_RSHIFT(psDec.LPC_order, 1); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 1], A_Q12[0]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 2], A_Q12[1]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 3], A_Q12[2]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 4], A_Q12[3]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 5], A_Q12[4]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 6], A_Q12[5]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 7], A_Q12[6]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 8], A_Q12[7]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 9], A_Q12[8]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 10], A_Q12[9]); - if (psDec.LPC_order == 16) { - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 11], A_Q12[10]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 12], A_Q12[11]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 13], A_Q12[12]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 14], A_Q12[13]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 15], A_Q12[14]); - sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 16], A_Q12[15]); - } - CNG_sig_Q10[lpci] = Inlines.silk_ADD_LSHIFT(CNG_sig_Q10[lpci], sum_Q6, 4); - frame[frame_ptr + i] = Inlines.silk_ADD_SAT16(frame[frame_ptr + i], (short)Inlines.silk_RSHIFT_ROUND(CNG_sig_Q10[lpci], 10)); - } - System.arraycopy(CNG_sig_Q10, length, psCNG.CNG_synth_state, 0, 16); - } else { - Arrays.MemSet(psCNG.CNG_synth_state, 0, psDec.LPC_order); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CNGState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CNGState.java deleted file mode 100644 index 4013159..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CNGState.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class CNGState { - final int[] CNG_exc_buf_Q14 = new int[320]; - final short[] CNG_smth_NLSF_Q15 = new short[16]; - final int[] CNG_synth_state = new int[16]; - int CNG_smth_Gain_Q16 = 0; - int rand_seed = 0; - int fs_kHz = 0; - - CNGState() { - } - - void Reset() { - Arrays.MemSet(this.CNG_exc_buf_Q14, 0, 320); - Arrays.MemSet(this.CNG_smth_NLSF_Q15, (short)0, 16); - Arrays.MemSet(this.CNG_synth_state, 0, 16); - this.CNG_smth_Gain_Q16 = 0; - this.rand_seed = 0; - this.fs_kHz = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CWRS.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CWRS.java deleted file mode 100644 index be2bc76..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CWRS.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.CeltTables; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; - -class CWRS { - static final int[] CELT_PVQ_U_ROW = new int[]{0, 176, 351, 525, 698, 870, 1041, 1131, 1178, 1207, 1226, 1240, 1248, 1254, 1257}; - - CWRS() { - } - - private static long CELT_PVQ_U(int _n, int _k) { - return CeltTables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[Inlines.IMIN(_n, _k)] + Inlines.IMAX(_n, _k)]; - } - - private static long CELT_PVQ_V(int _n, int _k) { - return CWRS.CELT_PVQ_U(_n, _k) + CWRS.CELT_PVQ_U(_n, _k + 1); - } - - static long icwrs(int _n, int[] _y) { - Inlines.OpusAssert(_n >= 2); - int j = _n - 1; - long i = _y[j] < 0 ? 1L : 0L; - int k = Inlines.abs(_y[j]); - do { - i += CWRS.CELT_PVQ_U(_n - --j, k); - k += Inlines.abs(_y[j]); - if (_y[j] >= 0) continue; - i += CWRS.CELT_PVQ_U(_n - j, k + 1); - } while (j > 0); - return i; - } - - static void encode_pulses(int[] _y, int _n, int _k, EntropyCoder _enc) { - Inlines.OpusAssert(_k > 0); - _enc.enc_uint(CWRS.icwrs(_n, _y), CWRS.CELT_PVQ_V(_n, _k)); - } - - static int cwrsi(int _n, int _k, long _i, int[] _y) { - short val; - int k0; - int s; - long p; - int yy = 0; - int y_ptr = 0; - Inlines.OpusAssert(_k > 0); - Inlines.OpusAssert(_n > 1); - while (_n > 2) { - long q; - if (_k >= _n) { - int row = CELT_PVQ_U_ROW[_n]; - p = CeltTables.CELT_PVQ_U_DATA[row + _k + 1]; - s = 0 - (_i >= p ? 1 : 0); - k0 = _k; - q = CeltTables.CELT_PVQ_U_DATA[row + _n]; - if (q > (_i -= Inlines.CapToUInt32(p & (long)s))) { - Inlines.OpusAssert(p > q); - _k = _n; - while ((p = CeltTables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[--_k] + _n]) > _i) { - } - } else { - p = CeltTables.CELT_PVQ_U_DATA[row + _k]; - while (p > _i) { - p = CeltTables.CELT_PVQ_U_DATA[row + --_k]; - } - } - _i -= p; - val = (short)(k0 - _k + s ^ s); - _y[y_ptr++] = val; - yy = Inlines.MAC16_16(yy, val, val); - } else { - p = CeltTables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[_k] + _n]; - q = CeltTables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[_k + 1] + _n]; - if (p <= _i && _i < q) { - _i -= p; - _y[y_ptr++] = 0; - } else { - s = 0 - (_i >= q ? 1 : 0); - _i -= Inlines.CapToUInt32(q & (long)s); - k0 = _k; - while ((p = CeltTables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[--_k] + _n]) > _i) { - } - _i -= p; - val = (short)(k0 - _k + s ^ s); - _y[y_ptr++] = val; - yy = Inlines.MAC16_16(yy, val, val); - } - } - --_n; - } - p = 2L * (long)_k + 1L; - s = 0 - (_i >= p ? 1 : 0); - k0 = _k; - _k = (int)((_i -= Inlines.CapToUInt32(p & (long)s)) + 1L >> 1); - if (_k != 0) { - _i -= 2L * (long)_k - 1L; - } - val = (short)(k0 - _k + s ^ s); - _y[y_ptr++] = val; - yy = Inlines.MAC16_16(yy, val, val); - s = -((int)_i); - val = (short)(_k + s ^ s); - _y[y_ptr] = val; - yy = Inlines.MAC16_16(yy, val, val); - return yy; - } - - static int decode_pulses(int[] _y, int _n, int _k, EntropyCoder _dec) { - return CWRS.cwrsi(_n, _k, _dec.dec_uint(CWRS.CELT_PVQ_V(_n, _k)), _y); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltCommon.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CeltCommon.java deleted file mode 100644 index b4f80d3..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltCommon.java +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.AnalysisInfo; -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Bands; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltMode; -import de.maxhenkel.voicechat.concentus.CeltTables; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Kernels; -import de.maxhenkel.voicechat.concentus.MDCT; -import de.maxhenkel.voicechat.concentus.OpusFramesize; -import de.maxhenkel.voicechat.concentus.Pitch; - -class CeltCommon { - private static final short[] inv_table = new short[]{255, 255, 156, 110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25, 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12, 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2}; - private static final short[][] gains = new short[][]{{10048, 7112, 4248}, {15200, 8784, 0}, {26208, 3280, 0}}; - private static final byte[][] tf_select_table = new byte[][]{{0, -1, 0, -1, 0, -1, 0, -1}, {0, -1, 0, -2, 1, 0, 1, -1}, {0, -2, 0, -3, 2, 0, 1, -1}, {0, -2, 0, -3, 3, 0, 1, -1}}; - - CeltCommon() { - } - - static int compute_vbr(CeltMode mode, AnalysisInfo analysis, int base_target, int LM, int bitrate, int lastCodedBands, int C, int intensity, int constrained_vbr, int stereo_saving, int tot_boost, int tf_estimate, int pitch_change, int maxDepth, OpusFramesize variable_duration, int lfe, int has_surround_mask, int surround_masking, int temporal_vbr) { - int nbEBands = mode.nbEBands; - short[] eBands = mode.eBands; - int coded_bands = lastCodedBands != 0 ? lastCodedBands : nbEBands; - int coded_bins = eBands[coded_bands] << LM; - if (C == 2) { - coded_bins += eBands[Inlines.IMIN(intensity, coded_bands)] << LM; - } - int target = base_target; - if (analysis.enabled && analysis.valid != 0 && (double)analysis.activity < 0.4) { - target -= (int)((float)(coded_bins << 3) * (0.4f - analysis.activity)); - } - if (C == 2) { - int coded_stereo_bands = Inlines.IMIN(intensity, coded_bands); - int coded_stereo_dof = (eBands[coded_stereo_bands] << LM) - coded_stereo_bands; - int max_frac = Inlines.DIV32_16(Inlines.MULT16_16(26214, coded_stereo_dof), coded_bins); - stereo_saving = Inlines.MIN16(stereo_saving, 256); - target -= Inlines.MIN32(Inlines.MULT16_32_Q15(max_frac, target), Inlines.SHR32(Inlines.MULT16_16(stereo_saving - 26, coded_stereo_dof << 3), 8)); - } - target += tot_boost - (16 << LM); - int tf_calibration = variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE ? 328 : 655; - target += Inlines.SHL32(Inlines.MULT16_32_Q15(tf_estimate - tf_calibration, target), 1); - if (analysis.enabled && analysis.valid != 0 && lfe == 0) { - float tonal = Inlines.MAX16(0.0f, analysis.tonality - 0.15f) - 0.09f; - int tonal_target = target + (int)((float)(coded_bins << 3) * 1.2f * tonal); - if (pitch_change != 0) { - tonal_target += (int)((float)(coded_bins << 3) * 0.8f); - } - target = tonal_target; - } - if (has_surround_mask != 0 && lfe == 0) { - int surround_target = target + Inlines.SHR32(Inlines.MULT16_16(surround_masking, coded_bins << 3), 10); - target = Inlines.IMAX(target / 4, surround_target); - } - int bins = eBands[nbEBands - 2] << LM; - int floor_depth = Inlines.SHR32(Inlines.MULT16_16(C * bins << 3, maxDepth), 10); - floor_depth = Inlines.IMAX(floor_depth, target >> 2); - target = Inlines.IMIN(target, floor_depth); - if (!(has_surround_mask != 0 && lfe == 0 || constrained_vbr == 0 && bitrate >= 64000)) { - int rate_factor = Inlines.MAX16(0, bitrate - 32000); - if (constrained_vbr != 0) { - rate_factor = Inlines.MIN16(rate_factor, 21955); - } - target = base_target + Inlines.MULT16_32_Q15(rate_factor, target - base_target); - } - if (has_surround_mask == 0 && tf_estimate < 3277) { - int amount = Inlines.MULT16_16_Q15(3329, Inlines.IMAX(0, Inlines.IMIN(32000, 96000 - bitrate))); - int tvbr_factor = Inlines.SHR32(Inlines.MULT16_16(temporal_vbr, amount), 10); - target += Inlines.MULT16_32_Q15(tvbr_factor, target); - } - target = Inlines.IMIN(2 * base_target, target); - return target; - } - - static int transient_analysis(int[][] input, int len, int C, BoxedValueInt tf_estimate, BoxedValueInt tf_chan) { - int is_transient = 0; - int mask_metric = 0; - tf_chan.Val = 0; - int[] tmp = new int[len]; - int len2 = len / 2; - for (int c = 0; c < C; ++c) { - int i; - int unmask = 0; - int mem0 = 0; - int mem1 = 0; - for (i = 0; i < len; ++i) { - int x = Inlines.SHR32(input[c][i], 12); - int y = Inlines.ADD32(mem0, x); - mem0 = mem1 + y - Inlines.SHL32(x, 1); - mem1 = x - Inlines.SHR32(y, 1); - tmp[i] = Inlines.EXTRACT16(Inlines.SHR32(y, 2)); - } - Arrays.MemSet(tmp, 0, 12); - int shift = 0; - shift = 14 - Inlines.celt_ilog2(1 + Inlines.celt_maxabs32(tmp, 0, len)); - if (shift != 0) { - for (i = 0; i < len; ++i) { - tmp[i] = Inlines.SHL16(tmp[i], shift); - } - } - int mean = 0; - mem0 = 0; - for (i = 0; i < len2; ++i) { - int x2 = Inlines.PSHR32(Inlines.MULT16_16(tmp[2 * i], tmp[2 * i]) + Inlines.MULT16_16(tmp[2 * i + 1], tmp[2 * i + 1]), 16); - mean += x2; - tmp[i] = mem0 + Inlines.PSHR32(x2 - mem0, 4); - mem0 = tmp[i]; - } - mem0 = 0; - int maxE = 0; - for (i = len2 - 1; i >= 0; --i) { - tmp[i] = mem0 + Inlines.PSHR32(tmp[i] - mem0, 3); - mem0 = tmp[i]; - maxE = Inlines.MAX16(maxE, mem0); - } - mean = Inlines.MULT16_16(Inlines.celt_sqrt(mean), Inlines.celt_sqrt(Inlines.MULT16_16(maxE, len2 >> 1))); - int norm = Inlines.SHL32(len2, 20) / Inlines.ADD32(1, Inlines.SHR32(mean, 1)); - unmask = 0; - for (i = 12; i < len2 - 5; i += 4) { - int id = Inlines.MAX32(0, Inlines.MIN32(127, Inlines.MULT16_32_Q15(tmp[i] + 1, norm))); - unmask += inv_table[id]; - } - if ((unmask = 64 * unmask * 4 / (6 * (len2 - 17))) <= mask_metric) continue; - tf_chan.Val = c; - mask_metric = unmask; - } - is_transient = mask_metric > 200 ? 1 : 0; - int tf_max = Inlines.MAX16(0, Inlines.celt_sqrt(27 * mask_metric) - 42); - tf_estimate.Val = Inlines.celt_sqrt(Inlines.MAX32(0, Inlines.SHL32(Inlines.MULT16_16(113, Inlines.MIN16(163, tf_max)), 14) - 37312528)); - return is_transient; - } - - static int patch_transient_decision(int[][] newE, int[][] oldE, int nbEBands, int start, int end, int C) { - int i; - int mean_diff = 0; - int[] spread_old = new int[26]; - if (C == 1) { - spread_old[start] = oldE[0][start]; - for (i = start + 1; i < end; ++i) { - spread_old[i] = Inlines.MAX16(spread_old[i - 1] - 1024, oldE[0][i]); - } - } else { - spread_old[start] = Inlines.MAX16(oldE[0][start], oldE[1][start]); - for (i = start + 1; i < end; ++i) { - spread_old[i] = Inlines.MAX16(spread_old[i - 1] - 1024, Inlines.MAX16(oldE[0][i], oldE[1][i])); - } - } - for (i = end - 2; i >= start; --i) { - spread_old[i] = Inlines.MAX16(spread_old[i], spread_old[i + 1] - 1024); - } - int c = 0; - do { - for (i = Inlines.IMAX(2, start); i < end - 1; ++i) { - int x1 = Inlines.MAX16(0, newE[c][i]); - int x2 = Inlines.MAX16(0, spread_old[i]); - mean_diff = Inlines.ADD32(mean_diff, Inlines.MAX16(0, Inlines.SUB16(x1, x2))); - } - } while (++c < C); - return (mean_diff = Inlines.DIV32(mean_diff, C * (end - 1 - Inlines.IMAX(2, start)))) > 1024 ? 1 : 0; - } - - static void compute_mdcts(CeltMode mode, int shortBlocks, int[][] input, int[][] output, int C, int CC, int LM, int upsample) { - int i; - int shift; - int N; - int B; - int overlap = mode.overlap; - if (shortBlocks != 0) { - B = shortBlocks; - N = mode.shortMdctSize; - shift = mode.maxLM; - } else { - B = 1; - N = mode.shortMdctSize << LM; - shift = mode.maxLM - LM; - } - int c = 0; - do { - for (int b = 0; b < B; ++b) { - MDCT.clt_mdct_forward(mode.mdct, input[c], b * N, output[c], b, mode.window, overlap, shift, B); - } - } while (++c < CC); - if (CC == 2 && C == 1) { - for (i = 0; i < B * N; ++i) { - output[0][i] = Inlines.ADD32(Inlines.HALF32(output[0][i]), Inlines.HALF32(output[1][i])); - } - } - if (upsample != 1) { - c = 0; - do { - int bound = B * N / upsample; - i = 0; - while (i < bound) { - int[] nArray = output[c]; - int n = i++; - nArray[n] = nArray[n] * upsample; - } - Arrays.MemSetWithOffset(output[c], 0, bound, B * N - bound); - } while (++c < C); - } - } - - static void celt_preemphasis(short[] pcmp, int pcmp_ptr, int[] inp, int inp_ptr, int N, int CC, int upsample, int[] coef, BoxedValueInt mem, int clip) { - int i; - int coef0 = coef[0]; - int m = mem.Val; - if (coef[1] == 0 && upsample == 1 && clip == 0) { - for (int i2 = 0; i2 < N; ++i2) { - short x = pcmp[pcmp_ptr + CC * i2]; - inp[inp_ptr + i2] = Inlines.SHL32(x, 12) - m; - m = Inlines.SHR32(Inlines.MULT16_16(coef0, (int)x), 3); - } - mem.Val = m; - return; - } - int Nu = N / upsample; - if (upsample != 1) { - Arrays.MemSetWithOffset(inp, 0, inp_ptr, N); - } - for (i = 0; i < Nu; ++i) { - inp[inp_ptr + i * upsample] = pcmp[pcmp_ptr + CC * i]; - } - for (i = 0; i < N; ++i) { - int x = inp[inp_ptr + i]; - inp[inp_ptr + i] = Inlines.SHL32(x, 12) - m; - m = Inlines.SHR32(Inlines.MULT16_16(coef0, x), 3); - } - mem.Val = m; - } - - static void celt_preemphasis(short[] pcmp, int[] inp, int inp_ptr, int N, int CC, int upsample, int[] coef, BoxedValueInt mem, int clip) { - int i; - int coef0 = coef[0]; - int m = mem.Val; - if (coef[1] == 0 && upsample == 1 && clip == 0) { - for (int i2 = 0; i2 < N; ++i2) { - short x = pcmp[CC * i2]; - inp[inp_ptr + i2] = Inlines.SHL32(x, 12) - m; - m = Inlines.SHR32(Inlines.MULT16_16(coef0, (int)x), 3); - } - mem.Val = m; - return; - } - int Nu = N / upsample; - if (upsample != 1) { - Arrays.MemSetWithOffset(inp, 0, inp_ptr, N); - } - for (i = 0; i < Nu; ++i) { - inp[inp_ptr + i * upsample] = pcmp[CC * i]; - } - for (i = 0; i < N; ++i) { - int x = inp[inp_ptr + i]; - inp[inp_ptr + i] = Inlines.SHL32(x, 12) - m; - m = Inlines.SHR32(Inlines.MULT16_16(coef0, x), 3); - } - mem.Val = m; - } - - static int l1_metric(int[] tmp, int N, int LM, int bias) { - int L1 = 0; - for (int i = 0; i < N; ++i) { - L1 += Inlines.EXTEND32(Inlines.ABS32(tmp[i])); - } - L1 = Inlines.MAC16_32_Q15(L1, LM * bias, L1); - return L1; - } - - static int tf_analysis(CeltMode m, int len, int isTransient, int[] tf_res, int lambda, int[][] X, int N0, int LM, BoxedValueInt tf_sum, int tf_estimate, int tf_chan) { - int curr1; - int curr0; - int cost1; - int cost0; - int i; - int[] selcost = new int[2]; - int tf_select = 0; - int bias = Inlines.MULT16_16_Q14(1311, Inlines.MAX16(-4096, 8192 - tf_estimate)); - int[] metric = new int[len]; - int[] tmp = new int[m.eBands[len] - m.eBands[len - 1] << LM]; - int[] tmp_1 = new int[m.eBands[len] - m.eBands[len - 1] << LM]; - int[] path0 = new int[len]; - int[] path1 = new int[len]; - tf_sum.Val = 0; - for (i = 0; i < len; ++i) { - int L1; - int best_level = 0; - int N = m.eBands[i + 1] - m.eBands[i] << LM; - boolean narrow = m.eBands[i + 1] - m.eBands[i] == 1; - System.arraycopy(X[tf_chan], m.eBands[i] << LM, tmp, 0, N); - int best_L1 = L1 = CeltCommon.l1_metric(tmp, N, isTransient != 0 ? LM : 0, bias); - if (isTransient != 0 && !narrow) { - System.arraycopy(tmp, 0, tmp_1, 0, N); - Bands.haar1ZeroOffset(tmp_1, N >> LM, 1 << LM); - L1 = CeltCommon.l1_metric(tmp_1, N, LM + 1, bias); - if (L1 < best_L1) { - best_L1 = L1; - best_level = -1; - } - } - for (int k = 0; k < LM + (isTransient == 0 && !narrow ? 1 : 0); ++k) { - int B = isTransient != 0 ? LM - k - 1 : k + 1; - Bands.haar1ZeroOffset(tmp, N >> k, 1 << k); - L1 = CeltCommon.l1_metric(tmp, N, B, bias); - if (L1 >= best_L1) continue; - best_L1 = L1; - best_level = k + 1; - } - metric[i] = isTransient != 0 ? 2 * best_level : -2 * best_level; - tf_sum.Val = tf_sum.Val + ((isTransient != 0 ? LM : 0) - metric[i] / 2); - if (!narrow || metric[i] != 0 && metric[i] != -2 * LM) continue; - int n = i; - metric[n] = metric[n] - 1; - } - tf_select = 0; - for (int sel = 0; sel < 2; ++sel) { - cost0 = 0; - cost1 = isTransient != 0 ? 0 : lambda; - for (i = 1; i < len; ++i) { - curr0 = Inlines.IMIN(cost0, cost1 + lambda); - curr1 = Inlines.IMIN(cost0 + lambda, cost1); - cost0 = curr0 + Inlines.abs(metric[i] - 2 * CeltTables.tf_select_table[LM][4 * isTransient + 2 * sel + 0]); - cost1 = curr1 + Inlines.abs(metric[i] - 2 * CeltTables.tf_select_table[LM][4 * isTransient + 2 * sel + 1]); - } - selcost[sel] = cost0 = Inlines.IMIN(cost0, cost1); - } - if (selcost[1] < selcost[0] && isTransient != 0) { - tf_select = 1; - } - cost0 = 0; - cost1 = isTransient != 0 ? 0 : lambda; - for (i = 1; i < len; ++i) { - int from0 = cost0; - int from1 = cost1 + lambda; - if (from0 < from1) { - curr0 = from0; - path0[i] = 0; - } else { - curr0 = from1; - path0[i] = 1; - } - from0 = cost0 + lambda; - from1 = cost1; - if (from0 < from1) { - curr1 = from0; - path1[i] = 0; - } else { - curr1 = from1; - path1[i] = 1; - } - cost0 = curr0 + Inlines.abs(metric[i] - 2 * CeltTables.tf_select_table[LM][4 * isTransient + 2 * tf_select + 0]); - cost1 = curr1 + Inlines.abs(metric[i] - 2 * CeltTables.tf_select_table[LM][4 * isTransient + 2 * tf_select + 1]); - } - tf_res[len - 1] = cost0 < cost1 ? 0 : 1; - for (i = len - 2; i >= 0; --i) { - tf_res[i] = tf_res[i + 1] == 1 ? path1[i + 1] : path0[i + 1]; - } - return tf_select; - } - - static void tf_encode(int start, int end, int isTransient, int[] tf_res, int LM, int tf_select, EntropyCoder enc) { - int i; - int budget = enc.storage * 8; - int tell = enc.tell(); - int logp = isTransient != 0 ? 2 : 4; - int tf_select_rsv = LM > 0 && tell + logp + 1 <= budget ? 1 : 0; - budget -= tf_select_rsv; - int tf_changed = 0; - int curr = 0; - for (i = start; i < end; ++i) { - if (tell + logp <= budget) { - enc.enc_bit_logp(tf_res[i] ^ curr, logp); - tell = enc.tell(); - curr = tf_res[i]; - tf_changed |= curr; - } else { - tf_res[i] = curr; - } - logp = isTransient != 0 ? 4 : 5; - } - if (tf_select_rsv != 0 && CeltTables.tf_select_table[LM][4 * isTransient + 0 + tf_changed] != CeltTables.tf_select_table[LM][4 * isTransient + 2 + tf_changed]) { - enc.enc_bit_logp(tf_select, 1); - } else { - tf_select = 0; - } - for (i = start; i < end; ++i) { - tf_res[i] = CeltTables.tf_select_table[LM][4 * isTransient + 2 * tf_select + tf_res[i]]; - } - } - - static int alloc_trim_analysis(CeltMode m, int[][] X, int[][] bandLogE, int end, int LM, int C, AnalysisInfo analysis, BoxedValueInt stereo_saving, int tf_estimate, int intensity, int surround_trim) { - int i; - int diff = 0; - int trim = 1280; - if (C == 2) { - int partial; - int sum = 0; - for (i = 0; i < 8; ++i) { - partial = Kernels.celt_inner_prod(X[0], m.eBands[i] << LM, X[1], m.eBands[i] << LM, m.eBands[i + 1] - m.eBands[i] << LM); - sum = Inlines.ADD16(sum, (int)Inlines.EXTRACT16(Inlines.SHR32(partial, 18))); - } - sum = Inlines.MULT16_16_Q15(4096, sum); - int minXC = sum = Inlines.MIN16(1024, Inlines.ABS32(sum)); - for (i = 8; i < intensity; ++i) { - partial = Kernels.celt_inner_prod(X[0], m.eBands[i] << LM, X[1], m.eBands[i] << LM, m.eBands[i + 1] - m.eBands[i] << LM); - minXC = Inlines.MIN16(minXC, (int)Inlines.ABS16(Inlines.EXTRACT16(Inlines.SHR32(partial, 18)))); - } - minXC = Inlines.MIN16(1024, Inlines.ABS32(minXC)); - int logXC = Inlines.celt_log2(1049625 - Inlines.MULT16_16(sum, sum)); - int logXC2 = Inlines.MAX16(Inlines.HALF16(logXC), Inlines.celt_log2(1049625 - Inlines.MULT16_16(minXC, minXC))); - logXC = Inlines.PSHR32(logXC - 6144, 2); - logXC2 = Inlines.PSHR32(logXC2 - 6144, 2); - trim += Inlines.MAX16(-1024, Inlines.MULT16_16_Q15(24576, logXC)); - stereo_saving.Val = Inlines.MIN16(stereo_saving.Val + 64, 0 - Inlines.HALF16(logXC2)); - } - int c = 0; - do { - for (i = 0; i < end - 1; ++i) { - diff += bandLogE[c][i] * (2 + 2 * i - end); - } - } while (++c < C); - trim -= Inlines.MAX16((int)Inlines.NEG16((short)512), Inlines.MIN16(512, Inlines.SHR16((diff /= C * (end - 1)) + 1024, 2) / 6)); - trim -= Inlines.SHR16(surround_trim, 2); - trim -= 2 * Inlines.SHR16(tf_estimate, 6); - if (analysis.enabled && analysis.valid != 0) { - trim -= Inlines.MAX16(-512, Inlines.MIN16(512, (int)(512.0f * (analysis.tonality_slope + 0.05f)))); - } - int trim_index = Inlines.PSHR32(trim, 8); - trim_index = Inlines.IMAX(0, Inlines.IMIN(10, trim_index)); - return trim_index; - } - - static int stereo_analysis(CeltMode m, int[][] X, int LM) { - int sumLR = 1; - int sumMS = 1; - for (int i = 0; i < 13; ++i) { - for (int j = m.eBands[i] << LM; j < m.eBands[i + 1] << LM; ++j) { - int L = Inlines.EXTEND32(X[0][j]); - int R = Inlines.EXTEND32(X[1][j]); - int M = Inlines.ADD32(L, R); - int S = Inlines.SUB32(L, R); - sumLR = Inlines.ADD32(sumLR, Inlines.ADD32(Inlines.ABS32(L), Inlines.ABS32(R))); - sumMS = Inlines.ADD32(sumMS, Inlines.ADD32(Inlines.ABS32(M), Inlines.ABS32(S))); - } - } - sumMS = Inlines.MULT16_32_Q15((short)23170, sumMS); - int thetas = 13; - if (LM <= 1) { - thetas -= 8; - } - return Inlines.MULT16_32_Q15((m.eBands[13] << LM + 1) + thetas, sumMS) > Inlines.MULT16_32_Q15(m.eBands[13] << LM + 1, sumLR) ? 1 : 0; - } - - static int median_of_5(int[] x, int x_ptr) { - int t4; - int t3; - int t1; - int t0; - int t2 = x[x_ptr + 2]; - if (x[x_ptr] > x[x_ptr + 1]) { - t0 = x[x_ptr + 1]; - t1 = x[x_ptr]; - } else { - t0 = x[x_ptr]; - t1 = x[x_ptr + 1]; - } - if (x[x_ptr + 3] > x[x_ptr + 4]) { - t3 = x[x_ptr + 4]; - t4 = x[x_ptr + 3]; - } else { - t3 = x[x_ptr + 3]; - t4 = x[x_ptr + 4]; - } - if (t0 > t3) { - int tmp = t3; - t3 = t0; - t0 = tmp; - tmp = t4; - t4 = t1; - t1 = tmp; - } - if (t2 > t1) { - if (t1 < t3) { - return Inlines.MIN16(t2, t3); - } - return Inlines.MIN16(t4, t1); - } - if (t2 < t3) { - return Inlines.MIN16(t1, t3); - } - return Inlines.MIN16(t2, t4); - } - - static int median_of_3(int[] x, int x_ptr) { - int t1; - int t0; - if (x[x_ptr] > x[x_ptr + 1]) { - t0 = x[x_ptr + 1]; - t1 = x[x_ptr]; - } else { - t0 = x[x_ptr]; - t1 = x[x_ptr + 1]; - } - int t2 = x[x_ptr + 2]; - if (t1 < t2) { - return t1; - } - if (t0 < t2) { - return t2; - } - return t0; - } - - static int dynalloc_analysis(int[][] bandLogE, int[][] bandLogE2, int nbEBands, int start, int end, int C, int[] offsets, int lsb_depth, short[] logN, int isTransient, int vbr, int constrained_vbr, short[] eBands, int LM, int effectiveBytes, BoxedValueInt tot_boost_, int lfe, int[] surround_dynalloc) { - int i; - int tot_boost = 0; - int[][] follower = Arrays.InitTwoDimensionalArrayInt(2, nbEBands); - int[] noise_floor = new int[C * nbEBands]; - Arrays.MemSet(offsets, 0, nbEBands); - int maxDepth = -32666; - for (i = 0; i < end; ++i) { - noise_floor[i] = Inlines.MULT16_16((short)64, logN[i]) + 512 + Inlines.SHL16(9 - lsb_depth, 10) - Inlines.SHL16(CeltTables.eMeans[i], 6) + Inlines.MULT16_16(6, (i + 5) * (i + 5)); - } - int c = 0; - do { - for (i = 0; i < end; ++i) { - maxDepth = Inlines.MAX16(maxDepth, bandLogE[c][i] - noise_floor[i]); - } - } while (++c < C); - if (effectiveBytes > 50 && LM >= 1 && lfe == 0) { - int last = 0; - c = 0; - do { - int[] f = follower[c]; - f[0] = bandLogE2[c][0]; - for (i = 1; i < end; ++i) { - if (bandLogE2[c][i] > bandLogE2[c][i - 1] + 512) { - last = i; - } - f[i] = Inlines.MIN16(f[i - 1] + 1536, bandLogE2[c][i]); - } - for (i = last - 1; i >= 0; --i) { - f[i] = Inlines.MIN16(f[i], Inlines.MIN16(f[i + 1] + 2048, bandLogE2[c][i])); - } - int offset = 1024; - for (i = 2; i < end - 2; ++i) { - f[i] = Inlines.MAX16(f[i], CeltCommon.median_of_5(bandLogE2[c], i - 2) - offset); - } - int tmp = CeltCommon.median_of_3(bandLogE2[c], 0) - offset; - f[0] = Inlines.MAX16(f[0], tmp); - f[1] = Inlines.MAX16(f[1], tmp); - tmp = CeltCommon.median_of_3(bandLogE2[c], end - 3) - offset; - f[end - 2] = Inlines.MAX16(f[end - 2], tmp); - f[end - 1] = Inlines.MAX16(f[end - 1], tmp); - for (i = 0; i < end; ++i) { - f[i] = Inlines.MAX16(f[i], noise_floor[i]); - } - } while (++c < C); - if (C == 2) { - for (i = start; i < end; ++i) { - follower[1][i] = Inlines.MAX16(follower[1][i], follower[0][i] - 4096); - follower[0][i] = Inlines.MAX16(follower[0][i], follower[1][i] - 4096); - follower[0][i] = Inlines.HALF16(Inlines.MAX16(0, bandLogE[0][i] - follower[0][i]) + Inlines.MAX16(0, bandLogE[1][i] - follower[1][i])); - } - } else { - for (i = start; i < end; ++i) { - follower[0][i] = Inlines.MAX16(0, bandLogE[0][i] - follower[0][i]); - } - } - for (i = start; i < end; ++i) { - follower[0][i] = Inlines.MAX16(follower[0][i], surround_dynalloc[i]); - } - if ((vbr == 0 || constrained_vbr != 0) && isTransient == 0) { - for (i = start; i < end; ++i) { - follower[0][i] = Inlines.HALF16(follower[0][i]); - } - } - for (i = start; i < end; ++i) { - int boost_bits; - int boost; - if (i < 8) { - int[] nArray = follower[0]; - int n = i; - nArray[n] = nArray[n] * 2; - } - if (i >= 12) { - follower[0][i] = Inlines.HALF16(follower[0][i]); - } - follower[0][i] = Inlines.MIN16(follower[0][i], 4096); - int width = C * (eBands[i + 1] - eBands[i]) << LM; - if (width < 6) { - boost = Inlines.SHR32(follower[0][i], 10); - boost_bits = boost * width << 3; - } else if (width > 48) { - boost = Inlines.SHR32(follower[0][i] * 8, 10); - boost_bits = (boost * width << 3) / 8; - } else { - boost = Inlines.SHR32(follower[0][i] * width / 6, 10); - boost_bits = boost * 6 << 3; - } - if ((vbr == 0 || constrained_vbr != 0 && isTransient == 0) && tot_boost + boost_bits >> 3 >> 3 > effectiveBytes / 4) { - int cap = effectiveBytes / 4 << 3 << 3; - offsets[i] = cap - tot_boost; - tot_boost = cap; - break; - } - offsets[i] = boost; - tot_boost += boost_bits; - } - } - tot_boost_.Val = tot_boost; - return maxDepth; - } - - static void deemphasis(int[][] input, int[] input_ptrs, short[] pcm, int pcm_ptr, int N, int C, int downsample, int[] coef, int[] mem, int accum) { - boolean apply_downsampling = false; - int[] scratch = new int[N]; - int coef0 = coef[0]; - int Nd = N / downsample; - int c = 0; - do { - int tmp; - int j; - int m = mem[c]; - int[] x = input[c]; - int x_ptr = input_ptrs[c]; - int y = pcm_ptr + c; - if (downsample > 1) { - for (j = 0; j < N; ++j) { - tmp = x[x_ptr + j] + m + 0; - m = Inlines.MULT16_32_Q15(coef0, tmp); - scratch[j] = tmp; - } - apply_downsampling = true; - } else if (accum != 0) { - for (j = 0; j < N; ++j) { - tmp = x[x_ptr + j] + m + 0; - m = Inlines.MULT16_32_Q15(coef0, tmp); - pcm[y + j * C] = Inlines.SAT16(Inlines.ADD32(pcm[y + j * C], Inlines.SIG2WORD16(tmp))); - } - } else { - for (j = 0; j < N; ++j) { - tmp = x[x_ptr + j] + m + 0; - if (x[x_ptr + j] > 0 && m > 0 && tmp < 0) { - tmp = Integer.MAX_VALUE; - m = Integer.MAX_VALUE; - } else { - m = Inlines.MULT16_32_Q15(coef0, tmp); - } - pcm[y + j * C] = Inlines.SIG2WORD16(tmp); - } - } - mem[c] = m; - if (!apply_downsampling) continue; - for (j = 0; j < Nd; ++j) { - pcm[y + j * C] = Inlines.SIG2WORD16(scratch[j * downsample]); - } - } while (++c < C); - } - - static void celt_synthesis(CeltMode mode, int[][] X, int[][] out_syn, int[] out_syn_ptrs, int[] oldBandE, int start, int effEnd, int C, int CC, int isTransient, int LM, int downsample, int silence) { - int shift; - int NB; - int B; - int overlap = mode.overlap; - int nbEBands = mode.nbEBands; - int N = mode.shortMdctSize << LM; - int[] freq = new int[N]; - int M = 1 << LM; - if (isTransient != 0) { - B = M; - NB = mode.shortMdctSize; - shift = mode.maxLM; - } else { - B = 1; - NB = mode.shortMdctSize << LM; - shift = mode.maxLM - LM; - } - if (CC == 2 && C == 1) { - int b; - Bands.denormalise_bands(mode, X[0], freq, 0, oldBandE, 0, start, effEnd, M, downsample, silence); - int freq2 = out_syn_ptrs[1] + overlap / 2; - System.arraycopy(freq, 0, out_syn[1], freq2, N); - for (b = 0; b < B; ++b) { - MDCT.clt_mdct_backward(mode.mdct, out_syn[1], freq2 + b, out_syn[0], out_syn_ptrs[0] + NB * b, mode.window, overlap, shift, B); - } - for (b = 0; b < B; ++b) { - MDCT.clt_mdct_backward(mode.mdct, freq, b, out_syn[1], out_syn_ptrs[1] + NB * b, mode.window, overlap, shift, B); - } - } else if (CC == 1 && C == 2) { - int freq2 = out_syn_ptrs[0] + overlap / 2; - Bands.denormalise_bands(mode, X[0], freq, 0, oldBandE, 0, start, effEnd, M, downsample, silence); - Bands.denormalise_bands(mode, X[1], out_syn[0], freq2, oldBandE, nbEBands, start, effEnd, M, downsample, silence); - for (int i = 0; i < N; ++i) { - freq[i] = Inlines.HALF32(Inlines.ADD32(freq[i], out_syn[0][freq2 + i])); - } - for (int b = 0; b < B; ++b) { - MDCT.clt_mdct_backward(mode.mdct, freq, b, out_syn[0], out_syn_ptrs[0] + NB * b, mode.window, overlap, shift, B); - } - } else { - int c = 0; - do { - Bands.denormalise_bands(mode, X[c], freq, 0, oldBandE, c * nbEBands, start, effEnd, M, downsample, silence); - for (int b = 0; b < B; ++b) { - MDCT.clt_mdct_backward(mode.mdct, freq, b, out_syn[c], out_syn_ptrs[c] + NB * b, mode.window, overlap, shift, B); - } - } while (++c < CC); - } - } - - static void tf_decode(int start, int end, int isTransient, int[] tf_res, int LM, EntropyCoder dec) { - int i; - int budget = dec.storage * 8; - int tell = dec.tell(); - int logp = isTransient != 0 ? 2 : 4; - int tf_select_rsv = LM > 0 && tell + logp + 1 <= budget ? 1 : 0; - budget -= tf_select_rsv; - int curr = 0; - int tf_changed = 0; - for (i = start; i < end; ++i) { - if (tell + logp <= budget) { - tell = dec.tell(); - tf_changed |= (curr ^= dec.dec_bit_logp(logp)); - } - tf_res[i] = curr; - logp = isTransient != 0 ? 4 : 5; - } - int tf_select = 0; - if (tf_select_rsv != 0 && CeltTables.tf_select_table[LM][4 * isTransient + 0 + tf_changed] != CeltTables.tf_select_table[LM][4 * isTransient + 2 + tf_changed]) { - tf_select = dec.dec_bit_logp(1L); - } - for (i = start; i < end; ++i) { - tf_res[i] = CeltTables.tf_select_table[LM][4 * isTransient + 2 * tf_select + tf_res[i]]; - } - } - - static int celt_plc_pitch_search(int[][] decode_mem, int C) { - BoxedValueInt pitch_index = new BoxedValueInt(0); - int[] lp_pitch_buf = new int[1024]; - Pitch.pitch_downsample(decode_mem, lp_pitch_buf, 2048, C); - Pitch.pitch_search(lp_pitch_buf, 360, lp_pitch_buf, 1328, 620, pitch_index); - pitch_index.Val = 720 - pitch_index.Val; - return pitch_index.Val; - } - - static int resampling_factor(int rate) { - int ret; - switch (rate) { - case 48000: { - ret = 1; - break; - } - case 24000: { - ret = 2; - break; - } - case 16000: { - ret = 3; - break; - } - case 12000: { - ret = 4; - break; - } - case 8000: { - ret = 6; - break; - } - default: { - Inlines.OpusAssert(false); - ret = 0; - } - } - return ret; - } - - static void comb_filter_const(int[] y, int y_ptr, int[] x, int x_ptr, int T, int N, int g10, int g11, int g12) { - int xpt = x_ptr - T; - int x4 = x[xpt - 2]; - int x3 = x[xpt - 1]; - int x2 = x[xpt]; - int x1 = x[xpt + 1]; - for (int i = 0; i < N; ++i) { - int x0 = x[xpt + i + 2]; - y[y_ptr + i] = x[x_ptr + i] + Inlines.MULT16_32_Q15(g10, x2) + Inlines.MULT16_32_Q15(g11, Inlines.ADD32(x1, x3)) + Inlines.MULT16_32_Q15(g12, Inlines.ADD32(x0, x4)); - x4 = x3; - x3 = x2; - x2 = x1; - x1 = x0; - } - } - - static void comb_filter(int[] y, int y_ptr, int[] x, int x_ptr, int T0, int T1, int N, int g0, int g1, int tapset0, int tapset1, int[] window, int overlap) { - int i; - if (g0 == 0 && g1 == 0) { - if (x_ptr != y_ptr) { - // empty if block - } - return; - } - int g00 = Inlines.MULT16_16_P15(g0, (int)gains[tapset0][0]); - int g01 = Inlines.MULT16_16_P15(g0, (int)gains[tapset0][1]); - int g02 = Inlines.MULT16_16_P15(g0, (int)gains[tapset0][2]); - int g10 = Inlines.MULT16_16_P15(g1, (int)gains[tapset1][0]); - int g11 = Inlines.MULT16_16_P15(g1, (int)gains[tapset1][1]); - int g12 = Inlines.MULT16_16_P15(g1, (int)gains[tapset1][2]); - int x1 = x[x_ptr - T1 + 1]; - int x2 = x[x_ptr - T1]; - int x3 = x[x_ptr - T1 - 1]; - int x4 = x[x_ptr - T1 - 2]; - if (g0 == g1 && T0 == T1 && tapset0 == tapset1) { - overlap = 0; - } - for (i = 0; i < overlap; ++i) { - int x0 = x[x_ptr + i - T1 + 2]; - int f = Inlines.MULT16_16_Q15(window[i], window[i]); - y[y_ptr + i] = x[x_ptr + i] + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((int)((short)(Short.MAX_VALUE - f)), g00), x[x_ptr + i - T0]) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((int)((short)(Short.MAX_VALUE - f)), g01), Inlines.ADD32(x[x_ptr + i - T0 + 1], x[x_ptr + i - T0 - 1])) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((int)((short)(Short.MAX_VALUE - f)), g02), Inlines.ADD32(x[x_ptr + i - T0 + 2], x[x_ptr + i - T0 - 2])) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(f, g10), x2) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(f, g11), Inlines.ADD32(x1, x3)) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(f, g12), Inlines.ADD32(x0, x4)); - x4 = x3; - x3 = x2; - x2 = x1; - x1 = x0; - } - if (g1 == 0) { - if (x_ptr != y_ptr) { - // empty if block - } - return; - } - CeltCommon.comb_filter_const(y, y_ptr + i, x, x_ptr + i, T1, N - i, g10, g11, g12); - } - - static void init_caps(CeltMode m, int[] cap, int LM, int C) { - for (int i = 0; i < m.nbEBands; ++i) { - int N = m.eBands[i + 1] - m.eBands[i] << LM; - cap[i] = (m.cache.caps[m.nbEBands * (2 * LM + C - 1) + i] + 64) * C * N >> 2; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltConstants.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CeltConstants.java deleted file mode 100644 index 49a9630..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltConstants.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class CeltConstants { - public static final int Q15ONE = Short.MAX_VALUE; - public static final float CELT_SIG_SCALE = 32768.0f; - public static final int SIG_SHIFT = 12; - public static final int NORM_SCALING = 16384; - public static final int DB_SHIFT = 10; - public static final int EPSILON = 1; - public static final int VERY_SMALL = 0; - public static final short VERY_LARGE16 = Short.MAX_VALUE; - public static final short Q15_ONE = Short.MAX_VALUE; - public static final int COMBFILTER_MAXPERIOD = 1024; - public static final int COMBFILTER_MINPERIOD = 15; - public static final int DECODE_BUFFER_SIZE = 2048; - public static final int BITALLOC_SIZE = 11; - public static final int MAX_PERIOD = 1024; - public static final int TOTAL_MODES = 1; - public static final int MAX_PSEUDO = 40; - public static final int LOG_MAX_PSEUDO = 6; - public static final int CELT_MAX_PULSES = 128; - public static final int MAX_FINE_BITS = 8; - public static final int FINE_OFFSET = 21; - public static final int QTHETA_OFFSET = 4; - public static final int QTHETA_OFFSET_TWOPHASE = 16; - public static final int PLC_PITCH_LAG_MAX = 720; - public static final int PLC_PITCH_LAG_MIN = 100; - public static final int LPC_ORDER = 24; - - CeltConstants() { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltDecoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CeltDecoder.java deleted file mode 100644 index 3ef5085..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltDecoder.java +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Autocorrelation; -import de.maxhenkel.voicechat.concentus.Bands; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltCommon; -import de.maxhenkel.voicechat.concentus.CeltLPC; -import de.maxhenkel.voicechat.concentus.CeltMode; -import de.maxhenkel.voicechat.concentus.CeltTables; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Kernels; -import de.maxhenkel.voicechat.concentus.OpusError; -import de.maxhenkel.voicechat.concentus.QuantizeBands; -import de.maxhenkel.voicechat.concentus.Rate; -import de.maxhenkel.voicechat.concentus.VQ; - -class CeltDecoder { - CeltMode mode = null; - int overlap = 0; - int channels = 0; - int stream_channels = 0; - int downsample = 0; - int start = 0; - int end = 0; - int signalling = 0; - int rng = 0; - int error = 0; - int last_pitch_index = 0; - int loss_count = 0; - int postfilter_period = 0; - int postfilter_period_old = 0; - int postfilter_gain = 0; - int postfilter_gain_old = 0; - int postfilter_tapset = 0; - int postfilter_tapset_old = 0; - final int[] preemph_memD = new int[2]; - int[][] decode_mem = null; - int[][] lpc = null; - int[] oldEBands = null; - int[] oldLogE = null; - int[] oldLogE2 = null; - int[] backgroundLogE = null; - - CeltDecoder() { - } - - private void Reset() { - this.mode = null; - this.overlap = 0; - this.channels = 0; - this.stream_channels = 0; - this.downsample = 0; - this.start = 0; - this.end = 0; - this.signalling = 0; - this.PartialReset(); - } - - private void PartialReset() { - this.rng = 0; - this.error = 0; - this.last_pitch_index = 0; - this.loss_count = 0; - this.postfilter_period = 0; - this.postfilter_period_old = 0; - this.postfilter_gain = 0; - this.postfilter_gain_old = 0; - this.postfilter_tapset = 0; - this.postfilter_tapset_old = 0; - Arrays.MemSet(this.preemph_memD, 0, 2); - this.decode_mem = null; - this.lpc = null; - this.oldEBands = null; - this.oldLogE = null; - this.oldLogE2 = null; - this.backgroundLogE = null; - } - - void ResetState() { - this.PartialReset(); - this.decode_mem = new int[this.channels][]; - this.lpc = new int[this.channels][]; - for (int c = 0; c < this.channels; ++c) { - this.decode_mem[c] = new int[2048 + this.mode.overlap]; - this.lpc[c] = new int[24]; - } - this.oldEBands = new int[2 * this.mode.nbEBands]; - this.oldLogE = new int[2 * this.mode.nbEBands]; - this.oldLogE2 = new int[2 * this.mode.nbEBands]; - this.backgroundLogE = new int[2 * this.mode.nbEBands]; - for (int i = 0; i < 2 * this.mode.nbEBands; ++i) { - this.oldLogE2[i] = -28672; - this.oldLogE[i] = -28672; - } - } - - int celt_decoder_init(int sampling_rate, int channels) { - int ret = this.opus_custom_decoder_init(CeltMode.mode48000_960_120, channels); - if (ret != OpusError.OPUS_OK) { - return ret; - } - this.downsample = CeltCommon.resampling_factor(sampling_rate); - if (this.downsample == 0) { - return OpusError.OPUS_BAD_ARG; - } - return OpusError.OPUS_OK; - } - - private int opus_custom_decoder_init(CeltMode mode, int channels) { - if (channels < 0 || channels > 2) { - return OpusError.OPUS_BAD_ARG; - } - if (this == null) { - return OpusError.OPUS_ALLOC_FAIL; - } - this.Reset(); - this.mode = mode; - this.overlap = mode.overlap; - this.stream_channels = this.channels = channels; - this.downsample = 1; - this.start = 0; - this.end = this.mode.effEBands; - this.signalling = 1; - this.loss_count = 0; - this.ResetState(); - return OpusError.OPUS_OK; - } - - void celt_decode_lost(int N, int LM) { - boolean noise_based; - int C = this.channels; - int[][] out_syn = new int[2][]; - int[] out_syn_ptrs = new int[2]; - CeltMode mode = this.mode; - int nbEBands = mode.nbEBands; - int overlap = mode.overlap; - short[] eBands = mode.eBands; - int c = 0; - do { - out_syn[c] = this.decode_mem[c]; - out_syn_ptrs[c] = 2048 - N; - } while (++c < C); - boolean bl = noise_based = this.loss_count >= 5 || this.start != 0; - if (noise_based) { - int i; - int end = this.end; - int effEnd = Inlines.IMAX(this.start, Inlines.IMIN(end, mode.effEBands)); - int[][] X = Arrays.InitTwoDimensionalArrayInt(C, N); - int decay = this.loss_count == 0 ? 1536 : 512; - c = 0; - do { - for (i = this.start; i < end; ++i) { - this.oldEBands[c * nbEBands + i] = Inlines.MAX16(this.backgroundLogE[c * nbEBands + i], this.oldEBands[c * nbEBands + i] - decay); - } - } while (++c < C); - int seed = this.rng; - for (c = 0; c < C; ++c) { - for (i = this.start; i < effEnd; ++i) { - int boffs = eBands[i] << LM; - int blen = eBands[i + 1] - eBands[i] << LM; - for (int j = 0; j < blen; ++j) { - seed = Bands.celt_lcg_rand(seed); - X[c][boffs + j] = seed >> 20; - } - VQ.renormalise_vector(X[c], 0, blen, Short.MAX_VALUE); - } - } - this.rng = seed; - c = 0; - do { - Arrays.MemMove(this.decode_mem[c], N, 0, 2048 - N + (overlap >> 1)); - } while (++c < C); - CeltCommon.celt_synthesis(mode, X, out_syn, out_syn_ptrs, this.oldEBands, this.start, effEnd, C, C, 0, LM, this.downsample, 0); - } else { - int pitch_index; - int fade = Short.MAX_VALUE; - if (this.loss_count == 0) { - this.last_pitch_index = pitch_index = CeltCommon.celt_plc_pitch_search(this.decode_mem, C); - } else { - pitch_index = this.last_pitch_index; - fade = 26214; - } - int[] etmp = new int[overlap]; - int[] exc = new int[1024]; - int[] window = mode.window; - c = 0; - do { - int i; - int S1 = 0; - int[] buf = this.decode_mem[c]; - for (i = 0; i < 1024; ++i) { - exc[i] = Inlines.ROUND16(buf[1024 + i], 12); - } - if (this.loss_count == 0) { - int[] ac = new int[25]; - Autocorrelation._celt_autocorr(exc, ac, window, overlap, 24, 1024); - ac[0] = ac[0] + Inlines.SHR32(ac[0], 13); - for (i = 1; i <= 24; ++i) { - int n = i; - ac[n] = ac[n] - Inlines.MULT16_32_Q15(2 * i * i, ac[i]); - } - CeltLPC.celt_lpc(this.lpc[c], ac, 24); - } - int exc_length = Inlines.IMIN(2 * pitch_index, 1024); - int[] lpc_mem = new int[24]; - for (i = 0; i < 24; ++i) { - lpc_mem[i] = Inlines.ROUND16(buf[2048 - exc_length - 1 - i], 12); - } - Kernels.celt_fir(exc, 1024 - exc_length, this.lpc[c], 0, exc, 1024 - exc_length, exc_length, 24, lpc_mem); - int E1 = 1; - int E2 = 1; - int shift = Inlines.IMAX(0, 2 * Inlines.celt_zlog2(Inlines.celt_maxabs16(exc, 1024 - exc_length, exc_length)) - 20); - int decay_length = exc_length >> 1; - for (i = 0; i < decay_length; ++i) { - int e = exc[1024 - decay_length + i]; - E1 += Inlines.SHR32(Inlines.MULT16_16(e, e), shift); - e = exc[1024 - 2 * decay_length + i]; - E2 += Inlines.SHR32(Inlines.MULT16_16(e, e), shift); - } - E1 = Inlines.MIN32(E1, E2); - int decay = Inlines.celt_sqrt(Inlines.frac_div32(Inlines.SHR32(E1, 1), E2)); - Arrays.MemMove(buf, N, 0, 2048 - N); - int extrapolation_offset = 1024 - pitch_index; - int extrapolation_len = N + overlap; - int attenuation = Inlines.MULT16_16_Q15(fade, decay); - int j = 0; - i = 0; - while (i < extrapolation_len) { - if (j >= pitch_index) { - j -= pitch_index; - attenuation = Inlines.MULT16_16_Q15(attenuation, decay); - } - buf[2048 - N + i] = Inlines.SHL32(Inlines.MULT16_16_Q15(attenuation, exc[extrapolation_offset + j]), 12); - int tmp = Inlines.ROUND16(buf[1024 - N + extrapolation_offset + j], 12); - S1 += Inlines.SHR32(Inlines.MULT16_16(tmp, tmp), 8); - ++i; - ++j; - } - lpc_mem = new int[24]; - for (i = 0; i < 24; ++i) { - lpc_mem[i] = Inlines.ROUND16(buf[2048 - N - 1 - i], 12); - } - CeltLPC.celt_iir(buf, 2048 - N, this.lpc[c], buf, 2048 - N, extrapolation_len, 24, lpc_mem); - int S2 = 0; - for (i = 0; i < extrapolation_len; ++i) { - int tmp = Inlines.ROUND16(buf[2048 - N + i], 12); - S2 += Inlines.SHR32(Inlines.MULT16_16(tmp, tmp), 8); - } - if (S1 <= Inlines.SHR32(S2, 2)) { - for (i = 0; i < extrapolation_len; ++i) { - buf[2048 - N + i] = 0; - } - } else if (S1 < S2) { - int ratio = Inlines.celt_sqrt(Inlines.frac_div32(Inlines.SHR32(S1, 1) + 1, S2 + 1)); - for (i = 0; i < overlap; ++i) { - int tmp_g = Short.MAX_VALUE - Inlines.MULT16_16_Q15(window[i], Short.MAX_VALUE - ratio); - buf[2048 - N + i] = Inlines.MULT16_32_Q15(tmp_g, buf[2048 - N + i]); - } - for (i = overlap; i < extrapolation_len; ++i) { - buf[2048 - N + i] = Inlines.MULT16_32_Q15(ratio, buf[2048 - N + i]); - } - } - CeltCommon.comb_filter(etmp, 0, buf, 2048, this.postfilter_period, this.postfilter_period, overlap, -this.postfilter_gain, -this.postfilter_gain, this.postfilter_tapset, this.postfilter_tapset, null, 0); - for (i = 0; i < overlap / 2; ++i) { - buf[2048 + i] = Inlines.MULT16_32_Q15(window[i], etmp[overlap - 1 - i]) + Inlines.MULT16_32_Q15(window[overlap - i - 1], etmp[i]); - } - } while (++c < C); - } - ++this.loss_count; - } - - int celt_decode_with_ec(byte[] data, int data_ptr, int len, short[] pcm, int pcm_ptr, int frame_size, EntropyCoder dec, int accum) { - int isTransient; - int i; - int LM; - int[][] out_syn = new int[2][]; - int[] out_syn_ptrs = new int[2]; - int CC = this.channels; - int intensity = 0; - int dual_stereo = 0; - int anti_collapse_on = 0; - int C = this.stream_channels; - CeltMode mode = this.mode; - int nbEBands = mode.nbEBands; - int overlap = mode.overlap; - short[] eBands = mode.eBands; - int start = this.start; - int end = this.end; - frame_size *= this.downsample; - int[] oldBandE = this.oldEBands; - int[] oldLogE = this.oldLogE; - int[] oldLogE2 = this.oldLogE2; - int[] backgroundLogE = this.backgroundLogE; - for (LM = 0; LM <= mode.maxLM && mode.shortMdctSize << LM != frame_size; ++LM) { - } - if (LM > mode.maxLM) { - return OpusError.OPUS_BAD_ARG; - } - int M = 1 << LM; - if (len < 0 || len > 1275 || pcm == null) { - return OpusError.OPUS_BAD_ARG; - } - int N = M * mode.shortMdctSize; - int c = 0; - do { - out_syn[c] = this.decode_mem[c]; - out_syn_ptrs[c] = 2048 - N; - } while (++c < CC); - int effEnd = end; - if (effEnd > mode.effEBands) { - effEnd = mode.effEBands; - } - if (data == null || len <= 1) { - this.celt_decode_lost(N, LM); - CeltCommon.deemphasis(out_syn, out_syn_ptrs, pcm, pcm_ptr, N, CC, this.downsample, mode.preemph, this.preemph_memD, accum); - return frame_size / this.downsample; - } - if (dec == null) { - dec = new EntropyCoder(); - dec.dec_init(data, data_ptr, len); - } - if (C == 1) { - for (i = 0; i < nbEBands; ++i) { - oldBandE[i] = Inlines.MAX16(oldBandE[i], oldBandE[nbEBands + i]); - } - } - int total_bits = len * 8; - int tell = dec.tell(); - int silence = tell >= total_bits ? 1 : (tell == 1 ? dec.dec_bit_logp(15L) : 0); - if (silence != 0) { - tell = len * 8; - dec.nbits_total += tell - dec.tell(); - } - int postfilter_gain = 0; - int postfilter_pitch = 0; - int postfilter_tapset = 0; - if (start == 0 && tell + 16 <= total_bits) { - if (dec.dec_bit_logp(1L) != 0) { - int octave = (int)dec.dec_uint(6L); - postfilter_pitch = (16 << octave) + dec.dec_bits(4 + octave) - 1; - int qg = dec.dec_bits(3); - if (dec.tell() + 2 <= total_bits) { - postfilter_tapset = dec.dec_icdf(CeltTables.tapset_icdf, 2); - } - postfilter_gain = 3072 * (qg + 1); - } - tell = dec.tell(); - } - if (LM > 0 && tell + 3 <= total_bits) { - isTransient = dec.dec_bit_logp(3L); - tell = dec.tell(); - } else { - isTransient = 0; - } - int shortBlocks = isTransient != 0 ? M : 0; - int intra_ener = tell + 3 <= total_bits ? dec.dec_bit_logp(3L) : 0; - QuantizeBands.unquant_coarse_energy(mode, start, end, oldBandE, intra_ener, dec, C, LM); - int[] tf_res = new int[nbEBands]; - CeltCommon.tf_decode(start, end, isTransient, tf_res, LM, dec); - tell = dec.tell(); - int spread_decision = 2; - if (tell + 4 <= total_bits) { - spread_decision = dec.dec_icdf(CeltTables.spread_icdf, 5); - } - int[] cap = new int[nbEBands]; - CeltCommon.init_caps(mode, cap, LM, C); - int[] offsets = new int[nbEBands]; - int dynalloc_logp = 6; - total_bits <<= 3; - tell = dec.tell_frac(); - for (i = start; i < end; ++i) { - int boost; - int width = C * (eBands[i + 1] - eBands[i]) << LM; - int quanta = Inlines.IMIN(width << 3, Inlines.IMAX(48, width)); - int dynalloc_loop_logp = dynalloc_logp; - for (boost = 0; tell + (dynalloc_loop_logp << 3) < total_bits && boost < cap[i]; boost += quanta, total_bits -= quanta) { - int flag = dec.dec_bit_logp(dynalloc_loop_logp); - tell = dec.tell_frac(); - if (flag == 0) break; - dynalloc_loop_logp = 1; - } - offsets[i] = boost; - if (boost <= 0) continue; - dynalloc_logp = Inlines.IMAX(2, dynalloc_logp - 1); - } - int[] fine_quant = new int[nbEBands]; - int alloc_trim = tell + 48 <= total_bits ? dec.dec_icdf(CeltTables.trim_icdf, 7) : 5; - int bits = (len * 8 << 3) - dec.tell_frac() - 1; - int anti_collapse_rsv = isTransient != 0 && LM >= 2 && bits >= LM + 2 << 3 ? 8 : 0; - bits -= anti_collapse_rsv; - int[] pulses = new int[nbEBands]; - int[] fine_priority = new int[nbEBands]; - BoxedValueInt boxed_intensity = new BoxedValueInt(intensity); - BoxedValueInt boxed_dual_stereo = new BoxedValueInt(dual_stereo); - BoxedValueInt boxed_balance = new BoxedValueInt(0); - int codedBands = Rate.compute_allocation(mode, start, end, offsets, cap, alloc_trim, boxed_intensity, boxed_dual_stereo, bits, boxed_balance, pulses, fine_quant, fine_priority, C, LM, dec, 0, 0, 0); - intensity = boxed_intensity.Val; - dual_stereo = boxed_dual_stereo.Val; - int balance = boxed_balance.Val; - QuantizeBands.unquant_fine_energy(mode, start, end, oldBandE, fine_quant, dec, C); - c = 0; - do { - Arrays.MemMove(this.decode_mem[c], N, 0, 2048 - N + overlap / 2); - } while (++c < CC); - short[] collapse_masks = new short[C * nbEBands]; - int[][] X = Arrays.InitTwoDimensionalArrayInt(C, N); - BoxedValueInt boxed_rng = new BoxedValueInt(this.rng); - Bands.quant_all_bands(0, mode, start, end, X[0], C == 2 ? X[1] : null, collapse_masks, null, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res, len * 64 - anti_collapse_rsv, balance, dec, LM, codedBands, boxed_rng); - this.rng = boxed_rng.Val; - if (anti_collapse_rsv > 0) { - anti_collapse_on = dec.dec_bits(1); - } - QuantizeBands.unquant_energy_finalise(mode, start, end, oldBandE, fine_quant, fine_priority, len * 8 - dec.tell(), dec, C); - if (anti_collapse_on != 0) { - Bands.anti_collapse(mode, X, collapse_masks, LM, C, N, start, end, oldBandE, oldLogE, oldLogE2, pulses, this.rng); - } - if (silence != 0) { - for (i = 0; i < C * nbEBands; ++i) { - oldBandE[i] = -28672; - } - } - CeltCommon.celt_synthesis(mode, X, out_syn, out_syn_ptrs, oldBandE, start, effEnd, C, CC, isTransient, LM, this.downsample, silence); - c = 0; - do { - this.postfilter_period = Inlines.IMAX(this.postfilter_period, 15); - this.postfilter_period_old = Inlines.IMAX(this.postfilter_period_old, 15); - CeltCommon.comb_filter(out_syn[c], out_syn_ptrs[c], out_syn[c], out_syn_ptrs[c], this.postfilter_period_old, this.postfilter_period, mode.shortMdctSize, this.postfilter_gain_old, this.postfilter_gain, this.postfilter_tapset_old, this.postfilter_tapset, mode.window, overlap); - if (LM == 0) continue; - CeltCommon.comb_filter(out_syn[c], out_syn_ptrs[c] + mode.shortMdctSize, out_syn[c], out_syn_ptrs[c] + mode.shortMdctSize, this.postfilter_period, postfilter_pitch, N - mode.shortMdctSize, this.postfilter_gain, postfilter_gain, this.postfilter_tapset, postfilter_tapset, mode.window, overlap); - } while (++c < CC); - this.postfilter_period_old = this.postfilter_period; - this.postfilter_gain_old = this.postfilter_gain; - this.postfilter_tapset_old = this.postfilter_tapset; - this.postfilter_period = postfilter_pitch; - this.postfilter_gain = postfilter_gain; - this.postfilter_tapset = postfilter_tapset; - if (LM != 0) { - this.postfilter_period_old = this.postfilter_period; - this.postfilter_gain_old = this.postfilter_gain; - this.postfilter_tapset_old = this.postfilter_tapset; - } - if (C == 1) { - System.arraycopy(oldBandE, 0, oldBandE, nbEBands, nbEBands); - } - if (isTransient == 0) { - System.arraycopy(oldLogE, 0, oldLogE2, 0, 2 * nbEBands); - System.arraycopy(oldBandE, 0, oldLogE, 0, 2 * nbEBands); - int max_background_increase = this.loss_count < 10 ? M * 1 : 1024; - for (i = 0; i < 2 * nbEBands; ++i) { - backgroundLogE[i] = Inlines.MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]); - } - } else { - for (i = 0; i < 2 * nbEBands; ++i) { - oldLogE[i] = Inlines.MIN16(oldLogE[i], oldBandE[i]); - } - } - c = 0; - do { - for (i = 0; i < start; ++i) { - oldBandE[c * nbEBands + i] = 0; - oldLogE2[c * nbEBands + i] = -28672; - oldLogE[c * nbEBands + i] = -28672; - } - for (i = end; i < nbEBands; ++i) { - oldBandE[c * nbEBands + i] = 0; - oldLogE2[c * nbEBands + i] = -28672; - oldLogE[c * nbEBands + i] = -28672; - } - } while (++c < 2); - this.rng = (int)dec.rng; - CeltCommon.deemphasis(out_syn, out_syn_ptrs, pcm, pcm_ptr, N, CC, this.downsample, mode.preemph, this.preemph_memD, accum); - this.loss_count = 0; - if (dec.tell() > 8 * len) { - return OpusError.OPUS_INTERNAL_ERROR; - } - if (dec.get_error() != 0) { - this.error = 1; - } - return frame_size / this.downsample; - } - - void SetStartBand(int value) { - if (value < 0 || value >= this.mode.nbEBands) { - throw new IllegalArgumentException("Start band above max number of ebands (or negative)"); - } - this.start = value; - } - - void SetEndBand(int value) { - if (value < 1 || value > this.mode.nbEBands) { - throw new IllegalArgumentException("End band above max number of ebands (or less than 1)"); - } - this.end = value; - } - - void SetChannels(int value) { - if (value < 1 || value > 2) { - throw new IllegalArgumentException("Channel count must be 1 or 2"); - } - this.stream_channels = value; - } - - int GetAndClearError() { - int returnVal = this.error; - this.error = 0; - return returnVal; - } - - public int GetLookahead() { - return this.overlap / this.downsample; - } - - public int GetPitch() { - return this.postfilter_period; - } - - public CeltMode GetMode() { - return this.mode; - } - - public void SetSignalling(int value) { - this.signalling = value; - } - - public int GetFinalRange() { - return this.rng; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltEncoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CeltEncoder.java deleted file mode 100644 index d91ddde..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltEncoder.java +++ /dev/null @@ -1,888 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.AnalysisInfo; -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Bands; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltCommon; -import de.maxhenkel.voicechat.concentus.CeltMode; -import de.maxhenkel.voicechat.concentus.CeltTables; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.OpusError; -import de.maxhenkel.voicechat.concentus.OpusFramesize; -import de.maxhenkel.voicechat.concentus.Pitch; -import de.maxhenkel.voicechat.concentus.QuantizeBands; -import de.maxhenkel.voicechat.concentus.Rate; - -class CeltEncoder { - CeltMode mode = null; - int channels = 0; - int stream_channels = 0; - int force_intra = 0; - int clip = 0; - int disable_pf = 0; - int complexity = 0; - int upsample = 0; - int start = 0; - int end = 0; - int bitrate = 0; - int vbr = 0; - int signalling = 0; - int constrained_vbr = 0; - int loss_rate = 0; - int lsb_depth = 0; - OpusFramesize variable_duration = OpusFramesize.OPUS_FRAMESIZE_UNKNOWN; - int lfe = 0; - int rng = 0; - int spread_decision = 0; - int delayedIntra = 0; - int tonal_average = 0; - int lastCodedBands = 0; - int hf_average = 0; - int tapset_decision = 0; - int prefilter_period = 0; - int prefilter_gain = 0; - int prefilter_tapset = 0; - int consec_transient = 0; - AnalysisInfo analysis = new AnalysisInfo(); - final int[] preemph_memE = new int[2]; - final int[] preemph_memD = new int[2]; - int vbr_reservoir = 0; - int vbr_drift = 0; - int vbr_offset = 0; - int vbr_count = 0; - int overlap_max = 0; - int stereo_saving = 0; - int intensity = 0; - int[] energy_mask = null; - int spec_avg = 0; - int[][] in_mem = null; - int[][] prefilter_mem = null; - int[][] oldBandE = null; - int[][] oldLogE = null; - int[][] oldLogE2 = null; - - CeltEncoder() { - } - - private void Reset() { - this.mode = null; - this.channels = 0; - this.stream_channels = 0; - this.force_intra = 0; - this.clip = 0; - this.disable_pf = 0; - this.complexity = 0; - this.upsample = 0; - this.start = 0; - this.end = 0; - this.bitrate = 0; - this.vbr = 0; - this.signalling = 0; - this.constrained_vbr = 0; - this.loss_rate = 0; - this.lsb_depth = 0; - this.variable_duration = OpusFramesize.OPUS_FRAMESIZE_UNKNOWN; - this.lfe = 0; - this.PartialReset(); - } - - private void PartialReset() { - this.rng = 0; - this.spread_decision = 0; - this.delayedIntra = 0; - this.tonal_average = 0; - this.lastCodedBands = 0; - this.hf_average = 0; - this.tapset_decision = 0; - this.prefilter_period = 0; - this.prefilter_gain = 0; - this.prefilter_tapset = 0; - this.consec_transient = 0; - this.analysis.Reset(); - this.preemph_memE[0] = 0; - this.preemph_memE[1] = 0; - this.preemph_memD[0] = 0; - this.preemph_memD[1] = 0; - this.vbr_reservoir = 0; - this.vbr_drift = 0; - this.vbr_offset = 0; - this.vbr_count = 0; - this.overlap_max = 0; - this.stereo_saving = 0; - this.intensity = 0; - this.energy_mask = null; - this.spec_avg = 0; - this.in_mem = null; - this.prefilter_mem = null; - this.oldBandE = null; - this.oldLogE = null; - this.oldLogE2 = null; - } - - void ResetState() { - int i; - this.PartialReset(); - this.in_mem = Arrays.InitTwoDimensionalArrayInt(this.channels, this.mode.overlap); - this.prefilter_mem = Arrays.InitTwoDimensionalArrayInt(this.channels, 1024); - this.oldBandE = Arrays.InitTwoDimensionalArrayInt(this.channels, this.mode.nbEBands); - this.oldLogE = Arrays.InitTwoDimensionalArrayInt(this.channels, this.mode.nbEBands); - this.oldLogE2 = Arrays.InitTwoDimensionalArrayInt(this.channels, this.mode.nbEBands); - for (i = 0; i < this.mode.nbEBands; ++i) { - this.oldLogE2[0][i] = -28672; - this.oldLogE[0][i] = -28672; - } - if (this.channels == 2) { - for (i = 0; i < this.mode.nbEBands; ++i) { - this.oldLogE2[1][i] = -28672; - this.oldLogE[1][i] = -28672; - } - } - this.vbr_offset = 0; - this.delayedIntra = 1; - this.spread_decision = 2; - this.tonal_average = 256; - this.hf_average = 0; - this.tapset_decision = 0; - } - - int opus_custom_encoder_init_arch(CeltMode mode, int channels) { - if (channels < 0 || channels > 2) { - return OpusError.OPUS_BAD_ARG; - } - if (this == null || mode == null) { - return OpusError.OPUS_ALLOC_FAIL; - } - this.Reset(); - this.mode = mode; - this.stream_channels = this.channels = channels; - this.upsample = 1; - this.start = 0; - this.end = this.mode.effEBands; - this.signalling = 1; - this.constrained_vbr = 1; - this.clip = 1; - this.bitrate = -1; - this.vbr = 0; - this.force_intra = 0; - this.complexity = 5; - this.lsb_depth = 24; - this.ResetState(); - return OpusError.OPUS_OK; - } - - int celt_encoder_init(int sampling_rate, int channels) { - int ret = this.opus_custom_encoder_init_arch(CeltMode.mode48000_960_120, channels); - if (ret != OpusError.OPUS_OK) { - return ret; - } - this.upsample = CeltCommon.resampling_factor(sampling_rate); - return OpusError.OPUS_OK; - } - - int run_prefilter(int[][] input, int[][] prefilter_mem, int CC, int N, int prefilter_tapset, BoxedValueInt pitch, BoxedValueInt gain, BoxedValueInt qgain, int enabled, int nbAvailableBytes) { - int qg; - int pf_on; - int gain1; - int[][] pre = new int[CC][]; - BoxedValueInt pitch_index = new BoxedValueInt(0); - CeltMode mode = this.mode; - int overlap = mode.overlap; - for (int z = 0; z < CC; ++z) { - pre[z] = new int[N + 1024]; - } - int c = 0; - do { - System.arraycopy(prefilter_mem[c], 0, pre[c], 0, 1024); - System.arraycopy(input[c], overlap, pre[c], 1024, N); - } while (++c < CC); - if (enabled != 0) { - int[] pitch_buf = new int[1024 + N >> 1]; - Pitch.pitch_downsample(pre, pitch_buf, 1024 + N, CC); - Pitch.pitch_search(pitch_buf, 512, pitch_buf, N, 979, pitch_index); - pitch_index.Val = 1024 - pitch_index.Val; - gain1 = Pitch.remove_doubling(pitch_buf, 1024, 15, N, pitch_index, this.prefilter_period, this.prefilter_gain); - if (pitch_index.Val > 1022) { - pitch_index.Val = 1022; - } - gain1 = Inlines.MULT16_16_Q15(22938, gain1); - if (this.loss_rate > 2) { - gain1 = Inlines.HALF32(gain1); - } - if (this.loss_rate > 4) { - gain1 = Inlines.HALF32(gain1); - } - if (this.loss_rate > 8) { - gain1 = 0; - } - } else { - gain1 = 0; - pitch_index.Val = 15; - } - int pf_threshold = 6554; - if (Inlines.abs(pitch_index.Val - this.prefilter_period) * 10 > pitch_index.Val) { - pf_threshold += 6554; - } - if (nbAvailableBytes < 25) { - pf_threshold += 3277; - } - if (nbAvailableBytes < 35) { - pf_threshold += 3277; - } - if (this.prefilter_gain > 13107) { - pf_threshold -= 3277; - } - if (this.prefilter_gain > 18022) { - pf_threshold -= 3277; - } - if (gain1 < (pf_threshold = Inlines.MAX16(pf_threshold, 6554))) { - gain1 = 0; - pf_on = 0; - qg = 0; - } else { - if (Inlines.ABS32(gain1 - this.prefilter_gain) < 3277) { - gain1 = this.prefilter_gain; - } - qg = (gain1 + 1536 >> 10) / 3 - 1; - qg = Inlines.IMAX(0, Inlines.IMIN(7, qg)); - gain1 = 3072 * (qg + 1); - pf_on = 1; - } - c = 0; - do { - int offset = mode.shortMdctSize - overlap; - this.prefilter_period = Inlines.IMAX(this.prefilter_period, 15); - System.arraycopy(this.in_mem[c], 0, input[c], 0, overlap); - if (offset != 0) { - CeltCommon.comb_filter(input[c], overlap, pre[c], 1024, this.prefilter_period, this.prefilter_period, offset, -this.prefilter_gain, -this.prefilter_gain, this.prefilter_tapset, this.prefilter_tapset, null, 0); - } - CeltCommon.comb_filter(input[c], overlap + offset, pre[c], 1024 + offset, this.prefilter_period, pitch_index.Val, N - offset, -this.prefilter_gain, -gain1, this.prefilter_tapset, prefilter_tapset, mode.window, overlap); - System.arraycopy(input[c], N, this.in_mem[c], 0, overlap); - if (N > 1024) { - System.arraycopy(pre[c], N, prefilter_mem[c], 0, 1024); - continue; - } - Arrays.MemMove(prefilter_mem[c], N, 0, 1024 - N); - System.arraycopy(pre[c], 1024, prefilter_mem[c], 1024 - N, N); - } while (++c < CC); - gain.Val = gain1; - pitch.Val = pitch_index.Val; - qgain.Val = qg; - return pf_on; - } - - int celt_encode_with_ec(short[] pcm, int pcm_ptr, int frame_size, byte[] compressed, int compressed_ptr, int nbCompressedBytes, EntropyCoder enc) { - int tf_sum; - int tf_select; - int i; - int vbr_bound; - int max_allowed; - int effectiveBytes; - int vbr_rate; - int nbFilledBytes; - int tell; - int LM; - int shortBlocks = 0; - int isTransient = 0; - int CC = this.channels; - int C = this.stream_channels; - int pitch_index = 15; - int gain1 = 0; - int dual_stereo = 0; - int prefilter_tapset = 0; - int anti_collapse_on = 0; - int silence = 0; - int tf_chan = 0; - int pitch_change = 0; - boolean transient_got_disabled = false; - int surround_masking = 0; - int temporal_vbr = 0; - int surround_trim = 0; - int equiv_rate = 510000; - CeltMode mode = this.mode; - int nbEBands = mode.nbEBands; - int overlap = mode.overlap; - short[] eBands = mode.eBands; - int start = this.start; - int end = this.end; - int tf_estimate = 0; - if (nbCompressedBytes < 2 || pcm == null) { - return OpusError.OPUS_BAD_ARG; - } - frame_size *= this.upsample; - for (LM = 0; LM <= mode.maxLM && mode.shortMdctSize << LM != frame_size; ++LM) { - } - if (LM > mode.maxLM) { - return OpusError.OPUS_BAD_ARG; - } - int M = 1 << LM; - int N = M * mode.shortMdctSize; - if (enc == null) { - tell = 1; - nbFilledBytes = 0; - } else { - tell = enc.tell(); - nbFilledBytes = tell + 4 >> 3; - } - Inlines.OpusAssert(this.signalling == 0); - nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, 1275); - int nbAvailableBytes = nbCompressedBytes - nbFilledBytes; - if (this.vbr != 0 && this.bitrate != -1) { - int den = mode.Fs >> 3; - vbr_rate = (this.bitrate * frame_size + (den >> 1)) / den; - effectiveBytes = vbr_rate >> 6; - } else { - vbr_rate = 0; - int tmp = this.bitrate * frame_size; - if (tell > 1) { - tmp += tell; - } - if (this.bitrate != -1) { - nbCompressedBytes = Inlines.IMAX(2, Inlines.IMIN(nbCompressedBytes, (tmp + 4 * mode.Fs) / (8 * mode.Fs) - (this.signalling != 0 ? 1 : 0))); - } - effectiveBytes = nbCompressedBytes; - } - if (this.bitrate != -1) { - equiv_rate = this.bitrate - (40 * C + 20) * ((400 >> LM) - 50); - } - if (enc == null) { - enc = new EntropyCoder(); - enc.enc_init(compressed, compressed_ptr, nbCompressedBytes); - } - if (vbr_rate > 0 && this.constrained_vbr != 0 && (max_allowed = Inlines.IMIN(Inlines.IMAX(tell == 1 ? 2 : 0, vbr_rate + (vbr_bound = vbr_rate) - this.vbr_reservoir >> 6), nbAvailableBytes)) < nbAvailableBytes) { - nbCompressedBytes = nbFilledBytes + max_allowed; - nbAvailableBytes = max_allowed; - enc.enc_shrink(nbCompressedBytes); - } - int total_bits = nbCompressedBytes * 8; - int effEnd = end; - if (effEnd > mode.effEBands) { - effEnd = mode.effEBands; - } - int[][] input = Arrays.InitTwoDimensionalArrayInt(CC, N + overlap); - int sample_max = Inlines.MAX32(this.overlap_max, Inlines.celt_maxabs32(pcm, pcm_ptr, C * (N - overlap) / this.upsample)); - this.overlap_max = Inlines.celt_maxabs32(pcm, pcm_ptr + C * (N - overlap) / this.upsample, C * overlap / this.upsample); - int n = silence = (sample_max = Inlines.MAX32(sample_max, this.overlap_max)) == 0 ? 1 : 0; - if (tell == 1) { - enc.enc_bit_logp(silence, 15); - } else { - silence = 0; - } - if (silence != 0) { - if (vbr_rate > 0) { - effectiveBytes = nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, nbFilledBytes + 2); - total_bits = nbCompressedBytes * 8; - nbAvailableBytes = 2; - enc.enc_shrink(nbCompressedBytes); - } - tell = nbCompressedBytes * 8; - enc.nbits_total += tell - enc.tell(); - } - int c = 0; - BoxedValueInt boxed_memE = new BoxedValueInt(0); - do { - int need_clip = 0; - boxed_memE.Val = this.preemph_memE[c]; - CeltCommon.celt_preemphasis(pcm, pcm_ptr + c, input[c], overlap, N, CC, this.upsample, mode.preemph, boxed_memE, need_clip); - this.preemph_memE[c] = boxed_memE.Val; - } while (++c < CC); - int enabled = (this.lfe != 0 && nbAvailableBytes > 3 || nbAvailableBytes > 12 * C) && start == 0 && silence == 0 && this.disable_pf == 0 && this.complexity >= 5 && (this.consec_transient == 0 || LM == 3 || this.variable_duration != OpusFramesize.OPUS_FRAMESIZE_VARIABLE) ? 1 : 0; - prefilter_tapset = this.tapset_decision; - BoxedValueInt boxed_pitch_index = new BoxedValueInt(0); - BoxedValueInt boxed_gain1 = new BoxedValueInt(0); - BoxedValueInt boxed_qg = new BoxedValueInt(0); - int pf_on = this.run_prefilter(input, this.prefilter_mem, CC, N, prefilter_tapset, boxed_pitch_index, boxed_gain1, boxed_qg, enabled, nbAvailableBytes); - pitch_index = boxed_pitch_index.Val; - gain1 = boxed_gain1.Val; - int qg = boxed_qg.Val; - if (!(gain1 <= 13107 && this.prefilter_gain <= 13107 || this.analysis.valid != 0 && !((double)this.analysis.tonality > 0.3) || !((double)pitch_index > 1.26 * (double)this.prefilter_period) && !((double)pitch_index < 0.79 * (double)this.prefilter_period))) { - pitch_change = 1; - } - if (pf_on == 0) { - if (start == 0 && tell + 16 <= total_bits) { - enc.enc_bit_logp(0, 1); - } - } else { - enc.enc_bit_logp(1, 1); - int octave = Inlines.EC_ILOG(++pitch_index) - 5; - enc.enc_uint(octave, 6L); - enc.enc_bits(pitch_index - (16 << octave), 4 + octave); - --pitch_index; - enc.enc_bits(qg, 3); - enc.enc_icdf(prefilter_tapset, CeltTables.tapset_icdf, 2); - } - isTransient = 0; - shortBlocks = 0; - if (this.complexity >= 1 && this.lfe == 0) { - BoxedValueInt boxed_tf_estimate = new BoxedValueInt(0); - BoxedValueInt boxed_tf_chan = new BoxedValueInt(0); - isTransient = CeltCommon.transient_analysis(input, N + overlap, CC, boxed_tf_estimate, boxed_tf_chan); - tf_estimate = boxed_tf_estimate.Val; - tf_chan = boxed_tf_chan.Val; - } - if (LM > 0 && enc.tell() + 3 <= total_bits) { - if (isTransient != 0) { - shortBlocks = M; - } - } else { - isTransient = 0; - transient_got_disabled = true; - } - int[][] freq = Arrays.InitTwoDimensionalArrayInt(CC, N); - int[][] bandE = Arrays.InitTwoDimensionalArrayInt(CC, nbEBands); - int[][] bandLogE = Arrays.InitTwoDimensionalArrayInt(CC, nbEBands); - boolean secondMdct = shortBlocks != 0 && this.complexity >= 8; - int[][] bandLogE2 = Arrays.InitTwoDimensionalArrayInt(CC, nbEBands); - if (secondMdct) { - CeltCommon.compute_mdcts(mode, 0, input, freq, C, CC, LM, this.upsample); - Bands.compute_band_energies(mode, freq, bandE, effEnd, C, LM); - QuantizeBands.amp2Log2(mode, effEnd, end, bandE, bandLogE2, C); - i = 0; - while (i < nbEBands) { - int[] nArray = bandLogE2[0]; - int n2 = i++; - nArray[n2] = nArray[n2] + Inlines.HALF16(Inlines.SHL16(LM, 10)); - } - if (C == 2) { - i = 0; - while (i < nbEBands) { - int[] nArray = bandLogE2[1]; - int n3 = i++; - nArray[n3] = nArray[n3] + Inlines.HALF16(Inlines.SHL16(LM, 10)); - } - } - } - CeltCommon.compute_mdcts(mode, shortBlocks, input, freq, C, CC, LM, this.upsample); - if (CC == 2 && C == 1) { - tf_chan = 0; - } - Bands.compute_band_energies(mode, freq, bandE, effEnd, C, LM); - if (this.lfe != 0) { - for (i = 2; i < end; ++i) { - bandE[0][i] = Inlines.IMIN(bandE[0][i], Inlines.MULT16_32_Q15((short)3, bandE[0][0])); - bandE[0][i] = Inlines.MAX32(bandE[0][i], 1); - } - } - QuantizeBands.amp2Log2(mode, effEnd, end, bandE, bandLogE, C); - int[] surround_dynalloc = new int[C * nbEBands]; - if (start == 0 && this.energy_mask != null && this.lfe == 0) { - int mask_avg = 0; - int diff = 0; - int count = 0; - int mask_end = Inlines.IMAX(2, this.lastCodedBands); - for (c = 0; c < C; ++c) { - for (i = 0; i < mask_end; ++i) { - int mask = Inlines.MAX16(Inlines.MIN16(this.energy_mask[nbEBands * c + i], 256), -2048); - if (mask > 0) { - mask = Inlines.HALF16(mask); - } - mask_avg += Inlines.MULT16_16(mask, eBands[i + 1] - eBands[i]); - count += eBands[i + 1] - eBands[i]; - diff += Inlines.MULT16_16(mask, 1 + 2 * i - mask_end); - } - } - Inlines.OpusAssert(count > 0); - mask_avg = Inlines.DIV32_16(mask_avg, count); - mask_avg += 205; - diff = diff * 6 / (C * (mask_end - 1) * (mask_end + 1) * mask_end); - diff = Inlines.HALF32(diff); - diff = Inlines.MAX32(Inlines.MIN32(diff, 32), -32); - int midband = 0; - while (eBands[midband + 1] < eBands[mask_end] / 2) { - ++midband; - } - int count_dynalloc = 0; - for (i = 0; i < mask_end; ++i) { - int lin = mask_avg + diff * (i - midband); - int unmask = C == 2 ? Inlines.MAX16(this.energy_mask[i], this.energy_mask[nbEBands + i]) : this.energy_mask[i]; - unmask = Inlines.MIN16(unmask, 0); - if ((unmask -= lin) <= 256) continue; - surround_dynalloc[i] = unmask - 256; - ++count_dynalloc; - } - if (count_dynalloc >= 3) { - if ((mask_avg += 256) > 0) { - mask_avg = 0; - diff = 0; - Arrays.MemSet(surround_dynalloc, 0, mask_end); - } else { - for (i = 0; i < mask_end; ++i) { - surround_dynalloc[i] = Inlines.MAX16(0, surround_dynalloc[i] - 256); - } - } - } - surround_trim = 64 * diff; - surround_masking = mask_avg += 205; - } - if (this.lfe == 0) { - int follow = -10240; - int frame_avg = 0; - int offset = shortBlocks != 0 ? Inlines.HALF16(Inlines.SHL16(LM, 10)) : 0; - for (i = start; i < end; ++i) { - follow = Inlines.MAX16(follow - 1024, bandLogE[0][i] - offset); - if (C == 2) { - follow = Inlines.MAX16(follow, bandLogE[1][i] - offset); - } - frame_avg += follow; - } - temporal_vbr = Inlines.SUB16(frame_avg /= end - start, this.spec_avg); - temporal_vbr = Inlines.MIN16(3072, Inlines.MAX16(-1536, temporal_vbr)); - this.spec_avg += (short)Inlines.MULT16_16_Q15(655, temporal_vbr); - } - if (!secondMdct) { - System.arraycopy(bandLogE[0], 0, bandLogE2[0], 0, nbEBands); - if (C == 2) { - System.arraycopy(bandLogE[1], 0, bandLogE2[1], 0, nbEBands); - } - } - if (LM > 0 && enc.tell() + 3 <= total_bits && isTransient == 0 && this.complexity >= 5 && this.lfe == 0 && CeltCommon.patch_transient_decision(bandLogE, this.oldBandE, nbEBands, start, end, C) != 0) { - isTransient = 1; - shortBlocks = M; - CeltCommon.compute_mdcts(mode, shortBlocks, input, freq, C, CC, LM, this.upsample); - Bands.compute_band_energies(mode, freq, bandE, effEnd, C, LM); - QuantizeBands.amp2Log2(mode, effEnd, end, bandE, bandLogE, C); - i = 0; - while (i < nbEBands) { - int[] nArray = bandLogE2[0]; - int n4 = i++; - nArray[n4] = nArray[n4] + Inlines.HALF16(Inlines.SHL16(LM, 10)); - } - if (C == 2) { - i = 0; - while (i < nbEBands) { - int[] nArray = bandLogE2[1]; - int n5 = i++; - nArray[n5] = nArray[n5] + Inlines.HALF16(Inlines.SHL16(LM, 10)); - } - } - tf_estimate = 3277; - } - if (LM > 0 && enc.tell() + 3 <= total_bits) { - enc.enc_bit_logp(isTransient, 3); - } - int[][] X = Arrays.InitTwoDimensionalArrayInt(C, N); - Bands.normalise_bands(mode, freq, X, bandE, effEnd, C, M); - int[] tf_res = new int[nbEBands]; - if (effectiveBytes >= 15 * C && start == 0 && this.complexity >= 2 && this.lfe == 0) { - int lambda = effectiveBytes < 40 ? 12 : (effectiveBytes < 60 ? 6 : (effectiveBytes < 100 ? 4 : 3)); - BoxedValueInt boxed_tf_sum = new BoxedValueInt(0); - tf_select = CeltCommon.tf_analysis(mode, effEnd, isTransient, tf_res, lambda *= 2, X, N, LM, boxed_tf_sum, tf_estimate, tf_chan); - tf_sum = boxed_tf_sum.Val; - for (i = effEnd; i < end; ++i) { - tf_res[i] = tf_res[effEnd - 1]; - } - } else { - tf_sum = 0; - for (i = 0; i < end; ++i) { - tf_res[i] = isTransient; - } - tf_select = 0; - } - int[][] error = Arrays.InitTwoDimensionalArrayInt(C, nbEBands); - BoxedValueInt boxed_delayedintra = new BoxedValueInt(this.delayedIntra); - QuantizeBands.quant_coarse_energy(mode, start, end, effEnd, bandLogE, this.oldBandE, total_bits, error, enc, C, LM, nbAvailableBytes, this.force_intra, boxed_delayedintra, this.complexity >= 4 ? 1 : 0, this.loss_rate, this.lfe); - this.delayedIntra = boxed_delayedintra.Val; - CeltCommon.tf_encode(start, end, isTransient, tf_res, LM, tf_select, enc); - if (enc.tell() + 4 <= total_bits) { - if (this.lfe != 0) { - this.tapset_decision = 0; - this.spread_decision = 2; - } else if (shortBlocks != 0 || this.complexity < 3 || nbAvailableBytes < 10 * C || start != 0) { - this.spread_decision = this.complexity == 0 ? 0 : 2; - } else { - BoxedValueInt boxed_tonal_average = new BoxedValueInt(this.tonal_average); - BoxedValueInt boxed_tapset_decision = new BoxedValueInt(this.tapset_decision); - BoxedValueInt boxed_hf_average = new BoxedValueInt(this.hf_average); - this.spread_decision = Bands.spreading_decision(mode, X, boxed_tonal_average, this.spread_decision, boxed_hf_average, boxed_tapset_decision, pf_on != 0 && shortBlocks == 0 ? 1 : 0, effEnd, C, M); - this.tonal_average = boxed_tonal_average.Val; - this.tapset_decision = boxed_tapset_decision.Val; - this.hf_average = boxed_hf_average.Val; - } - enc.enc_icdf(this.spread_decision, CeltTables.spread_icdf, 5); - } - int[] offsets = new int[nbEBands]; - BoxedValueInt boxed_tot_boost = new BoxedValueInt(0); - int maxDepth = CeltCommon.dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets, this.lsb_depth, mode.logN, isTransient, this.vbr, this.constrained_vbr, eBands, LM, effectiveBytes, boxed_tot_boost, this.lfe, surround_dynalloc); - int tot_boost = boxed_tot_boost.Val; - if (this.lfe != 0) { - offsets[0] = Inlines.IMIN(8, effectiveBytes / 3); - } - int[] cap = new int[nbEBands]; - CeltCommon.init_caps(mode, cap, LM, C); - int dynalloc_logp = 6; - total_bits <<= 3; - int total_boost = 0; - tell = enc.tell_frac(); - for (i = start; i < end; ++i) { - int width = C * (eBands[i + 1] - eBands[i]) << LM; - int quanta = Inlines.IMIN(width << 3, Inlines.IMAX(48, width)); - int dynalloc_loop_logp = dynalloc_logp; - int boost = 0; - int j = 0; - while (tell + (dynalloc_loop_logp << 3) < total_bits - total_boost && boost < cap[i]) { - int flag = j < offsets[i] ? 1 : 0; - enc.enc_bit_logp(flag, dynalloc_loop_logp); - tell = enc.tell_frac(); - if (flag == 0) break; - boost += quanta; - total_boost += quanta; - dynalloc_loop_logp = 1; - ++j; - } - if (j != 0) { - dynalloc_logp = Inlines.IMAX(2, dynalloc_logp - 1); - } - offsets[i] = boost; - } - if (C == 2) { - if (LM != 0) { - dual_stereo = CeltCommon.stereo_analysis(mode, X, LM); - } - this.intensity = Bands.hysteresis_decision(equiv_rate / 1000, CeltTables.intensity_thresholds, CeltTables.intensity_histeresis, 21, this.intensity); - this.intensity = Inlines.IMIN(end, Inlines.IMAX(start, this.intensity)); - } - int alloc_trim = 5; - if (tell + 48 <= total_bits - total_boost) { - if (this.lfe != 0) { - alloc_trim = 5; - } else { - BoxedValueInt boxed_stereo_saving = new BoxedValueInt(this.stereo_saving); - alloc_trim = CeltCommon.alloc_trim_analysis(mode, X, bandLogE, end, LM, C, this.analysis, boxed_stereo_saving, tf_estimate, this.intensity, surround_trim); - this.stereo_saving = boxed_stereo_saving.Val; - } - enc.enc_icdf(alloc_trim, CeltTables.trim_icdf, 7); - tell = enc.tell_frac(); - } - if (vbr_rate > 0) { - int alpha; - int lm_diff = mode.maxLM - LM; - nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, 1275 >> 3 - LM); - int base_target = vbr_rate - (40 * C + 20 << 3); - if (this.constrained_vbr != 0) { - base_target += this.vbr_offset >> lm_diff; - } - int target = CeltCommon.compute_vbr(mode, this.analysis, base_target, LM, equiv_rate, this.lastCodedBands, C, this.intensity, this.constrained_vbr, this.stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth, this.variable_duration, this.lfe, this.energy_mask != null ? 1 : 0, surround_masking, temporal_vbr); - int min_allowed = (tell + total_boost + 64 - 1 >> 6) + 2 - nbFilledBytes; - nbAvailableBytes = (target += tell) + 32 >> 6; - nbAvailableBytes = Inlines.IMAX(min_allowed, nbAvailableBytes); - nbAvailableBytes = Inlines.IMIN(nbCompressedBytes, nbAvailableBytes + nbFilledBytes) - nbFilledBytes; - int delta = target - vbr_rate; - target = nbAvailableBytes << 6; - if (silence != 0) { - nbAvailableBytes = 2; - target = 128; - delta = 0; - } - if (this.vbr_count < 970) { - ++this.vbr_count; - alpha = Inlines.celt_rcp(Inlines.SHL32(this.vbr_count + 20, 16)); - } else { - alpha = 33; - } - if (this.constrained_vbr != 0) { - this.vbr_reservoir += target - vbr_rate; - } - if (this.constrained_vbr != 0) { - this.vbr_drift += Inlines.MULT16_32_Q15(alpha, delta * (1 << lm_diff) - this.vbr_offset - this.vbr_drift); - this.vbr_offset = -this.vbr_drift; - } - if (this.constrained_vbr != 0 && this.vbr_reservoir < 0) { - int adjust = -this.vbr_reservoir / 64; - nbAvailableBytes += silence != 0 ? 0 : adjust; - this.vbr_reservoir = 0; - } - nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, nbAvailableBytes + nbFilledBytes); - enc.enc_shrink(nbCompressedBytes); - } - int[] fine_quant = new int[nbEBands]; - int[] pulses = new int[nbEBands]; - int[] fine_priority = new int[nbEBands]; - int bits = (nbCompressedBytes * 8 << 3) - enc.tell_frac() - 1; - int anti_collapse_rsv = isTransient != 0 && LM >= 2 && bits >= LM + 2 << 3 ? 8 : 0; - bits -= anti_collapse_rsv; - int signalBandwidth = end - 1; - if (this.analysis.enabled && this.analysis.valid != 0) { - int min_bandwidth = equiv_rate < 32000 * C ? 13 : (equiv_rate < 48000 * C ? 16 : (equiv_rate < 60000 * C ? 18 : (equiv_rate < 80000 * C ? 19 : 20))); - signalBandwidth = Inlines.IMAX(this.analysis.bandwidth, min_bandwidth); - } - if (this.lfe != 0) { - signalBandwidth = 1; - } - BoxedValueInt boxed_intensity = new BoxedValueInt(this.intensity); - BoxedValueInt boxed_balance = new BoxedValueInt(0); - BoxedValueInt boxed_dual_stereo = new BoxedValueInt(dual_stereo); - int codedBands = Rate.compute_allocation(mode, start, end, offsets, cap, alloc_trim, boxed_intensity, boxed_dual_stereo, bits, boxed_balance, pulses, fine_quant, fine_priority, C, LM, enc, 1, this.lastCodedBands, signalBandwidth); - this.intensity = boxed_intensity.Val; - int balance = boxed_balance.Val; - dual_stereo = boxed_dual_stereo.Val; - this.lastCodedBands = this.lastCodedBands != 0 ? Inlines.IMIN(this.lastCodedBands + 1, Inlines.IMAX(this.lastCodedBands - 1, codedBands)) : codedBands; - QuantizeBands.quant_fine_energy(mode, start, end, this.oldBandE, error, fine_quant, enc, C); - short[] collapse_masks = new short[C * nbEBands]; - BoxedValueInt boxed_rng = new BoxedValueInt(this.rng); - Bands.quant_all_bands(1, mode, start, end, X[0], C == 2 ? X[1] : null, collapse_masks, bandE, pulses, shortBlocks, this.spread_decision, dual_stereo, this.intensity, tf_res, nbCompressedBytes * 64 - anti_collapse_rsv, balance, enc, LM, codedBands, boxed_rng); - this.rng = boxed_rng.Val; - if (anti_collapse_rsv > 0) { - anti_collapse_on = this.consec_transient < 2 ? 1 : 0; - enc.enc_bits(anti_collapse_on, 1); - } - QuantizeBands.quant_energy_finalise(mode, start, end, this.oldBandE, error, fine_quant, fine_priority, nbCompressedBytes * 8 - enc.tell(), enc, C); - if (silence != 0) { - for (i = 0; i < nbEBands; ++i) { - this.oldBandE[0][i] = -28672; - } - if (C == 2) { - for (i = 0; i < nbEBands; ++i) { - this.oldBandE[1][i] = -28672; - } - } - } - this.prefilter_period = pitch_index; - this.prefilter_gain = gain1; - this.prefilter_tapset = prefilter_tapset; - if (CC == 2 && C == 1) { - System.arraycopy(this.oldBandE[0], 0, this.oldBandE[1], 0, nbEBands); - } - if (isTransient == 0) { - System.arraycopy(this.oldLogE[0], 0, this.oldLogE2[0], 0, nbEBands); - System.arraycopy(this.oldBandE[0], 0, this.oldLogE[0], 0, nbEBands); - if (CC == 2) { - System.arraycopy(this.oldLogE[1], 0, this.oldLogE2[1], 0, nbEBands); - System.arraycopy(this.oldBandE[1], 0, this.oldLogE[1], 0, nbEBands); - } - } else { - for (i = 0; i < nbEBands; ++i) { - this.oldLogE[0][i] = Inlines.MIN16(this.oldLogE[0][i], this.oldBandE[0][i]); - } - if (CC == 2) { - for (i = 0; i < nbEBands; ++i) { - this.oldLogE[1][i] = Inlines.MIN16(this.oldLogE[1][i], this.oldBandE[1][i]); - } - } - } - c = 0; - do { - for (i = 0; i < start; ++i) { - this.oldBandE[c][i] = 0; - this.oldLogE2[c][i] = -28672; - this.oldLogE[c][i] = -28672; - } - for (i = end; i < nbEBands; ++i) { - this.oldBandE[c][i] = 0; - this.oldLogE2[c][i] = -28672; - this.oldLogE[c][i] = -28672; - } - } while (++c < CC); - this.consec_transient = isTransient != 0 || transient_got_disabled ? ++this.consec_transient : 0; - this.rng = (int)enc.rng; - enc.enc_done(); - if (enc.get_error() != 0) { - return OpusError.OPUS_INTERNAL_ERROR; - } - return nbCompressedBytes; - } - - void SetComplexity(int value) { - if (value < 0 || value > 10) { - throw new IllegalArgumentException("Complexity must be between 0 and 10 inclusive"); - } - this.complexity = value; - } - - void SetStartBand(int value) { - if (value < 0 || value >= this.mode.nbEBands) { - throw new IllegalArgumentException("Start band above max number of ebands (or negative)"); - } - this.start = value; - } - - void SetEndBand(int value) { - if (value < 1 || value > this.mode.nbEBands) { - throw new IllegalArgumentException("End band above max number of ebands (or less than 1)"); - } - this.end = value; - } - - void SetPacketLossPercent(int value) { - if (value < 0 || value > 100) { - throw new IllegalArgumentException("Packet loss must be between 0 and 100"); - } - this.loss_rate = value; - } - - void SetPrediction(int value) { - if (value < 0 || value > 2) { - throw new IllegalArgumentException("CELT prediction mode must be 0, 1, or 2"); - } - this.disable_pf = value <= 1 ? 1 : 0; - this.force_intra = value == 0 ? 1 : 0; - } - - void SetVBRConstraint(boolean value) { - this.constrained_vbr = value ? 1 : 0; - } - - void SetVBR(boolean value) { - this.vbr = value ? 1 : 0; - } - - void SetBitrate(int value) { - if (value <= 500 && value != -1) { - throw new IllegalArgumentException("Bitrate out of range"); - } - this.bitrate = value = Inlines.IMIN(value, 260000 * this.channels); - } - - void SetChannels(int value) { - if (value < 1 || value > 2) { - throw new IllegalArgumentException("Channel count must be 1 or 2"); - } - this.stream_channels = value; - } - - void SetLSBDepth(int value) { - if (value < 8 || value > 24) { - throw new IllegalArgumentException("Bit depth must be between 8 and 24"); - } - this.lsb_depth = value; - } - - int GetLSBDepth() { - return this.lsb_depth; - } - - void SetExpertFrameDuration(OpusFramesize value) { - this.variable_duration = value; - } - - void SetSignalling(int value) { - this.signalling = value; - } - - void SetAnalysis(AnalysisInfo value) { - if (value == null) { - throw new IllegalArgumentException("AnalysisInfo"); - } - this.analysis.Assign(value); - } - - CeltMode GetMode() { - return this.mode; - } - - int GetFinalRange() { - return this.rng; - } - - void SetLFE(int value) { - this.lfe = value; - } - - void SetEnergyMask(int[] value) { - this.energy_mask = value; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltLPC.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CeltLPC.java deleted file mode 100644 index fbd180e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltLPC.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Kernels; - -class CeltLPC { - CeltLPC() { - } - - static void celt_lpc(int[] _lpc, int[] ac, int p) { - int i; - int error = ac[0]; - int[] lpc = new int[p]; - if (ac[0] != 0) { - for (i = 0; i < p; ++i) { - int j; - int rr = 0; - for (j = 0; j < i; ++j) { - rr += Inlines.MULT32_32_Q31(lpc[j], ac[i - j]); - } - int r = 0 - Inlines.frac_div32(Inlines.SHL32(rr += Inlines.SHR32(ac[i + 1], 3), 3), error); - lpc[i] = Inlines.SHR32(r, 3); - for (j = 0; j < i + 1 >> 1; ++j) { - int tmp1 = lpc[j]; - int tmp2 = lpc[i - 1 - j]; - lpc[j] = tmp1 + Inlines.MULT32_32_Q31(r, tmp2); - lpc[i - 1 - j] = tmp2 + Inlines.MULT32_32_Q31(r, tmp1); - } - if ((error -= Inlines.MULT32_32_Q31(Inlines.MULT32_32_Q31(r, r), error)) < Inlines.SHR32(ac[0], 10)) break; - } - } - for (i = 0; i < p; ++i) { - _lpc[i] = Inlines.ROUND16(lpc[i], 16); - } - } - - static void celt_iir(int[] _x, int _x_ptr, int[] den, int[] _y, int _y_ptr, int N, int ord, int[] mem) { - int i; - int[] rden = new int[ord]; - int[] y = new int[N + ord]; - Inlines.OpusAssert((ord & 3) == 0); - BoxedValueInt _sum0 = new BoxedValueInt(0); - BoxedValueInt _sum1 = new BoxedValueInt(0); - BoxedValueInt _sum2 = new BoxedValueInt(0); - BoxedValueInt _sum3 = new BoxedValueInt(0); - for (i = 0; i < ord; ++i) { - rden[i] = den[ord - i - 1]; - } - for (i = 0; i < ord; ++i) { - y[i] = 0 - mem[ord - i - 1]; - } - while (i < N + ord) { - y[i] = 0; - ++i; - } - for (i = 0; i < N - 3; i += 4) { - _sum0.Val = _x[_x_ptr + i]; - _sum1.Val = _x[_x_ptr + i + 1]; - _sum2.Val = _x[_x_ptr + i + 2]; - _sum3.Val = _x[_x_ptr + i + 3]; - Kernels.xcorr_kernel(rden, y, i, _sum0, _sum1, _sum2, _sum3, ord); - int sum0 = _sum0.Val; - int sum1 = _sum1.Val; - int sum2 = _sum2.Val; - int sum3 = _sum3.Val; - y[i + ord] = 0 - Inlines.ROUND16(sum0, 12); - _y[_y_ptr + i] = sum0; - sum1 = Inlines.MAC16_16(sum1, y[i + ord], den[0]); - y[i + ord + 1] = 0 - Inlines.ROUND16(sum1, 12); - _y[_y_ptr + i + 1] = sum1; - sum2 = Inlines.MAC16_16(sum2, y[i + ord + 1], den[0]); - sum2 = Inlines.MAC16_16(sum2, y[i + ord], den[1]); - y[i + ord + 2] = 0 - Inlines.ROUND16(sum2, 12); - _y[_y_ptr + i + 2] = sum2; - sum3 = Inlines.MAC16_16(sum3, y[i + ord + 2], den[0]); - sum3 = Inlines.MAC16_16(sum3, y[i + ord + 1], den[1]); - sum3 = Inlines.MAC16_16(sum3, y[i + ord], den[2]); - y[i + ord + 3] = 0 - Inlines.ROUND16(sum3, 12); - _y[_y_ptr + i + 3] = sum3; - } - while (i < N) { - int sum = _x[_x_ptr + i]; - for (int j = 0; j < ord; ++j) { - sum -= Inlines.MULT16_16(rden[j], y[i + j]); - } - y[i + ord] = Inlines.ROUND16(sum, 12); - _y[_y_ptr + i] = sum; - ++i; - } - for (i = 0; i < ord; ++i) { - mem[i] = _y[_y_ptr + N - i - 1]; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltMode.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CeltMode.java deleted file mode 100644 index fdc5261..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltMode.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.CeltTables; -import de.maxhenkel.voicechat.concentus.FFTState; -import de.maxhenkel.voicechat.concentus.MDCTLookup; -import de.maxhenkel.voicechat.concentus.PulseCache; - -class CeltMode { - int Fs = 0; - int overlap = 0; - int nbEBands = 0; - int effEBands = 0; - int[] preemph = new int[]{0, 0, 0, 0}; - short[] eBands = null; - int maxLM = 0; - int nbShortMdcts = 0; - int shortMdctSize = 0; - int nbAllocVectors = 0; - short[] allocVectors = null; - short[] logN = null; - int[] window = null; - MDCTLookup mdct = new MDCTLookup(); - PulseCache cache = new PulseCache(); - static final CeltMode mode48000_960_120 = new CeltMode(); - - private CeltMode() { - } - - static { - CeltMode.mode48000_960_120.Fs = 48000; - CeltMode.mode48000_960_120.overlap = 120; - CeltMode.mode48000_960_120.nbEBands = 21; - CeltMode.mode48000_960_120.effEBands = 21; - CeltMode.mode48000_960_120.preemph = new int[]{27853, 0, 4096, 8192}; - CeltMode.mode48000_960_120.eBands = CeltTables.eband5ms; - CeltMode.mode48000_960_120.maxLM = 3; - CeltMode.mode48000_960_120.nbShortMdcts = 8; - CeltMode.mode48000_960_120.shortMdctSize = 120; - CeltMode.mode48000_960_120.nbAllocVectors = 11; - CeltMode.mode48000_960_120.allocVectors = CeltTables.band_allocation; - CeltMode.mode48000_960_120.logN = CeltTables.logN400; - CeltMode.mode48000_960_120.window = CeltTables.window120; - CeltMode.mode48000_960_120.mdct = new MDCTLookup(); - CeltMode.mode48000_960_120.mdct.n = 1920; - CeltMode.mode48000_960_120.mdct.maxshift = 3; - CeltMode.mode48000_960_120.mdct.kfft = new FFTState[]{CeltTables.fft_state48000_960_0, CeltTables.fft_state48000_960_1, CeltTables.fft_state48000_960_2, CeltTables.fft_state48000_960_3}; - CeltMode.mode48000_960_120.mdct.trig = CeltTables.mdct_twiddles960; - CeltMode.mode48000_960_120.cache = new PulseCache(); - CeltMode.mode48000_960_120.cache.size = 392; - CeltMode.mode48000_960_120.cache.index = CeltTables.cache_index50; - CeltMode.mode48000_960_120.cache.bits = CeltTables.cache_bits50; - CeltMode.mode48000_960_120.cache.caps = CeltTables.cache_caps50; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltPitchXCorr.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CeltPitchXCorr.java deleted file mode 100644 index e32c8ee..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltPitchXCorr.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Kernels; - -class CeltPitchXCorr { - CeltPitchXCorr() { - } - - static int pitch_xcorr(int[] _x, int[] _y, int[] xcorr, int len, int max_pitch) { - int i; - int maxcorr = 1; - Inlines.OpusAssert(max_pitch > 0); - BoxedValueInt sum0 = new BoxedValueInt(0); - BoxedValueInt sum1 = new BoxedValueInt(0); - BoxedValueInt sum2 = new BoxedValueInt(0); - BoxedValueInt sum3 = new BoxedValueInt(0); - for (i = 0; i < max_pitch - 3; i += 4) { - sum0.Val = 0; - sum1.Val = 0; - sum2.Val = 0; - sum3.Val = 0; - Kernels.xcorr_kernel(_x, _y, i, sum0, sum1, sum2, sum3, len); - xcorr[i] = sum0.Val; - xcorr[i + 1] = sum1.Val; - xcorr[i + 2] = sum2.Val; - xcorr[i + 3] = sum3.Val; - sum0.Val = Inlines.MAX32(sum0.Val, sum1.Val); - sum2.Val = Inlines.MAX32(sum2.Val, sum3.Val); - sum0.Val = Inlines.MAX32(sum0.Val, sum2.Val); - maxcorr = Inlines.MAX32(maxcorr, sum0.Val); - } - while (i < max_pitch) { - int inner_sum; - xcorr[i] = inner_sum = Kernels.celt_inner_prod(_x, 0, _y, i, len); - maxcorr = Inlines.MAX32(maxcorr, inner_sum); - ++i; - } - return maxcorr; - } - - static int pitch_xcorr(short[] _x, int _x_ptr, short[] _y, int _y_ptr, int[] xcorr, int len, int max_pitch) { - int i; - int maxcorr = 1; - Inlines.OpusAssert(max_pitch > 0); - BoxedValueInt sum0 = new BoxedValueInt(0); - BoxedValueInt sum1 = new BoxedValueInt(0); - BoxedValueInt sum2 = new BoxedValueInt(0); - BoxedValueInt sum3 = new BoxedValueInt(0); - for (i = 0; i < max_pitch - 3; i += 4) { - sum0.Val = 0; - sum1.Val = 0; - sum2.Val = 0; - sum3.Val = 0; - Kernels.xcorr_kernel(_x, _x_ptr, _y, _y_ptr + i, sum0, sum1, sum2, sum3, len); - xcorr[i] = sum0.Val; - xcorr[i + 1] = sum1.Val; - xcorr[i + 2] = sum2.Val; - xcorr[i + 3] = sum3.Val; - sum0.Val = Inlines.MAX32(sum0.Val, sum1.Val); - sum2.Val = Inlines.MAX32(sum2.Val, sum3.Val); - sum0.Val = Inlines.MAX32(sum0.Val, sum2.Val); - maxcorr = Inlines.MAX32(maxcorr, sum0.Val); - } - while (i < max_pitch) { - int inner_sum; - xcorr[i] = inner_sum = Kernels.celt_inner_prod(_x, _x_ptr, _y, _y_ptr + i, len); - maxcorr = Inlines.MAX32(maxcorr, inner_sum); - ++i; - } - return maxcorr; - } - - static int pitch_xcorr(short[] _x, short[] _y, int[] xcorr, int len, int max_pitch) { - int i; - int maxcorr = 1; - Inlines.OpusAssert(max_pitch > 0); - BoxedValueInt sum0 = new BoxedValueInt(0); - BoxedValueInt sum1 = new BoxedValueInt(0); - BoxedValueInt sum2 = new BoxedValueInt(0); - BoxedValueInt sum3 = new BoxedValueInt(0); - for (i = 0; i < max_pitch - 3; i += 4) { - sum0.Val = 0; - sum1.Val = 0; - sum2.Val = 0; - sum3.Val = 0; - Kernels.xcorr_kernel(_x, 0, _y, i, sum0, sum1, sum2, sum3, len); - xcorr[i] = sum0.Val; - xcorr[i + 1] = sum1.Val; - xcorr[i + 2] = sum2.Val; - xcorr[i + 3] = sum3.Val; - sum0.Val = Inlines.MAX32(sum0.Val, sum1.Val); - sum2.Val = Inlines.MAX32(sum2.Val, sum3.Val); - sum0.Val = Inlines.MAX32(sum0.Val, sum2.Val); - maxcorr = Inlines.MAX32(maxcorr, sum0.Val); - } - while (i < max_pitch) { - int inner_sum; - xcorr[i] = inner_sum = Kernels.celt_inner_prod(_x, _y, i, len); - maxcorr = Inlines.MAX32(maxcorr, inner_sum); - ++i; - } - return maxcorr; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltTables.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CeltTables.java deleted file mode 100644 index bfa9a09..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CeltTables.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.FFTState; - -class CeltTables { - static final byte[] eMeans = new byte[]{103, 100, 92, 85, 81, 77, 72, 70, 78, 75, 73, 71, 78, 74, 69, 72, 70, 74, 76, 71, 60, 60, 60, 60, 60}; - static final int[] ordery_table = new int[]{1, 0, 3, 0, 2, 1, 7, 0, 4, 3, 6, 1, 5, 2, 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5}; - static final short[] eband5ms = new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100}; - static final short[][][] e_prob_model = new short[][][]{new short[][]{{72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11}, {24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50}}, new short[][]{{83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9}, {23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45}}, new short[][]{{61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10}, {21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42}}, new short[][]{{42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15}, {22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40}}}; - static final byte[][] tf_select_table = new byte[][]{{0, -1, 0, -1, 0, -1, 0, -1}, {0, -1, 0, -2, 1, 0, 1, -1}, {0, -2, 0, -3, 2, 0, 1, -1}, {0, -2, 0, -3, 3, 0, 1, -1}}; - static final short[] trim_icdf = new short[]{126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0}; - static final short[] spread_icdf = new short[]{25, 23, 2, 0}; - static final short[] tapset_icdf = new short[]{2, 1, 0}; - static final short[] band_allocation = new short[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, 0, 0, 0, 110, 100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0, 118, 110, 103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15, 4, 0, 0, 0, 0, 126, 119, 112, 104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0, 134, 127, 120, 114, 103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10, 1, 144, 137, 130, 124, 113, 107, 101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1, 152, 145, 138, 132, 123, 117, 111, 105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1, 162, 155, 148, 142, 133, 127, 121, 115, 108, 102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1, 172, 165, 158, 152, 143, 137, 131, 125, 118, 112, 106, 100, 94, 87, 81, 75, 69, 63, 56, 45, 20, 200, 200, 200, 200, 200, 200, 200, 200, 198, 193, 188, 183, 178, 173, 168, 163, 158, 153, 148, 129, 104}; - static final long[] CELT_PVQ_U_DATA = new long[]{1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 5L, 7L, 9L, 11L, 13L, 15L, 17L, 19L, 21L, 23L, 25L, 27L, 29L, 31L, 33L, 35L, 37L, 39L, 41L, 43L, 45L, 47L, 49L, 51L, 53L, 55L, 57L, 59L, 61L, 63L, 65L, 67L, 69L, 71L, 73L, 75L, 77L, 79L, 81L, 83L, 85L, 87L, 89L, 91L, 93L, 95L, 97L, 99L, 101L, 103L, 105L, 107L, 109L, 111L, 113L, 115L, 117L, 119L, 121L, 123L, 125L, 127L, 129L, 131L, 133L, 135L, 137L, 139L, 141L, 143L, 145L, 147L, 149L, 151L, 153L, 155L, 157L, 159L, 161L, 163L, 165L, 167L, 169L, 171L, 173L, 175L, 177L, 179L, 181L, 183L, 185L, 187L, 189L, 191L, 193L, 195L, 197L, 199L, 201L, 203L, 205L, 207L, 209L, 211L, 213L, 215L, 217L, 219L, 221L, 223L, 225L, 227L, 229L, 231L, 233L, 235L, 237L, 239L, 241L, 243L, 245L, 247L, 249L, 251L, 253L, 255L, 257L, 259L, 261L, 263L, 265L, 267L, 269L, 271L, 273L, 275L, 277L, 279L, 281L, 283L, 285L, 287L, 289L, 291L, 293L, 295L, 297L, 299L, 301L, 303L, 305L, 307L, 309L, 311L, 313L, 315L, 317L, 319L, 321L, 323L, 325L, 327L, 329L, 331L, 333L, 335L, 337L, 339L, 341L, 343L, 345L, 347L, 349L, 351L, 13L, 25L, 41L, 61L, 85L, 113L, 145L, 181L, 221L, 265L, 313L, 365L, 421L, 481L, 545L, 613L, 685L, 761L, 841L, 925L, 1013L, 1105L, 1201L, 1301L, 1405L, 1513L, 1625L, 1741L, 1861L, 1985L, 2113L, 2245L, 2381L, 2521L, 2665L, 2813L, 2965L, 3121L, 3281L, 3445L, 3613L, 3785L, 3961L, 4141L, 4325L, 4513L, 4705L, 4901L, 5101L, 5305L, 5513L, 5725L, 5941L, 6161L, 6385L, 6613L, 6845L, 7081L, 7321L, 7565L, 7813L, 8065L, 8321L, 8581L, 8845L, 9113L, 9385L, 9661L, 9941L, 10225L, 10513L, 10805L, 11101L, 11401L, 11705L, 12013L, 12325L, 12641L, 12961L, 13285L, 13613L, 13945L, 14281L, 14621L, 14965L, 15313L, 15665L, 16021L, 16381L, 16745L, 17113L, 17485L, 17861L, 18241L, 18625L, 19013L, 19405L, 19801L, 20201L, 20605L, 21013L, 21425L, 21841L, 22261L, 22685L, 23113L, 23545L, 23981L, 24421L, 24865L, 25313L, 25765L, 26221L, 26681L, 27145L, 27613L, 28085L, 28561L, 29041L, 29525L, 30013L, 30505L, 31001L, 31501L, 32005L, 32513L, 33025L, 33541L, 34061L, 34585L, 35113L, 35645L, 36181L, 36721L, 37265L, 37813L, 38365L, 38921L, 39481L, 40045L, 40613L, 41185L, 41761L, 42341L, 42925L, 43513L, 44105L, 44701L, 45301L, 45905L, 46513L, 47125L, 47741L, 48361L, 48985L, 49613L, 50245L, 50881L, 51521L, 52165L, 52813L, 53465L, 54121L, 54781L, 55445L, 56113L, 56785L, 57461L, 58141L, 58825L, 59513L, 60205L, 60901L, 61601L, 63L, 129L, 231L, 377L, 575L, 833L, 1159L, 1561L, 2047L, 2625L, 3303L, 4089L, 4991L, 6017L, 7175L, 8473L, 9919L, 11521L, 13287L, 15225L, 17343L, 19649L, 22151L, 24857L, 27775L, 30913L, 34279L, 37881L, 41727L, 45825L, 50183L, 54809L, 59711L, 64897L, 70375L, 76153L, 82239L, 88641L, 95367L, 102425L, 109823L, 117569L, 125671L, 134137L, 142975L, 152193L, 161799L, 171801L, 182207L, 193025L, 204263L, 215929L, 228031L, 240577L, 253575L, 267033L, 280959L, 295361L, 310247L, 325625L, 341503L, 357889L, 374791L, 392217L, 410175L, 428673L, 447719L, 467321L, 487487L, 508225L, 529543L, 551449L, 573951L, 597057L, 620775L, 645113L, 670079L, 695681L, 721927L, 748825L, 776383L, 804609L, 833511L, 863097L, 893375L, 924353L, 956039L, 988441L, 1021567L, 1055425L, 1090023L, 1125369L, 1161471L, 1198337L, 1235975L, 1274393L, 1313599L, 1353601L, 1394407L, 1436025L, 1478463L, 1521729L, 1565831L, 1610777L, 1656575L, 1703233L, 1750759L, 1799161L, 1848447L, 1898625L, 1949703L, 2001689L, 2054591L, 2108417L, 2163175L, 2218873L, 2275519L, 2333121L, 2391687L, 2451225L, 2511743L, 2573249L, 2635751L, 0x292FF9L, 2763775L, 2829313L, 2895879L, 2963481L, 3032127L, 3101825L, 3172583L, 3244409L, 3317311L, 3391297L, 3466375L, 3542553L, 3619839L, 3698241L, 3777767L, 3858425L, 3940223L, 4023169L, 4107271L, 4192537L, 4278975L, 4366593L, 4455399L, 4545401L, 4636607L, 4729025L, 4822663L, 4917529L, 5013631L, 5110977L, 5209575L, 5309433L, 5410559L, 5512961L, 5616647L, 5721625L, 5827903L, 5935489L, 6044391L, 6154617L, 6266175L, 6379073L, 6493319L, 6608921L, 6725887L, 6844225L, 6963943L, 7085049L, 7207551L, 321L, 681L, 1289L, 2241L, 3649L, 5641L, 8361L, 11969L, 16641L, 22569L, 29961L, 39041L, 50049L, 63241L, 78889L, 97281L, 118721L, 143529L, 172041L, 204609L, 241601L, 283401L, 330409L, 383041L, 441729L, 506921L, 579081L, 658689L, 746241L, 842249L, 947241L, 1061761L, 1186369L, 1321641L, 1468169L, 1626561L, 1797441L, 1981449L, 2179241L, 2391489L, 2618881L, 2862121L, 3121929L, 3399041L, 3694209L, 4008201L, 4341801L, 4695809L, 5071041L, 5468329L, 5888521L, 6332481L, 6801089L, 7295241L, 7815849L, 8363841L, 8940161L, 9545769L, 10181641L, 10848769L, 11548161L, 12280841L, 13047849L, 13850241L, 14689089L, 15565481L, 16480521L, 17435329L, 18431041L, 19468809L, 20549801L, 21675201L, 22846209L, 24064041L, 25329929L, 26645121L, 28010881L, 29428489L, 30899241L, 32424449L, 34005441L, 35643561L, 37340169L, 39096641L, 40914369L, 42794761L, 0x2AAAAA9L, 46749249L, 48826241L, 50971689L, 53187081L, 55473921L, 57833729L, 60268041L, 62778409L, 65366401L, 68033601L, 70781609L, 73612041L, 76526529L, 79526721L, 82614281L, 85790889L, 89058241L, 92418049L, 95872041L, 99421961L, 103069569L, 106816641L, 110664969L, 114616361L, 118672641L, 122835649L, 127107241L, 131489289L, 135983681L, 140592321L, 145317129L, 150160041L, 155123009L, 160208001L, 165417001L, 170752009L, 176215041L, 181808129L, 187533321L, 193392681L, 199388289L, 205522241L, 211796649L, 218213641L, 224775361L, 231483969L, 238341641L, 245350569L, 252512961L, 259831041L, 267307049L, 274943241L, 282741889L, 290705281L, 298835721L, 307135529L, 315607041L, 324252609L, 333074601L, 342075401L, 351257409L, 360623041L, 370174729L, 379914921L, 389846081L, 399970689L, 410291241L, 420810249L, 431530241L, 442453761L, 453583369L, 464921641L, 476471169L, 488234561L, 500214441L, 512413449L, 524834241L, 537479489L, 550351881L, 563454121L, 576788929L, 590359041L, 604167209L, 618216201L, 632508801L, 1683L, 3653L, 7183L, 13073L, 22363L, 36365L, 56695L, 85305L, 124515L, 177045L, 246047L, 335137L, 448427L, 590557L, 766727L, 982729L, 1244979L, 1560549L, 1937199L, 2383409L, 2908411L, 3522221L, 4235671L, 5060441L, 6009091L, 7095093L, 8332863L, 9737793L, 11326283L, 13115773L, 15124775L, 17372905L, 19880915L, 22670725L, 25765455L, 29189457L, 32968347L, 37129037L, 41699767L, 46710137L, 52191139L, 58175189L, 64696159L, 71789409L, 79491819L, 87841821L, 96879431L, 106646281L, 117185651L, 128542501L, 140763503L, 153897073L, 167993403L, 183104493L, 199284183L, 216588185L, 235074115L, 254801525L, 275831935L, 298228865L, 322057867L, 347386557L, 374284647L, 402823977L, 433078547L, 465124549L, 499040399L, 534906769L, 572806619L, 612825229L, 655050231L, 699571641L, 746481891L, 795875861L, 847850911L, 902506913L, 959946283L, 1020274013L, 1083597703L, 1150027593L, 1219676595L, 1292660325L, 1369097135L, 1449108145L, 1532817275L, 1620351277L, 1711839767L, 1807415257L, 1907213187L, 2011371957L, 2120032959L, 8989L, 19825L, 40081L, 75517L, 134245L, 227305L, 369305L, 579125L, 880685L, 1303777L, 1884961L, 2668525L, 3707509L, 5064793L, 6814249L, 9041957L, 11847485L, 15345233L, 19665841L, 24957661L, 31388293L, 39146185L, 48442297L, 59511829L, 72616013L, 88043969L, 106114625L, 127178701L, 151620757L, 179861305L, 212358985L, 249612805L, 292164445L, 340600625L, 395555537L, 457713341L, 527810725L, 606639529L, 695049433L, 793950709L, 904317037L, 1027188385L, 1163673953L, 1314955181L, 1482288821L, 1667010073L, 1870535785L, 2094367717L, 48639L, 108545L, 224143L, 433905L, 795455L, 1392065L, 2340495L, 3800305L, 5984767L, 9173505L, 13726991L, 20103025L, 28875327L, 40754369L, 56610575L, 77500017L, 104692735L, 139703809L, 184327311L, 240673265L, 311207743L, 398796225L, 506750351L, 638878193L, 799538175L, 993696769L, 1226990095L, 1505789553L, 1837271615L, 2229491905L, 265729L, 598417L, 1256465L, 2485825L, 4673345L, 8405905L, 14546705L, 24331777L, 39490049L, 62390545L, 96220561L, 145198913L, 214828609L, 312193553L, 446304145L, 628496897L, 872893441L, 1196924561L, 1621925137L, 2173806145L, 1462563L, 3317445L, 7059735L, 14218905L, 27298155L, 50250765L, 89129247L, 152951073L, 254831667L, 413442773L, 654862247L, 1014889769L, 1541911931L, 2300409629L, 3375210671L, 8097453L, 18474633L, 39753273L, 81270333L, 158819253L, 298199265L, 540279585L, 948062325L, 1616336765L, 45046719L, 103274625L, 224298231L, 464387817L, 921406335L, 1759885185L, 3248227095L, 251595969L, 579168825L, 1267854873L, 2653649025L, 1409933619L}; - static final int[] window120 = new int[]{2, 20, 55, 108, 178, 266, 372, 494, 635, 792, 966, 1157, 1365, 1590, 1831, 2089, 2362, 2651, 2956, 3276, 3611, 3961, 4325, 4703, 5094, 5499, 5916, 6346, 6788, 7241, 7705, 8179, 8663, 9156, 9657, 10167, 10684, 11207, 11736, 12271, 12810, 13353, 13899, 14447, 14997, 15547, 16098, 16648, 17197, 17744, 18287, 18827, 19363, 19893, 20418, 20936, 21447, 21950, 22445, 22931, 23407, 23874, 24330, 24774, 25208, 25629, 26039, 26435, 26819, 27190, 27548, 27893, 28224, 28541, 28845, 29135, 29411, 29674, 29924, 30160, 30384, 30594, 30792, 30977, 31151, 31313, 31463, 31602, 31731, 31849, 31958, 32057, 32148, 32229, 32303, 32370, 32429, 32481, 32528, 32568, 32604, 32634, 32661, 32683, 32701, 32717, 32729, 32740, 32748, 32754, 32758, 32762, 32764, 32766, Short.MAX_VALUE, Short.MAX_VALUE, Short.MAX_VALUE, Short.MAX_VALUE, Short.MAX_VALUE, Short.MAX_VALUE}; - static final short[] logN400 = new short[]{0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36}; - static final short[] cache_index50 = new short[]{-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, 82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, 41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, 41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, 318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, 305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, 240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387}; - static final short[] cache_bits50 = new short[]{40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, 31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, 51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, 66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, 64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, 94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, 124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, 97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, 142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, 28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, 153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, 229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, 166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, 86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, 25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, 185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, 110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, 74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, 163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, 228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, 90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, 87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, 106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, 224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, 182, 234}; - static final short[] cache_caps50 = new short[]{224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, 178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, 240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, 160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, 138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, 204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, 185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, 207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, 188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, 204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, 140, 66, 40}; - static final short[] fft_twiddles48000_960 = new short[]{Short.MAX_VALUE, 0, 32766, -429, 32757, -858, 32743, -1287, 32724, -1715, 32698, -2143, 32667, -2570, 32631, -2998, 32588, -3425, 32541, -3851, 32488, -4277, 32429, -4701, 32364, -5125, 32295, -5548, 32219, -5971, 32138, -6393, 32051, -6813, 31960, -7231, 31863, -7650, 31760, -8067, 31652, -8481, 31539, -8895, 31419, -9306, 31294, -9716, 31165, -10126, 31030, -10532, 30889, -10937, 30743, -11340, 30592, -11741, 30436, -12141, 30274, -12540, 30107, -12935, 29936, -13328, 29758, -13718, 29577, -14107, 29390, -14493, 29197, -14875, 29000, -15257, 28797, -15635, 28590, -16010, 28379, -16384, 28162, -16753, 27940, -17119, 27714, -17484, 27482, -17845, 27246, -18205, 27006, -18560, 26760, -18911, 26510, -19260, 26257, -19606, 25997, -19947, 25734, -20286, 25466, -20621, 25194, -20952, 24918, -21281, 24637, -21605, 24353, -21926, 24063, -22242, 23770, -22555, 23473, -22865, 23171, -23171, 22866, -23472, 22557, -23769, 22244, -24063, 21927, -24352, 21606, -24636, 21282, -24917, 20954, -25194, 20622, -25465, 20288, -25733, 19949, -25997, 19607, -26255, 19261, -26509, 18914, -26760, 18561, -27004, 18205, -27246, 17846, -27481, 17485, -27713, 17122, -27940, 16755, -28162, 16385, -28378, 16012, -28590, 15636, -28797, 15258, -28999, 14878, -29197, 14494, -29389, 14108, -29576, 13720, -29757, 13329, -29934, 12937, -30107, 12540, -30274, 12142, -30435, 11744, -30592, 11342, -30743, 10939, -30889, 10534, -31030, 10127, -31164, 9718, -31294, 9307, -31418, 8895, -31537, 8482, -31652, 8067, -31759, 7650, -31862, 7233, -31960, 6815, -32051, 6393, -32138, 5973, -32219, 5549, -32294, 5127, -32364, 4703, -32429, 4278, -32487, 3852, -32541, 3426, -32588, 2999, -32630, 2572, -32667, 2144, -32698, 1716, -32724, 1287, -32742, 860, -32757, 430, -32766, 0, -32767, -429, -32766, -858, -32757, -1287, -32743, -1715, -32724, -2143, -32698, -2570, -32667, -2998, -32631, -3425, -32588, -3851, -32541, -4277, -32488, -4701, -32429, -5125, -32364, -5548, -32295, -5971, -32219, -6393, -32138, -6813, -32051, -7231, -31960, -7650, -31863, -8067, -31760, -8481, -31652, -8895, -31539, -9306, -31419, -9716, -31294, -10126, -31165, -10532, -31030, -10937, -30889, -11340, -30743, -11741, -30592, -12141, -30436, -12540, -30274, -12935, -30107, -13328, -29936, -13718, -29758, -14107, -29577, -14493, -29390, -14875, -29197, -15257, -29000, -15635, -28797, -16010, -28590, -16384, -28379, -16753, -28162, -17119, -27940, -17484, -27714, -17845, -27482, -18205, -27246, -18560, -27006, -18911, -26760, -19260, -26510, -19606, -26257, -19947, -25997, -20286, -25734, -20621, -25466, -20952, -25194, -21281, -24918, -21605, -24637, -21926, -24353, -22242, -24063, -22555, -23770, -22865, -23473, -23171, -23171, -23472, -22866, -23769, -22557, -24063, -22244, -24352, -21927, -24636, -21606, -24917, -21282, -25194, -20954, -25465, -20622, -25733, -20288, -25997, -19949, -26255, -19607, -26509, -19261, -26760, -18914, -27004, -18561, -27246, -18205, -27481, -17846, -27713, -17485, -27940, -17122, -28162, -16755, -28378, -16385, -28590, -16012, -28797, -15636, -28999, -15258, -29197, -14878, -29389, -14494, -29576, -14108, -29757, -13720, -29934, -13329, -30107, -12937, -30274, -12540, -30435, -12142, -30592, -11744, -30743, -11342, -30889, -10939, -31030, -10534, -31164, -10127, -31294, -9718, -31418, -9307, -31537, -8895, -31652, -8482, -31759, -8067, -31862, -7650, -31960, -7233, -32051, -6815, -32138, -6393, -32219, -5973, -32294, -5549, -32364, -5127, -32429, -4703, -32487, -4278, -32541, -3852, -32588, -3426, -32630, -2999, -32667, -2572, -32698, -2144, -32724, -1716, -32742, -1287, -32757, -860, -32766, -430, -32767, 0, -32766, 429, -32757, 858, -32743, 1287, -32724, 1715, -32698, 2143, -32667, 2570, -32631, 2998, -32588, 3425, -32541, 3851, -32488, 4277, -32429, 4701, -32364, 5125, -32295, 5548, -32219, 5971, -32138, 6393, -32051, 6813, -31960, 7231, -31863, 7650, -31760, 8067, -31652, 8481, -31539, 8895, -31419, 9306, -31294, 9716, -31165, 10126, -31030, 10532, -30889, 10937, -30743, 11340, -30592, 11741, -30436, 12141, -30274, 12540, -30107, 12935, -29936, 13328, -29758, 13718, -29577, 14107, -29390, 14493, -29197, 14875, -29000, 15257, -28797, 15635, -28590, 16010, -28379, 16384, -28162, 16753, -27940, 17119, -27714, 17484, -27482, 17845, -27246, 18205, -27006, 18560, -26760, 18911, -26510, 19260, -26257, 19606, -25997, 19947, -25734, 20286, -25466, 20621, -25194, 20952, -24918, 21281, -24637, 21605, -24353, 21926, -24063, 22242, -23770, 22555, -23473, 22865, -23171, 23171, -22866, 23472, -22557, 23769, -22244, 24063, -21927, 24352, -21606, 24636, -21282, 24917, -20954, 25194, -20622, 25465, -20288, 25733, -19949, 25997, -19607, 26255, -19261, 26509, -18914, 26760, -18561, 27004, -18205, 27246, -17846, 27481, -17485, 27713, -17122, 27940, -16755, 28162, -16385, 28378, -16012, 28590, -15636, 28797, -15258, 28999, -14878, 29197, -14494, 29389, -14108, 29576, -13720, 29757, -13329, 29934, -12937, 30107, -12540, 30274, -12142, 30435, -11744, 30592, -11342, 30743, -10939, 30889, -10534, 31030, -10127, 31164, -9718, 31294, -9307, 31418, -8895, 31537, -8482, 31652, -8067, 31759, -7650, 31862, -7233, 31960, -6815, 32051, -6393, 32138, -5973, 32219, -5549, 32294, -5127, 32364, -4703, 32429, -4278, 32487, -3852, 32541, -3426, 32588, -2999, 32630, -2572, 32667, -2144, 32698, -1716, 32724, -1287, 32742, -860, 32757, -430, 32766, 0, Short.MAX_VALUE, 429, 32766, 858, 32757, 1287, 32743, 1715, 32724, 2143, 32698, 2570, 32667, 2998, 32631, 3425, 32588, 3851, 32541, 4277, 32488, 4701, 32429, 5125, 32364, 5548, 32295, 5971, 32219, 6393, 32138, 6813, 32051, 7231, 31960, 7650, 31863, 8067, 31760, 8481, 31652, 8895, 31539, 9306, 31419, 9716, 31294, 10126, 31165, 10532, 31030, 10937, 30889, 11340, 30743, 11741, 30592, 12141, 30436, 12540, 30274, 12935, 30107, 13328, 29936, 13718, 29758, 14107, 29577, 14493, 29390, 14875, 29197, 15257, 29000, 15635, 28797, 16010, 28590, 16384, 28379, 16753, 28162, 17119, 27940, 17484, 27714, 17845, 27482, 18205, 27246, 18560, 27006, 18911, 26760, 19260, 26510, 19606, 26257, 19947, 25997, 20286, 25734, 20621, 25466, 20952, 25194, 21281, 24918, 21605, 24637, 21926, 24353, 22242, 24063, 22555, 23770, 22865, 23473, 23171, 23171, 23472, 22866, 23769, 22557, 24063, 22244, 24352, 21927, 24636, 21606, 24917, 21282, 25194, 20954, 25465, 20622, 25733, 20288, 25997, 19949, 26255, 19607, 26509, 19261, 26760, 18914, 27004, 18561, 27246, 18205, 27481, 17846, 27713, 17485, 27940, 17122, 28162, 16755, 28378, 16385, 28590, 16012, 28797, 15636, 28999, 15258, 29197, 14878, 29389, 14494, 29576, 14108, 29757, 13720, 29934, 13329, 30107, 12937, 30274, 12540, 30435, 12142, 30592, 11744, 30743, 11342, 30889, 10939, 31030, 10534, 31164, 10127, 31294, 9718, 31418, 9307, 31537, 8895, 31652, 8482, 31759, 8067, 31862, 7650, 31960, 7233, 32051, 6815, 32138, 6393, 32219, 5973, 32294, 5549, 32364, 5127, 32429, 4703, 32487, 4278, 32541, 3852, 32588, 3426, 32630, 2999, 32667, 2572, 32698, 2144, 32724, 1716, 32742, 1287, 32757, 860, 32766, 430}; - static final short[] fft_bitrev480 = new short[]{0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448, 8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456, 16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464, 24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472, 4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452, 12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460, 20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468, 28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476, 1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449, 9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457, 17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465, 25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473, 5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453, 13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461, 21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469, 29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477, 2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450, 10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458, 18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466, 26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474, 6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454, 14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462, 22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470, 30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478, 3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451, 11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459, 19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467, 27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475, 7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455, 15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463, 23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471, 31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479}; - static final short[] fft_bitrev240 = new short[]{0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224, 4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228, 8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232, 12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236, 1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225, 5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229, 9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233, 13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237, 2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226, 6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230, 10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234, 14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238, 3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227, 7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231, 11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235, 15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239}; - static final short[] fft_bitrev120 = new short[]{0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112, 4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116, 1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113, 5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117, 2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114, 6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118, 3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115, 7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119}; - static final short[] fft_bitrev60 = new short[]{0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56, 1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57, 2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58, 3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59}; - static final FFTState fft_state48000_960_0 = new FFTState(); - static final FFTState fft_state48000_960_1; - static final FFTState fft_state48000_960_2; - static final FFTState fft_state48000_960_3; - static final short[] mdct_twiddles960; - static final int[] intensity_thresholds; - static final int[] intensity_histeresis; - - CeltTables() { - } - - /* - * Opcode count of 26407 triggered aggressive code reduction. Override with --aggressivesizethreshold. - */ - static { - CeltTables.fft_state48000_960_0.nfft = 480; - CeltTables.fft_state48000_960_0.scale = (short)17476; - CeltTables.fft_state48000_960_0.scale_shift = 8; - CeltTables.fft_state48000_960_0.shift = -1; - CeltTables.fft_state48000_960_0.factors = new short[]{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0}; - CeltTables.fft_state48000_960_0.bitrev = fft_bitrev480; - CeltTables.fft_state48000_960_0.twiddles = fft_twiddles48000_960; - fft_state48000_960_1 = new FFTState(); - CeltTables.fft_state48000_960_1.nfft = 240; - CeltTables.fft_state48000_960_1.scale = (short)17476; - CeltTables.fft_state48000_960_1.scale_shift = 7; - CeltTables.fft_state48000_960_1.shift = 1; - CeltTables.fft_state48000_960_1.factors = new short[]{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0}; - CeltTables.fft_state48000_960_1.bitrev = fft_bitrev240; - CeltTables.fft_state48000_960_1.twiddles = fft_twiddles48000_960; - fft_state48000_960_2 = new FFTState(); - CeltTables.fft_state48000_960_2.nfft = 120; - CeltTables.fft_state48000_960_2.scale = (short)17476; - CeltTables.fft_state48000_960_2.scale_shift = 6; - CeltTables.fft_state48000_960_2.shift = 2; - CeltTables.fft_state48000_960_2.factors = new short[]{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0}; - CeltTables.fft_state48000_960_2.bitrev = fft_bitrev120; - CeltTables.fft_state48000_960_2.twiddles = fft_twiddles48000_960; - fft_state48000_960_3 = new FFTState(); - CeltTables.fft_state48000_960_3.nfft = 60; - CeltTables.fft_state48000_960_3.scale = (short)17476; - CeltTables.fft_state48000_960_3.scale_shift = 5; - CeltTables.fft_state48000_960_3.shift = 3; - CeltTables.fft_state48000_960_3.factors = new short[]{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - CeltTables.fft_state48000_960_3.bitrev = fft_bitrev60; - CeltTables.fft_state48000_960_3.twiddles = fft_twiddles48000_960; - mdct_twiddles960 = new short[]{Short.MAX_VALUE, Short.MAX_VALUE, Short.MAX_VALUE, 32766, 32765, 32763, 32761, 32759, 32756, 32753, 32750, 32746, 32742, 32738, 32733, 32728, 32722, 32717, 32710, 32704, 32697, 32690, 32682, 32674, 32666, 32657, 32648, 32639, 32629, 32619, 32609, 32598, 32587, 32576, 32564, 32552, 32539, 32526, 32513, 32500, 32486, 32472, 32457, 32442, 32427, 32411, 32395, 32379, 32362, 32345, 32328, 32310, 32292, 32274, 32255, 32236, 32217, 32197, 32177, 32157, 32136, 32115, 32093, 32071, 32049, 32027, 32004, 31981, 31957, 31933, 31909, 31884, 31859, 31834, 31809, 31783, 31756, 31730, 31703, 31676, 31648, 31620, 31592, 31563, 31534, 31505, 31475, 31445, 31415, 31384, 31353, 31322, 31290, 31258, 31226, 31193, 31160, 31127, 31093, 31059, 31025, 30990, 30955, 30920, 30884, 30848, 30812, 30775, 30738, 30701, 30663, 30625, 30587, 30548, 30509, 30470, 30430, 30390, 30350, 30309, 30269, 30227, 30186, 30144, 30102, 30059, 30016, 29973, 29930, 29886, 29842, 29797, 29752, 29707, 29662, 29616, 29570, 29524, 29477, 29430, 29383, 29335, 29287, 29239, 29190, 29142, 29092, 29043, 28993, 28943, 28892, 28842, 28791, 28739, 28688, 28636, 28583, 28531, 28478, 28425, 28371, 28317, 28263, 28209, 28154, 28099, 28044, 27988, 27932, 27876, 27820, 27763, 27706, 27648, 27591, 27533, 27474, 27416, 27357, 27298, 27238, 27178, 27118, 27058, 26997, 26936, 26875, 26814, 26752, 26690, 26628, 26565, 26502, 26439, 26375, 26312, 26247, 26183, 26119, 26054, 25988, 25923, 25857, 25791, 25725, 25658, 25592, 25524, 25457, 25389, 25322, 25253, 25185, 25116, 25047, 24978, 24908, 24838, 24768, 24698, 24627, 24557, 24485, 24414, 24342, 24270, 24198, 24126, 24053, 23980, 23907, 23834, 23760, 23686, 23612, 23537, 23462, 23387, 23312, 23237, 23161, 23085, 23009, 22932, 22856, 22779, 22701, 22624, 22546, 22468, 22390, 22312, 22233, 22154, 22075, 21996, 21916, 21836, 21756, 21676, 21595, 21515, 21434, 21352, 21271, 21189, 21107, 21025, 20943, 20860, 20777, 20694, 20611, 20528, 20444, 20360, 20276, 20192, 20107, 20022, 19937, 19852, 19767, 19681, 19595, 19509, 19423, 19336, 19250, 19163, 19076, 18988, 18901, 18813, 18725, 18637, 18549, 18460, 18372, 18283, 18194, 18104, 18015, 17925, 17835, 17745, 17655, 17565, 17474, 17383, 17292, 17201, 17110, 17018, 16927, 16835, 16743, 16650, 16558, 16465, 16372, 16279, 16186, 16093, 15999, 15906, 15812, 15718, 15624, 15529, 15435, 15340, 15245, 15150, 15055, 14960, 14864, 14769, 14673, 14577, 14481, 14385, 14288, 14192, 14095, 13998, 13901, 13804, 13706, 13609, 13511, 13414, 13316, 13218, 13119, 13021, 12923, 12824, 12725, 12626, 12527, 12428, 12329, 12230, 12130, 12030, 11930, 11831, 11730, 11630, 11530, 11430, 11329, 11228, 11128, 11027, 10926, 10824, 10723, 10622, 10520, 10419, 10317, 10215, 10113, 10011, 9909, 9807, 9704, 9602, 9499, 9397, 9294, 9191, 9088, 8985, 8882, 8778, 8675, 8572, 8468, 8364, 8261, 8157, 8053, 7949, 7845, 7741, 7637, 7532, 7428, 7323, 7219, 7114, 7009, 6905, 6800, 6695, 6590, 6485, 6380, 6274, 6169, 6064, 5958, 5853, 5747, 5642, 5536, 5430, 5325, 5219, 5113, 5007, 4901, 4795, 4689, 4583, 4476, 4370, 4264, 4157, 4051, 3945, 3838, 3732, 3625, 3518, 3412, 3305, 3198, 3092, 2985, 2878, 2771, 2664, 2558, 2451, 2344, 2237, 2130, 2023, 1916, 1809, 1702, 1594, 1487, 1380, 1273, 1166, 1059, 952, 844, 737, 630, 523, 416, 308, 201, 94, -13, -121, -228, -335, -442, -550, -657, -764, -871, -978, -1086, -1193, -1300, -1407, -1514, -1621, -1728, -1835, -1942, -2049, -2157, -2263, -2370, -2477, -2584, -2691, -2798, -2905, -3012, -3118, -3225, -3332, -3439, -3545, -3652, -3758, -3865, -3971, -4078, -4184, -4290, -4397, -4503, -4609, -4715, -4821, -4927, -5033, -5139, -5245, -5351, -5457, -5562, -5668, -5774, -5879, -5985, -6090, -6195, -6301, -6406, -6511, -6616, -6721, -6826, -6931, -7036, -7140, -7245, -7349, -7454, -7558, -7663, -7767, -7871, -7975, -8079, -8183, -8287, -8390, -8494, -8597, -8701, -8804, -8907, -9011, -9114, -9217, -9319, -9422, -9525, -9627, -9730, -9832, -9934, -10037, -10139, -10241, -10342, -10444, -10546, -10647, -10748, -10850, -10951, -11052, -11153, -11253, -11354, -11455, -11555, -11655, -11756, -11856, -11955, -12055, -12155, -12254, -12354, -12453, -12552, -12651, -12750, -12849, -12947, -13046, -13144, -13242, -13340, -13438, -13536, -13633, -13731, -13828, -13925, -14022, -14119, -14216, -14312, -14409, -14505, -14601, -14697, -14793, -14888, -14984, -15079, -15174, -15269, -15364, -15459, -15553, -15647, -15741, -15835, -15929, -16023, -16116, -16210, -16303, -16396, -16488, -16581, -16673, -16766, -16858, -16949, -17041, -17133, -17224, -17315, -17406, -17497, -17587, -17678, -17768, -17858, -17948, -18037, -18127, -18216, -18305, -18394, -18483, -18571, -18659, -18747, -18835, -18923, -19010, -19098, -19185, -19271, -19358, -19444, -19531, -19617, -19702, -19788, -19873, -19959, -20043, -20128, -20213, -20297, -20381, -20465, -20549, -20632, -20715, -20798, -20881, -20963, -21046, -21128, -21210, -21291, -21373, -21454, -21535, -21616, -21696, -21776, -21856, -21936, -22016, -22095, -22174, -22253, -22331, -22410, -22488, -22566, -22643, -22721, -22798, -22875, -22951, -23028, -23104, -23180, -23256, -23331, -23406, -23481, -23556, -23630, -23704, -23778, -23852, -23925, -23998, -24071, -24144, -24216, -24288, -24360, -24432, -24503, -24574, -24645, -24716, -24786, -24856, -24926, -24995, -25064, -25133, -25202, -25270, -25339, -25406, -25474, -25541, -25608, -25675, -25742, -25808, -25874, -25939, -26005, -26070, -26135, -26199, -26264, -26327, -26391, -26455, -26518, -26581, -26643, -26705, -26767, -26829, -26891, -26952, -27013, -27073, -27133, -27193, -27253, -27312, -27372, -27430, -27489, -27547, -27605, -27663, -27720, -27777, -27834, -27890, -27946, -28002, -28058, -28113, -28168, -28223, -28277, -28331, -28385, -28438, -28491, -28544, -28596, -28649, -28701, -28752, -28803, -28854, -28905, -28955, -29006, -29055, -29105, -29154, -29203, -29251, -29299, -29347, -29395, -29442, -29489, -29535, -29582, -29628, -29673, -29719, -29764, -29808, -29853, -29897, -29941, -29984, -30027, -30070, -30112, -30154, -30196, -30238, -30279, -30320, -30360, -30400, -30440, -30480, -30519, -30558, -30596, -30635, -30672, -30710, -30747, -30784, -30821, -30857, -30893, -30929, -30964, -30999, -31033, -31068, -31102, -31135, -31168, -31201, -31234, -31266, -31298, -31330, -31361, -31392, -31422, -31453, -31483, -31512, -31541, -31570, -31599, -31627, -31655, -31682, -31710, -31737, -31763, -31789, -31815, -31841, -31866, -31891, -31915, -31939, -31963, -31986, -32010, -32032, -32055, -32077, -32099, -32120, -32141, -32162, -32182, -32202, -32222, -32241, -32260, -32279, -32297, -32315, -32333, -32350, -32367, -32383, -32399, -32415, -32431, -32446, -32461, -32475, -32489, -32503, -32517, -32530, -32542, -32555, -32567, -32579, -32590, -32601, -32612, -32622, -32632, -32641, -32651, -32659, -32668, -32676, -32684, -32692, -32699, -32706, -32712, -32718, -32724, -32729, -32734, -32739, -32743, -32747, -32751, -32754, -32757, -32760, -32762, -32764, -32765, -32767, -32767, -32767, Short.MAX_VALUE, Short.MAX_VALUE, 32765, 32761, 32756, 32750, 32742, 32732, 32722, 32710, 32696, 32681, 32665, 32647, 32628, 32608, 32586, 32562, 32538, 32512, 32484, 32455, 32425, 32393, 32360, 32326, 32290, 32253, 32214, 32174, 32133, 32090, 32046, 32001, 31954, 31906, 31856, 31805, 31753, 31700, 31645, 31588, 31530, 31471, 31411, 31349, 31286, 31222, 31156, 31089, 31020, 30951, 30880, 30807, 30733, 30658, 30582, 30504, 30425, 30345, 30263, 30181, 30096, 30011, 29924, 29836, 29747, 29656, 29564, 29471, 29377, 29281, 29184, 29086, 28987, 28886, 28784, 28681, 28577, 28471, 28365, 28257, 28147, 28037, 27925, 27812, 27698, 27583, 27467, 27349, 27231, 27111, 26990, 26868, 26744, 26620, 26494, 26367, 26239, 26110, 25980, 25849, 25717, 25583, 25449, 25313, 25176, 25038, 24900, 24760, 24619, 24477, 24333, 24189, 24044, 23898, 23751, 23602, 23453, 23303, 23152, 22999, 22846, 22692, 22537, 22380, 22223, 22065, 21906, 21746, 21585, 21423, 21261, 21097, 20933, 20767, 20601, 20434, 20265, 20096, 19927, 19756, 19584, 19412, 19239, 19065, 18890, 18714, 18538, 18361, 18183, 18004, 17824, 17644, 17463, 17281, 17098, 16915, 16731, 16546, 16361, 16175, 15988, 15800, 15612, 15423, 15234, 15043, 14852, 14661, 14469, 14276, 14083, 13889, 13694, 13499, 13303, 13107, 12910, 12713, 12515, 12317, 12118, 11918, 11718, 11517, 11316, 11115, 10913, 10710, 10508, 10304, 10100, 9896, 9691, 9486, 9281, 9075, 8869, 8662, 8455, 8248, 8040, 7832, 7623, 7415, 7206, 6996, 6787, 6577, 6366, 6156, 5945, 5734, 5523, 5311, 5100, 4888, 4675, 4463, 4251, 4038, 3825, 3612, 3399, 3185, 2972, 2758, 2544, 2330, 2116, 1902, 1688, 1474, 1260, 1045, 831, 617, 402, 188, -27, -241, -456, -670, -885, -1099, -1313, -1528, -1742, -1956, -2170, -2384, -2598, -2811, -3025, -3239, -3452, -3665, -3878, -4091, -4304, -4516, -4728, -4941, -5153, -5364, -5576, -5787, -5998, -6209, -6419, -6629, -6839, -7049, -7258, -7467, -7676, -7884, -8092, -8300, -8507, -8714, -8920, -9127, -9332, -9538, -9743, -9947, -10151, -10355, -10558, -10761, -10963, -11165, -11367, -11568, -11768, -11968, -12167, -12366, -12565, -12762, -12960, -13156, -13352, -13548, -13743, -13937, -14131, -14324, -14517, -14709, -14900, -15091, -15281, -15470, -15659, -15847, -16035, -16221, -16407, -16593, -16777, -16961, -17144, -17326, -17508, -17689, -17869, -18049, -18227, -18405, -18582, -18758, -18934, -19108, -19282, -19455, -19627, -19799, -19969, -20139, -20308, -20475, -20642, -20809, -20974, -21138, -21301, -21464, -21626, -21786, -21946, -22105, -22263, -22420, -22575, -22730, -22884, -23037, -23189, -23340, -23490, -23640, -23788, -23935, -24080, -24225, -24369, -24512, -24654, -24795, -24934, -25073, -25211, -25347, -25482, -25617, -25750, -25882, -26013, -26143, -26272, -26399, -26526, -26651, -26775, -26898, -27020, -27141, -27260, -27379, -27496, -27612, -27727, -27841, -27953, -28065, -28175, -28284, -28391, -28498, -28603, -28707, -28810, -28911, -29012, -29111, -29209, -29305, -29401, -29495, -29587, -29679, -29769, -29858, -29946, -30032, -30118, -30201, -30284, -30365, -30445, -30524, -30601, -30677, -30752, -30825, -30897, -30968, -31038, -31106, -31172, -31238, -31302, -31365, -31426, -31486, -31545, -31602, -31658, -31713, -31766, -31818, -31869, -31918, -31966, -32012, -32058, -32101, -32144, -32185, -32224, -32262, -32299, -32335, -32369, -32401, -32433, -32463, -32491, -32518, -32544, -32568, -32591, -32613, -32633, -32652, -32669, -32685, -32700, -32713, -32724, -32735, -32744, -32751, -32757, -32762, -32766, -32767, Short.MAX_VALUE, 32764, 32755, 32741, 32720, 32694, 32663, 32626, 32583, 32535, 32481, 32421, 32356, 32286, 32209, 32128, 32041, 31948, 31850, 31747, 31638, 31523, 31403, 31278, 31148, 31012, 30871, 30724, 30572, 30415, 30253, 30086, 29913, 29736, 29553, 29365, 29172, 28974, 28771, 28564, 28351, 28134, 27911, 27684, 27452, 27216, 26975, 26729, 26478, 26223, 25964, 25700, 25432, 25159, 24882, 24601, 24315, 24026, 23732, 23434, 23133, 22827, 22517, 22204, 21886, 21565, 21240, 20912, 20580, 20244, 19905, 19563, 19217, 18868, 18516, 18160, 17802, 17440, 17075, 16708, 16338, 15964, 15588, 15210, 14829, 14445, 14059, 13670, 13279, 12886, 12490, 12093, 11693, 11291, 10888, 10482, 10075, 9666, 9255, 8843, 8429, 8014, 7597, 7180, 6760, 6340, 5919, 5496, 5073, 4649, 4224, 3798, 3372, 2945, 2517, 2090, 1661, 1233, 804, 375, -54, -483, -911, -1340, -1768, -2197, -2624, -3052, -3479, -3905, -4330, -4755, -5179, -5602, -6024, -6445, -6865, -7284, -7702, -8118, -8533, -8946, -9358, -9768, -10177, -10584, -10989, -11392, -11793, -12192, -12589, -12984, -13377, -13767, -14155, -14541, -14924, -15305, -15683, -16058, -16430, -16800, -17167, -17531, -17892, -18249, -18604, -18956, -19304, -19649, -19990, -20329, -20663, -20994, -21322, -21646, -21966, -22282, -22595, -22904, -23208, -23509, -23806, -24099, -24387, -24672, -24952, -25228, -25499, -25766, -26029, -26288, -26541, -26791, -27035, -27275, -27511, -27741, -27967, -28188, -28405, -28616, -28823, -29024, -29221, -29412, -29599, -29780, -29957, -30128, -30294, -30455, -30611, -30761, -30906, -31046, -31181, -31310, -31434, -31552, -31665, -31773, -31875, -31972, -32063, -32149, -32229, -32304, -32373, -32437, -32495, -32547, -32594, -32635, -32671, -32701, -32726, -32745, -32758, -32766, Short.MAX_VALUE, 32754, 32717, 32658, 32577, 32473, 32348, 32200, 32029, 31837, 31624, 31388, 31131, 30853, 30553, 30232, 29891, 29530, 29148, 28746, 28324, 27883, 27423, 26944, 26447, 25931, 25398, 24847, 24279, 23695, 23095, 22478, 21846, 21199, 20538, 19863, 19174, 18472, 17757, 17030, 16291, 15541, 14781, 14010, 13230, 12441, 11643, 10837, 10024, 9204, 8377, 7545, 6708, 5866, 5020, 4171, 3319, 2464, 1608, 751, -107, -965, -1822, -2678, -3532, -4383, -5232, -6077, -6918, -7754, -8585, -9409, -10228, -11039, -11843, -12639, -13426, -14204, -14972, -15730, -16477, -17213, -17937, -18648, -19347, -20033, -20705, -21363, -22006, -22634, -23246, -23843, -24423, -24986, -25533, -26062, -26573, -27066, -27540, -27995, -28431, -28848, -29245, -29622, -29979, -30315, -30630, -30924, -31197, -31449, -31679, -31887, -32074, -32239, -32381, -32501, -32600, -32675, -32729, -32759}; - intensity_thresholds = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 36, 44, 50, 56, 62, 67, 72, 79, 88, 106, 134}; - intensity_histeresis = new int[]{1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 5, 6, 8, 8}; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/ChannelLayout.java b/source/decompiled/de/maxhenkel/voicechat/concentus/ChannelLayout.java deleted file mode 100644 index fe17c8a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/ChannelLayout.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class ChannelLayout { - int nb_channels; - int nb_streams; - int nb_coupled_streams; - final short[] mapping = new short[256]; - - ChannelLayout() { - } - - void Reset() { - this.nb_channels = 0; - this.nb_streams = 0; - this.nb_coupled_streams = 0; - Arrays.MemSet(this.mapping, (short)0); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CodeSigns.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CodeSigns.java deleted file mode 100644 index a358b9f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CodeSigns.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class CodeSigns { - CodeSigns() { - } - - private static int silk_enc_map(int a) { - return Inlines.silk_RSHIFT(a, 15) + 1; - } - - private static int silk_dec_map(int a) { - return Inlines.silk_LSHIFT(a, 1) - 1; - } - - static void silk_encode_signs(EntropyCoder psRangeEnc, byte[] pulses, int length, int signalType, int quantOffsetType, int[] sum_pulses) { - int i; - short[] icdf = new short[2]; - short[] sign_icdf = SilkTables.silk_sign_iCDF; - icdf[1] = 0; - int q_ptr = 0; - int icdf_ptr = i = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1)); - length = Inlines.silk_RSHIFT(length + 8, 4); - for (i = 0; i < length; ++i) { - int p = sum_pulses[i]; - if (p > 0) { - icdf[0] = sign_icdf[icdf_ptr + Inlines.silk_min(p & 0x1F, 6)]; - for (int j = q_ptr; j < q_ptr + 16; ++j) { - if (pulses[j] == 0) continue; - psRangeEnc.enc_icdf(CodeSigns.silk_enc_map(pulses[j]), icdf, 8); - } - } - q_ptr += 16; - } - } - - static void silk_decode_signs(EntropyCoder psRangeDec, short[] pulses, int length, int signalType, int quantOffsetType, int[] sum_pulses) { - int i; - short[] icdf = new short[2]; - short[] icdf_table = SilkTables.silk_sign_iCDF; - icdf[1] = 0; - int q_ptr = 0; - int icdf_ptr = i = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1)); - length = Inlines.silk_RSHIFT(length + 8, 4); - for (i = 0; i < length; ++i) { - int p = sum_pulses[i]; - if (p > 0) { - icdf[0] = icdf_table[icdf_ptr + Inlines.silk_min(p & 0x1F, 6)]; - for (int j = 0; j < 16; ++j) { - if (pulses[q_ptr + j] <= 0) continue; - int n = q_ptr + j; - pulses[n] = (short)(pulses[n] * (short)CodeSigns.silk_dec_map(psRangeDec.dec_icdf(icdf, 8))); - } - } - q_ptr += 16; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CodecHelpers.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CodecHelpers.java deleted file mode 100644 index 511d358..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CodecHelpers.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Downmix; -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.OpusBandwidth; -import de.maxhenkel.voicechat.concentus.OpusBandwidthHelpers; -import de.maxhenkel.voicechat.concentus.OpusFramesize; -import de.maxhenkel.voicechat.concentus.OpusFramesizeHelpers; -import de.maxhenkel.voicechat.concentus.OpusMode; -import de.maxhenkel.voicechat.concentus.StereoWidthState; - -public class CodecHelpers { - private static final int MAX_DYNAMIC_FRAMESIZE = 24; - - static byte gen_toc(OpusMode mode, int framerate, OpusBandwidth bandwidth, int channels) { - int toc; - int period = 0; - while (framerate < 400) { - framerate <<= 1; - ++period; - } - if (mode == OpusMode.MODE_SILK_ONLY) { - toc = (short)(OpusBandwidthHelpers.GetOrdinal(bandwidth) - OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) << 5); - toc = (short)(toc | (short)(period - 2 << 3)); - } else if (mode == OpusMode.MODE_CELT_ONLY) { - int tmp = OpusBandwidthHelpers.GetOrdinal(bandwidth) - OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND); - if (tmp < 0) { - tmp = 0; - } - toc = 128; - toc = (short)(toc | (short)(tmp << 5)); - toc = (short)(toc | (short)(period << 3)); - } else { - toc = 96; - toc = (short)(toc | (short)(OpusBandwidthHelpers.GetOrdinal(bandwidth) - OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) << 4)); - toc = (short)(toc | (short)(period - 2 << 3)); - } - toc = (short)(toc | (short)((channels == 2 ? 1 : 0) << 2)); - return (byte)(0xFF & toc); - } - - static void hp_cutoff(short[] input, int input_ptr, int cutoff_Hz, short[] output, int output_ptr, int[] hp_mem, int len, int channels, int Fs) { - int r_Q28; - int[] B_Q28 = new int[3]; - int[] A_Q28 = new int[2]; - Inlines.OpusAssert(cutoff_Hz <= 869074); - int Fc_Q19 = Inlines.silk_DIV32_16(Inlines.silk_SMULBB(2471, cutoff_Hz), Fs / 1000); - Inlines.OpusAssert(Fc_Q19 > 0 && Fc_Q19 < 32768); - B_Q28[0] = r_Q28 = 0x10000000 - Inlines.silk_MUL(471, Fc_Q19); - B_Q28[1] = Inlines.silk_LSHIFT(-r_Q28, 1); - B_Q28[2] = r_Q28; - int r_Q22 = Inlines.silk_RSHIFT(r_Q28, 6); - A_Q28[0] = Inlines.silk_SMULWW(r_Q22, Inlines.silk_SMULWW(Fc_Q19, Fc_Q19) - 0x800000); - A_Q28[1] = Inlines.silk_SMULWW(r_Q22, r_Q22); - Filters.silk_biquad_alt(input, input_ptr, B_Q28, A_Q28, hp_mem, 0, output, output_ptr, len, channels); - if (channels == 2) { - Filters.silk_biquad_alt(input, input_ptr + 1, B_Q28, A_Q28, hp_mem, 2, output, output_ptr + 1, len, channels); - } - } - - static void dc_reject(short[] input, int input_ptr, int cutoff_Hz, short[] output, int output_ptr, int[] hp_mem, int len, int channels, int Fs) { - int shift = Inlines.celt_ilog2(Fs / (cutoff_Hz * 3)); - for (int c = 0; c < channels; ++c) { - for (int i = 0; i < len; ++i) { - int x = Inlines.SHL32(Inlines.EXTEND32(input[channels * i + c + input_ptr]), 15); - int tmp = x - hp_mem[2 * c]; - hp_mem[2 * c] = hp_mem[2 * c] + Inlines.PSHR32(x - hp_mem[2 * c], shift); - int y = tmp - hp_mem[2 * c + 1]; - hp_mem[2 * c + 1] = hp_mem[2 * c + 1] + Inlines.PSHR32(tmp - hp_mem[2 * c + 1], shift); - output[channels * i + c + output_ptr] = Inlines.EXTRACT16(Inlines.SATURATE(Inlines.PSHR32(y, 15), Short.MAX_VALUE)); - } - } - } - - static void stereo_fade(short[] pcm_buf, int g1, int g2, int overlap48, int frame_size, int channels, int[] window, int Fs) { - int diff; - int i; - int inc = 48000 / Fs; - int overlap = overlap48 / inc; - g1 = Short.MAX_VALUE - g1; - g2 = Short.MAX_VALUE - g2; - for (i = 0; i < overlap; ++i) { - int w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]); - int g = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, g2), Short.MAX_VALUE - w, g1), 15); - diff = Inlines.EXTRACT16(Inlines.HALF32(pcm_buf[i * channels] - pcm_buf[i * channels + 1])); - diff = Inlines.MULT16_16_Q15(g, diff); - pcm_buf[i * channels] = (short)(pcm_buf[i * channels] - diff); - pcm_buf[i * channels + 1] = (short)(pcm_buf[i * channels + 1] + diff); - } - while (i < frame_size) { - diff = Inlines.EXTRACT16(Inlines.HALF32(pcm_buf[i * channels] - pcm_buf[i * channels + 1])); - diff = Inlines.MULT16_16_Q15(g2, diff); - pcm_buf[i * channels] = (short)(pcm_buf[i * channels] - diff); - pcm_buf[i * channels + 1] = (short)(pcm_buf[i * channels + 1] + diff); - ++i; - } - } - - static void gain_fade(short[] buffer, int buf_ptr, int g1, int g2, int overlap48, int frame_size, int channels, int[] window, int Fs) { - int g; - int w; - int i; - int inc = 48000 / Fs; - int overlap = overlap48 / inc; - if (channels == 1) { - for (i = 0; i < overlap; ++i) { - w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]); - g = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, g2), Short.MAX_VALUE - w, g1), 15); - buffer[buf_ptr + i] = (short)Inlines.MULT16_16_Q15(g, (int)buffer[buf_ptr + i]); - } - } else { - for (i = 0; i < overlap; ++i) { - w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]); - g = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, g2), Short.MAX_VALUE - w, g1), 15); - buffer[buf_ptr + i * 2] = (short)Inlines.MULT16_16_Q15(g, (int)buffer[buf_ptr + i * 2]); - buffer[buf_ptr + i * 2 + 1] = (short)Inlines.MULT16_16_Q15(g, (int)buffer[buf_ptr + i * 2 + 1]); - } - } - int c = 0; - do { - for (i = overlap; i < frame_size; ++i) { - buffer[buf_ptr + i * channels + c] = (short)Inlines.MULT16_16_Q15(g2, (int)buffer[buf_ptr + i * channels + c]); - } - } while (++c < channels); - } - - static float transient_boost(float[] E, int E_ptr, float[] E_1, int LM, int maxM) { - float sumE = 0.0f; - float sumE_1 = 0.0f; - int M = Inlines.IMIN(maxM, (1 << LM) + 1); - for (int i = E_ptr; i < M + E_ptr; ++i) { - sumE += E[i]; - sumE_1 += E_1[i]; - } - float metric = sumE * sumE_1 / (float)(M * M); - return Inlines.MIN16(1.0f, (float)Math.sqrt(Inlines.MAX16(0.0f, 0.05f * (metric - 2.0f)))); - } - - static int transient_viterbi(float[] E, float[] E_1, int N, int frame_cost, int rate) { - int i; - float[][] cost = Arrays.InitTwoDimensionalArrayFloat(24, 16); - int[][] states = Arrays.InitTwoDimensionalArrayInt(24, 16); - float factor = rate < 80 ? 0.0f : (rate > 160 ? 1.0f : ((float)rate - 80.0f) / 80.0f); - for (i = 0; i < 16; ++i) { - states[0][i] = -1; - cost[0][i] = 1.0E10f; - } - for (i = 0; i < 4; ++i) { - cost[0][1 << i] = (float)(frame_cost + rate * (1 << i)) * (1.0f + factor * CodecHelpers.transient_boost(E, 0, E_1, i, N + 1)); - states[0][1 << i] = i; - } - for (i = 1; i < N; ++i) { - int j; - for (j = 2; j < 16; ++j) { - cost[i][j] = cost[i - 1][j - 1]; - states[i][j] = j - 1; - } - for (j = 0; j < 4; ++j) { - states[i][1 << j] = 1; - float min_cost = cost[i - 1][1]; - for (int k = 1; k < 4; ++k) { - float tmp = cost[i - 1][(1 << k + 1) - 1]; - if (!(tmp < min_cost)) continue; - states[i][1 << j] = (1 << k + 1) - 1; - min_cost = tmp; - } - float curr_cost = (float)(frame_cost + rate * (1 << j)) * (1.0f + factor * CodecHelpers.transient_boost(E, i, E_1, j, N - i + 1)); - cost[i][1 << j] = min_cost; - if (N - i < 1 << j) { - float[] fArray = cost[i]; - int n = 1 << j; - fArray[n] = fArray[n] + curr_cost * (float)(N - i) / (float)(1 << j); - continue; - } - float[] fArray = cost[i]; - int n = 1 << j; - fArray[n] = fArray[n] + curr_cost; - } - } - int best_state = 1; - float best_cost = cost[N - 1][1]; - for (i = 2; i < 16; ++i) { - if (!(cost[N - 1][i] < best_cost)) continue; - best_cost = cost[N - 1][i]; - best_state = i; - } - for (i = N - 1; i >= 0; --i) { - best_state = states[i][best_state]; - } - return best_state; - } - - static int optimize_framesize(short[] x, int x_ptr, int len, int C, int Fs, int bitrate, int tonality, float[] mem, int buffering) { - int i; - int pos; - int offset; - float[] e = new float[28]; - float[] e_1 = new float[27]; - int bestLM = 0; - int subframe = Fs / 400; - int[] sub = new int[subframe]; - e[0] = mem[0]; - e_1[0] = 1.0f / (1.0f + mem[0]); - if (buffering != 0) { - offset = 2 * subframe - buffering; - Inlines.OpusAssert(offset >= 0 && offset <= subframe); - len -= offset; - e[1] = mem[1]; - e_1[1] = 1.0f / (1.0f + mem[1]); - e[2] = mem[2]; - e_1[2] = 1.0f / (1.0f + mem[2]); - pos = 3; - } else { - pos = 1; - offset = 0; - } - int N = Inlines.IMIN(len / subframe, 24); - int memx = 0; - for (i = 0; i < N; ++i) { - float tmp = 1.0f; - Downmix.downmix_int(x, x_ptr, sub, 0, subframe, i * subframe + offset, 0, -2, C); - if (i == 0) { - memx = sub[0]; - } - for (int j = 0; j < subframe; ++j) { - int tmpx = sub[j]; - tmp += (float)(tmpx - memx) * (float)(tmpx - memx); - memx = tmpx; - } - e[i + pos] = tmp; - e_1[i + pos] = 1.0f / tmp; - } - e[i + pos] = e[i + pos - 1]; - if (buffering != 0) { - N = Inlines.IMIN(24, N + 2); - } - bestLM = CodecHelpers.transient_viterbi(e, e_1, N, (int)((1.0f + 0.5f * (float)tonality) * (float)(60 * C + 40)), bitrate / 400); - mem[0] = e[1 << bestLM]; - if (buffering != 0) { - mem[1] = e[(1 << bestLM) + 1]; - mem[2] = e[(1 << bestLM) + 2]; - } - return bestLM; - } - - static int frame_size_select(int frame_size, OpusFramesize variable_duration, int Fs) { - int new_size; - if (frame_size < Fs / 400) { - return -1; - } - if (variable_duration == OpusFramesize.OPUS_FRAMESIZE_ARG) { - new_size = frame_size; - } else if (variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE) { - new_size = Fs / 50; - } else if (OpusFramesizeHelpers.GetOrdinal(variable_duration) >= OpusFramesizeHelpers.GetOrdinal(OpusFramesize.OPUS_FRAMESIZE_2_5_MS) && OpusFramesizeHelpers.GetOrdinal(variable_duration) <= OpusFramesizeHelpers.GetOrdinal(OpusFramesize.OPUS_FRAMESIZE_60_MS)) { - new_size = Inlines.IMIN(3 * Fs / 50, Fs / 400 << OpusFramesizeHelpers.GetOrdinal(variable_duration) - OpusFramesizeHelpers.GetOrdinal(OpusFramesize.OPUS_FRAMESIZE_2_5_MS)); - } else { - return -1; - } - if (new_size > frame_size) { - return -1; - } - if (400 * new_size != Fs && 200 * new_size != Fs && 100 * new_size != Fs && 50 * new_size != Fs && 25 * new_size != Fs && 50 * new_size != 3 * Fs) { - return -1; - } - return new_size; - } - - static int compute_frame_size(short[] analysis_pcm, int analysis_pcm_ptr, int frame_size, OpusFramesize variable_duration, int C, int Fs, int bitrate_bps, int delay_compensation, float[] subframe_mem, boolean analysis_enabled) { - if (analysis_enabled && variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs / 200) { - int LM = 3; - LM = CodecHelpers.optimize_framesize(analysis_pcm, analysis_pcm_ptr, frame_size, C, Fs, bitrate_bps, 0, subframe_mem, delay_compensation); - while (Fs / 400 << LM > frame_size) { - --LM; - } - frame_size = Fs / 400 << LM; - } else { - frame_size = CodecHelpers.frame_size_select(frame_size, variable_duration, Fs); - } - if (frame_size < 0) { - return -1; - } - return frame_size; - } - - static int compute_stereo_width(short[] pcm, int pcm_ptr, int frame_size, int Fs, StereoWidthState mem) { - int frame_rate = Fs / frame_size; - int short_alpha = Short.MAX_VALUE - 819175 / Inlines.IMAX(50, frame_rate); - int yy = 0; - int xy = 0; - int xx = 0; - for (int i = 0; i < frame_size - 3; i += 4) { - int pxx = 0; - int pxy = 0; - int pyy = 0; - int p2i = pcm_ptr + 2 * i; - short x = pcm[p2i]; - short y = pcm[p2i + 1]; - pxx = Inlines.SHR32(Inlines.MULT16_16((int)x, (int)x), 2); - pxy = Inlines.SHR32(Inlines.MULT16_16((int)x, (int)y), 2); - pyy = Inlines.SHR32(Inlines.MULT16_16((int)y, (int)y), 2); - x = pcm[p2i + 2]; - y = pcm[p2i + 3]; - pxx += Inlines.SHR32(Inlines.MULT16_16((int)x, (int)x), 2); - pxy += Inlines.SHR32(Inlines.MULT16_16((int)x, (int)y), 2); - pyy += Inlines.SHR32(Inlines.MULT16_16((int)y, (int)y), 2); - x = pcm[p2i + 4]; - y = pcm[p2i + 5]; - pxx += Inlines.SHR32(Inlines.MULT16_16((int)x, (int)x), 2); - pxy += Inlines.SHR32(Inlines.MULT16_16((int)x, (int)y), 2); - pyy += Inlines.SHR32(Inlines.MULT16_16((int)y, (int)y), 2); - x = pcm[p2i + 6]; - y = pcm[p2i + 7]; - xx += Inlines.SHR32(pxx += Inlines.SHR32(Inlines.MULT16_16((int)x, (int)x), 2), 10); - xy += Inlines.SHR32(pxy += Inlines.SHR32(Inlines.MULT16_16((int)x, (int)y), 2), 10); - yy += Inlines.SHR32(pyy += Inlines.SHR32(Inlines.MULT16_16((int)y, (int)y), 2), 10); - } - mem.XX += Inlines.MULT16_32_Q15(short_alpha, xx - mem.XX); - mem.XY += Inlines.MULT16_32_Q15(short_alpha, xy - mem.XY); - mem.YY += Inlines.MULT16_32_Q15(short_alpha, yy - mem.YY); - mem.XX = Inlines.MAX32(0, mem.XX); - mem.XY = Inlines.MAX32(0, mem.XY); - mem.YY = Inlines.MAX32(0, mem.YY); - if (Inlines.MAX32(mem.XX, mem.YY) > 210) { - int sqrt_xx = Inlines.celt_sqrt(mem.XX); - int sqrt_yy = Inlines.celt_sqrt(mem.YY); - int qrrt_xx = Inlines.celt_sqrt(sqrt_xx); - int qrrt_yy = Inlines.celt_sqrt(sqrt_yy); - mem.XY = Inlines.MIN32(mem.XY, sqrt_xx * sqrt_yy); - int corr = Inlines.SHR32(Inlines.frac_div32(mem.XY, 1 + Inlines.MULT16_16(sqrt_xx, sqrt_yy)), 16); - int ldiff = Short.MAX_VALUE * Inlines.ABS16(qrrt_xx - qrrt_yy) / (1 + qrrt_xx + qrrt_yy); - int width = Inlines.MULT16_16_Q15(Inlines.celt_sqrt(0x40000000 - Inlines.MULT16_16(corr, corr)), ldiff); - mem.smoothed_width += (width - mem.smoothed_width) / frame_rate; - mem.max_follower = Inlines.MAX16(mem.max_follower - 655 / frame_rate, mem.smoothed_width); - } else { - boolean width = false; - int corr = Short.MAX_VALUE; - boolean ldiff = false; - } - return Inlines.EXTRACT16(Inlines.MIN32(Short.MAX_VALUE, 20 * mem.max_follower)); - } - - static void smooth_fade(short[] in1, int in1_ptr, short[] in2, int in2_ptr, short[] output, int output_ptr, int overlap, int channels, int[] window, int Fs) { - int inc = 48000 / Fs; - for (int c = 0; c < channels; ++c) { - for (int i = 0; i < overlap; ++i) { - int w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]); - output[output_ptr + i * channels + c] = (short)Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, (int)in2[in2_ptr + i * channels + c]), Short.MAX_VALUE - w, (int)in1[in1_ptr + i * channels + c]), 15); - } - } - } - - public static String opus_strerror(int error) { - String[] error_strings = new String[]{"success", "invalid argument", "buffer too small", "error", "corrupted stream", "request not implemented", "invalid state", "memory allocation failed"}; - if (error > 0 || error < -7) { - return "unknown error"; - } - return error_strings[-error]; - } - - public static String GetVersionString() { - return "concentus 1.0a-java-fixed"; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/CorrelateMatrix.java b/source/decompiled/de/maxhenkel/voicechat/concentus/CorrelateMatrix.java deleted file mode 100644 index ba1197f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/CorrelateMatrix.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SumSqrShift; - -class CorrelateMatrix { - CorrelateMatrix() { - } - - static void silk_corrVector(short[] x, int x_ptr, short[] t, int t_ptr, int L, int order, int[] Xt, int rshifts) { - int ptr1 = x_ptr + order - 1; - int ptr2 = t_ptr; - if (rshifts > 0) { - for (int lag = 0; lag < order; ++lag) { - int inner_prod = 0; - for (int i = 0; i < L; ++i) { - inner_prod += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + i], t[ptr2 + i]), rshifts); - } - Xt[lag] = inner_prod; - --ptr1; - } - } else { - Inlines.OpusAssert(rshifts == 0); - for (int lag = 0; lag < order; ++lag) { - Xt[lag] = Inlines.silk_inner_prod(x, ptr1, t, ptr2, L); - --ptr1; - } - } - } - - static void silk_corrMatrix(short[] x, int x_ptr, int L, int order, int head_room, int[] XX, int XX_ptr, BoxedValueInt rshifts) { - int j; - int i; - BoxedValueInt boxed_energy = new BoxedValueInt(0); - BoxedValueInt boxed_rshifts_local = new BoxedValueInt(0); - SumSqrShift.silk_sum_sqr_shift(boxed_energy, boxed_rshifts_local, x, x_ptr, L + order - 1); - int energy = boxed_energy.Val; - int rshifts_local = boxed_rshifts_local.Val; - int head_room_rshifts = Inlines.silk_max(head_room - Inlines.silk_CLZ32(energy), 0); - energy = Inlines.silk_RSHIFT32(energy, head_room_rshifts); - rshifts_local += head_room_rshifts; - for (i = x_ptr; i < x_ptr + order - 1; ++i) { - energy -= Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[i], x[i]), rshifts_local); - } - if (rshifts_local < rshifts.Val) { - energy = Inlines.silk_RSHIFT32(energy, rshifts.Val - rshifts_local); - rshifts_local = rshifts.Val; - } - Inlines.MatrixSet(XX, XX_ptr, 0, 0, order, energy); - int ptr1 = x_ptr + order - 1; - for (j = 1; j < order; ++j) { - energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + L - j], x[ptr1 + L - j]), rshifts_local)); - energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 - j], x[ptr1 - j]), rshifts_local)); - Inlines.MatrixSet(XX, XX_ptr, j, j, order, energy); - } - int ptr2 = x_ptr + order - 2; - if (rshifts_local > 0) { - for (int lag = 1; lag < order; ++lag) { - energy = 0; - for (i = 0; i < L; ++i) { - energy += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + i], x[ptr2 + i]), rshifts_local); - } - Inlines.MatrixSet(XX, XX_ptr, lag, 0, order, energy); - Inlines.MatrixSet(XX, XX_ptr, 0, lag, order, energy); - for (j = 1; j < order - lag; ++j) { - energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + L - j], x[ptr2 + L - j]), rshifts_local)); - energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 - j], x[ptr2 - j]), rshifts_local)); - Inlines.MatrixSet(XX, XX_ptr, lag + j, j, order, energy); - Inlines.MatrixSet(XX, XX_ptr, j, lag + j, order, energy); - } - --ptr2; - } - } else { - for (int lag = 1; lag < order; ++lag) { - energy = Inlines.silk_inner_prod(x, ptr1, x, ptr2, L); - Inlines.MatrixSet(XX, XX_ptr, lag, 0, order, energy); - Inlines.MatrixSet(XX, XX_ptr, 0, lag, order, energy); - for (j = 1; j < order - lag; ++j) { - energy = Inlines.silk_SUB32(energy, Inlines.silk_SMULBB(x[ptr1 + L - j], x[ptr2 + L - j])); - energy = Inlines.silk_SMLABB(energy, x[ptr1 - j], x[ptr2 - j]); - Inlines.MatrixSet(XX, XX_ptr, lag + j, j, order, energy); - Inlines.MatrixSet(XX, XX_ptr, j, lag + j, order, energy); - } - --ptr2; - } - } - rshifts.Val = rshifts_local; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/DecControlState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/DecControlState.java deleted file mode 100644 index 048b1bc..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/DecControlState.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class DecControlState { - int nChannelsAPI = 0; - int nChannelsInternal = 0; - int API_sampleRate = 0; - int internalSampleRate = 0; - int payloadSize_ms = 0; - int prevPitchLag = 0; - - DecControlState() { - } - - void Reset() { - this.nChannelsAPI = 0; - this.nChannelsInternal = 0; - this.API_sampleRate = 0; - this.internalSampleRate = 0; - this.payloadSize_ms = 0; - this.prevPitchLag = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeAPI.java b/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeAPI.java deleted file mode 100644 index ba9205d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeAPI.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.DecControlState; -import de.maxhenkel.voicechat.concentus.DecodeIndices; -import de.maxhenkel.voicechat.concentus.DecodePulses; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Resampler; -import de.maxhenkel.voicechat.concentus.SilkChannelDecoder; -import de.maxhenkel.voicechat.concentus.SilkDecoder; -import de.maxhenkel.voicechat.concentus.SilkError; -import de.maxhenkel.voicechat.concentus.SilkTables; -import de.maxhenkel.voicechat.concentus.Stereo; - -class DecodeAPI { - DecodeAPI() { - } - - static int silk_InitDecoder(SilkDecoder decState) { - decState.Reset(); - int ret = SilkError.SILK_NO_ERROR; - SilkChannelDecoder[] channel_states = decState.channel_state; - for (int n = 0; n < 2; ++n) { - ret = channel_states[n].silk_init_decoder(); - } - decState.sStereo.Reset(); - decState.prev_decode_only_middle = 0; - return ret; - } - - static int silk_Decode(SilkDecoder psDec, DecControlState decControl, int lostFlag, int newPacketFlag, EntropyCoder psRangeDec, short[] samplesOut, int samplesOut_ptr, BoxedValueInt nSamplesOut) { - int resample_out_ptr; - short[] resample_out; - short[] samplesOut_tmp; - boolean delay_stack_alloc; - int condCoding; - int i; - boolean stereo_to_mono; - int n; - int decode_only_middle = 0; - int ret = SilkError.SILK_NO_ERROR; - BoxedValueInt nSamplesOutDec = new BoxedValueInt(0); - int[] samplesOut_tmp_ptrs = new int[2]; - int[] MS_pred_Q13 = new int[]{0, 0}; - SilkChannelDecoder[] channel_state = psDec.channel_state; - nSamplesOut.Val = 0; - Inlines.OpusAssert(decControl.nChannelsInternal == 1 || decControl.nChannelsInternal == 2); - if (newPacketFlag != 0) { - for (n = 0; n < decControl.nChannelsInternal; ++n) { - channel_state[n].nFramesDecoded = 0; - } - } - if (decControl.nChannelsInternal > psDec.nChannelsInternal) { - ret += channel_state[1].silk_init_decoder(); - } - boolean bl = stereo_to_mono = decControl.nChannelsInternal == 1 && psDec.nChannelsInternal == 2 && decControl.internalSampleRate == 1000 * channel_state[0].fs_kHz; - if (channel_state[0].nFramesDecoded == 0) { - for (n = 0; n < decControl.nChannelsInternal; ++n) { - if (decControl.payloadSize_ms == 0) { - channel_state[n].nFramesPerPacket = 1; - channel_state[n].nb_subfr = 2; - } else if (decControl.payloadSize_ms == 10) { - channel_state[n].nFramesPerPacket = 1; - channel_state[n].nb_subfr = 2; - } else if (decControl.payloadSize_ms == 20) { - channel_state[n].nFramesPerPacket = 1; - channel_state[n].nb_subfr = 4; - } else if (decControl.payloadSize_ms == 40) { - channel_state[n].nFramesPerPacket = 2; - channel_state[n].nb_subfr = 4; - } else if (decControl.payloadSize_ms == 60) { - channel_state[n].nFramesPerPacket = 3; - channel_state[n].nb_subfr = 4; - } else { - Inlines.OpusAssert(false); - return SilkError.SILK_DEC_INVALID_FRAME_SIZE; - } - int fs_kHz_dec = (decControl.internalSampleRate >> 10) + 1; - if (fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16) { - Inlines.OpusAssert(false); - return SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY; - } - ret += channel_state[n].silk_decoder_set_fs(fs_kHz_dec, decControl.API_sampleRate); - } - } - if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2 && (psDec.nChannelsAPI == 1 || psDec.nChannelsInternal == 1)) { - Arrays.MemSet(psDec.sStereo.pred_prev_Q13, (short)0, 2); - Arrays.MemSet(psDec.sStereo.sSide, (short)0, 2); - channel_state[1].resampler_state.Assign(channel_state[0].resampler_state); - } - psDec.nChannelsAPI = decControl.nChannelsAPI; - psDec.nChannelsInternal = decControl.nChannelsInternal; - if (decControl.API_sampleRate > 48000 || decControl.API_sampleRate < 8000) { - ret = SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY; - return ret; - } - if (lostFlag != 1 && channel_state[0].nFramesDecoded == 0) { - for (n = 0; n < decControl.nChannelsInternal; ++n) { - for (i = 0; i < channel_state[n].nFramesPerPacket; ++i) { - channel_state[n].VAD_flags[i] = psRangeDec.dec_bit_logp(1L); - } - channel_state[n].LBRR_flag = psRangeDec.dec_bit_logp(1L); - } - for (n = 0; n < decControl.nChannelsInternal; ++n) { - Arrays.MemSet(channel_state[n].LBRR_flags, 0, 3); - if (channel_state[n].LBRR_flag == 0) continue; - if (channel_state[n].nFramesPerPacket == 1) { - channel_state[n].LBRR_flags[0] = 1; - continue; - } - int LBRR_symbol = psRangeDec.dec_icdf(SilkTables.silk_LBRR_flags_iCDF_ptr[channel_state[n].nFramesPerPacket - 2], 8) + 1; - for (i = 0; i < channel_state[n].nFramesPerPacket; ++i) { - channel_state[n].LBRR_flags[i] = Inlines.silk_RSHIFT(LBRR_symbol, i) & 1; - } - } - if (lostFlag == 0) { - for (i = 0; i < channel_state[0].nFramesPerPacket; ++i) { - for (n = 0; n < decControl.nChannelsInternal; ++n) { - if (channel_state[n].LBRR_flags[i] == 0) continue; - short[] pulses = new short[320]; - if (decControl.nChannelsInternal == 2 && n == 0) { - Stereo.silk_stereo_decode_pred(psRangeDec, MS_pred_Q13); - if (channel_state[1].LBRR_flags[i] == 0) { - BoxedValueInt decodeOnlyMiddleBoxed = new BoxedValueInt(decode_only_middle); - Stereo.silk_stereo_decode_mid_only(psRangeDec, decodeOnlyMiddleBoxed); - decode_only_middle = decodeOnlyMiddleBoxed.Val; - } - } - condCoding = i > 0 && channel_state[n].LBRR_flags[i - 1] != 0 ? 2 : 0; - DecodeIndices.silk_decode_indices(channel_state[n], psRangeDec, i, 1, condCoding); - DecodePulses.silk_decode_pulses(psRangeDec, pulses, channel_state[n].indices.signalType, channel_state[n].indices.quantOffsetType, channel_state[n].frame_length); - } - } - } - } - if (decControl.nChannelsInternal == 2) { - if (lostFlag == 0 || lostFlag == 2 && channel_state[0].LBRR_flags[channel_state[0].nFramesDecoded] == 1) { - Stereo.silk_stereo_decode_pred(psRangeDec, MS_pred_Q13); - if (lostFlag == 0 && channel_state[1].VAD_flags[channel_state[0].nFramesDecoded] == 0 || lostFlag == 2 && channel_state[1].LBRR_flags[channel_state[0].nFramesDecoded] == 0) { - BoxedValueInt decodeOnlyMiddleBoxed = new BoxedValueInt(decode_only_middle); - Stereo.silk_stereo_decode_mid_only(psRangeDec, decodeOnlyMiddleBoxed); - decode_only_middle = decodeOnlyMiddleBoxed.Val; - } else { - decode_only_middle = 0; - } - } else { - for (n = 0; n < 2; ++n) { - MS_pred_Q13[n] = psDec.sStereo.pred_prev_Q13[n]; - } - } - } - if (decControl.nChannelsInternal == 2 && decode_only_middle == 0 && psDec.prev_decode_only_middle == 1) { - Arrays.MemSet(psDec.channel_state[1].outBuf, (short)0, 480); - Arrays.MemSet(psDec.channel_state[1].sLPC_Q14_buf, 0, 16); - psDec.channel_state[1].lagPrev = 100; - psDec.channel_state[1].LastGainIndex = (byte)10; - psDec.channel_state[1].prevSignalType = 0; - psDec.channel_state[1].first_frame_after_reset = 1; - } - boolean bl2 = delay_stack_alloc = decControl.internalSampleRate * decControl.nChannelsInternal < decControl.API_sampleRate * decControl.nChannelsAPI; - if (delay_stack_alloc) { - samplesOut_tmp = samplesOut; - samplesOut_tmp_ptrs[0] = samplesOut_ptr; - samplesOut_tmp_ptrs[1] = samplesOut_ptr + channel_state[0].frame_length + 2; - } else { - short[] samplesOut1_tmp_storage1 = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)]; - samplesOut_tmp = samplesOut1_tmp_storage1; - samplesOut_tmp_ptrs[0] = 0; - samplesOut_tmp_ptrs[1] = channel_state[0].frame_length + 2; - } - boolean has_side = lostFlag == 0 ? decode_only_middle == 0 : psDec.prev_decode_only_middle == 0 || decControl.nChannelsInternal == 2 && lostFlag == 2 && channel_state[1].LBRR_flags[channel_state[1].nFramesDecoded] == 1; - for (n = 0; n < decControl.nChannelsInternal; ++n) { - if (n == 0 || has_side) { - int FrameIndex = channel_state[0].nFramesDecoded - n; - condCoding = FrameIndex <= 0 ? 0 : (lostFlag == 2 ? (channel_state[n].LBRR_flags[FrameIndex - 1] != 0 ? 2 : 0) : (n > 0 && psDec.prev_decode_only_middle != 0 ? 1 : 2)); - ret += channel_state[n].silk_decode_frame(psRangeDec, samplesOut_tmp, samplesOut_tmp_ptrs[n] + 2, nSamplesOutDec, lostFlag, condCoding); - } else { - Arrays.MemSetWithOffset(samplesOut_tmp, (short)0, samplesOut_tmp_ptrs[n] + 2, nSamplesOutDec.Val); - } - ++channel_state[n].nFramesDecoded; - } - if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2) { - Stereo.silk_stereo_MS_to_LR(psDec.sStereo, samplesOut_tmp, samplesOut_tmp_ptrs[0], samplesOut_tmp, samplesOut_tmp_ptrs[1], MS_pred_Q13, channel_state[0].fs_kHz, nSamplesOutDec.Val); - } else { - System.arraycopy(psDec.sStereo.sMid, 0, samplesOut_tmp, samplesOut_tmp_ptrs[0], 2); - System.arraycopy(samplesOut_tmp, samplesOut_tmp_ptrs[0] + nSamplesOutDec.Val, psDec.sStereo.sMid, 0, 2); - } - nSamplesOut.Val = Inlines.silk_DIV32(nSamplesOutDec.Val * decControl.API_sampleRate, Inlines.silk_SMULBB(channel_state[0].fs_kHz, 1000)); - if (decControl.nChannelsAPI == 2) { - short[] samplesOut2_tmp = new short[nSamplesOut.Val]; - resample_out = samplesOut2_tmp; - resample_out_ptr = 0; - } else { - resample_out = samplesOut; - resample_out_ptr = samplesOut_ptr; - } - if (delay_stack_alloc) { - short[] samplesOut1_tmp_storage2 = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)]; - System.arraycopy(samplesOut, samplesOut_ptr, samplesOut1_tmp_storage2, 0, decControl.nChannelsInternal * (channel_state[0].frame_length + 2)); - samplesOut_tmp = samplesOut1_tmp_storage2; - samplesOut_tmp_ptrs[0] = 0; - samplesOut_tmp_ptrs[1] = channel_state[0].frame_length + 2; - } - for (n = 0; n < Inlines.silk_min(decControl.nChannelsAPI, decControl.nChannelsInternal); ++n) { - ret += Resampler.silk_resampler(channel_state[n].resampler_state, resample_out, resample_out_ptr, samplesOut_tmp, samplesOut_tmp_ptrs[n] + 1, nSamplesOutDec.Val); - if (decControl.nChannelsAPI != 2) continue; - int nptr = samplesOut_ptr + n; - for (i = 0; i < nSamplesOut.Val; ++i) { - samplesOut[nptr + 2 * i] = resample_out[resample_out_ptr + i]; - } - } - if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 1) { - if (stereo_to_mono) { - ret += Resampler.silk_resampler(channel_state[1].resampler_state, resample_out, resample_out_ptr, samplesOut_tmp, samplesOut_tmp_ptrs[0] + 1, nSamplesOutDec.Val); - for (i = 0; i < nSamplesOut.Val; ++i) { - samplesOut[samplesOut_ptr + 1 + 2 * i] = resample_out[resample_out_ptr + i]; - } - } else { - for (i = 0; i < nSamplesOut.Val; ++i) { - samplesOut[samplesOut_ptr + 1 + 2 * i] = samplesOut[samplesOut_ptr + 2 * i]; - } - } - } - if (channel_state[0].prevSignalType == 2) { - int[] mult_tab = new int[]{6, 4, 3}; - decControl.prevPitchLag = channel_state[0].lagPrev * mult_tab[channel_state[0].fs_kHz - 8 >> 2]; - } else { - decControl.prevPitchLag = 0; - } - if (lostFlag == 1) { - for (i = 0; i < psDec.nChannelsInternal; ++i) { - psDec.channel_state[i].LastGainIndex = (byte)10; - } - } else { - psDec.prev_decode_only_middle = decode_only_middle; - } - return ret; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeCore.java b/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeCore.java deleted file mode 100644 index e038e59..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeCore.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkChannelDecoder; -import de.maxhenkel.voicechat.concentus.SilkDecoderControl; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class DecodeCore { - DecodeCore() { - } - - static void silk_decode_core(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, short[] xq, int xq_ptr, short[] pulses) { - int i; - int lag = 0; - short[] B_Q14 = psDecCtrl.LTPCoef_Q14; - Inlines.OpusAssert(psDec.prev_gain_Q16 != 0); - short[] sLTP = new short[psDec.ltp_mem_length]; - int[] sLTP_Q15 = new int[psDec.ltp_mem_length + psDec.frame_length]; - int[] res_Q14 = new int[psDec.subfr_length]; - int[] sLPC_Q14 = new int[psDec.subfr_length + 16]; - short offset_Q10 = SilkTables.silk_Quantization_Offsets_Q10[psDec.indices.signalType >> 1][psDec.indices.quantOffsetType]; - boolean NLSF_interpolation_flag = psDec.indices.NLSFInterpCoef_Q2 < 4; - int rand_seed = psDec.indices.Seed; - for (i = 0; i < psDec.frame_length; ++i) { - rand_seed = Inlines.silk_RAND(rand_seed); - psDec.exc_Q14[i] = Inlines.silk_LSHIFT(pulses[i], 14); - if (psDec.exc_Q14[i] > 0) { - int n = i; - psDec.exc_Q14[n] = psDec.exc_Q14[n] - 1280; - } else if (psDec.exc_Q14[i] < 0) { - int n = i; - psDec.exc_Q14[n] = psDec.exc_Q14[n] + 1280; - } - int n = i; - psDec.exc_Q14[n] = psDec.exc_Q14[n] + (offset_Q10 << 4); - if (rand_seed < 0) { - psDec.exc_Q14[i] = -psDec.exc_Q14[i]; - } - rand_seed = Inlines.silk_ADD32_ovflw(rand_seed, pulses[i]); - } - System.arraycopy(psDec.sLPC_Q14_buf, 0, sLPC_Q14, 0, 16); - int pexc_Q14 = 0; - int pxq = xq_ptr; - int sLTP_buf_idx = psDec.ltp_mem_length; - for (int k = 0; k < psDec.nb_subfr; ++k) { - int gain_adj_Q16; - int[] pres_Q14 = res_Q14; - int pres_Q14_ptr = 0; - short[] A_Q12 = psDecCtrl.PredCoef_Q12[k >> 1]; - int B_Q14_ptr = k * 5; - int signalType = psDec.indices.signalType; - int Gain_Q10 = Inlines.silk_RSHIFT(psDecCtrl.Gains_Q16[k], 6); - int inv_gain_Q31 = Inlines.silk_INVERSE32_varQ(psDecCtrl.Gains_Q16[k], 47); - if (psDecCtrl.Gains_Q16[k] != psDec.prev_gain_Q16) { - gain_adj_Q16 = Inlines.silk_DIV32_varQ(psDec.prev_gain_Q16, psDecCtrl.Gains_Q16[k], 16); - for (i = 0; i < 16; ++i) { - sLPC_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, sLPC_Q14[i]); - } - } else { - gain_adj_Q16 = 65536; - } - Inlines.OpusAssert(inv_gain_Q31 != 0); - psDec.prev_gain_Q16 = psDecCtrl.Gains_Q16[k]; - if (psDec.lossCnt != 0 && psDec.prevSignalType == 2 && psDec.indices.signalType != 2 && k < 2) { - Arrays.MemSetWithOffset(B_Q14, (short)0, B_Q14_ptr, 5); - B_Q14[B_Q14_ptr + 2] = 4096; - signalType = 2; - psDecCtrl.pitchL[k] = psDec.lagPrev; - } - if (signalType == 2) { - lag = psDecCtrl.pitchL[k]; - if (k == 0 || k == 2 && NLSF_interpolation_flag) { - int start_idx = psDec.ltp_mem_length - lag - psDec.LPC_order - 2; - Inlines.OpusAssert(start_idx > 0); - if (k == 2) { - System.arraycopy(xq, xq_ptr, psDec.outBuf, psDec.ltp_mem_length, 2 * psDec.subfr_length); - } - Filters.silk_LPC_analysis_filter(sLTP, start_idx, psDec.outBuf, start_idx + k * psDec.subfr_length, A_Q12, 0, psDec.ltp_mem_length - start_idx, psDec.LPC_order); - if (k == 0) { - inv_gain_Q31 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(inv_gain_Q31, psDecCtrl.LTP_scale_Q14), 2); - } - for (i = 0; i < lag + 2; ++i) { - sLTP_Q15[sLTP_buf_idx - i - 1] = Inlines.silk_SMULWB(inv_gain_Q31, sLTP[psDec.ltp_mem_length - i - 1]); - } - } else if (gain_adj_Q16 != 65536) { - for (i = 0; i < lag + 2; ++i) { - sLTP_Q15[sLTP_buf_idx - i - 1] = Inlines.silk_SMULWW(gain_adj_Q16, sLTP_Q15[sLTP_buf_idx - i - 1]); - } - } - } - if (signalType == 2) { - int pred_lag_ptr = sLTP_buf_idx - lag + 2; - for (i = 0; i < psDec.subfr_length; ++i) { - int LTP_pred_Q13 = 2; - LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr], B_Q14[B_Q14_ptr]); - LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 1], B_Q14[B_Q14_ptr + 1]); - LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 2], B_Q14[B_Q14_ptr + 2]); - LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 3], B_Q14[B_Q14_ptr + 3]); - LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 4], B_Q14[B_Q14_ptr + 4]); - ++pred_lag_ptr; - pres_Q14[pres_Q14_ptr + i] = Inlines.silk_ADD_LSHIFT32(psDec.exc_Q14[pexc_Q14 + i], LTP_pred_Q13, 1); - sLTP_Q15[sLTP_buf_idx] = Inlines.silk_LSHIFT(pres_Q14[pres_Q14_ptr + i], 1); - ++sLTP_buf_idx; - } - } else { - pres_Q14 = psDec.exc_Q14; - pres_Q14_ptr = pexc_Q14; - } - for (i = 0; i < psDec.subfr_length; ++i) { - Inlines.OpusAssert(psDec.LPC_order == 10 || psDec.LPC_order == 16); - int LPC_pred_Q10 = Inlines.silk_RSHIFT(psDec.LPC_order, 1); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 1], A_Q12[0]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 2], A_Q12[1]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 3], A_Q12[2]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 4], A_Q12[3]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 5], A_Q12[4]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 6], A_Q12[5]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 7], A_Q12[6]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 8], A_Q12[7]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 9], A_Q12[8]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 10], A_Q12[9]); - if (psDec.LPC_order == 16) { - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 11], A_Q12[10]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 12], A_Q12[11]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 13], A_Q12[12]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 14], A_Q12[13]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 15], A_Q12[14]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[16 + i - 16], A_Q12[15]); - } - sLPC_Q14[16 + i] = Inlines.silk_ADD_LSHIFT32(pres_Q14[pres_Q14_ptr + i], LPC_pred_Q10, 4); - xq[pxq + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(sLPC_Q14[16 + i], Gain_Q10), 8)); - } - System.arraycopy(sLPC_Q14, psDec.subfr_length, sLPC_Q14, 0, 16); - pexc_Q14 += psDec.subfr_length; - pxq += psDec.subfr_length; - } - System.arraycopy(sLPC_Q14, 0, psDec.sLPC_Q14_buf, 0, 16); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeIndices.java b/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeIndices.java deleted file mode 100644 index d15da8f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeIndices.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.NLSF; -import de.maxhenkel.voicechat.concentus.SilkChannelDecoder; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class DecodeIndices { - DecodeIndices() { - } - - static void silk_decode_indices(SilkChannelDecoder psDec, EntropyCoder psRangeDec, int FrameIndex, int decode_LBRR, int condCoding) { - int i; - short[] ec_ix = new short[psDec.LPC_order]; - short[] pred_Q8 = new short[psDec.LPC_order]; - int Ix = decode_LBRR != 0 || psDec.VAD_flags[FrameIndex] != 0 ? psRangeDec.dec_icdf(SilkTables.silk_type_offset_VAD_iCDF, 8) + 2 : psRangeDec.dec_icdf(SilkTables.silk_type_offset_no_VAD_iCDF, 8); - psDec.indices.signalType = (byte)Inlines.silk_RSHIFT(Ix, 1); - psDec.indices.quantOffsetType = (byte)(Ix & 1); - if (condCoding == 2) { - psDec.indices.GainsIndices[0] = (byte)psRangeDec.dec_icdf(SilkTables.silk_delta_gain_iCDF, 8); - } else { - psDec.indices.GainsIndices[0] = (byte)Inlines.silk_LSHIFT(psRangeDec.dec_icdf(SilkTables.silk_gain_iCDF[psDec.indices.signalType], 8), 3); - psDec.indices.GainsIndices[0] = (byte)(psDec.indices.GainsIndices[0] + (byte)psRangeDec.dec_icdf(SilkTables.silk_uniform8_iCDF, 8)); - } - for (i = 1; i < psDec.nb_subfr; ++i) { - psDec.indices.GainsIndices[i] = (byte)psRangeDec.dec_icdf(SilkTables.silk_delta_gain_iCDF, 8); - } - psDec.indices.NLSFIndices[0] = (byte)psRangeDec.dec_icdf(psDec.psNLSF_CB.CB1_iCDF, (psDec.indices.signalType >> 1) * psDec.psNLSF_CB.nVectors, 8); - NLSF.silk_NLSF_unpack(ec_ix, pred_Q8, psDec.psNLSF_CB, psDec.indices.NLSFIndices[0]); - Inlines.OpusAssert(psDec.psNLSF_CB.order == psDec.LPC_order); - for (i = 0; i < psDec.psNLSF_CB.order; ++i) { - Ix = psRangeDec.dec_icdf(psDec.psNLSF_CB.ec_iCDF, ec_ix[i], 8); - if (Ix == 0) { - Ix -= psRangeDec.dec_icdf(SilkTables.silk_NLSF_EXT_iCDF, 8); - } else if (Ix == 8) { - Ix += psRangeDec.dec_icdf(SilkTables.silk_NLSF_EXT_iCDF, 8); - } - psDec.indices.NLSFIndices[i + 1] = (byte)(Ix - 4); - } - psDec.indices.NLSFInterpCoef_Q2 = psDec.nb_subfr == 4 ? (byte)psRangeDec.dec_icdf(SilkTables.silk_NLSF_interpolation_factor_iCDF, 8) : (byte)4; - if (psDec.indices.signalType == 2) { - int delta_lagIndex; - boolean decode_absolute_lagIndex = true; - if (condCoding == 2 && psDec.ec_prevSignalType == 2 && (delta_lagIndex = (int)psRangeDec.dec_icdf(SilkTables.silk_pitch_delta_iCDF, 8)) > 0) { - psDec.indices.lagIndex = (short)(psDec.ec_prevLagIndex + (delta_lagIndex -= 9)); - decode_absolute_lagIndex = false; - } - if (decode_absolute_lagIndex) { - psDec.indices.lagIndex = (short)(psRangeDec.dec_icdf(SilkTables.silk_pitch_lag_iCDF, 8) * Inlines.silk_RSHIFT(psDec.fs_kHz, 1)); - psDec.indices.lagIndex = (short)(psDec.indices.lagIndex + (short)psRangeDec.dec_icdf(psDec.pitch_lag_low_bits_iCDF, 8)); - } - psDec.ec_prevLagIndex = psDec.indices.lagIndex; - psDec.indices.contourIndex = (byte)psRangeDec.dec_icdf(psDec.pitch_contour_iCDF, 8); - psDec.indices.PERIndex = (byte)psRangeDec.dec_icdf(SilkTables.silk_LTP_per_index_iCDF, 8); - for (int k = 0; k < psDec.nb_subfr; ++k) { - psDec.indices.LTPIndex[k] = (byte)psRangeDec.dec_icdf(SilkTables.silk_LTP_gain_iCDF_ptrs[psDec.indices.PERIndex], 8); - } - psDec.indices.LTP_scaleIndex = condCoding == 0 ? (byte)psRangeDec.dec_icdf(SilkTables.silk_LTPscale_iCDF, 8) : (byte)0; - } - psDec.ec_prevSignalType = psDec.indices.signalType; - psDec.indices.Seed = (byte)psRangeDec.dec_icdf(SilkTables.silk_uniform4_iCDF, 8); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeParameters.java b/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeParameters.java deleted file mode 100644 index 3f5b6cd..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodeParameters.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BWExpander; -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.DecodePitch; -import de.maxhenkel.voicechat.concentus.GainQuantization; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.NLSF; -import de.maxhenkel.voicechat.concentus.SilkChannelDecoder; -import de.maxhenkel.voicechat.concentus.SilkDecoderControl; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class DecodeParameters { - DecodeParameters() { - } - - static void silk_decode_parameters(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, int condCoding) { - int i; - short[] pNLSF_Q15 = new short[psDec.LPC_order]; - short[] pNLSF0_Q15 = new short[psDec.LPC_order]; - BoxedValueByte boxedLastGainIndex = new BoxedValueByte(psDec.LastGainIndex); - GainQuantization.silk_gains_dequant(psDecCtrl.Gains_Q16, psDec.indices.GainsIndices, boxedLastGainIndex, condCoding == 2 ? 1 : 0, psDec.nb_subfr); - psDec.LastGainIndex = boxedLastGainIndex.Val; - NLSF.silk_NLSF_decode(pNLSF_Q15, psDec.indices.NLSFIndices, psDec.psNLSF_CB); - NLSF.silk_NLSF2A(psDecCtrl.PredCoef_Q12[1], pNLSF_Q15, psDec.LPC_order); - if (psDec.first_frame_after_reset == 1) { - psDec.indices.NLSFInterpCoef_Q2 = (byte)4; - } - if (psDec.indices.NLSFInterpCoef_Q2 < 4) { - for (i = 0; i < psDec.LPC_order; ++i) { - pNLSF0_Q15[i] = (short)(psDec.prevNLSF_Q15[i] + Inlines.silk_RSHIFT(Inlines.silk_MUL(psDec.indices.NLSFInterpCoef_Q2, pNLSF_Q15[i] - psDec.prevNLSF_Q15[i]), 2)); - } - NLSF.silk_NLSF2A(psDecCtrl.PredCoef_Q12[0], pNLSF0_Q15, psDec.LPC_order); - } else { - System.arraycopy(psDecCtrl.PredCoef_Q12[1], 0, psDecCtrl.PredCoef_Q12[0], 0, psDec.LPC_order); - } - System.arraycopy(pNLSF_Q15, 0, psDec.prevNLSF_Q15, 0, psDec.LPC_order); - if (psDec.lossCnt != 0) { - BWExpander.silk_bwexpander(psDecCtrl.PredCoef_Q12[0], psDec.LPC_order, 63570); - BWExpander.silk_bwexpander(psDecCtrl.PredCoef_Q12[1], psDec.LPC_order, 63570); - } - if (psDec.indices.signalType == 2) { - byte Ix; - DecodePitch.silk_decode_pitch(psDec.indices.lagIndex, psDec.indices.contourIndex, psDecCtrl.pitchL, psDec.fs_kHz, psDec.nb_subfr); - byte[][] cbk_ptr_Q7 = SilkTables.silk_LTP_vq_ptrs_Q7[psDec.indices.PERIndex]; - for (int k = 0; k < psDec.nb_subfr; ++k) { - Ix = psDec.indices.LTPIndex[k]; - for (i = 0; i < 5; ++i) { - psDecCtrl.LTPCoef_Q14[k * 5 + i] = (short)Inlines.silk_LSHIFT(cbk_ptr_Q7[Ix][i], 7); - } - } - Ix = psDec.indices.LTP_scaleIndex; - psDecCtrl.LTP_scale_Q14 = SilkTables.silk_LTPScales_table_Q14[Ix]; - } else { - Arrays.MemSet(psDecCtrl.pitchL, 0, psDec.nb_subfr); - Arrays.MemSet(psDecCtrl.LTPCoef_Q14, (short)0, 5 * psDec.nb_subfr); - psDec.indices.PERIndex = 0; - psDecCtrl.LTP_scale_Q14 = 0; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodePitch.java b/source/decompiled/de/maxhenkel/voicechat/concentus/DecodePitch.java deleted file mode 100644 index 555f395..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodePitch.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class DecodePitch { - DecodePitch() { - } - - static void silk_decode_pitch(short lagIndex, byte contourIndex, int[] pitch_lags, int Fs_kHz, int nb_subfr) { - byte[][] Lag_CB_ptr; - if (Fs_kHz == 8) { - if (nb_subfr == 4) { - Lag_CB_ptr = SilkTables.silk_CB_lags_stage2; - } else { - Inlines.OpusAssert(nb_subfr == 2); - Lag_CB_ptr = SilkTables.silk_CB_lags_stage2_10_ms; - } - } else if (nb_subfr == 4) { - Lag_CB_ptr = SilkTables.silk_CB_lags_stage3; - } else { - Inlines.OpusAssert(nb_subfr == 2); - Lag_CB_ptr = SilkTables.silk_CB_lags_stage3_10_ms; - } - int min_lag = Inlines.silk_SMULBB(2, Fs_kHz); - int max_lag = Inlines.silk_SMULBB(18, Fs_kHz); - int lag = min_lag + lagIndex; - for (int k = 0; k < nb_subfr; ++k) { - pitch_lags[k] = lag + Lag_CB_ptr[k][contourIndex]; - pitch_lags[k] = Inlines.silk_LIMIT(pitch_lags[k], min_lag, max_lag); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodePulses.java b/source/decompiled/de/maxhenkel/voicechat/concentus/DecodePulses.java deleted file mode 100644 index c9daee8..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/DecodePulses.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.CodeSigns; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.ShellCoder; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class DecodePulses { - DecodePulses() { - } - - static void silk_decode_pulses(EntropyCoder psRangeDec, short[] pulses, int signalType, int quantOffsetType, int frame_length) { - int i; - int[] sum_pulses = new int[20]; - int[] nLshifts = new int[20]; - int RateLevelIndex = psRangeDec.dec_icdf(SilkTables.silk_rate_levels_iCDF[signalType >> 1], 8); - Inlines.OpusAssert(true); - int iter = Inlines.silk_RSHIFT(frame_length, 4); - if (iter * 16 < frame_length) { - Inlines.OpusAssert(frame_length == 120); - ++iter; - } - for (i = 0; i < iter; ++i) { - nLshifts[i] = 0; - sum_pulses[i] = psRangeDec.dec_icdf(SilkTables.silk_pulses_per_block_iCDF[RateLevelIndex], 8); - while (sum_pulses[i] == 17) { - int n = i; - nLshifts[n] = nLshifts[n] + 1; - sum_pulses[i] = psRangeDec.dec_icdf(SilkTables.silk_pulses_per_block_iCDF[9], nLshifts[i] == 10 ? 1 : 0, 8); - } - } - for (i = 0; i < iter; ++i) { - if (sum_pulses[i] > 0) { - ShellCoder.silk_shell_decoder(pulses, Inlines.silk_SMULBB(i, 16), psRangeDec, sum_pulses[i]); - continue; - } - Arrays.MemSetWithOffset(pulses, (short)0, Inlines.silk_SMULBB(i, 16), 16); - } - for (i = 0; i < iter; ++i) { - if (nLshifts[i] <= 0) continue; - int nLS = nLshifts[i]; - int pulses_ptr = Inlines.silk_SMULBB(i, 16); - for (int k = 0; k < 16; ++k) { - int abs_q = pulses[pulses_ptr + k]; - for (int j = 0; j < nLS; ++j) { - abs_q = Inlines.silk_LSHIFT(abs_q, 1); - abs_q += psRangeDec.dec_icdf(SilkTables.silk_lsb_iCDF, 8); - } - pulses[pulses_ptr + k] = (short)abs_q; - } - int n = i; - sum_pulses[n] = sum_pulses[n] | nLS << 5; - } - CodeSigns.silk_decode_signs(psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/DecoderAPIFlag.java b/source/decompiled/de/maxhenkel/voicechat/concentus/DecoderAPIFlag.java deleted file mode 100644 index 80363a7..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/DecoderAPIFlag.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class DecoderAPIFlag { - public static final int FLAG_DECODE_NORMAL = 0; - public static final int FLAG_PACKET_LOST = 1; - public static final int FLAG_DECODE_LBRR = 2; - - DecoderAPIFlag() { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Downmix.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Downmix.java deleted file mode 100644 index 33f05c3..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Downmix.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class Downmix { - Downmix() { - } - - static void downmix_int(short[] x, int x_ptr, int[] sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C) { - int j; - for (j = 0; j < subframe; ++j) { - sub[j + sub_ptr] = x[(j + offset) * C + c1]; - } - if (c2 > -1) { - for (j = 0; j < subframe; ++j) { - int n = j + sub_ptr; - sub[n] = sub[n] + x[(j + offset) * C + c2]; - } - } else if (c2 == -2) { - for (int c = 1; c < C; ++c) { - for (j = 0; j < subframe; ++j) { - int n = j + sub_ptr; - sub[n] = sub[n] + x[(j + offset) * C + c]; - } - } - } - int scale = 4096; - scale = C == -2 ? (scale /= C) : (scale /= 2); - for (j = 0; j < subframe; ++j) { - int n = j + sub_ptr; - sub[n] = sub[n] * scale; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/EncControlState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/EncControlState.java deleted file mode 100644 index 06db12e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/EncControlState.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkError; - -class EncControlState { - int nChannelsAPI = 0; - int nChannelsInternal = 0; - int API_sampleRate = 0; - int maxInternalSampleRate = 0; - int minInternalSampleRate = 0; - int desiredInternalSampleRate = 0; - int payloadSize_ms = 0; - int bitRate = 0; - int packetLossPercentage = 0; - int complexity = 0; - int useInBandFEC = 0; - int useDTX = 0; - int useCBR = 0; - int maxBits = 0; - int toMono = 0; - int opusCanSwitch = 0; - int reducedDependency = 0; - int internalSampleRate = 0; - int allowBandwidthSwitch = 0; - int inWBmodeWithoutVariableLP = 0; - int stereoWidth_Q14 = 0; - int switchReady = 0; - - EncControlState() { - } - - void Reset() { - this.nChannelsAPI = 0; - this.nChannelsInternal = 0; - this.API_sampleRate = 0; - this.maxInternalSampleRate = 0; - this.minInternalSampleRate = 0; - this.desiredInternalSampleRate = 0; - this.payloadSize_ms = 0; - this.bitRate = 0; - this.packetLossPercentage = 0; - this.complexity = 0; - this.useInBandFEC = 0; - this.useDTX = 0; - this.useCBR = 0; - this.maxBits = 0; - this.toMono = 0; - this.opusCanSwitch = 0; - this.reducedDependency = 0; - this.internalSampleRate = 0; - this.allowBandwidthSwitch = 0; - this.inWBmodeWithoutVariableLP = 0; - this.stereoWidth_Q14 = 0; - this.switchReady = 0; - } - - int check_control_input() { - if (this.API_sampleRate != 8000 && this.API_sampleRate != 12000 && this.API_sampleRate != 16000 && this.API_sampleRate != 24000 && this.API_sampleRate != 32000 && this.API_sampleRate != 44100 && this.API_sampleRate != 48000 || this.desiredInternalSampleRate != 8000 && this.desiredInternalSampleRate != 12000 && this.desiredInternalSampleRate != 16000 || this.maxInternalSampleRate != 8000 && this.maxInternalSampleRate != 12000 && this.maxInternalSampleRate != 16000 || this.minInternalSampleRate != 8000 && this.minInternalSampleRate != 12000 && this.minInternalSampleRate != 16000 || this.minInternalSampleRate > this.desiredInternalSampleRate || this.maxInternalSampleRate < this.desiredInternalSampleRate || this.minInternalSampleRate > this.maxInternalSampleRate) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_FS_NOT_SUPPORTED; - } - if (this.payloadSize_ms != 10 && this.payloadSize_ms != 20 && this.payloadSize_ms != 40 && this.payloadSize_ms != 60) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; - } - if (this.packetLossPercentage < 0 || this.packetLossPercentage > 100) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INVALID_LOSS_RATE; - } - if (this.useDTX < 0 || this.useDTX > 1) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INVALID_DTX_SETTING; - } - if (this.useCBR < 0 || this.useCBR > 1) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INVALID_CBR_SETTING; - } - if (this.useInBandFEC < 0 || this.useInBandFEC > 1) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INVALID_INBAND_FEC_SETTING; - } - if (this.nChannelsAPI < 1 || this.nChannelsAPI > 2) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; - } - if (this.nChannelsInternal < 1 || this.nChannelsInternal > 2) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; - } - if (this.nChannelsInternal > this.nChannelsAPI) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; - } - if (this.complexity < 0 || this.complexity > 10) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INVALID_COMPLEXITY_SETTING; - } - return SilkError.SILK_NO_ERROR; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/EncodeAPI.java b/source/decompiled/de/maxhenkel/voicechat/concentus/EncodeAPI.java deleted file mode 100644 index a804aa0..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/EncodeAPI.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.EncControlState; -import de.maxhenkel.voicechat.concentus.EncodeIndices; -import de.maxhenkel.voicechat.concentus.EncodePulses; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.HPVariableCutoff; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Resampler; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkEncoder; -import de.maxhenkel.voicechat.concentus.SilkError; -import de.maxhenkel.voicechat.concentus.SilkTables; -import de.maxhenkel.voicechat.concentus.Stereo; - -class EncodeAPI { - EncodeAPI() { - } - - static int silk_InitEncoder(SilkEncoder encState, EncControlState encStatus) { - int ret = SilkError.SILK_NO_ERROR; - encState.Reset(); - for (int n = 0; n < 2; ++n) { - Inlines.OpusAssert((ret += SilkEncoder.silk_init_encoder(encState.state_Fxx[n])) == SilkError.SILK_NO_ERROR); - } - encState.nChannelsAPI = 1; - encState.nChannelsInternal = 1; - Inlines.OpusAssert((ret += EncodeAPI.silk_QueryEncoder(encState, encStatus)) == SilkError.SILK_NO_ERROR); - return ret; - } - - static int silk_QueryEncoder(SilkEncoder encState, EncControlState encStatus) { - int ret = SilkError.SILK_NO_ERROR; - SilkChannelEncoder state_Fxx = encState.state_Fxx[0]; - encStatus.Reset(); - encStatus.nChannelsAPI = encState.nChannelsAPI; - encStatus.nChannelsInternal = encState.nChannelsInternal; - encStatus.API_sampleRate = state_Fxx.API_fs_Hz; - encStatus.maxInternalSampleRate = state_Fxx.maxInternal_fs_Hz; - encStatus.minInternalSampleRate = state_Fxx.minInternal_fs_Hz; - encStatus.desiredInternalSampleRate = state_Fxx.desiredInternal_fs_Hz; - encStatus.payloadSize_ms = state_Fxx.PacketSize_ms; - encStatus.bitRate = state_Fxx.TargetRate_bps; - encStatus.packetLossPercentage = state_Fxx.PacketLoss_perc; - encStatus.complexity = state_Fxx.Complexity; - encStatus.useInBandFEC = state_Fxx.useInBandFEC; - encStatus.useDTX = state_Fxx.useDTX; - encStatus.useCBR = state_Fxx.useCBR; - encStatus.internalSampleRate = Inlines.silk_SMULBB(state_Fxx.fs_kHz, 1000); - encStatus.allowBandwidthSwitch = state_Fxx.allow_bandwidth_switch; - encStatus.inWBmodeWithoutVariableLP = state_Fxx.fs_kHz == 16 && state_Fxx.sLP.mode == 0 ? 1 : 0; - return ret; - } - - static int silk_Encode(SilkEncoder psEnc, EncControlState encControl, short[] samplesIn, int nSamplesIn, EntropyCoder psRangeEnc, BoxedValueInt nBytesOut, int prefillFlag) { - int i; - int n; - int ret = SilkError.SILK_NO_ERROR; - int tmp_payloadSize_ms = 0; - int tmp_complexity = 0; - int nSamplesFromInput = 0; - int[] MStargetRates_bps = new int[2]; - nBytesOut.Val = 0; - if (encControl.reducedDependency != 0) { - psEnc.state_Fxx[0].first_frame_after_reset = 1; - psEnc.state_Fxx[1].first_frame_after_reset = 1; - } - psEnc.state_Fxx[1].nFramesEncoded = 0; - psEnc.state_Fxx[0].nFramesEncoded = 0; - if ((ret += encControl.check_control_input()) != SilkError.SILK_NO_ERROR) { - Inlines.OpusAssert(false); - return ret; - } - encControl.switchReady = 0; - if (encControl.nChannelsInternal > psEnc.nChannelsInternal) { - ret += SilkEncoder.silk_init_encoder(psEnc.state_Fxx[1]); - Arrays.MemSet(psEnc.sStereo.pred_prev_Q13, (short)0, 2); - Arrays.MemSet(psEnc.sStereo.sSide, (short)0, 2); - psEnc.sStereo.mid_side_amp_Q0[0] = 0; - psEnc.sStereo.mid_side_amp_Q0[1] = 1; - psEnc.sStereo.mid_side_amp_Q0[2] = 0; - psEnc.sStereo.mid_side_amp_Q0[3] = 1; - psEnc.sStereo.width_prev_Q14 = 0; - psEnc.sStereo.smth_width_Q14 = (short)16384; - if (psEnc.nChannelsAPI == 2) { - psEnc.state_Fxx[1].resampler_state.Assign(psEnc.state_Fxx[0].resampler_state); - System.arraycopy(psEnc.state_Fxx[0].In_HP_State, 0, psEnc.state_Fxx[1].In_HP_State, 0, 2); - } - } - boolean transition = encControl.payloadSize_ms != psEnc.state_Fxx[0].PacketSize_ms || psEnc.nChannelsInternal != encControl.nChannelsInternal; - psEnc.nChannelsAPI = encControl.nChannelsAPI; - psEnc.nChannelsInternal = encControl.nChannelsInternal; - int nBlocksOf10ms = Inlines.silk_DIV32(100 * nSamplesIn, encControl.API_sampleRate); - int tot_blocks = nBlocksOf10ms > 1 ? nBlocksOf10ms >> 1 : 1; - int curr_block = 0; - if (prefillFlag != 0) { - if (nBlocksOf10ms != 1) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; - } - for (n = 0; n < encControl.nChannelsInternal; ++n) { - Inlines.OpusAssert((ret += SilkEncoder.silk_init_encoder(psEnc.state_Fxx[n])) == SilkError.SILK_NO_ERROR); - } - tmp_payloadSize_ms = encControl.payloadSize_ms; - encControl.payloadSize_ms = 10; - tmp_complexity = encControl.complexity; - encControl.complexity = 0; - for (n = 0; n < encControl.nChannelsInternal; ++n) { - psEnc.state_Fxx[n].controlled_since_last_payload = 0; - psEnc.state_Fxx[n].prefillFlag = 1; - } - } else { - if (nBlocksOf10ms * encControl.API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; - } - if (1000 * nSamplesIn > encControl.payloadSize_ms * encControl.API_sampleRate) { - Inlines.OpusAssert(false); - return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; - } - } - int TargetRate_bps = Inlines.silk_RSHIFT32(encControl.bitRate, encControl.nChannelsInternal - 1); - for (n = 0; n < encControl.nChannelsInternal; ++n) { - int force_fs_kHz; - int n2 = force_fs_kHz = n == 1 ? psEnc.state_Fxx[0].fs_kHz : 0; - if ((ret += psEnc.state_Fxx[n].silk_control_encoder(encControl, TargetRate_bps, psEnc.allowBandwidthSwitch, n, force_fs_kHz)) != SilkError.SILK_NO_ERROR) { - Inlines.OpusAssert(false); - return ret; - } - if (psEnc.state_Fxx[n].first_frame_after_reset != 0 || transition) { - for (i = 0; i < psEnc.state_Fxx[0].nFramesPerPacket; ++i) { - psEnc.state_Fxx[n].LBRR_flags[i] = 0; - } - } - psEnc.state_Fxx[n].inDTX = psEnc.state_Fxx[n].useDTX; - } - Inlines.OpusAssert(encControl.nChannelsInternal == 1 || psEnc.state_Fxx[0].fs_kHz == psEnc.state_Fxx[1].fs_kHz); - int nSamplesToBufferMax = 10 * nBlocksOf10ms * psEnc.state_Fxx[0].fs_kHz; - int nSamplesFromInputMax = Inlines.silk_DIV32_16(nSamplesToBufferMax * psEnc.state_Fxx[0].API_fs_Hz, (short)(psEnc.state_Fxx[0].fs_kHz * 1000)); - short[] buf = new short[nSamplesFromInputMax]; - int samplesIn_ptr = 0; - while (true) { - int nSamplesToBuffer = psEnc.state_Fxx[0].frame_length - psEnc.state_Fxx[0].inputBufIx; - nSamplesToBuffer = Inlines.silk_min(nSamplesToBuffer, nSamplesToBufferMax); - nSamplesFromInput = Inlines.silk_DIV32_16(nSamplesToBuffer * psEnc.state_Fxx[0].API_fs_Hz, psEnc.state_Fxx[0].fs_kHz * 1000); - if (encControl.nChannelsAPI == 2 && encControl.nChannelsInternal == 2) { - int id = psEnc.state_Fxx[0].nFramesEncoded; - for (n = 0; n < nSamplesFromInput; ++n) { - buf[n] = samplesIn[samplesIn_ptr + 2 * n]; - } - if (psEnc.nPrevChannelsInternal == 1 && id == 0) { - psEnc.state_Fxx[1].resampler_state.Assign(psEnc.state_Fxx[0].resampler_state); - } - ret += Resampler.silk_resampler(psEnc.state_Fxx[0].resampler_state, psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].inputBufIx + 2, buf, 0, nSamplesFromInput); - psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer; - nSamplesToBuffer = psEnc.state_Fxx[1].frame_length - psEnc.state_Fxx[1].inputBufIx; - nSamplesToBuffer = Inlines.silk_min(nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc.state_Fxx[1].fs_kHz); - for (n = 0; n < nSamplesFromInput; ++n) { - buf[n] = samplesIn[samplesIn_ptr + 2 * n + 1]; - } - ret += Resampler.silk_resampler(psEnc.state_Fxx[1].resampler_state, psEnc.state_Fxx[1].inputBuf, psEnc.state_Fxx[1].inputBufIx + 2, buf, 0, nSamplesFromInput); - psEnc.state_Fxx[1].inputBufIx += nSamplesToBuffer; - } else if (encControl.nChannelsAPI == 2 && encControl.nChannelsInternal == 1) { - for (n = 0; n < nSamplesFromInput; ++n) { - int sum = samplesIn[samplesIn_ptr + 2 * n] + samplesIn[samplesIn_ptr + 2 * n + 1]; - buf[n] = (short)Inlines.silk_RSHIFT_ROUND(sum, 1); - } - ret += Resampler.silk_resampler(psEnc.state_Fxx[0].resampler_state, psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].inputBufIx + 2, buf, 0, nSamplesFromInput); - if (psEnc.nPrevChannelsInternal == 2 && psEnc.state_Fxx[0].nFramesEncoded == 0) { - ret += Resampler.silk_resampler(psEnc.state_Fxx[1].resampler_state, psEnc.state_Fxx[1].inputBuf, psEnc.state_Fxx[1].inputBufIx + 2, buf, 0, nSamplesFromInput); - for (n = 0; n < psEnc.state_Fxx[0].frame_length; ++n) { - psEnc.state_Fxx[0].inputBuf[psEnc.state_Fxx[0].inputBufIx + n + 2] = (short)Inlines.silk_RSHIFT(psEnc.state_Fxx[0].inputBuf[psEnc.state_Fxx[0].inputBufIx + n + 2] + psEnc.state_Fxx[1].inputBuf[psEnc.state_Fxx[1].inputBufIx + n + 2], 1); - } - } - psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer; - } else { - Inlines.OpusAssert(encControl.nChannelsAPI == 1 && encControl.nChannelsInternal == 1); - System.arraycopy(samplesIn, samplesIn_ptr, buf, 0, nSamplesFromInput); - ret += Resampler.silk_resampler(psEnc.state_Fxx[0].resampler_state, psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].inputBufIx + 2, buf, 0, nSamplesFromInput); - psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer; - } - samplesIn_ptr += nSamplesFromInput * encControl.nChannelsAPI; - nSamplesIn -= nSamplesFromInput; - psEnc.allowBandwidthSwitch = 0; - if (psEnc.state_Fxx[0].inputBufIx < psEnc.state_Fxx[0].frame_length) break; - Inlines.OpusAssert(psEnc.state_Fxx[0].inputBufIx == psEnc.state_Fxx[0].frame_length); - Inlines.OpusAssert(encControl.nChannelsInternal == 1 || psEnc.state_Fxx[1].inputBufIx == psEnc.state_Fxx[1].frame_length); - if (psEnc.state_Fxx[0].nFramesEncoded == 0 && prefillFlag == 0) { - short[] iCDF = new short[]{0, 0}; - iCDF[0] = (short)(256 - Inlines.silk_RSHIFT(256, (psEnc.state_Fxx[0].nFramesPerPacket + 1) * encControl.nChannelsInternal)); - psRangeEnc.enc_icdf(0, iCDF, 8); - for (n = 0; n < encControl.nChannelsInternal; ++n) { - int LBRR_symbol = 0; - for (i = 0; i < psEnc.state_Fxx[n].nFramesPerPacket; ++i) { - LBRR_symbol |= Inlines.silk_LSHIFT(psEnc.state_Fxx[n].LBRR_flags[i], i); - } - psEnc.state_Fxx[n].LBRR_flag = (byte)(LBRR_symbol > 0 ? 1 : 0); - if (LBRR_symbol == 0 || psEnc.state_Fxx[n].nFramesPerPacket <= 1) continue; - psRangeEnc.enc_icdf(LBRR_symbol - 1, SilkTables.silk_LBRR_flags_iCDF_ptr[psEnc.state_Fxx[n].nFramesPerPacket - 2], 8); - } - for (i = 0; i < psEnc.state_Fxx[0].nFramesPerPacket; ++i) { - for (n = 0; n < encControl.nChannelsInternal; ++n) { - if (psEnc.state_Fxx[n].LBRR_flags[i] == 0) continue; - if (encControl.nChannelsInternal == 2 && n == 0) { - Stereo.silk_stereo_encode_pred(psRangeEnc, psEnc.sStereo.predIx[i]); - if (psEnc.state_Fxx[1].LBRR_flags[i] == 0) { - Stereo.silk_stereo_encode_mid_only(psRangeEnc, psEnc.sStereo.mid_only_flags[i]); - } - } - int condCoding = i > 0 && psEnc.state_Fxx[n].LBRR_flags[i - 1] != 0 ? 2 : 0; - EncodeIndices.silk_encode_indices(psEnc.state_Fxx[n], psRangeEnc, i, 1, condCoding); - EncodePulses.silk_encode_pulses(psRangeEnc, psEnc.state_Fxx[n].indices_LBRR[i].signalType, psEnc.state_Fxx[n].indices_LBRR[i].quantOffsetType, psEnc.state_Fxx[n].pulses_LBRR[i], psEnc.state_Fxx[n].frame_length); - } - } - for (n = 0; n < encControl.nChannelsInternal; ++n) { - Arrays.MemSet(psEnc.state_Fxx[n].LBRR_flags, 0, 3); - } - psEnc.nBitsUsedLBRR = psRangeEnc.tell(); - } - HPVariableCutoff.silk_HP_variable_cutoff(psEnc.state_Fxx); - int nBits = Inlines.silk_DIV32_16(Inlines.silk_MUL(encControl.bitRate, encControl.payloadSize_ms), 1000); - if (prefillFlag == 0) { - nBits -= psEnc.nBitsUsedLBRR; - } - nBits = Inlines.silk_DIV32_16(nBits, psEnc.state_Fxx[0].nFramesPerPacket); - TargetRate_bps = encControl.payloadSize_ms == 10 ? Inlines.silk_SMULBB(nBits, 100) : Inlines.silk_SMULBB(nBits, 50); - TargetRate_bps -= Inlines.silk_DIV32_16(Inlines.silk_MUL(psEnc.nBitsExceeded, 1000), 500); - if (prefillFlag == 0 && psEnc.state_Fxx[0].nFramesEncoded > 0) { - int bitsBalance = psRangeEnc.tell() - psEnc.nBitsUsedLBRR - nBits * psEnc.state_Fxx[0].nFramesEncoded; - TargetRate_bps -= Inlines.silk_DIV32_16(Inlines.silk_MUL(bitsBalance, 1000), 500); - } - TargetRate_bps = Inlines.silk_LIMIT(TargetRate_bps, encControl.bitRate, 5000); - if (encControl.nChannelsInternal == 2) { - BoxedValueByte midOnlyFlagBoxed = new BoxedValueByte(psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded]); - Stereo.silk_stereo_LR_to_MS(psEnc.sStereo, psEnc.state_Fxx[0].inputBuf, 2, psEnc.state_Fxx[1].inputBuf, 2, psEnc.sStereo.predIx[psEnc.state_Fxx[0].nFramesEncoded], midOnlyFlagBoxed, MStargetRates_bps, TargetRate_bps, psEnc.state_Fxx[0].speech_activity_Q8, encControl.toMono, psEnc.state_Fxx[0].fs_kHz, psEnc.state_Fxx[0].frame_length); - psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded] = midOnlyFlagBoxed.Val; - if (midOnlyFlagBoxed.Val == 0) { - if (psEnc.prev_decode_only_middle == 1) { - psEnc.state_Fxx[1].sShape.Reset(); - psEnc.state_Fxx[1].sPrefilt.Reset(); - psEnc.state_Fxx[1].sNSQ.Reset(); - Arrays.MemSet(psEnc.state_Fxx[1].prev_NLSFq_Q15, (short)0, 16); - Arrays.MemSet(psEnc.state_Fxx[1].sLP.In_LP_State, 0, 2); - psEnc.state_Fxx[1].prevLag = 100; - psEnc.state_Fxx[1].sNSQ.lagPrev = 100; - psEnc.state_Fxx[1].sShape.LastGainIndex = (byte)10; - psEnc.state_Fxx[1].prevSignalType = 0; - psEnc.state_Fxx[1].sNSQ.prev_gain_Q16 = 65536; - psEnc.state_Fxx[1].first_frame_after_reset = 1; - } - psEnc.state_Fxx[1].silk_encode_do_VAD(); - } else { - psEnc.state_Fxx[1].VAD_flags[psEnc.state_Fxx[0].nFramesEncoded] = 0; - } - if (prefillFlag == 0) { - Stereo.silk_stereo_encode_pred(psRangeEnc, psEnc.sStereo.predIx[psEnc.state_Fxx[0].nFramesEncoded]); - if (psEnc.state_Fxx[1].VAD_flags[psEnc.state_Fxx[0].nFramesEncoded] == 0) { - Stereo.silk_stereo_encode_mid_only(psRangeEnc, psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded]); - } - } - } else { - System.arraycopy(psEnc.sStereo.sMid, 0, psEnc.state_Fxx[0].inputBuf, 0, 2); - System.arraycopy(psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].frame_length, psEnc.sStereo.sMid, 0, 2); - } - psEnc.state_Fxx[0].silk_encode_do_VAD(); - for (n = 0; n < encControl.nChannelsInternal; ++n) { - int channelRate_bps; - int useCBR; - int maxBits = encControl.maxBits; - if (tot_blocks == 2 && curr_block == 0) { - maxBits = maxBits * 3 / 5; - } else if (tot_blocks == 3) { - if (curr_block == 0) { - maxBits = maxBits * 2 / 5; - } else if (curr_block == 1) { - maxBits = maxBits * 3 / 4; - } - } - int n3 = useCBR = encControl.useCBR != 0 && curr_block == tot_blocks - 1 ? 1 : 0; - if (encControl.nChannelsInternal == 1) { - channelRate_bps = TargetRate_bps; - } else { - channelRate_bps = MStargetRates_bps[n]; - if (n == 0 && MStargetRates_bps[1] > 0) { - useCBR = 0; - maxBits -= encControl.maxBits / (tot_blocks * 2); - } - } - if (channelRate_bps > 0) { - psEnc.state_Fxx[n].silk_control_SNR(channelRate_bps); - int condCoding = psEnc.state_Fxx[0].nFramesEncoded - n <= 0 ? 0 : (n > 0 && psEnc.prev_decode_only_middle != 0 ? 1 : 2); - Inlines.OpusAssert((ret += psEnc.state_Fxx[n].silk_encode_frame(nBytesOut, psRangeEnc, condCoding, maxBits, useCBR)) == SilkError.SILK_NO_ERROR); - } - psEnc.state_Fxx[n].controlled_since_last_payload = 0; - psEnc.state_Fxx[n].inputBufIx = 0; - ++psEnc.state_Fxx[n].nFramesEncoded; - } - psEnc.prev_decode_only_middle = psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded - 1]; - if (nBytesOut.Val > 0 && psEnc.state_Fxx[0].nFramesEncoded == psEnc.state_Fxx[0].nFramesPerPacket) { - int flags = 0; - for (n = 0; n < encControl.nChannelsInternal; ++n) { - for (i = 0; i < psEnc.state_Fxx[n].nFramesPerPacket; ++i) { - flags = Inlines.silk_LSHIFT(flags, 1); - flags |= psEnc.state_Fxx[n].VAD_flags[i]; - } - flags = Inlines.silk_LSHIFT(flags, 1); - flags |= psEnc.state_Fxx[n].LBRR_flag; - } - if (prefillFlag == 0) { - psRangeEnc.enc_patch_initial_bits(flags, (psEnc.state_Fxx[0].nFramesPerPacket + 1) * encControl.nChannelsInternal); - } - if (psEnc.state_Fxx[0].inDTX != 0 && (encControl.nChannelsInternal == 1 || psEnc.state_Fxx[1].inDTX != 0)) { - nBytesOut.Val = 0; - } - psEnc.nBitsExceeded += nBytesOut.Val * 8; - psEnc.nBitsExceeded -= Inlines.silk_DIV32_16(Inlines.silk_MUL(encControl.bitRate, encControl.payloadSize_ms), 1000); - psEnc.nBitsExceeded = Inlines.silk_LIMIT(psEnc.nBitsExceeded, 0, 10000); - int speech_act_thr_for_switch_Q8 = Inlines.silk_SMLAWB(13, 3188, psEnc.timeSinceSwitchAllowed_ms); - if (psEnc.state_Fxx[0].speech_activity_Q8 < speech_act_thr_for_switch_Q8) { - psEnc.allowBandwidthSwitch = 1; - psEnc.timeSinceSwitchAllowed_ms = 0; - } else { - psEnc.allowBandwidthSwitch = 0; - psEnc.timeSinceSwitchAllowed_ms += encControl.payloadSize_ms; - } - } - if (nSamplesIn == 0) break; - ++curr_block; - } - psEnc.nPrevChannelsInternal = encControl.nChannelsInternal; - encControl.allowBandwidthSwitch = psEnc.allowBandwidthSwitch; - encControl.inWBmodeWithoutVariableLP = psEnc.state_Fxx[0].fs_kHz == 16 && psEnc.state_Fxx[0].sLP.mode == 0 ? 1 : 0; - encControl.internalSampleRate = Inlines.silk_SMULBB(psEnc.state_Fxx[0].fs_kHz, 1000); - int n4 = encControl.stereoWidth_Q14 = encControl.toMono != 0 ? 0 : (int)psEnc.sStereo.smth_width_Q14; - if (prefillFlag != 0) { - encControl.payloadSize_ms = tmp_payloadSize_ms; - encControl.complexity = tmp_complexity; - for (n = 0; n < encControl.nChannelsInternal; ++n) { - psEnc.state_Fxx[n].controlled_since_last_payload = 0; - psEnc.state_Fxx[n].prefillFlag = 0; - } - } - return ret; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/EncodeIndices.java b/source/decompiled/de/maxhenkel/voicechat/concentus/EncodeIndices.java deleted file mode 100644 index bed616b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/EncodeIndices.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.NLSF; -import de.maxhenkel.voicechat.concentus.SideInfoIndices; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class EncodeIndices { - EncodeIndices() { - } - - static void silk_encode_indices(SilkChannelEncoder psEncC, EntropyCoder psRangeEnc, int FrameIndex, int encode_LBRR, int condCoding) { - int i; - short[] ec_ix = new short[16]; - short[] pred_Q8 = new short[16]; - SideInfoIndices psIndices = encode_LBRR != 0 ? psEncC.indices_LBRR[FrameIndex] : psEncC.indices; - int typeOffset = 2 * psIndices.signalType + psIndices.quantOffsetType; - Inlines.OpusAssert(typeOffset >= 0 && typeOffset < 6); - Inlines.OpusAssert(encode_LBRR == 0 || typeOffset >= 2); - if (encode_LBRR != 0 || typeOffset >= 2) { - psRangeEnc.enc_icdf(typeOffset - 2, SilkTables.silk_type_offset_VAD_iCDF, 8); - } else { - psRangeEnc.enc_icdf(typeOffset, SilkTables.silk_type_offset_no_VAD_iCDF, 8); - } - if (condCoding == 2) { - Inlines.OpusAssert(psIndices.GainsIndices[0] >= 0 && psIndices.GainsIndices[0] < 41); - psRangeEnc.enc_icdf(psIndices.GainsIndices[0], SilkTables.silk_delta_gain_iCDF, 8); - } else { - Inlines.OpusAssert(psIndices.GainsIndices[0] >= 0 && psIndices.GainsIndices[0] < 64); - psRangeEnc.enc_icdf(Inlines.silk_RSHIFT(psIndices.GainsIndices[0], 3), SilkTables.silk_gain_iCDF[psIndices.signalType], 8); - psRangeEnc.enc_icdf(psIndices.GainsIndices[0] & 7, SilkTables.silk_uniform8_iCDF, 8); - } - for (i = 1; i < psEncC.nb_subfr; ++i) { - Inlines.OpusAssert(psIndices.GainsIndices[i] >= 0 && psIndices.GainsIndices[i] < 41); - psRangeEnc.enc_icdf(psIndices.GainsIndices[i], SilkTables.silk_delta_gain_iCDF, 8); - } - psRangeEnc.enc_icdf(psIndices.NLSFIndices[0], psEncC.psNLSF_CB.CB1_iCDF, (psIndices.signalType >> 1) * psEncC.psNLSF_CB.nVectors, 8); - NLSF.silk_NLSF_unpack(ec_ix, pred_Q8, psEncC.psNLSF_CB, psIndices.NLSFIndices[0]); - Inlines.OpusAssert(psEncC.psNLSF_CB.order == psEncC.predictLPCOrder); - for (i = 0; i < psEncC.psNLSF_CB.order; ++i) { - if (psIndices.NLSFIndices[i + 1] >= 4) { - psRangeEnc.enc_icdf(8, psEncC.psNLSF_CB.ec_iCDF, ec_ix[i], 8); - psRangeEnc.enc_icdf(psIndices.NLSFIndices[i + 1] - 4, SilkTables.silk_NLSF_EXT_iCDF, 8); - continue; - } - if (psIndices.NLSFIndices[i + 1] <= -4) { - psRangeEnc.enc_icdf(0, psEncC.psNLSF_CB.ec_iCDF, ec_ix[i], 8); - psRangeEnc.enc_icdf(-psIndices.NLSFIndices[i + 1] - 4, SilkTables.silk_NLSF_EXT_iCDF, 8); - continue; - } - psRangeEnc.enc_icdf(psIndices.NLSFIndices[i + 1] + 4, psEncC.psNLSF_CB.ec_iCDF, ec_ix[i], 8); - } - if (psEncC.nb_subfr == 4) { - Inlines.OpusAssert(psIndices.NLSFInterpCoef_Q2 >= 0 && psIndices.NLSFInterpCoef_Q2 < 5); - psRangeEnc.enc_icdf(psIndices.NLSFInterpCoef_Q2, SilkTables.silk_NLSF_interpolation_factor_iCDF, 8); - } - if (psIndices.signalType == 2) { - boolean encode_absolute_lagIndex = true; - if (condCoding == 2 && psEncC.ec_prevSignalType == 2) { - int delta_lagIndex = psIndices.lagIndex - psEncC.ec_prevLagIndex; - if (delta_lagIndex < -8 || delta_lagIndex > 11) { - delta_lagIndex = 0; - } else { - delta_lagIndex += 9; - encode_absolute_lagIndex = false; - } - Inlines.OpusAssert(delta_lagIndex >= 0 && delta_lagIndex < 21); - psRangeEnc.enc_icdf(delta_lagIndex, SilkTables.silk_pitch_delta_iCDF, 8); - } - if (encode_absolute_lagIndex) { - int pitch_high_bits = Inlines.silk_DIV32_16(psIndices.lagIndex, Inlines.silk_RSHIFT(psEncC.fs_kHz, 1)); - int pitch_low_bits = psIndices.lagIndex - Inlines.silk_SMULBB(pitch_high_bits, Inlines.silk_RSHIFT(psEncC.fs_kHz, 1)); - Inlines.OpusAssert(pitch_low_bits < psEncC.fs_kHz / 2); - Inlines.OpusAssert(pitch_high_bits < 32); - psRangeEnc.enc_icdf(pitch_high_bits, SilkTables.silk_pitch_lag_iCDF, 8); - psRangeEnc.enc_icdf(pitch_low_bits, psEncC.pitch_lag_low_bits_iCDF, 8); - } - psEncC.ec_prevLagIndex = psIndices.lagIndex; - Inlines.OpusAssert(psIndices.contourIndex >= 0); - Inlines.OpusAssert(psIndices.contourIndex < 34 && psEncC.fs_kHz > 8 && psEncC.nb_subfr == 4 || psIndices.contourIndex < 11 && psEncC.fs_kHz == 8 && psEncC.nb_subfr == 4 || psIndices.contourIndex < 12 && psEncC.fs_kHz > 8 && psEncC.nb_subfr == 2 || psIndices.contourIndex < 3 && psEncC.fs_kHz == 8 && psEncC.nb_subfr == 2); - psRangeEnc.enc_icdf(psIndices.contourIndex, psEncC.pitch_contour_iCDF, 8); - Inlines.OpusAssert(psIndices.PERIndex >= 0 && psIndices.PERIndex < 3); - psRangeEnc.enc_icdf(psIndices.PERIndex, SilkTables.silk_LTP_per_index_iCDF, 8); - for (int k = 0; k < psEncC.nb_subfr; ++k) { - Inlines.OpusAssert(psIndices.LTPIndex[k] >= 0 && psIndices.LTPIndex[k] < 8 << psIndices.PERIndex); - psRangeEnc.enc_icdf(psIndices.LTPIndex[k], SilkTables.silk_LTP_gain_iCDF_ptrs[psIndices.PERIndex], 8); - } - if (condCoding == 0) { - Inlines.OpusAssert(psIndices.LTP_scaleIndex >= 0 && psIndices.LTP_scaleIndex < 3); - psRangeEnc.enc_icdf(psIndices.LTP_scaleIndex, SilkTables.silk_LTPscale_iCDF, 8); - } - Inlines.OpusAssert(condCoding == 0 || psIndices.LTP_scaleIndex == 0); - } - psEncC.ec_prevSignalType = psIndices.signalType; - Inlines.OpusAssert(psIndices.Seed >= 0 && psIndices.Seed < 4); - psRangeEnc.enc_icdf(psIndices.Seed, SilkTables.silk_uniform4_iCDF, 8); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/EncodePulses.java b/source/decompiled/de/maxhenkel/voicechat/concentus/EncodePulses.java deleted file mode 100644 index 66d6c61..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/EncodePulses.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.CodeSigns; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.ShellCoder; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class EncodePulses { - EncodePulses() { - } - - static int combine_and_check(int[] pulses_comb, int pulses_comb_ptr, int[] pulses_in, int pulses_in_ptr, int max_pulses, int len) { - for (int k = 0; k < len; ++k) { - int k2p = 2 * k + pulses_in_ptr; - int sum = pulses_in[k2p] + pulses_in[k2p + 1]; - if (sum > max_pulses) { - return 1; - } - pulses_comb[pulses_comb_ptr + k] = sum; - } - return 0; - } - - static int combine_and_check(int[] pulses_comb, int[] pulses_in, int max_pulses, int len) { - for (int k = 0; k < len; ++k) { - int sum = pulses_in[2 * k] + pulses_in[2 * k + 1]; - if (sum > max_pulses) { - return 1; - } - pulses_comb[k] = sum; - } - return 0; - } - - static void silk_encode_pulses(EntropyCoder psRangeEnc, int signalType, int quantOffsetType, byte[] pulses, int frame_length) { - int k; - int i; - int RateLevelIndex = 0; - int[] pulses_comb = new int[8]; - Arrays.MemSet(pulses_comb, 0, 8); - Inlines.OpusAssert(true); - int iter = Inlines.silk_RSHIFT(frame_length, 4); - if (iter * 16 < frame_length) { - Inlines.OpusAssert(frame_length == 120); - ++iter; - Arrays.MemSetWithOffset(pulses, (byte)0, frame_length, 16); - } - int[] abs_pulses = new int[iter * 16]; - Inlines.OpusAssert(true); - for (i = 0; i < iter * 16; i += 4) { - abs_pulses[i + 0] = Inlines.silk_abs(pulses[i + 0]); - abs_pulses[i + 1] = Inlines.silk_abs(pulses[i + 1]); - abs_pulses[i + 2] = Inlines.silk_abs(pulses[i + 2]); - abs_pulses[i + 3] = Inlines.silk_abs(pulses[i + 3]); - } - int[] sum_pulses = new int[iter]; - int[] nRshifts = new int[iter]; - int abs_pulses_ptr = 0; - for (i = 0; i < iter; ++i) { - nRshifts[i] = 0; - block2: while (true) { - int scale_down = EncodePulses.combine_and_check(pulses_comb, 0, abs_pulses, abs_pulses_ptr, SilkTables.silk_max_pulses_table[0], 8); - scale_down += EncodePulses.combine_and_check(pulses_comb, pulses_comb, SilkTables.silk_max_pulses_table[1], 4); - scale_down += EncodePulses.combine_and_check(pulses_comb, pulses_comb, SilkTables.silk_max_pulses_table[2], 2); - if ((scale_down += EncodePulses.combine_and_check(sum_pulses, i, pulses_comb, 0, SilkTables.silk_max_pulses_table[3], 1)) == 0) break; - int n = i; - nRshifts[n] = nRshifts[n] + 1; - k = abs_pulses_ptr; - while (true) { - if (k >= abs_pulses_ptr + 16) continue block2; - abs_pulses[k] = Inlines.silk_RSHIFT(abs_pulses[k], 1); - ++k; - } - break; - } - abs_pulses_ptr += 16; - } - int minSumBits_Q5 = Integer.MAX_VALUE; - for (k = 0; k < 9; ++k) { - short[] nBits_ptr = SilkTables.silk_pulses_per_block_BITS_Q5[k]; - int sumBits_Q5 = SilkTables.silk_rate_levels_BITS_Q5[signalType >> 1][k]; - for (i = 0; i < iter; ++i) { - if (nRshifts[i] > 0) { - sumBits_Q5 += nBits_ptr[17]; - continue; - } - sumBits_Q5 += nBits_ptr[sum_pulses[i]]; - } - if (sumBits_Q5 >= minSumBits_Q5) continue; - minSumBits_Q5 = sumBits_Q5; - RateLevelIndex = k; - } - psRangeEnc.enc_icdf(RateLevelIndex, SilkTables.silk_rate_levels_iCDF[signalType >> 1], 8); - for (i = 0; i < iter; ++i) { - if (nRshifts[i] == 0) { - psRangeEnc.enc_icdf(sum_pulses[i], SilkTables.silk_pulses_per_block_iCDF[RateLevelIndex], 8); - continue; - } - psRangeEnc.enc_icdf(17, SilkTables.silk_pulses_per_block_iCDF[RateLevelIndex], 8); - for (k = 0; k < nRshifts[i] - 1; ++k) { - psRangeEnc.enc_icdf(17, SilkTables.silk_pulses_per_block_iCDF[9], 8); - } - psRangeEnc.enc_icdf(sum_pulses[i], SilkTables.silk_pulses_per_block_iCDF[9], 8); - } - for (i = 0; i < iter; ++i) { - if (sum_pulses[i] <= 0) continue; - ShellCoder.silk_shell_encoder(psRangeEnc, abs_pulses, i * 16); - } - for (i = 0; i < iter; ++i) { - if (nRshifts[i] <= 0) continue; - int pulses_ptr = i * 16; - int nLS = nRshifts[i] - 1; - for (k = 0; k < 16; ++k) { - int bit; - byte abs_q = (byte)Inlines.silk_abs(pulses[pulses_ptr + k]); - for (int j = nLS; j > 0; --j) { - bit = Inlines.silk_RSHIFT(abs_q, j) & 1; - psRangeEnc.enc_icdf(bit, SilkTables.silk_lsb_iCDF, 8); - } - bit = abs_q & 1; - psRangeEnc.enc_icdf(bit, SilkTables.silk_lsb_iCDF, 8); - } - } - CodeSigns.silk_encode_signs(psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/EntropyCoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/EntropyCoder.java deleted file mode 100644 index ae07e66..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/EntropyCoder.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Inlines; - -class EntropyCoder { - private final int EC_WINDOW_SIZE = 32; - private final int EC_UINT_BITS = 8; - static final int BITRES = 3; - private final int EC_SYM_BITS = 8; - private final int EC_CODE_BITS = 32; - private final long EC_SYM_MAX = 255L; - private final int EC_CODE_SHIFT = 23; - private final long EC_CODE_TOP = 0x80000000L; - private final long EC_CODE_BOT = 0x800000L; - private final int EC_CODE_EXTRA = 7; - private byte[] buf; - private int buf_ptr; - int storage; - int end_offs; - long end_window; - int nend_bits; - int nbits_total; - int offs; - long rng; - long val; - long ext; - int rem; - int error; - private static final int[] correction = new int[]{35733, 38967, 42495, 46340, 50535, 55109, 60097, 65535}; - - EntropyCoder() { - this.Reset(); - } - - void Reset() { - this.buf = null; - this.buf_ptr = 0; - this.storage = 0; - this.end_offs = 0; - this.end_window = 0L; - this.nend_bits = 0; - this.offs = 0; - this.rng = 0L; - this.val = 0L; - this.ext = 0L; - this.rem = 0; - this.error = 0; - } - - void Assign(EntropyCoder other) { - this.buf = other.buf; - this.buf_ptr = other.buf_ptr; - this.storage = other.storage; - this.end_offs = other.end_offs; - this.end_window = other.end_window; - this.nend_bits = other.nend_bits; - this.nbits_total = other.nbits_total; - this.offs = other.offs; - this.rng = other.rng; - this.val = other.val; - this.ext = other.ext; - this.rem = other.rem; - this.error = other.error; - } - - byte[] get_buffer() { - byte[] convertedBuf = new byte[this.storage]; - System.arraycopy(this.buf, this.buf_ptr, convertedBuf, 0, this.storage); - return convertedBuf; - } - - void write_buffer(byte[] data, int data_ptr, int target_offset, int size) { - System.arraycopy(data, data_ptr, this.buf, this.buf_ptr + target_offset, size); - } - - int read_byte() { - return this.offs < this.storage ? Inlines.SignedByteToUnsignedInt(this.buf[this.buf_ptr + this.offs++]) : 0; - } - - int read_byte_from_end() { - return this.end_offs < this.storage ? Inlines.SignedByteToUnsignedInt(this.buf[this.buf_ptr + (this.storage - ++this.end_offs)]) : 0; - } - - int write_byte(long _value) { - if (this.offs + this.end_offs >= this.storage) { - return -1; - } - this.buf[this.buf_ptr + this.offs++] = (byte)(_value & 0xFFL); - return 0; - } - - int write_byte_at_end(long _value) { - if (this.offs + this.end_offs >= this.storage) { - return -1; - } - this.buf[this.buf_ptr + (this.storage - ++this.end_offs)] = (byte)(_value & 0xFFL); - return 0; - } - - void dec_normalize() { - while (this.rng <= 0x800000L) { - this.nbits_total += 8; - this.rng = Inlines.CapToUInt32(this.rng << 8); - int sym = this.rem; - this.rem = this.read_byte(); - sym = (sym << 8 | this.rem) >> 1; - this.val = Inlines.CapToUInt32((this.val << 8) + (0xFFL & (long)(~sym)) & Integer.MAX_VALUE); - } - } - - void dec_init(byte[] _buf, int _buf_ptr, int _storage) { - this.buf = _buf; - this.buf_ptr = _buf_ptr; - this.storage = _storage; - this.end_offs = 0; - this.end_window = 0L; - this.nend_bits = 0; - this.nbits_total = 9; - this.offs = 0; - this.rng = 128L; - this.rem = this.read_byte(); - this.val = Inlines.CapToUInt32(this.rng - 1L - (long)(this.rem >> 1)); - this.error = 0; - this.dec_normalize(); - } - - long decode(long _ft) { - _ft = Inlines.CapToUInt32(_ft); - this.ext = Inlines.CapToUInt32(this.rng / _ft); - long s = Inlines.CapToUInt32(this.val / this.ext); - return Inlines.CapToUInt32(_ft - Inlines.EC_MINI(Inlines.CapToUInt32(s + 1L), _ft)); - } - - long decode_bin(int _bits) { - this.ext = this.rng >> _bits; - long s = Inlines.CapToUInt32(this.val / this.ext); - return Inlines.CapToUInt32(Inlines.CapToUInt32(1L << _bits) - Inlines.EC_MINI(Inlines.CapToUInt32(s + 1L), 1L << _bits)); - } - - void dec_update(long _fl, long _fh, long _ft) { - _fl = Inlines.CapToUInt32(_fl); - _fh = Inlines.CapToUInt32(_fh); - _ft = Inlines.CapToUInt32(_ft); - long s = Inlines.CapToUInt32(this.ext * (_ft - _fh)); - this.val -= s; - this.rng = _fl > 0L ? Inlines.CapToUInt32(this.ext * (_fh - _fl)) : this.rng - s; - this.dec_normalize(); - } - - int dec_bit_logp(long _logp) { - int ret; - long d = this.val; - long r = this.rng; - long s = r >> (int)_logp; - int n = ret = d < s ? 1 : 0; - if (ret == 0) { - this.val = Inlines.CapToUInt32(d - s); - } - this.rng = ret != 0 ? s : r - s; - this.dec_normalize(); - return ret; - } - - int dec_icdf(short[] _icdf, int _ftb) { - long t; - long s = this.rng; - long d = this.val; - long r = s >> _ftb; - int ret = -1; - do { - t = s; - } while (d < (s = Inlines.CapToUInt32(r * (long)_icdf[++ret]))); - this.val = Inlines.CapToUInt32(d - s); - this.rng = Inlines.CapToUInt32(t - s); - this.dec_normalize(); - return ret; - } - - int dec_icdf(short[] _icdf, int _icdf_offset, int _ftb) { - long t; - long s = this.rng; - long d = this.val; - long r = s >> _ftb; - int ret = _icdf_offset - 1; - do { - t = s; - } while (d < (s = Inlines.CapToUInt32(r * (long)_icdf[++ret]))); - this.val = Inlines.CapToUInt32(d - s); - this.rng = Inlines.CapToUInt32(t - s); - this.dec_normalize(); - return ret - _icdf_offset; - } - - long dec_uint(long _ft) { - Inlines.OpusAssert((_ft = Inlines.CapToUInt32(_ft)) > 1L); - int ftb = Inlines.EC_ILOG(--_ft); - if (ftb > 8) { - long ft = Inlines.CapToUInt32((_ft >> (ftb -= 8)) + 1L); - long s = Inlines.CapToUInt32(this.decode(ft)); - this.dec_update(s, s + 1L, ft); - long t = Inlines.CapToUInt32(s << ftb | (long)this.dec_bits(ftb)); - if (t <= _ft) { - return t; - } - this.error = 1; - return _ft; - } - long s = Inlines.CapToUInt32(this.decode(++_ft)); - this.dec_update(s, s + 1L, _ft); - return s; - } - - int dec_bits(int _bits) { - long window = this.end_window; - int available = this.nend_bits; - if (available < _bits) { - do { - window = Inlines.CapToUInt32(window | (long)(this.read_byte_from_end() << available)); - } while ((available += 8) <= 24); - } - int ret = (int)(0xFFFFFFFFFFFFFFFFL & (window & (long)((1 << _bits) - 1))); - this.end_window = Inlines.CapToUInt32(window >>= _bits); - this.nend_bits = available -= _bits; - this.nbits_total += _bits; - return ret; - } - - void enc_carry_out(int _c) { - if ((long)_c != 255L) { - int carry = _c >> 8; - if (this.rem >= 0) { - this.error |= this.write_byte(Inlines.CapToUInt32(this.rem + carry)); - } - if (this.ext > 0L) { - long sym = 255L + (long)carry & 0xFFL; - do { - this.error |= this.write_byte(sym); - } while (--this.ext > 0L); - } - this.rem = (int)((long)_c & 0xFFL); - } else { - ++this.ext; - } - } - - void enc_normalize() { - while (this.rng <= 0x800000L) { - this.enc_carry_out((int)(this.val >> 23)); - this.val = Inlines.CapToUInt32(this.val << 8 & Integer.MAX_VALUE); - this.rng = Inlines.CapToUInt32(this.rng << 8); - this.nbits_total += 8; - } - } - - void enc_init(byte[] _buf, int buf_ptr, int _size) { - this.buf = _buf; - this.buf_ptr = buf_ptr; - this.end_offs = 0; - this.end_window = 0L; - this.nend_bits = 0; - this.nbits_total = 33; - this.offs = 0; - this.rng = Inlines.CapToUInt32(0x80000000L); - this.rem = -1; - this.val = 0L; - this.ext = 0L; - this.storage = _size; - this.error = 0; - } - - void encode(long _fl, long _fh, long _ft) { - _fl = Inlines.CapToUInt32(_fl); - _fh = Inlines.CapToUInt32(_fh); - _ft = Inlines.CapToUInt32(_ft); - long r = Inlines.CapToUInt32(this.rng / _ft); - if (_fl > 0L) { - this.val += Inlines.CapToUInt32(this.rng - r * (_ft - _fl)); - this.rng = Inlines.CapToUInt32(r * (_fh - _fl)); - } else { - this.rng = Inlines.CapToUInt32(this.rng - r * (_ft - _fh)); - } - this.enc_normalize(); - } - - void encode_bin(long _fl, long _fh, int _bits) { - _fl = Inlines.CapToUInt32(_fl); - _fh = Inlines.CapToUInt32(_fh); - long r = Inlines.CapToUInt32(this.rng >> _bits); - if (_fl > 0L) { - this.val = Inlines.CapToUInt32(this.val + Inlines.CapToUInt32(this.rng - r * ((long)(1 << _bits) - _fl))); - this.rng = Inlines.CapToUInt32(r * (_fh - _fl)); - } else { - this.rng = Inlines.CapToUInt32(this.rng - r * ((long)(1 << _bits) - _fh)); - } - this.enc_normalize(); - } - - void enc_bit_logp(int _val, int _logp) { - long r = this.rng; - long l = this.val; - long s = r >> _logp; - r -= s; - if (_val != 0) { - this.val = Inlines.CapToUInt32(l + r); - } - this.rng = _val != 0 ? s : r; - this.enc_normalize(); - } - - void enc_icdf(int _s, short[] _icdf, int _ftb) { - long r = Inlines.CapToUInt32(this.rng >> _ftb); - if (_s > 0) { - this.val += Inlines.CapToUInt32(this.rng - Inlines.CapToUInt32(r * (long)_icdf[_s - 1])); - this.rng = r * Inlines.CapToUInt32(_icdf[_s - 1] - _icdf[_s]); - } else { - this.rng = Inlines.CapToUInt32(this.rng - r * (long)_icdf[_s]); - } - this.enc_normalize(); - } - - void enc_icdf(int _s, short[] _icdf, int icdf_ptr, int _ftb) { - long r = Inlines.CapToUInt32(this.rng >> _ftb); - if (_s > 0) { - this.val += Inlines.CapToUInt32(this.rng - Inlines.CapToUInt32(r * (long)_icdf[icdf_ptr + _s - 1])); - this.rng = Inlines.CapToUInt32(r * Inlines.CapToUInt32(_icdf[icdf_ptr + _s - 1] - _icdf[icdf_ptr + _s])); - } else { - this.rng = Inlines.CapToUInt32(this.rng - r * (long)_icdf[icdf_ptr + _s]); - } - this.enc_normalize(); - } - - void enc_uint(long _fl, long _ft) { - _fl = Inlines.CapToUInt32(_fl); - Inlines.OpusAssert((_ft = Inlines.CapToUInt32(_ft)) > 1L); - int ftb = Inlines.EC_ILOG(--_ft); - if (ftb > 8) { - long ft = Inlines.CapToUInt32((_ft >> (ftb -= 8)) + 1L); - long fl = Inlines.CapToUInt32(_fl >> ftb); - this.encode(fl, fl + 1L, ft); - this.enc_bits(_fl & Inlines.CapToUInt32((1 << ftb) - 1), ftb); - } else { - this.encode(_fl, _fl + 1L, _ft + 1L); - } - } - - void enc_bits(long _fl, int _bits) { - _fl = Inlines.CapToUInt32(_fl); - long window = this.end_window; - int used = this.nend_bits; - Inlines.OpusAssert(_bits > 0); - if (used + _bits > 32) { - do { - this.error |= this.write_byte_at_end(window & 0xFFL); - window >>= 8; - } while ((used -= 8) >= 8); - } - window |= Inlines.CapToUInt32(_fl << used); - this.end_window = window; - this.nend_bits = used += _bits; - this.nbits_total += _bits; - } - - void enc_patch_initial_bits(long _val, int _nbits) { - Inlines.OpusAssert(_nbits <= 8); - int shift = 8 - _nbits; - long mask = (1 << _nbits) - 1 << shift; - if (this.offs > 0) { - this.buf[this.buf_ptr] = (byte)((long)this.buf[this.buf_ptr] & (mask ^ 0xFFFFFFFFFFFFFFFFL) | Inlines.CapToUInt32(_val << shift)); - } else if (this.rem >= 0) { - this.rem = (int)Inlines.CapToUInt32(Inlines.CapToUInt32((long)this.rem & (mask ^ 0xFFFFFFFFFFFFFFFFL) | _val) << shift); - } else if (this.rng <= 0x80000000L >> _nbits) { - this.val = Inlines.CapToUInt32(this.val & (mask << 23 ^ 0xFFFFFFFFFFFFFFFFL) | Inlines.CapToUInt32(Inlines.CapToUInt32(_val) << 23 + shift)); - } else { - this.error = -1; - } - } - - void enc_shrink(int _size) { - Inlines.OpusAssert(this.offs + this.end_offs <= _size); - Arrays.MemMove(this.buf, this.buf_ptr + _size - this.end_offs, this.buf_ptr + this.storage - this.end_offs, this.end_offs); - this.storage = _size; - } - - int range_bytes() { - return this.offs; - } - - int get_error() { - return this.error; - } - - int tell() { - int returnVal = this.nbits_total - Inlines.EC_ILOG(this.rng); - return returnVal; - } - - int tell_frac() { - long b; - int nbits = this.nbits_total << 3; - int l = Inlines.EC_ILOG(this.rng); - int r = (int)(this.rng >> l - 16); - b = Inlines.CapToUInt32(b + (long)(r > correction[(int)(b = Inlines.CapToUInt32((r >> 12) - 8))] ? 1 : 0)); - l = (int)((long)(l << 3) + b); - return nbits - l; - } - - void enc_done() { - int used; - int l = 32 - Inlines.EC_ILOG(this.rng); - long msk = Inlines.CapToUInt32(Integer.MAX_VALUE >>> l); - long end = Inlines.CapToUInt32(Inlines.CapToUInt32(this.val + msk) & (msk ^ 0xFFFFFFFFFFFFFFFFL)); - if ((end | msk) >= this.val + this.rng) { - ++l; - end = Inlines.CapToUInt32(Inlines.CapToUInt32(this.val + (msk >>= 1)) & (msk ^ 0xFFFFFFFFFFFFFFFFL)); - } - while (l > 0) { - this.enc_carry_out((int)(end >> 23)); - end = Inlines.CapToUInt32(end << 8 & Integer.MAX_VALUE); - l -= 8; - } - if (this.rem >= 0 || this.ext > 0L) { - this.enc_carry_out(0); - } - long window = this.end_window; - for (used = this.nend_bits; used >= 8; used -= 8) { - this.error |= this.write_byte_at_end(window & 0xFFL); - window >>= 8; - } - if (this.error == 0) { - Arrays.MemSetWithOffset(this.buf, (byte)0, this.buf_ptr + this.offs, this.storage - this.offs - this.end_offs); - if (used > 0) { - if (this.end_offs >= this.storage) { - this.error = -1; - } else { - l = -l; - if (this.offs + this.end_offs >= this.storage && l < used) { - window = Inlines.CapToUInt32(window & (long)((1 << l) - 1)); - this.error = -1; - } - int z = this.buf_ptr + this.storage - this.end_offs - 1; - this.buf[z] = (byte)(this.buf[z] | (byte)(window & 0xFFL)); - } - } - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/FFTState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/FFTState.java deleted file mode 100644 index f9f6330..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/FFTState.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class FFTState { - int nfft = 0; - short scale = 0; - int scale_shift = 0; - int shift = 0; - short[] factors = new short[16]; - short[] bitrev = null; - short[] twiddles = null; - - FFTState() { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Filters.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Filters.java deleted file mode 100644 index 6742f15..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Filters.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Kernels; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkEncoderControl; -import de.maxhenkel.voicechat.concentus.SilkPrefilterState; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class Filters { - private static final short A_fb1_20 = 10788; - private static final short A_fb1_21 = -24290; - private static final int QA = 24; - private static final int A_LIMIT = 0xFFEF9E; - - Filters() { - } - - static void silk_warped_LPC_analysis_filter(int[] state, int[] res_Q2, short[] coef_Q13, int coef_Q13_ptr, short[] input, int input_ptr, short lambda_Q16, int length, int order) { - Inlines.OpusAssert((order & 1) == 0); - for (int n = 0; n < length; ++n) { - int tmp2 = Inlines.silk_SMLAWB(state[0], state[1], lambda_Q16); - state[0] = Inlines.silk_LSHIFT(input[input_ptr + n], 14); - int tmp1 = Inlines.silk_SMLAWB(state[1], state[2] - tmp2, lambda_Q16); - state[1] = tmp2; - int acc_Q11 = Inlines.silk_RSHIFT(order, 1); - acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp2, coef_Q13[coef_Q13_ptr]); - for (int i = 2; i < order; i += 2) { - tmp2 = Inlines.silk_SMLAWB(state[i], state[i + 1] - tmp1, lambda_Q16); - state[i] = tmp1; - acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp1, coef_Q13[coef_Q13_ptr + i - 1]); - tmp1 = Inlines.silk_SMLAWB(state[i + 1], state[i + 2] - tmp2, lambda_Q16); - state[i + 1] = tmp2; - acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp2, coef_Q13[coef_Q13_ptr + i]); - } - state[order] = tmp1; - acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp1, coef_Q13[coef_Q13_ptr + order - 1]); - res_Q2[n] = Inlines.silk_LSHIFT(input[input_ptr + n], 2) - Inlines.silk_RSHIFT_ROUND(acc_Q11, 9); - } - } - - static void silk_prefilter(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, int[] xw_Q3, short[] x, int x_ptr) { - SilkPrefilterState P = psEnc.sPrefilt; - short[] B_Q10 = new short[2]; - int px = x_ptr; - int pxw_Q3 = 0; - int lag = P.lagPrev; - int[] x_filt_Q12 = new int[psEnc.subfr_length]; - int[] st_res_Q2 = new int[psEnc.subfr_length]; - for (int k = 0; k < psEnc.nb_subfr; ++k) { - int HarmShapeGain_Q12; - if (psEnc.indices.signalType == 2) { - lag = psEncCtrl.pitchL[k]; - } - Inlines.OpusAssert((HarmShapeGain_Q12 = Inlines.silk_SMULWB(psEncCtrl.HarmShapeGain_Q14[k], 16384 - psEncCtrl.HarmBoost_Q14[k])) >= 0); - int HarmShapeFIRPacked_Q12 = Inlines.silk_RSHIFT(HarmShapeGain_Q12, 2); - HarmShapeFIRPacked_Q12 |= Inlines.silk_LSHIFT(Inlines.silk_RSHIFT(HarmShapeGain_Q12, 1), 16); - int Tilt_Q14 = psEncCtrl.Tilt_Q14[k]; - int LF_shp_Q14 = psEncCtrl.LF_shp_Q14[k]; - int AR1_shp_Q13 = k * 16; - Filters.silk_warped_LPC_analysis_filter(P.sAR_shp, st_res_Q2, psEncCtrl.AR1_Q13, AR1_shp_Q13, x, px, (short)psEnc.warping_Q16, psEnc.subfr_length, psEnc.shapingLPCOrder); - B_Q10[0] = (short)Inlines.silk_RSHIFT_ROUND(psEncCtrl.GainsPre_Q14[k], 4); - int tmp_32 = Inlines.silk_SMLABB(0x333333, psEncCtrl.HarmBoost_Q14[k], HarmShapeGain_Q12); - tmp_32 = Inlines.silk_SMLABB(tmp_32, psEncCtrl.coding_quality_Q14, 410); - tmp_32 = Inlines.silk_SMULWB(tmp_32, -psEncCtrl.GainsPre_Q14[k]); - tmp_32 = Inlines.silk_RSHIFT_ROUND(tmp_32, 14); - B_Q10[1] = (short)Inlines.silk_SAT16(tmp_32); - x_filt_Q12[0] = Inlines.silk_MLA(Inlines.silk_MUL(st_res_Q2[0], B_Q10[0]), P.sHarmHP_Q2, B_Q10[1]); - for (int j = 1; j < psEnc.subfr_length; ++j) { - x_filt_Q12[j] = Inlines.silk_MLA(Inlines.silk_MUL(st_res_Q2[j], B_Q10[0]), st_res_Q2[j - 1], B_Q10[1]); - } - P.sHarmHP_Q2 = st_res_Q2[psEnc.subfr_length - 1]; - Filters.silk_prefilt(P, x_filt_Q12, xw_Q3, pxw_Q3, HarmShapeFIRPacked_Q12, Tilt_Q14, LF_shp_Q14, lag, psEnc.subfr_length); - px += psEnc.subfr_length; - pxw_Q3 += psEnc.subfr_length; - } - P.lagPrev = psEncCtrl.pitchL[psEnc.nb_subfr - 1]; - } - - static void silk_prefilt(SilkPrefilterState P, int[] st_res_Q12, int[] xw_Q3, int xw_Q3_ptr, int HarmShapeFIRPacked_Q12, int Tilt_Q14, int LF_shp_Q14, int lag, int length) { - short[] LTP_shp_buf = P.sLTP_shp; - int LTP_shp_buf_idx = P.sLTP_shp_buf_idx; - int sLF_AR_shp_Q12 = P.sLF_AR_shp_Q12; - int sLF_MA_shp_Q12 = P.sLF_MA_shp_Q12; - for (int i = 0; i < length; ++i) { - int n_LTP_Q12; - if (lag > 0) { - Inlines.OpusAssert(true); - int idx = lag + LTP_shp_buf_idx; - n_LTP_Q12 = Inlines.silk_SMULBB(LTP_shp_buf[idx - 1 - 1 & 0x1FF], HarmShapeFIRPacked_Q12); - n_LTP_Q12 = Inlines.silk_SMLABT(n_LTP_Q12, LTP_shp_buf[idx - 1 & 0x1FF], HarmShapeFIRPacked_Q12); - n_LTP_Q12 = Inlines.silk_SMLABB(n_LTP_Q12, LTP_shp_buf[idx - 1 + 1 & 0x1FF], HarmShapeFIRPacked_Q12); - } else { - n_LTP_Q12 = 0; - } - int n_Tilt_Q10 = Inlines.silk_SMULWB(sLF_AR_shp_Q12, Tilt_Q14); - int n_LF_Q10 = Inlines.silk_SMLAWB(Inlines.silk_SMULWT(sLF_AR_shp_Q12, LF_shp_Q14), sLF_MA_shp_Q12, LF_shp_Q14); - sLF_AR_shp_Q12 = Inlines.silk_SUB32(st_res_Q12[i], Inlines.silk_LSHIFT(n_Tilt_Q10, 2)); - sLF_MA_shp_Q12 = Inlines.silk_SUB32(sLF_AR_shp_Q12, Inlines.silk_LSHIFT(n_LF_Q10, 2)); - LTP_shp_buf_idx = LTP_shp_buf_idx - 1 & 0x1FF; - LTP_shp_buf[LTP_shp_buf_idx] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sLF_MA_shp_Q12, 12)); - xw_Q3[xw_Q3_ptr + i] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SUB32(sLF_MA_shp_Q12, n_LTP_Q12), 9); - } - P.sLF_AR_shp_Q12 = sLF_AR_shp_Q12; - P.sLF_MA_shp_Q12 = sLF_MA_shp_Q12; - P.sLTP_shp_buf_idx = LTP_shp_buf_idx; - } - - static void silk_biquad_alt(short[] input, int input_ptr, int[] B_Q28, int[] A_Q28, int[] S, short[] output, int output_ptr, int len, int stride) { - int A0_L_Q28 = -A_Q28[0] & 0x3FFF; - int A0_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[0], 14); - int A1_L_Q28 = -A_Q28[1] & 0x3FFF; - int A1_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[1], 14); - for (int k = 0; k < len; ++k) { - short inval = input[input_ptr + k * stride]; - int out32_Q14 = Inlines.silk_LSHIFT(Inlines.silk_SMLAWB(S[0], B_Q28[0], inval), 2); - S[0] = S[1] + Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A0_L_Q28), 14); - S[0] = Inlines.silk_SMLAWB(S[0], out32_Q14, A0_U_Q28); - S[0] = Inlines.silk_SMLAWB(S[0], B_Q28[1], inval); - S[1] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A1_L_Q28), 14); - S[1] = Inlines.silk_SMLAWB(S[1], out32_Q14, A1_U_Q28); - S[1] = Inlines.silk_SMLAWB(S[1], B_Q28[2], inval); - output[output_ptr + k * stride] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(out32_Q14 + 16384 - 1, 14)); - } - } - - static void silk_biquad_alt(short[] input, int input_ptr, int[] B_Q28, int[] A_Q28, int[] S, int S_ptr, short[] output, int output_ptr, int len, int stride) { - int A0_L_Q28 = -A_Q28[0] & 0x3FFF; - int A0_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[0], 14); - int A1_L_Q28 = -A_Q28[1] & 0x3FFF; - int A1_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[1], 14); - for (int k = 0; k < len; ++k) { - int s1 = S_ptr + 1; - short inval = input[input_ptr + k * stride]; - int out32_Q14 = Inlines.silk_LSHIFT(Inlines.silk_SMLAWB(S[S_ptr], B_Q28[0], inval), 2); - S[S_ptr] = S[s1] + Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A0_L_Q28), 14); - S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr], out32_Q14, A0_U_Q28); - S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr], B_Q28[1], inval); - S[s1] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A1_L_Q28), 14); - S[s1] = Inlines.silk_SMLAWB(S[s1], out32_Q14, A1_U_Q28); - S[s1] = Inlines.silk_SMLAWB(S[s1], B_Q28[2], inval); - output[output_ptr + k * stride] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(out32_Q14 + 16384 - 1, 14)); - } - } - - static void silk_ana_filt_bank_1(short[] input, int input_ptr, int[] S, short[] outL, short[] outH, int outH_ptr, int N) { - int N2 = Inlines.silk_RSHIFT(N, 1); - for (int k = 0; k < N2; ++k) { - int in32 = Inlines.silk_LSHIFT(input[input_ptr + 2 * k], 10); - int Y = Inlines.silk_SUB32(in32, S[0]); - int X = Inlines.silk_SMLAWB(Y, Y, -24290); - int out_1 = Inlines.silk_ADD32(S[0], X); - S[0] = Inlines.silk_ADD32(in32, X); - in32 = Inlines.silk_LSHIFT(input[input_ptr + 2 * k + 1], 10); - Y = Inlines.silk_SUB32(in32, S[1]); - X = Inlines.silk_SMULWB(Y, 10788); - int out_2 = Inlines.silk_ADD32(S[1], X); - S[1] = Inlines.silk_ADD32(in32, X); - outL[k] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_ADD32(out_2, out_1), 11)); - outH[outH_ptr + k] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SUB32(out_2, out_1), 11)); - } - } - - static void silk_bwexpander_32(int[] ar, int d, int chirp_Q16) { - int chirp_minus_one_Q16 = chirp_Q16 - 65536; - for (int i = 0; i < d - 1; ++i) { - ar[i] = Inlines.silk_SMULWW(chirp_Q16, ar[i]); - chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, chirp_minus_one_Q16), 16); - } - ar[d - 1] = Inlines.silk_SMULWW(chirp_Q16, ar[d - 1]); - } - - static void silk_LP_interpolate_filter_taps(int[] B_Q28, int[] A_Q28, int ind, int fac_Q16) { - if (ind < 4) { - if (fac_Q16 > 0) { - if (fac_Q16 < 32768) { - for (int nb = 0; nb < 3; ++nb) { - B_Q28[nb] = Inlines.silk_SMLAWB(SilkTables.silk_Transition_LP_B_Q28[ind][nb], SilkTables.silk_Transition_LP_B_Q28[ind + 1][nb] - SilkTables.silk_Transition_LP_B_Q28[ind][nb], fac_Q16); - } - for (int na = 0; na < 2; ++na) { - A_Q28[na] = Inlines.silk_SMLAWB(SilkTables.silk_Transition_LP_A_Q28[ind][na], SilkTables.silk_Transition_LP_A_Q28[ind + 1][na] - SilkTables.silk_Transition_LP_A_Q28[ind][na], fac_Q16); - } - } else { - Inlines.OpusAssert(fac_Q16 - 65536 == Inlines.silk_SAT16(fac_Q16 - 65536)); - for (int nb = 0; nb < 3; ++nb) { - B_Q28[nb] = Inlines.silk_SMLAWB(SilkTables.silk_Transition_LP_B_Q28[ind + 1][nb], SilkTables.silk_Transition_LP_B_Q28[ind + 1][nb] - SilkTables.silk_Transition_LP_B_Q28[ind][nb], fac_Q16 - 65536); - } - for (int na = 0; na < 2; ++na) { - A_Q28[na] = Inlines.silk_SMLAWB(SilkTables.silk_Transition_LP_A_Q28[ind + 1][na], SilkTables.silk_Transition_LP_A_Q28[ind + 1][na] - SilkTables.silk_Transition_LP_A_Q28[ind][na], fac_Q16 - 65536); - } - } - } else { - System.arraycopy(SilkTables.silk_Transition_LP_B_Q28[ind], 0, B_Q28, 0, 3); - System.arraycopy(SilkTables.silk_Transition_LP_A_Q28[ind], 0, A_Q28, 0, 2); - } - } else { - System.arraycopy(SilkTables.silk_Transition_LP_B_Q28[4], 0, B_Q28, 0, 3); - System.arraycopy(SilkTables.silk_Transition_LP_A_Q28[4], 0, A_Q28, 0, 2); - } - } - - static void silk_LPC_analysis_filter(short[] output, int output_ptr, short[] input, int input_ptr, short[] B, int B_ptr, int len, int d) { - int j; - short[] mem = new short[16]; - short[] num = new short[16]; - Inlines.OpusAssert(d >= 6); - Inlines.OpusAssert((d & 1) == 0); - Inlines.OpusAssert(d <= len); - Inlines.OpusAssert(d <= 16); - for (j = 0; j < d; ++j) { - num[j] = (short)(0 - B[B_ptr + j]); - } - for (j = 0; j < d; ++j) { - mem[j] = input[input_ptr + d - j - 1]; - } - Kernels.celt_fir(input, input_ptr + d, num, output, output_ptr + d, len - d, d, mem); - for (j = output_ptr; j < output_ptr + d; ++j) { - output[j] = 0; - } - } - - static int LPC_inverse_pred_gain_QA(int[][] A_QA, int order) { - int rc_mult1_Q30; - int rc_Q31; - int[] Anew_QA = A_QA[order & 1]; - int invGain_Q30 = 0x40000000; - for (int k = order - 1; k > 0; --k) { - if (Anew_QA[k] > 0xFFEF9E || Anew_QA[k] < -16773022) { - return 0; - } - rc_Q31 = 0 - Inlines.silk_LSHIFT(Anew_QA[k], 7); - rc_mult1_Q30 = 0x40000000 - Inlines.silk_SMMUL(rc_Q31, rc_Q31); - Inlines.OpusAssert(rc_mult1_Q30 > 32768); - Inlines.OpusAssert(rc_mult1_Q30 <= 0x40000000); - int mult2Q = 32 - Inlines.silk_CLZ32(Inlines.silk_abs(rc_mult1_Q30)); - int rc_mult2 = Inlines.silk_INVERSE32_varQ(rc_mult1_Q30, mult2Q + 30); - invGain_Q30 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2); - Inlines.OpusAssert(invGain_Q30 >= 0); - Inlines.OpusAssert(invGain_Q30 <= 0x40000000); - int[] Aold_QA = Anew_QA; - Anew_QA = A_QA[k & 1]; - for (int n = 0; n < k; ++n) { - int tmp_QA = Aold_QA[n] - Inlines.MUL32_FRAC_Q(Aold_QA[k - n - 1], rc_Q31, 31); - Anew_QA[n] = Inlines.MUL32_FRAC_Q(tmp_QA, rc_mult2, mult2Q); - } - } - if (Anew_QA[0] > 0xFFEF9E || Anew_QA[0] < -16773022) { - return 0; - } - rc_Q31 = 0 - Inlines.silk_LSHIFT(Anew_QA[0], 7); - rc_mult1_Q30 = 0x40000000 - Inlines.silk_SMMUL(rc_Q31, rc_Q31); - Inlines.OpusAssert((invGain_Q30 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2)) >= 0); - Inlines.OpusAssert(invGain_Q30 <= 0x40000000); - return invGain_Q30; - } - - static int silk_LPC_inverse_pred_gain(short[] A_Q12, int order) { - int[][] Atmp_QA = new int[][]{new int[order], new int[order]}; - int DC_resp = 0; - int[] Anew_QA = Atmp_QA[order & 1]; - for (int k = 0; k < order; ++k) { - DC_resp += A_Q12[k]; - Anew_QA[k] = Inlines.silk_LSHIFT32(A_Q12[k], 12); - } - if (DC_resp >= 4096) { - return 0; - } - return Filters.LPC_inverse_pred_gain_QA(Atmp_QA, order); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/FindLPC.java b/source/decompiled/de/maxhenkel/voicechat/concentus/FindLPC.java deleted file mode 100644 index 9b33036..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/FindLPC.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.BurgModified; -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.NLSF; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SumSqrShift; - -class FindLPC { - FindLPC() { - } - - static void silk_find_LPC(SilkChannelEncoder psEncC, short[] NLSF_Q15, short[] x, int minInvGain_Q30) { - int[] a_Q16 = new int[16]; - BoxedValueInt res_nrg0 = new BoxedValueInt(0); - BoxedValueInt res_nrg1 = new BoxedValueInt(0); - BoxedValueInt rshift0 = new BoxedValueInt(0); - BoxedValueInt rshift1 = new BoxedValueInt(0); - BoxedValueInt scratch_box1 = new BoxedValueInt(0); - BoxedValueInt scratch_box2 = new BoxedValueInt(0); - int[] a_tmp_Q16 = new int[16]; - short[] a_tmp_Q12 = new short[16]; - short[] NLSF0_Q15 = new short[16]; - int subfr_length = psEncC.subfr_length + psEncC.predictLPCOrder; - psEncC.indices.NLSFInterpCoef_Q2 = (byte)4; - BurgModified.silk_burg_modified(scratch_box1, scratch_box2, a_Q16, x, 0, minInvGain_Q30, subfr_length, psEncC.nb_subfr, psEncC.predictLPCOrder); - int res_nrg = scratch_box1.Val; - int res_nrg_Q = scratch_box2.Val; - if (psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == 4) { - BurgModified.silk_burg_modified(scratch_box1, scratch_box2, a_tmp_Q16, x, 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC.predictLPCOrder); - int res_tmp_nrg = scratch_box1.Val; - int res_tmp_nrg_Q = scratch_box2.Val; - int shift = res_tmp_nrg_Q - res_nrg_Q; - if (shift >= 0) { - if (shift < 32) { - res_nrg -= Inlines.silk_RSHIFT(res_tmp_nrg, shift); - } - } else { - Inlines.OpusAssert(shift > -32); - res_nrg = Inlines.silk_RSHIFT(res_nrg, -shift) - res_tmp_nrg; - res_nrg_Q = res_tmp_nrg_Q; - } - NLSF.silk_A2NLSF(NLSF_Q15, a_tmp_Q16, psEncC.predictLPCOrder); - short[] LPC_res = new short[2 * subfr_length]; - for (int k = 3; k >= 0; --k) { - int res_nrg_interp_Q; - Inlines.silk_interpolate(NLSF0_Q15, psEncC.prev_NLSFq_Q15, NLSF_Q15, k, psEncC.predictLPCOrder); - NLSF.silk_NLSF2A(a_tmp_Q12, NLSF0_Q15, psEncC.predictLPCOrder); - Filters.silk_LPC_analysis_filter(LPC_res, 0, x, 0, a_tmp_Q12, 0, 2 * subfr_length, psEncC.predictLPCOrder); - SumSqrShift.silk_sum_sqr_shift(res_nrg0, rshift0, LPC_res, psEncC.predictLPCOrder, subfr_length - psEncC.predictLPCOrder); - SumSqrShift.silk_sum_sqr_shift(res_nrg1, rshift1, LPC_res, psEncC.predictLPCOrder + subfr_length, subfr_length - psEncC.predictLPCOrder); - shift = rshift0.Val - rshift1.Val; - if (shift >= 0) { - res_nrg1.Val = Inlines.silk_RSHIFT(res_nrg1.Val, shift); - res_nrg_interp_Q = 0 - rshift0.Val; - } else { - res_nrg0.Val = Inlines.silk_RSHIFT(res_nrg0.Val, 0 - shift); - res_nrg_interp_Q = 0 - rshift1.Val; - } - int res_nrg_interp = Inlines.silk_ADD32(res_nrg0.Val, res_nrg1.Val); - shift = res_nrg_interp_Q - res_nrg_Q; - boolean isInterpLower = shift >= 0 ? Inlines.silk_RSHIFT(res_nrg_interp, shift) < res_nrg : (-shift < 32 ? res_nrg_interp < Inlines.silk_RSHIFT(res_nrg, -shift) : false); - if (!isInterpLower) continue; - res_nrg = res_nrg_interp; - res_nrg_Q = res_nrg_interp_Q; - psEncC.indices.NLSFInterpCoef_Q2 = (byte)k; - } - } - if (psEncC.indices.NLSFInterpCoef_Q2 == 4) { - NLSF.silk_A2NLSF(NLSF_Q15, a_Q16, psEncC.predictLPCOrder); - } - Inlines.OpusAssert(psEncC.indices.NLSFInterpCoef_Q2 == 4 || psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == 4); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/FindLTP.java b/source/decompiled/de/maxhenkel/voicechat/concentus/FindLTP.java deleted file mode 100644 index fc1f234..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/FindLTP.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CorrelateMatrix; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.LinearAlgebra; -import de.maxhenkel.voicechat.concentus.RegularizeCorrelations; -import de.maxhenkel.voicechat.concentus.ResidualEnergy; -import de.maxhenkel.voicechat.concentus.SumSqrShift; - -class FindLTP { - private static final int LTP_CORRS_HEAD_ROOM = 2; - - FindLTP() { - } - - static void silk_find_LTP(short[] b_Q14, int[] WLTP, BoxedValueInt LTPredCodGain_Q7, short[] r_lpc, int[] lag, int[] Wght_Q15, int subfr_length, int nb_subfr, int mem_offset, int[] corr_rshifts) { - int i; - int temp32; - int extra_shifts; - int k; - int[] b_Q16 = new int[5]; - int[] delta_b_Q14 = new int[5]; - int[] d_Q14 = new int[4]; - int[] nrg = new int[4]; - int[] w = new int[4]; - int[] Rr = new int[5]; - int[] rr = new int[4]; - int b_Q14_ptr = 0; - int WLTP_ptr = 0; - int r_ptr = mem_offset; - for (k = 0; k < nb_subfr; ++k) { - int lag_ptr = r_ptr - (lag[k] + 2); - BoxedValueInt boxed_rr = new BoxedValueInt(0); - BoxedValueInt boxed_rr_shift = new BoxedValueInt(0); - SumSqrShift.silk_sum_sqr_shift(boxed_rr, boxed_rr_shift, r_lpc, r_ptr, subfr_length); - rr[k] = boxed_rr.Val; - int rr_shifts = boxed_rr_shift.Val; - int LZs = Inlines.silk_CLZ32(rr[k]); - if (LZs < 2) { - rr[k] = Inlines.silk_RSHIFT_ROUND(rr[k], 2 - LZs); - rr_shifts += 2 - LZs; - } - corr_rshifts[k] = rr_shifts; - BoxedValueInt boxed_shifts = new BoxedValueInt(corr_rshifts[k]); - CorrelateMatrix.silk_corrMatrix(r_lpc, lag_ptr, subfr_length, 5, 2, WLTP, WLTP_ptr, boxed_shifts); - corr_rshifts[k] = boxed_shifts.Val; - CorrelateMatrix.silk_corrVector(r_lpc, lag_ptr, r_lpc, r_ptr, subfr_length, 5, Rr, corr_rshifts[k]); - if (corr_rshifts[k] > rr_shifts) { - rr[k] = Inlines.silk_RSHIFT(rr[k], corr_rshifts[k] - rr_shifts); - } - Inlines.OpusAssert(rr[k] >= 0); - int regu = 1; - regu = Inlines.silk_SMLAWB(regu, rr[k], 1092); - regu = Inlines.silk_SMLAWB(regu, Inlines.MatrixGet(WLTP, WLTP_ptr, 0, 0, 5), 1092); - regu = Inlines.silk_SMLAWB(regu, Inlines.MatrixGet(WLTP, WLTP_ptr, 4, 4, 5), 1092); - RegularizeCorrelations.silk_regularize_correlations(WLTP, WLTP_ptr, rr, k, regu, 5); - LinearAlgebra.silk_solve_LDL(WLTP, WLTP_ptr, 5, Rr, b_Q16); - FindLTP.silk_fit_LTP(b_Q16, b_Q14, b_Q14_ptr); - nrg[k] = ResidualEnergy.silk_residual_energy16_covar(b_Q14, b_Q14_ptr, WLTP, WLTP_ptr, Rr, rr[k], 5, 14); - extra_shifts = Inlines.silk_min_int(corr_rshifts[k], 2); - int denom32 = Inlines.silk_LSHIFT_SAT32(Inlines.silk_SMULWB(nrg[k], Wght_Q15[k]), 1 + extra_shifts) + Inlines.silk_RSHIFT(Inlines.silk_SMULWB(subfr_length, 655), corr_rshifts[k] - extra_shifts); - denom32 = Inlines.silk_max(denom32, 1); - Inlines.OpusAssert((long)Wght_Q15[k] << 16 < Integer.MAX_VALUE); - temp32 = Inlines.silk_DIV32(Inlines.silk_LSHIFT(Wght_Q15[k], 16), denom32); - temp32 = Inlines.silk_RSHIFT(temp32, 31 + corr_rshifts[k] - extra_shifts - 26); - int WLTP_max = 0; - for (i = WLTP_ptr; i < WLTP_ptr + 25; ++i) { - WLTP_max = Inlines.silk_max(WLTP[i], WLTP_max); - } - int lshift = Inlines.silk_CLZ32(WLTP_max) - 1 - 3; - Inlines.OpusAssert(8 + lshift >= 0); - if (8 + lshift < 31) { - temp32 = Inlines.silk_min_32(temp32, Inlines.silk_LSHIFT(1, 8 + lshift)); - } - Inlines.silk_scale_vector32_Q26_lshift_18(WLTP, WLTP_ptr, temp32, 25); - w[k] = Inlines.MatrixGet(WLTP, WLTP_ptr, 2, 2, 5); - Inlines.OpusAssert(w[k] >= 0); - r_ptr += subfr_length; - b_Q14_ptr += 5; - WLTP_ptr += 25; - } - int maxRshifts = 0; - for (k = 0; k < nb_subfr; ++k) { - maxRshifts = Inlines.silk_max_int(corr_rshifts[k], maxRshifts); - } - if (LTPredCodGain_Q7 != null) { - int LPC_LTP_res_nrg = 0; - int LPC_res_nrg = 0; - Inlines.OpusAssert(true); - for (k = 0; k < nb_subfr; ++k) { - LPC_res_nrg = Inlines.silk_ADD32(LPC_res_nrg, Inlines.silk_RSHIFT(Inlines.silk_ADD32(Inlines.silk_SMULWB(rr[k], Wght_Q15[k]), 1), 1 + (maxRshifts - corr_rshifts[k]))); - LPC_LTP_res_nrg = Inlines.silk_ADD32(LPC_LTP_res_nrg, Inlines.silk_RSHIFT(Inlines.silk_ADD32(Inlines.silk_SMULWB(nrg[k], Wght_Q15[k]), 1), 1 + (maxRshifts - corr_rshifts[k]))); - } - LPC_LTP_res_nrg = Inlines.silk_max(LPC_LTP_res_nrg, 1); - int div_Q16 = Inlines.silk_DIV32_varQ(LPC_res_nrg, LPC_LTP_res_nrg, 16); - LTPredCodGain_Q7.Val = Inlines.silk_SMULBB(3, Inlines.silk_lin2log(div_Q16) - 2048); - Inlines.OpusAssert(LTPredCodGain_Q7.Val == Inlines.silk_SAT16(Inlines.silk_MUL(3, Inlines.silk_lin2log(div_Q16) - 2048))); - } - b_Q14_ptr = 0; - for (k = 0; k < nb_subfr; ++k) { - d_Q14[k] = 0; - for (i = b_Q14_ptr; i < b_Q14_ptr + 5; ++i) { - int n = k; - d_Q14[n] = d_Q14[n] + b_Q14[i]; - } - b_Q14_ptr += 5; - } - int max_abs_d_Q14 = 0; - int max_w_bits = 0; - for (k = 0; k < nb_subfr; ++k) { - max_abs_d_Q14 = Inlines.silk_max_32(max_abs_d_Q14, Inlines.silk_abs(d_Q14[k])); - max_w_bits = Inlines.silk_max_32(max_w_bits, 32 - Inlines.silk_CLZ32(w[k]) + corr_rshifts[k] - maxRshifts); - } - Inlines.OpusAssert(max_abs_d_Q14 <= 163840); - extra_shifts = max_w_bits + 32 - Inlines.silk_CLZ32(max_abs_d_Q14) - 14; - extra_shifts -= 29 + maxRshifts; - extra_shifts = Inlines.silk_max_int(extra_shifts, 0); - int maxRshifts_wxtra = maxRshifts + extra_shifts; - temp32 = Inlines.silk_RSHIFT(262, maxRshifts + extra_shifts) + 1; - int wd = 0; - for (k = 0; k < nb_subfr; ++k) { - temp32 = Inlines.silk_ADD32(temp32, Inlines.silk_RSHIFT(w[k], maxRshifts_wxtra - corr_rshifts[k])); - wd = Inlines.silk_ADD32(wd, Inlines.silk_LSHIFT(Inlines.silk_SMULWW(Inlines.silk_RSHIFT(w[k], maxRshifts_wxtra - corr_rshifts[k]), d_Q14[k]), 2)); - } - int m_Q12 = Inlines.silk_DIV32_varQ(wd, temp32, 12); - b_Q14_ptr = 0; - for (k = 0; k < nb_subfr; ++k) { - temp32 = 2 - corr_rshifts[k] > 0 ? Inlines.silk_RSHIFT(w[k], 2 - corr_rshifts[k]) : Inlines.silk_LSHIFT_SAT32(w[k], corr_rshifts[k] - 2); - int g_Q26 = Inlines.silk_MUL(Inlines.silk_DIV32(0x666667, Inlines.silk_RSHIFT(0x666667, 10) + temp32), Inlines.silk_LSHIFT_SAT32(Inlines.silk_SUB_SAT32(m_Q12, Inlines.silk_RSHIFT(d_Q14[k], 2)), 4)); - temp32 = 0; - for (i = 0; i < 5; ++i) { - delta_b_Q14[i] = Inlines.silk_max_16(b_Q14[b_Q14_ptr + i], (short)1638); - temp32 += delta_b_Q14[i]; - } - temp32 = Inlines.silk_DIV32(g_Q26, temp32); - for (i = 0; i < 5; ++i) { - b_Q14[b_Q14_ptr + i] = (short)Inlines.silk_LIMIT_32(b_Q14[b_Q14_ptr + i] + Inlines.silk_SMULWB(Inlines.silk_LSHIFT_SAT32(temp32, 4), delta_b_Q14[i]), -16000, 28000); - } - b_Q14_ptr += 5; - } - } - - static void silk_fit_LTP(int[] LTP_coefs_Q16, short[] LTP_coefs_Q14, int LTP_coefs_Q14_ptr) { - for (int i = 0; i < 5; ++i) { - LTP_coefs_Q14[LTP_coefs_Q14_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(LTP_coefs_Q16[i], 2)); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/FindPitchLags.java b/source/decompiled/de/maxhenkel/voicechat/concentus/FindPitchLags.java deleted file mode 100644 index 292a83b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/FindPitchLags.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.ApplySineWindow; -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Autocorrelation; -import de.maxhenkel.voicechat.concentus.BWExpander; -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.BoxedValueShort; -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.K2A; -import de.maxhenkel.voicechat.concentus.PitchAnalysisCore; -import de.maxhenkel.voicechat.concentus.Schur; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkEncoderControl; - -class FindPitchLags { - FindPitchLags() { - } - - static void silk_find_pitch_lags(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, short[] res, short[] x, int x_ptr) { - int[] auto_corr = new int[17]; - short[] rc_Q15 = new short[16]; - int[] A_Q24 = new int[16]; - short[] A_Q12 = new short[16]; - int buf_len = psEnc.la_pitch + psEnc.frame_length + psEnc.ltp_mem_length; - Inlines.OpusAssert(buf_len >= psEnc.pitch_LPC_win_length); - int x_buf = x_ptr - psEnc.ltp_mem_length; - short[] Wsig = new short[psEnc.pitch_LPC_win_length]; - int x_buf_ptr = x_buf + buf_len - psEnc.pitch_LPC_win_length; - int Wsig_ptr = 0; - ApplySineWindow.silk_apply_sine_window(Wsig, Wsig_ptr, x, x_buf_ptr, 1, psEnc.la_pitch); - System.arraycopy(x, x_buf_ptr += psEnc.la_pitch, Wsig, Wsig_ptr += psEnc.la_pitch, psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1)); - ApplySineWindow.silk_apply_sine_window(Wsig, Wsig_ptr += psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1), x, x_buf_ptr += psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1), 2, psEnc.la_pitch); - BoxedValueInt boxed_scale = new BoxedValueInt(0); - Autocorrelation.silk_autocorr(auto_corr, boxed_scale, Wsig, psEnc.pitch_LPC_win_length, psEnc.pitchEstimationLPCOrder + 1); - int scale = boxed_scale.Val; - auto_corr[0] = Inlines.silk_SMLAWB(auto_corr[0], auto_corr[0], 66) + 1; - int res_nrg = Schur.silk_schur(rc_Q15, auto_corr, psEnc.pitchEstimationLPCOrder); - psEncCtrl.predGain_Q16 = Inlines.silk_DIV32_varQ(auto_corr[0], Inlines.silk_max_int(res_nrg, 1), 16); - K2A.silk_k2a(A_Q24, rc_Q15, psEnc.pitchEstimationLPCOrder); - for (int i = 0; i < psEnc.pitchEstimationLPCOrder; ++i) { - A_Q12[i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(A_Q24[i], 12)); - } - BWExpander.silk_bwexpander(A_Q12, psEnc.pitchEstimationLPCOrder, 64881); - Filters.silk_LPC_analysis_filter(res, 0, x, x_buf, A_Q12, 0, buf_len, psEnc.pitchEstimationLPCOrder); - if (psEnc.indices.signalType != 0 && psEnc.first_frame_after_reset == 0) { - int thrhld_Q13 = 4915; - thrhld_Q13 = Inlines.silk_SMLABB(thrhld_Q13, -32, psEnc.pitchEstimationLPCOrder); - thrhld_Q13 = Inlines.silk_SMLAWB(thrhld_Q13, -209714, psEnc.speech_activity_Q8); - thrhld_Q13 = Inlines.silk_SMLABB(thrhld_Q13, -1228, Inlines.silk_RSHIFT(psEnc.prevSignalType, 1)); - thrhld_Q13 = Inlines.silk_SMLAWB(thrhld_Q13, -1637, psEnc.input_tilt_Q15); - BoxedValueShort boxed_lagIndex = new BoxedValueShort(psEnc.indices.lagIndex); - BoxedValueByte boxed_contourIndex = new BoxedValueByte(psEnc.indices.contourIndex); - BoxedValueInt boxed_LTPcorr = new BoxedValueInt(psEnc.LTPCorr_Q15); - psEnc.indices.signalType = PitchAnalysisCore.silk_pitch_analysis_core(res, psEncCtrl.pitchL, boxed_lagIndex, boxed_contourIndex, boxed_LTPcorr, psEnc.prevLag, psEnc.pitchEstimationThreshold_Q16, thrhld_Q13 = Inlines.silk_SAT16(thrhld_Q13), psEnc.fs_kHz, psEnc.pitchEstimationComplexity, psEnc.nb_subfr) == 0 ? (byte)2 : (byte)1; - psEnc.indices.lagIndex = boxed_lagIndex.Val; - psEnc.indices.contourIndex = boxed_contourIndex.Val; - psEnc.LTPCorr_Q15 = boxed_LTPcorr.Val; - } else { - Arrays.MemSet(psEncCtrl.pitchL, 0, 4); - psEnc.indices.lagIndex = 0; - psEnc.indices.contourIndex = 0; - psEnc.LTPCorr_Q15 = 0; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/FindPredCoefs.java b/source/decompiled/de/maxhenkel/voicechat/concentus/FindPredCoefs.java deleted file mode 100644 index 023e657..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/FindPredCoefs.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.FindLPC; -import de.maxhenkel.voicechat.concentus.FindLTP; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.LTPAnalysisFilter; -import de.maxhenkel.voicechat.concentus.LTPScaleControl; -import de.maxhenkel.voicechat.concentus.NLSF; -import de.maxhenkel.voicechat.concentus.QuantizeLTPGains; -import de.maxhenkel.voicechat.concentus.ResidualEnergy; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkEncoderControl; - -class FindPredCoefs { - FindPredCoefs() { - } - - static void silk_find_pred_coefs(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, short[] res_pitch, short[] x, int x_ptr, int condCoding) { - int minInvGain_Q30; - int i; - int[] invGains_Q16 = new int[4]; - int[] local_gains = new int[4]; - int[] Wght_Q15 = new int[4]; - short[] NLSF_Q15 = new short[16]; - int[] LTP_corrs_rshift = new int[4]; - int min_gain_Q16 = 0x1FFFFFF; - for (i = 0; i < psEnc.nb_subfr; ++i) { - min_gain_Q16 = Inlines.silk_min(min_gain_Q16, psEncCtrl.Gains_Q16[i]); - } - for (i = 0; i < psEnc.nb_subfr; ++i) { - Inlines.OpusAssert(psEncCtrl.Gains_Q16[i] > 0); - invGains_Q16[i] = Inlines.silk_DIV32_varQ(min_gain_Q16, psEncCtrl.Gains_Q16[i], 14); - invGains_Q16[i] = Inlines.silk_max(invGains_Q16[i], 363); - Inlines.OpusAssert(invGains_Q16[i] == Inlines.silk_SAT16(invGains_Q16[i])); - int tmp = Inlines.silk_SMULWB(invGains_Q16[i], invGains_Q16[i]); - Wght_Q15[i] = Inlines.silk_RSHIFT(tmp, 1); - local_gains[i] = Inlines.silk_DIV32(65536, invGains_Q16[i]); - } - short[] LPC_in_pre = new short[psEnc.nb_subfr * psEnc.predictLPCOrder + psEnc.frame_length]; - if (psEnc.indices.signalType == 2) { - Inlines.OpusAssert(psEnc.ltp_mem_length - psEnc.predictLPCOrder >= psEncCtrl.pitchL[0] + 2); - int[] WLTP = new int[psEnc.nb_subfr * 5 * 5]; - BoxedValueInt boxed_codgain = new BoxedValueInt(psEncCtrl.LTPredCodGain_Q7); - FindLTP.silk_find_LTP(psEncCtrl.LTPCoef_Q14, WLTP, boxed_codgain, res_pitch, psEncCtrl.pitchL, Wght_Q15, psEnc.subfr_length, psEnc.nb_subfr, psEnc.ltp_mem_length, LTP_corrs_rshift); - psEncCtrl.LTPredCodGain_Q7 = boxed_codgain.Val; - BoxedValueByte boxed_periodicity = new BoxedValueByte(psEnc.indices.PERIndex); - BoxedValueInt boxed_gain = new BoxedValueInt(psEnc.sum_log_gain_Q7); - QuantizeLTPGains.silk_quant_LTP_gains(psEncCtrl.LTPCoef_Q14, psEnc.indices.LTPIndex, boxed_periodicity, boxed_gain, WLTP, psEnc.mu_LTP_Q9, psEnc.LTPQuantLowComplexity, psEnc.nb_subfr); - psEnc.indices.PERIndex = boxed_periodicity.Val; - psEnc.sum_log_gain_Q7 = boxed_gain.Val; - LTPScaleControl.silk_LTP_scale_ctrl(psEnc, psEncCtrl, condCoding); - LTPAnalysisFilter.silk_LTP_analysis_filter(LPC_in_pre, x, x_ptr - psEnc.predictLPCOrder, psEncCtrl.LTPCoef_Q14, psEncCtrl.pitchL, invGains_Q16, psEnc.subfr_length, psEnc.nb_subfr, psEnc.predictLPCOrder); - } else { - int x_ptr2 = x_ptr - psEnc.predictLPCOrder; - int x_pre_ptr = 0; - for (i = 0; i < psEnc.nb_subfr; ++i) { - Inlines.silk_scale_copy_vector16(LPC_in_pre, x_pre_ptr, x, x_ptr2, invGains_Q16[i], psEnc.subfr_length + psEnc.predictLPCOrder); - x_pre_ptr += psEnc.subfr_length + psEnc.predictLPCOrder; - x_ptr2 += psEnc.subfr_length; - } - Arrays.MemSet(psEncCtrl.LTPCoef_Q14, (short)0, psEnc.nb_subfr * 5); - psEncCtrl.LTPredCodGain_Q7 = 0; - psEnc.sum_log_gain_Q7 = 0; - } - if (psEnc.first_frame_after_reset != 0) { - minInvGain_Q30 = 10737418; - } else { - minInvGain_Q30 = Inlines.silk_log2lin(Inlines.silk_SMLAWB(2048, psEncCtrl.LTPredCodGain_Q7, 21845)); - minInvGain_Q30 = Inlines.silk_DIV32_varQ(minInvGain_Q30, Inlines.silk_SMULWW(10000, Inlines.silk_SMLAWB(65536, 196608, psEncCtrl.coding_quality_Q14)), 14); - } - FindLPC.silk_find_LPC(psEnc, NLSF_Q15, LPC_in_pre, minInvGain_Q30); - NLSF.silk_process_NLSFs(psEnc, psEncCtrl.PredCoef_Q12, NLSF_Q15, psEnc.prev_NLSFq_Q15); - ResidualEnergy.silk_residual_energy(psEncCtrl.ResNrg, psEncCtrl.ResNrgQ, LPC_in_pre, psEncCtrl.PredCoef_Q12, local_gains, psEnc.subfr_length, psEnc.nb_subfr, psEnc.predictLPCOrder); - System.arraycopy(NLSF_Q15, 0, psEnc.prev_NLSFq_Q15, 0, 16); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/GainQuantization.java b/source/decompiled/de/maxhenkel/voicechat/concentus/GainQuantization.java deleted file mode 100644 index ffd3562..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/GainQuantization.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.Inlines; - -class GainQuantization { - private static final int OFFSET = 2090; - private static final int SCALE_Q16 = 2251; - private static final int INV_SCALE_Q16 = 1907825; - - GainQuantization() { - } - - static void silk_gains_quant(byte[] ind, int[] gain_Q16, BoxedValueByte prev_ind, int conditional, int nb_subfr) { - for (int k = 0; k < nb_subfr; ++k) { - ind[k] = (byte)Inlines.silk_SMULWB(2251, Inlines.silk_lin2log(gain_Q16[k]) - 2090); - if (ind[k] < prev_ind.Val) { - int n = k; - ind[n] = (byte)(ind[n] + 1); - } - ind[k] = (byte)Inlines.silk_LIMIT_int(ind[k], 0, 63); - if (k == 0 && conditional == 0) { - ind[k] = (byte)Inlines.silk_LIMIT_int(ind[k], prev_ind.Val + -4, 63); - prev_ind.Val = ind[k]; - } else { - ind[k] = (byte)(ind[k] - prev_ind.Val); - int double_step_size_threshold = 8 + prev_ind.Val; - if (ind[k] > double_step_size_threshold) { - ind[k] = (byte)(double_step_size_threshold + Inlines.silk_RSHIFT(ind[k] - double_step_size_threshold + 1, 1)); - } - ind[k] = (byte)Inlines.silk_LIMIT_int(ind[k], -4, 36); - prev_ind.Val = ind[k] > double_step_size_threshold ? (byte)(prev_ind.Val + (byte)(Inlines.silk_LSHIFT(ind[k], 1) - double_step_size_threshold)) : (byte)(prev_ind.Val + ind[k]); - int n = k; - ind[n] = (byte)(ind[n] - -4); - } - gain_Q16[k] = Inlines.silk_log2lin(Inlines.silk_min_32(Inlines.silk_SMULWB(1907825, prev_ind.Val) + 2090, 3967)); - } - } - - static void silk_gains_dequant(int[] gain_Q16, byte[] ind, BoxedValueByte prev_ind, int conditional, int nb_subfr) { - for (int k = 0; k < nb_subfr; ++k) { - int double_step_size_threshold; - int ind_tmp; - prev_ind.Val = k == 0 && conditional == 0 ? (byte)Inlines.silk_max_int(ind[k], prev_ind.Val - 16) : ((ind_tmp = ind[k] + -4) > (double_step_size_threshold = 8 + prev_ind.Val) ? (byte)(prev_ind.Val + (byte)(Inlines.silk_LSHIFT(ind_tmp, 1) - double_step_size_threshold)) : (byte)(prev_ind.Val + (byte)ind_tmp)); - prev_ind.Val = (byte)Inlines.silk_LIMIT_int(prev_ind.Val, 0, 63); - gain_Q16[k] = Inlines.silk_log2lin(Inlines.silk_min_32(Inlines.silk_SMULWB(1907825, prev_ind.Val) + 2090, 3967)); - } - } - - static int silk_gains_ID(byte[] ind, int nb_subfr) { - int gainsID = 0; - for (int k = 0; k < nb_subfr; ++k) { - gainsID = Inlines.silk_ADD_LSHIFT32(ind[k], gainsID, 8); - } - return gainsID; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/HPVariableCutoff.java b/source/decompiled/de/maxhenkel/voicechat/concentus/HPVariableCutoff.java deleted file mode 100644 index 924b732..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/HPVariableCutoff.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; - -class HPVariableCutoff { - HPVariableCutoff() { - } - - static void silk_HP_variable_cutoff(SilkChannelEncoder[] state_Fxx) { - SilkChannelEncoder psEncC1 = state_Fxx[0]; - if (psEncC1.prevSignalType == 2) { - int pitch_freq_Hz_Q16 = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(Inlines.silk_MUL(psEncC1.fs_kHz, 1000), 16), psEncC1.prevLag); - int pitch_freq_log_Q7 = Inlines.silk_lin2log(pitch_freq_Hz_Q16) - 2048; - int quality_Q15 = psEncC1.input_quality_bands_Q15[0]; - int delta_freq_Q7 = (pitch_freq_log_Q7 = Inlines.silk_SMLAWB(pitch_freq_log_Q7, Inlines.silk_SMULWB(Inlines.silk_LSHIFT(-quality_Q15, 2), quality_Q15), pitch_freq_log_Q7 - (Inlines.silk_lin2log(0x3C0000) - 2048))) - Inlines.silk_RSHIFT(psEncC1.variable_HP_smth1_Q15, 8); - if (delta_freq_Q7 < 0) { - delta_freq_Q7 = Inlines.silk_MUL(delta_freq_Q7, 3); - } - delta_freq_Q7 = Inlines.silk_LIMIT_32(delta_freq_Q7, -51, 51); - psEncC1.variable_HP_smth1_Q15 = Inlines.silk_SMLAWB(psEncC1.variable_HP_smth1_Q15, Inlines.silk_SMULBB(psEncC1.speech_activity_Q8, delta_freq_Q7), 6554); - psEncC1.variable_HP_smth1_Q15 = Inlines.silk_LIMIT_32(psEncC1.variable_HP_smth1_Q15, Inlines.silk_LSHIFT(Inlines.silk_lin2log(60), 8), Inlines.silk_LSHIFT(Inlines.silk_lin2log(100), 8)); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Inlines.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Inlines.java deleted file mode 100644 index 7d17551..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Inlines.java +++ /dev/null @@ -1,1263 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.PitchAnalysisCore; - -class Inlines { - private static short[] sqrt_C = new short[]{23175, 11561, -3011, 1699, -664}; - private static short log2_C0 = (short)-6793; - - Inlines() { - } - - static void OpusAssert(boolean condition) { - if (!condition) { - throw new AssertionError(); - } - } - - static void OpusAssert(boolean condition, String message) { - if (!condition) { - throw new AssertionError((Object)message); - } - } - - static long CapToUInt32(long val) { - return 0xFFFFFFFFL & (long)((int)val); - } - - static long CapToUInt32(int val) { - return val; - } - - static int MULT16_16SU(int a, int b) { - return (short)a * (b & 0xFFFF); - } - - static int MULT16_32_Q16(short a, int b) { - return Inlines.ADD32(Inlines.MULT16_16((int)a, Inlines.SHR(b, 16)), Inlines.SHR(Inlines.MULT16_16SU(a, b & 0xFFFF), 16)); - } - - static int MULT16_32_Q16(int a, int b) { - return Inlines.ADD32(Inlines.MULT16_16(a, Inlines.SHR(b, 16)), Inlines.SHR(Inlines.MULT16_16SU(a, b & 0xFFFF), 16)); - } - - static int MULT16_32_P16(short a, int b) { - return Inlines.ADD32(Inlines.MULT16_16((int)a, Inlines.SHR(b, 16)), Inlines.PSHR(Inlines.MULT16_16SU(a, b & 0xFFFF), 16)); - } - - static int MULT16_32_P16(int a, int b) { - return Inlines.ADD32(Inlines.MULT16_16(a, Inlines.SHR(b, 16)), Inlines.PSHR(Inlines.MULT16_16SU(a, b & 0xFFFF), 16)); - } - - static int MULT16_32_Q15(short a, int b) { - return (a * (b >> 16) << 1) + (a * (b & 0xFFFF) >> 15); - } - - static int MULT16_32_Q15(int a, int b) { - return (a * (b >> 16) << 1) + (a * (b & 0xFFFF) >> 15); - } - - static int MULT32_32_Q31(int a, int b) { - return Inlines.ADD32(Inlines.ADD32(Inlines.SHL(Inlines.MULT16_16(Inlines.SHR(a, 16), Inlines.SHR(b, 16)), 1), Inlines.SHR(Inlines.MULT16_16SU(Inlines.SHR(a, 16), b & 0xFFFF), 15)), Inlines.SHR(Inlines.MULT16_16SU(Inlines.SHR(b, 16), a & 0xFFFF), 15)); - } - - static short QCONST16(float x, int bits) { - return (short)(0.5 + (double)(x * (float)(1 << bits))); - } - - static int QCONST32(float x, int bits) { - return (int)(0.5 + (double)(x * (float)(1 << bits))); - } - - static short NEG16(short x) { - return (short)(0 - x); - } - - static int NEG16(int x) { - return 0 - x; - } - - static int NEG32(int x) { - return 0 - x; - } - - static short EXTRACT16(int x) { - return (short)x; - } - - static int EXTEND32(short x) { - return x; - } - - static int EXTEND32(int x) { - return x; - } - - static short SHR16(short a, int shift) { - return (short)(a >> shift); - } - - static int SHR16(int a, int shift) { - return a >> shift; - } - - static short SHL16(short a, int shift) { - return (short)((a & 0xFFFF) << shift); - } - - static int SHL16(int a, int shift) { - return (int)(0xFFFFFFFFFFFFFFFFL & (long)a << shift); - } - - static int SHR32(int a, int shift) { - return a >> shift; - } - - static int SHL32(int a, int shift) { - return (int)(0xFFFFFFFFFFFFFFFFL & (long)a << shift); - } - - static int PSHR32(int a, int shift) { - return Inlines.SHR32(a + (Inlines.EXTEND32(1) << shift >> 1), shift); - } - - static short PSHR16(short a, int shift) { - return Inlines.SHR16((short)(a + (1 << shift >> 1)), shift); - } - - static int PSHR16(int a, int shift) { - return Inlines.SHR32(a + (1 << shift >> 1), shift); - } - - static int VSHR32(int a, int shift) { - return shift > 0 ? Inlines.SHR32(a, shift) : Inlines.SHL32(a, -shift); - } - - private static int SHR(int a, int shift) { - return a >> shift; - } - - private static int SHL(int a, int shift) { - return Inlines.SHL32(a, shift); - } - - private static int SHR(short a, int shift) { - return a >> shift; - } - - private static int SHL(short a, int shift) { - return Inlines.SHL32(a, shift); - } - - private static int PSHR(int a, int shift) { - return Inlines.SHR(a + (Inlines.EXTEND32(1) << shift >> 1), shift); - } - - static int SATURATE(int x, int a) { - return x > a ? a : (x < -a ? -a : x); - } - - static short SATURATE16(int x) { - return Inlines.EXTRACT16(x > Short.MAX_VALUE ? Short.MAX_VALUE : (x < Short.MIN_VALUE ? Short.MIN_VALUE : x)); - } - - static short ROUND16(short x, short a) { - return Inlines.EXTRACT16(Inlines.PSHR32(x, a)); - } - - static int ROUND16(int x, int a) { - return Inlines.PSHR32(x, a); - } - - static int PDIV32(int a, int b) { - return a / b; - } - - static short HALF16(short x) { - return Inlines.SHR16(x, 1); - } - - static int HALF16(int x) { - return Inlines.SHR32(x, 1); - } - - static int HALF32(int x) { - return Inlines.SHR32(x, 1); - } - - static short ADD16(short a, short b) { - return (short)(a + b); - } - - static int ADD16(int a, int b) { - return a + b; - } - - static short SUB16(short a, short b) { - return (short)(a - b); - } - - static int SUB16(int a, int b) { - return a - b; - } - - static int ADD32(int a, int b) { - return a + b; - } - - static int SUB32(int a, int b) { - return a - b; - } - - static short MULT16_16_16(short a, short b) { - return (short)(a * b); - } - - static int MULT16_16_16(int a, int b) { - return a * b; - } - - static int MULT16_16(int a, int b) { - return a * b; - } - - static int MULT16_16(short a, short b) { - return a * b; - } - - static int MAC16_16(short c, short a, short b) { - return c + a * b; - } - - static int MAC16_16(int c, short a, short b) { - return c + a * b; - } - - static int MAC16_16(int c, int a, int b) { - return c + a * b; - } - - static int MAC16_32_Q15(int c, short a, short b) { - return Inlines.ADD32(c, Inlines.ADD32(Inlines.MULT16_16((int)a, Inlines.SHR(b, 15)), Inlines.SHR(Inlines.MULT16_16((int)a, b & Short.MAX_VALUE), 15))); - } - - static int MAC16_32_Q15(int c, int a, int b) { - return Inlines.ADD32(c, Inlines.ADD32(Inlines.MULT16_16(a, Inlines.SHR(b, 15)), Inlines.SHR(Inlines.MULT16_16(a, b & Short.MAX_VALUE), 15))); - } - - static int MAC16_32_Q16(int c, short a, short b) { - return Inlines.ADD32(c, Inlines.ADD32(Inlines.MULT16_16((int)a, Inlines.SHR(b, 16)), Inlines.SHR(Inlines.MULT16_16SU(a, b & 0xFFFF), 16))); - } - - static int MAC16_32_Q16(int c, int a, int b) { - return Inlines.ADD32(c, Inlines.ADD32(Inlines.MULT16_16(a, Inlines.SHR(b, 16)), Inlines.SHR(Inlines.MULT16_16SU(a, b & 0xFFFF), 16))); - } - - static int MULT16_16_Q11_32(short a, short b) { - return Inlines.SHR(Inlines.MULT16_16(a, b), 11); - } - - static int MULT16_16_Q11_32(int a, int b) { - return Inlines.SHR(Inlines.MULT16_16(a, b), 11); - } - - static short MULT16_16_Q11(short a, short b) { - return (short)Inlines.SHR(Inlines.MULT16_16(a, b), 11); - } - - static int MULT16_16_Q11(int a, int b) { - return Inlines.SHR(Inlines.MULT16_16(a, b), 11); - } - - static short MULT16_16_Q13(short a, short b) { - return (short)Inlines.SHR(Inlines.MULT16_16(a, b), 13); - } - - static int MULT16_16_Q13(int a, int b) { - return Inlines.SHR(Inlines.MULT16_16(a, b), 13); - } - - static short MULT16_16_Q14(short a, short b) { - return (short)Inlines.SHR(Inlines.MULT16_16(a, b), 14); - } - - static int MULT16_16_Q14(int a, int b) { - return Inlines.SHR(Inlines.MULT16_16(a, b), 14); - } - - static short MULT16_16_Q15(short a, short b) { - return (short)Inlines.SHR(Inlines.MULT16_16(a, b), 15); - } - - static int MULT16_16_Q15(int a, int b) { - return Inlines.SHR(Inlines.MULT16_16(a, b), 15); - } - - static short MULT16_16_P13(short a, short b) { - return (short)Inlines.SHR(Inlines.ADD32(4096, Inlines.MULT16_16(a, b)), 13); - } - - static int MULT16_16_P13(int a, int b) { - return Inlines.SHR(Inlines.ADD32(4096, Inlines.MULT16_16(a, b)), 13); - } - - static short MULT16_16_P14(short a, short b) { - return (short)Inlines.SHR(Inlines.ADD32(8192, Inlines.MULT16_16(a, b)), 14); - } - - static int MULT16_16_P14(int a, int b) { - return Inlines.SHR(Inlines.ADD32(8192, Inlines.MULT16_16(a, b)), 14); - } - - static short MULT16_16_P15(short a, short b) { - return (short)Inlines.SHR(Inlines.ADD32(16384, Inlines.MULT16_16(a, b)), 15); - } - - static int MULT16_16_P15(int a, int b) { - return Inlines.SHR(Inlines.ADD32(16384, Inlines.MULT16_16(a, b)), 15); - } - - static short DIV32_16(int a, short b) { - return (short)(a / b); - } - - static int DIV32_16(int a, int b) { - return a / b; - } - - static int DIV32(int a, int b) { - return a / b; - } - - static short SAT16(int x) { - return (short)(x > Short.MAX_VALUE ? Short.MAX_VALUE : (short)(x < Short.MIN_VALUE ? Short.MIN_VALUE : (short)x)); - } - - static short SIG2WORD16(int x) { - x = Inlines.PSHR32(x, 12); - x = Inlines.MAX32(x, Short.MIN_VALUE); - x = Inlines.MIN32(x, Short.MAX_VALUE); - return Inlines.EXTRACT16(x); - } - - static short MIN(short a, short b) { - return a < b ? a : b; - } - - static short MAX(short a, short b) { - return a > b ? a : b; - } - - static short MIN16(short a, short b) { - return a < b ? a : b; - } - - static short MAX16(short a, short b) { - return a > b ? a : b; - } - - static int MIN16(int a, int b) { - return a < b ? a : b; - } - - static int MAX16(int a, int b) { - return a > b ? a : b; - } - - static float MIN16(float a, float b) { - return a < b ? a : b; - } - - static float MAX16(float a, float b) { - return a > b ? a : b; - } - - static int MIN(int a, int b) { - return a < b ? a : b; - } - - static int MAX(int a, int b) { - return a > b ? a : b; - } - - static int IMIN(int a, int b) { - return a < b ? a : b; - } - - static long IMIN(long a, long b) { - return a < b ? a : b; - } - - static int IMAX(int a, int b) { - return a > b ? a : b; - } - - static int MIN32(int a, int b) { - return a < b ? a : b; - } - - static int MAX32(int a, int b) { - return a > b ? a : b; - } - - static float MIN32(float a, float b) { - return a < b ? a : b; - } - - static float MAX32(float a, float b) { - return a > b ? a : b; - } - - static int ABS16(int x) { - return x < 0 ? -x : x; - } - - static float ABS16(float x) { - return x < 0.0f ? -x : x; - } - - static short ABS16(short x) { - return x < 0 ? -x : x; - } - - static int ABS32(int x) { - return x < 0 ? -x : x; - } - - static int celt_udiv(int n, int d) { - Inlines.OpusAssert(d > 0); - return n / d; - } - - static int celt_sudiv(int n, int d) { - Inlines.OpusAssert(d > 0); - return n / d; - } - - static int celt_div(int a, int b) { - return Inlines.MULT32_32_Q31(a, Inlines.celt_rcp(b)); - } - - static int celt_ilog2(int x) { - Inlines.OpusAssert(x > 0, "celt_ilog2() only defined for strictly positive numbers"); - return Inlines.EC_ILOG(x) - 1; - } - - static int celt_zlog2(int x) { - return x <= 0 ? 0 : Inlines.celt_ilog2(x); - } - - static int celt_maxabs16(int[] x, int x_ptr, int len) { - int maxval = 0; - int minval = 0; - for (int i = x_ptr; i < len + x_ptr; ++i) { - maxval = Inlines.MAX32(maxval, x[i]); - minval = Inlines.MIN32(minval, x[i]); - } - return Inlines.MAX32(Inlines.EXTEND32(maxval), -Inlines.EXTEND32(minval)); - } - - static int celt_maxabs32(int[] x, int x_ptr, int len) { - int maxval = 0; - int minval = 0; - for (int i = x_ptr; i < x_ptr + len; ++i) { - maxval = Inlines.MAX32(maxval, x[i]); - minval = Inlines.MIN32(minval, x[i]); - } - return Inlines.MAX32(maxval, 0 - minval); - } - - static short celt_maxabs32(short[] x, int x_ptr, int len) { - short maxval = 0; - short minval = 0; - for (int i = x_ptr; i < x_ptr + len; ++i) { - maxval = Inlines.MAX16(maxval, x[i]); - minval = Inlines.MIN16(minval, x[i]); - } - return Inlines.MAX(maxval, (short)(0 - minval)); - } - - static int FRAC_MUL16(int a, int b) { - return 16384 + (short)a * (short)b >> 15; - } - - static int isqrt32(long _val) { - int g = 0; - int bshift = Inlines.EC_ILOG(_val) - 1 >> 1; - int b = 1 << bshift; - do { - long t; - if ((t = (long)((g << 1) + b << bshift)) <= _val) { - g += b; - _val -= t; - } - b >>= 1; - } while (--bshift >= 0); - return g; - } - - static int celt_sqrt(int x) { - if (x == 0) { - return 0; - } - if (x >= 0x40000000) { - return Short.MAX_VALUE; - } - int k = (Inlines.celt_ilog2(x) >> 1) - 7; - x = Inlines.VSHR32(x, 2 * k); - short n = (short)(x - 32768); - int rt = Inlines.ADD16(sqrt_C[0], Inlines.MULT16_16_Q15(n, Inlines.ADD16(sqrt_C[1], Inlines.MULT16_16_Q15(n, Inlines.ADD16(sqrt_C[2], Inlines.MULT16_16_Q15(n, Inlines.ADD16(sqrt_C[3], Inlines.MULT16_16_Q15(n, sqrt_C[4])))))))); - rt = Inlines.VSHR32(rt, 7 - k); - return rt; - } - - static int celt_rcp(int x) { - Inlines.OpusAssert(x > 0, "celt_rcp() only defined for positive values"); - int i = Inlines.celt_ilog2(x); - int n = Inlines.VSHR32(x, i - 15) - 32768; - int r = Inlines.ADD16(30840, Inlines.MULT16_16_Q15(-15420, n)); - r = Inlines.SUB16(r, Inlines.MULT16_16_Q15(r, Inlines.ADD16(Inlines.MULT16_16_Q15(r, n), Inlines.ADD16(r, Short.MIN_VALUE)))); - r = Inlines.SUB16(r, Inlines.ADD16(1, Inlines.MULT16_16_Q15(r, Inlines.ADD16(Inlines.MULT16_16_Q15(r, n), Inlines.ADD16(r, Short.MIN_VALUE))))); - return Inlines.VSHR32(Inlines.EXTEND32(r), i - 16); - } - - static int celt_rsqrt_norm(int x) { - int n = x - 32768; - int r = Inlines.ADD16(23557, Inlines.MULT16_16_Q15(n, Inlines.ADD16(-13490, Inlines.MULT16_16_Q15(n, 6713)))); - int r2 = Inlines.MULT16_16_Q15(r, r); - int y = Inlines.SHL16(Inlines.SUB16(Inlines.ADD16(Inlines.MULT16_16_Q15(r2, n), r2), 16384), 1); - return Inlines.ADD16(r, Inlines.MULT16_16_Q15(r, Inlines.MULT16_16_Q15(y, Inlines.SUB16(Inlines.MULT16_16_Q15(y, 12288), 16384)))); - } - - static int frac_div32(int a, int b) { - int shift = Inlines.celt_ilog2(b) - 29; - a = Inlines.VSHR32(a, shift); - b = Inlines.VSHR32(b, shift); - int rcp = Inlines.ROUND16(Inlines.celt_rcp(Inlines.ROUND16(b, 16)), 3); - int result = Inlines.MULT16_32_Q15(rcp, a); - int rem = Inlines.PSHR32(a, 2) - Inlines.MULT32_32_Q31(result, b); - if ((result = Inlines.ADD32(result, Inlines.SHL32(Inlines.MULT16_32_Q15(rcp, rem), 2))) >= 0x20000000) { - return Integer.MAX_VALUE; - } - if (result <= -536870912) { - return -2147483647; - } - return Inlines.SHL32(result, 2); - } - - static int celt_log2(int x) { - if (x == 0) { - return -32767; - } - int i = Inlines.celt_ilog2(x); - int n = Inlines.VSHR32(x, i - 15) - 32768 - 16384; - int frac = Inlines.ADD16((int)log2_C0, Inlines.MULT16_16_Q15(n, Inlines.ADD16(15746, Inlines.MULT16_16_Q15(n, Inlines.ADD16(-5217, Inlines.MULT16_16_Q15(n, Inlines.ADD16(2545, Inlines.MULT16_16_Q15(n, -1401)))))))); - return Inlines.SHL16((short)(i - 13), 10) + Inlines.SHR16(frac, 4); - } - - static int celt_exp2_frac(int x) { - int frac = Inlines.SHL16(x, 4); - return Inlines.ADD16(16383, Inlines.MULT16_16_Q15(frac, Inlines.ADD16(22804, Inlines.MULT16_16_Q15(frac, Inlines.ADD16(14819, Inlines.MULT16_16_Q15(10204, frac)))))); - } - - static int celt_exp2(int x) { - int integer = Inlines.SHR16(x, 10); - if (integer > 14) { - return 0x7F000000; - } - if (integer < -15) { - return 0; - } - short frac = (short)Inlines.celt_exp2_frac((short)(x - Inlines.SHL16((short)integer, 10))); - return Inlines.VSHR32(Inlines.EXTEND32((int)frac), -integer - 2); - } - - static int celt_atan01(int x) { - return Inlines.MULT16_16_P15(x, Inlines.ADD32(Short.MAX_VALUE, Inlines.MULT16_16_P15(x, Inlines.ADD32(-21, Inlines.MULT16_16_P15(x, Inlines.ADD32(-11943, Inlines.MULT16_16_P15(4936, x))))))); - } - - static int celt_atan2p(int y, int x) { - if (y < x) { - int arg = Inlines.celt_div(Inlines.SHL32(Inlines.EXTEND32(y), 15), x); - if (arg >= Short.MAX_VALUE) { - arg = Short.MAX_VALUE; - } - return Inlines.SHR32(Inlines.celt_atan01(Inlines.EXTRACT16(arg)), 1); - } - int arg = Inlines.celt_div(Inlines.SHL32(Inlines.EXTEND32(x), 15), y); - if (arg >= Short.MAX_VALUE) { - arg = Short.MAX_VALUE; - } - return 25736 - Inlines.SHR16(Inlines.celt_atan01(Inlines.EXTRACT16(arg)), 1); - } - - static int celt_cos_norm(int x) { - if ((x &= 0x1FFFF) > Inlines.SHL32(Inlines.EXTEND32(1), 16)) { - x = Inlines.SUB32(Inlines.SHL32(Inlines.EXTEND32(1), 17), x); - } - if ((x & Short.MAX_VALUE) != 0) { - if (x < Inlines.SHL32(Inlines.EXTEND32(1), 15)) { - return Inlines._celt_cos_pi_2(Inlines.EXTRACT16(x)); - } - return Inlines.NEG32(Inlines._celt_cos_pi_2(Inlines.EXTRACT16(65536 - x))); - } - if ((x & 0xFFFF) != 0) { - return 0; - } - if ((x & 0x1FFFF) != 0) { - return -32767; - } - return Short.MAX_VALUE; - } - - static int _celt_cos_pi_2(int x) { - int x2 = Inlines.MULT16_16_P15(x, x); - return Inlines.ADD32(1, Inlines.MIN32(32766, Inlines.ADD32(Inlines.SUB16(Short.MAX_VALUE, x2), Inlines.MULT16_16_P15(x2, Inlines.ADD32(-7651, Inlines.MULT16_16_P15(x2, Inlines.ADD32(8277, Inlines.MULT16_16_P15(-626, x2)))))))); - } - - static short FLOAT2INT16(float x) { - if ((x *= 32768.0f) < -32768.0f) { - x = -32768.0f; - } - if (x > 32767.0f) { - x = 32767.0f; - } - return (short)x; - } - - static int silk_ROR32(int a32, int rot) { - int m = 0 - rot; - if (rot == 0) { - return a32; - } - if (rot < 0) { - return a32 << m | a32 >> 32 - m; - } - return a32 << 32 - rot | a32 >> rot; - } - - static int silk_MUL(int a32, int b32) { - int ret = a32 * b32; - return ret; - } - - static int silk_MLA(int a32, int b32, int c32) { - int ret = Inlines.silk_ADD32(a32, b32 * c32); - Inlines.OpusAssert((long)ret == (long)a32 + (long)b32 * (long)c32); - return ret; - } - - static int silk_SMULTT(int a32, int b32) { - return (a32 >> 16) * (b32 >> 16); - } - - static int silk_SMLATT(int a32, int b32, int c32) { - return Inlines.silk_ADD32(a32, (b32 >> 16) * (c32 >> 16)); - } - - static long silk_SMLALBB(long a64, short b16, short c16) { - return Inlines.silk_ADD64(a64, b16 * c16); - } - - static long silk_SMULL(int a32, int b32) { - return (long)a32 * (long)b32; - } - - static int silk_ADD32_ovflw(int a, int b) { - return (int)((long)a + (long)b); - } - - static int silk_ADD32_ovflw(long a, long b) { - return (int)(a + b); - } - - static int silk_SUB32_ovflw(int a, int b) { - return (int)((long)a - (long)b); - } - - static int silk_MLA_ovflw(int a32, int b32, int c32) { - return Inlines.silk_ADD32_ovflw((long)a32, (long)b32 * (long)c32); - } - - static int silk_SMLABB_ovflw(int a32, int b32, int c32) { - return Inlines.silk_ADD32_ovflw(a32, (short)b32 * (short)c32); - } - - static int silk_SMULBB(int a32, int b32) { - return (short)a32 * (short)b32; - } - - static int silk_SMULWB(int a32, int b32) { - return (int)((long)a32 * (long)((short)b32) >> 16); - } - - static int silk_SMLABB(int a32, int b32, int c32) { - return a32 + (short)b32 * (short)c32; - } - - static int silk_DIV32_16(int a32, int b32) { - return a32 / b32; - } - - static int silk_DIV32(int a32, int b32) { - return a32 / b32; - } - - static short silk_ADD16(short a, short b) { - short ret = (short)(a + b); - return ret; - } - - static int silk_ADD32(int a, int b) { - int ret = a + b; - return ret; - } - - static long silk_ADD64(long a, long b) { - long ret = a + b; - Inlines.OpusAssert(ret == Inlines.silk_ADD_SAT64(a, b)); - return ret; - } - - static short silk_SUB16(short a, short b) { - short ret = (short)(a - b); - Inlines.OpusAssert(ret == Inlines.silk_SUB_SAT16(a, b)); - return ret; - } - - static int silk_SUB32(int a, int b) { - int ret = a - b; - Inlines.OpusAssert(ret == Inlines.silk_SUB_SAT32(a, b)); - return ret; - } - - static long silk_SUB64(long a, long b) { - long ret = a - b; - Inlines.OpusAssert(ret == Inlines.silk_SUB_SAT64(a, b)); - return ret; - } - - static int silk_SAT8(int a) { - return a > 127 ? 127 : (a < -128 ? -128 : a); - } - - static int silk_SAT16(int a) { - return a > Short.MAX_VALUE ? Short.MAX_VALUE : (a < Short.MIN_VALUE ? Short.MIN_VALUE : a); - } - - static int silk_SAT32(long a) { - return a > Integer.MAX_VALUE ? Integer.MAX_VALUE : (a < Integer.MIN_VALUE ? Integer.MIN_VALUE : (int)a); - } - - static short silk_ADD_SAT16(short a16, short b16) { - short res = (short)Inlines.silk_SAT16(Inlines.silk_ADD32(a16, b16)); - Inlines.OpusAssert(res == Inlines.silk_SAT16(a16 + b16)); - return res; - } - - static int silk_ADD_SAT32(int a32, int b32) { - int res = ((long)a32 + (long)b32 & Integer.MIN_VALUE) == 0L ? ((a32 & b32 & Integer.MIN_VALUE) != 0 ? Integer.MIN_VALUE : a32 + b32) : (((a32 | b32) & Integer.MIN_VALUE) == 0 ? Integer.MAX_VALUE : a32 + b32); - Inlines.OpusAssert(res == Inlines.silk_SAT32((long)a32 + (long)b32)); - return res; - } - - static long silk_ADD_SAT64(long a64, long b64) { - long res = (a64 + b64 & Long.MIN_VALUE) == 0L ? ((a64 & b64 & Long.MIN_VALUE) != 0L ? Long.MIN_VALUE : a64 + b64) : (((a64 | b64) & Long.MIN_VALUE) == 0L ? Long.MAX_VALUE : a64 + b64); - return res; - } - - static short silk_SUB_SAT16(short a16, short b16) { - short res = (short)Inlines.silk_SAT16(Inlines.silk_SUB32(a16, b16)); - Inlines.OpusAssert(res == Inlines.silk_SAT16(a16 - b16)); - return res; - } - - static int silk_SUB_SAT32(int a32, int b32) { - int res = ((long)a32 - (long)b32 & Integer.MIN_VALUE) == 0L ? ((a32 & (b32 ^ Integer.MIN_VALUE) & Integer.MIN_VALUE) != 0 ? Integer.MIN_VALUE : a32 - b32) : (((a32 ^ Integer.MIN_VALUE) & b32 & Integer.MIN_VALUE) != 0 ? Integer.MAX_VALUE : a32 - b32); - Inlines.OpusAssert(res == Inlines.silk_SAT32((long)a32 - (long)b32)); - return res; - } - - static long silk_SUB_SAT64(long a64, long b64) { - long res = (a64 - b64 & Long.MIN_VALUE) == 0L ? ((a64 & (b64 ^ Long.MIN_VALUE) & Long.MIN_VALUE) != 0L ? Long.MIN_VALUE : a64 - b64) : (((a64 ^ Long.MIN_VALUE) & b64 & Long.MIN_VALUE) != 0L ? Long.MAX_VALUE : a64 - b64); - return res; - } - - static byte silk_ADD_POS_SAT8(byte a, byte b) { - return (byte)((a + b & 0x80) != 0 ? 127 : a + b); - } - - static short silk_ADD_POS_SAT16(short a, short b) { - return (short)((a + b & 0x8000) != 0 ? Short.MAX_VALUE : a + b); - } - - static int silk_ADD_POS_SAT32(int a, int b) { - return (a + b & Integer.MIN_VALUE) != 0 ? Integer.MAX_VALUE : a + b; - } - - static long silk_ADD_POS_SAT64(long a, long b) { - return (a + b & Long.MIN_VALUE) != 0L ? Long.MAX_VALUE : a + b; - } - - static byte silk_LSHIFT8(byte a, int shift) { - byte ret = (byte)(a << shift); - return ret; - } - - static short silk_LSHIFT16(short a, int shift) { - short ret = (short)(a << shift); - return ret; - } - - static int silk_LSHIFT32(int a, int shift) { - int ret = a << shift; - return ret; - } - - static long silk_LSHIFT64(long a, int shift) { - long ret = a << shift; - return ret; - } - - static int silk_LSHIFT(int a, int shift) { - int ret = a << shift; - return ret; - } - - static int silk_LSHIFT_ovflw(int a, int shift) { - return a << shift; - } - - static int silk_LSHIFT_SAT32(int a, int shift) { - return Inlines.silk_LSHIFT32(Inlines.silk_LIMIT(a, Inlines.silk_RSHIFT32(Integer.MIN_VALUE, shift), Inlines.silk_RSHIFT32(Integer.MAX_VALUE, shift)), shift); - } - - static byte silk_RSHIFT8(byte a, int shift) { - return (byte)(a >> shift); - } - - static short silk_RSHIFT16(short a, int shift) { - return (short)(a >> shift); - } - - static int silk_RSHIFT32(int a, int shift) { - return a >> shift; - } - - static int silk_RSHIFT(int a, int shift) { - return a >> shift; - } - - static long silk_RSHIFT64(long a, int shift) { - return a >> shift; - } - - static long silk_RSHIFT_uint(long a, int shift) { - return Inlines.CapToUInt32(a) >> shift; - } - - static int silk_ADD_LSHIFT(int a, int b, int shift) { - int ret = a + (b << shift); - return ret; - } - - static int silk_ADD_LSHIFT32(int a, int b, int shift) { - int ret = a + (b << shift); - return ret; - } - - static int silk_ADD_RSHIFT(int a, int b, int shift) { - int ret = a + (b >> shift); - return ret; - } - - static int silk_ADD_RSHIFT32(int a, int b, int shift) { - int ret = a + (b >> shift); - return ret; - } - - static long silk_ADD_RSHIFT_uint(long a, long b, int shift) { - long ret = Inlines.CapToUInt32(a + (Inlines.CapToUInt32(b) >> shift)); - return ret; - } - - static int silk_SUB_LSHIFT32(int a, int b, int shift) { - int ret = a - (b << shift); - return ret; - } - - static int silk_SUB_RSHIFT32(int a, int b, int shift) { - int ret = a - (b >> shift); - return ret; - } - - static int silk_RSHIFT_ROUND(int a, int shift) { - int ret = shift == 1 ? (a >> 1) + (a & 1) : (a >> shift - 1) + 1 >> 1; - return ret; - } - - static long silk_RSHIFT_ROUND64(long a, int shift) { - long ret = shift == 1 ? (a >> 1) + (a & 1L) : (a >> shift - 1) + 1L >> 1; - return ret; - } - - static int silk_min(int a, int b) { - return a < b ? a : b; - } - - static int silk_max(int a, int b) { - return a > b ? a : b; - } - - static float silk_min(float a, float b) { - return a < b ? a : b; - } - - static float silk_max(float a, float b) { - return a > b ? a : b; - } - - static int SILK_CONST(float number, int scale) { - return (int)((double)(number * (float)(1L << scale)) + 0.5); - } - - static int silk_min_int(int a, int b) { - return a < b ? a : b; - } - - static short silk_min_16(short a, short b) { - return a < b ? a : b; - } - - static int silk_min_32(int a, int b) { - return a < b ? a : b; - } - - static long silk_min_64(long a, long b) { - return a < b ? a : b; - } - - static int silk_max_int(int a, int b) { - return a > b ? a : b; - } - - static short silk_max_16(short a, short b) { - return a > b ? a : b; - } - - static int silk_max_32(int a, int b) { - return a > b ? a : b; - } - - static long silk_max_64(long a, long b) { - return a > b ? a : b; - } - - static float silk_LIMIT(float a, float limit1, float limit2) { - return limit1 > limit2 ? (a > limit1 ? limit1 : (a < limit2 ? limit2 : a)) : (a > limit2 ? limit2 : (a < limit1 ? limit1 : a)); - } - - static int silk_LIMIT(int a, int limit1, int limit2) { - return Inlines.silk_LIMIT_32(a, limit1, limit2); - } - - static int silk_LIMIT_int(int a, int limit1, int limit2) { - return Inlines.silk_LIMIT_32(a, limit1, limit2); - } - - static short silk_LIMIT_16(short a, short limit1, short limit2) { - return limit1 > limit2 ? (a > limit1 ? limit1 : (a < limit2 ? limit2 : a)) : (a > limit2 ? limit2 : (a < limit1 ? limit1 : a)); - } - - static int silk_LIMIT_32(int a, int limit1, int limit2) { - return limit1 > limit2 ? (a > limit1 ? limit1 : (a < limit2 ? limit2 : a)) : (a > limit2 ? limit2 : (a < limit1 ? limit1 : a)); - } - - static int silk_abs(int a) { - return a > 0 ? a : -a; - } - - static int silk_abs_int16(int a) { - return (a ^ a >> 15) - (a >> 15); - } - - static int silk_abs_int32(int a) { - return (a ^ a >> 31) - (a >> 31); - } - - static long silk_abs_int64(long a) { - return a > 0L ? a : -a; - } - - static long silk_sign(int a) { - return a > 0 ? 1L : (long)(a < 0 ? -1 : 0); - } - - static int silk_RAND(int seed) { - return Inlines.silk_MLA_ovflw(907633515, seed, 196314165); - } - - static int silk_SMMUL(int a32, int b32) { - return (int)Inlines.silk_RSHIFT64(Inlines.silk_SMULL(a32, b32), 32); - } - - static int silk_SMLAWT(int a32, int b32, int c32) { - int ret = a32 + (b32 >> 16) * (c32 >> 16) + ((b32 & 0xFFFF) * (c32 >> 16) >> 16); - return ret; - } - - static int silk_DIV32_varQ(int a32, int b32, int Qres) { - Inlines.OpusAssert(b32 != 0); - Inlines.OpusAssert(Qres >= 0); - int a_headrm = Inlines.silk_CLZ32(Inlines.silk_abs(a32)) - 1; - int a32_nrm = Inlines.silk_LSHIFT(a32, a_headrm); - int b_headrm = Inlines.silk_CLZ32(Inlines.silk_abs(b32)) - 1; - int b32_nrm = Inlines.silk_LSHIFT(b32, b_headrm); - int b32_inv = Inlines.silk_DIV32_16(0x1FFFFFFF, Inlines.silk_RSHIFT(b32_nrm, 16)); - int result = Inlines.silk_SMULWB(a32_nrm, b32_inv); - a32_nrm = Inlines.silk_SUB32_ovflw(a32_nrm, Inlines.silk_LSHIFT_ovflw(Inlines.silk_SMMUL(b32_nrm, result), 3)); - result = Inlines.silk_SMLAWB(result, a32_nrm, b32_inv); - int lshift = 29 + a_headrm - b_headrm - Qres; - if (lshift < 0) { - return Inlines.silk_LSHIFT_SAT32(result, -lshift); - } - if (lshift < 32) { - return Inlines.silk_RSHIFT(result, lshift); - } - return 0; - } - - static int silk_INVERSE32_varQ(int b32, int Qres) { - Inlines.OpusAssert(b32 != 0); - Inlines.OpusAssert(Qres > 0); - int b_headrm = Inlines.silk_CLZ32(Inlines.silk_abs(b32)) - 1; - int b32_nrm = Inlines.silk_LSHIFT(b32, b_headrm); - int b32_inv = Inlines.silk_DIV32_16(0x1FFFFFFF, (short)Inlines.silk_RSHIFT(b32_nrm, 16)); - int result = Inlines.silk_LSHIFT(b32_inv, 16); - int err_Q32 = Inlines.silk_LSHIFT(0x20000000 - Inlines.silk_SMULWB(b32_nrm, b32_inv), 3); - result = Inlines.silk_SMLAWW(result, err_Q32, b32_inv); - int lshift = 61 - b_headrm - Qres; - if (lshift <= 0) { - return Inlines.silk_LSHIFT_SAT32(result, -lshift); - } - if (lshift < 32) { - return Inlines.silk_RSHIFT(result, lshift); - } - return 0; - } - - static int silk_SMLAWB(int a32, int b32, int c32) { - int ret = a32 + Inlines.silk_SMULWB(b32, c32); - return ret; - } - - static int silk_SMULWT(int a32, int b32) { - return (a32 >> 16) * (b32 >> 16) + ((a32 & 0xFFFF) * (b32 >> 16) >> 16); - } - - static int silk_SMULBT(int a32, int b32) { - return (short)a32 * (b32 >> 16); - } - - static int silk_SMLABT(int a32, int b32, int c32) { - return a32 + (short)b32 * (c32 >> 16); - } - - static long silk_SMLAL(long a64, int b32, int c32) { - return Inlines.silk_ADD64(a64, (long)b32 * (long)c32); - } - - static int MatrixGetPointer(int row, int column, int N) { - return row * N + column; - } - - static int MatrixGet(int[] Matrix_base_adr, int row, int column, int N) { - return Matrix_base_adr[row * N + column]; - } - - static short MatrixGet(short[] Matrix_base_adr, int row, int column, int N) { - return Matrix_base_adr[row * N + column]; - } - - static PitchAnalysisCore.silk_pe_stage3_vals MatrixGet(PitchAnalysisCore.silk_pe_stage3_vals[] Matrix_base_adr, int row, int column, int N) { - return Matrix_base_adr[row * N + column]; - } - - static int MatrixGet(int[] Matrix_base_adr, int matrix_ptr, int row, int column, int N) { - return Matrix_base_adr[matrix_ptr + row * N + column]; - } - - static short MatrixGet(short[] Matrix_base_adr, int matrix_ptr, int row, int column, int N) { - return Matrix_base_adr[matrix_ptr + row * N + column]; - } - - static void MatrixSet(int[] Matrix_base_adr, int matrix_ptr, int row, int column, int N, int value) { - Matrix_base_adr[matrix_ptr + row * N + column] = value; - } - - static void MatrixSet(short[] Matrix_base_adr, int matrix_ptr, int row, int column, int N, short value) { - Matrix_base_adr[matrix_ptr + row * N + column] = value; - } - - static void MatrixSet(int[] Matrix_base_adr, int row, int column, int N, int value) { - Matrix_base_adr[row * N + column] = value; - } - - static void MatrixSet(short[] Matrix_base_adr, int row, int column, int N, short value) { - Matrix_base_adr[row * N + column] = value; - } - - static int silk_SMULWW(int a32, int b32) { - return Inlines.silk_MLA(Inlines.silk_SMULWB(a32, b32), a32, Inlines.silk_RSHIFT_ROUND(b32, 16)); - } - - static int silk_SMLAWW(int a32, int b32, int c32) { - return Inlines.silk_MLA(Inlines.silk_SMLAWB(a32, b32, c32), b32, Inlines.silk_RSHIFT_ROUND(c32, 16)); - } - - static int silk_CLZ64(long input) { - int in_upper = (int)Inlines.silk_RSHIFT64(input, 32); - if (in_upper == 0) { - return 32 + Inlines.silk_CLZ32((int)input); - } - return Inlines.silk_CLZ32(in_upper); - } - - static int silk_CLZ32(int in32) { - return in32 == 0 ? 32 : 32 - Inlines.EC_ILOG(in32); - } - - static void silk_CLZ_FRAC(int input, BoxedValueInt lz, BoxedValueInt frac_Q7) { - int lzeros; - lz.Val = lzeros = Inlines.silk_CLZ32(input); - frac_Q7.Val = Inlines.silk_ROR32(input, 24 - lzeros) & 0x7F; - } - - static int silk_SQRT_APPROX(int x) { - if (x <= 0) { - return 0; - } - BoxedValueInt boxed_lz = new BoxedValueInt(0); - BoxedValueInt boxed_frac_Q7 = new BoxedValueInt(0); - Inlines.silk_CLZ_FRAC(x, boxed_lz, boxed_frac_Q7); - int lz = boxed_lz.Val; - int frac_Q7 = boxed_frac_Q7.Val; - int y = (lz & 1) != 0 ? 32768 : 46214; - y >>= Inlines.silk_RSHIFT(lz, 1); - y = Inlines.silk_SMLAWB(y, y, Inlines.silk_SMULBB(213, frac_Q7)); - return y; - } - - static int MUL32_FRAC_Q(int a32, int b32, int Q) { - return (int)Inlines.silk_RSHIFT_ROUND64(Inlines.silk_SMULL(a32, b32), Q); - } - - static int silk_lin2log(int inLin) { - BoxedValueInt lz = new BoxedValueInt(0); - BoxedValueInt frac_Q7 = new BoxedValueInt(0); - Inlines.silk_CLZ_FRAC(inLin, lz, frac_Q7); - return Inlines.silk_LSHIFT(31 - lz.Val, 7) + Inlines.silk_SMLAWB(frac_Q7.Val, Inlines.silk_MUL(frac_Q7.Val, 128 - frac_Q7.Val), 179); - } - - static int silk_log2lin(int inLog_Q7) { - if (inLog_Q7 < 0) { - return 0; - } - if (inLog_Q7 >= 3967) { - return Integer.MAX_VALUE; - } - int output = Inlines.silk_LSHIFT(1, Inlines.silk_RSHIFT(inLog_Q7, 7)); - int frac_Q7 = inLog_Q7 & 0x7F; - output = inLog_Q7 < 2048 ? Inlines.silk_ADD_RSHIFT32(output, Inlines.silk_MUL(output, Inlines.silk_SMLAWB(frac_Q7, Inlines.silk_SMULBB(frac_Q7, 128 - frac_Q7), -174)), 7) : Inlines.silk_MLA(output, Inlines.silk_RSHIFT(output, 7), Inlines.silk_SMLAWB(frac_Q7, Inlines.silk_SMULBB(frac_Q7, 128 - frac_Q7), -174)); - return output; - } - - static void silk_interpolate(short[] xi, short[] x0, short[] x1, int ifact_Q2, int d) { - Inlines.OpusAssert(ifact_Q2 >= 0); - Inlines.OpusAssert(ifact_Q2 <= 4); - for (int i = 0; i < d; ++i) { - xi[i] = (short)Inlines.silk_ADD_RSHIFT(x0[i], Inlines.silk_SMULBB(x1[i] - x0[i], ifact_Q2), 2); - } - } - - static int silk_inner_prod_aligned_scale(short[] inVec1, short[] inVec2, int scale, int len) { - int sum = 0; - for (int i = 0; i < len; ++i) { - sum = Inlines.silk_ADD_RSHIFT32(sum, Inlines.silk_SMULBB(inVec1[i], inVec2[i]), scale); - } - return sum; - } - - static void silk_scale_copy_vector16(short[] data_out, int data_out_ptr, short[] data_in, int data_in_ptr, int gain_Q16, int dataSize) { - for (int i = 0; i < dataSize; ++i) { - data_out[data_out_ptr + i] = (short)Inlines.silk_SMULWB(gain_Q16, data_in[data_in_ptr + i]); - } - } - - static void silk_scale_vector32_Q26_lshift_18(int[] data1, int data1_ptr, int gain_Q26, int dataSize) { - for (int i = data1_ptr; i < data1_ptr + dataSize; ++i) { - data1[i] = (int)Inlines.silk_RSHIFT64(Inlines.silk_SMULL(data1[i], gain_Q26), 8); - } - } - - static int silk_inner_prod(short[] inVec1, int inVec1_ptr, short[] inVec2, int inVec2_ptr, int len) { - int xy = 0; - for (int i = 0; i < len; ++i) { - xy = Inlines.MAC16_16(xy, inVec1[inVec1_ptr + i], inVec2[inVec2_ptr + i]); - } - return xy; - } - - static int silk_inner_prod_self(short[] inVec, int inVec_ptr, int len) { - int xy = 0; - for (int i = inVec_ptr; i < inVec_ptr + len; ++i) { - xy = Inlines.MAC16_16(xy, inVec[i], inVec[i]); - } - return xy; - } - - static long silk_inner_prod16_aligned_64(short[] inVec1, int inVec1_ptr, short[] inVec2, int inVec2_ptr, int len) { - long sum = 0L; - for (int i = 0; i < len; ++i) { - sum = Inlines.silk_SMLALBB(sum, inVec1[inVec1_ptr + i], inVec2[inVec2_ptr + i]); - } - return sum; - } - - static long EC_MINI(long a, long b) { - return a + (b - a & (long)(b < a ? -1 : 0)); - } - - static int EC_ILOG(long x) { - if (x == 0L) { - return 1; - } - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - long y = x - (x >> 1 & 0x55555555L); - y = (y >> 2 & 0x33333333L) + (y & 0x33333333L); - y = (y >> 4) + y & 0xF0F0F0FL; - y += y >> 8; - y += y >> 16; - return (int)(y &= 0x3FL); - } - - static int abs(int a) { - if (a < 0) { - return 0 - a; - } - return a; - } - - static int SignedByteToUnsignedInt(byte b) { - return b & 0xFF; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/K2A.java b/source/decompiled/de/maxhenkel/voicechat/concentus/K2A.java deleted file mode 100644 index 6908a7c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/K2A.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; - -class K2A { - K2A() { - } - - static void silk_k2a(int[] A_Q24, short[] rc_Q15, int order) { - int[] Atmp = new int[16]; - for (int k = 0; k < order; ++k) { - int n; - for (n = 0; n < k; ++n) { - Atmp[n] = A_Q24[n]; - } - for (n = 0; n < k; ++n) { - A_Q24[n] = Inlines.silk_SMLAWB(A_Q24[n], Inlines.silk_LSHIFT(Atmp[k - n - 1], 1), rc_Q15[k]); - } - A_Q24[k] = 0 - Inlines.silk_LSHIFT(rc_Q15[k], 9); - } - } - - static void silk_k2a_Q16(int[] A_Q24, int[] rc_Q16, int order) { - int[] Atmp = new int[16]; - for (int k = 0; k < order; ++k) { - int n; - for (n = 0; n < k; ++n) { - Atmp[n] = A_Q24[n]; - } - for (n = 0; n < k; ++n) { - A_Q24[n] = Inlines.silk_SMLAWW(A_Q24[n], Atmp[k - n - 1], rc_Q16[k]); - } - A_Q24[k] = 0 - Inlines.silk_LSHIFT(rc_Q16[k], 8); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Kernels.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Kernels.java deleted file mode 100644 index 8e69f8a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Kernels.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Inlines; - -class Kernels { - Kernels() { - } - - static void celt_fir(short[] x, int x_ptr, short[] num, short[] y, int y_ptr, int N, int ord, short[] mem) { - int i; - short[] rnum = new short[ord]; - short[] local_x = new short[N + ord]; - for (i = 0; i < ord; ++i) { - rnum[i] = num[ord - i - 1]; - } - for (i = 0; i < ord; ++i) { - local_x[i] = mem[ord - i - 1]; - } - for (i = 0; i < N; ++i) { - local_x[i + ord] = x[x_ptr + i]; - } - for (i = 0; i < ord; ++i) { - mem[i] = x[x_ptr + N - i - 1]; - } - BoxedValueInt sum0 = new BoxedValueInt(0); - BoxedValueInt sum1 = new BoxedValueInt(0); - BoxedValueInt sum2 = new BoxedValueInt(0); - BoxedValueInt sum3 = new BoxedValueInt(0); - for (i = 0; i < N - 3; i += 4) { - sum0.Val = 0; - sum1.Val = 0; - sum2.Val = 0; - sum3.Val = 0; - Kernels.xcorr_kernel(rnum, 0, local_x, i, sum0, sum1, sum2, sum3, ord); - y[y_ptr + i] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum0.Val, 12))); - y[y_ptr + i + 1] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 1]), Inlines.PSHR32(sum1.Val, 12))); - y[y_ptr + i + 2] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 2]), Inlines.PSHR32(sum2.Val, 12))); - y[y_ptr + i + 3] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 3]), Inlines.PSHR32(sum3.Val, 12))); - } - while (i < N) { - int sum = 0; - for (int j = 0; j < ord; ++j) { - sum = Inlines.MAC16_16(sum, rnum[j], local_x[i + j]); - } - y[y_ptr + i] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum, 12))); - ++i; - } - } - - static void celt_fir(int[] x, int x_ptr, int[] num, int num_ptr, int[] y, int y_ptr, int N, int ord, int[] mem) { - int i; - int[] rnum = new int[ord]; - int[] local_x = new int[N + ord]; - for (i = 0; i < ord; ++i) { - rnum[i] = num[num_ptr + ord - i - 1]; - } - for (i = 0; i < ord; ++i) { - local_x[i] = mem[ord - i - 1]; - } - for (i = 0; i < N; ++i) { - local_x[i + ord] = x[x_ptr + i]; - } - for (i = 0; i < ord; ++i) { - mem[i] = x[x_ptr + N - i - 1]; - } - BoxedValueInt sum0 = new BoxedValueInt(0); - BoxedValueInt sum1 = new BoxedValueInt(0); - BoxedValueInt sum2 = new BoxedValueInt(0); - BoxedValueInt sum3 = new BoxedValueInt(0); - for (i = 0; i < N - 3; i += 4) { - sum0.Val = 0; - sum1.Val = 0; - sum2.Val = 0; - sum3.Val = 0; - Kernels.xcorr_kernel(rnum, local_x, i, sum0, sum1, sum2, sum3, ord); - y[y_ptr + i] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum0.Val, 12))); - y[y_ptr + i + 1] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 1]), Inlines.PSHR32(sum1.Val, 12))); - y[y_ptr + i + 2] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 2]), Inlines.PSHR32(sum2.Val, 12))); - y[y_ptr + i + 3] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 3]), Inlines.PSHR32(sum3.Val, 12))); - } - while (i < N) { - int sum = 0; - for (int j = 0; j < ord; ++j) { - sum = Inlines.MAC16_16(sum, rnum[j], local_x[i + j]); - } - y[y_ptr + i] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum, 12))); - ++i; - } - } - - static void xcorr_kernel(short[] x, int x_ptr, short[] y, int y_ptr, BoxedValueInt _sum0, BoxedValueInt _sum1, BoxedValueInt _sum2, BoxedValueInt _sum3, int len) { - short tmp; - int j; - int sum0 = _sum0.Val; - int sum1 = _sum1.Val; - int sum2 = _sum2.Val; - int sum3 = _sum3.Val; - Inlines.OpusAssert(len >= 3); - short y_3 = 0; - short y_0 = y[y_ptr++]; - short y_1 = y[y_ptr++]; - short y_2 = y[y_ptr++]; - for (j = 0; j < len - 3; j += 4) { - tmp = x[x_ptr++]; - y_3 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_0); - sum1 = Inlines.MAC16_16(sum1, tmp, y_1); - sum2 = Inlines.MAC16_16(sum2, tmp, y_2); - sum3 = Inlines.MAC16_16(sum3, tmp, y_3); - tmp = x[x_ptr++]; - y_0 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_1); - sum1 = Inlines.MAC16_16(sum1, tmp, y_2); - sum2 = Inlines.MAC16_16(sum2, tmp, y_3); - sum3 = Inlines.MAC16_16(sum3, tmp, y_0); - tmp = x[x_ptr++]; - y_1 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_2); - sum1 = Inlines.MAC16_16(sum1, tmp, y_3); - sum2 = Inlines.MAC16_16(sum2, tmp, y_0); - sum3 = Inlines.MAC16_16(sum3, tmp, y_1); - tmp = x[x_ptr++]; - y_2 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_3); - sum1 = Inlines.MAC16_16(sum1, tmp, y_0); - sum2 = Inlines.MAC16_16(sum2, tmp, y_1); - sum3 = Inlines.MAC16_16(sum3, tmp, y_2); - } - if (j++ < len) { - tmp = x[x_ptr++]; - y_3 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_0); - sum1 = Inlines.MAC16_16(sum1, tmp, y_1); - sum2 = Inlines.MAC16_16(sum2, tmp, y_2); - sum3 = Inlines.MAC16_16(sum3, tmp, y_3); - } - if (j++ < len) { - tmp = x[x_ptr++]; - y_0 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_1); - sum1 = Inlines.MAC16_16(sum1, tmp, y_2); - sum2 = Inlines.MAC16_16(sum2, tmp, y_3); - sum3 = Inlines.MAC16_16(sum3, tmp, y_0); - } - if (j < len) { - tmp = x[x_ptr++]; - y_1 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_2); - sum1 = Inlines.MAC16_16(sum1, tmp, y_3); - sum2 = Inlines.MAC16_16(sum2, tmp, y_0); - sum3 = Inlines.MAC16_16(sum3, tmp, y_1); - } - _sum0.Val = sum0; - _sum1.Val = sum1; - _sum2.Val = sum2; - _sum3.Val = sum3; - } - - static void xcorr_kernel(int[] x, int[] y, int y_ptr, BoxedValueInt _sum0, BoxedValueInt _sum1, BoxedValueInt _sum2, BoxedValueInt _sum3, int len) { - int tmp; - int j; - int sum0 = _sum0.Val; - int sum1 = _sum1.Val; - int sum2 = _sum2.Val; - int sum3 = _sum3.Val; - int x_ptr = 0; - Inlines.OpusAssert(len >= 3); - int y_3 = 0; - int y_0 = y[y_ptr++]; - int y_1 = y[y_ptr++]; - int y_2 = y[y_ptr++]; - for (j = 0; j < len - 3; j += 4) { - tmp = x[x_ptr++]; - y_3 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_0); - sum1 = Inlines.MAC16_16(sum1, tmp, y_1); - sum2 = Inlines.MAC16_16(sum2, tmp, y_2); - sum3 = Inlines.MAC16_16(sum3, tmp, y_3); - tmp = x[x_ptr++]; - y_0 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_1); - sum1 = Inlines.MAC16_16(sum1, tmp, y_2); - sum2 = Inlines.MAC16_16(sum2, tmp, y_3); - sum3 = Inlines.MAC16_16(sum3, tmp, y_0); - tmp = x[x_ptr++]; - y_1 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_2); - sum1 = Inlines.MAC16_16(sum1, tmp, y_3); - sum2 = Inlines.MAC16_16(sum2, tmp, y_0); - sum3 = Inlines.MAC16_16(sum3, tmp, y_1); - tmp = x[x_ptr++]; - y_2 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_3); - sum1 = Inlines.MAC16_16(sum1, tmp, y_0); - sum2 = Inlines.MAC16_16(sum2, tmp, y_1); - sum3 = Inlines.MAC16_16(sum3, tmp, y_2); - } - if (j++ < len) { - tmp = x[x_ptr++]; - y_3 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_0); - sum1 = Inlines.MAC16_16(sum1, tmp, y_1); - sum2 = Inlines.MAC16_16(sum2, tmp, y_2); - sum3 = Inlines.MAC16_16(sum3, tmp, y_3); - } - if (j++ < len) { - tmp = x[x_ptr++]; - y_0 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_1); - sum1 = Inlines.MAC16_16(sum1, tmp, y_2); - sum2 = Inlines.MAC16_16(sum2, tmp, y_3); - sum3 = Inlines.MAC16_16(sum3, tmp, y_0); - } - if (j < len) { - tmp = x[x_ptr++]; - y_1 = y[y_ptr++]; - sum0 = Inlines.MAC16_16(sum0, tmp, y_2); - sum1 = Inlines.MAC16_16(sum1, tmp, y_3); - sum2 = Inlines.MAC16_16(sum2, tmp, y_0); - sum3 = Inlines.MAC16_16(sum3, tmp, y_1); - } - _sum0.Val = sum0; - _sum1.Val = sum1; - _sum2.Val = sum2; - _sum3.Val = sum3; - } - - static int celt_inner_prod(short[] x, int x_ptr, short[] y, int y_ptr, int N) { - int xy = 0; - for (int i = 0; i < N; ++i) { - xy = Inlines.MAC16_16(xy, x[x_ptr + i], y[y_ptr + i]); - } - return xy; - } - - static int celt_inner_prod(short[] x, short[] y, int y_ptr, int N) { - int xy = 0; - for (int i = 0; i < N; ++i) { - xy = Inlines.MAC16_16(xy, x[i], y[y_ptr + i]); - } - return xy; - } - - static int celt_inner_prod(int[] x, int x_ptr, int[] y, int y_ptr, int N) { - int xy = 0; - for (int i = 0; i < N; ++i) { - xy = Inlines.MAC16_16(xy, x[x_ptr + i], y[y_ptr + i]); - } - return xy; - } - - static void dual_inner_prod(int[] x, int x_ptr, int[] y01, int y01_ptr, int[] y02, int y02_ptr, int N, BoxedValueInt xy1, BoxedValueInt xy2) { - int xy01 = 0; - int xy02 = 0; - for (int i = 0; i < N; ++i) { - xy01 = Inlines.MAC16_16(xy01, x[x_ptr + i], y01[y01_ptr + i]); - xy02 = Inlines.MAC16_16(xy02, x[x_ptr + i], y02[y02_ptr + i]); - } - xy1.Val = xy01; - xy2.Val = xy02; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/KissFFT.java b/source/decompiled/de/maxhenkel/voicechat/concentus/KissFFT.java deleted file mode 100644 index 43f4ea5..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/KissFFT.java +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.FFTState; -import de.maxhenkel.voicechat.concentus.Inlines; - -class KissFFT { - static final int MAXFACTORS = 8; - - KissFFT() { - } - - static int S_MUL(int a, int b) { - return Inlines.MULT16_32_Q15(b, a); - } - - static int S_MUL(int a, short b) { - return Inlines.MULT16_32_Q15(b, a); - } - - static int HALF_OF(int x) { - return x >> 1; - } - - static void kf_bfly2(int[] Fout, int fout_ptr, int m, int N) { - short tw = 23170; - Inlines.OpusAssert(m == 4); - for (int i = 0; i < N; ++i) { - int Fout2 = fout_ptr + 8; - int t_r = Fout[Fout2 + 0]; - int t_i = Fout[Fout2 + 1]; - Fout[Fout2 + 0] = Fout[fout_ptr + 0] - t_r; - Fout[Fout2 + 1] = Fout[fout_ptr + 1] - t_i; - int n = fout_ptr + 0; - Fout[n] = Fout[n] + t_r; - int n2 = fout_ptr + 1; - Fout[n2] = Fout[n2] + t_i; - t_r = KissFFT.S_MUL(Fout[Fout2 + 2] + Fout[Fout2 + 3], tw); - t_i = KissFFT.S_MUL(Fout[Fout2 + 3] - Fout[Fout2 + 2], tw); - Fout[Fout2 + 2] = Fout[fout_ptr + 2] - t_r; - Fout[Fout2 + 3] = Fout[fout_ptr + 3] - t_i; - int n3 = fout_ptr + 2; - Fout[n3] = Fout[n3] + t_r; - int n4 = fout_ptr + 3; - Fout[n4] = Fout[n4] + t_i; - t_r = Fout[Fout2 + 5]; - t_i = 0 - Fout[Fout2 + 4]; - Fout[Fout2 + 4] = Fout[fout_ptr + 4] - t_r; - Fout[Fout2 + 5] = Fout[fout_ptr + 5] - t_i; - int n5 = fout_ptr + 4; - Fout[n5] = Fout[n5] + t_r; - int n6 = fout_ptr + 5; - Fout[n6] = Fout[n6] + t_i; - t_r = KissFFT.S_MUL(Fout[Fout2 + 7] - Fout[Fout2 + 6], tw); - t_i = KissFFT.S_MUL(0 - Fout[Fout2 + 7] - Fout[Fout2 + 6], tw); - Fout[Fout2 + 6] = Fout[fout_ptr + 6] - t_r; - Fout[Fout2 + 7] = Fout[fout_ptr + 7] - t_i; - int n7 = fout_ptr + 6; - Fout[n7] = Fout[n7] + t_r; - int n8 = fout_ptr + 7; - Fout[n8] = Fout[n8] + t_i; - fout_ptr += 16; - } - } - - static void kf_bfly4(int[] Fout, int fout_ptr, int fstride, FFTState st, int m, int N, int mm) { - if (m == 1) { - for (int i = 0; i < N; ++i) { - int scratch0 = Fout[fout_ptr + 0] - Fout[fout_ptr + 4]; - int scratch1 = Fout[fout_ptr + 1] - Fout[fout_ptr + 5]; - int n = fout_ptr + 0; - Fout[n] = Fout[n] + Fout[fout_ptr + 4]; - int n2 = fout_ptr + 1; - Fout[n2] = Fout[n2] + Fout[fout_ptr + 5]; - int scratch2 = Fout[fout_ptr + 2] + Fout[fout_ptr + 6]; - int scratch3 = Fout[fout_ptr + 3] + Fout[fout_ptr + 7]; - Fout[fout_ptr + 4] = Fout[fout_ptr + 0] - scratch2; - Fout[fout_ptr + 5] = Fout[fout_ptr + 1] - scratch3; - int n3 = fout_ptr + 0; - Fout[n3] = Fout[n3] + scratch2; - int n4 = fout_ptr + 1; - Fout[n4] = Fout[n4] + scratch3; - scratch2 = Fout[fout_ptr + 2] - Fout[fout_ptr + 6]; - scratch3 = Fout[fout_ptr + 3] - Fout[fout_ptr + 7]; - Fout[fout_ptr + 2] = scratch0 + scratch3; - Fout[fout_ptr + 3] = scratch1 - scratch2; - Fout[fout_ptr + 6] = scratch0 - scratch3; - Fout[fout_ptr + 7] = scratch1 + scratch2; - fout_ptr += 8; - } - } else { - int Fout_beg = fout_ptr; - for (int i = 0; i < N; ++i) { - fout_ptr = Fout_beg + 2 * i * mm; - int m1 = fout_ptr + 2 * m; - int m2 = fout_ptr + 4 * m; - int m3 = fout_ptr + 6 * m; - int tw1 = 0; - int tw2 = 0; - int tw3 = 0; - for (int j = 0; j < m; ++j) { - int scratch0 = KissFFT.S_MUL(Fout[m1], st.twiddles[tw1]) - KissFFT.S_MUL(Fout[m1 + 1], st.twiddles[tw1 + 1]); - int scratch1 = KissFFT.S_MUL(Fout[m1], st.twiddles[tw1 + 1]) + KissFFT.S_MUL(Fout[m1 + 1], st.twiddles[tw1]); - int scratch2 = KissFFT.S_MUL(Fout[m2], st.twiddles[tw2]) - KissFFT.S_MUL(Fout[m2 + 1], st.twiddles[tw2 + 1]); - int scratch3 = KissFFT.S_MUL(Fout[m2], st.twiddles[tw2 + 1]) + KissFFT.S_MUL(Fout[m2 + 1], st.twiddles[tw2]); - int scratch4 = KissFFT.S_MUL(Fout[m3], st.twiddles[tw3]) - KissFFT.S_MUL(Fout[m3 + 1], st.twiddles[tw3 + 1]); - int scratch5 = KissFFT.S_MUL(Fout[m3], st.twiddles[tw3 + 1]) + KissFFT.S_MUL(Fout[m3 + 1], st.twiddles[tw3]); - int scratch10 = Fout[fout_ptr] - scratch2; - int scratch11 = Fout[fout_ptr + 1] - scratch3; - int n = fout_ptr; - Fout[n] = Fout[n] + scratch2; - int n5 = fout_ptr + 1; - Fout[n5] = Fout[n5] + scratch3; - int scratch6 = scratch0 + scratch4; - int scratch7 = scratch1 + scratch5; - int scratch8 = scratch0 - scratch4; - int scratch9 = scratch1 - scratch5; - Fout[m2] = Fout[fout_ptr] - scratch6; - Fout[m2 + 1] = Fout[fout_ptr + 1] - scratch7; - tw1 += fstride * 2; - tw2 += fstride * 4; - tw3 += fstride * 6; - int n6 = fout_ptr; - Fout[n6] = Fout[n6] + scratch6; - int n7 = fout_ptr + 1; - Fout[n7] = Fout[n7] + scratch7; - Fout[m1] = scratch10 + scratch9; - Fout[m1 + 1] = scratch11 - scratch8; - Fout[m3] = scratch10 - scratch9; - Fout[m3 + 1] = scratch11 + scratch8; - fout_ptr += 2; - m1 += 2; - m2 += 2; - m3 += 2; - } - } - } - } - - static void kf_bfly3(int[] Fout, int fout_ptr, int fstride, FFTState st, int m, int N, int mm) { - int m1 = 2 * m; - int m2 = 4 * m; - int Fout_beg = fout_ptr; - for (int i = 0; i < N; ++i) { - fout_ptr = Fout_beg + 2 * i * mm; - int tw2 = 0; - int tw1 = 0; - int k = m; - do { - int scratch2 = KissFFT.S_MUL(Fout[fout_ptr + m1], st.twiddles[tw1]) - KissFFT.S_MUL(Fout[fout_ptr + m1 + 1], st.twiddles[tw1 + 1]); - int scratch3 = KissFFT.S_MUL(Fout[fout_ptr + m1], st.twiddles[tw1 + 1]) + KissFFT.S_MUL(Fout[fout_ptr + m1 + 1], st.twiddles[tw1]); - int scratch4 = KissFFT.S_MUL(Fout[fout_ptr + m2], st.twiddles[tw2]) - KissFFT.S_MUL(Fout[fout_ptr + m2 + 1], st.twiddles[tw2 + 1]); - int scratch5 = KissFFT.S_MUL(Fout[fout_ptr + m2], st.twiddles[tw2 + 1]) + KissFFT.S_MUL(Fout[fout_ptr + m2 + 1], st.twiddles[tw2]); - int scratch6 = scratch2 + scratch4; - int scratch7 = scratch3 + scratch5; - int scratch0 = scratch2 - scratch4; - int scratch1 = scratch3 - scratch5; - tw1 += fstride * 2; - tw2 += fstride * 4; - Fout[fout_ptr + m1] = Fout[fout_ptr + 0] - KissFFT.HALF_OF(scratch6); - Fout[fout_ptr + m1 + 1] = Fout[fout_ptr + 1] - KissFFT.HALF_OF(scratch7); - scratch0 = KissFFT.S_MUL(scratch0, -28378); - scratch1 = KissFFT.S_MUL(scratch1, -28378); - int n = fout_ptr + 0; - Fout[n] = Fout[n] + scratch6; - int n2 = fout_ptr + 1; - Fout[n2] = Fout[n2] + scratch7; - Fout[fout_ptr + m2] = Fout[fout_ptr + m1] + scratch1; - Fout[fout_ptr + m2 + 1] = Fout[fout_ptr + m1 + 1] - scratch0; - int n3 = fout_ptr + m1; - Fout[n3] = Fout[n3] - scratch1; - int n4 = fout_ptr + m1 + 1; - Fout[n4] = Fout[n4] + scratch0; - fout_ptr += 2; - } while (--k != 0); - } - } - - static void kf_bfly5(int[] Fout, int fout_ptr, int fstride, FFTState st, int m, int N, int mm) { - int Fout_beg = fout_ptr; - short ya_r = 10126; - short ya_i = -31164; - short yb_r = -26510; - short yb_i = -19261; - for (int i = 0; i < N; ++i) { - int tw4 = 0; - int tw3 = 0; - int tw2 = 0; - int tw1 = 0; - int Fout0 = fout_ptr = Fout_beg + 2 * i * mm; - int Fout1 = fout_ptr + 2 * m; - int Fout2 = fout_ptr + 4 * m; - int Fout3 = fout_ptr + 6 * m; - int Fout4 = fout_ptr + 8 * m; - for (int u = 0; u < m; ++u) { - int scratch0 = Fout[Fout0 + 0]; - int scratch1 = Fout[Fout0 + 1]; - int scratch2 = KissFFT.S_MUL(Fout[Fout1 + 0], st.twiddles[tw1]) - KissFFT.S_MUL(Fout[Fout1 + 1], st.twiddles[tw1 + 1]); - int scratch3 = KissFFT.S_MUL(Fout[Fout1 + 0], st.twiddles[tw1 + 1]) + KissFFT.S_MUL(Fout[Fout1 + 1], st.twiddles[tw1]); - int scratch4 = KissFFT.S_MUL(Fout[Fout2 + 0], st.twiddles[tw2]) - KissFFT.S_MUL(Fout[Fout2 + 1], st.twiddles[tw2 + 1]); - int scratch5 = KissFFT.S_MUL(Fout[Fout2 + 0], st.twiddles[tw2 + 1]) + KissFFT.S_MUL(Fout[Fout2 + 1], st.twiddles[tw2]); - int scratch6 = KissFFT.S_MUL(Fout[Fout3 + 0], st.twiddles[tw3]) - KissFFT.S_MUL(Fout[Fout3 + 1], st.twiddles[tw3 + 1]); - int scratch7 = KissFFT.S_MUL(Fout[Fout3 + 0], st.twiddles[tw3 + 1]) + KissFFT.S_MUL(Fout[Fout3 + 1], st.twiddles[tw3]); - int scratch8 = KissFFT.S_MUL(Fout[Fout4 + 0], st.twiddles[tw4]) - KissFFT.S_MUL(Fout[Fout4 + 1], st.twiddles[tw4 + 1]); - int scratch9 = KissFFT.S_MUL(Fout[Fout4 + 0], st.twiddles[tw4 + 1]) + KissFFT.S_MUL(Fout[Fout4 + 1], st.twiddles[tw4]); - tw1 += 2 * fstride; - tw2 += 4 * fstride; - tw3 += 6 * fstride; - tw4 += 8 * fstride; - int scratch14 = scratch2 + scratch8; - int scratch15 = scratch3 + scratch9; - int scratch20 = scratch2 - scratch8; - int scratch21 = scratch3 - scratch9; - int scratch16 = scratch4 + scratch6; - int scratch17 = scratch5 + scratch7; - int scratch18 = scratch4 - scratch6; - int scratch19 = scratch5 - scratch7; - int n = Fout0 + 0; - Fout[n] = Fout[n] + (scratch14 + scratch16); - int n2 = Fout0 + 1; - Fout[n2] = Fout[n2] + (scratch15 + scratch17); - int scratch10 = scratch0 + KissFFT.S_MUL(scratch14, ya_r) + KissFFT.S_MUL(scratch16, yb_r); - int scratch11 = scratch1 + KissFFT.S_MUL(scratch15, ya_r) + KissFFT.S_MUL(scratch17, yb_r); - int scratch12 = KissFFT.S_MUL(scratch21, ya_i) + KissFFT.S_MUL(scratch19, yb_i); - int scratch13 = 0 - KissFFT.S_MUL(scratch20, ya_i) - KissFFT.S_MUL(scratch18, yb_i); - Fout[Fout1 + 0] = scratch10 - scratch12; - Fout[Fout1 + 1] = scratch11 - scratch13; - Fout[Fout4 + 0] = scratch10 + scratch12; - Fout[Fout4 + 1] = scratch11 + scratch13; - int scratch22 = scratch0 + KissFFT.S_MUL(scratch14, yb_r) + KissFFT.S_MUL(scratch16, ya_r); - int scratch23 = scratch1 + KissFFT.S_MUL(scratch15, yb_r) + KissFFT.S_MUL(scratch17, ya_r); - int scratch24 = 0 - KissFFT.S_MUL(scratch21, yb_i) + KissFFT.S_MUL(scratch19, ya_i); - int scratch25 = KissFFT.S_MUL(scratch20, yb_i) - KissFFT.S_MUL(scratch18, ya_i); - Fout[Fout2 + 0] = scratch22 + scratch24; - Fout[Fout2 + 1] = scratch23 + scratch25; - Fout[Fout3 + 0] = scratch22 - scratch24; - Fout[Fout3 + 1] = scratch23 - scratch25; - Fout0 += 2; - Fout1 += 2; - Fout2 += 2; - Fout3 += 2; - Fout4 += 2; - } - } - } - - static void opus_fft_impl(FFTState st, int[] fout, int fout_ptr) { - short m; - int[] fstride = new int[8]; - int shift = st.shift > 0 ? st.shift : 0; - fstride[0] = 1; - int L = 0; - do { - short p = st.factors[2 * L]; - m = st.factors[2 * L + 1]; - fstride[L + 1] = fstride[L] * p; - ++L; - } while (m != 1); - m = st.factors[2 * L - 1]; - for (int i = L - 1; i >= 0; --i) { - short m2 = i != 0 ? st.factors[2 * i - 1] : (short)1; - switch (st.factors[2 * i]) { - case 2: { - KissFFT.kf_bfly2(fout, fout_ptr, m, fstride[i]); - break; - } - case 4: { - KissFFT.kf_bfly4(fout, fout_ptr, fstride[i] << shift, st, m, fstride[i], m2); - break; - } - case 3: { - KissFFT.kf_bfly3(fout, fout_ptr, fstride[i] << shift, st, m, fstride[i], m2); - break; - } - case 5: { - KissFFT.kf_bfly5(fout, fout_ptr, fstride[i] << shift, st, m, fstride[i], m2); - } - } - m = m2; - } - } - - static void opus_fft(FFTState st, int[] fin, int[] fout) { - int scale_shift = st.scale_shift - 1; - short scale = st.scale; - Inlines.OpusAssert(fin != fout, "In-place FFT not supported"); - for (int i = 0; i < st.nfft; ++i) { - fout[2 * st.bitrev[i]] = Inlines.SHR32(Inlines.MULT16_32_Q16(scale, fin[2 * i]), scale_shift); - fout[2 * st.bitrev[i] + 1] = Inlines.SHR32(Inlines.MULT16_32_Q16(scale, fin[2 * i + 1]), scale_shift); - } - KissFFT.opus_fft_impl(st, fout, 0); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/LPCInversePredGain.java b/source/decompiled/de/maxhenkel/voicechat/concentus/LPCInversePredGain.java deleted file mode 100644 index d38e295..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/LPCInversePredGain.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Inlines; - -class LPCInversePredGain { - private static final int QA = 24; - private static final int A_LIMIT = 0xFFEF9E; - - LPCInversePredGain() { - } - - static int LPC_inverse_pred_gain_QA(int[][] A_QA, int order) { - int rc_mult1_Q30; - int rc_Q31; - int[] Anew_QA = A_QA[order & 1]; - int invGain_Q30 = 0x40000000; - for (int k = order - 1; k > 0; --k) { - if (Anew_QA[k] > 0xFFEF9E || Anew_QA[k] < -16773022) { - return 0; - } - rc_Q31 = 0 - Inlines.silk_LSHIFT(Anew_QA[k], 7); - rc_mult1_Q30 = 0x40000000 - Inlines.silk_SMMUL(rc_Q31, rc_Q31); - Inlines.OpusAssert(rc_mult1_Q30 > 32768); - Inlines.OpusAssert(rc_mult1_Q30 <= 0x40000000); - int mult2Q = 32 - Inlines.silk_CLZ32(Inlines.silk_abs(rc_mult1_Q30)); - int rc_mult2 = Inlines.silk_INVERSE32_varQ(rc_mult1_Q30, mult2Q + 30); - invGain_Q30 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2); - Inlines.OpusAssert(invGain_Q30 >= 0); - Inlines.OpusAssert(invGain_Q30 <= 0x40000000); - int[] Aold_QA = Anew_QA; - Anew_QA = A_QA[k & 1]; - for (int n = 0; n < k; ++n) { - int tmp_QA = Aold_QA[n] - Inlines.MUL32_FRAC_Q(Aold_QA[k - n - 1], rc_Q31, 31); - Anew_QA[n] = Inlines.MUL32_FRAC_Q(tmp_QA, rc_mult2, mult2Q); - } - } - if (Anew_QA[0] > 0xFFEF9E || Anew_QA[0] < -16773022) { - return 0; - } - rc_Q31 = 0 - Inlines.silk_LSHIFT(Anew_QA[0], 7); - rc_mult1_Q30 = 0x40000000 - Inlines.silk_SMMUL(rc_Q31, rc_Q31); - Inlines.OpusAssert((invGain_Q30 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2)) >= 0); - Inlines.OpusAssert(invGain_Q30 <= 0x40000000); - return invGain_Q30; - } - - static int silk_LPC_inverse_pred_gain(short[] A_Q12, int order) { - int[][] Atmp_QA = Arrays.InitTwoDimensionalArrayInt(2, 16); - int DC_resp = 0; - int[] Anew_QA = Atmp_QA[order & 1]; - for (int k = 0; k < order; ++k) { - DC_resp += A_Q12[k]; - Anew_QA[k] = Inlines.silk_LSHIFT32(A_Q12[k], 12); - } - if (DC_resp >= 4096) { - return 0; - } - return LPCInversePredGain.LPC_inverse_pred_gain_QA(Atmp_QA, order); - } - - static int silk_LPC_inverse_pred_gain_Q24(int[] A_Q24, int order) { - int[][] Atmp_QA = Arrays.InitTwoDimensionalArrayInt(2, 16); - int[] Anew_QA = Atmp_QA[order & 1]; - for (int k = 0; k < order; ++k) { - Anew_QA[k] = Inlines.silk_RSHIFT32(A_Q24[k], 0); - } - return LPCInversePredGain.LPC_inverse_pred_gain_QA(Atmp_QA, order); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/LTPAnalysisFilter.java b/source/decompiled/de/maxhenkel/voicechat/concentus/LTPAnalysisFilter.java deleted file mode 100644 index 3c5fcb5..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/LTPAnalysisFilter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; - -class LTPAnalysisFilter { - LTPAnalysisFilter() { - } - - static void silk_LTP_analysis_filter(short[] LTP_res, short[] x, int x_ptr, short[] LTPCoef_Q14, int[] pitchL, int[] invGains_Q16, int subfr_length, int nb_subfr, int pre_length) { - short[] Btmp_Q14 = new short[5]; - int x_ptr2 = x_ptr; - int LTP_res_ptr = 0; - for (int k = 0; k < nb_subfr; ++k) { - int x_lag_ptr = x_ptr2 - pitchL[k]; - Btmp_Q14[0] = LTPCoef_Q14[k * 5]; - Btmp_Q14[1] = LTPCoef_Q14[k * 5 + 1]; - Btmp_Q14[2] = LTPCoef_Q14[k * 5 + 2]; - Btmp_Q14[3] = LTPCoef_Q14[k * 5 + 3]; - Btmp_Q14[4] = LTPCoef_Q14[k * 5 + 4]; - for (int i = 0; i < subfr_length + pre_length; ++i) { - int LTP_res_ptri = LTP_res_ptr + i; - LTP_res[LTP_res_ptri] = x[x_ptr2 + i]; - int LTP_est = Inlines.silk_SMULBB(x[x_lag_ptr + 2], Btmp_Q14[0]); - LTP_est = Inlines.silk_SMLABB_ovflw(LTP_est, x[x_lag_ptr + 1], Btmp_Q14[1]); - LTP_est = Inlines.silk_SMLABB_ovflw(LTP_est, x[x_lag_ptr], Btmp_Q14[2]); - LTP_est = Inlines.silk_SMLABB_ovflw(LTP_est, x[x_lag_ptr - 1], Btmp_Q14[3]); - LTP_est = Inlines.silk_SMLABB_ovflw(LTP_est, x[x_lag_ptr - 2], Btmp_Q14[4]); - LTP_est = Inlines.silk_RSHIFT_ROUND(LTP_est, 14); - LTP_res[LTP_res_ptri] = (short)Inlines.silk_SAT16(x[x_ptr2 + i] - LTP_est); - LTP_res[LTP_res_ptri] = (short)Inlines.silk_SMULWB(invGains_Q16[k], LTP_res[LTP_res_ptri]); - ++x_lag_ptr; - } - LTP_res_ptr += subfr_length + pre_length; - x_ptr2 += subfr_length; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/LTPScaleControl.java b/source/decompiled/de/maxhenkel/voicechat/concentus/LTPScaleControl.java deleted file mode 100644 index 323130c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/LTPScaleControl.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkEncoderControl; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class LTPScaleControl { - LTPScaleControl() { - } - - static void silk_LTP_scale_ctrl(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, int condCoding) { - if (condCoding == 0) { - int round_loss = psEnc.PacketLoss_perc + psEnc.nFramesPerPacket; - psEnc.indices.LTP_scaleIndex = (byte)Inlines.silk_LIMIT(Inlines.silk_SMULWB(Inlines.silk_SMULBB(round_loss, psEncCtrl.LTPredCodGain_Q7), 51), 0, 2); - } else { - psEnc.indices.LTP_scaleIndex = 0; - } - psEncCtrl.LTP_scale_Q14 = SilkTables.silk_LTPScales_table_Q14[psEnc.indices.LTP_scaleIndex]; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Laplace.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Laplace.java deleted file mode 100644 index 897592b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Laplace.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; - -class Laplace { - private static final int LAPLACE_LOG_MINP = 0; - private static final long LAPLACE_MINP = 1L; - private static final int LAPLACE_NMIN = 16; - - Laplace() { - } - - static long ec_laplace_get_freq1(long fs0, int decay) { - long ft = Inlines.CapToUInt32(32736L - fs0); - return Inlines.CapToUInt32(ft * (long)(16384 - decay)) >> 15; - } - - static void ec_laplace_encode(EntropyCoder enc, BoxedValueInt value, long fs, int decay) { - int val = value.Val; - long fl = 0L; - if (val != 0) { - int i; - int s = 0 - (val < 0 ? 1 : 0); - val = val + s ^ s; - fl = fs; - fs = Laplace.ec_laplace_get_freq1(fs, decay); - for (i = 1; fs > 0L && i < val; ++i) { - fl = Inlines.CapToUInt32(fl + (fs *= 2L) + 2L); - fs = Inlines.CapToUInt32(fs * (long)decay >> 15); - } - if (fs == 0L) { - int ndi_max = (int)(32768L - fl + 1L - 1L) >> 0; - ndi_max = ndi_max - s >> 1; - int di = Inlines.IMIN(val - i, ndi_max - 1); - fl = Inlines.CapToUInt32(fl + (long)(2 * di + 1 + s) * 1L); - fs = Inlines.IMIN(1L, 32768L - fl); - value.Val = i + di + s ^ s; - } else { - fl += Inlines.CapToUInt32(++fs & (long)(~s)); - } - Inlines.OpusAssert(fl + fs <= 32768L); - Inlines.OpusAssert(fs > 0L); - } - enc.encode_bin(fl, fl + fs, 15); - } - - static int ec_laplace_decode(EntropyCoder dec, long fs, int decay) { - int val = 0; - long fm = dec.decode_bin(15); - long fl = 0L; - if (fm >= fs) { - ++val; - fl = fs; - fs = Laplace.ec_laplace_get_freq1(fs, decay) + 1L; - while (fs > 1L && fm >= fl + 2L * fs) { - fl = Inlines.CapToUInt32(fl + (fs *= 2L)); - fs = Inlines.CapToUInt32((fs - 2L) * (long)decay >> 15); - ++fs; - ++val; - } - if (fs <= 1L) { - int di = (int)(fm - fl) >> 1; - val += di; - fl = Inlines.CapToUInt32(fl + Inlines.CapToUInt32((long)(2 * di) * 1L)); - } - if (fm < fl + fs) { - val = -val; - } else { - fl = Inlines.CapToUInt32(fl + fs); - } - } - Inlines.OpusAssert(fl < 32768L); - Inlines.OpusAssert(fs > 0L); - Inlines.OpusAssert(fl <= fm); - Inlines.OpusAssert(fm < Inlines.IMIN(fl + fs, 32768L)); - dec.dec_update(fl, Inlines.IMIN(fl + fs, 32768L), 32768L); - return val; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/LinearAlgebra.java b/source/decompiled/de/maxhenkel/voicechat/concentus/LinearAlgebra.java deleted file mode 100644 index a6d7042..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/LinearAlgebra.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; - -class LinearAlgebra { - LinearAlgebra() { - } - - static void silk_solve_LDL(int[] A, int A_ptr, int M, int[] b, int[] x_Q16) { - Inlines.OpusAssert(M <= 16); - int[] L_Q16 = new int[M * M]; - int[] Y = new int[16]; - int[] inv_D = new int[32]; - LinearAlgebra.silk_LDL_factorize(A, A_ptr, M, L_Q16, inv_D); - LinearAlgebra.silk_LS_SolveFirst(L_Q16, M, b, Y); - LinearAlgebra.silk_LS_divide_Q16(Y, inv_D, M); - LinearAlgebra.silk_LS_SolveLast(L_Q16, M, Y, x_Q16); - } - - private static void silk_LDL_factorize(int[] A, int A_ptr, int M, int[] L_Q16, int[] inv_D) { - int[] v_Q0 = new int[M]; - int[] D_Q0 = new int[M]; - Inlines.OpusAssert(M <= 16); - boolean status = true; - int diag_min_value = Inlines.silk_max_32(Inlines.silk_SMMUL(Inlines.silk_ADD_SAT32(A[A_ptr], A[A_ptr + Inlines.silk_SMULBB(M, M) - 1]), 21475), 512); - block0: for (int loop_count = 0; loop_count < M && status; ++loop_count) { - status = false; - for (int j = 0; j < M; ++j) { - int i; - int[] scratch1 = L_Q16; - int scratch1_ptr = Inlines.MatrixGetPointer(j, 0, M); - int tmp_32 = 0; - for (i = 0; i < j; ++i) { - v_Q0[i] = Inlines.silk_SMULWW(D_Q0[i], scratch1[scratch1_ptr + i]); - tmp_32 = Inlines.silk_SMLAWW(tmp_32, v_Q0[i], scratch1[scratch1_ptr + i]); - } - tmp_32 = Inlines.silk_SUB32(Inlines.MatrixGet(A, A_ptr, j, j, M), tmp_32); - if (tmp_32 < diag_min_value) { - tmp_32 = Inlines.silk_SUB32(Inlines.silk_SMULBB(loop_count + 1, diag_min_value), tmp_32); - for (i = 0; i < M; ++i) { - Inlines.MatrixSet(A, A_ptr, i, i, M, Inlines.silk_ADD32(Inlines.MatrixGet(A, A_ptr, i, i, M), tmp_32)); - } - status = true; - continue block0; - } - D_Q0[j] = tmp_32; - int one_div_diag_Q36 = Inlines.silk_INVERSE32_varQ(tmp_32, 36); - int one_div_diag_Q40 = Inlines.silk_LSHIFT(one_div_diag_Q36, 4); - int err = Inlines.silk_SUB32(0x1000000, Inlines.silk_SMULWW(tmp_32, one_div_diag_Q40)); - int one_div_diag_Q48 = Inlines.silk_SMULWW(err, one_div_diag_Q40); - inv_D[j * 2 + 0] = one_div_diag_Q36; - inv_D[j * 2 + 1] = one_div_diag_Q48; - Inlines.MatrixSet(L_Q16, j, j, M, 65536); - scratch1 = A; - scratch1_ptr = Inlines.MatrixGetPointer(j, 0, M) + A_ptr; - int[] scratch2 = L_Q16; - int scratch2_ptr = Inlines.MatrixGetPointer(j + 1, 0, M); - for (i = j + 1; i < M; ++i) { - tmp_32 = 0; - for (int k = 0; k < j; ++k) { - tmp_32 = Inlines.silk_SMLAWW(tmp_32, v_Q0[k], scratch2[scratch2_ptr + k]); - } - tmp_32 = Inlines.silk_SUB32(scratch1[scratch1_ptr + i], tmp_32); - Inlines.MatrixSet(L_Q16, i, j, M, Inlines.silk_ADD32(Inlines.silk_SMMUL(tmp_32, one_div_diag_Q48), Inlines.silk_RSHIFT(Inlines.silk_SMULWW(tmp_32, one_div_diag_Q36), 4))); - scratch2_ptr += M; - } - } - } - Inlines.OpusAssert(!status); - } - - private static void silk_LS_divide_Q16(int[] T, int[] inv_D, int M) { - for (int i = 0; i < M; ++i) { - int one_div_diag_Q36 = inv_D[i * 2 + 0]; - int one_div_diag_Q48 = inv_D[i * 2 + 1]; - int tmp_32 = T[i]; - T[i] = Inlines.silk_ADD32(Inlines.silk_SMMUL(tmp_32, one_div_diag_Q48), Inlines.silk_RSHIFT(Inlines.silk_SMULWW(tmp_32, one_div_diag_Q36), 4)); - } - } - - private static void silk_LS_SolveFirst(int[] L_Q16, int M, int[] b, int[] x_Q16) { - for (int i = 0; i < M; ++i) { - int ptr32 = Inlines.MatrixGetPointer(i, 0, M); - int tmp_32 = 0; - for (int j = 0; j < i; ++j) { - tmp_32 = Inlines.silk_SMLAWW(tmp_32, L_Q16[ptr32 + j], x_Q16[j]); - } - x_Q16[i] = Inlines.silk_SUB32(b[i], tmp_32); - } - } - - private static void silk_LS_SolveLast(int[] L_Q16, int M, int[] b, int[] x_Q16) { - for (int i = M - 1; i >= 0; --i) { - int ptr32 = Inlines.MatrixGetPointer(0, i, M); - int tmp_32 = 0; - for (int j = M - 1; j > i; --j) { - tmp_32 = Inlines.silk_SMLAWW(tmp_32, L_Q16[ptr32 + Inlines.silk_SMULBB(j, M)], x_Q16[j]); - } - x_Q16[i] = Inlines.silk_SUB32(b[i], tmp_32); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/MDCT.java b/source/decompiled/de/maxhenkel/voicechat/concentus/MDCT.java deleted file mode 100644 index 2f2708e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/MDCT.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.FFTState; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.KissFFT; -import de.maxhenkel.voicechat.concentus.MDCTLookup; - -class MDCT { - MDCT() { - } - - static void clt_mdct_forward(MDCTLookup l, int[] input, int input_ptr, int[] output, int output_ptr, int[] window, int overlap, int shift, int stride) { - int i; - FFTState st = l.kfft[shift]; - int trig_ptr = 0; - int scale_shift = st.scale_shift - 1; - short scale = st.scale; - int N = l.n; - short[] trig = l.trig; - for (i = 0; i < shift; ++i) { - trig_ptr += (N >>= 1); - } - int N2 = N >> 1; - int N4 = N >> 2; - int[] f = new int[N2]; - int[] f2 = new int[N4 * 2]; - int xp1 = input_ptr + (overlap >> 1); - int xp2 = input_ptr + N2 - 1 + (overlap >> 1); - int yp = 0; - int wp1 = overlap >> 1; - int wp2 = (overlap >> 1) - 1; - for (i = 0; i < overlap + 3 >> 2; ++i) { - f[yp++] = Inlines.MULT16_32_Q15(window[wp2], input[xp1 + N2]) + Inlines.MULT16_32_Q15(window[wp1], input[xp2]); - f[yp++] = Inlines.MULT16_32_Q15(window[wp1], input[xp1]) - Inlines.MULT16_32_Q15(window[wp2], input[xp2 - N2]); - xp1 += 2; - xp2 -= 2; - wp1 += 2; - wp2 -= 2; - } - wp1 = 0; - wp2 = overlap - 1; - while (i < N4 - (overlap + 3 >> 2)) { - f[yp++] = input[xp2]; - f[yp++] = input[xp1]; - xp1 += 2; - xp2 -= 2; - ++i; - } - while (i < N4) { - f[yp++] = Inlines.MULT16_32_Q15(window[wp2], input[xp2]) - Inlines.MULT16_32_Q15(window[wp1], input[xp1 - N2]); - f[yp++] = Inlines.MULT16_32_Q15(window[wp2], input[xp1]) + Inlines.MULT16_32_Q15(window[wp1], input[xp2 + N2]); - xp1 += 2; - xp2 -= 2; - wp1 += 2; - wp2 -= 2; - ++i; - } - int yp2 = 0; - int t = trig_ptr; - for (i = 0; i < N4; ++i) { - short t0 = trig[t + i]; - short t1 = trig[t + N4 + i]; - int re = f[yp2++]; - int im = f[yp2++]; - int yr = KissFFT.S_MUL(re, t0) - KissFFT.S_MUL(im, t1); - int yi = KissFFT.S_MUL(im, t0) + KissFFT.S_MUL(re, t1); - f2[2 * st.bitrev[i]] = Inlines.PSHR32(Inlines.MULT16_32_Q16((int)scale, yr), scale_shift); - f2[2 * st.bitrev[i] + 1] = Inlines.PSHR32(Inlines.MULT16_32_Q16((int)scale, yi), scale_shift); - } - KissFFT.opus_fft_impl(st, f2, 0); - int fp = 0; - int yp1 = output_ptr; - int yp22 = output_ptr + stride * (N2 - 1); - int t2 = trig_ptr; - for (i = 0; i < N4; ++i) { - int yr = KissFFT.S_MUL(f2[fp + 1], trig[t2 + N4 + i]) - KissFFT.S_MUL(f2[fp], trig[t2 + i]); - int yi = KissFFT.S_MUL(f2[fp], trig[t2 + N4 + i]) + KissFFT.S_MUL(f2[fp + 1], trig[t2 + i]); - output[yp1] = yr; - output[yp22] = yi; - fp += 2; - yp1 += 2 * stride; - yp22 -= 2 * stride; - } - } - - static void clt_mdct_backward(MDCTLookup l, int[] input, int input_ptr, int[] output, int output_ptr, int[] window, int overlap, int shift, int stride) { - int i; - int trig = 0; - int N = l.n; - for (i = 0; i < shift; ++i) { - trig += (N >>= 1); - } - int N2 = N >> 1; - int N4 = N >> 2; - int xp2 = input_ptr + stride * (N2 - 1); - int yp = output_ptr + (overlap >> 1); - short[] bitrev = l.kfft[shift].bitrev; - int bitrav_ptr = 0; - for (i = 0; i < N4; ++i) { - short rev = bitrev[bitrav_ptr++]; - int ypr = yp + 2 * rev; - output[ypr + 1] = KissFFT.S_MUL(input[xp2], l.trig[trig + i]) + KissFFT.S_MUL(input[input_ptr], l.trig[trig + N4 + i]); - output[ypr] = KissFFT.S_MUL(input[input_ptr], l.trig[trig + i]) - KissFFT.S_MUL(input[xp2], l.trig[trig + N4 + i]); - input_ptr += 2 * stride; - xp2 -= 2 * stride; - } - KissFFT.opus_fft_impl(l.kfft[shift], output, output_ptr + (overlap >> 1)); - int yp0 = output_ptr + (overlap >> 1); - int yp1 = output_ptr + (overlap >> 1) + N2 - 2; - int t = trig; - int tN4m1 = t + N4 - 1; - int tN2m1 = t + N2 - 1; - for (i = 0; i < N4 + 1 >> 1; ++i) { - int re = output[yp0 + 1]; - int im = output[yp0]; - short t0 = l.trig[t + i]; - short t1 = l.trig[t + N4 + i]; - int yr = KissFFT.S_MUL(re, t0) + KissFFT.S_MUL(im, t1); - int yi = KissFFT.S_MUL(re, t1) - KissFFT.S_MUL(im, t0); - re = output[yp1 + 1]; - im = output[yp1]; - output[yp0] = yr; - output[yp1 + 1] = yi; - t0 = l.trig[tN4m1 - i]; - t1 = l.trig[tN2m1 - i]; - yr = KissFFT.S_MUL(re, t0) + KissFFT.S_MUL(im, t1); - yi = KissFFT.S_MUL(re, t1) - KissFFT.S_MUL(im, t0); - output[yp1] = yr; - output[yp0 + 1] = yi; - yp0 += 2; - yp1 -= 2; - } - int xp1 = output_ptr + overlap - 1; - yp1 = output_ptr; - int wp1 = 0; - int wp2 = overlap - 1; - for (i = 0; i < overlap / 2; ++i) { - int x1 = output[xp1]; - int x2 = output[yp1]; - output[yp1++] = Inlines.MULT16_32_Q15(window[wp2], x2) - Inlines.MULT16_32_Q15(window[wp1], x1); - output[xp1--] = Inlines.MULT16_32_Q15(window[wp1], x2) + Inlines.MULT16_32_Q15(window[wp2], x1); - ++wp1; - --wp2; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/MDCTLookup.java b/source/decompiled/de/maxhenkel/voicechat/concentus/MDCTLookup.java deleted file mode 100644 index 09b9865..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/MDCTLookup.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.FFTState; - -class MDCTLookup { - int n = 0; - int maxshift = 0; - FFTState[] kfft = new FFTState[4]; - short[] trig = null; - - MDCTLookup() { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/MLPState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/MLPState.java deleted file mode 100644 index ba0c328..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/MLPState.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class MLPState { - int layers; - int[] topo; - float[] weights; - - MLPState() { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/MultiLayerPerceptron.java b/source/decompiled/de/maxhenkel/voicechat/concentus/MultiLayerPerceptron.java deleted file mode 100644 index 9d49615..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/MultiLayerPerceptron.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.MLPState; -import de.maxhenkel.voicechat.concentus.OpusTables; - -class MultiLayerPerceptron { - private static final int MAX_NEURONS = 100; - - MultiLayerPerceptron() { - } - - static float tansig_approx(float x) { - float sign = 1.0f; - if (!(x < 8.0f)) { - return 1.0f; - } - if (!(x > -8.0f)) { - return -1.0f; - } - if (x < 0.0f) { - x = -x; - sign = -1.0f; - } - int i = (int)Math.floor(0.5f + 25.0f * x); - float y = OpusTables.tansig_table[i]; - float dy = 1.0f - y * y; - y += (x -= 0.04f * (float)i) * dy * (1.0f - y * x); - return sign * y; - } - - static void mlp_process(MLPState m, float[] input, float[] output) { - int k; - float sum; - int j; - float[] hidden = new float[100]; - float[] W = m.weights; - int W_ptr = 0; - for (j = 0; j < m.topo[1]; ++j) { - sum = W[W_ptr]; - ++W_ptr; - for (k = 0; k < m.topo[0]; ++k) { - sum += input[k] * W[W_ptr]; - ++W_ptr; - } - hidden[j] = MultiLayerPerceptron.tansig_approx(sum); - } - for (j = 0; j < m.topo[2]; ++j) { - sum = W[W_ptr]; - ++W_ptr; - for (k = 0; k < m.topo[1]; ++k) { - sum += hidden[k] * W[W_ptr]; - ++W_ptr; - } - output[j] = MultiLayerPerceptron.tansig_approx(sum); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/NLSF.java b/source/decompiled/de/maxhenkel/voicechat/concentus/NLSF.java deleted file mode 100644 index debf93b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/NLSF.java +++ /dev/null @@ -1,625 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.NLSFCodebook; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkTables; -import de.maxhenkel.voicechat.concentus.Sort; - -class NLSF { - private static final int MAX_STABILIZE_LOOPS = 20; - private static final int QA = 16; - private static final int BIN_DIV_STEPS_A2NLSF = 3; - private static final int MAX_ITERATIONS_A2NLSF = 30; - private static final byte[] ordering16 = new byte[]{0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1}; - private static final byte[] ordering10 = new byte[]{0, 9, 6, 3, 4, 5, 8, 1, 2, 7}; - - NLSF() { - } - - static void silk_NLSF_VQ(int[] err_Q26, short[] in_Q15, short[] pCB_Q8, int K, int LPC_order) { - int pCB_idx = 0; - Inlines.OpusAssert(err_Q26 != null); - Inlines.OpusAssert(LPC_order <= 16); - Inlines.OpusAssert((LPC_order & 1) == 0); - for (int i = 0; i < K; ++i) { - int sum_error_Q26 = 0; - for (int m = 0; m < LPC_order; m += 2) { - int diff_Q15 = Inlines.silk_SUB_LSHIFT32(in_Q15[m], pCB_Q8[pCB_idx++], 7); - int sum_error_Q30 = Inlines.silk_SMULBB(diff_Q15, diff_Q15); - Inlines.OpusAssert((sum_error_Q26 = Inlines.silk_ADD_RSHIFT32(sum_error_Q26, sum_error_Q30 = Inlines.silk_SMLABB(sum_error_Q30, diff_Q15 = Inlines.silk_SUB_LSHIFT32(in_Q15[m + 1], pCB_Q8[pCB_idx++], 7), diff_Q15), 4)) >= 0); - Inlines.OpusAssert(sum_error_Q30 >= 0); - } - err_Q26[i] = sum_error_Q26; - } - } - - static void silk_NLSF_VQ_weights_laroia(short[] pNLSFW_Q_OUT, short[] pNLSF_Q15, int D) { - Inlines.OpusAssert(pNLSFW_Q_OUT != null); - Inlines.OpusAssert(D > 0); - Inlines.OpusAssert((D & 1) == 0); - int tmp1_int = Inlines.silk_max_int(pNLSF_Q15[0], 1); - tmp1_int = Inlines.silk_DIV32(131072, tmp1_int); - int tmp2_int = Inlines.silk_max_int(pNLSF_Q15[1] - pNLSF_Q15[0], 1); - tmp2_int = Inlines.silk_DIV32(131072, tmp2_int); - pNLSFW_Q_OUT[0] = (short)Inlines.silk_min_int(tmp1_int + tmp2_int, Short.MAX_VALUE); - Inlines.OpusAssert(pNLSFW_Q_OUT[0] > 0); - for (int k = 1; k < D - 1; k += 2) { - tmp1_int = Inlines.silk_max_int(pNLSF_Q15[k + 1] - pNLSF_Q15[k], 1); - tmp1_int = Inlines.silk_DIV32(131072, tmp1_int); - pNLSFW_Q_OUT[k] = (short)Inlines.silk_min_int(tmp1_int + tmp2_int, Short.MAX_VALUE); - Inlines.OpusAssert(pNLSFW_Q_OUT[k] > 0); - tmp2_int = Inlines.silk_max_int(pNLSF_Q15[k + 2] - pNLSF_Q15[k + 1], 1); - tmp2_int = Inlines.silk_DIV32(131072, tmp2_int); - pNLSFW_Q_OUT[k + 1] = (short)Inlines.silk_min_int(tmp1_int + tmp2_int, Short.MAX_VALUE); - Inlines.OpusAssert(pNLSFW_Q_OUT[k + 1] > 0); - } - tmp1_int = Inlines.silk_max_int(32768 - pNLSF_Q15[D - 1], 1); - tmp1_int = Inlines.silk_DIV32(131072, tmp1_int); - pNLSFW_Q_OUT[D - 1] = (short)Inlines.silk_min_int(tmp1_int + tmp2_int, Short.MAX_VALUE); - Inlines.OpusAssert(pNLSFW_Q_OUT[D - 1] > 0); - } - - static void silk_NLSF_residual_dequant(short[] x_Q10, byte[] indices, int indices_ptr, short[] pred_coef_Q8, int quant_step_size_Q16, short order) { - short out_Q10 = 0; - for (int i = order - 1; i >= 0; --i) { - int pred_Q10 = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(out_Q10, pred_coef_Q8[i]), 8); - out_Q10 = Inlines.silk_LSHIFT16(indices[indices_ptr + i], 10); - if (out_Q10 > 0) { - out_Q10 = Inlines.silk_SUB16(out_Q10, (short)102); - } else if (out_Q10 < 0) { - out_Q10 = Inlines.silk_ADD16(out_Q10, (short)102); - } - x_Q10[i] = out_Q10 = (short)Inlines.silk_SMLAWB(pred_Q10, out_Q10, quant_step_size_Q16); - } - } - - static void silk_NLSF_unpack(short[] ec_ix, short[] pred_Q8, NLSFCodebook psNLSF_CB, int CB1_index) { - short[] ec_sel = psNLSF_CB.ec_sel; - int ec_sel_ptr = CB1_index * psNLSF_CB.order / 2; - for (int i = 0; i < psNLSF_CB.order; i += 2) { - short entry = ec_sel[ec_sel_ptr]; - ++ec_sel_ptr; - ec_ix[i] = (short)Inlines.silk_SMULBB(Inlines.silk_RSHIFT(entry, 1) & 7, 9); - pred_Q8[i] = psNLSF_CB.pred_Q8[i + (entry & 1) * (psNLSF_CB.order - 1)]; - ec_ix[i + 1] = (short)Inlines.silk_SMULBB(Inlines.silk_RSHIFT(entry, 5) & 7, 9); - pred_Q8[i + 1] = psNLSF_CB.pred_Q8[i + (Inlines.silk_RSHIFT(entry, 4) & 1) * (psNLSF_CB.order - 1) + 1]; - } - } - - static void silk_NLSF_stabilize(short[] NLSF_Q15, short[] NDeltaMin_Q15, int L) { - int i; - int loops; - int I = 0; - Inlines.OpusAssert(NDeltaMin_Q15[L] >= 1); - for (loops = 0; loops < 20; ++loops) { - int k; - int diff_Q15; - int min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0]; - I = 0; - for (i = 1; i <= L - 1; ++i) { - diff_Q15 = NLSF_Q15[i] - (NLSF_Q15[i - 1] + NDeltaMin_Q15[i]); - if (diff_Q15 >= min_diff_Q15) continue; - min_diff_Q15 = diff_Q15; - I = i; - } - diff_Q15 = 32768 - (NLSF_Q15[L - 1] + NDeltaMin_Q15[L]); - if (diff_Q15 < min_diff_Q15) { - min_diff_Q15 = diff_Q15; - I = L; - } - if (min_diff_Q15 >= 0) { - return; - } - if (I == 0) { - NLSF_Q15[0] = NDeltaMin_Q15[0]; - continue; - } - if (I == L) { - NLSF_Q15[L - 1] = (short)(32768 - NDeltaMin_Q15[L]); - continue; - } - int min_center_Q15 = 0; - for (k = 0; k < I; ++k) { - min_center_Q15 += NDeltaMin_Q15[k]; - } - min_center_Q15 += Inlines.silk_RSHIFT(NDeltaMin_Q15[I], 1); - int max_center_Q15 = 32768; - for (k = L; k > I; --k) { - max_center_Q15 -= NDeltaMin_Q15[k]; - } - short center_freq_Q15 = (short)Inlines.silk_LIMIT_32(Inlines.silk_RSHIFT_ROUND(NLSF_Q15[I - 1] + NLSF_Q15[I], 1), min_center_Q15, max_center_Q15 -= Inlines.silk_RSHIFT(NDeltaMin_Q15[I], 1)); - NLSF_Q15[I - 1] = (short)(center_freq_Q15 - Inlines.silk_RSHIFT(NDeltaMin_Q15[I], 1)); - NLSF_Q15[I] = (short)(NLSF_Q15[I - 1] + NDeltaMin_Q15[I]); - } - if (loops == 20) { - Sort.silk_insertion_sort_increasing_all_values_int16(NLSF_Q15, L); - NLSF_Q15[0] = (short)Inlines.silk_max_int(NLSF_Q15[0], NDeltaMin_Q15[0]); - for (i = 1; i < L; ++i) { - NLSF_Q15[i] = (short)Inlines.silk_max_int(NLSF_Q15[i], NLSF_Q15[i - 1] + NDeltaMin_Q15[i]); - } - NLSF_Q15[L - 1] = (short)Inlines.silk_min_int(NLSF_Q15[L - 1], 32768 - NDeltaMin_Q15[L]); - for (i = L - 2; i >= 0; --i) { - NLSF_Q15[i] = (short)Inlines.silk_min_int(NLSF_Q15[i], NLSF_Q15[i + 1] - NDeltaMin_Q15[i + 1]); - } - } - } - - static void silk_NLSF_decode(short[] pNLSF_Q15, byte[] NLSFIndices, NLSFCodebook psNLSF_CB) { - int i; - short[] pred_Q8 = new short[psNLSF_CB.order]; - short[] ec_ix = new short[psNLSF_CB.order]; - short[] res_Q10 = new short[psNLSF_CB.order]; - short[] W_tmp_QW = new short[psNLSF_CB.order]; - short[] pCB = psNLSF_CB.CB1_NLSF_Q8; - int pCB_element = NLSFIndices[0] * psNLSF_CB.order; - for (i = 0; i < psNLSF_CB.order; ++i) { - pNLSF_Q15[i] = Inlines.silk_LSHIFT16(pCB[pCB_element + i], 7); - } - NLSF.silk_NLSF_unpack(ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[0]); - NLSF.silk_NLSF_residual_dequant(res_Q10, NLSFIndices, 1, pred_Q8, psNLSF_CB.quantStepSize_Q16, psNLSF_CB.order); - NLSF.silk_NLSF_VQ_weights_laroia(W_tmp_QW, pNLSF_Q15, psNLSF_CB.order); - for (i = 0; i < psNLSF_CB.order; ++i) { - int W_tmp_Q9 = Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT(W_tmp_QW[i], 16)); - int NLSF_Q15_tmp = Inlines.silk_ADD32(pNLSF_Q15[i], Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(res_Q10[i], 14), (short)W_tmp_Q9)); - pNLSF_Q15[i] = (short)Inlines.silk_LIMIT(NLSF_Q15_tmp, 0, Short.MAX_VALUE); - } - NLSF.silk_NLSF_stabilize(pNLSF_Q15, psNLSF_CB.deltaMin_Q15, psNLSF_CB.order); - } - - static int silk_NLSF_del_dec_quant(byte[] indices, short[] x_Q10, short[] w_Q5, short[] pred_coef_Q8, short[] ec_ix, short[] ec_rates_Q5, int quant_step_size_Q16, short inv_quant_step_size_Q6, int mu_Q20, short order) { - int ind_tmp; - int j; - int out1_Q10; - int out0_Q10; - int i; - int[] ind_sort = new int[4]; - byte[][] ind = new byte[4][]; - for (i = 0; i < 4; ++i) { - ind[i] = new byte[16]; - } - short[] prev_out_Q10 = new short[8]; - int[] RD_Q25 = new int[8]; - int[] RD_min_Q25 = new int[4]; - int[] RD_max_Q25 = new int[4]; - int[] out0_Q10_table = new int[20]; - int[] out1_Q10_table = new int[20]; - for (i = -10; i <= 9; ++i) { - out0_Q10 = Inlines.silk_LSHIFT(i, 10); - out1_Q10 = Inlines.silk_ADD16((short)out0_Q10, (short)1024); - if (i > 0) { - out0_Q10 = Inlines.silk_SUB16((short)out0_Q10, (short)102); - out1_Q10 = Inlines.silk_SUB16((short)out1_Q10, (short)102); - } else if (i == 0) { - out1_Q10 = Inlines.silk_SUB16((short)out1_Q10, (short)102); - } else if (i == -1) { - out0_Q10 = Inlines.silk_ADD16((short)out0_Q10, (short)102); - } else { - out0_Q10 = Inlines.silk_ADD16((short)out0_Q10, (short)102); - out1_Q10 = Inlines.silk_ADD16((short)out1_Q10, (short)102); - } - out0_Q10_table[i + 10] = Inlines.silk_SMULWB(out0_Q10, quant_step_size_Q16); - out1_Q10_table[i + 10] = Inlines.silk_SMULWB(out1_Q10, quant_step_size_Q16); - } - Inlines.OpusAssert(true); - int nStates = 1; - RD_Q25[0] = 0; - prev_out_Q10[0] = 0; - i = order - 1; - while (true) { - int pred_coef_Q16 = Inlines.silk_LSHIFT(pred_coef_Q8[i], 8); - short in_Q10 = x_Q10[i]; - for (j = 0; j < nStates; ++j) { - int rate1_Q5; - int rate0_Q5; - int pred_Q10 = Inlines.silk_SMULWB(pred_coef_Q16, prev_out_Q10[j]); - short res_Q10 = Inlines.silk_SUB16(in_Q10, (short)pred_Q10); - ind_tmp = Inlines.silk_SMULWB(inv_quant_step_size_Q6, res_Q10); - ind_tmp = Inlines.silk_LIMIT(ind_tmp, -10, 9); - ind[j][i] = (byte)ind_tmp; - int rates_Q5 = ec_ix[i] + ind_tmp; - out0_Q10 = out0_Q10_table[ind_tmp + 10]; - out1_Q10 = out1_Q10_table[ind_tmp + 10]; - out0_Q10 = Inlines.silk_ADD16((short)out0_Q10, (short)pred_Q10); - out1_Q10 = Inlines.silk_ADD16((short)out1_Q10, (short)pred_Q10); - prev_out_Q10[j] = (short)out0_Q10; - prev_out_Q10[j + nStates] = (short)out1_Q10; - if (ind_tmp + 1 >= 4) { - if (ind_tmp + 1 == 4) { - rate0_Q5 = ec_rates_Q5[rates_Q5 + 4]; - rate1_Q5 = 280; - } else { - rate0_Q5 = Inlines.silk_SMLABB(108, 43, ind_tmp); - rate1_Q5 = Inlines.silk_ADD16((short)rate0_Q5, (short)43); - } - } else if (ind_tmp <= -4) { - if (ind_tmp == -4) { - rate0_Q5 = 280; - rate1_Q5 = ec_rates_Q5[rates_Q5 + 1 + 4]; - } else { - rate0_Q5 = Inlines.silk_SMLABB(108, -43, ind_tmp); - rate1_Q5 = Inlines.silk_SUB16((short)rate0_Q5, (short)43); - } - } else { - rate0_Q5 = ec_rates_Q5[rates_Q5 + 4]; - rate1_Q5 = ec_rates_Q5[rates_Q5 + 1 + 4]; - } - int RD_tmp_Q25 = RD_Q25[j]; - short diff_Q10 = Inlines.silk_SUB16(in_Q10, (short)out0_Q10); - RD_Q25[j] = Inlines.silk_SMLABB(Inlines.silk_MLA(RD_tmp_Q25, Inlines.silk_SMULBB(diff_Q10, diff_Q10), w_Q5[i]), mu_Q20, rate0_Q5); - diff_Q10 = Inlines.silk_SUB16(in_Q10, (short)out1_Q10); - RD_Q25[j + nStates] = Inlines.silk_SMLABB(Inlines.silk_MLA(RD_tmp_Q25, Inlines.silk_SMULBB(diff_Q10, diff_Q10), w_Q5[i]), mu_Q20, rate1_Q5); - } - if (nStates <= 2) { - for (j = 0; j < nStates; ++j) { - ind[j + nStates][i] = (byte)(ind[j][i] + 1); - } - for (j = nStates = Inlines.silk_LSHIFT(nStates, 1); j < 4; ++j) { - ind[j][i] = ind[j - nStates][i]; - } - } else { - if (i <= 0) break; - for (j = 0; j < 4; ++j) { - if (RD_Q25[j] > RD_Q25[j + 4]) { - RD_max_Q25[j] = RD_Q25[j]; - RD_min_Q25[j] = RD_Q25[j + 4]; - RD_Q25[j] = RD_min_Q25[j]; - RD_Q25[j + 4] = RD_max_Q25[j]; - out0_Q10 = prev_out_Q10[j]; - prev_out_Q10[j] = prev_out_Q10[j + 4]; - prev_out_Q10[j + 4] = (short)out0_Q10; - ind_sort[j] = j + 4; - continue; - } - RD_min_Q25[j] = RD_Q25[j]; - RD_max_Q25[j] = RD_Q25[j + 4]; - ind_sort[j] = j; - } - while (true) { - int min_max_Q25 = Integer.MAX_VALUE; - int max_min_Q25 = 0; - int ind_min_max = 0; - int ind_max_min = 0; - for (j = 0; j < 4; ++j) { - if (min_max_Q25 > RD_max_Q25[j]) { - min_max_Q25 = RD_max_Q25[j]; - ind_min_max = j; - } - if (max_min_Q25 >= RD_min_Q25[j]) continue; - max_min_Q25 = RD_min_Q25[j]; - ind_max_min = j; - } - if (min_max_Q25 >= max_min_Q25) break; - ind_sort[ind_max_min] = ind_sort[ind_min_max] ^ 4; - RD_Q25[ind_max_min] = RD_Q25[ind_min_max + 4]; - prev_out_Q10[ind_max_min] = prev_out_Q10[ind_min_max + 4]; - RD_min_Q25[ind_max_min] = 0; - RD_max_Q25[ind_min_max] = Integer.MAX_VALUE; - System.arraycopy(ind[ind_min_max], 0, ind[ind_max_min], 0, order); - } - for (j = 0; j < 4; ++j) { - byte x = (byte)Inlines.silk_RSHIFT(ind_sort[j], 2); - byte[] byArray = ind[j]; - int n = i; - byArray[n] = (byte)(byArray[n] + x); - } - } - --i; - } - ind_tmp = 0; - int min_Q25 = Integer.MAX_VALUE; - for (j = 0; j < 8; ++j) { - if (min_Q25 <= RD_Q25[j]) continue; - min_Q25 = RD_Q25[j]; - ind_tmp = j; - } - for (j = 0; j < order; ++j) { - indices[j] = ind[ind_tmp & 3][j]; - Inlines.OpusAssert(indices[j] >= -10); - Inlines.OpusAssert(indices[j] <= 10); - } - indices[0] = (byte)(indices[0] + Inlines.silk_RSHIFT(ind_tmp, 2)); - Inlines.OpusAssert(indices[0] <= 10); - Inlines.OpusAssert(min_Q25 >= 0); - return min_Q25; - } - - static int silk_NLSF_encode(byte[] NLSFIndices, short[] pNLSF_Q15, NLSFCodebook psNLSF_CB, short[] pW_QW, int NLSF_mu_Q20, int nSurvivors, int signalType) { - short[] res_Q15 = new short[psNLSF_CB.order]; - short[] res_Q10 = new short[psNLSF_CB.order]; - short[] NLSF_tmp_Q15 = new short[psNLSF_CB.order]; - short[] W_tmp_QW = new short[psNLSF_CB.order]; - short[] W_adj_Q5 = new short[psNLSF_CB.order]; - short[] pred_Q8 = new short[psNLSF_CB.order]; - short[] ec_ix = new short[psNLSF_CB.order]; - short[] pCB = psNLSF_CB.CB1_NLSF_Q8; - Inlines.OpusAssert(nSurvivors <= 32); - Inlines.OpusAssert(signalType >= 0 && signalType <= 2); - Inlines.OpusAssert(NLSF_mu_Q20 <= Short.MAX_VALUE && NLSF_mu_Q20 >= 0); - NLSF.silk_NLSF_stabilize(pNLSF_Q15, psNLSF_CB.deltaMin_Q15, psNLSF_CB.order); - int[] err_Q26 = new int[psNLSF_CB.nVectors]; - NLSF.silk_NLSF_VQ(err_Q26, pNLSF_Q15, psNLSF_CB.CB1_NLSF_Q8, psNLSF_CB.nVectors, psNLSF_CB.order); - int[] tempIndices1 = new int[nSurvivors]; - Sort.silk_insertion_sort_increasing(err_Q26, tempIndices1, psNLSF_CB.nVectors, nSurvivors); - int[] RD_Q25 = new int[nSurvivors]; - byte[][] tempIndices2 = Arrays.InitTwoDimensionalArrayByte(nSurvivors, 16); - for (int s = 0; s < nSurvivors; ++s) { - int i; - int ind1 = tempIndices1[s]; - int pCB_element = ind1 * psNLSF_CB.order; - for (i = 0; i < psNLSF_CB.order; ++i) { - NLSF_tmp_Q15[i] = Inlines.silk_LSHIFT16(pCB[pCB_element + i], 7); - res_Q15[i] = (short)(pNLSF_Q15[i] - NLSF_tmp_Q15[i]); - } - NLSF.silk_NLSF_VQ_weights_laroia(W_tmp_QW, NLSF_tmp_Q15, psNLSF_CB.order); - for (i = 0; i < psNLSF_CB.order; ++i) { - int W_tmp_Q9 = Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT(W_tmp_QW[i], 16)); - res_Q10[i] = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(res_Q15[i], W_tmp_Q9), 14); - } - for (i = 0; i < psNLSF_CB.order; ++i) { - W_adj_Q5[i] = (short)Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(pW_QW[i], 5), W_tmp_QW[i]); - } - NLSF.silk_NLSF_unpack(ec_ix, pred_Q8, psNLSF_CB, ind1); - RD_Q25[s] = NLSF.silk_NLSF_del_dec_quant(tempIndices2[s], res_Q10, W_adj_Q5, pred_Q8, ec_ix, psNLSF_CB.ec_Rates_Q5, psNLSF_CB.quantStepSize_Q16, psNLSF_CB.invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB.order); - int iCDF_ptr = (signalType >> 1) * psNLSF_CB.nVectors; - int prob_Q8 = ind1 == 0 ? 256 - psNLSF_CB.CB1_iCDF[iCDF_ptr + ind1] : psNLSF_CB.CB1_iCDF[iCDF_ptr + ind1 - 1] - psNLSF_CB.CB1_iCDF[iCDF_ptr + ind1]; - int bits_q7 = 1024 - Inlines.silk_lin2log(prob_Q8); - RD_Q25[s] = Inlines.silk_SMLABB(RD_Q25[s], bits_q7, Inlines.silk_RSHIFT(NLSF_mu_Q20, 2)); - } - int[] bestIndex = new int[1]; - Sort.silk_insertion_sort_increasing(RD_Q25, bestIndex, nSurvivors, 1); - NLSFIndices[0] = (byte)tempIndices1[bestIndex[0]]; - System.arraycopy(tempIndices2[bestIndex[0]], 0, NLSFIndices, 1, psNLSF_CB.order); - NLSF.silk_NLSF_decode(pNLSF_Q15, NLSFIndices, psNLSF_CB); - return RD_Q25[0]; - } - - static void silk_NLSF2A_find_poly(int[] o, int[] cLSF, int cLSF_ptr, int dd) { - o[0] = Inlines.silk_LSHIFT(1, 16); - o[1] = 0 - cLSF[cLSF_ptr]; - for (int k = 1; k < dd; ++k) { - int ftmp = cLSF[cLSF_ptr + 2 * k]; - o[k + 1] = Inlines.silk_LSHIFT(o[k - 1], 1) - (int)Inlines.silk_RSHIFT_ROUND64(Inlines.silk_SMULL(ftmp, o[k]), 16); - for (int n = k; n > 1; --n) { - int n2 = n; - o[n2] = o[n2] + (o[n - 2] - (int)Inlines.silk_RSHIFT_ROUND64(Inlines.silk_SMULL(ftmp, o[n - 1]), 16)); - } - o[1] = o[1] - ftmp; - } - } - - static void silk_NLSF2A(short[] a_Q12, short[] NLSF2, int d) { - int i; - int k; - int[] cos_LSF_QA = new int[d]; - int[] P = new int[d / 2 + 1]; - int[] Q = new int[d / 2 + 1]; - int[] a32_QA1 = new int[d]; - int idx = 0; - Inlines.OpusAssert(true); - Inlines.OpusAssert(d == 10 || d == 16); - byte[] ordering = d == 16 ? ordering16 : ordering10; - for (k = 0; k < d; ++k) { - Inlines.OpusAssert(NLSF2[k] >= 0); - int f_int = Inlines.silk_RSHIFT(NLSF2[k], 8); - int f_frac = NLSF2[k] - Inlines.silk_LSHIFT(f_int, 8); - Inlines.OpusAssert(f_int >= 0); - Inlines.OpusAssert(f_int < 128); - short cos_val = SilkTables.silk_LSFCosTab_Q12[f_int]; - int delta = SilkTables.silk_LSFCosTab_Q12[f_int + 1] - cos_val; - cos_LSF_QA[ordering[k]] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_LSHIFT(cos_val, 8) + Inlines.silk_MUL(delta, f_frac), 4); - } - int dd = Inlines.silk_RSHIFT(d, 1); - NLSF.silk_NLSF2A_find_poly(P, cos_LSF_QA, 0, dd); - NLSF.silk_NLSF2A_find_poly(Q, cos_LSF_QA, 1, dd); - for (k = 0; k < dd; ++k) { - int Ptmp = P[k + 1] + P[k]; - int Qtmp = Q[k + 1] - Q[k]; - a32_QA1[k] = -Qtmp - Ptmp; - a32_QA1[d - k - 1] = Qtmp - Ptmp; - } - for (i = 0; i < 10; ++i) { - int maxabs = 0; - for (k = 0; k < d; ++k) { - int absval = Inlines.silk_abs(a32_QA1[k]); - if (absval <= maxabs) continue; - maxabs = absval; - idx = k; - } - if ((maxabs = Inlines.silk_RSHIFT_ROUND(maxabs, 5)) <= Short.MAX_VALUE) break; - maxabs = Inlines.silk_min(maxabs, 163838); - int sc_Q16 = 65470 - Inlines.silk_DIV32(Inlines.silk_LSHIFT(maxabs - Short.MAX_VALUE, 14), Inlines.silk_RSHIFT32(Inlines.silk_MUL(maxabs, idx + 1), 2)); - Filters.silk_bwexpander_32(a32_QA1, d, sc_Q16); - } - if (i == 10) { - for (k = 0; k < d; ++k) { - a_Q12[k] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a32_QA1[k], 5)); - a32_QA1[k] = Inlines.silk_LSHIFT(a_Q12[k], 5); - } - } else { - for (k = 0; k < d; ++k) { - a_Q12[k] = (short)Inlines.silk_RSHIFT_ROUND(a32_QA1[k], 5); - } - } - for (i = 0; i < 16 && Filters.silk_LPC_inverse_pred_gain(a_Q12, d) < 107374; ++i) { - Filters.silk_bwexpander_32(a32_QA1, d, 65536 - Inlines.silk_LSHIFT(2, i)); - for (k = 0; k < d; ++k) { - a_Q12[k] = (short)Inlines.silk_RSHIFT_ROUND(a32_QA1[k], 5); - } - } - } - - static void silk_A2NLSF_trans_poly(int[] p, int dd) { - for (int k = 2; k <= dd; ++k) { - for (int n = dd; n > k; --n) { - int n2 = n - 2; - p[n2] = p[n2] - p[n]; - } - int n = k - 2; - p[n] = p[n] - Inlines.silk_LSHIFT(p[k], 1); - } - } - - static int silk_A2NLSF_eval_poly(int[] p, int x, int dd) { - int y32 = p[dd]; - int x_Q16 = Inlines.silk_LSHIFT(x, 4); - if (8 == dd) { - y32 = Inlines.silk_SMLAWW(p[7], y32, x_Q16); - y32 = Inlines.silk_SMLAWW(p[6], y32, x_Q16); - y32 = Inlines.silk_SMLAWW(p[5], y32, x_Q16); - y32 = Inlines.silk_SMLAWW(p[4], y32, x_Q16); - y32 = Inlines.silk_SMLAWW(p[3], y32, x_Q16); - y32 = Inlines.silk_SMLAWW(p[2], y32, x_Q16); - y32 = Inlines.silk_SMLAWW(p[1], y32, x_Q16); - y32 = Inlines.silk_SMLAWW(p[0], y32, x_Q16); - } else { - for (int n = dd - 1; n >= 0; --n) { - y32 = Inlines.silk_SMLAWW(p[n], y32, x_Q16); - } - } - return y32; - } - - static void silk_A2NLSF_init(int[] a_Q16, int[] P, int[] Q, int dd) { - int k; - P[dd] = Inlines.silk_LSHIFT(1, 16); - Q[dd] = Inlines.silk_LSHIFT(1, 16); - for (k = 0; k < dd; ++k) { - P[k] = -a_Q16[dd - k - 1] - a_Q16[dd + k]; - Q[k] = -a_Q16[dd - k - 1] + a_Q16[dd + k]; - } - for (k = dd; k > 0; --k) { - int n = k - 1; - P[n] = P[n] - P[k]; - int n2 = k - 1; - Q[n2] = Q[n2] + Q[k]; - } - NLSF.silk_A2NLSF_trans_poly(P, dd); - NLSF.silk_A2NLSF_trans_poly(Q, dd); - } - - static void silk_A2NLSF(short[] NLSF2, int[] a_Q16, int d) { - int root_ix; - int[] P = new int[9]; - int[] Q = new int[9]; - int[][] PQ = new int[][]{P, Q}; - int dd = Inlines.silk_RSHIFT(d, 1); - NLSF.silk_A2NLSF_init(a_Q16, P, Q, dd); - int[] p = P; - int xlo = SilkTables.silk_LSFCosTab_Q12[0]; - int ylo = NLSF.silk_A2NLSF_eval_poly(p, xlo, dd); - if (ylo < 0) { - NLSF2[0] = 0; - p = Q; - ylo = NLSF.silk_A2NLSF_eval_poly(p, xlo, dd); - root_ix = 1; - } else { - root_ix = 0; - } - int k = 1; - int i = 0; - int thr = 0; - while (true) { - int xhi = SilkTables.silk_LSFCosTab_Q12[k]; - int yhi = NLSF.silk_A2NLSF_eval_poly(p, xhi, dd); - if (ylo <= 0 && yhi >= thr || ylo >= 0 && yhi <= -thr) { - thr = yhi == 0 ? 1 : 0; - int ffrac = -256; - for (int m = 0; m < 3; ++m) { - int xmid = Inlines.silk_RSHIFT_ROUND(xlo + xhi, 1); - int ymid = NLSF.silk_A2NLSF_eval_poly(p, xmid, dd); - if (ylo <= 0 && ymid >= 0 || ylo >= 0 && ymid <= 0) { - xhi = xmid; - yhi = ymid; - continue; - } - xlo = xmid; - ylo = ymid; - ffrac = Inlines.silk_ADD_RSHIFT(ffrac, 128, m); - } - if (Inlines.silk_abs(ylo) < 65536) { - int den = ylo - yhi; - int nom = Inlines.silk_LSHIFT(ylo, 5) + Inlines.silk_RSHIFT(den, 1); - if (den != 0) { - ffrac += Inlines.silk_DIV32(nom, den); - } - } else { - ffrac += Inlines.silk_DIV32(ylo, Inlines.silk_RSHIFT(ylo - yhi, 5)); - } - NLSF2[root_ix] = (short)Inlines.silk_min_32(Inlines.silk_LSHIFT(k, 8) + ffrac, Short.MAX_VALUE); - Inlines.OpusAssert(NLSF2[root_ix] >= 0); - if (++root_ix >= d) break; - p = PQ[root_ix & 1]; - xlo = SilkTables.silk_LSFCosTab_Q12[k - 1]; - ylo = Inlines.silk_LSHIFT(1 - (root_ix & 2), 12); - continue; - } - xlo = xhi; - ylo = yhi; - thr = 0; - if (++k <= 128) continue; - if (++i > 30) { - NLSF2[0] = (short)Inlines.silk_DIV32_16(32768, (short)(d + 1)); - for (k = 1; k < d; ++k) { - NLSF2[k] = (short)Inlines.silk_SMULBB(k + 1, NLSF2[0]); - } - return; - } - Filters.silk_bwexpander_32(a_Q16, d, 65536 - Inlines.silk_SMULBB(10 + i, i)); - NLSF.silk_A2NLSF_init(a_Q16, P, Q, dd); - p = P; - xlo = SilkTables.silk_LSFCosTab_Q12[0]; - ylo = NLSF.silk_A2NLSF_eval_poly(p, xlo, dd); - if (ylo < 0) { - NLSF2[0] = 0; - p = Q; - ylo = NLSF.silk_A2NLSF_eval_poly(p, xlo, dd); - root_ix = 1; - } else { - root_ix = 0; - } - k = 1; - } - } - - static void silk_process_NLSFs(SilkChannelEncoder psEncC, short[][] PredCoef_Q12, short[] pNLSF_Q15, short[] prev_NLSFq_Q15) { - boolean doInterpolate; - short[] pNLSF0_temp_Q15 = new short[16]; - short[] pNLSFW_QW = new short[16]; - short[] pNLSFW0_temp_QW = new short[16]; - Inlines.OpusAssert(psEncC.speech_activity_Q8 >= 0); - Inlines.OpusAssert(psEncC.speech_activity_Q8 <= 256); - Inlines.OpusAssert(psEncC.useInterpolatedNLSFs == 1 || psEncC.indices.NLSFInterpCoef_Q2 == 4); - int NLSF_mu_Q20 = Inlines.silk_SMLAWB(3146, -268434, psEncC.speech_activity_Q8); - if (psEncC.nb_subfr == 2) { - NLSF_mu_Q20 = Inlines.silk_ADD_RSHIFT(NLSF_mu_Q20, NLSF_mu_Q20, 1); - } - Inlines.OpusAssert(NLSF_mu_Q20 > 0); - Inlines.OpusAssert(NLSF_mu_Q20 <= 5243); - NLSF.silk_NLSF_VQ_weights_laroia(pNLSFW_QW, pNLSF_Q15, psEncC.predictLPCOrder); - boolean bl = doInterpolate = psEncC.useInterpolatedNLSFs == 1 && psEncC.indices.NLSFInterpCoef_Q2 < 4; - if (doInterpolate) { - Inlines.silk_interpolate(pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, psEncC.indices.NLSFInterpCoef_Q2, psEncC.predictLPCOrder); - NLSF.silk_NLSF_VQ_weights_laroia(pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC.predictLPCOrder); - int i_sqr_Q15 = Inlines.silk_LSHIFT(Inlines.silk_SMULBB(psEncC.indices.NLSFInterpCoef_Q2, psEncC.indices.NLSFInterpCoef_Q2), 11); - for (int i = 0; i < psEncC.predictLPCOrder; ++i) { - pNLSFW_QW[i] = (short)Inlines.silk_SMLAWB(Inlines.silk_RSHIFT(pNLSFW_QW[i], 1), pNLSFW0_temp_QW[i], i_sqr_Q15); - Inlines.OpusAssert(pNLSFW_QW[i] >= 1); - } - } - NLSF.silk_NLSF_encode(psEncC.indices.NLSFIndices, pNLSF_Q15, psEncC.psNLSF_CB, pNLSFW_QW, NLSF_mu_Q20, psEncC.NLSF_MSVQ_Survivors, psEncC.indices.signalType); - NLSF.silk_NLSF2A(PredCoef_Q12[1], pNLSF_Q15, psEncC.predictLPCOrder); - if (doInterpolate) { - Inlines.silk_interpolate(pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, psEncC.indices.NLSFInterpCoef_Q2, psEncC.predictLPCOrder); - NLSF.silk_NLSF2A(PredCoef_Q12[0], pNLSF0_temp_Q15, psEncC.predictLPCOrder); - } else { - System.arraycopy(PredCoef_Q12[1], 0, PredCoef_Q12[0], 0, psEncC.predictLPCOrder); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/NLSFCodebook.java b/source/decompiled/de/maxhenkel/voicechat/concentus/NLSFCodebook.java deleted file mode 100644 index b5505a2..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/NLSFCodebook.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class NLSFCodebook { - short nVectors = 0; - short order = 0; - short quantStepSize_Q16 = 0; - short invQuantStepSize_Q6 = 0; - short[] CB1_NLSF_Q8 = null; - short[] CB1_iCDF = null; - short[] pred_Q8 = null; - short[] ec_sel = null; - short[] ec_iCDF = null; - short[] ec_Rates_Q5 = null; - short[] deltaMin_Q15 = null; - - NLSFCodebook() { - } - - void Reset() { - this.nVectors = 0; - this.order = 0; - this.quantStepSize_Q16 = 0; - this.invQuantStepSize_Q6 = 0; - this.CB1_NLSF_Q8 = null; - this.CB1_iCDF = null; - this.pred_Q8 = null; - this.ec_sel = null; - this.ec_iCDF = null; - this.ec_Rates_Q5 = null; - this.deltaMin_Q15 = null; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/NoiseShapeAnalysis.java b/source/decompiled/de/maxhenkel/voicechat/concentus/NoiseShapeAnalysis.java deleted file mode 100644 index f430c48..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/NoiseShapeAnalysis.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.ApplySineWindow; -import de.maxhenkel.voicechat.concentus.Autocorrelation; -import de.maxhenkel.voicechat.concentus.BWExpander; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.K2A; -import de.maxhenkel.voicechat.concentus.LPCInversePredGain; -import de.maxhenkel.voicechat.concentus.Schur; -import de.maxhenkel.voicechat.concentus.Sigmoid; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkEncoderControl; -import de.maxhenkel.voicechat.concentus.SilkShapeState; -import de.maxhenkel.voicechat.concentus.SumSqrShift; - -class NoiseShapeAnalysis { - NoiseShapeAnalysis() { - } - - static int warped_gain(int[] coefs_Q24, int lambda_Q16, int order) { - lambda_Q16 = -lambda_Q16; - int gain_Q24 = coefs_Q24[order - 1]; - for (int i = order - 2; i >= 0; --i) { - gain_Q24 = Inlines.silk_SMLAWB(coefs_Q24[i], gain_Q24, lambda_Q16); - } - gain_Q24 = Inlines.silk_SMLAWB(0x1000000, gain_Q24, -lambda_Q16); - return Inlines.silk_INVERSE32_varQ(gain_Q24, 40); - } - - static void limit_warped_coefs(int[] coefs_syn_Q24, int[] coefs_ana_Q24, int lambda_Q16, int limit_Q24, int order) { - int i; - int ind = 0; - lambda_Q16 = -lambda_Q16; - for (i = order - 1; i > 0; --i) { - coefs_syn_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16); - coefs_ana_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16); - } - lambda_Q16 = -lambda_Q16; - int nom_Q16 = Inlines.silk_SMLAWB(65536, -lambda_Q16, lambda_Q16); - int den_Q24 = Inlines.silk_SMLAWB(0x1000000, coefs_syn_Q24[0], lambda_Q16); - int gain_syn_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24); - den_Q24 = Inlines.silk_SMLAWB(0x1000000, coefs_ana_Q24[0], lambda_Q16); - int gain_ana_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24); - for (i = 0; i < order; ++i) { - coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]); - coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]); - } - for (int iter = 0; iter < 10; ++iter) { - int maxabs_Q24 = -1; - for (i = 0; i < order; ++i) { - int tmp = Inlines.silk_max(Inlines.silk_abs_int32(coefs_syn_Q24[i]), Inlines.silk_abs_int32(coefs_ana_Q24[i])); - if (tmp <= maxabs_Q24) continue; - maxabs_Q24 = tmp; - ind = i; - } - if (maxabs_Q24 <= limit_Q24) { - return; - } - for (i = 1; i < order; ++i) { - coefs_syn_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16); - coefs_ana_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16); - } - gain_syn_Q16 = Inlines.silk_INVERSE32_varQ(gain_syn_Q16, 32); - gain_ana_Q16 = Inlines.silk_INVERSE32_varQ(gain_ana_Q16, 32); - for (i = 0; i < order; ++i) { - coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]); - coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]); - } - int chirp_Q16 = 64881 - Inlines.silk_DIV32_varQ(Inlines.silk_SMULWB(maxabs_Q24 - limit_Q24, Inlines.silk_SMLABB(819, 102, iter)), Inlines.silk_MUL(maxabs_Q24, ind + 1), 22); - BWExpander.silk_bwexpander_32(coefs_syn_Q24, order, chirp_Q16); - BWExpander.silk_bwexpander_32(coefs_ana_Q24, order, chirp_Q16); - lambda_Q16 = -lambda_Q16; - for (i = order - 1; i > 0; --i) { - coefs_syn_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16); - coefs_ana_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16); - } - lambda_Q16 = -lambda_Q16; - nom_Q16 = Inlines.silk_SMLAWB(65536, -lambda_Q16, lambda_Q16); - den_Q24 = Inlines.silk_SMLAWB(0x1000000, coefs_syn_Q24[0], lambda_Q16); - gain_syn_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24); - den_Q24 = Inlines.silk_SMLAWB(0x1000000, coefs_ana_Q24[0], lambda_Q16); - gain_ana_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24); - for (i = 0; i < order; ++i) { - coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]); - coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]); - } - } - Inlines.OpusAssert(false); - } - - static void silk_noise_shape_analysis(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, short[] pitch_res, int pitch_res_ptr, short[] x, int x_ptr) { - int HarmShapeGain_Q16; - int Tilt_Q16; - int b_Q14; - int gain_mult_Q16; - int BWExp2_Q16; - int nrg; - int k; - SilkShapeState psShapeSt = psEnc.sShape; - int scale = 0; - int[] auto_corr = new int[17]; - int[] refl_coef_Q16 = new int[16]; - int[] AR1_Q24 = new int[16]; - int[] AR2_Q24 = new int[16]; - int x_ptr2 = x_ptr - psEnc.la_shape; - int SNR_adj_dB_Q7 = psEnc.SNR_dB_Q7; - psEncCtrl.input_quality_Q14 = Inlines.silk_RSHIFT(psEnc.input_quality_bands_Q15[0] + psEnc.input_quality_bands_Q15[1], 2); - psEncCtrl.coding_quality_Q14 = Inlines.silk_RSHIFT(Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT_ROUND(SNR_adj_dB_Q7 - 2560, 4)), 1); - if (psEnc.useCBR == 0) { - int b_Q8 = 256 - psEnc.speech_activity_Q8; - b_Q8 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(b_Q8, 8), b_Q8); - SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7, Inlines.silk_SMULBB(-8, b_Q8), Inlines.silk_SMULWB(16384 + psEncCtrl.input_quality_Q14, psEncCtrl.coding_quality_Q14)); - } - SNR_adj_dB_Q7 = psEnc.indices.signalType == 2 ? Inlines.silk_SMLAWB(SNR_adj_dB_Q7, 512, psEnc.LTPCorr_Q15) : Inlines.silk_SMLAWB(SNR_adj_dB_Q7, Inlines.silk_SMLAWB(3072, -104858, psEnc.SNR_dB_Q7), 16384 - psEncCtrl.input_quality_Q14); - if (psEnc.indices.signalType == 2) { - psEnc.indices.quantOffsetType = 0; - psEncCtrl.sparseness_Q8 = 0; - } else { - int nSamples = Inlines.silk_LSHIFT(psEnc.fs_kHz, 1); - int energy_variation_Q7 = 0; - int log_energy_prev_Q7 = 0; - int pitch_res_ptr2 = pitch_res_ptr; - BoxedValueInt boxed_nrg = new BoxedValueInt(0); - BoxedValueInt boxed_scale = new BoxedValueInt(0); - for (k = 0; k < Inlines.silk_SMULBB(5, psEnc.nb_subfr) / 2; ++k) { - SumSqrShift.silk_sum_sqr_shift(boxed_nrg, boxed_scale, pitch_res, pitch_res_ptr2, nSamples); - nrg = boxed_nrg.Val; - scale = boxed_scale.Val; - int log_energy_Q7 = Inlines.silk_lin2log(nrg += Inlines.silk_RSHIFT(nSamples, scale)); - if (k > 0) { - energy_variation_Q7 += Inlines.silk_abs(log_energy_Q7 - log_energy_prev_Q7); - } - log_energy_prev_Q7 = log_energy_Q7; - pitch_res_ptr2 += nSamples; - } - psEncCtrl.sparseness_Q8 = Inlines.silk_RSHIFT(Sigmoid.silk_sigm_Q15(Inlines.silk_SMULWB(energy_variation_Q7 - 640, 6554)), 7); - psEnc.indices.quantOffsetType = psEncCtrl.sparseness_Q8 > 192 ? (byte)0 : 1; - SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7, 65536, psEncCtrl.sparseness_Q8 - 128); - } - int strength_Q16 = Inlines.silk_SMULWB(psEncCtrl.predGain_Q16, 66); - int BWExp1_Q16 = BWExp2_Q16 = Inlines.silk_DIV32_varQ(62259, Inlines.silk_SMLAWW(65536, strength_Q16, strength_Q16), 16); - int delta_Q16 = Inlines.silk_SMULWB(65536 - Inlines.silk_SMULBB(3, psEncCtrl.coding_quality_Q14), 655); - BWExp1_Q16 = Inlines.silk_SUB32(BWExp1_Q16, delta_Q16); - BWExp2_Q16 = Inlines.silk_ADD32(BWExp2_Q16, delta_Q16); - BWExp1_Q16 = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(BWExp1_Q16, 14), Inlines.silk_RSHIFT(BWExp2_Q16, 2)); - int warping_Q16 = psEnc.warping_Q16 > 0 ? Inlines.silk_SMLAWB(psEnc.warping_Q16, psEncCtrl.coding_quality_Q14, 2621) : 0; - short[] x_windowed = new short[psEnc.shapeWinLength]; - for (k = 0; k < psEnc.nb_subfr; ++k) { - int flat_part = psEnc.fs_kHz * 3; - int slope_part = Inlines.silk_RSHIFT(psEnc.shapeWinLength - flat_part, 1); - ApplySineWindow.silk_apply_sine_window(x_windowed, 0, x, x_ptr2, 1, slope_part); - int shift = slope_part; - System.arraycopy(x, x_ptr2 + shift, x_windowed, shift, flat_part); - ApplySineWindow.silk_apply_sine_window(x_windowed, shift += flat_part, x, x_ptr2 + shift, 2, slope_part); - x_ptr2 += psEnc.subfr_length; - BoxedValueInt scale_boxed = new BoxedValueInt(scale); - if (psEnc.warping_Q16 > 0) { - Autocorrelation.silk_warped_autocorrelation(auto_corr, scale_boxed, x_windowed, warping_Q16, psEnc.shapeWinLength, psEnc.shapingLPCOrder); - } else { - Autocorrelation.silk_autocorr(auto_corr, scale_boxed, x_windowed, psEnc.shapeWinLength, psEnc.shapingLPCOrder + 1); - } - scale = scale_boxed.Val; - auto_corr[0] = Inlines.silk_ADD32(auto_corr[0], Inlines.silk_max_32(Inlines.silk_SMULWB(Inlines.silk_RSHIFT(auto_corr[0], 4), 52), 1)); - nrg = Schur.silk_schur64(refl_coef_Q16, auto_corr, psEnc.shapingLPCOrder); - Inlines.OpusAssert(nrg >= 0); - K2A.silk_k2a_Q16(AR2_Q24, refl_coef_Q16, psEnc.shapingLPCOrder); - int Qnrg = -scale; - Inlines.OpusAssert(Qnrg >= -12); - Inlines.OpusAssert(Qnrg <= 30); - if ((Qnrg & 1) != 0) { - --Qnrg; - nrg >>= 1; - } - int tmp32 = Inlines.silk_SQRT_APPROX(nrg); - psEncCtrl.Gains_Q16[k] = Inlines.silk_LSHIFT_SAT32(tmp32, 16 - (Qnrg >>= 1)); - if (psEnc.warping_Q16 > 0) { - gain_mult_Q16 = NoiseShapeAnalysis.warped_gain(AR2_Q24, warping_Q16, psEnc.shapingLPCOrder); - Inlines.OpusAssert(psEncCtrl.Gains_Q16[k] >= 0); - psEncCtrl.Gains_Q16[k] = Inlines.silk_SMULWW(Inlines.silk_RSHIFT_ROUND(psEncCtrl.Gains_Q16[k], 1), gain_mult_Q16) >= 0x3FFFFFFF ? Integer.MAX_VALUE : Inlines.silk_SMULWW(psEncCtrl.Gains_Q16[k], gain_mult_Q16); - } - BWExpander.silk_bwexpander_32(AR2_Q24, psEnc.shapingLPCOrder, BWExp2_Q16); - System.arraycopy(AR2_Q24, 0, AR1_Q24, 0, psEnc.shapingLPCOrder); - Inlines.OpusAssert(BWExp1_Q16 <= 65536); - BWExpander.silk_bwexpander_32(AR1_Q24, psEnc.shapingLPCOrder, BWExp1_Q16); - int pre_nrg_Q30 = LPCInversePredGain.silk_LPC_inverse_pred_gain_Q24(AR2_Q24, psEnc.shapingLPCOrder); - nrg = LPCInversePredGain.silk_LPC_inverse_pred_gain_Q24(AR1_Q24, psEnc.shapingLPCOrder); - pre_nrg_Q30 = Inlines.silk_LSHIFT32(Inlines.silk_SMULWB(pre_nrg_Q30, 22938), 1); - psEncCtrl.GainsPre_Q14[k] = 4915 + Inlines.silk_DIV32_varQ(pre_nrg_Q30, nrg, 14); - NoiseShapeAnalysis.limit_warped_coefs(AR2_Q24, AR1_Q24, warping_Q16, 67092088, psEnc.shapingLPCOrder); - for (int i = 0; i < psEnc.shapingLPCOrder; ++i) { - psEncCtrl.AR1_Q13[k * 16 + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(AR1_Q24[i], 11)); - psEncCtrl.AR2_Q13[k * 16 + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(AR2_Q24[i], 11)); - } - } - gain_mult_Q16 = Inlines.silk_log2lin(-Inlines.silk_SMLAWB(-2048, SNR_adj_dB_Q7, 10486)); - int gain_add_Q16 = Inlines.silk_log2lin(Inlines.silk_SMLAWB(2048, 256, 10486)); - Inlines.OpusAssert(gain_mult_Q16 > 0); - for (k = 0; k < psEnc.nb_subfr; ++k) { - psEncCtrl.Gains_Q16[k] = Inlines.silk_SMULWW(psEncCtrl.Gains_Q16[k], gain_mult_Q16); - Inlines.OpusAssert(psEncCtrl.Gains_Q16[k] >= 0); - psEncCtrl.Gains_Q16[k] = Inlines.silk_ADD_POS_SAT32(psEncCtrl.Gains_Q16[k], gain_add_Q16); - } - gain_mult_Q16 = 65536 + Inlines.silk_RSHIFT_ROUND(Inlines.silk_MLA(0x333333, psEncCtrl.coding_quality_Q14, 410), 10); - for (k = 0; k < psEnc.nb_subfr; ++k) { - psEncCtrl.GainsPre_Q14[k] = Inlines.silk_SMULWB(gain_mult_Q16, psEncCtrl.GainsPre_Q14[k]); - } - strength_Q16 = Inlines.silk_MUL(64, Inlines.silk_SMLAWB(4096, 4096, psEnc.input_quality_bands_Q15[0] - 32768)); - strength_Q16 = Inlines.silk_RSHIFT(Inlines.silk_MUL(strength_Q16, psEnc.speech_activity_Q8), 8); - if (psEnc.indices.signalType == 2) { - int fs_kHz_inv = Inlines.silk_DIV32_16(3277, psEnc.fs_kHz); - k = 0; - while (k < psEnc.nb_subfr) { - b_Q14 = fs_kHz_inv + Inlines.silk_DIV32_16(49152, psEncCtrl.pitchL[k]); - psEncCtrl.LF_shp_Q14[k] = Inlines.silk_LSHIFT(16384 - b_Q14 - Inlines.silk_SMULWB(strength_Q16, b_Q14), 16); - int n = k++; - psEncCtrl.LF_shp_Q14[n] = psEncCtrl.LF_shp_Q14[n] | b_Q14 - 16384 & 0xFFFF; - } - Inlines.OpusAssert(true); - Tilt_Q16 = -16384 - Inlines.silk_SMULWB(49152, Inlines.silk_SMULWB(0x59999A, psEnc.speech_activity_Q8)); - } else { - b_Q14 = Inlines.silk_DIV32_16(21299, psEnc.fs_kHz); - psEncCtrl.LF_shp_Q14[0] = Inlines.silk_LSHIFT(16384 - b_Q14 - Inlines.silk_SMULWB(strength_Q16, Inlines.silk_SMULWB(39322, b_Q14)), 16); - psEncCtrl.LF_shp_Q14[0] = psEncCtrl.LF_shp_Q14[0] | b_Q14 - 16384 & 0xFFFF; - for (k = 1; k < psEnc.nb_subfr; ++k) { - psEncCtrl.LF_shp_Q14[k] = psEncCtrl.LF_shp_Q14[0]; - } - Tilt_Q16 = -16384; - } - int HarmBoost_Q16 = Inlines.silk_SMULWB(Inlines.silk_SMULWB(131072 - Inlines.silk_LSHIFT(psEncCtrl.coding_quality_Q14, 3), psEnc.LTPCorr_Q15), 6554); - HarmBoost_Q16 = Inlines.silk_SMLAWB(HarmBoost_Q16, 65536 - Inlines.silk_LSHIFT(psEncCtrl.input_quality_Q14, 2), 6554); - if (psEnc.indices.signalType == 2) { - HarmShapeGain_Q16 = Inlines.silk_SMLAWB(19661, 65536 - Inlines.silk_SMULWB(262144 - Inlines.silk_LSHIFT(psEncCtrl.coding_quality_Q14, 4), psEncCtrl.input_quality_Q14), 13107); - HarmShapeGain_Q16 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(HarmShapeGain_Q16, 1), Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT(psEnc.LTPCorr_Q15, 15))); - } else { - HarmShapeGain_Q16 = 0; - } - for (k = 0; k < 4; ++k) { - psShapeSt.HarmBoost_smth_Q16 = Inlines.silk_SMLAWB(psShapeSt.HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt.HarmBoost_smth_Q16, 26214); - psShapeSt.HarmShapeGain_smth_Q16 = Inlines.silk_SMLAWB(psShapeSt.HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt.HarmShapeGain_smth_Q16, 26214); - psShapeSt.Tilt_smth_Q16 = Inlines.silk_SMLAWB(psShapeSt.Tilt_smth_Q16, Tilt_Q16 - psShapeSt.Tilt_smth_Q16, 26214); - psEncCtrl.HarmBoost_Q14[k] = Inlines.silk_RSHIFT_ROUND(psShapeSt.HarmBoost_smth_Q16, 2); - psEncCtrl.HarmShapeGain_Q14[k] = Inlines.silk_RSHIFT_ROUND(psShapeSt.HarmShapeGain_smth_Q16, 2); - psEncCtrl.Tilt_Q14[k] = Inlines.silk_RSHIFT_ROUND(psShapeSt.Tilt_smth_Q16, 2); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusApplication.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusApplication.java deleted file mode 100644 index 93f9029..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -public enum OpusApplication { - OPUS_APPLICATION_UNIMPLEMENTED, - OPUS_APPLICATION_VOIP, - OPUS_APPLICATION_AUDIO, - OPUS_APPLICATION_RESTRICTED_LOWDELAY; - -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusBandwidth.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusBandwidth.java deleted file mode 100644 index 06e698a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusBandwidth.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -public enum OpusBandwidth { - OPUS_BANDWIDTH_UNKNOWN, - OPUS_BANDWIDTH_AUTO, - OPUS_BANDWIDTH_NARROWBAND, - OPUS_BANDWIDTH_MEDIUMBAND, - OPUS_BANDWIDTH_WIDEBAND, - OPUS_BANDWIDTH_SUPERWIDEBAND, - OPUS_BANDWIDTH_FULLBAND; - -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusBandwidthHelpers.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusBandwidthHelpers.java deleted file mode 100644 index 97002f4..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusBandwidthHelpers.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.OpusBandwidth; - -class OpusBandwidthHelpers { - OpusBandwidthHelpers() { - } - - static int GetOrdinal(OpusBandwidth bw) { - switch (bw) { - case OPUS_BANDWIDTH_NARROWBAND: { - return 1; - } - case OPUS_BANDWIDTH_MEDIUMBAND: { - return 2; - } - case OPUS_BANDWIDTH_WIDEBAND: { - return 3; - } - case OPUS_BANDWIDTH_SUPERWIDEBAND: { - return 4; - } - case OPUS_BANDWIDTH_FULLBAND: { - return 5; - } - } - return -1; - } - - static OpusBandwidth GetBandwidth(int ordinal) { - switch (ordinal) { - case 1: { - return OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; - } - case 2: { - return OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND; - } - case 3: { - return OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; - } - case 4: { - return OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND; - } - case 5: { - return OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; - } - } - return OpusBandwidth.OPUS_BANDWIDTH_AUTO; - } - - static OpusBandwidth MIN(OpusBandwidth a, OpusBandwidth b) { - if (OpusBandwidthHelpers.GetOrdinal(a) < OpusBandwidthHelpers.GetOrdinal(b)) { - return a; - } - return b; - } - - static OpusBandwidth MAX(OpusBandwidth a, OpusBandwidth b) { - if (OpusBandwidthHelpers.GetOrdinal(a) > OpusBandwidthHelpers.GetOrdinal(b)) { - return a; - } - return b; - } - - static OpusBandwidth SUBTRACT(OpusBandwidth a, int b) { - return OpusBandwidthHelpers.GetBandwidth(OpusBandwidthHelpers.GetOrdinal(a) - b); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusConstants.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusConstants.java deleted file mode 100644 index 42ee1b8..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusConstants.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -public class OpusConstants { - public static final int OPUS_AUTO = -1000; - public static final int OPUS_BITRATE_MAX = -1; - public static final int NB_FRAMES = 8; - public static final int NB_TBANDS = 18; - public static final int NB_TOT_BANDS = 21; - public static final int NB_TONAL_SKIP_BANDS = 9; - public static final int ANALYSIS_BUF_SIZE = 720; - public static final int DETECT_SIZE = 200; - public static final int MAX_ENCODER_BUFFER = 480; -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusDecoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusDecoder.java deleted file mode 100644 index 61c1960..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusDecoder.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltDecoder; -import de.maxhenkel.voicechat.concentus.CodecHelpers; -import de.maxhenkel.voicechat.concentus.DecControlState; -import de.maxhenkel.voicechat.concentus.DecodeAPI; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.OpusBandwidth; -import de.maxhenkel.voicechat.concentus.OpusError; -import de.maxhenkel.voicechat.concentus.OpusException; -import de.maxhenkel.voicechat.concentus.OpusMode; -import de.maxhenkel.voicechat.concentus.OpusPacketInfo; -import de.maxhenkel.voicechat.concentus.SilkDecoder; - -public class OpusDecoder { - int channels; - int Fs; - final DecControlState DecControl = new DecControlState(); - int decode_gain; - int stream_channels; - OpusBandwidth bandwidth; - OpusMode mode; - OpusMode prev_mode; - int frame_size; - int prev_redundancy; - int last_packet_duration; - int rangeFinal; - SilkDecoder SilkDecoder = new SilkDecoder(); - CeltDecoder Celt_Decoder = new CeltDecoder(); - private static final byte[] SILENCE = new byte[]{-1, -1}; - - OpusDecoder() { - } - - void reset() { - this.channels = 0; - this.Fs = 0; - this.DecControl.Reset(); - this.decode_gain = 0; - this.partialReset(); - } - - void partialReset() { - this.stream_channels = 0; - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN; - this.mode = OpusMode.MODE_UNKNOWN; - this.prev_mode = OpusMode.MODE_UNKNOWN; - this.frame_size = 0; - this.prev_redundancy = 0; - this.last_packet_duration = 0; - this.rangeFinal = 0; - } - - int opus_decoder_init(int Fs, int channels) { - if (Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000 || channels != 1 && channels != 2) { - return OpusError.OPUS_BAD_ARG; - } - this.reset(); - SilkDecoder silk_dec = this.SilkDecoder; - CeltDecoder celt_dec = this.Celt_Decoder; - this.stream_channels = this.channels = channels; - this.DecControl.API_sampleRate = this.Fs = Fs; - this.DecControl.nChannelsAPI = this.channels; - int ret = DecodeAPI.silk_InitDecoder(silk_dec); - if (ret != 0) { - return OpusError.OPUS_INTERNAL_ERROR; - } - ret = celt_dec.celt_decoder_init(Fs, channels); - if (ret != OpusError.OPUS_OK) { - return OpusError.OPUS_INTERNAL_ERROR; - } - celt_dec.SetSignalling(0); - this.prev_mode = OpusMode.MODE_UNKNOWN; - this.frame_size = Fs / 400; - return OpusError.OPUS_OK; - } - - public OpusDecoder(int Fs, int channels) throws OpusException { - if (Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000) { - throw new IllegalArgumentException("Sample rate is invalid (must be 8/12/16/24/48 Khz)"); - } - if (channels != 1 && channels != 2) { - throw new IllegalArgumentException("Number of channels must be 1 or 2"); - } - int ret = this.opus_decoder_init(Fs, channels); - if (ret != OpusError.OPUS_OK) { - if (ret == OpusError.OPUS_BAD_ARG) { - throw new IllegalArgumentException("OPUS_BAD_ARG when creating decoder"); - } - throw new OpusException("Error while initializing decoder", ret); - } - } - - int opus_decode_frame(byte[] data, int data_ptr, int len, short[] pcm, int pcm_ptr, int frame_size, int decode_fec) { - int i; - OpusMode mode; - int audiosize; - int silk_ret = 0; - int celt_ret = 0; - EntropyCoder dec = new EntropyCoder(); - short[] pcm_transition = null; - boolean transition = false; - int redundancy = 0; - int redundancy_bytes = 0; - int celt_to_silk = 0; - int redundant_rng = 0; - SilkDecoder silk_dec = this.SilkDecoder; - CeltDecoder celt_dec = this.Celt_Decoder; - int F20 = this.Fs / 50; - int F10 = F20 >> 1; - int F5 = F10 >> 1; - int F2_5 = F5 >> 1; - if (frame_size < F2_5) { - return OpusError.OPUS_BUFFER_TOO_SMALL; - } - frame_size = Inlines.IMIN(frame_size, this.Fs / 25 * 3); - if (len <= 1) { - data = null; - frame_size = Inlines.IMIN(frame_size, this.frame_size); - } - if (data != null) { - audiosize = this.frame_size; - mode = this.mode; - dec.dec_init(data, data_ptr, len); - } else { - audiosize = frame_size; - mode = this.prev_mode; - if (mode == OpusMode.MODE_UNKNOWN) { - for (int i2 = pcm_ptr; i2 < pcm_ptr + audiosize * this.channels; ++i2) { - pcm[i2] = 0; - } - return audiosize; - } - if (audiosize > F20) { - int ret; - do { - if ((ret = this.opus_decode_frame(null, 0, 0, pcm, pcm_ptr, Inlines.IMIN(audiosize, F20), 0)) < 0) { - return ret; - } - pcm_ptr += ret * this.channels; - } while ((audiosize -= ret) > 0); - return frame_size; - } - if (audiosize < F20) { - if (audiosize > F10) { - audiosize = F10; - } else if (mode != OpusMode.MODE_SILK_ONLY && audiosize > F5 && audiosize < F10) { - audiosize = F5; - } - } - } - int celt_accum = mode != OpusMode.MODE_CELT_ONLY && frame_size >= F10 ? 1 : 0; - int pcm_transition_silk_size = 0; - int pcm_transition_celt_size = 0; - if (data != null && this.prev_mode != OpusMode.MODE_UNKNOWN && this.prev_mode != OpusMode.MODE_AUTO && (mode == OpusMode.MODE_CELT_ONLY && this.prev_mode != OpusMode.MODE_CELT_ONLY && this.prev_redundancy == 0 || mode != OpusMode.MODE_CELT_ONLY && this.prev_mode == OpusMode.MODE_CELT_ONLY)) { - transition = true; - if (mode == OpusMode.MODE_CELT_ONLY) { - pcm_transition_celt_size = F5 * this.channels; - } else { - pcm_transition_silk_size = F5 * this.channels; - } - } - short[] pcm_transition_celt = new short[pcm_transition_celt_size]; - if (transition && mode == OpusMode.MODE_CELT_ONLY) { - pcm_transition = pcm_transition_celt; - this.opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0); - } - if (audiosize > frame_size) { - return OpusError.OPUS_BAD_ARG; - } - frame_size = audiosize; - int pcm_silk_size = mode != OpusMode.MODE_CELT_ONLY && celt_accum == 0 ? Inlines.IMAX(F10, frame_size) * this.channels : 0; - short[] pcm_silk = new short[pcm_silk_size]; - if (mode != OpusMode.MODE_CELT_ONLY) { - int silk_frame_size; - short[] pcm_ptr2; - int pcm_ptr2_ptr = 0; - if (celt_accum != 0) { - pcm_ptr2 = pcm; - pcm_ptr2_ptr = pcm_ptr; - } else { - pcm_ptr2 = pcm_silk; - pcm_ptr2_ptr = 0; - } - if (this.prev_mode == OpusMode.MODE_CELT_ONLY) { - DecodeAPI.silk_InitDecoder(silk_dec); - } - this.DecControl.payloadSize_ms = Inlines.IMAX(10, 1000 * audiosize / this.Fs); - if (data != null) { - this.DecControl.nChannelsInternal = this.stream_channels; - if (mode == OpusMode.MODE_SILK_ONLY) { - if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { - this.DecControl.internalSampleRate = 8000; - } else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { - this.DecControl.internalSampleRate = 12000; - } else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) { - this.DecControl.internalSampleRate = 16000; - } else { - this.DecControl.internalSampleRate = 16000; - Inlines.OpusAssert(false); - } - } else { - this.DecControl.internalSampleRate = 16000; - } - } - int lost_flag = data == null ? 1 : 2 * decode_fec; - int decoded_samples = 0; - do { - int first_frame = decoded_samples == 0 ? 1 : 0; - BoxedValueInt boxed_silk_frame_size = new BoxedValueInt(0); - silk_ret = DecodeAPI.silk_Decode(silk_dec, this.DecControl, lost_flag, first_frame, dec, pcm_ptr2, pcm_ptr2_ptr, boxed_silk_frame_size); - silk_frame_size = boxed_silk_frame_size.Val; - if (silk_ret != 0) { - if (lost_flag != 0) { - silk_frame_size = frame_size; - Arrays.MemSetWithOffset(pcm_ptr2, (short)0, pcm_ptr2_ptr, frame_size * this.channels); - } else { - return OpusError.OPUS_INTERNAL_ERROR; - } - } - pcm_ptr2_ptr += silk_frame_size * this.channels; - } while ((decoded_samples += silk_frame_size) < frame_size); - } - int start_band = 0; - if (decode_fec == 0 && mode != OpusMode.MODE_CELT_ONLY && data != null && dec.tell() + 17 + 20 * (this.mode == OpusMode.MODE_HYBRID ? 1 : 0) <= 8 * len && (redundancy = mode == OpusMode.MODE_HYBRID ? dec.dec_bit_logp(12L) : 1) != 0) { - celt_to_silk = dec.dec_bit_logp(1L); - int n = redundancy_bytes = mode == OpusMode.MODE_HYBRID ? (int)dec.dec_uint(256L) + 2 : len - (dec.tell() + 7 >> 3); - if ((len -= redundancy_bytes) * 8 < dec.tell()) { - len = 0; - redundancy_bytes = 0; - redundancy = 0; - } - dec.storage -= redundancy_bytes; - } - if (mode != OpusMode.MODE_CELT_ONLY) { - start_band = 17; - } - int endband = 21; - switch (this.bandwidth) { - case OPUS_BANDWIDTH_NARROWBAND: { - endband = 13; - break; - } - case OPUS_BANDWIDTH_MEDIUMBAND: - case OPUS_BANDWIDTH_WIDEBAND: { - endband = 17; - break; - } - case OPUS_BANDWIDTH_SUPERWIDEBAND: { - endband = 19; - break; - } - case OPUS_BANDWIDTH_FULLBAND: { - endband = 21; - } - } - celt_dec.SetEndBand(endband); - celt_dec.SetChannels(this.stream_channels); - if (redundancy != 0) { - transition = false; - pcm_transition_silk_size = 0; - } - short[] pcm_transition_silk = new short[pcm_transition_silk_size]; - if (transition && mode != OpusMode.MODE_CELT_ONLY) { - pcm_transition = pcm_transition_silk; - this.opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0); - } - int redundant_audio_size = redundancy != 0 ? F5 * this.channels : 0; - short[] redundant_audio = new short[redundant_audio_size]; - if (redundancy != 0 && celt_to_silk != 0) { - celt_dec.SetStartBand(0); - celt_dec.celt_decode_with_ec(data, data_ptr + len, redundancy_bytes, redundant_audio, 0, F5, null, 0); - redundant_rng = celt_dec.GetFinalRange(); - } - celt_dec.SetStartBand(start_band); - if (mode != OpusMode.MODE_SILK_ONLY) { - int celt_frame_size = Inlines.IMIN(F20, frame_size); - if (mode != this.prev_mode && this.prev_mode != OpusMode.MODE_AUTO && this.prev_mode != OpusMode.MODE_UNKNOWN && this.prev_redundancy == 0) { - celt_dec.ResetState(); - } - celt_ret = celt_dec.celt_decode_with_ec(decode_fec != 0 ? null : data, data_ptr, len, pcm, pcm_ptr, celt_frame_size, dec, celt_accum); - } else { - if (celt_accum == 0) { - for (i = pcm_ptr; i < frame_size * this.channels + pcm_ptr; ++i) { - pcm[i] = 0; - } - } - if (this.prev_mode == OpusMode.MODE_HYBRID && (redundancy == 0 || celt_to_silk == 0 || this.prev_redundancy == 0)) { - celt_dec.SetStartBand(0); - celt_dec.celt_decode_with_ec(SILENCE, 0, 2, pcm, pcm_ptr, F2_5, null, celt_accum); - } - } - if (mode != OpusMode.MODE_CELT_ONLY && celt_accum == 0) { - for (i = 0; i < frame_size * this.channels; ++i) { - pcm[pcm_ptr + i] = Inlines.SAT16(Inlines.ADD32(pcm[pcm_ptr + i], pcm_silk[i])); - } - } - int[] window = celt_dec.GetMode().window; - if (redundancy != 0 && celt_to_silk == 0) { - celt_dec.ResetState(); - celt_dec.SetStartBand(0); - celt_dec.celt_decode_with_ec(data, data_ptr + len, redundancy_bytes, redundant_audio, 0, F5, null, 0); - redundant_rng = celt_dec.GetFinalRange(); - CodecHelpers.smooth_fade(pcm, pcm_ptr + this.channels * (frame_size - F2_5), redundant_audio, this.channels * F2_5, pcm, pcm_ptr + this.channels * (frame_size - F2_5), F2_5, this.channels, window, this.Fs); - } - if (redundancy != 0 && celt_to_silk != 0) { - for (int c = 0; c < this.channels; ++c) { - for (i = 0; i < F2_5; ++i) { - pcm[this.channels * i + c + pcm_ptr] = redundant_audio[this.channels * i + c]; - } - } - CodecHelpers.smooth_fade(redundant_audio, this.channels * F2_5, pcm, pcm_ptr + this.channels * F2_5, pcm, pcm_ptr + this.channels * F2_5, F2_5, this.channels, window, this.Fs); - } - if (transition) { - if (audiosize >= F5) { - for (i = 0; i < this.channels * F2_5; ++i) { - pcm[i] = pcm_transition[i]; - } - CodecHelpers.smooth_fade(pcm_transition, this.channels * F2_5, pcm, pcm_ptr + this.channels * F2_5, pcm, pcm_ptr + this.channels * F2_5, F2_5, this.channels, window, this.Fs); - } else { - CodecHelpers.smooth_fade(pcm_transition, 0, pcm, pcm_ptr, pcm, pcm_ptr, F2_5, this.channels, window, this.Fs); - } - } - if (this.decode_gain != 0) { - int gain = Inlines.celt_exp2(Inlines.MULT16_16_P15(21771, this.decode_gain)); - for (i = pcm_ptr; i < pcm_ptr + frame_size * this.channels; ++i) { - int x = Inlines.MULT16_32_P16(pcm[i], gain); - pcm[i] = (short)Inlines.SATURATE(x, Short.MAX_VALUE); - } - } - this.rangeFinal = len <= 1 ? 0 : (int)dec.rng ^ redundant_rng; - this.prev_mode = mode; - this.prev_redundancy = redundancy != 0 && celt_to_silk == 0 ? 1 : 0; - return celt_ret < 0 ? celt_ret : audiosize; - } - - int opus_decode_native(byte[] data, int data_ptr, int len, short[] pcm_out, int pcm_out_ptr, int frame_size, int decode_fec, int self_delimited, BoxedValueInt packet_offset, int soft_clip) { - packet_offset.Val = 0; - short[] size = new short[48]; - if (decode_fec < 0 || decode_fec > 1) { - return OpusError.OPUS_BAD_ARG; - } - if ((decode_fec != 0 || len == 0 || data == null) && frame_size % (this.Fs / 400) != 0) { - return OpusError.OPUS_BAD_ARG; - } - if (len == 0 || data == null) { - int ret; - int pcm_count = 0; - do { - if ((ret = this.opus_decode_frame(null, 0, 0, pcm_out, pcm_out_ptr + pcm_count * this.channels, frame_size - pcm_count, 0)) >= 0) continue; - return ret; - } while ((pcm_count += ret) < frame_size); - Inlines.OpusAssert(pcm_count == frame_size); - this.last_packet_duration = pcm_count; - return pcm_count; - } - if (len < 0) { - return OpusError.OPUS_BAD_ARG; - } - OpusMode packet_mode = OpusPacketInfo.getEncoderMode(data, data_ptr); - OpusBandwidth packet_bandwidth = OpusPacketInfo.getBandwidth(data, data_ptr); - int packet_frame_size = OpusPacketInfo.getNumSamplesPerFrame(data, data_ptr, this.Fs); - int packet_stream_channels = OpusPacketInfo.getNumEncodedChannels(data, data_ptr); - BoxedValueByte boxed_toc = new BoxedValueByte(0); - BoxedValueInt boxed_offset = new BoxedValueInt(0); - int count = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, boxed_toc, null, 0, size, 0, boxed_offset, packet_offset); - int offset = boxed_offset.Val; - if (count < 0) { - return count; - } - data_ptr += offset; - if (decode_fec != 0) { - int ret; - BoxedValueInt dummy = new BoxedValueInt(0); - if (frame_size < packet_frame_size || packet_mode == OpusMode.MODE_CELT_ONLY || this.mode == OpusMode.MODE_CELT_ONLY) { - return this.opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size, 0, 0, dummy, soft_clip); - } - int duration_copy = this.last_packet_duration; - if (frame_size - packet_frame_size != 0) { - ret = this.opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size - packet_frame_size, 0, 0, dummy, soft_clip); - if (ret < 0) { - this.last_packet_duration = duration_copy; - return ret; - } - Inlines.OpusAssert(ret == frame_size - packet_frame_size); - } - this.mode = packet_mode; - this.bandwidth = packet_bandwidth; - this.frame_size = packet_frame_size; - this.stream_channels = packet_stream_channels; - ret = this.opus_decode_frame(data, data_ptr, size[0], pcm_out, pcm_out_ptr + this.channels * (frame_size - packet_frame_size), packet_frame_size, 1); - if (ret < 0) { - return ret; - } - this.last_packet_duration = frame_size; - return frame_size; - } - if (count * packet_frame_size > frame_size) { - return OpusError.OPUS_BUFFER_TOO_SMALL; - } - this.mode = packet_mode; - this.bandwidth = packet_bandwidth; - this.frame_size = packet_frame_size; - this.stream_channels = packet_stream_channels; - int nb_samples = 0; - for (int i = 0; i < count; ++i) { - int ret = this.opus_decode_frame(data, data_ptr, size[i], pcm_out, pcm_out_ptr + nb_samples * this.channels, frame_size - nb_samples, 0); - if (ret < 0) { - return ret; - } - Inlines.OpusAssert(ret == packet_frame_size); - data_ptr += size[i]; - nb_samples += ret; - } - this.last_packet_duration = nb_samples; - return nb_samples; - } - - public int decode(byte[] in_data, int in_data_offset, int len, short[] out_pcm, int out_pcm_offset, int frame_size, boolean decode_fec) throws OpusException { - if (frame_size <= 0) { - throw new IllegalArgumentException("Frame size must be > 0"); - } - try { - BoxedValueInt dummy = new BoxedValueInt(0); - int ret = this.opus_decode_native(in_data, in_data_offset, len, out_pcm, out_pcm_offset, frame_size, decode_fec ? 1 : 0, 0, dummy, 0); - if (ret < 0) { - if (ret == OpusError.OPUS_BAD_ARG) { - throw new IllegalArgumentException("OPUS_BAD_ARG while decoding"); - } - throw new OpusException("An error occurred during decoding", ret); - } - return ret; - } - catch (ArithmeticException e) { - throw new OpusException("Internal error during decoding: " + e.getMessage()); - } - } - - public int decode(byte[] in_data, int in_data_offset, int len, byte[] out_pcm, int out_pcm_offset, int frame_size, boolean decode_fec) throws OpusException { - short[] spcm = new short[Math.min(frame_size, 5760) * this.channels]; - int decSamples = this.decode(in_data, in_data_offset, len, spcm, 0, frame_size, decode_fec); - int idx = out_pcm_offset; - for (int c = 0; c < spcm.length; ++c) { - out_pcm[idx++] = (byte)(spcm[c] & 0xFF); - out_pcm[idx++] = (byte)(spcm[c] >> 8 & 0xFF); - } - return decSamples; - } - - public OpusBandwidth getBandwidth() { - return this.bandwidth; - } - - public int getFinalRange() { - return this.rangeFinal; - } - - public int getSampleRate() { - return this.Fs; - } - - public int getPitch() { - if (this.prev_mode == OpusMode.MODE_CELT_ONLY) { - return this.Celt_Decoder.GetPitch(); - } - return this.DecControl.prevPitchLag; - } - - public int getGain() { - return this.decode_gain; - } - - public void setGain(int value) { - if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { - throw new IllegalArgumentException("Gain must be within the range of a signed int16"); - } - this.decode_gain = value; - } - - public int getLastPacketDuration() { - return this.last_packet_duration; - } - - public void resetState() { - this.partialReset(); - this.Celt_Decoder.ResetState(); - DecodeAPI.silk_InitDecoder(this.SilkDecoder); - this.stream_channels = this.channels; - this.frame_size = this.Fs / 400; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusEncoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusEncoder.java deleted file mode 100644 index 4f7edc8..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusEncoder.java +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Analysis; -import de.maxhenkel.voicechat.concentus.AnalysisInfo; -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltEncoder; -import de.maxhenkel.voicechat.concentus.CeltMode; -import de.maxhenkel.voicechat.concentus.CodecHelpers; -import de.maxhenkel.voicechat.concentus.EncControlState; -import de.maxhenkel.voicechat.concentus.EncodeAPI; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.OpusApplication; -import de.maxhenkel.voicechat.concentus.OpusBandwidth; -import de.maxhenkel.voicechat.concentus.OpusBandwidthHelpers; -import de.maxhenkel.voicechat.concentus.OpusError; -import de.maxhenkel.voicechat.concentus.OpusException; -import de.maxhenkel.voicechat.concentus.OpusFramesize; -import de.maxhenkel.voicechat.concentus.OpusMode; -import de.maxhenkel.voicechat.concentus.OpusRepacketizer; -import de.maxhenkel.voicechat.concentus.OpusSignal; -import de.maxhenkel.voicechat.concentus.OpusTables; -import de.maxhenkel.voicechat.concentus.SilkEncoder; -import de.maxhenkel.voicechat.concentus.StereoWidthState; -import de.maxhenkel.voicechat.concentus.TonalityAnalysisState; - -public class OpusEncoder { - final EncControlState silk_mode = new EncControlState(); - OpusApplication application; - int channels; - int delay_compensation; - int force_channels; - OpusSignal signal_type; - OpusBandwidth user_bandwidth; - OpusBandwidth max_bandwidth; - OpusMode user_forced_mode; - int voice_ratio; - int Fs; - int use_vbr; - int vbr_constraint; - OpusFramesize variable_duration; - int bitrate_bps; - int user_bitrate_bps; - int lsb_depth; - int encoder_buffer; - int lfe; - final TonalityAnalysisState analysis = new TonalityAnalysisState(); - int stream_channels; - short hybrid_stereo_width_Q14; - int variable_HP_smth2_Q15; - int prev_HB_gain; - final int[] hp_mem = new int[4]; - OpusMode mode; - OpusMode prev_mode; - int prev_channels; - int prev_framesize; - OpusBandwidth bandwidth; - int silk_bw_switch; - int first; - int[] energy_masking; - final StereoWidthState width_mem = new StereoWidthState(); - final short[] delay_buffer = new short[960]; - OpusBandwidth detected_bandwidth; - int rangeFinal; - final SilkEncoder SilkEncoder = new SilkEncoder(); - final CeltEncoder Celt_Encoder = new CeltEncoder(); - - OpusEncoder() { - } - - void reset() { - this.silk_mode.Reset(); - this.application = OpusApplication.OPUS_APPLICATION_UNIMPLEMENTED; - this.channels = 0; - this.delay_compensation = 0; - this.force_channels = 0; - this.signal_type = OpusSignal.OPUS_SIGNAL_UNKNOWN; - this.user_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN; - this.max_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN; - this.user_forced_mode = OpusMode.MODE_UNKNOWN; - this.voice_ratio = 0; - this.Fs = 0; - this.use_vbr = 0; - this.vbr_constraint = 0; - this.variable_duration = OpusFramesize.OPUS_FRAMESIZE_UNKNOWN; - this.bitrate_bps = 0; - this.user_bitrate_bps = 0; - this.lsb_depth = 0; - this.encoder_buffer = 0; - this.lfe = 0; - this.analysis.Reset(); - this.PartialReset(); - } - - void PartialReset() { - this.stream_channels = 0; - this.hybrid_stereo_width_Q14 = 0; - this.variable_HP_smth2_Q15 = 0; - this.prev_HB_gain = 0; - Arrays.MemSet(this.hp_mem, 0, 4); - this.mode = OpusMode.MODE_UNKNOWN; - this.prev_mode = OpusMode.MODE_UNKNOWN; - this.prev_channels = 0; - this.prev_framesize = 0; - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN; - this.silk_bw_switch = 0; - this.first = 0; - this.energy_masking = null; - this.width_mem.Reset(); - Arrays.MemSet(this.delay_buffer, (short)0, 960); - this.detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN; - this.rangeFinal = 0; - } - - public void resetState() { - EncControlState dummy = new EncControlState(); - this.analysis.Reset(); - this.PartialReset(); - this.Celt_Encoder.ResetState(); - EncodeAPI.silk_InitEncoder(this.SilkEncoder, dummy); - this.stream_channels = this.channels; - this.hybrid_stereo_width_Q14 = (short)16384; - this.prev_HB_gain = Short.MAX_VALUE; - this.first = 1; - this.mode = OpusMode.MODE_HYBRID; - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; - this.variable_HP_smth2_Q15 = Inlines.silk_LSHIFT(Inlines.silk_lin2log(60), 8); - } - - public OpusEncoder(int Fs, int channels, OpusApplication application) throws OpusException { - if (Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000) { - throw new IllegalArgumentException("Sample rate is invalid (must be 8/12/16/24/48 Khz)"); - } - if (channels != 1 && channels != 2) { - throw new IllegalArgumentException("Number of channels must be 1 or 2"); - } - int ret = this.opus_init_encoder(Fs, channels, application); - if (ret != OpusError.OPUS_OK) { - if (ret == OpusError.OPUS_BAD_ARG) { - throw new IllegalArgumentException("OPUS_BAD_ARG when creating encoder"); - } - throw new OpusException("Error while initializing encoder", ret); - } - } - - int opus_init_encoder(int Fs, int channels, OpusApplication application) { - if (Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000 || channels != 1 && channels != 2 || application == OpusApplication.OPUS_APPLICATION_UNIMPLEMENTED) { - return OpusError.OPUS_BAD_ARG; - } - this.reset(); - SilkEncoder silk_enc = this.SilkEncoder; - CeltEncoder celt_enc = this.Celt_Encoder; - this.stream_channels = this.channels = channels; - this.Fs = Fs; - int ret = EncodeAPI.silk_InitEncoder(silk_enc, this.silk_mode); - if (ret != 0) { - return OpusError.OPUS_INTERNAL_ERROR; - } - this.silk_mode.nChannelsAPI = channels; - this.silk_mode.nChannelsInternal = channels; - this.silk_mode.API_sampleRate = this.Fs; - this.silk_mode.maxInternalSampleRate = 16000; - this.silk_mode.minInternalSampleRate = 8000; - this.silk_mode.desiredInternalSampleRate = 16000; - this.silk_mode.payloadSize_ms = 20; - this.silk_mode.bitRate = 25000; - this.silk_mode.packetLossPercentage = 0; - this.silk_mode.complexity = 9; - this.silk_mode.useInBandFEC = 0; - this.silk_mode.useDTX = 0; - this.silk_mode.useCBR = 0; - this.silk_mode.reducedDependency = 0; - int err = celt_enc.celt_encoder_init(Fs, channels); - if (err != OpusError.OPUS_OK) { - return OpusError.OPUS_INTERNAL_ERROR; - } - celt_enc.SetSignalling(0); - celt_enc.SetComplexity(this.silk_mode.complexity); - this.use_vbr = 1; - this.vbr_constraint = 1; - this.user_bitrate_bps = -1000; - this.bitrate_bps = 3000 + Fs * channels; - this.application = application; - this.signal_type = OpusSignal.OPUS_SIGNAL_AUTO; - this.user_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_AUTO; - this.max_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; - this.force_channels = -1000; - this.user_forced_mode = OpusMode.MODE_AUTO; - this.voice_ratio = -1; - this.encoder_buffer = this.Fs / 100; - this.lsb_depth = 24; - this.variable_duration = OpusFramesize.OPUS_FRAMESIZE_ARG; - this.delay_compensation = this.Fs / 250; - this.hybrid_stereo_width_Q14 = (short)16384; - this.prev_HB_gain = Short.MAX_VALUE; - this.variable_HP_smth2_Q15 = Inlines.silk_LSHIFT(Inlines.silk_lin2log(60), 8); - this.first = 1; - this.mode = OpusMode.MODE_HYBRID; - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; - Analysis.tonality_analysis_init(this.analysis); - return OpusError.OPUS_OK; - } - - int user_bitrate_to_bitrate(int frame_size, int max_data_bytes) { - if (frame_size == 0) { - frame_size = this.Fs / 400; - } - if (this.user_bitrate_bps == -1000) { - return 60 * this.Fs / frame_size + this.Fs * this.channels; - } - if (this.user_bitrate_bps == -1) { - return max_data_bytes * 8 * this.Fs / frame_size; - } - return this.user_bitrate_bps; - } - - int opus_encode_native(short[] pcm, int pcm_ptr, int frame_size, byte[] data, int data_ptr, int out_data_bytes, int lsb_depth, short[] analysis_pcm, int analysis_pcm_ptr, int analysis_size, int c1, int c2, int analysis_channels, int float_api) { - int nb_compr_bytes; - int i; - int voice_est; - int ret = 0; - EntropyCoder enc = new EntropyCoder(); - boolean prefill = false; - int start_band = 0; - int redundancy = 0; - int redundancy_bytes = 0; - int celt_to_silk = 0; - boolean to_celt = false; - int redundant_rng = 0; - AnalysisInfo analysis_info = new AnalysisInfo(); - int analysis_read_pos_bak = -1; - int analysis_read_subframe_bak = -1; - int max_data_bytes = Inlines.IMIN(1276, out_data_bytes); - this.rangeFinal = 0; - if (this.variable_duration == OpusFramesize.OPUS_FRAMESIZE_UNKNOWN && 400 * frame_size != this.Fs && 200 * frame_size != this.Fs && 100 * frame_size != this.Fs && 50 * frame_size != this.Fs && 25 * frame_size != this.Fs && 50 * frame_size != 3 * this.Fs || 400 * frame_size < this.Fs || max_data_bytes <= 0) { - return OpusError.OPUS_BAD_ARG; - } - SilkEncoder silk_enc = this.SilkEncoder; - CeltEncoder celt_enc = this.Celt_Encoder; - int delay_compensation = this.application == OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY ? 0 : this.delay_compensation; - lsb_depth = Inlines.IMIN(lsb_depth, this.lsb_depth); - CeltMode celt_mode = celt_enc.GetMode(); - this.voice_ratio = -1; - if (this.analysis.enabled) { - analysis_info.valid = 0; - if (this.silk_mode.complexity >= 7 && this.Fs == 48000) { - analysis_read_pos_bak = this.analysis.read_pos; - analysis_read_subframe_bak = this.analysis.read_subframe; - Analysis.run_analysis(this.analysis, celt_mode, (short[])(analysis_pcm != null ? analysis_pcm : null), analysis_pcm_ptr, analysis_size, frame_size, c1, c2, analysis_channels, this.Fs, lsb_depth, analysis_info); - } - this.detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN; - if (analysis_info.valid != 0) { - int analysis_bandwidth; - if (this.signal_type == OpusSignal.OPUS_SIGNAL_AUTO) { - this.voice_ratio = (int)Math.floor(0.5f + 100.0f * (1.0f - analysis_info.music_prob)); - } - this.detected_bandwidth = (analysis_bandwidth = analysis_info.bandwidth) <= 12 ? OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND : (analysis_bandwidth <= 14 ? OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND : (analysis_bandwidth <= 16 ? OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND : (analysis_bandwidth <= 18 ? OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND : OpusBandwidth.OPUS_BANDWIDTH_FULLBAND))); - } - } - int stereo_width = this.channels == 2 && this.force_channels != 1 ? CodecHelpers.compute_stereo_width(pcm, pcm_ptr, frame_size, this.Fs, this.width_mem) : 0; - int total_buffer = delay_compensation; - this.bitrate_bps = this.user_bitrate_to_bitrate(frame_size, max_data_bytes); - int frame_rate = this.Fs / frame_size; - if (this.use_vbr == 0) { - int frame_rate3 = 3 * this.Fs / frame_size; - int cbrBytes = Inlines.IMIN((3 * this.bitrate_bps / 8 + frame_rate3 / 2) / frame_rate3, max_data_bytes); - this.bitrate_bps = cbrBytes * frame_rate3 * 8 / 3; - max_data_bytes = cbrBytes; - } - if (max_data_bytes < 3 || this.bitrate_bps < 3 * frame_rate * 8 || frame_rate < 50 && (max_data_bytes * frame_rate < 300 || this.bitrate_bps < 2400)) { - OpusBandwidth bw; - OpusMode tocmode = this.mode; - OpusBandwidth opusBandwidth = bw = this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN ? OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND : this.bandwidth; - if (tocmode == OpusMode.MODE_UNKNOWN) { - tocmode = OpusMode.MODE_SILK_ONLY; - } - if (frame_rate > 100) { - tocmode = OpusMode.MODE_CELT_ONLY; - } - if (frame_rate < 50) { - tocmode = OpusMode.MODE_SILK_ONLY; - } - if (tocmode == OpusMode.MODE_SILK_ONLY && OpusBandwidthHelpers.GetOrdinal(bw) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) { - bw = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; - } else if (tocmode == OpusMode.MODE_CELT_ONLY && OpusBandwidthHelpers.GetOrdinal(bw) == OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND)) { - bw = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; - } else if (tocmode == OpusMode.MODE_HYBRID && OpusBandwidthHelpers.GetOrdinal(bw) <= OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND)) { - bw = OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND; - } - data[data_ptr] = CodecHelpers.gen_toc(tocmode, frame_rate, bw, this.stream_channels); - ret = 1; - if (this.use_vbr == 0 && (ret = OpusRepacketizer.padPacket(data, data_ptr, ret, max_data_bytes)) == OpusError.OPUS_OK) { - ret = max_data_bytes; - } - return ret; - } - int max_rate = frame_rate * max_data_bytes * 8; - int equiv_rate = this.bitrate_bps - (40 * this.channels + 20) * (this.Fs / frame_size - 50); - if (this.signal_type == OpusSignal.OPUS_SIGNAL_VOICE) { - voice_est = 127; - } else if (this.signal_type == OpusSignal.OPUS_SIGNAL_MUSIC) { - voice_est = 0; - } else if (this.voice_ratio >= 0) { - voice_est = this.voice_ratio * 327 >> 8; - if (this.application == OpusApplication.OPUS_APPLICATION_AUDIO) { - voice_est = Inlines.IMIN(voice_est, 115); - } - } else { - voice_est = this.application == OpusApplication.OPUS_APPLICATION_VOIP ? 115 : 48; - } - if (this.force_channels != -1000 && this.channels == 2) { - this.stream_channels = this.force_channels; - } else if (this.channels == 2) { - int stereo_threshold = 30000 + (voice_est * voice_est * 0 >> 14); - stereo_threshold = this.stream_channels == 2 ? (stereo_threshold -= 1000) : (stereo_threshold += 1000); - this.stream_channels = equiv_rate > stereo_threshold ? 2 : 1; - } else { - this.stream_channels = this.channels; - } - equiv_rate = this.bitrate_bps - (40 * this.stream_channels + 20) * (this.Fs / frame_size - 50); - if (this.application == OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) { - this.mode = OpusMode.MODE_CELT_ONLY; - } else if (this.user_forced_mode == OpusMode.MODE_AUTO) { - int mode_voice = Inlines.MULT16_32_Q15(Short.MAX_VALUE - stereo_width, OpusTables.mode_thresholds[0][0]) + Inlines.MULT16_32_Q15(stereo_width, OpusTables.mode_thresholds[1][0]); - int mode_music = Inlines.MULT16_32_Q15(Short.MAX_VALUE - stereo_width, OpusTables.mode_thresholds[1][1]) + Inlines.MULT16_32_Q15(stereo_width, OpusTables.mode_thresholds[1][1]); - int threshold = mode_music + (voice_est * voice_est * (mode_voice - mode_music) >> 14); - if (this.application == OpusApplication.OPUS_APPLICATION_VOIP) { - threshold += 8000; - } - if (this.prev_mode == OpusMode.MODE_CELT_ONLY) { - threshold -= 4000; - } else if (this.prev_mode != OpusMode.MODE_AUTO && this.prev_mode != OpusMode.MODE_UNKNOWN) { - threshold += 4000; - } - OpusMode opusMode = this.mode = equiv_rate >= threshold ? OpusMode.MODE_CELT_ONLY : OpusMode.MODE_SILK_ONLY; - if (this.silk_mode.useInBandFEC != 0 && this.silk_mode.packetLossPercentage > 128 - voice_est >> 4) { - this.mode = OpusMode.MODE_SILK_ONLY; - } - if (this.silk_mode.useDTX != 0 && voice_est > 100) { - this.mode = OpusMode.MODE_SILK_ONLY; - } - } else { - this.mode = this.user_forced_mode; - } - if (this.mode != OpusMode.MODE_CELT_ONLY && frame_size < this.Fs / 100) { - this.mode = OpusMode.MODE_CELT_ONLY; - } - if (this.lfe != 0) { - this.mode = OpusMode.MODE_CELT_ONLY; - } - if (max_data_bytes < (frame_rate > 50 ? 12000 : 8000) * frame_size / (this.Fs * 8)) { - this.mode = OpusMode.MODE_CELT_ONLY; - } - if (this.stream_channels == 1 && this.prev_channels == 2 && this.silk_mode.toMono == 0 && this.mode != OpusMode.MODE_CELT_ONLY && this.prev_mode != OpusMode.MODE_CELT_ONLY) { - this.silk_mode.toMono = 1; - this.stream_channels = 2; - } else { - this.silk_mode.toMono = 0; - } - if (this.prev_mode != OpusMode.MODE_AUTO && this.prev_mode != OpusMode.MODE_UNKNOWN && (this.mode != OpusMode.MODE_CELT_ONLY && this.prev_mode == OpusMode.MODE_CELT_ONLY || this.mode == OpusMode.MODE_CELT_ONLY && this.prev_mode != OpusMode.MODE_CELT_ONLY)) { - redundancy = 1; - int n = celt_to_silk = this.mode != OpusMode.MODE_CELT_ONLY ? 1 : 0; - if (celt_to_silk == 0) { - if (frame_size >= this.Fs / 100) { - this.mode = this.prev_mode; - to_celt = true; - } else { - redundancy = 0; - } - } - } - if (this.silk_bw_switch != 0) { - redundancy = 1; - celt_to_silk = 1; - this.silk_bw_switch = 0; - prefill = true; - } - if (redundancy != 0) { - redundancy_bytes = Inlines.IMIN(257, max_data_bytes * (this.Fs / 200) / (frame_size + this.Fs / 200)); - if (this.use_vbr != 0) { - redundancy_bytes = Inlines.IMIN(redundancy_bytes, this.bitrate_bps / 1600); - } - } - if (this.mode != OpusMode.MODE_CELT_ONLY && this.prev_mode == OpusMode.MODE_CELT_ONLY) { - EncControlState dummy = new EncControlState(); - EncodeAPI.silk_InitEncoder(silk_enc, dummy); - prefill = true; - } - if (this.mode == OpusMode.MODE_CELT_ONLY || this.first != 0 || this.silk_mode.allowBandwidthSwitch != 0) { - int threshold; - int[] music_bandwidth_thresholds; - int[] voice_bandwidth_thresholds; - int[] bandwidth_thresholds = new int[8]; - OpusBandwidth bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; - int equiv_rate2 = equiv_rate; - if (this.mode != OpusMode.MODE_CELT_ONLY) { - equiv_rate2 = equiv_rate2 * (45 + this.silk_mode.complexity) / 50; - if (this.use_vbr == 0) { - equiv_rate2 -= 1000; - } - } - if (this.channels == 2 && this.force_channels != 1) { - voice_bandwidth_thresholds = OpusTables.stereo_voice_bandwidth_thresholds; - music_bandwidth_thresholds = OpusTables.stereo_music_bandwidth_thresholds; - } else { - voice_bandwidth_thresholds = OpusTables.mono_voice_bandwidth_thresholds; - music_bandwidth_thresholds = OpusTables.mono_music_bandwidth_thresholds; - } - for (i = 0; i < 8; ++i) { - bandwidth_thresholds[i] = music_bandwidth_thresholds[i] + (voice_est * voice_est * (voice_bandwidth_thresholds[i] - music_bandwidth_thresholds[i]) >> 14); - } - do { - threshold = bandwidth_thresholds[2 * (OpusBandwidthHelpers.GetOrdinal(bandwidth) - OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND))]; - int hysteresis = bandwidth_thresholds[2 * (OpusBandwidthHelpers.GetOrdinal(bandwidth) - OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND)) + 1]; - if (this.first != 0) continue; - if (OpusBandwidthHelpers.GetOrdinal(this.bandwidth) >= OpusBandwidthHelpers.GetOrdinal(bandwidth)) { - threshold -= hysteresis; - continue; - } - threshold += hysteresis; - } while (equiv_rate2 < threshold && OpusBandwidthHelpers.GetOrdinal(bandwidth = OpusBandwidthHelpers.SUBTRACT(bandwidth, 1)) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND)); - this.bandwidth = bandwidth; - if (this.first == 0 && this.mode != OpusMode.MODE_CELT_ONLY && this.silk_mode.inWBmodeWithoutVariableLP == 0 && OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) { - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; - } - } - if (OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(this.max_bandwidth)) { - this.bandwidth = this.max_bandwidth; - } - if (this.user_bandwidth != OpusBandwidth.OPUS_BANDWIDTH_AUTO) { - this.bandwidth = this.user_bandwidth; - } - if (this.mode != OpusMode.MODE_CELT_ONLY && max_rate < 15000) { - this.bandwidth = OpusBandwidthHelpers.MIN(this.bandwidth, OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND); - } - if (this.Fs <= 24000 && OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND)) { - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND; - } - if (this.Fs <= 16000 && OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) { - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; - } - if (this.Fs <= 12000 && OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND)) { - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND; - } - if (this.Fs <= 8000 && OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND)) { - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; - } - if (this.detected_bandwidth != OpusBandwidth.OPUS_BANDWIDTH_UNKNOWN && this.user_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_AUTO) { - OpusBandwidth min_detected_bandwidth = equiv_rate <= 18000 * this.stream_channels && this.mode == OpusMode.MODE_CELT_ONLY ? OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND : (equiv_rate <= 24000 * this.stream_channels && this.mode == OpusMode.MODE_CELT_ONLY ? OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND : (equiv_rate <= 30000 * this.stream_channels ? OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND : (equiv_rate <= 44000 * this.stream_channels ? OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND : OpusBandwidth.OPUS_BANDWIDTH_FULLBAND))); - this.detected_bandwidth = OpusBandwidthHelpers.MAX(this.detected_bandwidth, min_detected_bandwidth); - this.bandwidth = OpusBandwidthHelpers.MIN(this.bandwidth, this.detected_bandwidth); - } - celt_enc.SetLSBDepth(lsb_depth); - if (this.mode == OpusMode.MODE_CELT_ONLY && this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; - } - if (this.lfe != 0) { - this.bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; - } - if (frame_size > this.Fs / 50 && (this.mode == OpusMode.MODE_CELT_ONLY || OpusBandwidthHelpers.GetOrdinal(this.bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND))) { - if (this.analysis.enabled && analysis_read_pos_bak != -1) { - this.analysis.read_pos = analysis_read_pos_bak; - this.analysis.read_subframe = analysis_read_subframe_bak; - } - int nb_frames = frame_size > this.Fs / 25 ? 3 : 2; - int bytes_per_frame = Inlines.IMIN(1276, (out_data_bytes - 3) / nb_frames); - byte[] tmp_data = new byte[nb_frames * bytes_per_frame]; - OpusRepacketizer rp = new OpusRepacketizer(); - OpusMode bak_mode = this.user_forced_mode; - OpusBandwidth bak_bandwidth = this.user_bandwidth; - int bak_channels = this.force_channels; - this.user_forced_mode = this.mode; - this.user_bandwidth = this.bandwidth; - this.force_channels = this.stream_channels; - int bak_to_mono = this.silk_mode.toMono; - if (bak_to_mono != 0) { - this.force_channels = 1; - } else { - this.prev_channels = this.stream_channels; - } - for (i = 0; i < nb_frames; ++i) { - int tmp_len; - this.silk_mode.toMono = 0; - if (to_celt && i == nb_frames - 1) { - this.user_forced_mode = OpusMode.MODE_CELT_ONLY; - } - if ((tmp_len = this.opus_encode_native(pcm, pcm_ptr + i * (this.channels * this.Fs / 50), this.Fs / 50, tmp_data, i * bytes_per_frame, bytes_per_frame, lsb_depth, null, 0, 0, c1, c2, analysis_channels, float_api)) < 0) { - return OpusError.OPUS_INTERNAL_ERROR; - } - ret = rp.addPacket(tmp_data, i * bytes_per_frame, tmp_len); - if (ret >= 0) continue; - return OpusError.OPUS_INTERNAL_ERROR; - } - int repacketize_len = this.use_vbr != 0 ? out_data_bytes : Inlines.IMIN(3 * this.bitrate_bps / (1200 / nb_frames), out_data_bytes); - ret = rp.opus_repacketizer_out_range_impl(0, nb_frames, data, data_ptr, repacketize_len, 0, this.use_vbr == 0 ? 1 : 0); - if (ret < 0) { - return OpusError.OPUS_INTERNAL_ERROR; - } - this.user_forced_mode = bak_mode; - this.user_bandwidth = bak_bandwidth; - this.force_channels = bak_channels; - this.silk_mode.toMono = bak_to_mono; - return ret; - } - OpusBandwidth curr_bandwidth = this.bandwidth; - if (this.mode == OpusMode.MODE_SILK_ONLY && OpusBandwidthHelpers.GetOrdinal(curr_bandwidth) > OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) { - this.mode = OpusMode.MODE_HYBRID; - } - if (this.mode == OpusMode.MODE_HYBRID && OpusBandwidthHelpers.GetOrdinal(curr_bandwidth) <= OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) { - this.mode = OpusMode.MODE_SILK_ONLY; - } - int bytes_target = Inlines.IMIN(max_data_bytes - redundancy_bytes, this.bitrate_bps * frame_size / (this.Fs * 8)) - 1; - enc.enc_init(data, ++data_ptr, max_data_bytes - 1); - short[] pcm_buf = new short[(total_buffer + frame_size) * this.channels]; - System.arraycopy(this.delay_buffer, (this.encoder_buffer - total_buffer) * this.channels, pcm_buf, 0, total_buffer * this.channels); - int hp_freq_smth1 = this.mode == OpusMode.MODE_CELT_ONLY ? Inlines.silk_LSHIFT(Inlines.silk_lin2log(60), 8) : silk_enc.state_Fxx[0].variable_HP_smth1_Q15; - this.variable_HP_smth2_Q15 = Inlines.silk_SMLAWB(this.variable_HP_smth2_Q15, hp_freq_smth1 - this.variable_HP_smth2_Q15, 983); - int cutoff_Hz = Inlines.silk_log2lin(Inlines.silk_RSHIFT(this.variable_HP_smth2_Q15, 8)); - if (this.application == OpusApplication.OPUS_APPLICATION_VOIP) { - CodecHelpers.hp_cutoff(pcm, pcm_ptr, cutoff_Hz, pcm_buf, total_buffer * this.channels, this.hp_mem, frame_size, this.channels, this.Fs); - } else { - CodecHelpers.dc_reject(pcm, pcm_ptr, 3, pcm_buf, total_buffer * this.channels, this.hp_mem, frame_size, this.channels, this.Fs); - } - int HB_gain = Short.MAX_VALUE; - if (this.mode != OpusMode.MODE_CELT_ONLY) { - short[] pcm_silk = new short[this.channels * frame_size]; - int total_bitRate = 8 * bytes_target * frame_rate; - if (this.mode == OpusMode.MODE_HYBRID) { - this.silk_mode.bitRate = this.stream_channels * (5000 + (this.Fs == 100 * frame_size ? 1000 : 0)); - this.silk_mode.bitRate = curr_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND ? (this.silk_mode.bitRate += (total_bitRate - this.silk_mode.bitRate) * 2 / 3) : (this.silk_mode.bitRate += (total_bitRate - this.silk_mode.bitRate) * 3 / 5); - if (this.silk_mode.bitRate > total_bitRate * 4 / 5) { - this.silk_mode.bitRate = total_bitRate * 4 / 5; - } - if (this.energy_masking == null) { - int celt_rate = total_bitRate - this.silk_mode.bitRate; - int HB_gain_ref = curr_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND ? 3000 : 3600; - HB_gain = Inlines.SHL32(celt_rate, 9) / Inlines.SHR32(celt_rate + this.stream_channels * HB_gain_ref, 6); - HB_gain = HB_gain < 28086 ? HB_gain + 4681 : Short.MAX_VALUE; - } - } else { - this.silk_mode.bitRate = total_bitRate; - } - if (this.energy_masking != null && this.use_vbr != 0 && this.lfe == 0) { - int mask_sum = 0; - int end = 17; - int srate = 16000; - if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { - end = 13; - srate = 8000; - } else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { - end = 15; - srate = 12000; - } - for (int c = 0; c < this.channels; ++c) { - for (i = 0; i < end; ++i) { - int mask = Inlines.MAX16(Inlines.MIN16(this.energy_masking[21 * c + i], 512), -2048); - if (mask > 0) { - mask = Inlines.HALF16(mask); - } - mask_sum += mask; - } - } - int masking_depth = mask_sum / end * this.channels; - int rate_offset = Inlines.PSHR32(Inlines.MULT16_16(srate, masking_depth += 205), 10); - rate_offset = Inlines.MAX32(rate_offset, -2 * this.silk_mode.bitRate / 3); - this.silk_mode.bitRate = this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND || this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_FULLBAND ? (this.silk_mode.bitRate += 3 * rate_offset / 5) : (this.silk_mode.bitRate += rate_offset); - bytes_target += rate_offset * frame_size / (8 * this.Fs); - } - this.silk_mode.payloadSize_ms = 1000 * frame_size / this.Fs; - this.silk_mode.nChannelsAPI = this.channels; - this.silk_mode.nChannelsInternal = this.stream_channels; - if (curr_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { - this.silk_mode.desiredInternalSampleRate = 8000; - } else if (curr_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { - this.silk_mode.desiredInternalSampleRate = 12000; - } else { - Inlines.OpusAssert(this.mode == OpusMode.MODE_HYBRID || curr_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND); - this.silk_mode.desiredInternalSampleRate = 16000; - } - this.silk_mode.minInternalSampleRate = this.mode == OpusMode.MODE_HYBRID ? 16000 : 8000; - if (this.mode == OpusMode.MODE_SILK_ONLY) { - int effective_max_rate = max_rate; - this.silk_mode.maxInternalSampleRate = 16000; - if (frame_rate > 50) { - effective_max_rate = effective_max_rate * 2 / 3; - } - if (effective_max_rate < 13000) { - this.silk_mode.maxInternalSampleRate = 12000; - this.silk_mode.desiredInternalSampleRate = Inlines.IMIN(12000, this.silk_mode.desiredInternalSampleRate); - } - if (effective_max_rate < 9600) { - this.silk_mode.maxInternalSampleRate = 8000; - this.silk_mode.desiredInternalSampleRate = Inlines.IMIN(8000, this.silk_mode.desiredInternalSampleRate); - } - } else { - this.silk_mode.maxInternalSampleRate = 16000; - } - this.silk_mode.useCBR = this.use_vbr == 0 ? 1 : 0; - int nBytes = Inlines.IMIN(1275, max_data_bytes - 1 - redundancy_bytes); - this.silk_mode.maxBits = nBytes * 8; - if (this.mode == OpusMode.MODE_HYBRID) { - this.silk_mode.maxBits = this.silk_mode.maxBits * 9 / 10; - } - if (this.silk_mode.useCBR != 0) { - this.silk_mode.maxBits = this.silk_mode.bitRate * frame_size / (this.Fs * 8) * 8; - this.silk_mode.bitRate = Inlines.IMAX(1, this.silk_mode.bitRate - 2000); - } - if (prefill) { - BoxedValueInt zero = new BoxedValueInt(0); - int prefill_offset = this.channels * (this.encoder_buffer - this.delay_compensation - this.Fs / 400); - CodecHelpers.gain_fade(this.delay_buffer, prefill_offset, 0, Short.MAX_VALUE, celt_mode.overlap, this.Fs / 400, this.channels, celt_mode.window, this.Fs); - Arrays.MemSet(this.delay_buffer, (short)0, prefill_offset); - System.arraycopy(this.delay_buffer, 0, pcm_silk, 0, this.encoder_buffer * this.channels); - EncodeAPI.silk_Encode(silk_enc, this.silk_mode, pcm_silk, this.encoder_buffer, null, zero, 1); - } - System.arraycopy(pcm_buf, total_buffer * this.channels, pcm_silk, 0, frame_size * this.channels); - BoxedValueInt boxed_silkBytes = new BoxedValueInt(nBytes); - ret = EncodeAPI.silk_Encode(silk_enc, this.silk_mode, pcm_silk, frame_size, enc, boxed_silkBytes, 0); - nBytes = boxed_silkBytes.Val; - if (ret != 0) { - return OpusError.OPUS_INTERNAL_ERROR; - } - if (nBytes == 0) { - this.rangeFinal = 0; - data[data_ptr - 1] = CodecHelpers.gen_toc(this.mode, this.Fs / frame_size, curr_bandwidth, this.stream_channels); - return 1; - } - if (this.mode == OpusMode.MODE_SILK_ONLY) { - if (this.silk_mode.internalSampleRate == 8000) { - curr_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; - } else if (this.silk_mode.internalSampleRate == 12000) { - curr_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND; - } else if (this.silk_mode.internalSampleRate == 16000) { - curr_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; - } - } else { - Inlines.OpusAssert(this.silk_mode.internalSampleRate == 16000); - } - this.silk_mode.opusCanSwitch = this.silk_mode.switchReady; - if (this.silk_mode.opusCanSwitch != 0) { - redundancy = 1; - celt_to_silk = 0; - this.silk_bw_switch = 1; - } - } - int endband = 21; - switch (curr_bandwidth) { - case OPUS_BANDWIDTH_NARROWBAND: { - endband = 13; - break; - } - case OPUS_BANDWIDTH_MEDIUMBAND: - case OPUS_BANDWIDTH_WIDEBAND: { - endband = 17; - break; - } - case OPUS_BANDWIDTH_SUPERWIDEBAND: { - endband = 19; - break; - } - case OPUS_BANDWIDTH_FULLBAND: { - endband = 21; - } - } - celt_enc.SetEndBand(endband); - celt_enc.SetChannels(this.stream_channels); - celt_enc.SetBitrate(-1); - if (this.mode != OpusMode.MODE_SILK_ONLY) { - int celt_pred = 2; - celt_enc.SetVBR(false); - if (this.silk_mode.reducedDependency != 0) { - celt_pred = 0; - } - celt_enc.SetPrediction(celt_pred); - if (this.mode == OpusMode.MODE_HYBRID) { - int len = enc.tell() + 7 >> 3; - if (redundancy != 0) { - len += this.mode == OpusMode.MODE_HYBRID ? 3 : 1; - } - nb_compr_bytes = this.use_vbr != 0 ? len + bytes_target - this.silk_mode.bitRate * frame_size / (8 * this.Fs) : (len > bytes_target ? len : bytes_target); - } else if (this.use_vbr != 0) { - int bonus = 0; - if (this.analysis.enabled && this.variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE && frame_size != this.Fs / 50) { - bonus = (60 * this.stream_channels + 40) * (this.Fs / frame_size - 50); - if (analysis_info.valid != 0) { - bonus = (int)((float)bonus * (1.0f + 0.5f * analysis_info.tonality)); - } - } - celt_enc.SetVBR(true); - celt_enc.SetVBRConstraint(this.vbr_constraint != 0); - celt_enc.SetBitrate(this.bitrate_bps + bonus); - nb_compr_bytes = max_data_bytes - 1 - redundancy_bytes; - } else { - nb_compr_bytes = bytes_target; - } - } else { - nb_compr_bytes = 0; - } - short[] tmp_prefill = new short[this.channels * this.Fs / 400]; - if (this.mode != OpusMode.MODE_SILK_ONLY && this.mode != this.prev_mode && this.prev_mode != OpusMode.MODE_AUTO && this.prev_mode != OpusMode.MODE_UNKNOWN) { - System.arraycopy(this.delay_buffer, (this.encoder_buffer - total_buffer - this.Fs / 400) * this.channels, tmp_prefill, 0, this.channels * this.Fs / 400); - } - if (this.channels * (this.encoder_buffer - (frame_size + total_buffer)) > 0) { - Arrays.MemMove(this.delay_buffer, this.channels * frame_size, 0, this.channels * (this.encoder_buffer - frame_size - total_buffer)); - System.arraycopy(pcm_buf, 0, this.delay_buffer, this.channels * (this.encoder_buffer - frame_size - total_buffer), (frame_size + total_buffer) * this.channels); - } else { - System.arraycopy(pcm_buf, (frame_size + total_buffer - this.encoder_buffer) * this.channels, this.delay_buffer, 0, this.encoder_buffer * this.channels); - } - if (this.prev_HB_gain < Short.MAX_VALUE || HB_gain < Short.MAX_VALUE) { - CodecHelpers.gain_fade(pcm_buf, 0, this.prev_HB_gain, HB_gain, celt_mode.overlap, frame_size, this.channels, celt_mode.window, this.Fs); - } - this.prev_HB_gain = HB_gain; - if (this.mode != OpusMode.MODE_HYBRID || this.stream_channels == 1) { - this.silk_mode.stereoWidth_Q14 = Inlines.IMIN(16384, 2 * Inlines.IMAX(0, equiv_rate - 30000)); - } - if (this.energy_masking == null && this.channels == 2 && (this.hybrid_stereo_width_Q14 < 16384 || this.silk_mode.stereoWidth_Q14 < 16384)) { - int g1 = this.hybrid_stereo_width_Q14; - int g2 = this.silk_mode.stereoWidth_Q14; - g1 = g1 == 16384 ? Short.MAX_VALUE : Inlines.SHL16(g1, 1); - g2 = g2 == 16384 ? Short.MAX_VALUE : Inlines.SHL16(g2, 1); - CodecHelpers.stereo_fade(pcm_buf, g1, g2, celt_mode.overlap, frame_size, this.channels, celt_mode.window, this.Fs); - this.hybrid_stereo_width_Q14 = (short)this.silk_mode.stereoWidth_Q14; - } - if (this.mode != OpusMode.MODE_CELT_ONLY && enc.tell() + 17 + 20 * (this.mode == OpusMode.MODE_HYBRID ? 1 : 0) <= 8 * (max_data_bytes - 1)) { - if (this.mode == OpusMode.MODE_HYBRID && (redundancy != 0 || enc.tell() + 37 <= 8 * nb_compr_bytes)) { - enc.enc_bit_logp(redundancy, 12); - } - if (redundancy != 0) { - enc.enc_bit_logp(celt_to_silk, 1); - int max_redundancy = this.mode == OpusMode.MODE_HYBRID ? max_data_bytes - 1 - nb_compr_bytes : max_data_bytes - 1 - (enc.tell() + 7 >> 3); - redundancy_bytes = Inlines.IMIN(max_redundancy, this.bitrate_bps / 1600); - redundancy_bytes = Inlines.IMIN(257, Inlines.IMAX(2, redundancy_bytes)); - if (this.mode == OpusMode.MODE_HYBRID) { - enc.enc_uint(redundancy_bytes - 2, 256L); - } - } - } else { - redundancy = 0; - } - if (redundancy == 0) { - this.silk_bw_switch = 0; - redundancy_bytes = 0; - } - if (this.mode != OpusMode.MODE_CELT_ONLY) { - start_band = 17; - } - if (this.mode == OpusMode.MODE_SILK_ONLY) { - ret = enc.tell() + 7 >> 3; - enc.enc_done(); - nb_compr_bytes = ret; - } else { - nb_compr_bytes = Inlines.IMIN(max_data_bytes - 1 - redundancy_bytes, nb_compr_bytes); - enc.enc_shrink(nb_compr_bytes); - } - if (this.analysis.enabled && redundancy != 0 || this.mode != OpusMode.MODE_SILK_ONLY) { - analysis_info.enabled = this.analysis.enabled; - celt_enc.SetAnalysis(analysis_info); - } - if (redundancy != 0 && celt_to_silk != 0) { - celt_enc.SetStartBand(0); - celt_enc.SetVBR(false); - int err = celt_enc.celt_encode_with_ec(pcm_buf, 0, this.Fs / 200, data, data_ptr + nb_compr_bytes, redundancy_bytes, null); - if (err < 0) { - return OpusError.OPUS_INTERNAL_ERROR; - } - redundant_rng = celt_enc.GetFinalRange(); - celt_enc.ResetState(); - } - celt_enc.SetStartBand(start_band); - if (this.mode != OpusMode.MODE_SILK_ONLY) { - if (this.mode != this.prev_mode && this.prev_mode != OpusMode.MODE_AUTO && this.prev_mode != OpusMode.MODE_UNKNOWN) { - byte[] dummy = new byte[2]; - celt_enc.ResetState(); - celt_enc.celt_encode_with_ec(tmp_prefill, 0, this.Fs / 400, dummy, 0, 2, null); - celt_enc.SetPrediction(0); - } - if (enc.tell() <= 8 * nb_compr_bytes && (ret = celt_enc.celt_encode_with_ec(pcm_buf, 0, frame_size, null, 0, nb_compr_bytes, enc)) < 0) { - return OpusError.OPUS_INTERNAL_ERROR; - } - } - if (redundancy != 0 && celt_to_silk == 0) { - byte[] dummy = new byte[2]; - int N2 = this.Fs / 200; - int N4 = this.Fs / 400; - celt_enc.ResetState(); - celt_enc.SetStartBand(0); - celt_enc.SetPrediction(0); - celt_enc.celt_encode_with_ec(pcm_buf, this.channels * (frame_size - N2 - N4), N4, dummy, 0, 2, null); - int err = celt_enc.celt_encode_with_ec(pcm_buf, this.channels * (frame_size - N2), N2, data, data_ptr + nb_compr_bytes, redundancy_bytes, null); - if (err < 0) { - return OpusError.OPUS_INTERNAL_ERROR; - } - redundant_rng = celt_enc.GetFinalRange(); - } - data[--data_ptr] = CodecHelpers.gen_toc(this.mode, this.Fs / frame_size, curr_bandwidth, this.stream_channels); - this.rangeFinal = (int)enc.rng ^ redundant_rng; - this.prev_mode = to_celt ? OpusMode.MODE_CELT_ONLY : this.mode; - this.prev_channels = this.stream_channels; - this.prev_framesize = frame_size; - this.first = 0; - if (enc.tell() > (max_data_bytes - 1) * 8) { - if (max_data_bytes < 2) { - return OpusError.OPUS_BUFFER_TOO_SMALL; - } - data[data_ptr + 1] = 0; - ret = 1; - this.rangeFinal = 0; - } else if (this.mode == OpusMode.MODE_SILK_ONLY && redundancy == 0) { - while (ret > 2 && data[data_ptr + ret] == 0) { - --ret; - } - } - ret += 1 + redundancy_bytes; - if (this.use_vbr == 0) { - if (OpusRepacketizer.padPacket(data, data_ptr, ret, max_data_bytes) != OpusError.OPUS_OK) { - return OpusError.OPUS_INTERNAL_ERROR; - } - ret = max_data_bytes; - } - return ret; - } - - public int encode(short[] in_pcm, int pcm_offset, int frame_size, byte[] out_data, int out_data_offset, int max_data_bytes) throws OpusException { - if (out_data_offset + max_data_bytes > out_data.length) { - throw new IllegalArgumentException("Output buffer is too small: Stated size is " + max_data_bytes + " bytes, actual size is " + (out_data.length - out_data_offset) + " bytes"); - } - int delay_compensation = this.application == OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY ? 0 : this.delay_compensation; - int internal_frame_size = CodecHelpers.compute_frame_size(in_pcm, pcm_offset, frame_size, this.variable_duration, this.channels, this.Fs, this.bitrate_bps, delay_compensation, this.analysis.subframe_mem, this.analysis.enabled); - if (pcm_offset + internal_frame_size > in_pcm.length) { - throw new IllegalArgumentException("Not enough samples provided in input signal: Expected " + internal_frame_size + " samples, found " + (in_pcm.length - pcm_offset)); - } - try { - int ret = this.opus_encode_native(in_pcm, pcm_offset, internal_frame_size, out_data, out_data_offset, max_data_bytes, 16, in_pcm, pcm_offset, frame_size, 0, -2, this.channels, 0); - if (ret < 0) { - if (ret == OpusError.OPUS_BAD_ARG) { - throw new IllegalArgumentException("OPUS_BAD_ARG while encoding"); - } - throw new OpusException("An error occurred during encoding", ret); - } - return ret; - } - catch (ArithmeticException e) { - throw new OpusException("Internal error during encoding: " + e.getMessage()); - } - } - - public int encode(byte[] in_pcm, int pcm_offset, int frame_size, byte[] out_data, int out_data_offset, int max_data_bytes) throws OpusException { - short[] spcm = new short[frame_size * this.channels]; - int idx = pcm_offset; - for (int c = 0; c < spcm.length; ++c) { - spcm[c] = (short)((in_pcm[idx] & 0xFF | in_pcm[idx + 1] << 8) & 0xFFFF); - idx += 2; - } - return this.encode(spcm, 0, frame_size, out_data, out_data_offset, max_data_bytes); - } - - public OpusApplication getApplication() { - return this.application; - } - - public void setApplication(OpusApplication value) { - if (this.first == 0 && this.application != value) { - throw new IllegalArgumentException("Application cannot be changed after encoding has started"); - } - this.application = value; - } - - public int getBitrate() { - return this.user_bitrate_to_bitrate(this.prev_framesize, 1276); - } - - public void setBitrate(int value) { - if (value != -1000 && value != -1) { - if (value <= 0) { - throw new IllegalArgumentException("Bitrate must be positive"); - } - if (value <= 500) { - value = 500; - } else if (value > 300000 * this.channels) { - value = 300000 * this.channels; - } - } - this.user_bitrate_bps = value; - } - - public int getForceChannels() { - return this.force_channels; - } - - public void setForceChannels(int value) { - if ((value < 1 || value > this.channels) && value != -1000) { - throw new IllegalArgumentException("Force channels must be <= num. of channels"); - } - this.force_channels = value; - } - - public OpusBandwidth getMaxBandwidth() { - return this.max_bandwidth; - } - - public void setMaxBandwidth(OpusBandwidth value) { - this.max_bandwidth = value; - this.silk_mode.maxInternalSampleRate = this.max_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND ? 8000 : (this.max_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND ? 12000 : 16000); - } - - public OpusBandwidth getBandwidth() { - return this.bandwidth; - } - - public void setBandwidth(OpusBandwidth value) { - this.user_bandwidth = value; - this.silk_mode.maxInternalSampleRate = this.user_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND ? 8000 : (this.user_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND ? 12000 : 16000); - } - - public boolean getUseDTX() { - return this.silk_mode.useDTX != 0; - } - - public void setUseDTX(boolean value) { - this.silk_mode.useDTX = value ? 1 : 0; - } - - public int getComplexity() { - return this.silk_mode.complexity; - } - - public void setComplexity(int value) { - if (value < 0 || value > 10) { - throw new IllegalArgumentException("Complexity must be between 0 and 10"); - } - this.silk_mode.complexity = value; - this.Celt_Encoder.SetComplexity(value); - } - - public boolean getUseInbandFEC() { - return this.silk_mode.useInBandFEC != 0; - } - - public void setUseInbandFEC(boolean value) { - this.silk_mode.useInBandFEC = value ? 1 : 0; - } - - public int getPacketLossPercent() { - return this.silk_mode.packetLossPercentage; - } - - public void setPacketLossPercent(int value) { - if (value < 0 || value > 100) { - throw new IllegalArgumentException("Packet loss must be between 0 and 100"); - } - this.silk_mode.packetLossPercentage = value; - this.Celt_Encoder.SetPacketLossPercent(value); - } - - public boolean getUseVBR() { - return this.use_vbr != 0; - } - - public void setUseVBR(boolean value) { - this.use_vbr = value ? 1 : 0; - this.silk_mode.useCBR = value ? 0 : 1; - } - - public boolean getUseConstrainedVBR() { - return this.vbr_constraint != 0; - } - - public void setUseConstrainedVBR(boolean value) { - this.vbr_constraint = value ? 1 : 0; - } - - public OpusSignal getSignalType() { - return this.signal_type; - } - - public void setSignalType(OpusSignal value) { - this.signal_type = value; - } - - public int getLookahead() { - int returnVal = this.Fs / 400; - if (this.application != OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) { - returnVal += this.delay_compensation; - } - return returnVal; - } - - public int getSampleRate() { - return this.Fs; - } - - public int getFinalRange() { - return this.rangeFinal; - } - - public int getLSBDepth() { - return this.lsb_depth; - } - - public void setLSBDepth(int value) { - if (value < 8 || value > 24) { - throw new IllegalArgumentException("LSB depth must be between 8 and 24"); - } - this.lsb_depth = value; - } - - public OpusFramesize getExpertFrameDuration() { - return this.variable_duration; - } - - public void setExpertFrameDuration(OpusFramesize value) { - this.variable_duration = value; - this.Celt_Encoder.SetExpertFrameDuration(value); - } - - public OpusMode getForceMode() { - return this.user_forced_mode; - } - - public void setForceMode(OpusMode value) { - this.user_forced_mode = value; - } - - public boolean getIsLFE() { - return this.lfe != 0; - } - - public void setIsLFE(boolean value) { - this.lfe = value ? 1 : 0; - this.Celt_Encoder.SetLFE(value ? 1 : 0); - } - - public boolean getPredictionDisabled() { - return this.silk_mode.reducedDependency != 0; - } - - public void setPredictionDisabled(boolean value) { - this.silk_mode.reducedDependency = value ? 1 : 0; - } - - public boolean getEnableAnalysis() { - return this.analysis.enabled; - } - - public void setEnableAnalysis(boolean value) { - this.analysis.enabled = value; - } - - void SetEnergyMask(int[] value) { - this.energy_masking = value; - this.Celt_Encoder.SetEnergyMask(value); - } - - CeltMode GetCeltMode() { - return this.Celt_Encoder.GetMode(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusError.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusError.java deleted file mode 100644 index e32167e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusError.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -public class OpusError { - public static int OPUS_OK = 0; - public static int OPUS_BAD_ARG = -1; - public static int OPUS_BUFFER_TOO_SMALL = -2; - public static int OPUS_INTERNAL_ERROR = -3; - public static int OPUS_INVALID_PACKET = -4; - public static int OPUS_UNIMPLEMENTED = -5; - public static int OPUS_INVALID_STATE = -6; - public static int OPUS_ALLOC_FAIL = -7; -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusException.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusException.java deleted file mode 100644 index 95a1c05..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.CodecHelpers; - -public class OpusException -extends Exception { - private String _message; - private int _opus_error_code; - - public OpusException() { - this("", 0); - } - - public OpusException(String message) { - this(message, 1); - } - - public OpusException(String message, int opus_error_code) { - this._message = message + ": " + CodecHelpers.opus_strerror(opus_error_code); - this._opus_error_code = opus_error_code; - } - - @Override - public String getMessage() { - return this._message; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusFramesize.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusFramesize.java deleted file mode 100644 index 86e7eb9..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusFramesize.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -public enum OpusFramesize { - OPUS_FRAMESIZE_UNKNOWN, - OPUS_FRAMESIZE_ARG, - OPUS_FRAMESIZE_2_5_MS, - OPUS_FRAMESIZE_5_MS, - OPUS_FRAMESIZE_10_MS, - OPUS_FRAMESIZE_20_MS, - OPUS_FRAMESIZE_40_MS, - OPUS_FRAMESIZE_60_MS, - OPUS_FRAMESIZE_VARIABLE; - -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusFramesizeHelpers.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusFramesizeHelpers.java deleted file mode 100644 index f7d121c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusFramesizeHelpers.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.OpusFramesize; - -class OpusFramesizeHelpers { - OpusFramesizeHelpers() { - } - - static int GetOrdinal(OpusFramesize size) { - switch (size) { - case OPUS_FRAMESIZE_ARG: { - return 1; - } - case OPUS_FRAMESIZE_2_5_MS: { - return 2; - } - case OPUS_FRAMESIZE_5_MS: { - return 3; - } - case OPUS_FRAMESIZE_10_MS: { - return 4; - } - case OPUS_FRAMESIZE_20_MS: { - return 5; - } - case OPUS_FRAMESIZE_40_MS: { - return 6; - } - case OPUS_FRAMESIZE_60_MS: { - return 7; - } - case OPUS_FRAMESIZE_VARIABLE: { - return 8; - } - } - return -1; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMSDecoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMSDecoder.java deleted file mode 100644 index bd2d04b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMSDecoder.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.ChannelLayout; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.OpusBandwidth; -import de.maxhenkel.voicechat.concentus.OpusDecoder; -import de.maxhenkel.voicechat.concentus.OpusError; -import de.maxhenkel.voicechat.concentus.OpusException; -import de.maxhenkel.voicechat.concentus.OpusMultistream; -import de.maxhenkel.voicechat.concentus.OpusPacketInfo; - -public class OpusMSDecoder { - ChannelLayout layout = new ChannelLayout(); - OpusDecoder[] decoders = null; - - private OpusMSDecoder(int nb_streams, int nb_coupled_streams) { - this.decoders = new OpusDecoder[nb_streams]; - for (int c = 0; c < nb_streams; ++c) { - this.decoders[c] = new OpusDecoder(); - } - } - - int opus_multistream_decoder_init(int Fs, int channels, int streams, int coupled_streams, short[] mapping) { - int ret; - int i; - int decoder_ptr = 0; - if (channels > 255 || channels < 1 || coupled_streams > streams || streams < 1 || coupled_streams < 0 || streams > 255 - coupled_streams) { - throw new IllegalArgumentException("Invalid channel or coupled stream count"); - } - this.layout.nb_channels = channels; - this.layout.nb_streams = streams; - this.layout.nb_coupled_streams = coupled_streams; - for (i = 0; i < this.layout.nb_channels; ++i) { - this.layout.mapping[i] = mapping[i]; - } - if (OpusMultistream.validate_layout(this.layout) == 0) { - throw new IllegalArgumentException("Invalid surround channel layout"); - } - for (i = 0; i < this.layout.nb_coupled_streams; ++i) { - ret = this.decoders[decoder_ptr].opus_decoder_init(Fs, 2); - if (ret != OpusError.OPUS_OK) { - return ret; - } - ++decoder_ptr; - } - while (i < this.layout.nb_streams) { - ret = this.decoders[decoder_ptr].opus_decoder_init(Fs, 1); - if (ret != OpusError.OPUS_OK) { - return ret; - } - ++decoder_ptr; - ++i; - } - return OpusError.OPUS_OK; - } - - public static OpusMSDecoder create(int Fs, int channels, int streams, int coupled_streams, short[] mapping) throws OpusException { - if (channels > 255 || channels < 1 || coupled_streams > streams || streams < 1 || coupled_streams < 0 || streams > 255 - coupled_streams) { - throw new IllegalArgumentException("Invalid channel / stream configuration"); - } - OpusMSDecoder st = new OpusMSDecoder(streams, coupled_streams); - int ret = st.opus_multistream_decoder_init(Fs, channels, streams, coupled_streams, mapping); - if (ret != OpusError.OPUS_OK) { - if (ret == OpusError.OPUS_BAD_ARG) { - throw new IllegalArgumentException("Bad argument while creating MS decoder"); - } - throw new OpusException("Could not create MS decoder", ret); - } - return st; - } - - static int opus_multistream_packet_validate(byte[] data, int data_ptr, int len, int nb_streams, int Fs) { - BoxedValueByte toc = new BoxedValueByte(0); - short[] size = new short[48]; - int samples = 0; - BoxedValueInt packet_offset = new BoxedValueInt(0); - BoxedValueInt dummy = new BoxedValueInt(0); - for (int s = 0; s < nb_streams; ++s) { - if (len <= 0) { - return OpusError.OPUS_INVALID_PACKET; - } - int count = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, s != nb_streams - 1 ? 1 : 0, toc, null, 0, size, 0, dummy, packet_offset); - if (count < 0) { - return count; - } - int tmp_samples = OpusPacketInfo.getNumSamples(data, data_ptr, packet_offset.Val, Fs); - if (s != 0 && samples != tmp_samples) { - return OpusError.OPUS_INVALID_PACKET; - } - samples = tmp_samples; - data_ptr += packet_offset.Val; - len -= packet_offset.Val; - } - return samples; - } - - int opus_multistream_decode_native(byte[] data, int data_ptr, int len, short[] pcm, int pcm_ptr, int frame_size, int decode_fec, int soft_clip) { - boolean do_plc = false; - int Fs = this.getSampleRate(); - frame_size = Inlines.IMIN(frame_size, Fs / 25 * 3); - short[] buf = new short[2 * frame_size]; - int decoder_ptr = 0; - if (len == 0) { - do_plc = true; - } - if (len < 0) { - return OpusError.OPUS_BAD_ARG; - } - if (!do_plc && len < 2 * this.layout.nb_streams - 1) { - return OpusError.OPUS_INVALID_PACKET; - } - if (!do_plc) { - int ret = OpusMSDecoder.opus_multistream_packet_validate(data, data_ptr, len, this.layout.nb_streams, Fs); - if (ret < 0) { - return ret; - } - if (ret > frame_size) { - return OpusError.OPUS_BUFFER_TOO_SMALL; - } - } - for (int s = 0; s < this.layout.nb_streams; ++s) { - int chan; - int prev; - OpusDecoder dec = this.decoders[decoder_ptr++]; - if (!do_plc && len <= 0) { - return OpusError.OPUS_INTERNAL_ERROR; - } - BoxedValueInt packet_offset = new BoxedValueInt(0); - int ret = dec.opus_decode_native(data, data_ptr, len, buf, 0, frame_size, decode_fec, s != this.layout.nb_streams - 1 ? 1 : 0, packet_offset, soft_clip); - data_ptr += packet_offset.Val; - len -= packet_offset.Val; - if (ret <= 0) { - return ret; - } - frame_size = ret; - if (s < this.layout.nb_coupled_streams) { - prev = -1; - while ((chan = OpusMultistream.get_left_channel(this.layout, s, prev)) != -1) { - OpusMSDecoder.opus_copy_channel_out_short(pcm, pcm_ptr, this.layout.nb_channels, chan, buf, 0, 2, frame_size); - prev = chan; - } - prev = -1; - while ((chan = OpusMultistream.get_right_channel(this.layout, s, prev)) != -1) { - OpusMSDecoder.opus_copy_channel_out_short(pcm, pcm_ptr, this.layout.nb_channels, chan, buf, 1, 2, frame_size); - prev = chan; - } - continue; - } - prev = -1; - while ((chan = OpusMultistream.get_mono_channel(this.layout, s, prev)) != -1) { - OpusMSDecoder.opus_copy_channel_out_short(pcm, pcm_ptr, this.layout.nb_channels, chan, buf, 0, 1, frame_size); - prev = chan; - } - } - for (int c = 0; c < this.layout.nb_channels; ++c) { - if (this.layout.mapping[c] != 255) continue; - OpusMSDecoder.opus_copy_channel_out_short(pcm, pcm_ptr, this.layout.nb_channels, c, null, 0, 0, frame_size); - } - return frame_size; - } - - static void opus_copy_channel_out_short(short[] dst, int dst_ptr, int dst_stride, int dst_channel, short[] src, int src_ptr, int src_stride, int frame_size) { - if (src != null) { - for (int i = 0; i < frame_size; ++i) { - dst[i * dst_stride + dst_channel + dst_ptr] = src[i * src_stride + src_ptr]; - } - } else { - for (int i = 0; i < frame_size; ++i) { - dst[i * dst_stride + dst_channel + dst_ptr] = 0; - } - } - } - - public int decodeMultistream(byte[] data, int data_offset, int len, short[] out_pcm, int out_pcm_offset, int frame_size, int decode_fec) { - return this.opus_multistream_decode_native(data, data_offset, len, out_pcm, out_pcm_offset, frame_size, decode_fec, 0); - } - - public OpusBandwidth getBandwidth() { - if (this.decoders == null || this.decoders.length == 0) { - throw new IllegalStateException("Decoder not initialized"); - } - return this.decoders[0].getBandwidth(); - } - - public int getSampleRate() { - if (this.decoders == null || this.decoders.length == 0) { - throw new IllegalStateException("Decoder not initialized"); - } - return this.decoders[0].getSampleRate(); - } - - public int getGain() { - if (this.decoders == null || this.decoders.length == 0) { - throw new IllegalStateException("Decoder not initialized"); - } - return this.decoders[0].getGain(); - } - - public void setGain(int value) { - for (int s = 0; s < this.layout.nb_streams; ++s) { - this.decoders[s].setGain(value); - } - } - - public int getLastPacketDuration() { - if (this.decoders == null || this.decoders.length == 0) { - return OpusError.OPUS_INVALID_STATE; - } - return this.decoders[0].getLastPacketDuration(); - } - - public int getFinalRange() { - int value = 0; - for (int s = 0; s < this.layout.nb_streams; ++s) { - value ^= this.decoders[s].getFinalRange(); - } - return value; - } - - public void ResetState() { - for (int s = 0; s < this.layout.nb_streams; ++s) { - this.decoders[s].resetState(); - } - } - - public OpusDecoder GetMultistreamDecoderState(int streamId) { - return this.decoders[streamId]; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMSEncoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMSEncoder.java deleted file mode 100644 index 1877d9e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMSEncoder.java +++ /dev/null @@ -1,735 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Bands; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltCommon; -import de.maxhenkel.voicechat.concentus.CeltMode; -import de.maxhenkel.voicechat.concentus.ChannelLayout; -import de.maxhenkel.voicechat.concentus.CodecHelpers; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.MDCT; -import de.maxhenkel.voicechat.concentus.OpusApplication; -import de.maxhenkel.voicechat.concentus.OpusBandwidth; -import de.maxhenkel.voicechat.concentus.OpusEncoder; -import de.maxhenkel.voicechat.concentus.OpusError; -import de.maxhenkel.voicechat.concentus.OpusException; -import de.maxhenkel.voicechat.concentus.OpusFramesize; -import de.maxhenkel.voicechat.concentus.OpusMode; -import de.maxhenkel.voicechat.concentus.OpusMultistream; -import de.maxhenkel.voicechat.concentus.OpusRepacketizer; -import de.maxhenkel.voicechat.concentus.OpusSignal; -import de.maxhenkel.voicechat.concentus.QuantizeBands; -import de.maxhenkel.voicechat.concentus.VorbisLayout; - -public class OpusMSEncoder { - final ChannelLayout layout = new ChannelLayout(); - int lfe_stream = 0; - OpusApplication application = OpusApplication.OPUS_APPLICATION_AUDIO; - OpusFramesize variable_duration = OpusFramesize.OPUS_FRAMESIZE_UNKNOWN; - int surround = 0; - int bitrate_bps = 0; - final float[] subframe_mem = new float[3]; - OpusEncoder[] encoders = null; - int[] window_mem = null; - int[] preemph_mem = null; - private static final int[] diff_table = new int[]{512, 300, 165, 87, 45, 23, 11, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0}; - private final int MS_FRAME_TMP = 3832; - - private OpusMSEncoder(int nb_streams, int nb_coupled_streams) { - if (nb_streams < 1 || nb_coupled_streams > nb_streams || nb_coupled_streams < 0) { - throw new IllegalArgumentException("Invalid channel count in MS encoder"); - } - this.encoders = new OpusEncoder[nb_streams]; - for (int c = 0; c < nb_streams; ++c) { - this.encoders[c] = new OpusEncoder(); - } - int nb_channels = nb_coupled_streams * 2 + (nb_streams - nb_coupled_streams); - this.window_mem = new int[nb_channels * 120]; - this.preemph_mem = new int[nb_channels]; - } - - public void resetState() { - this.subframe_mem[2] = 0.0f; - this.subframe_mem[1] = 0.0f; - this.subframe_mem[0] = 0.0f; - if (this.surround != 0) { - Arrays.MemSet(this.preemph_mem, 0, this.layout.nb_channels); - Arrays.MemSet(this.window_mem, 0, this.layout.nb_channels * 120); - } - int encoder_ptr = 0; - for (int s = 0; s < this.layout.nb_streams; ++s) { - OpusEncoder enc = this.encoders[encoder_ptr++]; - enc.resetState(); - } - } - - static int validate_encoder_layout(ChannelLayout layout) { - for (int s = 0; s < layout.nb_streams; ++s) { - if (s < layout.nb_coupled_streams) { - if (OpusMultistream.get_left_channel(layout, s, -1) == -1) { - return 0; - } - if (OpusMultistream.get_right_channel(layout, s, -1) != -1) continue; - return 0; - } - if (OpusMultistream.get_mono_channel(layout, s, -1) != -1) continue; - return 0; - } - return 1; - } - - static void channel_pos(int channels, int[] pos) { - if (channels == 4) { - pos[0] = 1; - pos[1] = 3; - pos[2] = 1; - pos[3] = 3; - } else if (channels == 3 || channels == 5 || channels == 6) { - pos[0] = 1; - pos[1] = 2; - pos[2] = 3; - pos[3] = 1; - pos[4] = 3; - pos[5] = 0; - } else if (channels == 7) { - pos[0] = 1; - pos[1] = 2; - pos[2] = 3; - pos[3] = 1; - pos[4] = 3; - pos[5] = 2; - pos[6] = 0; - } else if (channels == 8) { - pos[0] = 1; - pos[1] = 2; - pos[2] = 3; - pos[3] = 1; - pos[4] = 3; - pos[5] = 1; - pos[6] = 3; - pos[7] = 0; - } - } - - static int logSum(int a, int b) { - int diff; - int max; - if (a > b) { - max = a; - diff = Inlines.SUB32(Inlines.EXTEND32(a), Inlines.EXTEND32(b)); - } else { - max = b; - diff = Inlines.SUB32(Inlines.EXTEND32(b), Inlines.EXTEND32(a)); - } - if (diff >= 8192) { - return max; - } - int low = Inlines.SHR32(diff, 9); - int frac = Inlines.SHL16(diff - Inlines.SHL16(low, 9), 6); - return max + diff_table[low] + Inlines.MULT16_16_Q15(frac, Inlines.SUB16(diff_table[low + 1], diff_table[low])); - } - - static void surround_analysis(CeltMode celt_mode, short[] pcm, int pcm_ptr, int[] bandLogE, int[] mem, int[] preemph_mem, int len, int overlap, int channels, int rate) { - int i; - int c; - int LM; - int[] pos = new int[]{0, 0, 0, 0, 0, 0, 0, 0}; - int[][] bandE = Arrays.InitTwoDimensionalArrayInt(1, 21); - int[][] maskLogE = Arrays.InitTwoDimensionalArrayInt(3, 21); - int upsample = CeltCommon.resampling_factor(rate); - int frame_size = len * upsample; - for (LM = 0; LM < celt_mode.maxLM && celt_mode.shortMdctSize << LM != frame_size; ++LM) { - } - int[] input = new int[frame_size + overlap]; - short[] x = new short[len]; - int[][] freq = Arrays.InitTwoDimensionalArrayInt(1, frame_size); - OpusMSEncoder.channel_pos(channels, pos); - for (c = 0; c < 3; ++c) { - for (i = 0; i < 21; ++i) { - maskLogE[c][i] = -28672; - } - } - for (c = 0; c < channels; ++c) { - System.arraycopy(mem, c * overlap, input, 0, overlap); - OpusMSEncoder.opus_copy_channel_in_short(x, 0, 1, pcm, pcm_ptr, channels, c, len); - BoxedValueInt boxed_preemph = new BoxedValueInt(preemph_mem[c]); - CeltCommon.celt_preemphasis(x, input, overlap, frame_size, 1, upsample, celt_mode.preemph, boxed_preemph, 0); - preemph_mem[c] = boxed_preemph.Val; - MDCT.clt_mdct_forward(celt_mode.mdct, input, 0, freq[0], 0, celt_mode.window, overlap, celt_mode.maxLM - LM, 1); - if (upsample != 1) { - int bound = len; - i = 0; - while (i < bound) { - int[] nArray = freq[0]; - int n = i++; - nArray[n] = nArray[n] * upsample; - } - while (i < frame_size) { - freq[0][i] = 0; - ++i; - } - } - Bands.compute_band_energies(celt_mode, freq, bandE, 21, 1, LM); - QuantizeBands.amp2Log2(celt_mode, 21, 21, bandE[0], bandLogE, 21 * c, 1); - for (i = 1; i < 21; ++i) { - bandLogE[21 * c + i] = Inlines.MAX16(bandLogE[21 * c + i], bandLogE[21 * c + i - 1] - 1024); - } - for (i = 19; i >= 0; --i) { - bandLogE[21 * c + i] = Inlines.MAX16(bandLogE[21 * c + i], bandLogE[21 * c + i + 1] - 2048); - } - if (pos[c] == 1) { - for (i = 0; i < 21; ++i) { - maskLogE[0][i] = OpusMSEncoder.logSum(maskLogE[0][i], bandLogE[21 * c + i]); - } - } else if (pos[c] == 3) { - for (i = 0; i < 21; ++i) { - maskLogE[2][i] = OpusMSEncoder.logSum(maskLogE[2][i], bandLogE[21 * c + i]); - } - } else if (pos[c] == 2) { - for (i = 0; i < 21; ++i) { - maskLogE[0][i] = OpusMSEncoder.logSum(maskLogE[0][i], bandLogE[21 * c + i] - 512); - maskLogE[2][i] = OpusMSEncoder.logSum(maskLogE[2][i], bandLogE[21 * c + i] - 512); - } - } - System.arraycopy(input, frame_size, mem, c * overlap, overlap); - } - for (i = 0; i < 21; ++i) { - maskLogE[1][i] = Inlines.MIN32(maskLogE[0][i], maskLogE[2][i]); - } - int channel_offset = Inlines.HALF16(Inlines.celt_log2(32768 / (channels - 1))); - for (c = 0; c < 3; ++c) { - i = 0; - while (i < 21) { - int[] nArray = maskLogE[c]; - int n = i++; - nArray[n] = nArray[n] + channel_offset; - } - } - for (c = 0; c < channels; ++c) { - if (pos[c] != 0) { - int[] mask = maskLogE[pos[c] - 1]; - for (i = 0; i < 21; ++i) { - bandLogE[21 * c + i] = bandLogE[21 * c + i] - mask[i]; - } - continue; - } - for (i = 0; i < 21; ++i) { - bandLogE[21 * c + i] = 0; - } - } - } - - int opus_multistream_encoder_init(int Fs, int channels, int streams, int coupled_streams, short[] mapping, OpusApplication application, int surround) { - int ret; - int i; - if (channels > 255 || channels < 1 || coupled_streams > streams || streams < 1 || coupled_streams < 0 || streams > 255 - coupled_streams) { - return OpusError.OPUS_BAD_ARG; - } - this.layout.nb_channels = channels; - this.layout.nb_streams = streams; - this.layout.nb_coupled_streams = coupled_streams; - this.subframe_mem[2] = 0.0f; - this.subframe_mem[1] = 0.0f; - this.subframe_mem[0] = 0.0f; - if (surround == 0) { - this.lfe_stream = -1; - } - this.bitrate_bps = -1000; - this.application = application; - this.variable_duration = OpusFramesize.OPUS_FRAMESIZE_ARG; - for (i = 0; i < this.layout.nb_channels; ++i) { - this.layout.mapping[i] = mapping[i]; - } - if (OpusMultistream.validate_layout(this.layout) == 0 || OpusMSEncoder.validate_encoder_layout(this.layout) == 0) { - return OpusError.OPUS_BAD_ARG; - } - int encoder_ptr = 0; - for (i = 0; i < this.layout.nb_coupled_streams; ++i) { - ret = this.encoders[encoder_ptr].opus_init_encoder(Fs, 2, application); - if (ret != OpusError.OPUS_OK) { - return ret; - } - if (i == this.lfe_stream) { - this.encoders[encoder_ptr].setIsLFE(true); - } - ++encoder_ptr; - } - while (i < this.layout.nb_streams) { - ret = this.encoders[encoder_ptr].opus_init_encoder(Fs, 1, application); - if (i == this.lfe_stream) { - this.encoders[encoder_ptr].setIsLFE(true); - } - if (ret != OpusError.OPUS_OK) { - return ret; - } - ++encoder_ptr; - ++i; - } - if (surround != 0) { - Arrays.MemSet(this.preemph_mem, 0, channels); - Arrays.MemSet(this.window_mem, 0, channels * 120); - } - this.surround = surround; - return OpusError.OPUS_OK; - } - - /* - * Enabled force condition propagation - * Lifted jumps to return sites - */ - int opus_multistream_surround_encoder_init(int Fs, int channels, int mapping_family, BoxedValueInt streams, BoxedValueInt coupled_streams, short[] mapping, OpusApplication application) { - streams.Val = 0; - coupled_streams.Val = 0; - if (channels > 255 || channels < 1) { - return OpusError.OPUS_BAD_ARG; - } - this.lfe_stream = -1; - if (mapping_family == 0) { - if (channels == 1) { - streams.Val = 1; - coupled_streams.Val = 0; - mapping[0] = 0; - return this.opus_multistream_encoder_init(Fs, channels, streams.Val, coupled_streams.Val, mapping, application, channels > 2 && mapping_family == 1 ? 1 : 0); - } else { - if (channels != 2) return OpusError.OPUS_UNIMPLEMENTED; - streams.Val = 1; - coupled_streams.Val = 1; - mapping[0] = 0; - mapping[1] = 1; - } - return this.opus_multistream_encoder_init(Fs, channels, streams.Val, coupled_streams.Val, mapping, application, channels > 2 && mapping_family == 1 ? 1 : 0); - } else if (mapping_family == 1 && channels <= 8 && channels >= 1) { - streams.Val = VorbisLayout.vorbis_mappings[channels - 1].nb_streams; - coupled_streams.Val = VorbisLayout.vorbis_mappings[channels - 1].nb_coupled_streams; - for (int i = 0; i < channels; ++i) { - mapping[i] = VorbisLayout.vorbis_mappings[channels - 1].mapping[i]; - } - if (channels < 6) return this.opus_multistream_encoder_init(Fs, channels, streams.Val, coupled_streams.Val, mapping, application, channels > 2 && mapping_family == 1 ? 1 : 0); - this.lfe_stream = streams.Val - 1; - return this.opus_multistream_encoder_init(Fs, channels, streams.Val, coupled_streams.Val, mapping, application, channels > 2 && mapping_family == 1 ? 1 : 0); - } else { - if (mapping_family != 255) return OpusError.OPUS_UNIMPLEMENTED; - streams.Val = channels; - coupled_streams.Val = 0; - for (int i = 0; i < channels; i = (int)((byte)(i + 1))) { - mapping[i] = (short)i; - } - } - return this.opus_multistream_encoder_init(Fs, channels, streams.Val, coupled_streams.Val, mapping, application, channels > 2 && mapping_family == 1 ? 1 : 0); - } - - public static OpusMSEncoder Create(int Fs, int channels, int streams, int coupled_streams, short[] mapping, OpusApplication application) throws OpusException { - if (channels > 255 || channels < 1 || coupled_streams > streams || streams < 1 || coupled_streams < 0 || streams > 255 - coupled_streams) { - throw new IllegalArgumentException("Invalid channel / stream configuration"); - } - OpusMSEncoder st = new OpusMSEncoder(streams, coupled_streams); - int ret = st.opus_multistream_encoder_init(Fs, channels, streams, coupled_streams, mapping, application, 0); - if (ret != OpusError.OPUS_OK) { - if (ret == OpusError.OPUS_BAD_ARG) { - throw new IllegalArgumentException("OPUS_BAD_ARG when creating MS encoder"); - } - throw new OpusException("Could not create MS encoder", ret); - } - return st; - } - - /* - * Enabled force condition propagation - * Lifted jumps to return sites - */ - static void GetStreamCount(int channels, int mapping_family, BoxedValueInt nb_streams, BoxedValueInt nb_coupled_streams) { - if (mapping_family == 0) { - if (channels == 1) { - nb_streams.Val = 1; - nb_coupled_streams.Val = 0; - return; - } else { - if (channels != 2) throw new IllegalArgumentException("More than 2 channels requires custom mappings"); - nb_streams.Val = 1; - nb_coupled_streams.Val = 1; - } - return; - } else if (mapping_family == 1 && channels <= 8 && channels >= 1) { - nb_streams.Val = VorbisLayout.vorbis_mappings[channels - 1].nb_streams; - nb_coupled_streams.Val = VorbisLayout.vorbis_mappings[channels - 1].nb_coupled_streams; - return; - } else { - if (mapping_family != 255) throw new IllegalArgumentException("Invalid mapping family"); - nb_streams.Val = channels; - nb_coupled_streams.Val = 0; - } - } - - public static OpusMSEncoder CreateSurround(int Fs, int channels, int mapping_family, BoxedValueInt streams, BoxedValueInt coupled_streams, short[] mapping, OpusApplication application) throws OpusException { - if (channels > 255 || channels < 1 || application == OpusApplication.OPUS_APPLICATION_UNIMPLEMENTED) { - throw new IllegalArgumentException("Invalid channel count or application"); - } - BoxedValueInt nb_streams = new BoxedValueInt(0); - BoxedValueInt nb_coupled_streams = new BoxedValueInt(0); - OpusMSEncoder.GetStreamCount(channels, mapping_family, nb_streams, nb_coupled_streams); - OpusMSEncoder st = new OpusMSEncoder(nb_streams.Val, nb_coupled_streams.Val); - int ret = st.opus_multistream_surround_encoder_init(Fs, channels, mapping_family, streams, coupled_streams, mapping, application); - if (ret != OpusError.OPUS_OK) { - if (ret == OpusError.OPUS_BAD_ARG) { - throw new IllegalArgumentException("Bad argument passed to CreateSurround"); - } - throw new OpusException("Could not create multistream encoder", ret); - } - return st; - } - - int surround_rate_allocation(int[] out_rates, int frame_size) { - int channel_rate; - int rate_sum = 0; - OpusEncoder ptr = this.encoders[0]; - int Fs = ptr.getSampleRate(); - int stream_offset = this.bitrate_bps > this.layout.nb_channels * 40000 ? 20000 : this.bitrate_bps / this.layout.nb_channels / 2; - stream_offset += 60 * (Fs / frame_size - 50); - int lfe_offset = 3500 + 60 * (Fs / frame_size - 50); - int coupled_ratio = 512; - int lfe_ratio = 32; - if (this.bitrate_bps == -1000) { - channel_rate = Fs + 60 * Fs / frame_size; - } else if (this.bitrate_bps == -1) { - channel_rate = 300000; - } else { - int nb_lfe = this.lfe_stream != -1 ? 1 : 0; - int nb_coupled = this.layout.nb_coupled_streams; - int nb_uncoupled = this.layout.nb_streams - nb_coupled - nb_lfe; - int total = (nb_uncoupled << 8) + coupled_ratio * nb_coupled + nb_lfe * lfe_ratio; - channel_rate = 256 * (this.bitrate_bps - lfe_offset * nb_lfe - stream_offset * (nb_coupled + nb_uncoupled)) / total; - } - for (int i = 0; i < this.layout.nb_streams; ++i) { - out_rates[i] = i < this.layout.nb_coupled_streams ? stream_offset + (channel_rate * coupled_ratio >> 8) : (i != this.lfe_stream ? stream_offset + channel_rate : lfe_offset + (channel_rate * lfe_ratio >> 8)); - out_rates[i] = Inlines.IMAX(out_rates[i], 500); - rate_sum += out_rates[i]; - } - return rate_sum; - } - - int opus_multistream_encode_native(short[] pcm, int pcm_ptr, int analysis_frame_size, byte[] data, int data_ptr, int max_data_bytes, int lsb_depth, int float_api) { - int s; - byte[] tmp_data = new byte[3832]; - OpusRepacketizer rp = new OpusRepacketizer(); - int[] bitrates = new int[256]; - int[] bandLogE = new int[42]; - int[] mem = null; - int[] preemph_mem = null; - if (this.surround != 0) { - preemph_mem = this.preemph_mem; - mem = this.window_mem; - } - int encoder_ptr = 0; - int Fs = this.encoders[encoder_ptr].getSampleRate(); - boolean vbr = this.encoders[encoder_ptr].getUseVBR(); - CeltMode celt_mode = this.encoders[encoder_ptr].GetCeltMode(); - int channels = this.layout.nb_streams + this.layout.nb_coupled_streams; - int delay_compensation = this.encoders[encoder_ptr].getLookahead(); - int frame_size = CodecHelpers.compute_frame_size(pcm, pcm_ptr, analysis_frame_size, this.variable_duration, channels, Fs, this.bitrate_bps, delay_compensation -= Fs / 400, this.subframe_mem, this.encoders[encoder_ptr].analysis.enabled); - if (400 * frame_size < Fs) { - return OpusError.OPUS_BAD_ARG; - } - if (400 * frame_size != Fs && 200 * frame_size != Fs && 100 * frame_size != Fs && 50 * frame_size != Fs && 25 * frame_size != Fs && 50 * frame_size != 3 * Fs) { - return OpusError.OPUS_BAD_ARG; - } - int smallest_packet = this.layout.nb_streams * 2 - 1; - if (max_data_bytes < smallest_packet) { - return OpusError.OPUS_BUFFER_TOO_SMALL; - } - short[] buf = new short[2 * frame_size]; - int[] bandSMR = new int[21 * this.layout.nb_channels]; - if (this.surround != 0) { - OpusMSEncoder.surround_analysis(celt_mode, pcm, pcm_ptr, bandSMR, mem, preemph_mem, frame_size, 120, this.layout.nb_channels, Fs); - } - int rate_sum = this.surround_rate_allocation(bitrates, frame_size); - if (!vbr) { - if (this.bitrate_bps == -1000) { - max_data_bytes = Inlines.IMIN(max_data_bytes, 3 * rate_sum / (24 * Fs / frame_size)); - } else if (this.bitrate_bps != -1) { - max_data_bytes = Inlines.IMIN(max_data_bytes, Inlines.IMAX(smallest_packet, 3 * this.bitrate_bps / (24 * Fs / frame_size))); - } - } - for (s = 0; s < this.layout.nb_streams; ++s) { - OpusEncoder enc = this.encoders[encoder_ptr]; - ++encoder_ptr; - enc.setBitrate(bitrates[s]); - if (this.surround == 0) continue; - int equiv_rate = this.bitrate_bps; - if (frame_size * 50 < Fs) { - equiv_rate -= 60 * (Fs / frame_size - 50) * this.layout.nb_channels; - } - if (equiv_rate > 10000 * this.layout.nb_channels) { - enc.setBandwidth(OpusBandwidth.OPUS_BANDWIDTH_FULLBAND); - } else if (equiv_rate > 7000 * this.layout.nb_channels) { - enc.setBandwidth(OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND); - } else if (equiv_rate > 5000 * this.layout.nb_channels) { - enc.setBandwidth(OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND); - } else { - enc.setBandwidth(OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND); - } - if (s >= this.layout.nb_coupled_streams) continue; - enc.setForceMode(OpusMode.MODE_CELT_ONLY); - enc.setForceChannels(2); - } - encoder_ptr = 0; - int tot_size = 0; - for (s = 0; s < this.layout.nb_streams; ++s) { - int len; - int c2; - int c1; - int i; - rp.Reset(); - OpusEncoder enc = this.encoders[encoder_ptr]; - if (s < this.layout.nb_coupled_streams) { - int left = OpusMultistream.get_left_channel(this.layout, s, -1); - int right = OpusMultistream.get_right_channel(this.layout, s, -1); - OpusMSEncoder.opus_copy_channel_in_short(buf, 0, 2, pcm, pcm_ptr, this.layout.nb_channels, left, frame_size); - OpusMSEncoder.opus_copy_channel_in_short(buf, 1, 2, pcm, pcm_ptr, this.layout.nb_channels, right, frame_size); - ++encoder_ptr; - if (this.surround != 0) { - for (i = 0; i < 21; ++i) { - bandLogE[i] = bandSMR[21 * left + i]; - bandLogE[21 + i] = bandSMR[21 * right + i]; - } - } - c1 = left; - c2 = right; - } else { - int chan = OpusMultistream.get_mono_channel(this.layout, s, -1); - OpusMSEncoder.opus_copy_channel_in_short(buf, 0, 1, pcm, pcm_ptr, this.layout.nb_channels, chan, frame_size); - ++encoder_ptr; - if (this.surround != 0) { - for (i = 0; i < 21; ++i) { - bandLogE[i] = bandSMR[21 * chan + i]; - } - } - c1 = chan; - c2 = -1; - } - if (this.surround != 0) { - enc.SetEnergyMask(bandLogE); - } - int curr_max = max_data_bytes - tot_size; - curr_max -= Inlines.IMAX(0, 2 * (this.layout.nb_streams - s - 1) - 1); - curr_max = Inlines.IMIN(curr_max, 3832); - if (s != this.layout.nb_streams - 1) { - curr_max -= curr_max > 253 ? 2 : 1; - } - if (!vbr && s == this.layout.nb_streams - 1) { - enc.setBitrate(curr_max * (8 * Fs / frame_size)); - } - if ((len = enc.opus_encode_native(buf, 0, frame_size, tmp_data, 0, curr_max, lsb_depth, pcm, pcm_ptr, analysis_frame_size, c1, c2, this.layout.nb_channels, float_api)) < 0) { - return len; - } - rp.addPacket(tmp_data, 0, len); - len = rp.opus_repacketizer_out_range_impl(0, rp.getNumFrames(), data, data_ptr, max_data_bytes - tot_size, s != this.layout.nb_streams - 1 ? 1 : 0, !vbr && s == this.layout.nb_streams - 1 ? 1 : 0); - data_ptr += len; - tot_size += len; - } - return tot_size; - } - - static void opus_copy_channel_in_short(short[] dst, int dst_ptr, int dst_stride, short[] src, int src_ptr, int src_stride, int src_channel, int frame_size) { - for (int i = 0; i < frame_size; ++i) { - dst[dst_ptr + i * dst_stride] = src[i * src_stride + src_channel + src_ptr]; - } - } - - public int encodeMultistream(short[] pcm, int pcm_offset, int frame_size, byte[] outputBuffer, int outputBuffer_offset, int max_data_bytes) { - return this.opus_multistream_encode_native(pcm, pcm_offset, frame_size, outputBuffer, outputBuffer_offset, max_data_bytes, 16, 0); - } - - public int getBitrate() { - int value = 0; - int encoder_ptr = 0; - for (int s = 0; s < this.layout.nb_streams; ++s) { - OpusEncoder enc = this.encoders[encoder_ptr++]; - value += enc.getBitrate(); - } - return value; - } - - public void setBitrate(int value) { - if (value < 0 && value != -1000 && value != -1) { - throw new IllegalArgumentException("Invalid bitrate"); - } - this.bitrate_bps = value; - } - - public OpusApplication getApplication() { - return this.encoders[0].getApplication(); - } - - public void setApplication(OpusApplication value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setApplication(value); - } - } - - public int getForceChannels() { - return this.encoders[0].getForceChannels(); - } - - public void setForceChannels(int value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setForceChannels(value); - } - } - - public OpusBandwidth getMaxBandwidth() { - return this.encoders[0].getMaxBandwidth(); - } - - public void setMaxBandwidth(OpusBandwidth value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setMaxBandwidth(value); - } - } - - public OpusBandwidth getBandwidth() { - return this.encoders[0].getBandwidth(); - } - - public void setBandwidth(OpusBandwidth value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setBandwidth(value); - } - } - - public boolean getUseDTX() { - return this.encoders[0].getUseDTX(); - } - - public void setUseDTX(boolean value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setUseDTX(value); - } - } - - public int getComplexity() { - return this.encoders[0].getComplexity(); - } - - public void setComplexity(int value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setComplexity(value); - } - } - - public OpusMode getForceMode() { - return this.encoders[0].getForceMode(); - } - - public void setForceMode(OpusMode value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setForceMode(value); - } - } - - public boolean getUseInbandFEC() { - return this.encoders[0].getUseInbandFEC(); - } - - public void setUseInbandFEC(boolean value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setUseInbandFEC(value); - } - } - - public int getPacketLossPercent() { - return this.encoders[0].getPacketLossPercent(); - } - - public void setPacketLossPercent(int value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setPacketLossPercent(value); - } - } - - public boolean getUseVBR() { - return this.encoders[0].getUseVBR(); - } - - public void setUseVBR(boolean value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setUseVBR(value); - } - } - - public boolean getUseConstrainedVBR() { - return this.encoders[0].getUseConstrainedVBR(); - } - - public void setUseConstrainedVBR(boolean value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setUseConstrainedVBR(value); - } - } - - public OpusSignal getSignalType() { - return this.encoders[0].getSignalType(); - } - - public void setSignalType(OpusSignal value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setSignalType(value); - } - } - - public int getLookahead() { - return this.encoders[0].getLookahead(); - } - - public int getSampleRate() { - return this.encoders[0].getSampleRate(); - } - - public int getFinalRange() { - int value = 0; - int encoder_ptr = 0; - for (int s = 0; s < this.layout.nb_streams; ++s) { - value ^= this.encoders[encoder_ptr++].getFinalRange(); - } - return value; - } - - public int getLSBDepth() { - return this.encoders[0].getLSBDepth(); - } - - public void setLSBDepth(int value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setLSBDepth(value); - } - } - - public boolean getPredictionDisabled() { - return this.encoders[0].getPredictionDisabled(); - } - - public void setPredictionDisabled(boolean value) { - for (int encoder_ptr = 0; encoder_ptr < this.layout.nb_streams; ++encoder_ptr) { - this.encoders[encoder_ptr].setPredictionDisabled(value); - } - } - - public OpusFramesize getExpertFrameDuration() { - return this.variable_duration; - } - - public void setExpertFrameDuration(OpusFramesize value) { - this.variable_duration = value; - } - - public OpusEncoder getMultistreamEncoderState(int streamId) { - if (streamId >= this.layout.nb_streams) { - throw new IllegalArgumentException("Requested stream doesn't exist"); - } - return this.encoders[streamId]; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMode.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMode.java deleted file mode 100644 index 0dfb454..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMode.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -public enum OpusMode { - MODE_UNKNOWN, - MODE_AUTO, - MODE_SILK_ONLY, - MODE_HYBRID, - MODE_CELT_ONLY; - -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMultistream.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMultistream.java deleted file mode 100644 index 993665f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusMultistream.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.ChannelLayout; - -class OpusMultistream { - OpusMultistream() { - } - - static int validate_layout(ChannelLayout layout) { - int max_channel = layout.nb_streams + layout.nb_coupled_streams; - if (max_channel > 255) { - return 0; - } - for (int i = 0; i < layout.nb_channels; ++i) { - if (layout.mapping[i] < max_channel || layout.mapping[i] == 255) continue; - return 0; - } - return 1; - } - - static int get_left_channel(ChannelLayout layout, int stream_id, int prev) { - int i; - int n = i = prev < 0 ? 0 : prev + 1; - while (i < layout.nb_channels) { - if (layout.mapping[i] == stream_id * 2) { - return i; - } - ++i; - } - return -1; - } - - static int get_right_channel(ChannelLayout layout, int stream_id, int prev) { - int i; - int n = i = prev < 0 ? 0 : prev + 1; - while (i < layout.nb_channels) { - if (layout.mapping[i] == stream_id * 2 + 1) { - return i; - } - ++i; - } - return -1; - } - - static int get_mono_channel(ChannelLayout layout, int stream_id, int prev) { - int i; - int n = i = prev < 0 ? 0 : prev + 1; - while (i < layout.nb_channels) { - if (layout.mapping[i] == stream_id + layout.nb_coupled_streams) { - return i; - } - ++i; - } - return -1; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusPacketInfo.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusPacketInfo.java deleted file mode 100644 index 6870920..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusPacketInfo.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.BoxedValueShort; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.OpusBandwidth; -import de.maxhenkel.voicechat.concentus.OpusBandwidthHelpers; -import de.maxhenkel.voicechat.concentus.OpusDecoder; -import de.maxhenkel.voicechat.concentus.OpusError; -import de.maxhenkel.voicechat.concentus.OpusException; -import de.maxhenkel.voicechat.concentus.OpusMode; -import java.util.ArrayList; -import java.util.List; - -public class OpusPacketInfo { - public byte TOCByte; - public List Frames; - public int PayloadOffset; - - private OpusPacketInfo(byte toc, List frames, int payloadOffset) { - this.TOCByte = toc; - this.Frames = frames; - this.PayloadOffset = payloadOffset; - } - - public static OpusPacketInfo parseOpusPacket(byte[] packet, int packet_offset, int len) throws OpusException { - BoxedValueInt packetOffset; - BoxedValueInt payload_offset; - short[] size; - BoxedValueByte out_toc = new BoxedValueByte(0); - int numFrames = OpusPacketInfo.getNumFrames(packet, packet_offset, len); - byte[][] frames = new byte[numFrames][]; - int error = OpusPacketInfo.opus_packet_parse_impl(packet, packet_offset, len, 0, out_toc, frames, 0, size = new short[numFrames], 0, payload_offset = new BoxedValueInt(0), packetOffset = new BoxedValueInt(0)); - if (error < 0) { - throw new OpusException("An error occurred while parsing the packet", error); - } - ArrayList copiedFrames = new ArrayList(); - for (int c = 0; c < frames.length; ++c) { - Byte[] convertedFrame = new Byte[frames[c].length]; - for (int d = 0; d < convertedFrame.length; ++d) { - convertedFrame[d] = frames[c][d]; - } - copiedFrames.add(convertedFrame); - } - return new OpusPacketInfo(out_toc.Val, copiedFrames, payload_offset.Val); - } - - public static int getNumSamplesPerFrame(byte[] packet, int packet_offset, int Fs) { - int audiosize; - if ((packet[packet_offset] & 0x80) != 0) { - audiosize = packet[packet_offset] >> 3 & 3; - audiosize = (Fs << audiosize) / 400; - } else { - audiosize = (packet[packet_offset] & 0x60) == 96 ? ((packet[packet_offset] & 8) != 0 ? Fs / 50 : Fs / 100) : ((audiosize = packet[packet_offset] >> 3 & 3) == 3 ? Fs * 60 / 1000 : (Fs << audiosize) / 100); - } - return audiosize; - } - - public static OpusBandwidth getBandwidth(byte[] packet, int packet_offset) { - OpusBandwidth bandwidth; - if ((packet[packet_offset] & 0x80) != 0) { - bandwidth = OpusBandwidthHelpers.GetBandwidth(OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) + (packet[packet_offset] >> 5 & 3)); - if (bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { - bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; - } - } else { - bandwidth = (packet[packet_offset] & 0x60) == 96 ? ((packet[packet_offset] & 0x10) != 0 ? OpusBandwidth.OPUS_BANDWIDTH_FULLBAND : OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) : OpusBandwidthHelpers.GetBandwidth(OpusBandwidthHelpers.GetOrdinal(OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) + (packet[packet_offset] >> 5 & 3)); - } - return bandwidth; - } - - public static int getNumEncodedChannels(byte[] packet, int packet_offset) { - return (packet[packet_offset] & 4) != 0 ? 2 : 1; - } - - public static int getNumFrames(byte[] packet, int packet_offset, int len) { - if (len < 1) { - return OpusError.OPUS_BAD_ARG; - } - int count = packet[packet_offset] & 3; - if (count == 0) { - return 1; - } - if (count != 3) { - return 2; - } - if (len < 2) { - return OpusError.OPUS_INVALID_PACKET; - } - return packet[packet_offset + 1] & 0x3F; - } - - public static int getNumSamples(byte[] packet, int packet_offset, int len, int Fs) { - int count = OpusPacketInfo.getNumFrames(packet, packet_offset, len); - if (count < 0) { - return count; - } - int samples = count * OpusPacketInfo.getNumSamplesPerFrame(packet, packet_offset, Fs); - if (samples * 25 > Fs * 3) { - return OpusError.OPUS_INVALID_PACKET; - } - return samples; - } - - public static int getNumSamples(OpusDecoder dec, byte[] packet, int packet_offset, int len) { - return OpusPacketInfo.getNumSamples(packet, packet_offset, len, dec.Fs); - } - - public static OpusMode getEncoderMode(byte[] packet, int packet_offset) { - OpusMode mode = (packet[packet_offset] & 0x80) != 0 ? OpusMode.MODE_CELT_ONLY : ((packet[packet_offset] & 0x60) == 96 ? OpusMode.MODE_HYBRID : OpusMode.MODE_SILK_ONLY); - return mode; - } - - static int encode_size(int size, byte[] data, int data_ptr) { - if (size < 252) { - data[data_ptr] = (byte)(size & 0xFF); - return 1; - } - int dp1 = 252 + (size & 3); - data[data_ptr] = (byte)(dp1 & 0xFF); - data[data_ptr + 1] = (byte)(size - dp1 >> 2); - return 2; - } - - static int parse_size(byte[] data, int data_ptr, int len, BoxedValueShort size) { - if (len < 1) { - size.Val = (short)-1; - return -1; - } - if (Inlines.SignedByteToUnsignedInt(data[data_ptr]) < 252) { - size.Val = (short)Inlines.SignedByteToUnsignedInt(data[data_ptr]); - return 1; - } - if (len < 2) { - size.Val = (short)-1; - return -1; - } - size.Val = (short)(4 * Inlines.SignedByteToUnsignedInt(data[data_ptr + 1]) + Inlines.SignedByteToUnsignedInt(data[data_ptr])); - return 2; - } - - static int opus_packet_parse_impl(byte[] data, int data_ptr, int len, int self_delimited, BoxedValueByte out_toc, byte[][] frames, int frames_ptr, short[] sizes, int sizes_ptr, BoxedValueInt payload_offset, BoxedValueInt packet_offset) { - int i; - int bytes; - BoxedValueShort boxed_size; - int count; - int pad = 0; - int data0 = data_ptr; - out_toc.Val = 0; - payload_offset.Val = 0; - packet_offset.Val = 0; - if (sizes == null || len < 0) { - return OpusError.OPUS_BAD_ARG; - } - if (len == 0) { - return OpusError.OPUS_INVALID_PACKET; - } - int framesize = OpusPacketInfo.getNumSamplesPerFrame(data, data_ptr, 48000); - boolean cbr = false; - byte toc = data[data_ptr++]; - int last_size = --len; - switch (toc & 3) { - case 0: { - count = 1; - break; - } - case 1: { - count = 2; - cbr = true; - if (self_delimited != 0) break; - if ((len & 1) != 0) { - return OpusError.OPUS_INVALID_PACKET; - } - last_size = len / 2; - sizes[sizes_ptr] = (short)last_size; - break; - } - case 2: { - count = 2; - boxed_size = new BoxedValueShort(sizes[sizes_ptr]); - bytes = OpusPacketInfo.parse_size(data, data_ptr, len, boxed_size); - sizes[sizes_ptr] = boxed_size.Val; - if (sizes[sizes_ptr] < 0 || sizes[sizes_ptr] > (len -= bytes)) { - return OpusError.OPUS_INVALID_PACKET; - } - data_ptr += bytes; - last_size = len - sizes[sizes_ptr]; - break; - } - default: { - int ch; - if (len < 1) { - return OpusError.OPUS_INVALID_PACKET; - } - if ((count = (ch = Inlines.SignedByteToUnsignedInt(data[data_ptr++])) & 0x3F) <= 0 || framesize * count > 5760) { - return OpusError.OPUS_INVALID_PACKET; - } - --len; - if ((ch & 0x40) != 0) { - int p; - do { - if (len <= 0) { - return OpusError.OPUS_INVALID_PACKET; - } - p = Inlines.SignedByteToUnsignedInt(data[data_ptr++]); - --len; - int tmp = p == 255 ? 254 : p; - len -= tmp; - pad += tmp; - } while (p == 255); - } - if (len < 0) { - return OpusError.OPUS_INVALID_PACKET; - } - boolean bl = cbr = (ch & 0x80) == 0; - if (!cbr) { - last_size = len; - for (i = 0; i < count - 1; ++i) { - boxed_size = new BoxedValueShort(sizes[sizes_ptr + i]); - bytes = OpusPacketInfo.parse_size(data, data_ptr, len, boxed_size); - sizes[sizes_ptr + i] = boxed_size.Val; - if (sizes[sizes_ptr + i] < 0 || sizes[sizes_ptr + i] > (len -= bytes)) { - return OpusError.OPUS_INVALID_PACKET; - } - data_ptr += bytes; - last_size -= bytes + sizes[sizes_ptr + i]; - } - if (last_size >= 0) break; - return OpusError.OPUS_INVALID_PACKET; - } - if (self_delimited != 0) break; - last_size = len / count; - if (last_size * count != len) { - return OpusError.OPUS_INVALID_PACKET; - } - for (i = 0; i < count - 1; ++i) { - sizes[sizes_ptr + i] = (short)last_size; - } - } - } - if (self_delimited != 0) { - boxed_size = new BoxedValueShort(sizes[sizes_ptr + count - 1]); - bytes = OpusPacketInfo.parse_size(data, data_ptr, len, boxed_size); - sizes[sizes_ptr + count - 1] = boxed_size.Val; - if (sizes[sizes_ptr + count - 1] < 0 || sizes[sizes_ptr + count - 1] > (len -= bytes)) { - return OpusError.OPUS_INVALID_PACKET; - } - data_ptr += bytes; - if (cbr) { - if (sizes[sizes_ptr + count - 1] * count > len) { - return OpusError.OPUS_INVALID_PACKET; - } - for (i = 0; i < count - 1; ++i) { - sizes[sizes_ptr + i] = sizes[sizes_ptr + count - 1]; - } - } else if (bytes + sizes[sizes_ptr + count - 1] > last_size) { - return OpusError.OPUS_INVALID_PACKET; - } - } else { - if (last_size > 1275) { - return OpusError.OPUS_INVALID_PACKET; - } - sizes[sizes_ptr + count - 1] = (short)last_size; - } - payload_offset.Val = data_ptr - data0; - for (i = 0; i < count; ++i) { - if (frames != null) { - frames[frames_ptr + i] = new byte[data.length - data_ptr]; - System.arraycopy(data, data_ptr, frames[frames_ptr + i], 0, data.length - data_ptr); - } - data_ptr += sizes[sizes_ptr + i]; - } - packet_offset.Val = pad + (data_ptr - data0); - out_toc.Val = toc; - return count; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusRepacketizer.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusRepacketizer.java deleted file mode 100644 index 90b91b8..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusRepacketizer.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.OpusError; -import de.maxhenkel.voicechat.concentus.OpusPacketInfo; - -public class OpusRepacketizer { - byte toc = 0; - int nb_frames = 0; - final byte[][] frames = new byte[48][]; - final short[] len = new short[48]; - int framesize = 0; - - public void Reset() { - this.nb_frames = 0; - } - - public OpusRepacketizer() { - this.Reset(); - } - - int opus_repacketizer_cat_impl(byte[] data, int data_ptr, int len, int self_delimited) { - BoxedValueByte dummy_toc = new BoxedValueByte(0); - BoxedValueInt dummy_offset = new BoxedValueInt(0); - if (len < 1) { - return OpusError.OPUS_INVALID_PACKET; - } - if (this.nb_frames == 0) { - this.toc = data[data_ptr]; - this.framesize = OpusPacketInfo.getNumSamplesPerFrame(data, data_ptr, 8000); - } else if ((this.toc & 0xFC) != (data[data_ptr] & 0xFC)) { - return OpusError.OPUS_INVALID_PACKET; - } - int curr_nb_frames = OpusPacketInfo.getNumFrames(data, data_ptr, len); - if (curr_nb_frames < 1) { - return OpusError.OPUS_INVALID_PACKET; - } - if ((curr_nb_frames + this.nb_frames) * this.framesize > 960) { - return OpusError.OPUS_INVALID_PACKET; - } - int ret = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, dummy_toc, this.frames, this.nb_frames, this.len, this.nb_frames, dummy_offset, dummy_offset); - if (ret < 1) { - return ret; - } - this.nb_frames += curr_nb_frames; - return OpusError.OPUS_OK; - } - - public int addPacket(byte[] data, int data_offset, int len) { - return this.opus_repacketizer_cat_impl(data, data_offset, len, 0); - } - - public int getNumFrames() { - return this.nb_frames; - } - - int opus_repacketizer_out_range_impl(int begin, int end, byte[] data, int data_ptr, int maxlen, int self_delimited, int pad) { - int i; - if (begin < 0 || begin >= end || end > this.nb_frames) { - return OpusError.OPUS_BAD_ARG; - } - int count = end - begin; - int tot_size = self_delimited != 0 ? 1 + (this.len[count - 1] >= 252 ? 1 : 0) : 0; - int ptr = data_ptr; - if (count == 1) { - if ((tot_size += this.len[0] + 1) > maxlen) { - return OpusError.OPUS_BUFFER_TOO_SMALL; - } - data[ptr++] = (byte)(this.toc & 0xFC); - } else if (count == 2) { - if (this.len[1] == this.len[0]) { - if ((tot_size += 2 * this.len[0] + 1) > maxlen) { - return OpusError.OPUS_BUFFER_TOO_SMALL; - } - data[ptr++] = (byte)(this.toc & 0xFC | 1); - } else { - if ((tot_size += this.len[0] + this.len[1] + 2 + (this.len[0] >= 252 ? 1 : 0)) > maxlen) { - return OpusError.OPUS_BUFFER_TOO_SMALL; - } - data[ptr++] = (byte)(this.toc & 0xFC | 2); - ptr += OpusPacketInfo.encode_size(this.len[0], data, ptr); - } - } - if (count > 2 || pad != 0 && tot_size < maxlen) { - int pad_amount = 0; - ptr = data_ptr; - tot_size = self_delimited != 0 ? 1 + (this.len[count - 1] >= 252 ? 1 : 0) : 0; - boolean vbr = false; - for (i = 1; i < count; ++i) { - if (this.len[i] == this.len[0]) continue; - vbr = true; - break; - } - if (vbr) { - tot_size += 2; - for (i = 0; i < count - 1; ++i) { - tot_size += 1 + (this.len[i] >= 252 ? 1 : 0) + this.len[i]; - } - if ((tot_size += this.len[count - 1]) > maxlen) { - return OpusError.OPUS_BUFFER_TOO_SMALL; - } - data[ptr++] = (byte)(this.toc & 0xFC | 3); - data[ptr++] = (byte)(count | 0x80); - } else { - if ((tot_size += count * this.len[0] + 2) > maxlen) { - return OpusError.OPUS_BUFFER_TOO_SMALL; - } - data[ptr++] = (byte)(this.toc & 0xFC | 3); - data[ptr++] = (byte)count; - } - int n = pad_amount = pad != 0 ? maxlen - tot_size : 0; - if (pad_amount != 0) { - data[data_ptr + 1] = (byte)(data[data_ptr + 1] | 0x40); - int nb_255s = (pad_amount - 1) / 255; - for (i = 0; i < nb_255s; ++i) { - data[ptr++] = -1; - } - data[ptr++] = (byte)(pad_amount - 255 * nb_255s - 1); - tot_size += pad_amount; - } - if (vbr) { - for (i = 0; i < count - 1; ++i) { - ptr += OpusPacketInfo.encode_size(this.len[i], data, ptr); - } - } - } - if (self_delimited != 0) { - int sdlen = OpusPacketInfo.encode_size(this.len[count - 1], data, ptr); - ptr += sdlen; - } - for (i = begin; i < count + begin; ++i) { - if (data == this.frames[i]) { - Arrays.MemMove(data, 0, ptr, (int)this.len[i]); - } else { - System.arraycopy(this.frames[i], 0, data, ptr, this.len[i]); - } - ptr += this.len[i]; - } - if (pad != 0) { - Arrays.MemSetWithOffset(data, (byte)0, ptr, data_ptr + maxlen - ptr); - } - return tot_size; - } - - public int createPacket(int begin, int end, byte[] data, int data_offset, int maxlen) { - return this.opus_repacketizer_out_range_impl(begin, end, data, data_offset, maxlen, 0, 0); - } - - public int createPacket(byte[] data, int data_offset, int maxlen) { - return this.opus_repacketizer_out_range_impl(0, this.nb_frames, data, data_offset, maxlen, 0, 0); - } - - public static int padPacket(byte[] data, int data_offset, int len, int new_len) { - OpusRepacketizer rp = new OpusRepacketizer(); - if (len < 1) { - return OpusError.OPUS_BAD_ARG; - } - if (len == new_len) { - return OpusError.OPUS_OK; - } - if (len > new_len) { - return OpusError.OPUS_BAD_ARG; - } - rp.Reset(); - Arrays.MemMove(data, data_offset, data_offset + new_len - len, len); - rp.addPacket(data, data_offset + new_len - len, len); - int ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, data_offset, new_len, 0, 1); - if (ret > 0) { - return OpusError.OPUS_OK; - } - return ret; - } - - public static int unpadPacket(byte[] data, int data_offset, int len) { - if (len < 1) { - return OpusError.OPUS_BAD_ARG; - } - OpusRepacketizer rp = new OpusRepacketizer(); - rp.Reset(); - int ret = rp.addPacket(data, data_offset, len); - if (ret < 0) { - return ret; - } - ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, data_offset, len, 0, 0); - Inlines.OpusAssert(ret > 0 && ret <= len); - return ret; - } - - public static int padMultistreamPacket(byte[] data, int data_offset, int len, int new_len, int nb_streams) { - BoxedValueByte dummy_toc = new BoxedValueByte(0); - short[] size = new short[48]; - BoxedValueInt packet_offset = new BoxedValueInt(0); - BoxedValueInt dummy_offset = new BoxedValueInt(0); - if (len < 1) { - return OpusError.OPUS_BAD_ARG; - } - if (len == new_len) { - return OpusError.OPUS_OK; - } - if (len > new_len) { - return OpusError.OPUS_BAD_ARG; - } - int amount = new_len - len; - for (int s = 0; s < nb_streams - 1; ++s) { - if (len <= 0) { - return OpusError.OPUS_INVALID_PACKET; - } - int count = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, 1, dummy_toc, null, 0, size, 0, dummy_offset, packet_offset); - if (count < 0) { - return count; - } - data_offset += packet_offset.Val; - len -= packet_offset.Val; - } - return OpusRepacketizer.padPacket(data, data_offset, len, len + amount); - } - - public static int unpadMultistreamPacket(byte[] data, int data_offset, int len, int nb_streams) { - BoxedValueByte dummy_toc = new BoxedValueByte(0); - short[] size = new short[48]; - BoxedValueInt packet_offset = new BoxedValueInt(0); - BoxedValueInt dummy_offset = new BoxedValueInt(0); - OpusRepacketizer rp = new OpusRepacketizer(); - if (len < 1) { - return OpusError.OPUS_BAD_ARG; - } - int dst = data_offset; - int dst_len = 0; - for (int s = 0; s < nb_streams; ++s) { - int self_delimited = (s != nb_streams ? 1 : 0) - 1; - if (len <= 0) { - return OpusError.OPUS_INVALID_PACKET; - } - rp.Reset(); - int ret = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, self_delimited, dummy_toc, null, 0, size, 0, dummy_offset, packet_offset); - if (ret < 0) { - return ret; - } - ret = rp.opus_repacketizer_cat_impl(data, data_offset, packet_offset.Val, self_delimited); - if (ret < 0) { - return ret; - } - ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, dst, len, self_delimited, 0); - if (ret < 0) { - return ret; - } - dst_len += ret; - dst += ret; - data_offset += packet_offset.Val; - len -= packet_offset.Val; - } - return dst_len; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusSignal.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusSignal.java deleted file mode 100644 index 2c37415..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusSignal.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -public enum OpusSignal { - OPUS_SIGNAL_UNKNOWN, - OPUS_SIGNAL_AUTO, - OPUS_SIGNAL_VOICE, - OPUS_SIGNAL_MUSIC; - -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusTables.java b/source/decompiled/de/maxhenkel/voicechat/concentus/OpusTables.java deleted file mode 100644 index a4cd60a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/OpusTables.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.MLPState; - -class OpusTables { - static final float[] dct_table = new float[]{0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.351851f, 0.33833f, 0.311806f, 0.2733f, 0.224292f, 0.166664f, 0.102631f, 0.034654f, -0.034654f, -0.102631f, -0.166664f, -0.224292f, -0.2733f, -0.311806f, -0.33833f, -0.351851f, 0.34676f, 0.293969f, 0.196424f, 0.068975f, -0.068975f, -0.196424f, -0.293969f, -0.34676f, -0.34676f, -0.293969f, -0.196424f, -0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.34676f, 0.33833f, 0.224292f, 0.034654f, -0.166664f, -0.311806f, -0.351851f, -0.2733f, -0.102631f, 0.102631f, 0.2733f, 0.351851f, 0.311806f, 0.166664f, -0.034654f, -0.224292f, -0.33833f, 0.326641f, 0.135299f, -0.135299f, -0.326641f, -0.326641f, -0.135299f, 0.135299f, 0.326641f, 0.326641f, 0.135299f, -0.135299f, -0.326641f, -0.326641f, -0.135299f, 0.135299f, 0.326641f, 0.311806f, 0.034654f, -0.2733f, -0.33833f, -0.102631f, 0.224292f, 0.351851f, 0.166664f, -0.166664f, -0.351851f, -0.224292f, 0.102631f, 0.33833f, 0.2733f, -0.034654f, -0.311806f, 0.293969f, -0.068975f, -0.34676f, -0.196424f, 0.196424f, 0.34676f, 0.068975f, -0.293969f, -0.293969f, 0.068975f, 0.34676f, 0.196424f, -0.196424f, -0.34676f, -0.068975f, 0.293969f, 0.2733f, -0.166664f, -0.33833f, 0.034654f, 0.351851f, 0.102631f, -0.311806f, -0.224292f, 0.224292f, 0.311806f, -0.102631f, -0.351851f, -0.034654f, 0.33833f, 0.166664f, -0.2733f}; - static final float[] analysis_window = new float[]{4.3E-5f, 1.71E-4f, 3.85E-4f, 6.85E-4f, 0.001071f, 0.001541f, 0.002098f, 0.002739f, 0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f, 0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.02059f, 0.02249f, 0.024472f, 0.026535f, 0.028679f, 0.030904f, 0.03321f, 0.035595f, 0.03806f, 0.040604f, 0.043227f, 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f, 0.070297f, 0.07368f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f, 0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.12408f, 0.128428f, 0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.1606f, 0.165435f, 0.170327f, 0.175276f, 0.18028f, 0.18534f, 0.190453f, 0.195619f, 0.200838f, 0.206107f, 0.211427f, 0.216797f, 0.222215f, 0.22768f, 0.233193f, 0.238751f, 0.244353f, 0.25f, 0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.29067f, 0.296632f, 0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.33928f, 0.345492f, 0.351729f, 0.357992f, 0.36428f, 0.37059f, 0.376923f, 0.383277f, 0.389651f, 0.396044f, 0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f, 0.454249f, 0.46077f, 0.467298f, 0.473832f, 0.48037f, 0.486912f, 0.493455f, 0.5f, 0.506545f, 0.513088f, 0.51963f, 0.526168f, 0.532702f, 0.53923f, 0.545751f, 0.552264f, 0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f, 0.610349f, 0.616723f, 0.623077f, 0.62941f, 0.63572f, 0.642008f, 0.648271f, 0.654508f, 0.66072f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f, 0.70933f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.75f, 0.755647f, 0.761249f, 0.766807f, 0.77232f, 0.777785f, 0.783203f, 0.788573f, 0.793893f, 0.799162f, 0.804381f, 0.809547f, 0.81466f, 0.81972f, 0.824724f, 0.829673f, 0.834565f, 0.8394f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f, 0.87592f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f, 0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.92632f, 0.929703f, 0.933013f, 0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f, 0.959396f, 0.96194f, 0.964405f, 0.96679f, 0.969096f, 0.971321f, 0.973465f, 0.975528f, 0.97751f, 0.97941f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f, 0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f, 0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.0f}; - static final int[] tbands = new int[]{2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120}; - static final int[] extra_bands = new int[]{1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200}; - static final float[] weights = new float[]{-0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f, -0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f, -0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f, 0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f, 0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f, 24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f, -0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f, -0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f, -0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f, 1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f, 15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f, 0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f, -0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f, 0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f, 0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f, -1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f, -0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f, -0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 9.90594E-4f, 0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f, -0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f, 2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f, 0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f, -0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f, 0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f, 0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f, -4.60683f, 1.4697f, 0.335845f, -1.81905f, -30.1699f, 5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f, -0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f, -0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f, -0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f, 1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f, -7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f, -0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f, 0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f, 0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f, -0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f, 10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f, -0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f, -0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f, -0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f, 0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f, -0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f, 0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f, 0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f, -0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f, 0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f, -0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f, -0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f, -0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f, -0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f, -0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f, 5.8427f, -0.38075f, 0.221894f, -1.41934f, -1879430.0f, 1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f, 0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f, -0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f, 0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f, -0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f, -975268.0f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f, 0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f, -0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f, -2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f, 0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f, -6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f, 0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f, -0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f, -0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f, 0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f, -0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f, 0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f, -0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f, 0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f, -2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f, 4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f, 0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f, -0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f, 0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f, 0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f, 3.95279f, 1.89068f, 0.486087f, -11.3343f, 3941600.0f, -0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f, 0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f, 0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f, 0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f, 4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f, -1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f, 3.87308f, 3.52558f}; - static final int[] topo = new int[]{25, 15, 2}; - static final MLPState net = new MLPState(); - static final float[] tansig_table; - static final int[] mono_voice_bandwidth_thresholds; - static final int[] mono_music_bandwidth_thresholds; - static final int[] stereo_voice_bandwidth_thresholds; - static final int[] stereo_music_bandwidth_thresholds; - public static final int stereo_voice_threshold = 30000; - public static final int stereo_music_threshold = 30000; - static final int[][] mode_thresholds; - - OpusTables() { - } - - static { - OpusTables.net.layers = 3; - OpusTables.net.topo = topo; - OpusTables.net.weights = weights; - tansig_table = new float[]{0.0f, 0.039979f, 0.07983f, 0.119427f, 0.158649f, 0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f, 0.379949f, 0.413644f, 0.446244f, 0.4777f, 0.507977f, 0.53705f, 0.5649f, 0.591519f, 0.616909f, 0.641077f, 0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f, 0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.82104f, 0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, 0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.91542f, 0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f, 0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.96109f, 0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f, 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f, 0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, 0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.99202f, 0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f, 0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f, 0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.99759f, 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f, 0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, 0.999f, 0.999076f, 0.999147f, 0.999213f, 0.999273f, 0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f, 0.99955f, 0.999585f, 0.999617f, 0.999646f, 0.999673f, 0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f, 0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f, 0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, 0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f, 0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f, 0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.99997f, 0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.99998f, 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f, 0.999988f, 0.999989f, 0.99999f, 0.99999f, 0.999991f, 0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f, 0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f, 0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; - mono_voice_bandwidth_thresholds = new int[]{11000, 1000, 14000, 1000, 17000, 1000, 21000, 2000}; - mono_music_bandwidth_thresholds = new int[]{12000, 1000, 15000, 1000, 18000, 2000, 22000, 2000}; - stereo_voice_bandwidth_thresholds = new int[]{11000, 1000, 14000, 1000, 21000, 2000, 28000, 2000}; - stereo_music_bandwidth_thresholds = new int[]{12000, 1000, 18000, 2000, 21000, 2000, 30000, 2000}; - mode_thresholds = new int[][]{{64000, 16000}, {36000, 16000}}; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/PLC.java b/source/decompiled/de/maxhenkel/voicechat/concentus/PLC.java deleted file mode 100644 index 9ff9d1b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/PLC.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BWExpander; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.LPCInversePredGain; -import de.maxhenkel.voicechat.concentus.PLCStruct; -import de.maxhenkel.voicechat.concentus.SilkChannelDecoder; -import de.maxhenkel.voicechat.concentus.SilkDecoderControl; -import de.maxhenkel.voicechat.concentus.SumSqrShift; - -class PLC { - private static final int NB_ATT = 2; - private static final short[] HARM_ATT_Q15 = new short[]{32440, 31130}; - private static final short[] PLC_RAND_ATTENUATE_V_Q15 = new short[]{31130, 26214}; - private static final short[] PLC_RAND_ATTENUATE_UV_Q15 = new short[]{32440, 29491}; - - PLC() { - } - - static void silk_PLC_Reset(SilkChannelDecoder psDec) { - psDec.sPLC.pitchL_Q8 = Inlines.silk_LSHIFT(psDec.frame_length, 7); - psDec.sPLC.prevGain_Q16[0] = 65536; - psDec.sPLC.prevGain_Q16[1] = 65536; - psDec.sPLC.subfr_length = 20; - psDec.sPLC.nb_subfr = 2; - } - - static void silk_PLC(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, short[] frame, int frame_ptr, int lost) { - if (psDec.fs_kHz != psDec.sPLC.fs_kHz) { - PLC.silk_PLC_Reset(psDec); - psDec.sPLC.fs_kHz = psDec.fs_kHz; - } - if (lost != 0) { - PLC.silk_PLC_conceal(psDec, psDecCtrl, frame, frame_ptr); - ++psDec.lossCnt; - } else { - PLC.silk_PLC_update(psDec, psDecCtrl); - } - } - - static void silk_PLC_update(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl) { - PLCStruct psPLC = psDec.sPLC; - psDec.prevSignalType = psDec.indices.signalType; - int LTP_Gain_Q14 = 0; - if (psDec.indices.signalType == 2) { - int i; - for (int j = 0; j * psDec.subfr_length < psDecCtrl.pitchL[psDec.nb_subfr - 1] && j != psDec.nb_subfr; ++j) { - int temp_LTP_Gain_Q14 = 0; - for (i = 0; i < 5; ++i) { - temp_LTP_Gain_Q14 += psDecCtrl.LTPCoef_Q14[(psDec.nb_subfr - 1 - j) * 5 + i]; - } - if (temp_LTP_Gain_Q14 <= LTP_Gain_Q14) continue; - LTP_Gain_Q14 = temp_LTP_Gain_Q14; - System.arraycopy(psDecCtrl.LTPCoef_Q14, Inlines.silk_SMULBB(psDec.nb_subfr - 1 - j, 5), psPLC.LTPCoef_Q14, 0, 5); - psPLC.pitchL_Q8 = Inlines.silk_LSHIFT(psDecCtrl.pitchL[psDec.nb_subfr - 1 - j], 8); - } - Arrays.MemSet(psPLC.LTPCoef_Q14, (short)0, 5); - psPLC.LTPCoef_Q14[2] = (short)LTP_Gain_Q14; - if (LTP_Gain_Q14 < 11469) { - int tmp = Inlines.silk_LSHIFT(11469, 10); - int scale_Q10 = Inlines.silk_DIV32(tmp, Inlines.silk_max(LTP_Gain_Q14, 1)); - for (i = 0; i < 5; ++i) { - psPLC.LTPCoef_Q14[i] = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(psPLC.LTPCoef_Q14[i], scale_Q10), 10); - } - } else if (LTP_Gain_Q14 > 15565) { - int tmp = Inlines.silk_LSHIFT(15565, 14); - int scale_Q14 = Inlines.silk_DIV32(tmp, Inlines.silk_max(LTP_Gain_Q14, 1)); - for (i = 0; i < 5; ++i) { - psPLC.LTPCoef_Q14[i] = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(psPLC.LTPCoef_Q14[i], scale_Q14), 14); - } - } - } else { - psPLC.pitchL_Q8 = Inlines.silk_LSHIFT(Inlines.silk_SMULBB(psDec.fs_kHz, 18), 8); - Arrays.MemSet(psPLC.LTPCoef_Q14, (short)0, 5); - } - System.arraycopy(psDecCtrl.PredCoef_Q12[1], 0, psPLC.prevLPC_Q12, 0, psDec.LPC_order); - psPLC.prevLTP_scale_Q14 = (short)psDecCtrl.LTP_scale_Q14; - System.arraycopy(psDecCtrl.Gains_Q16, psDec.nb_subfr - 2, psPLC.prevGain_Q16, 0, 2); - psPLC.subfr_length = psDec.subfr_length; - psPLC.nb_subfr = psDec.nb_subfr; - } - - static void silk_PLC_energy(BoxedValueInt energy1, BoxedValueInt shift1, BoxedValueInt energy2, BoxedValueInt shift2, int[] exc_Q14, int[] prevGain_Q10, int subfr_length, int nb_subfr) { - int exc_buf_ptr = 0; - short[] exc_buf = new short[2 * subfr_length]; - for (int k = 0; k < 2; ++k) { - for (int i = 0; i < subfr_length; ++i) { - exc_buf[exc_buf_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(Inlines.silk_SMULWW(exc_Q14[i + (k + nb_subfr - 2) * subfr_length], prevGain_Q10[k]), 8)); - } - exc_buf_ptr += subfr_length; - } - SumSqrShift.silk_sum_sqr_shift(energy1, shift1, exc_buf, subfr_length); - SumSqrShift.silk_sum_sqr_shift(energy2, shift2, exc_buf, subfr_length, subfr_length); - } - - static void silk_PLC_conceal(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, short[] frame, int frame_ptr) { - int j; - int i; - BoxedValueInt energy1 = new BoxedValueInt(0); - BoxedValueInt energy2 = new BoxedValueInt(0); - BoxedValueInt shift1 = new BoxedValueInt(0); - BoxedValueInt shift2 = new BoxedValueInt(0); - short[] sLTP = new short[psDec.ltp_mem_length]; - int[] sLTP_Q14 = new int[psDec.ltp_mem_length + psDec.frame_length]; - PLCStruct psPLC = psDec.sPLC; - int[] prevGain_Q10 = new int[]{Inlines.silk_RSHIFT(psPLC.prevGain_Q16[0], 6), Inlines.silk_RSHIFT(psPLC.prevGain_Q16[1], 6)}; - if (psDec.first_frame_after_reset != 0) { - Arrays.MemSet(psPLC.prevLPC_Q12, (short)0, 16); - } - PLC.silk_PLC_energy(energy1, shift1, energy2, shift2, psDec.exc_Q14, prevGain_Q10, psDec.subfr_length, psDec.nb_subfr); - int rand_ptr = Inlines.silk_RSHIFT(energy1.Val, shift2.Val) < Inlines.silk_RSHIFT(energy2.Val, shift1.Val) ? Inlines.silk_max_int(0, (psPLC.nb_subfr - 1) * psPLC.subfr_length - 128) : Inlines.silk_max_int(0, psPLC.nb_subfr * psPLC.subfr_length - 128); - short[] B_Q14 = psPLC.LTPCoef_Q14; - short rand_scale_Q14 = psPLC.randScale_Q14; - short harm_Gain_Q15 = HARM_ATT_Q15[Inlines.silk_min_int(1, psDec.lossCnt)]; - int rand_Gain_Q15 = psDec.prevSignalType == 2 ? PLC_RAND_ATTENUATE_V_Q15[Inlines.silk_min_int(1, psDec.lossCnt)] : PLC_RAND_ATTENUATE_UV_Q15[Inlines.silk_min_int(1, psDec.lossCnt)]; - BWExpander.silk_bwexpander(psPLC.prevLPC_Q12, psDec.LPC_order, 64881); - if (psDec.lossCnt == 0) { - rand_scale_Q14 = 16384; - if (psDec.prevSignalType == 2) { - for (i = 0; i < 5; ++i) { - rand_scale_Q14 = (short)(rand_scale_Q14 - B_Q14[i]); - } - rand_scale_Q14 = Inlines.silk_max_16((short)3277, rand_scale_Q14); - rand_scale_Q14 = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(rand_scale_Q14, psPLC.prevLTP_scale_Q14), 14); - } else { - int invGain_Q30 = LPCInversePredGain.silk_LPC_inverse_pred_gain(psPLC.prevLPC_Q12, psDec.LPC_order); - int down_scale_Q30 = Inlines.silk_min_32(Inlines.silk_RSHIFT(0x40000000, 3), invGain_Q30); - down_scale_Q30 = Inlines.silk_max_32(Inlines.silk_RSHIFT(0x40000000, 8), down_scale_Q30); - down_scale_Q30 = Inlines.silk_LSHIFT(down_scale_Q30, 3); - rand_Gain_Q15 = Inlines.silk_RSHIFT(Inlines.silk_SMULWB(down_scale_Q30, rand_Gain_Q15), 14); - } - } - int rand_seed = psPLC.rand_seed; - int lag = Inlines.silk_RSHIFT_ROUND(psPLC.pitchL_Q8, 8); - int sLTP_buf_idx = psDec.ltp_mem_length; - int idx = psDec.ltp_mem_length - lag - psDec.LPC_order - 2; - Inlines.OpusAssert(idx > 0); - Filters.silk_LPC_analysis_filter(sLTP, idx, psDec.outBuf, idx, psPLC.prevLPC_Q12, 0, psDec.ltp_mem_length - idx, psDec.LPC_order); - int inv_gain_Q30 = Inlines.silk_INVERSE32_varQ(psPLC.prevGain_Q16[1], 46); - inv_gain_Q30 = Inlines.silk_min(inv_gain_Q30, 0x3FFFFFFF); - for (i = idx + psDec.LPC_order; i < psDec.ltp_mem_length; ++i) { - sLTP_Q14[i] = Inlines.silk_SMULWB(inv_gain_Q30, sLTP[i]); - } - for (int k = 0; k < psDec.nb_subfr; ++k) { - int pred_lag_ptr = sLTP_buf_idx - lag + 2; - for (i = 0; i < psDec.subfr_length; ++i) { - int LTP_pred_Q12 = 2; - LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr], B_Q14[0]); - LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 1], B_Q14[1]); - LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 2], B_Q14[2]); - LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 3], B_Q14[3]); - LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 4], B_Q14[4]); - ++pred_lag_ptr; - rand_seed = Inlines.silk_RAND(rand_seed); - idx = Inlines.silk_RSHIFT(rand_seed, 25) & 0x7F; - sLTP_Q14[sLTP_buf_idx] = Inlines.silk_LSHIFT32(Inlines.silk_SMLAWB(LTP_pred_Q12, psDec.exc_Q14[rand_ptr + idx], rand_scale_Q14), 2); - ++sLTP_buf_idx; - } - for (j = 0; j < 5; ++j) { - B_Q14[j] = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(harm_Gain_Q15, B_Q14[j]), 15); - } - rand_scale_Q14 = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(rand_scale_Q14, rand_Gain_Q15), 15); - psPLC.pitchL_Q8 = Inlines.silk_SMLAWB(psPLC.pitchL_Q8, psPLC.pitchL_Q8, 655); - psPLC.pitchL_Q8 = Inlines.silk_min_32(psPLC.pitchL_Q8, Inlines.silk_LSHIFT(Inlines.silk_SMULBB(18, psDec.fs_kHz), 8)); - lag = Inlines.silk_RSHIFT_ROUND(psPLC.pitchL_Q8, 8); - } - int sLPC_Q14_ptr = psDec.ltp_mem_length - 16; - System.arraycopy(psDec.sLPC_Q14_buf, 0, sLTP_Q14, sLPC_Q14_ptr, 16); - Inlines.OpusAssert(psDec.LPC_order >= 10); - for (i = 0; i < psDec.frame_length; ++i) { - int sLPCmaxi = sLPC_Q14_ptr + 16 + i; - int LPC_pred_Q10 = Inlines.silk_RSHIFT(psDec.LPC_order, 1); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 1], psPLC.prevLPC_Q12[0]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 2], psPLC.prevLPC_Q12[1]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 3], psPLC.prevLPC_Q12[2]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 4], psPLC.prevLPC_Q12[3]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 5], psPLC.prevLPC_Q12[4]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 6], psPLC.prevLPC_Q12[5]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 7], psPLC.prevLPC_Q12[6]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 8], psPLC.prevLPC_Q12[7]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 9], psPLC.prevLPC_Q12[8]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 10], psPLC.prevLPC_Q12[9]); - for (j = 10; j < psDec.LPC_order; ++j) { - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - j - 1], psPLC.prevLPC_Q12[j]); - } - sLTP_Q14[sLPCmaxi] = Inlines.silk_ADD_LSHIFT32(sLTP_Q14[sLPCmaxi], LPC_pred_Q10, 4); - frame[frame_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(sLTP_Q14[sLPCmaxi], prevGain_Q10[1]), 8))); - } - System.arraycopy(sLTP_Q14, sLPC_Q14_ptr + psDec.frame_length, psDec.sLPC_Q14_buf, 0, 16); - psPLC.rand_seed = rand_seed; - psPLC.randScale_Q14 = rand_scale_Q14; - for (i = 0; i < 4; ++i) { - psDecCtrl.pitchL[i] = lag; - } - } - - static void silk_PLC_glue_frames(SilkChannelDecoder psDec, short[] frame, int frame_ptr, int length) { - BoxedValueInt energy_shift = new BoxedValueInt(0); - BoxedValueInt energy = new BoxedValueInt(0); - PLCStruct psPLC = psDec.sPLC; - if (psDec.lossCnt != 0) { - BoxedValueInt boxed_conc_e = new BoxedValueInt(0); - BoxedValueInt boxed_conc_shift = new BoxedValueInt(0); - SumSqrShift.silk_sum_sqr_shift(boxed_conc_e, boxed_conc_shift, frame, frame_ptr, length); - psPLC.conc_energy = boxed_conc_e.Val; - psPLC.conc_energy_shift = boxed_conc_shift.Val; - psPLC.last_frame_lost = 1; - } else { - if (psDec.sPLC.last_frame_lost != 0) { - SumSqrShift.silk_sum_sqr_shift(energy, energy_shift, frame, frame_ptr, length); - if (energy_shift.Val > psPLC.conc_energy_shift) { - psPLC.conc_energy = Inlines.silk_RSHIFT(psPLC.conc_energy, energy_shift.Val - psPLC.conc_energy_shift); - } else if (energy_shift.Val < psPLC.conc_energy_shift) { - energy.Val = Inlines.silk_RSHIFT(energy.Val, psPLC.conc_energy_shift - energy_shift.Val); - } - if (energy.Val > psPLC.conc_energy) { - int LZ = Inlines.silk_CLZ32(psPLC.conc_energy); - psPLC.conc_energy = Inlines.silk_LSHIFT(psPLC.conc_energy, --LZ); - energy.Val = Inlines.silk_RSHIFT(energy.Val, Inlines.silk_max_32(24 - LZ, 0)); - int frac_Q24 = Inlines.silk_DIV32(psPLC.conc_energy, Inlines.silk_max(energy.Val, 1)); - int gain_Q16 = Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(frac_Q24), 4); - int slope_Q16 = Inlines.silk_DIV32_16(65536 - gain_Q16, length); - slope_Q16 = Inlines.silk_LSHIFT(slope_Q16, 2); - for (int i = frame_ptr; i < frame_ptr + length; ++i) { - frame[i] = (short)Inlines.silk_SMULWB(gain_Q16, frame[i]); - if ((gain_Q16 += slope_Q16) > 65536) break; - } - } - } - psPLC.last_frame_lost = 0; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/PLCStruct.java b/source/decompiled/de/maxhenkel/voicechat/concentus/PLCStruct.java deleted file mode 100644 index 91ec03b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/PLCStruct.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class PLCStruct { - int pitchL_Q8 = 0; - final short[] LTPCoef_Q14 = new short[5]; - final short[] prevLPC_Q12 = new short[16]; - int last_frame_lost = 0; - int rand_seed = 0; - short randScale_Q14 = 0; - int conc_energy = 0; - int conc_energy_shift = 0; - short prevLTP_scale_Q14 = 0; - final int[] prevGain_Q16 = new int[2]; - int fs_kHz = 0; - int nb_subfr = 0; - int subfr_length = 0; - - PLCStruct() { - } - - void Reset() { - this.pitchL_Q8 = 0; - Arrays.MemSet(this.LTPCoef_Q14, (short)0, 5); - Arrays.MemSet(this.prevLPC_Q12, (short)0, 16); - this.last_frame_lost = 0; - this.rand_seed = 0; - this.randScale_Q14 = 0; - this.conc_energy = 0; - this.conc_energy_shift = 0; - this.prevLTP_scale_Q14 = 0; - Arrays.MemSet(this.prevGain_Q16, 0, 2); - this.fs_kHz = 0; - this.nb_subfr = 0; - this.subfr_length = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Pitch.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Pitch.java deleted file mode 100644 index b578c0b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Pitch.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Autocorrelation; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltLPC; -import de.maxhenkel.voicechat.concentus.CeltPitchXCorr; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Kernels; - -class Pitch { - private static final int[] second_check = new int[]{0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}; - - Pitch() { - } - - static void find_best_pitch(int[] xcorr, int[] y, int len, int max_pitch, int[] best_pitch, int yshift, int maxcorr) { - int Syy = 1; - int xshift = Inlines.celt_ilog2(maxcorr) - 14; - int best_num_0 = -1; - int best_num_1 = -1; - int best_den_0 = 0; - int best_den_1 = 0; - best_pitch[0] = 0; - best_pitch[1] = 1; - for (int j = 0; j < len; ++j) { - Syy = Inlines.ADD32(Syy, Inlines.SHR32(Inlines.MULT16_16(y[j], y[j]), yshift)); - } - for (int i = 0; i < max_pitch; ++i) { - short xcorr16; - int num; - if (xcorr[i] > 0 && Inlines.MULT16_32_Q15(num = Inlines.MULT16_16_Q15((int)(xcorr16 = Inlines.EXTRACT16(Inlines.VSHR32(xcorr[i], xshift))), (int)xcorr16), best_den_1) > Inlines.MULT16_32_Q15(best_num_1, Syy)) { - if (Inlines.MULT16_32_Q15(num, best_den_0) > Inlines.MULT16_32_Q15(best_num_0, Syy)) { - best_num_1 = best_num_0; - best_den_1 = best_den_0; - best_pitch[1] = best_pitch[0]; - best_num_0 = num; - best_den_0 = Syy; - best_pitch[0] = i; - } else { - best_num_1 = num; - best_den_1 = Syy; - best_pitch[1] = i; - } - } - Syy += Inlines.SHR32(Inlines.MULT16_16(y[i + len], y[i + len]), yshift) - Inlines.SHR32(Inlines.MULT16_16(y[i], y[i]), yshift); - Syy = Inlines.MAX32(1, Syy); - } - } - - static void celt_fir5(int[] x, int[] num, int[] y, int N, int[] mem) { - int num0 = num[0]; - int num1 = num[1]; - int num2 = num[2]; - int num3 = num[3]; - int num4 = num[4]; - int mem0 = mem[0]; - int mem1 = mem[1]; - int mem2 = mem[2]; - int mem3 = mem[3]; - int mem4 = mem[4]; - for (int i = 0; i < N; ++i) { - int sum = Inlines.SHL32(Inlines.EXTEND32(x[i]), 12); - sum = Inlines.MAC16_16(sum, num0, mem0); - sum = Inlines.MAC16_16(sum, num1, mem1); - sum = Inlines.MAC16_16(sum, num2, mem2); - sum = Inlines.MAC16_16(sum, num3, mem3); - sum = Inlines.MAC16_16(sum, num4, mem4); - mem4 = mem3; - mem3 = mem2; - mem2 = mem1; - mem1 = mem0; - mem0 = x[i]; - y[i] = Inlines.ROUND16(sum, 12); - } - mem[0] = mem0; - mem[1] = mem1; - mem[2] = mem2; - mem[3] = mem3; - mem[4] = mem4; - } - - static void pitch_downsample(int[][] x, int[] x_lp, int len, int C) { - int i; - int shift; - int[] ac = new int[5]; - int tmp = Short.MAX_VALUE; - int[] lpc = new int[4]; - int[] mem = new int[]{0, 0, 0, 0, 0}; - int[] lpc2 = new int[5]; - int c1 = 26214; - int maxabs = Inlines.celt_maxabs32(x[0], 0, len); - if (C == 2) { - int maxabs_1 = Inlines.celt_maxabs32(x[1], 0, len); - maxabs = Inlines.MAX32(maxabs, maxabs_1); - } - if (maxabs < 1) { - maxabs = 1; - } - if ((shift = Inlines.celt_ilog2(maxabs) - 10) < 0) { - shift = 0; - } - if (C == 2) { - ++shift; - } - int halflen = len >> 1; - for (i = 1; i < halflen; ++i) { - x_lp[i] = Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[0][2 * i - 1] + x[0][2 * i + 1]) + x[0][2 * i]), shift); - } - x_lp[0] = Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[0][1]) + x[0][0]), shift); - if (C == 2) { - for (i = 1; i < halflen; ++i) { - int n = i; - x_lp[n] = x_lp[n] + Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[1][2 * i - 1] + x[1][2 * i + 1]) + x[1][2 * i]), shift); - } - x_lp[0] = x_lp[0] + Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[1][1]) + x[1][0]), shift); - } - Autocorrelation._celt_autocorr(x_lp, ac, null, 0, 4, halflen); - ac[0] = ac[0] + Inlines.SHR32(ac[0], 13); - for (i = 1; i <= 4; ++i) { - int n = i; - ac[n] = ac[n] - Inlines.MULT16_32_Q15(2 * i * i, ac[i]); - } - CeltLPC.celt_lpc(lpc, ac, 4); - for (i = 0; i < 4; ++i) { - tmp = Inlines.MULT16_16_Q15(29491, tmp); - lpc[i] = Inlines.MULT16_16_Q15(lpc[i], tmp); - } - lpc2[0] = lpc[0] + 3277; - lpc2[1] = lpc[1] + Inlines.MULT16_16_Q15(c1, lpc[0]); - lpc2[2] = lpc[2] + Inlines.MULT16_16_Q15(c1, lpc[1]); - lpc2[3] = lpc[3] + Inlines.MULT16_16_Q15(c1, lpc[2]); - lpc2[4] = Inlines.MULT16_16_Q15(c1, lpc[3]); - Pitch.celt_fir5(x_lp, lpc2, x_lp, halflen, mem); - } - - static void pitch_search(int[] x_lp, int x_lp_ptr, int[] y, int len, int max_pitch, BoxedValueInt pitch) { - int b; - int a; - int c; - int ymax; - int j; - int[] best_pitch = new int[]{0, 0}; - int shift = 0; - Inlines.OpusAssert(len > 0); - Inlines.OpusAssert(max_pitch > 0); - int lag = len + max_pitch; - int[] x_lp4 = new int[len >> 2]; - int[] y_lp4 = new int[lag >> 2]; - int[] xcorr = new int[max_pitch >> 1]; - for (j = 0; j < len >> 2; ++j) { - x_lp4[j] = x_lp[x_lp_ptr + 2 * j]; - } - for (j = 0; j < lag >> 2; ++j) { - y_lp4[j] = y[2 * j]; - } - int xmax = Inlines.celt_maxabs32(x_lp4, 0, len >> 2); - shift = Inlines.celt_ilog2(Inlines.MAX32(1, Inlines.MAX32(xmax, ymax = Inlines.celt_maxabs32(y_lp4, 0, lag >> 2)))) - 11; - if (shift > 0) { - for (j = 0; j < len >> 2; ++j) { - x_lp4[j] = Inlines.SHR16(x_lp4[j], shift); - } - for (j = 0; j < lag >> 2; ++j) { - y_lp4[j] = Inlines.SHR16(y_lp4[j], shift); - } - shift *= 2; - } else { - shift = 0; - } - int maxcorr = CeltPitchXCorr.pitch_xcorr(x_lp4, y_lp4, xcorr, len >> 2, max_pitch >> 2); - Pitch.find_best_pitch(xcorr, y_lp4, len >> 2, max_pitch >> 2, best_pitch, 0, maxcorr); - maxcorr = 1; - for (int i = 0; i < max_pitch >> 1; ++i) { - xcorr[i] = 0; - if (Inlines.abs(i - 2 * best_pitch[0]) > 2 && Inlines.abs(i - 2 * best_pitch[1]) > 2) continue; - int sum = 0; - for (j = 0; j < len >> 1; ++j) { - sum += Inlines.SHR32(Inlines.MULT16_16(x_lp[x_lp_ptr + j], y[i + j]), shift); - } - xcorr[i] = Inlines.MAX32(-1, sum); - maxcorr = Inlines.MAX32(maxcorr, sum); - } - Pitch.find_best_pitch(xcorr, y, len >> 1, max_pitch >> 1, best_pitch, shift + 1, maxcorr); - int offset = best_pitch[0] > 0 && best_pitch[0] < (max_pitch >> 1) - 1 ? ((c = xcorr[best_pitch[0] + 1]) - (a = xcorr[best_pitch[0] - 1]) > Inlines.MULT16_32_Q15((short)22938, (b = xcorr[best_pitch[0]]) - a) ? 1 : (a - c > Inlines.MULT16_32_Q15((short)22938, b - c) ? -1 : 0)) : 0; - pitch.Val = 2 * best_pitch[0] - offset; - } - - static int remove_doubling(int[] x, int maxperiod, int minperiod, int N, BoxedValueInt T0_, int prev_period, int prev_gain) { - int k; - int g; - int T0; - int[] xcorr = new int[3]; - int minperiod0 = minperiod; - minperiod /= 2; - T0_.Val /= 2; - prev_period /= 2; - N /= 2; - int x_ptr = maxperiod /= 2; - if (T0_.Val >= maxperiod) { - T0_.Val = maxperiod - 1; - } - int T = T0 = T0_.Val; - int[] yy_lookup = new int[maxperiod + 1]; - BoxedValueInt boxed_xx = new BoxedValueInt(0); - BoxedValueInt boxed_xy = new BoxedValueInt(0); - BoxedValueInt boxed_xy2 = new BoxedValueInt(0); - Kernels.dual_inner_prod(x, x_ptr, x, x_ptr, x, x_ptr - T0, N, boxed_xx, boxed_xy); - int xx = boxed_xx.Val; - int xy = boxed_xy.Val; - yy_lookup[0] = xx; - int yy = xx; - for (int i = 1; i <= maxperiod; ++i) { - int xi = x_ptr - i; - yy = yy + Inlines.MULT16_16(x[xi], x[xi]) - Inlines.MULT16_16(x[xi + N], x[xi + N]); - yy_lookup[i] = Inlines.MAX32(0, yy); - } - yy = yy_lookup[T0]; - int best_xy = xy; - int best_yy = yy; - int x2y2 = 1 + Inlines.HALF32(Inlines.MULT32_32_Q31(xx, yy)); - int sh = Inlines.celt_ilog2(x2y2) >> 1; - int t = Inlines.VSHR32(x2y2, 2 * (sh - 7)); - int g0 = g = Inlines.VSHR32(Inlines.MULT16_32_Q15(Inlines.celt_rsqrt_norm(t), xy), sh + 1); - for (k = 2; k <= 15; ++k) { - int cont = 0; - int T1 = Inlines.celt_udiv(2 * T0 + k, 2 * k); - if (T1 < minperiod) break; - int T1b = k == 2 ? (T1 + T0 > maxperiod ? T0 : T0 + T1) : Inlines.celt_udiv(2 * second_check[k] * T0 + k, 2 * k); - Kernels.dual_inner_prod(x, x_ptr, x, x_ptr - T1, x, x_ptr - T1b, N, boxed_xy, boxed_xy2); - xy = boxed_xy.Val; - int xy2 = boxed_xy2.Val; - yy = yy_lookup[T1] + yy_lookup[T1b]; - int x2y22 = 1 + Inlines.MULT32_32_Q31(xx, yy); - int sh2 = Inlines.celt_ilog2(x2y22) >> 1; - int t2 = Inlines.VSHR32(x2y22, 2 * (sh2 - 7)); - int g1 = Inlines.VSHR32(Inlines.MULT16_32_Q15(Inlines.celt_rsqrt_norm(t2), xy += xy2), sh2 + 1); - cont = Inlines.abs(T1 - prev_period) <= 1 ? prev_gain : (Inlines.abs(T1 - prev_period) <= 2 && 5 * k * k < T0 ? Inlines.HALF16(prev_gain) : 0); - int thresh = Inlines.MAX16(9830, Inlines.MULT16_16_Q15(22938, g0) - cont); - if (T1 < 3 * minperiod) { - thresh = Inlines.MAX16(13107, Inlines.MULT16_16_Q15(27853, g0) - cont); - } else if (T1 < 2 * minperiod) { - thresh = Inlines.MAX16(16384, Inlines.MULT16_16_Q15(29491, g0) - cont); - } - if (g1 <= thresh) continue; - best_xy = xy; - best_yy = yy; - T = T1; - g = g1; - } - int pg = best_yy <= (best_xy = Inlines.MAX32(0, best_xy)) ? Short.MAX_VALUE : Inlines.SHR32(Inlines.frac_div32(best_xy, best_yy + 1), 16); - for (k = 0; k < 3; ++k) { - xcorr[k] = Kernels.celt_inner_prod(x, x_ptr, x, x_ptr - (T + k - 1), N); - } - int offset = xcorr[2] - xcorr[0] > Inlines.MULT16_32_Q15((short)22938, xcorr[1] - xcorr[0]) ? 1 : (xcorr[0] - xcorr[2] > Inlines.MULT16_32_Q15((short)22938, xcorr[1] - xcorr[2]) ? -1 : 0); - if (pg > g) { - pg = g; - } - T0_.Val = 2 * T + offset; - if (T0_.Val < minperiod0) { - T0_.Val = minperiod0; - } - return pg; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/PitchAnalysisCore.java b/source/decompiled/de/maxhenkel/voicechat/concentus/PitchAnalysisCore.java deleted file mode 100644 index b8658bf..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/PitchAnalysisCore.java +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.BoxedValueShort; -import de.maxhenkel.voicechat.concentus.CeltPitchXCorr; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Resampler; -import de.maxhenkel.voicechat.concentus.SilkTables; -import de.maxhenkel.voicechat.concentus.Sort; -import de.maxhenkel.voicechat.concentus.SumSqrShift; - -class PitchAnalysisCore { - private static final int SCRATCH_SIZE = 22; - private static final int SF_LENGTH_4KHZ = 20; - private static final int SF_LENGTH_8KHZ = 40; - private static final int MIN_LAG_4KHZ = 8; - private static final int MIN_LAG_8KHZ = 16; - private static final int MAX_LAG_4KHZ = 72; - private static final int MAX_LAG_8KHZ = 143; - private static final int CSTRIDE_4KHZ = 65; - private static final int CSTRIDE_8KHZ = 132; - private static final int D_COMP_MIN = 13; - private static final int D_COMP_MAX = 147; - private static final int D_COMP_STRIDE = 134; - - PitchAnalysisCore() { - } - - static int silk_pitch_analysis_core(short[] frame, int[] pitch_out, BoxedValueShort lagIndex, BoxedValueByte contourIndex, BoxedValueInt LTPCorr_Q15, int prevLag, int search_thres1_Q16, int search_thres2_Q13, int Fs_kHz, int complexity, int nb_subfr) { - int CCmax_new; - int nb_cbk_search; - byte[][] Lag_CB_ptr; - int prevLag_log2_Q7; - int j; - int energy_target; - int length_d_srch; - int sum; - int d; - int cross_corr; - int basis_ptr; - short[] basis; - int k; - int i; - int[] filt_state = new int[6]; - int[] d_srch = new int[24]; - int[] CC = new int[11]; - Inlines.OpusAssert(Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16); - Inlines.OpusAssert(complexity >= 0); - Inlines.OpusAssert(complexity <= 2); - Inlines.OpusAssert(search_thres1_Q16 >= 0 && search_thres1_Q16 <= 65536); - Inlines.OpusAssert(search_thres2_Q13 >= 0 && search_thres2_Q13 <= 8192); - int frame_length = (20 + nb_subfr * 5) * Fs_kHz; - int frame_length_4kHz = (20 + nb_subfr * 5) * 4; - int frame_length_8kHz = (20 + nb_subfr * 5) * 8; - int sf_length = 5 * Fs_kHz; - int min_lag = 2 * Fs_kHz; - int max_lag = 18 * Fs_kHz - 1; - short[] frame_8kHz = new short[frame_length_8kHz]; - if (Fs_kHz == 16) { - Arrays.MemSet(filt_state, 0, 2); - Resampler.silk_resampler_down2(filt_state, frame_8kHz, frame, frame_length); - } else if (Fs_kHz == 12) { - Arrays.MemSet(filt_state, 0, 6); - Resampler.silk_resampler_down2_3(filt_state, frame_8kHz, frame, frame_length); - } else { - Inlines.OpusAssert(Fs_kHz == 8); - System.arraycopy(frame, 0, frame_8kHz, 0, frame_length_8kHz); - } - Arrays.MemSet(filt_state, 0, 2); - short[] frame_4kHz = new short[frame_length_4kHz]; - Resampler.silk_resampler_down2(filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz); - for (i = frame_length_4kHz - 1; i > 0; --i) { - frame_4kHz[i] = Inlines.silk_ADD_SAT16(frame_4kHz[i], frame_4kHz[i - 1]); - } - BoxedValueInt boxed_energy = new BoxedValueInt(0); - BoxedValueInt boxed_shift = new BoxedValueInt(0); - SumSqrShift.silk_sum_sqr_shift(boxed_energy, boxed_shift, frame_4kHz, frame_length_4kHz); - int energy = boxed_energy.Val; - int shift = boxed_shift.Val; - if (shift > 0) { - shift = Inlines.silk_RSHIFT(shift, 1); - for (i = 0; i < frame_length_4kHz; ++i) { - frame_4kHz[i] = Inlines.silk_RSHIFT16(frame_4kHz[i], shift); - } - } - short[] C = new short[nb_subfr * 132]; - int[] xcorr32 = new int[65]; - Arrays.MemSet(C, (short)0, (nb_subfr >> 1) * 65); - short[] target = frame_4kHz; - int target_ptr = Inlines.silk_LSHIFT(20, 2); - for (k = 0; k < nb_subfr >> 1; ++k) { - basis = target; - basis_ptr = target_ptr - 8; - CeltPitchXCorr.pitch_xcorr(target, target_ptr, target, target_ptr - 72, xcorr32, 40, 65); - cross_corr = xcorr32[64]; - int normalizer = Inlines.silk_inner_prod_self(target, target_ptr, 40); - normalizer = Inlines.silk_ADD32(normalizer, Inlines.silk_inner_prod_self(basis, basis_ptr, 40)); - normalizer = Inlines.silk_ADD32(normalizer, Inlines.silk_SMULBB(40, 4000)); - Inlines.MatrixSet(C, k, 0, 65, (short)Inlines.silk_DIV32_varQ(cross_corr, normalizer, 14)); - for (d = 9; d <= 72; ++d) { - cross_corr = xcorr32[72 - d]; - normalizer = Inlines.silk_ADD32(normalizer, Inlines.silk_SMULBB(basis[--basis_ptr], basis[basis_ptr]) - Inlines.silk_SMULBB(basis[basis_ptr + 40], basis[basis_ptr + 40])); - Inlines.MatrixSet(C, k, d - 8, 65, (short)Inlines.silk_DIV32_varQ(cross_corr, normalizer, 14)); - } - target_ptr += 40; - } - if (nb_subfr == 4) { - for (i = 72; i >= 8; --i) { - sum = Inlines.MatrixGet(C, 0, i - 8, 65) + Inlines.MatrixGet(C, 1, i - 8, 65); - sum = Inlines.silk_SMLAWB(sum, sum, Inlines.silk_LSHIFT(-i, 4)); - C[i - 8] = (short)sum; - } - } else { - for (i = 72; i >= 8; --i) { - sum = Inlines.silk_LSHIFT(C[i - 8], 1); - sum = Inlines.silk_SMLAWB(sum, sum, Inlines.silk_LSHIFT(-i, 4)); - C[i - 8] = (short)sum; - } - } - Inlines.OpusAssert(3 * (length_d_srch = Inlines.silk_ADD_LSHIFT32(4, complexity, 1)) <= 24); - Sort.silk_insertion_sort_decreasing_int16(C, d_srch, 65, length_d_srch); - short Cmax = C[0]; - if (Cmax < 3277) { - Arrays.MemSet(pitch_out, 0, nb_subfr); - LTPCorr_Q15.Val = 0; - lagIndex.Val = 0; - contourIndex.Val = 0; - return 1; - } - int threshold = Inlines.silk_SMULWB(search_thres1_Q16, Cmax); - for (i = 0; i < length_d_srch; ++i) { - if (C[i] <= threshold) { - length_d_srch = i; - break; - } - d_srch[i] = Inlines.silk_LSHIFT(d_srch[i] + 8, 1); - } - Inlines.OpusAssert(length_d_srch > 0); - short[] d_comp = new short[134]; - for (i = 13; i < 147; ++i) { - d_comp[i - 13] = 0; - } - for (i = 0; i < length_d_srch; ++i) { - d_comp[d_srch[i] - 13] = 1; - } - for (i = 146; i >= 16; --i) { - int n = i - 13; - d_comp[n] = (short)(d_comp[n] + (short)(d_comp[i - 1 - 13] + d_comp[i - 2 - 13])); - } - length_d_srch = 0; - for (i = 16; i < 144; ++i) { - if (d_comp[i + 1 - 13] <= 0) continue; - d_srch[length_d_srch] = i; - ++length_d_srch; - } - for (i = 146; i >= 16; --i) { - int n = i - 13; - d_comp[n] = (short)(d_comp[n] + (short)(d_comp[i - 1 - 13] + d_comp[i - 2 - 13] + d_comp[i - 3 - 13])); - } - int length_d_comp = 0; - for (i = 16; i < 147; ++i) { - if (d_comp[i - 13] <= 0) continue; - d_comp[length_d_comp] = (short)(i - 2); - ++length_d_comp; - } - boxed_energy.Val = 0; - boxed_shift.Val = 0; - SumSqrShift.silk_sum_sqr_shift(boxed_energy, boxed_shift, frame_8kHz, frame_length_8kHz); - energy = boxed_energy.Val; - shift = boxed_shift.Val; - if (shift > 0) { - shift = Inlines.silk_RSHIFT(shift, 1); - for (i = 0; i < frame_length_8kHz; ++i) { - frame_8kHz[i] = Inlines.silk_RSHIFT16(frame_8kHz[i], shift); - } - } - Arrays.MemSet(C, (short)0, nb_subfr * 132); - target = frame_8kHz; - target_ptr = 160; - for (k = 0; k < nb_subfr; ++k) { - energy_target = Inlines.silk_ADD32(Inlines.silk_inner_prod(target, target_ptr, target, target_ptr, 40), 1); - for (j = 0; j < length_d_comp; ++j) { - basis = target; - d = d_comp[j]; - basis_ptr = target_ptr - d; - cross_corr = Inlines.silk_inner_prod(target, target_ptr, basis, basis_ptr, 40); - if (cross_corr > 0) { - int energy_basis = Inlines.silk_inner_prod_self(basis, basis_ptr, 40); - Inlines.MatrixSet(C, k, d - 14, 132, (short)Inlines.silk_DIV32_varQ(cross_corr, Inlines.silk_ADD32(energy_target, energy_basis), 14)); - continue; - } - Inlines.MatrixSet(C, k, d - 14, 132, (short)0); - } - target_ptr += 40; - } - int CCmax = Integer.MIN_VALUE; - int CCmax_b = Integer.MIN_VALUE; - int CBimax = 0; - int lag = -1; - if (prevLag > 0) { - if (Fs_kHz == 12) { - prevLag = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(prevLag, 1), 3); - } else if (Fs_kHz == 16) { - prevLag = Inlines.silk_RSHIFT(prevLag, 1); - } - prevLag_log2_Q7 = Inlines.silk_lin2log(prevLag); - } else { - prevLag_log2_Q7 = 0; - } - Inlines.OpusAssert(search_thres2_Q13 == Inlines.silk_SAT16(search_thres2_Q13)); - if (nb_subfr == 4) { - Lag_CB_ptr = SilkTables.silk_CB_lags_stage2; - nb_cbk_search = Fs_kHz == 8 && complexity > 0 ? 11 : 3; - } else { - Lag_CB_ptr = SilkTables.silk_CB_lags_stage2_10_ms; - nb_cbk_search = 3; - } - for (k = 0; k < length_d_srch; ++k) { - d = d_srch[k]; - for (j = 0; j < nb_cbk_search; ++j) { - CC[j] = 0; - for (i = 0; i < nb_subfr; ++i) { - int d_subfr = d + Lag_CB_ptr[i][j]; - CC[j] = CC[j] + Inlines.MatrixGet(C, i, d_subfr - 14, 132); - } - } - CCmax_new = Integer.MIN_VALUE; - int CBimax_new = 0; - for (i = 0; i < nb_cbk_search; ++i) { - if (CC[i] <= CCmax_new) continue; - CCmax_new = CC[i]; - CBimax_new = i; - } - int lag_log2_Q7 = Inlines.silk_lin2log(d); - Inlines.OpusAssert(lag_log2_Q7 == Inlines.silk_SAT16(lag_log2_Q7)); - Inlines.OpusAssert(nb_subfr * 1638 == Inlines.silk_SAT16(nb_subfr * 1638)); - int CCmax_new_b = CCmax_new - Inlines.silk_RSHIFT(Inlines.silk_SMULBB(nb_subfr * 1638, lag_log2_Q7), 7); - Inlines.OpusAssert(nb_subfr * 1638 == Inlines.silk_SAT16(nb_subfr * 1638)); - if (prevLag > 0) { - int delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7; - Inlines.OpusAssert(delta_lag_log2_sqr_Q7 == Inlines.silk_SAT16(delta_lag_log2_sqr_Q7)); - delta_lag_log2_sqr_Q7 = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7), 7); - int prev_lag_bias_Q13 = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(nb_subfr * 1638, LTPCorr_Q15.Val), 15); - prev_lag_bias_Q13 = Inlines.silk_DIV32(Inlines.silk_MUL(prev_lag_bias_Q13, delta_lag_log2_sqr_Q7), delta_lag_log2_sqr_Q7 + 64); - CCmax_new_b -= prev_lag_bias_Q13; - } - if (CCmax_new_b <= CCmax_b || CCmax_new <= Inlines.silk_SMULBB(nb_subfr, search_thres2_Q13) || SilkTables.silk_CB_lags_stage2[0][CBimax_new] > 16) continue; - CCmax_b = CCmax_new_b; - CCmax = CCmax_new; - lag = d; - CBimax = CBimax_new; - } - if (lag == -1) { - Arrays.MemSet(pitch_out, 0, nb_subfr); - LTPCorr_Q15.Val = 0; - lagIndex.Val = 0; - contourIndex.Val = 0; - return 1; - } - LTPCorr_Q15.Val = Inlines.silk_LSHIFT(Inlines.silk_DIV32_16(CCmax, nb_subfr), 2); - Inlines.OpusAssert(LTPCorr_Q15.Val >= 0); - if (Fs_kHz > 8) { - short[] input_frame_ptr; - boxed_energy.Val = 0; - boxed_shift.Val = 0; - SumSqrShift.silk_sum_sqr_shift(boxed_energy, boxed_shift, frame, frame_length); - energy = boxed_energy.Val; - shift = boxed_shift.Val; - if (shift > 0) { - short[] scratch_mem = new short[frame_length]; - shift = Inlines.silk_RSHIFT(shift, 1); - for (i = 0; i < frame_length; ++i) { - scratch_mem[i] = Inlines.silk_RSHIFT16(frame[i], shift); - } - input_frame_ptr = scratch_mem; - } else { - input_frame_ptr = frame; - } - int CBimax_old = CBimax; - Inlines.OpusAssert(lag == Inlines.silk_SAT16(lag)); - lag = Fs_kHz == 12 ? Inlines.silk_RSHIFT(Inlines.silk_SMULBB(lag, 3), 1) : (Fs_kHz == 16 ? Inlines.silk_LSHIFT(lag, 1) : Inlines.silk_SMULBB(lag, 3)); - lag = Inlines.silk_LIMIT_int(lag, min_lag, max_lag); - int start_lag = Inlines.silk_max_int(lag - 2, min_lag); - int end_lag = Inlines.silk_min_int(lag + 2, max_lag); - int lag_new = lag; - CBimax = 0; - CCmax = Integer.MIN_VALUE; - for (k = 0; k < nb_subfr; ++k) { - pitch_out[k] = lag + 2 * SilkTables.silk_CB_lags_stage2[k][CBimax_old]; - } - if (nb_subfr == 4) { - nb_cbk_search = SilkTables.silk_nb_cbk_searchs_stage3[complexity]; - Lag_CB_ptr = SilkTables.silk_CB_lags_stage3; - } else { - nb_cbk_search = 12; - Lag_CB_ptr = SilkTables.silk_CB_lags_stage3_10_ms; - } - silk_pe_stage3_vals[] energies_st3 = new silk_pe_stage3_vals[nb_subfr * nb_cbk_search]; - silk_pe_stage3_vals[] cross_corr_st3 = new silk_pe_stage3_vals[nb_subfr * nb_cbk_search]; - for (int c = 0; c < nb_subfr * nb_cbk_search; ++c) { - energies_st3[c] = new silk_pe_stage3_vals(); - cross_corr_st3[c] = new silk_pe_stage3_vals(); - } - PitchAnalysisCore.silk_P_Ana_calc_corr_st3(cross_corr_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity); - PitchAnalysisCore.silk_P_Ana_calc_energy_st3(energies_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity); - int lag_counter = 0; - Inlines.OpusAssert(lag == Inlines.silk_SAT16(lag)); - int contour_bias_Q15 = Inlines.silk_DIV32_16(1638, lag); - target = input_frame_ptr; - target_ptr = 20 * Fs_kHz; - energy_target = Inlines.silk_ADD32(Inlines.silk_inner_prod_self(target, target_ptr, nb_subfr * sf_length), 1); - for (d = start_lag; d <= end_lag; ++d) { - for (j = 0; j < nb_cbk_search; ++j) { - cross_corr = 0; - energy = energy_target; - for (k = 0; k < nb_subfr; ++k) { - cross_corr = Inlines.silk_ADD32(cross_corr, Inlines.MatrixGet((silk_pe_stage3_vals[])cross_corr_st3, (int)k, (int)j, (int)nb_cbk_search).Values[lag_counter]); - Inlines.OpusAssert((energy = Inlines.silk_ADD32(energy, Inlines.MatrixGet((silk_pe_stage3_vals[])energies_st3, (int)k, (int)j, (int)nb_cbk_search).Values[lag_counter])) >= 0); - } - if (cross_corr > 0) { - CCmax_new = Inlines.silk_DIV32_varQ(cross_corr, energy, 14); - int diff = Short.MAX_VALUE - Inlines.silk_MUL(contour_bias_Q15, j); - Inlines.OpusAssert(diff == Inlines.silk_SAT16(diff)); - CCmax_new = Inlines.silk_SMULWB(CCmax_new, diff); - } else { - CCmax_new = 0; - } - if (CCmax_new <= CCmax || d + SilkTables.silk_CB_lags_stage3[0][j] > max_lag) continue; - CCmax = CCmax_new; - lag_new = d; - CBimax = j; - } - ++lag_counter; - } - for (k = 0; k < nb_subfr; ++k) { - pitch_out[k] = lag_new + Lag_CB_ptr[k][CBimax]; - pitch_out[k] = Inlines.silk_LIMIT(pitch_out[k], min_lag, 18 * Fs_kHz); - } - lagIndex.Val = (short)(lag_new - min_lag); - contourIndex.Val = (byte)CBimax; - } else { - for (k = 0; k < nb_subfr; ++k) { - pitch_out[k] = lag + Lag_CB_ptr[k][CBimax]; - pitch_out[k] = Inlines.silk_LIMIT(pitch_out[k], 16, 144); - } - lagIndex.Val = (short)(lag - 16); - contourIndex.Val = (byte)CBimax; - } - Inlines.OpusAssert(lagIndex.Val >= 0); - return 0; - } - - private static void silk_P_Ana_calc_corr_st3(silk_pe_stage3_vals[] cross_corr_st3, short[] frame, int start_lag, int sf_length, int nb_subfr, int complexity) { - int nb_cbk_search; - byte[][] Lag_CB_ptr; - byte[][] Lag_range_ptr; - Inlines.OpusAssert(complexity >= 0); - Inlines.OpusAssert(complexity <= 2); - if (nb_subfr == 4) { - Lag_range_ptr = SilkTables.silk_Lag_range_stage3[complexity]; - Lag_CB_ptr = SilkTables.silk_CB_lags_stage3; - nb_cbk_search = SilkTables.silk_nb_cbk_searchs_stage3[complexity]; - } else { - Inlines.OpusAssert(nb_subfr == 2); - Lag_range_ptr = SilkTables.silk_Lag_range_stage3_10_ms; - Lag_CB_ptr = SilkTables.silk_CB_lags_stage3_10_ms; - nb_cbk_search = 12; - } - int[] scratch_mem = new int[22]; - int[] xcorr32 = new int[22]; - int target_ptr = Inlines.silk_LSHIFT(sf_length, 2); - for (int k = 0; k < nb_subfr; ++k) { - int j; - int lag_counter = 0; - byte lag_high = Lag_range_ptr[k][1]; - int lag_low = Lag_range_ptr[k][0]; - Inlines.OpusAssert(lag_high - lag_low + 1 <= 22); - CeltPitchXCorr.pitch_xcorr(frame, target_ptr, frame, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1); - for (j = lag_low; j <= lag_high; ++j) { - Inlines.OpusAssert(lag_counter < 22); - scratch_mem[lag_counter] = xcorr32[lag_high - j]; - ++lag_counter; - } - byte delta = Lag_range_ptr[k][0]; - for (int i = 0; i < nb_cbk_search; ++i) { - int idx = Lag_CB_ptr[k][i] - delta; - for (j = 0; j < 5; ++j) { - Inlines.OpusAssert(idx + j < 22); - Inlines.OpusAssert(idx + j < lag_counter); - Inlines.MatrixGet((silk_pe_stage3_vals[])cross_corr_st3, (int)k, (int)i, (int)nb_cbk_search).Values[j] = scratch_mem[idx + j]; - } - } - target_ptr += sf_length; - } - } - - static void silk_P_Ana_calc_energy_st3(silk_pe_stage3_vals[] energies_st3, short[] frame, int start_lag, int sf_length, int nb_subfr, int complexity) { - int nb_cbk_search; - byte[][] Lag_CB_ptr; - byte[][] Lag_range_ptr; - Inlines.OpusAssert(complexity >= 0); - Inlines.OpusAssert(complexity <= 2); - if (nb_subfr == 4) { - Lag_range_ptr = SilkTables.silk_Lag_range_stage3[complexity]; - Lag_CB_ptr = SilkTables.silk_CB_lags_stage3; - nb_cbk_search = SilkTables.silk_nb_cbk_searchs_stage3[complexity]; - } else { - Inlines.OpusAssert(nb_subfr == 2); - Lag_range_ptr = SilkTables.silk_Lag_range_stage3_10_ms; - Lag_CB_ptr = SilkTables.silk_CB_lags_stage3_10_ms; - nb_cbk_search = 12; - } - int[] scratch_mem = new int[22]; - int target_ptr = Inlines.silk_LSHIFT(sf_length, 2); - for (int k = 0; k < nb_subfr; ++k) { - int i; - int lag_counter = 0; - int basis_ptr = target_ptr - (start_lag + Lag_range_ptr[k][0]); - int energy = Inlines.silk_inner_prod_self(frame, basis_ptr, sf_length); - Inlines.OpusAssert(energy >= 0); - scratch_mem[lag_counter] = energy; - ++lag_counter; - int lag_diff = Lag_range_ptr[k][1] - Lag_range_ptr[k][0] + 1; - for (i = 1; i < lag_diff; ++i) { - Inlines.OpusAssert((energy -= Inlines.silk_SMULBB(frame[basis_ptr + sf_length - i], frame[basis_ptr + sf_length - i])) >= 0); - energy = Inlines.silk_ADD_SAT32(energy, Inlines.silk_SMULBB(frame[basis_ptr - i], frame[basis_ptr - i])); - Inlines.OpusAssert(energy >= 0); - Inlines.OpusAssert(lag_counter < 22); - scratch_mem[lag_counter] = energy; - ++lag_counter; - } - byte delta = Lag_range_ptr[k][0]; - for (i = 0; i < nb_cbk_search; ++i) { - int idx = Lag_CB_ptr[k][i] - delta; - for (int j = 0; j < 5; ++j) { - Inlines.OpusAssert(idx + j < 22); - Inlines.OpusAssert(idx + j < lag_counter); - Inlines.MatrixGet((silk_pe_stage3_vals[])energies_st3, (int)k, (int)i, (int)nb_cbk_search).Values[j] = scratch_mem[idx + j]; - Inlines.OpusAssert(Inlines.MatrixGet((silk_pe_stage3_vals[])energies_st3, (int)k, (int)i, (int)nb_cbk_search).Values[j] >= 0); - } - } - target_ptr += sf_length; - } - } - - static class silk_pe_stage3_vals { - public final int[] Values = new int[5]; - - silk_pe_stage3_vals() { - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/ProcessGains.java b/source/decompiled/de/maxhenkel/voicechat/concentus/ProcessGains.java deleted file mode 100644 index 81f0500..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/ProcessGains.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.GainQuantization; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Sigmoid; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkEncoderControl; -import de.maxhenkel.voicechat.concentus.SilkShapeState; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class ProcessGains { - ProcessGains() { - } - - static void silk_process_gains(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, int condCoding) { - int k; - SilkShapeState psShapeSt = psEnc.sShape; - if (psEnc.indices.signalType == 2) { - int s_Q16 = 0 - Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT_ROUND(psEncCtrl.LTPredCodGain_Q7 - 1536, 4)); - for (k = 0; k < psEnc.nb_subfr; ++k) { - psEncCtrl.Gains_Q16[k] = Inlines.silk_SMLAWB(psEncCtrl.Gains_Q16[k], psEncCtrl.Gains_Q16[k], s_Q16); - } - } - int InvMaxSqrVal_Q16 = Inlines.silk_DIV32_16(Inlines.silk_log2lin(Inlines.silk_SMULWB(8894 - psEnc.SNR_dB_Q7, 21627)), psEnc.subfr_length); - for (k = 0; k < psEnc.nb_subfr; ++k) { - int gain; - int ResNrg = psEncCtrl.ResNrg[k]; - int ResNrgPart = Inlines.silk_SMULWW(ResNrg, InvMaxSqrVal_Q16); - ResNrgPart = psEncCtrl.ResNrgQ[k] > 0 ? Inlines.silk_RSHIFT_ROUND(ResNrgPart, psEncCtrl.ResNrgQ[k]) : (ResNrgPart >= Inlines.silk_RSHIFT(Integer.MAX_VALUE, -psEncCtrl.ResNrgQ[k]) ? Integer.MAX_VALUE : Inlines.silk_LSHIFT(ResNrgPart, -psEncCtrl.ResNrgQ[k])); - int gain_squared = Inlines.silk_ADD_SAT32(ResNrgPart, Inlines.silk_SMMUL(gain = psEncCtrl.Gains_Q16[k], gain)); - if (gain_squared < Short.MAX_VALUE) { - gain_squared = Inlines.silk_SMLAWW(Inlines.silk_LSHIFT(ResNrgPart, 16), gain, gain); - Inlines.OpusAssert(gain_squared > 0); - gain = Inlines.silk_SQRT_APPROX(gain_squared); - gain = Inlines.silk_min(gain, 0x7FFFFF); - psEncCtrl.Gains_Q16[k] = Inlines.silk_LSHIFT_SAT32(gain, 8); - continue; - } - gain = Inlines.silk_SQRT_APPROX(gain_squared); - gain = Inlines.silk_min(gain, Short.MAX_VALUE); - psEncCtrl.Gains_Q16[k] = Inlines.silk_LSHIFT_SAT32(gain, 16); - } - System.arraycopy(psEncCtrl.Gains_Q16, 0, psEncCtrl.GainsUnq_Q16, 0, psEnc.nb_subfr); - psEncCtrl.lastGainIndexPrev = psShapeSt.LastGainIndex; - BoxedValueByte boxed_lastGainIndex = new BoxedValueByte(psShapeSt.LastGainIndex); - GainQuantization.silk_gains_quant(psEnc.indices.GainsIndices, psEncCtrl.Gains_Q16, boxed_lastGainIndex, condCoding == 2 ? 1 : 0, psEnc.nb_subfr); - psShapeSt.LastGainIndex = boxed_lastGainIndex.Val; - if (psEnc.indices.signalType == 2) { - psEnc.indices.quantOffsetType = psEncCtrl.LTPredCodGain_Q7 + Inlines.silk_RSHIFT(psEnc.input_tilt_Q15, 8) > 128 ? (byte)0 : 1; - } - short quant_offset_Q10 = SilkTables.silk_Quantization_Offsets_Q10[psEnc.indices.signalType >> 1][psEnc.indices.quantOffsetType]; - psEncCtrl.Lambda_Q10 = 1229 + Inlines.silk_SMULBB(-50, psEnc.nStatesDelayedDecision) + Inlines.silk_SMULWB(-52428, psEnc.speech_activity_Q8) + Inlines.silk_SMULWB(-409, psEncCtrl.input_quality_Q14) + Inlines.silk_SMULWB(-818, psEncCtrl.coding_quality_Q14) + Inlines.silk_SMULWB(52429, quant_offset_Q10); - Inlines.OpusAssert(psEncCtrl.Lambda_Q10 > 0); - Inlines.OpusAssert(psEncCtrl.Lambda_Q10 < 2048); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/PulseCache.java b/source/decompiled/de/maxhenkel/voicechat/concentus/PulseCache.java deleted file mode 100644 index 52fff55..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/PulseCache.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class PulseCache { - int size = 0; - short[] index = null; - short[] bits = null; - short[] caps = null; - - PulseCache() { - } - - void Reset() { - this.size = 0; - this.index = null; - this.bits = null; - this.caps = null; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/QuantizeBands.java b/source/decompiled/de/maxhenkel/voicechat/concentus/QuantizeBands.java deleted file mode 100644 index d35030c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/QuantizeBands.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltMode; -import de.maxhenkel.voicechat.concentus.CeltTables; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Laplace; - -class QuantizeBands { - private static final int[] pred_coef = new int[]{29440, 26112, 21248, 16384}; - private static final int[] beta_coef = new int[]{30147, 22282, 12124, 6554}; - private static final int beta_intra = 4915; - private static short[] small_energy_icdf = new short[]{2, 1, 0}; - - QuantizeBands() { - } - - static int loss_distortion(int[][] eBands, int[][] oldEBands, int start, int end, int len, int C) { - int dist = 0; - int c = 0; - do { - for (int i = start; i < end; ++i) { - int d = Inlines.SUB16(Inlines.SHR16(eBands[c][i], 3), Inlines.SHR16(oldEBands[c][i], 3)); - dist = Inlines.MAC16_16(dist, d, d); - } - } while (++c < C); - return Inlines.MIN32(200, Inlines.SHR32(dist, 14)); - } - - static int quant_coarse_energy_impl(CeltMode m, int start, int end, int[][] eBands, int[][] oldEBands, int budget, int tell, short[] prob_model, int[][] error, EntropyCoder enc, int C, int LM, int intra, int max_decay, int lfe) { - int beta; - int coef; - int badness = 0; - int[] prev = new int[]{0, 0}; - if (tell + 3 <= budget) { - enc.enc_bit_logp(intra, 3); - } - if (intra != 0) { - coef = 0; - beta = 4915; - } else { - beta = beta_coef[LM]; - coef = pred_coef[LM]; - } - for (int i = start; i < end; ++i) { - int c = 0; - do { - int x = eBands[c][i]; - int oldE = Inlines.MAX16(-9216, oldEBands[c][i]); - int f = Inlines.SHL32(Inlines.EXTEND32(x), 7) - Inlines.PSHR32(Inlines.MULT16_16(coef, oldE), 8) - prev[c]; - int qi = f + 65536 >> 17; - short decay_bound = Inlines.EXTRACT16(Inlines.MAX32(-28672, Inlines.SUB32(oldEBands[c][i], max_decay))); - if (qi < 0 && x < decay_bound && (qi += Inlines.SHR16(Inlines.SUB16((int)decay_bound, x), 10)) > 0) { - qi = 0; - } - int qi0 = qi; - tell = enc.tell(); - int bits_left = budget - tell - 3 * C * (end - i); - if (i != start && bits_left < 30) { - if (bits_left < 24) { - qi = Inlines.IMIN(1, qi); - } - if (bits_left < 16) { - qi = Inlines.IMAX(-1, qi); - } - } - if (lfe != 0 && i >= 2) { - qi = Inlines.IMIN(qi, 0); - } - if (budget - tell >= 15) { - int pi = 2 * Inlines.IMIN(i, 20); - BoxedValueInt boxed_qi = new BoxedValueInt(qi); - Laplace.ec_laplace_encode(enc, boxed_qi, prob_model[pi] << 7, prob_model[pi + 1] << 6); - qi = boxed_qi.Val; - } else if (budget - tell >= 2) { - enc.enc_icdf(2 * qi ^ 0 - ((qi = Inlines.IMAX(-1, Inlines.IMIN(qi, 1))) < 0 ? 1 : 0), small_energy_icdf, 2); - } else if (budget - tell >= 1) { - qi = Inlines.IMIN(0, qi); - enc.enc_bit_logp(-qi, 1); - } else { - qi = -1; - } - error[c][i] = Inlines.PSHR32(f, 7) - Inlines.SHL16(qi, 10); - badness += Inlines.abs(qi0 - qi); - int q = Inlines.SHL32(qi, 10); - int tmp = Inlines.PSHR32(Inlines.MULT16_16(coef, oldE), 8) + prev[c] + Inlines.SHL32(q, 7); - tmp = Inlines.MAX32(-3670016, tmp); - oldEBands[c][i] = Inlines.PSHR32(tmp, 7); - prev[c] = prev[c] + Inlines.SHL32(q, 7) - Inlines.MULT16_16(beta, Inlines.PSHR32(q, 8)); - } while (++c < C); - } - return lfe != 0 ? 0 : badness; - } - - static void quant_coarse_energy(CeltMode m, int start, int end, int effEnd, int[][] eBands, int[][] oldEBands, int budget, int[][] error, EntropyCoder enc, int C, int LM, int nbAvailableBytes, int force_intra, BoxedValueInt delayedIntra, int two_pass, int loss_rate, int lfe) { - EntropyCoder enc_start_state = new EntropyCoder(); - int badness1 = 0; - int intra = force_intra != 0 || two_pass == 0 && delayedIntra.Val > 2 * C * (end - start) && nbAvailableBytes > (end - start) * C ? 1 : 0; - int intra_bias = budget * delayedIntra.Val * loss_rate / (C * 512); - int new_distortion = QuantizeBands.loss_distortion(eBands, oldEBands, start, effEnd, m.nbEBands, C); - int tell = enc.tell(); - if (tell + 3 > budget) { - intra = 0; - two_pass = 0; - } - int max_decay = 16384; - if (end - start > 10) { - max_decay = Inlines.MIN32(max_decay, Inlines.SHL32(nbAvailableBytes, 7)); - } - if (lfe != 0) { - max_decay = 3072; - } - enc_start_state.Assign(enc); - int[][] oldEBands_intra = Arrays.InitTwoDimensionalArrayInt(C, m.nbEBands); - int[][] error_intra = Arrays.InitTwoDimensionalArrayInt(C, m.nbEBands); - System.arraycopy(oldEBands[0], 0, oldEBands_intra[0], 0, m.nbEBands); - if (C == 2) { - System.arraycopy(oldEBands[1], 0, oldEBands_intra[1], 0, m.nbEBands); - } - if (two_pass != 0 || intra != 0) { - badness1 = QuantizeBands.quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget, tell, CeltTables.e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe); - } - if (intra == 0) { - EntropyCoder enc_intra_state = new EntropyCoder(); - byte[] intra_bits = null; - int tell_intra = enc.tell_frac(); - enc_intra_state.Assign(enc); - int nstart_bytes = enc_start_state.range_bytes(); - int nintra_bytes = enc_intra_state.range_bytes(); - int intra_buf = nstart_bytes; - int save_bytes = nintra_bytes - nstart_bytes; - if (save_bytes != 0) { - intra_bits = new byte[save_bytes]; - System.arraycopy(enc_intra_state.get_buffer(), intra_buf, intra_bits, 0, save_bytes); - } - enc.Assign(enc_start_state); - int badness2 = QuantizeBands.quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget, tell, CeltTables.e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe); - if (two_pass != 0 && (badness1 < badness2 || badness1 == badness2 && enc.tell_frac() + intra_bias > tell_intra)) { - enc.Assign(enc_intra_state); - if (intra_bits != null) { - enc_intra_state.write_buffer(intra_bits, 0, intra_buf, nintra_bytes - nstart_bytes); - } - System.arraycopy(oldEBands_intra[0], 0, oldEBands[0], 0, m.nbEBands); - System.arraycopy(error_intra[0], 0, error[0], 0, m.nbEBands); - if (C == 2) { - System.arraycopy(oldEBands_intra[1], 0, oldEBands[1], 0, m.nbEBands); - System.arraycopy(error_intra[1], 0, error[1], 0, m.nbEBands); - } - intra = 1; - } - } else { - System.arraycopy(oldEBands_intra[0], 0, oldEBands[0], 0, m.nbEBands); - System.arraycopy(error_intra[0], 0, error[0], 0, m.nbEBands); - if (C == 2) { - System.arraycopy(oldEBands_intra[1], 0, oldEBands[1], 0, m.nbEBands); - System.arraycopy(error_intra[1], 0, error[1], 0, m.nbEBands); - } - } - delayedIntra.Val = intra != 0 ? new_distortion : Inlines.ADD32(Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(pred_coef[LM], pred_coef[LM]), delayedIntra.Val), new_distortion); - } - - static void quant_fine_energy(CeltMode m, int start, int end, int[][] oldEBands, int[][] error, int[] fine_quant, EntropyCoder enc, int C) { - for (int i = start; i < end; ++i) { - int frac = 1 << fine_quant[i]; - if (fine_quant[i] <= 0) continue; - int c = 0; - do { - int q2; - if ((q2 = error[c][i] + 512 >> 10 - fine_quant[i]) > frac - 1) { - q2 = frac - 1; - } - if (q2 < 0) { - q2 = 0; - } - enc.enc_bits(q2, fine_quant[i]); - int offset = Inlines.SUB16(Inlines.SHR32(Inlines.SHL32(q2, 10) + 512, fine_quant[i]), 512); - int[] nArray = oldEBands[c]; - int n = i; - nArray[n] = nArray[n] + offset; - int[] nArray2 = error[c]; - int n2 = i; - nArray2[n2] = nArray2[n2] - offset; - } while (++c < C); - } - } - - static void quant_energy_finalise(CeltMode m, int start, int end, int[][] oldEBands, int[][] error, int[] fine_quant, int[] fine_priority, int bits_left, EntropyCoder enc, int C) { - for (int prio = 0; prio < 2; ++prio) { - for (int i = start; i < end && bits_left >= C; ++i) { - if (fine_quant[i] >= 8 || fine_priority[i] != prio) continue; - int c = 0; - do { - int q2 = error[c][i] < 0 ? 0 : 1; - enc.enc_bits(q2, 1); - int offset = Inlines.SHR16(Inlines.SHL16(q2, 10) - 512, fine_quant[i] + 1); - int[] nArray = oldEBands[c]; - int n = i; - nArray[n] = nArray[n] + offset; - --bits_left; - } while (++c < C); - } - } - } - - static void unquant_coarse_energy(CeltMode m, int start, int end, int[] oldEBands, int intra, EntropyCoder dec, int C, int LM) { - int beta; - int coef; - short[] prob_model = CeltTables.e_prob_model[LM][intra]; - int[] prev = new int[]{0, 0}; - if (intra != 0) { - coef = 0; - beta = 4915; - } else { - beta = beta_coef[LM]; - coef = pred_coef[LM]; - } - int budget = dec.storage * 8; - for (int i = start; i < end; ++i) { - int c = 0; - do { - int qi; - Inlines.OpusAssert(c < 2); - int tell = dec.tell(); - if (budget - tell >= 15) { - int pi = 2 * Inlines.IMIN(i, 20); - qi = Laplace.ec_laplace_decode(dec, prob_model[pi] << 7, prob_model[pi + 1] << 6); - } else if (budget - tell >= 2) { - qi = dec.dec_icdf(small_energy_icdf, 2); - qi = qi >> 1 ^ -(qi & 1); - } else { - qi = budget - tell >= 1 ? 0 - dec.dec_bit_logp(1L) : -1; - } - int q = Inlines.SHL32(qi, 10); - oldEBands[i + c * m.nbEBands] = Inlines.MAX16(-9216, oldEBands[i + c * m.nbEBands]); - int tmp = Inlines.PSHR32(Inlines.MULT16_16(coef, oldEBands[i + c * m.nbEBands]), 8) + prev[c] + Inlines.SHL32(q, 7); - tmp = Inlines.MAX32(-3670016, tmp); - oldEBands[i + c * m.nbEBands] = Inlines.PSHR32(tmp, 7); - prev[c] = prev[c] + Inlines.SHL32(q, 7) - Inlines.MULT16_16(beta, Inlines.PSHR32(q, 8)); - } while (++c < C); - } - } - - static void unquant_fine_energy(CeltMode m, int start, int end, int[] oldEBands, int[] fine_quant, EntropyCoder dec, int C) { - for (int i = start; i < end; ++i) { - if (fine_quant[i] <= 0) continue; - int c = 0; - do { - int q2 = dec.dec_bits(fine_quant[i]); - int offset = Inlines.SUB16(Inlines.SHR32(Inlines.SHL32(q2, 10) + 512, fine_quant[i]), 512); - int n = i + c * m.nbEBands; - oldEBands[n] = oldEBands[n] + offset; - } while (++c < C); - } - } - - static void unquant_energy_finalise(CeltMode m, int start, int end, int[] oldEBands, int[] fine_quant, int[] fine_priority, int bits_left, EntropyCoder dec, int C) { - for (int prio = 0; prio < 2; ++prio) { - for (int i = start; i < end && bits_left >= C; ++i) { - if (fine_quant[i] >= 8 || fine_priority[i] != prio) continue; - int c = 0; - do { - int q2 = dec.dec_bits(1); - int offset = Inlines.SHR16(Inlines.SHL16(q2, 10) - 512, fine_quant[i] + 1); - int n = i + c * m.nbEBands; - oldEBands[n] = oldEBands[n] + offset; - --bits_left; - } while (++c < C); - } - } - } - - static void amp2Log2(CeltMode m, int effEnd, int end, int[][] bandE, int[][] bandLogE, int C) { - int c = 0; - do { - int i; - for (i = 0; i < effEnd; ++i) { - bandLogE[c][i] = Inlines.celt_log2(Inlines.SHL32(bandE[c][i], 2)) - Inlines.SHL16((int)CeltTables.eMeans[i], 6); - } - for (i = effEnd; i < end; ++i) { - bandLogE[c][i] = -14336; - } - } while (++c < C); - } - - static void amp2Log2(CeltMode m, int effEnd, int end, int[] bandE, int[] bandLogE, int bandLogE_ptr, int C) { - int c = 0; - do { - int i; - for (i = 0; i < effEnd; ++i) { - bandLogE[bandLogE_ptr + c * m.nbEBands + i] = Inlines.celt_log2(Inlines.SHL32(bandE[i + c * m.nbEBands], 2)) - Inlines.SHL16((int)CeltTables.eMeans[i], 6); - } - for (i = effEnd; i < end; ++i) { - bandLogE[bandLogE_ptr + c * m.nbEBands + i] = -14336; - } - } while (++c < C); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/QuantizeLTPGains.java b/source/decompiled/de/maxhenkel/voicechat/concentus/QuantizeLTPGains.java deleted file mode 100644 index 0c76fd2..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/QuantizeLTPGains.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkTables; -import de.maxhenkel.voicechat.concentus.VQ_WMat_EC; - -class QuantizeLTPGains { - QuantizeLTPGains() { - } - - static void silk_quant_LTP_gains(short[] B_Q14, byte[] cbk_index, BoxedValueByte periodicity_index, BoxedValueInt sum_log_gain_Q7, int[] W_Q18, int mu_Q9, int lowComplexity, int nb_subfr) { - int j; - byte[][] cbk_ptr_Q7; - int k; - byte[] temp_idx = new byte[4]; - int min_rate_dist_Q14 = Integer.MAX_VALUE; - int best_sum_log_gain_Q7 = 0; - for (k = 0; k < 3; ++k) { - int gain_safety = 51; - short[] cl_ptr_Q5 = SilkTables.silk_LTP_gain_BITS_Q5_ptrs[k]; - cbk_ptr_Q7 = SilkTables.silk_LTP_vq_ptrs_Q7[k]; - short[] cbk_gain_ptr_Q7 = SilkTables.silk_LTP_vq_gain_ptrs_Q7[k]; - byte cbk_size = SilkTables.silk_LTP_vq_sizes[k]; - int W_Q18_ptr = 0; - int b_Q14_ptr = 0; - int rate_dist_Q14 = 0; - int sum_log_gain_tmp_Q7 = sum_log_gain_Q7.Val; - for (j = 0; j < nb_subfr; ++j) { - int max_gain_Q7 = Inlines.silk_log2lin(5333 - sum_log_gain_tmp_Q7 + 896) - gain_safety; - BoxedValueByte temp_idx_box = new BoxedValueByte(temp_idx[j]); - BoxedValueInt rate_dist_Q14_subfr_box = new BoxedValueInt(0); - BoxedValueInt gain_Q7_box = new BoxedValueInt(0); - VQ_WMat_EC.silk_VQ_WMat_EC(temp_idx_box, rate_dist_Q14_subfr_box, gain_Q7_box, B_Q14, b_Q14_ptr, W_Q18, W_Q18_ptr, cbk_ptr_Q7, cbk_gain_ptr_Q7, cl_ptr_Q5, mu_Q9, max_gain_Q7, cbk_size); - int rate_dist_Q14_subfr = rate_dist_Q14_subfr_box.Val; - int gain_Q7 = gain_Q7_box.Val; - temp_idx[j] = temp_idx_box.Val; - rate_dist_Q14 = Inlines.silk_ADD_POS_SAT32(rate_dist_Q14, rate_dist_Q14_subfr); - sum_log_gain_tmp_Q7 = Inlines.silk_max(0, sum_log_gain_tmp_Q7 + Inlines.silk_lin2log(gain_safety + gain_Q7) - 896); - b_Q14_ptr += 5; - W_Q18_ptr += 25; - } - if ((rate_dist_Q14 = Inlines.silk_min(0x7FFFFFFE, rate_dist_Q14)) < min_rate_dist_Q14) { - min_rate_dist_Q14 = rate_dist_Q14; - periodicity_index.Val = (byte)k; - System.arraycopy(temp_idx, 0, cbk_index, 0, nb_subfr); - best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7; - } - if (lowComplexity != 0 && rate_dist_Q14 < 12304) break; - } - cbk_ptr_Q7 = SilkTables.silk_LTP_vq_ptrs_Q7[periodicity_index.Val]; - for (j = 0; j < nb_subfr; ++j) { - for (k = 0; k < 5; ++k) { - B_Q14[j * 5 + k] = (short)Inlines.silk_LSHIFT(cbk_ptr_Q7[cbk_index[j]][k], 7); - } - } - sum_log_gain_Q7.Val = best_sum_log_gain_Q7; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Rate.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Rate.java deleted file mode 100644 index ff2327d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Rate.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CeltMode; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; - -class Rate { - private static final byte[] LOG2_FRAC_TABLE = new byte[]{0, 8, 13, 16, 19, 21, 23, 24, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 34, 35, 36, 36, 37, 37}; - private static final int ALLOC_STEPS = 6; - - Rate() { - } - - static int get_pulses(int i) { - return i < 8 ? i : 8 + (i & 7) << (i >> 3) - 1; - } - - static int bits2pulses(CeltMode m, int band, int LM, int bits) { - short[] cache = m.cache.bits; - short cache_ptr = m.cache.index[++LM * m.nbEBands + band]; - int lo = 0; - int hi = cache[cache_ptr]; - --bits; - for (int i = 0; i < 6; ++i) { - int mid = lo + hi + 1 >> 1; - if (cache[cache_ptr + mid] >= bits) { - hi = mid; - continue; - } - lo = mid; - } - if (bits - (lo == 0 ? -1 : cache[cache_ptr + lo]) <= cache[cache_ptr + hi] - bits) { - return lo; - } - return hi; - } - - static int pulses2bits(CeltMode m, int band, int LM, int pulses) { - return pulses == 0 ? 0 : m.cache.bits[m.cache.index[++LM * m.nbEBands + band] + pulses] + 1; - } - - static int interp_bits2pulses(CeltMode m, int start, int end, int skip_start, int[] bits1, int[] bits2, int[] thresh, int[] cap, int total, BoxedValueInt _balance, int skip_rsv, BoxedValueInt intensity, int intensity_rsv, BoxedValueInt dual_stereo, int dual_stereo_rsv, int[] bits, int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, int encode, int prev, int signalBandwidth) { - int percoeff; - int left; - int tmp; - int j; - boolean done; - int psum; - int codedBands = -1; - int alloc_floor = C << 3; - int stereo = C > 1 ? 1 : 0; - int logM = LM << 3; - int lo = 0; - int hi = 64; - for (int i = 0; i < 6; ++i) { - int mid = lo + hi >> 1; - psum = 0; - done = false; - j = end; - while (j-- > start) { - int tmp2 = bits1[j] + (mid * bits2[j] >> 6); - if (tmp2 >= thresh[j] || done) { - done = true; - psum += Inlines.IMIN(tmp2, cap[j]); - continue; - } - if (tmp2 < alloc_floor) continue; - psum += alloc_floor; - } - if (psum > total) { - hi = mid; - continue; - } - lo = mid; - } - psum = 0; - done = false; - j = end; - while (j-- > start) { - tmp = bits1[j] + (lo * bits2[j] >> 6); - if (tmp < thresh[j] && !done) { - tmp = tmp >= alloc_floor ? alloc_floor : 0; - } else { - done = true; - } - bits[j] = tmp = Inlines.IMIN(tmp, cap[j]); - psum += tmp; - } - codedBands = end; - while (true) { - int rem; - int band_width; - if ((j = codedBands - 1) <= skip_start) { - total += skip_rsv; - break; - } - left = total - psum; - percoeff = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]); - int band_bits = bits[j] + percoeff * (band_width = m.eBands[codedBands] - m.eBands[j]) + (rem = Inlines.IMAX((left -= (m.eBands[codedBands] - m.eBands[start]) * percoeff) - (m.eBands[j] - m.eBands[start]), 0)); - if (band_bits >= Inlines.IMAX(thresh[j], alloc_floor + 8)) { - if (encode != 0) { - if (codedBands <= start + 2 || band_bits > (j < prev ? 7 : 9) * band_width << LM << 3 >> 4 && j <= signalBandwidth) { - ec.enc_bit_logp(1, 1); - break; - } - ec.enc_bit_logp(0, 1); - } else if (ec.dec_bit_logp(1L) != 0) break; - psum += 8; - band_bits -= 8; - } - psum -= bits[j] + intensity_rsv; - if (intensity_rsv > 0) { - intensity_rsv = LOG2_FRAC_TABLE[j - start]; - } - psum += intensity_rsv; - if (band_bits >= alloc_floor) { - psum += alloc_floor; - bits[j] = alloc_floor; - } else { - bits[j] = 0; - } - --codedBands; - } - Inlines.OpusAssert(codedBands > start); - if (intensity_rsv > 0) { - if (encode != 0) { - intensity.Val = Inlines.IMIN(intensity.Val, codedBands); - ec.enc_uint(intensity.Val - start, codedBands + 1 - start); - } else { - intensity.Val = start + (int)ec.dec_uint(codedBands + 1 - start); - } - } else { - intensity.Val = 0; - } - if (intensity.Val <= start) { - total += dual_stereo_rsv; - dual_stereo_rsv = 0; - } - if (dual_stereo_rsv > 0) { - if (encode != 0) { - ec.enc_bit_logp(dual_stereo.Val, 1); - } else { - dual_stereo.Val = ec.dec_bit_logp(1L); - } - } else { - dual_stereo.Val = 0; - } - left = total - psum; - percoeff = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]); - left -= (m.eBands[codedBands] - m.eBands[start]) * percoeff; - for (j = start; j < codedBands; ++j) { - int n = j; - bits[n] = bits[n] + percoeff * (m.eBands[j + 1] - m.eBands[j]); - } - j = start; - while (j < codedBands) { - tmp = Inlines.IMIN(left, m.eBands[j + 1] - m.eBands[j]); - int n = j++; - bits[n] = bits[n] + tmp; - left -= tmp; - } - int balance = 0; - for (j = start; j < codedBands; ++j) { - int excess; - Inlines.OpusAssert(bits[j] >= 0); - int N0 = m.eBands[j + 1] - m.eBands[j]; - int N = N0 << LM; - int bit = bits[j] + balance; - if (N > 1) { - excess = Inlines.MAX32(bit - cap[j], 0); - bits[j] = bit - excess; - int den = C * N + (C == 2 && N > 2 && dual_stereo.Val == 0 && j < intensity.Val ? 1 : 0); - int NClogN = den * (m.logN[j] + logM); - int offset = (NClogN >> 1) - den * 21; - if (N == 2) { - offset += den << 3 >> 2; - } - if (bits[j] + offset < den * 2 << 3) { - offset += NClogN >> 2; - } else if (bits[j] + offset < den * 3 << 3) { - offset += NClogN >> 3; - } - ebits[j] = Inlines.IMAX(0, bits[j] + offset + (den << 2)); - ebits[j] = Inlines.celt_udiv(ebits[j], den) >> 3; - if (C * ebits[j] > bits[j] >> 3) { - ebits[j] = bits[j] >> stereo >> 3; - } - ebits[j] = Inlines.IMIN(ebits[j], 8); - fine_priority[j] = ebits[j] * (den << 3) >= bits[j] + offset ? 1 : 0; - int n = j; - bits[n] = bits[n] - (C * ebits[j] << 3); - } else { - excess = Inlines.MAX32(0, bit - (C << 3)); - bits[j] = bit - excess; - ebits[j] = 0; - fine_priority[j] = 1; - } - if (excess > 0) { - int extra_fine = Inlines.IMIN(excess >> stereo + 3, 8 - ebits[j]); - int n = j; - ebits[n] = ebits[n] + extra_fine; - int extra_bits = extra_fine * C << 3; - fine_priority[j] = extra_bits >= excess - balance ? 1 : 0; - excess -= extra_bits; - } - balance = excess; - Inlines.OpusAssert(bits[j] >= 0); - Inlines.OpusAssert(ebits[j] >= 0); - } - _balance.Val = balance; - while (j < end) { - ebits[j] = bits[j] >> stereo >> 3; - Inlines.OpusAssert(C * ebits[j] << 3 == bits[j]); - bits[j] = 0; - fine_priority[j] = ebits[j] < 1 ? 1 : 0; - ++j; - } - return codedBands; - } - - static int compute_allocation(CeltMode m, int start, int end, int[] offsets, int[] cap, int alloc_trim, BoxedValueInt intensity, BoxedValueInt dual_stereo, int total, BoxedValueInt balance, int[] pulses, int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, int encode, int prev, int signalBandwidth) { - int j; - total = Inlines.IMAX(total, 0); - int len = m.nbEBands; - int skip_start = start; - int skip_rsv = total >= 8 ? 8 : 0; - total -= skip_rsv; - int dual_stereo_rsv = 0; - int intensity_rsv = 0; - if (C == 2) { - intensity_rsv = LOG2_FRAC_TABLE[end - start]; - if (intensity_rsv > total) { - intensity_rsv = 0; - } else { - dual_stereo_rsv = (total -= intensity_rsv) >= 8 ? 8 : 0; - total -= dual_stereo_rsv; - } - } - int[] bits1 = new int[len]; - int[] bits2 = new int[len]; - int[] thresh = new int[len]; - int[] trim_offset = new int[len]; - for (j = start; j < end; ++j) { - thresh[j] = Inlines.IMAX(C << 3, 3 * (m.eBands[j + 1] - m.eBands[j]) << LM << 3 >> 4); - trim_offset[j] = C * (m.eBands[j + 1] - m.eBands[j]) * (alloc_trim - 5 - LM) * (end - j - 1) * (1 << LM + 3) >> 6; - if (m.eBands[j + 1] - m.eBands[j] << LM != 1) continue; - int n = j; - trim_offset[n] = trim_offset[n] - (C << 3); - } - int lo = 1; - int hi = m.nbAllocVectors - 1; - do { - boolean done = false; - int psum = 0; - int mid = lo + hi >> 1; - j = end; - while (j-- > start) { - int N = m.eBands[j + 1] - m.eBands[j]; - int bitsj = C * N * m.allocVectors[mid * len + j] << LM >> 2; - if (bitsj > 0) { - bitsj = Inlines.IMAX(0, bitsj + trim_offset[j]); - } - if ((bitsj += offsets[j]) >= thresh[j] || done) { - done = true; - psum += Inlines.IMIN(bitsj, cap[j]); - continue; - } - if (bitsj < C << 3) continue; - psum += C << 3; - } - if (psum > total) { - hi = mid - 1; - continue; - } - lo = mid + 1; - } while (lo <= hi); - hi = lo--; - for (j = start; j < end; ++j) { - int bits2j; - int N = m.eBands[j + 1] - m.eBands[j]; - int bits1j = C * N * m.allocVectors[lo * len + j] << LM >> 2; - int n = bits2j = hi >= m.nbAllocVectors ? cap[j] : C * N * m.allocVectors[hi * len + j] << LM >> 2; - if (bits1j > 0) { - bits1j = Inlines.IMAX(0, bits1j + trim_offset[j]); - } - if (bits2j > 0) { - bits2j = Inlines.IMAX(0, bits2j + trim_offset[j]); - } - if (lo > 0) { - bits1j += offsets[j]; - } - bits2j += offsets[j]; - if (offsets[j] > 0) { - skip_start = j; - } - bits2j = Inlines.IMAX(0, bits2j - bits1j); - bits1[j] = bits1j; - bits2[j] = bits2j; - } - int codedBands = Rate.interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap, total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv, pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth); - return codedBands; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/RegularizeCorrelations.java b/source/decompiled/de/maxhenkel/voicechat/concentus/RegularizeCorrelations.java deleted file mode 100644 index b67b303..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/RegularizeCorrelations.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; - -class RegularizeCorrelations { - RegularizeCorrelations() { - } - - static void silk_regularize_correlations(int[] XX, int XX_ptr, int[] xx, int xx_ptr, int noise, int D) { - for (int i = 0; i < D; ++i) { - Inlines.MatrixSet(XX, XX_ptr, i, i, D, Inlines.silk_ADD32(Inlines.MatrixGet(XX, XX_ptr, i, i, D), noise)); - } - int n = xx_ptr; - xx[n] = xx[n] + noise; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Resampler.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Resampler.java deleted file mode 100644 index beb6dca..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Resampler.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkError; -import de.maxhenkel.voicechat.concentus.SilkResamplerState; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class Resampler { - private static final int USE_silk_resampler_copy = 0; - private static final int USE_silk_resampler_private_up2_HQ_wrapper = 1; - private static final int USE_silk_resampler_private_IIR_FIR = 2; - private static final int USE_silk_resampler_private_down_FIR = 3; - private static final int ORDER_FIR = 4; - - Resampler() { - } - - private static int rateID(int R) { - return ((R >> 12) - (R > 16000 ? 1 : 0) >> (R > 24000 ? 1 : 0)) - 1; - } - - /* - * Enabled aggressive block sorting - */ - static int silk_resampler_init(SilkResamplerState S, int Fs_Hz_in, int Fs_Hz_out, int forEnc) { - int up2x; - block13: { - block15: { - block18: { - block17: { - block16: { - block14: { - S.Reset(); - if (forEnc != 0) { - if (Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000 || Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000) { - Inlines.OpusAssert(false); - return -1; - } - S.inputDelay = SilkTables.delay_matrix_enc[Resampler.rateID(Fs_Hz_in)][Resampler.rateID(Fs_Hz_out)]; - } else { - if (Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 || Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000) { - Inlines.OpusAssert(false); - return -1; - } - S.inputDelay = SilkTables.delay_matrix_dec[Resampler.rateID(Fs_Hz_in)][Resampler.rateID(Fs_Hz_out)]; - } - S.Fs_in_kHz = Inlines.silk_DIV32_16(Fs_Hz_in, 1000); - S.Fs_out_kHz = Inlines.silk_DIV32_16(Fs_Hz_out, 1000); - S.batchSize = S.Fs_in_kHz * 10; - up2x = 0; - if (Fs_Hz_out <= Fs_Hz_in) break block14; - if (Fs_Hz_out == Inlines.silk_MUL(Fs_Hz_in, 2)) { - S.resampler_function = 1; - break block13; - } else { - S.resampler_function = 2; - up2x = 1; - } - break block13; - } - if (Fs_Hz_out >= Fs_Hz_in) break block15; - S.resampler_function = 3; - if (Inlines.silk_MUL(Fs_Hz_out, 4) != Inlines.silk_MUL(Fs_Hz_in, 3)) break block16; - S.FIR_Fracs = 3; - S.FIR_Order = 18; - S.Coefs = SilkTables.silk_Resampler_3_4_COEFS; - break block13; - } - if (Inlines.silk_MUL(Fs_Hz_out, 3) != Inlines.silk_MUL(Fs_Hz_in, 2)) break block17; - S.FIR_Fracs = 2; - S.FIR_Order = 18; - S.Coefs = SilkTables.silk_Resampler_2_3_COEFS; - break block13; - } - if (Inlines.silk_MUL(Fs_Hz_out, 2) != Fs_Hz_in) break block18; - S.FIR_Fracs = 1; - S.FIR_Order = 24; - S.Coefs = SilkTables.silk_Resampler_1_2_COEFS; - break block13; - } - if (Inlines.silk_MUL(Fs_Hz_out, 3) == Fs_Hz_in) { - S.FIR_Fracs = 1; - S.FIR_Order = 36; - S.Coefs = SilkTables.silk_Resampler_1_3_COEFS; - break block13; - } else if (Inlines.silk_MUL(Fs_Hz_out, 4) == Fs_Hz_in) { - S.FIR_Fracs = 1; - S.FIR_Order = 36; - S.Coefs = SilkTables.silk_Resampler_1_4_COEFS; - break block13; - } else { - if (Inlines.silk_MUL(Fs_Hz_out, 6) != Fs_Hz_in) { - Inlines.OpusAssert(false); - return -1; - } - S.FIR_Fracs = 1; - S.FIR_Order = 36; - S.Coefs = SilkTables.silk_Resampler_1_6_COEFS; - } - break block13; - } - S.resampler_function = 0; - } - S.invRatio_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_DIV32(Inlines.silk_LSHIFT32(Fs_Hz_in, 14 + up2x), Fs_Hz_out), 2); - while (Inlines.silk_SMULWW(S.invRatio_Q16, Fs_Hz_out) < Inlines.silk_LSHIFT32(Fs_Hz_in, up2x)) { - ++S.invRatio_Q16; - } - return 0; - } - - static int silk_resampler(SilkResamplerState S, short[] output, int output_ptr, short[] input, int input_ptr, int inLen) { - Inlines.OpusAssert(inLen >= S.Fs_in_kHz); - Inlines.OpusAssert(S.inputDelay <= S.Fs_in_kHz); - int nSamples = S.Fs_in_kHz - S.inputDelay; - short[] delayBufPtr = S.delayBuf; - System.arraycopy(input, input_ptr, delayBufPtr, S.inputDelay, nSamples); - switch (S.resampler_function) { - case 1: { - Resampler.silk_resampler_private_up2_HQ(S.sIIR, output, output_ptr, delayBufPtr, 0, S.Fs_in_kHz); - Resampler.silk_resampler_private_up2_HQ(S.sIIR, output, output_ptr + S.Fs_out_kHz, input, input_ptr + nSamples, inLen - S.Fs_in_kHz); - break; - } - case 2: { - Resampler.silk_resampler_private_IIR_FIR(S, output, output_ptr, delayBufPtr, 0, S.Fs_in_kHz); - Resampler.silk_resampler_private_IIR_FIR(S, output, output_ptr + S.Fs_out_kHz, input, input_ptr + nSamples, inLen - S.Fs_in_kHz); - break; - } - case 3: { - Resampler.silk_resampler_private_down_FIR(S, output, output_ptr, delayBufPtr, 0, S.Fs_in_kHz); - Resampler.silk_resampler_private_down_FIR(S, output, output_ptr + S.Fs_out_kHz, input, input_ptr + nSamples, inLen - S.Fs_in_kHz); - break; - } - default: { - System.arraycopy(delayBufPtr, 0, output, output_ptr, S.Fs_in_kHz); - System.arraycopy(input, input_ptr + nSamples, output, output_ptr + S.Fs_out_kHz, inLen - S.Fs_in_kHz); - } - } - System.arraycopy(input, input_ptr + inLen - S.inputDelay, delayBufPtr, 0, S.inputDelay); - return SilkError.SILK_NO_ERROR; - } - - static void silk_resampler_down2(int[] S, short[] output, short[] input, int inLen) { - int len2 = Inlines.silk_RSHIFT32(inLen, 1); - Inlines.OpusAssert(true); - Inlines.OpusAssert(true); - for (int k = 0; k < len2; ++k) { - int in32 = Inlines.silk_LSHIFT(input[2 * k], 10); - int Y = Inlines.silk_SUB32(in32, S[0]); - int X = Inlines.silk_SMLAWB(Y, Y, -25727); - int out32 = Inlines.silk_ADD32(S[0], X); - S[0] = Inlines.silk_ADD32(in32, X); - in32 = Inlines.silk_LSHIFT(input[2 * k + 1], 10); - Y = Inlines.silk_SUB32(in32, S[1]); - X = Inlines.silk_SMULWB(Y, 9872); - out32 = Inlines.silk_ADD32(out32, S[1]); - out32 = Inlines.silk_ADD32(out32, X); - S[1] = Inlines.silk_ADD32(in32, X); - output[k] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(out32, 11)); - } - } - - static void silk_resampler_down2_3(int[] S, short[] output, short[] input, int inLen) { - int nSamplesIn; - int[] buf = new int[484]; - int input_ptr = 0; - int output_ptr = 0; - System.arraycopy(S, 0, buf, 0, 4); - while (true) { - nSamplesIn = Inlines.silk_min(inLen, 480); - Resampler.silk_resampler_private_AR2(S, 4, buf, 4, input, input_ptr, SilkTables.silk_Resampler_2_3_COEFS_LQ, nSamplesIn); - int buf_ptr = 0; - for (int counter = nSamplesIn; counter > 2; counter -= 3) { - int res_Q6 = Inlines.silk_SMULWB(buf[buf_ptr], SilkTables.silk_Resampler_2_3_COEFS_LQ[2]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 1], SilkTables.silk_Resampler_2_3_COEFS_LQ[3]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 2], SilkTables.silk_Resampler_2_3_COEFS_LQ[5]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 3], SilkTables.silk_Resampler_2_3_COEFS_LQ[4]); - output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q6, 6)); - res_Q6 = Inlines.silk_SMULWB(buf[buf_ptr + 1], SilkTables.silk_Resampler_2_3_COEFS_LQ[4]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 2], SilkTables.silk_Resampler_2_3_COEFS_LQ[5]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 3], SilkTables.silk_Resampler_2_3_COEFS_LQ[3]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 4], SilkTables.silk_Resampler_2_3_COEFS_LQ[2]); - output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q6, 6)); - buf_ptr += 3; - } - input_ptr += nSamplesIn; - if ((inLen -= nSamplesIn) <= 0) break; - System.arraycopy(buf, nSamplesIn, buf, 0, 4); - } - System.arraycopy(buf, nSamplesIn, S, 0, 4); - } - - static void silk_resampler_private_AR2(int[] S, int S_ptr, int[] out_Q8, int out_Q8_ptr, short[] input, int input_ptr, short[] A_Q14, int len) { - for (int k = 0; k < len; ++k) { - int out32; - out_Q8[out_Q8_ptr + k] = out32 = Inlines.silk_ADD_LSHIFT32(S[S_ptr], input[input_ptr + k], 8); - out32 = Inlines.silk_LSHIFT(out32, 2); - S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr + 1], out32, A_Q14[0]); - S[S_ptr + 1] = Inlines.silk_SMULWB(out32, A_Q14[1]); - } - } - - static int silk_resampler_private_down_FIR_INTERPOL(short[] output, int output_ptr, int[] buf, short[] FIR_Coefs, int FIR_Coefs_ptr, int FIR_Order, int FIR_Fracs, int max_index_Q16, int index_increment_Q16) { - switch (FIR_Order) { - case 18: { - for (int index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16) { - int buf_ptr = Inlines.silk_RSHIFT(index_Q16, 16); - int interpol_ind = Inlines.silk_SMULWB(index_Q16 & 0xFFFF, FIR_Fracs); - int interpol_ptr = FIR_Coefs_ptr + 9 * interpol_ind; - int res_Q6 = Inlines.silk_SMULWB(buf[buf_ptr + 0], FIR_Coefs[interpol_ptr + 0]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 1], FIR_Coefs[interpol_ptr + 1]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 2], FIR_Coefs[interpol_ptr + 2]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 3], FIR_Coefs[interpol_ptr + 3]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 4], FIR_Coefs[interpol_ptr + 4]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 5], FIR_Coefs[interpol_ptr + 5]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 6], FIR_Coefs[interpol_ptr + 6]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 7], FIR_Coefs[interpol_ptr + 7]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 8], FIR_Coefs[interpol_ptr + 8]); - interpol_ptr = FIR_Coefs_ptr + 9 * (FIR_Fracs - 1 - interpol_ind); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 17], FIR_Coefs[interpol_ptr + 0]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 16], FIR_Coefs[interpol_ptr + 1]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 15], FIR_Coefs[interpol_ptr + 2]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 14], FIR_Coefs[interpol_ptr + 3]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 13], FIR_Coefs[interpol_ptr + 4]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 12], FIR_Coefs[interpol_ptr + 5]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 11], FIR_Coefs[interpol_ptr + 6]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 10], FIR_Coefs[interpol_ptr + 7]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, buf[buf_ptr + 9], FIR_Coefs[interpol_ptr + 8]); - output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q6, 6)); - } - break; - } - case 24: { - for (int index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16) { - int buf_ptr = Inlines.silk_RSHIFT(index_Q16, 16); - int res_Q6 = Inlines.silk_SMULWB(Inlines.silk_ADD32(buf[buf_ptr + 0], buf[buf_ptr + 23]), FIR_Coefs[FIR_Coefs_ptr + 0]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 1], buf[buf_ptr + 22]), FIR_Coefs[FIR_Coefs_ptr + 1]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 2], buf[buf_ptr + 21]), FIR_Coefs[FIR_Coefs_ptr + 2]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 3], buf[buf_ptr + 20]), FIR_Coefs[FIR_Coefs_ptr + 3]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 4], buf[buf_ptr + 19]), FIR_Coefs[FIR_Coefs_ptr + 4]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 5], buf[buf_ptr + 18]), FIR_Coefs[FIR_Coefs_ptr + 5]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 6], buf[buf_ptr + 17]), FIR_Coefs[FIR_Coefs_ptr + 6]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 7], buf[buf_ptr + 16]), FIR_Coefs[FIR_Coefs_ptr + 7]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 8], buf[buf_ptr + 15]), FIR_Coefs[FIR_Coefs_ptr + 8]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 9], buf[buf_ptr + 14]), FIR_Coefs[FIR_Coefs_ptr + 9]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 10], buf[buf_ptr + 13]), FIR_Coefs[FIR_Coefs_ptr + 10]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 11], buf[buf_ptr + 12]), FIR_Coefs[FIR_Coefs_ptr + 11]); - output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q6, 6)); - } - break; - } - case 36: { - for (int index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16) { - int buf_ptr = Inlines.silk_RSHIFT(index_Q16, 16); - int res_Q6 = Inlines.silk_SMULWB(Inlines.silk_ADD32(buf[buf_ptr + 0], buf[buf_ptr + 35]), FIR_Coefs[FIR_Coefs_ptr + 0]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 1], buf[buf_ptr + 34]), FIR_Coefs[FIR_Coefs_ptr + 1]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 2], buf[buf_ptr + 33]), FIR_Coefs[FIR_Coefs_ptr + 2]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 3], buf[buf_ptr + 32]), FIR_Coefs[FIR_Coefs_ptr + 3]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 4], buf[buf_ptr + 31]), FIR_Coefs[FIR_Coefs_ptr + 4]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 5], buf[buf_ptr + 30]), FIR_Coefs[FIR_Coefs_ptr + 5]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 6], buf[buf_ptr + 29]), FIR_Coefs[FIR_Coefs_ptr + 6]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 7], buf[buf_ptr + 28]), FIR_Coefs[FIR_Coefs_ptr + 7]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 8], buf[buf_ptr + 27]), FIR_Coefs[FIR_Coefs_ptr + 8]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 9], buf[buf_ptr + 26]), FIR_Coefs[FIR_Coefs_ptr + 9]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 10], buf[buf_ptr + 25]), FIR_Coefs[FIR_Coefs_ptr + 10]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 11], buf[buf_ptr + 24]), FIR_Coefs[FIR_Coefs_ptr + 11]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 12], buf[buf_ptr + 23]), FIR_Coefs[FIR_Coefs_ptr + 12]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 13], buf[buf_ptr + 22]), FIR_Coefs[FIR_Coefs_ptr + 13]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 14], buf[buf_ptr + 21]), FIR_Coefs[FIR_Coefs_ptr + 14]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 15], buf[buf_ptr + 20]), FIR_Coefs[FIR_Coefs_ptr + 15]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 16], buf[buf_ptr + 19]), FIR_Coefs[FIR_Coefs_ptr + 16]); - res_Q6 = Inlines.silk_SMLAWB(res_Q6, Inlines.silk_ADD32(buf[buf_ptr + 17], buf[buf_ptr + 18]), FIR_Coefs[FIR_Coefs_ptr + 17]); - output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q6, 6)); - } - break; - } - default: { - Inlines.OpusAssert(false); - } - } - return output_ptr; - } - - static void silk_resampler_private_down_FIR(SilkResamplerState S, short[] output, int output_ptr, short[] input, int input_ptr, int inLen) { - int nSamplesIn; - int[] buf = new int[S.batchSize + S.FIR_Order]; - System.arraycopy(S.sFIR_i32, 0, buf, 0, S.FIR_Order); - int index_increment_Q16 = S.invRatio_Q16; - while (true) { - nSamplesIn = Inlines.silk_min(inLen, S.batchSize); - Resampler.silk_resampler_private_AR2(S.sIIR, 0, buf, S.FIR_Order, input, input_ptr, S.Coefs, nSamplesIn); - int max_index_Q16 = Inlines.silk_LSHIFT32(nSamplesIn, 16); - output_ptr = Resampler.silk_resampler_private_down_FIR_INTERPOL(output, output_ptr, buf, S.Coefs, 2, S.FIR_Order, S.FIR_Fracs, max_index_Q16, index_increment_Q16); - input_ptr += nSamplesIn; - if ((inLen -= nSamplesIn) <= 1) break; - System.arraycopy(buf, nSamplesIn, buf, 0, S.FIR_Order); - } - System.arraycopy(buf, nSamplesIn, S.sFIR_i32, 0, S.FIR_Order); - } - - static int silk_resampler_private_IIR_FIR_INTERPOL(short[] output, int output_ptr, short[] buf, int max_index_Q16, int index_increment_Q16) { - for (int index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16) { - int table_index = Inlines.silk_SMULWB(index_Q16 & 0xFFFF, 12); - int buf_ptr = index_Q16 >> 16; - int res_Q15 = Inlines.silk_SMULBB(buf[buf_ptr], SilkTables.silk_resampler_frac_FIR_12[table_index][0]); - res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 1], SilkTables.silk_resampler_frac_FIR_12[table_index][1]); - res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 2], SilkTables.silk_resampler_frac_FIR_12[table_index][2]); - res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 3], SilkTables.silk_resampler_frac_FIR_12[table_index][3]); - res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 4], SilkTables.silk_resampler_frac_FIR_12[11 - table_index][3]); - res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 5], SilkTables.silk_resampler_frac_FIR_12[11 - table_index][2]); - res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 6], SilkTables.silk_resampler_frac_FIR_12[11 - table_index][1]); - res_Q15 = Inlines.silk_SMLABB(res_Q15, buf[buf_ptr + 7], SilkTables.silk_resampler_frac_FIR_12[11 - table_index][0]); - output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(res_Q15, 15)); - } - return output_ptr; - } - - static void silk_resampler_private_IIR_FIR(SilkResamplerState S, short[] output, int output_ptr, short[] input, int input_ptr, int inLen) { - int nSamplesIn; - short[] buf = new short[2 * S.batchSize + 8]; - System.arraycopy(S.sFIR_i16, 0, buf, 0, 8); - int index_increment_Q16 = S.invRatio_Q16; - while (true) { - nSamplesIn = Inlines.silk_min(inLen, S.batchSize); - Resampler.silk_resampler_private_up2_HQ(S.sIIR, buf, 8, input, input_ptr, nSamplesIn); - int max_index_Q16 = Inlines.silk_LSHIFT32(nSamplesIn, 17); - output_ptr = Resampler.silk_resampler_private_IIR_FIR_INTERPOL(output, output_ptr, buf, max_index_Q16, index_increment_Q16); - input_ptr += nSamplesIn; - if ((inLen -= nSamplesIn) <= 0) break; - System.arraycopy(buf, nSamplesIn << 1, buf, 0, 8); - } - System.arraycopy(buf, nSamplesIn << 1, S.sFIR_i16, 0, 8); - } - - static void silk_resampler_private_up2_HQ(int[] S, short[] output, int output_ptr, short[] input, int input_ptr, int len) { - Inlines.OpusAssert(SilkTables.silk_resampler_up2_hq_0[0] > 0); - Inlines.OpusAssert(SilkTables.silk_resampler_up2_hq_0[1] > 0); - Inlines.OpusAssert(SilkTables.silk_resampler_up2_hq_0[2] < 0); - Inlines.OpusAssert(SilkTables.silk_resampler_up2_hq_1[0] > 0); - Inlines.OpusAssert(SilkTables.silk_resampler_up2_hq_1[1] > 0); - Inlines.OpusAssert(SilkTables.silk_resampler_up2_hq_1[2] < 0); - for (int k = 0; k < len; ++k) { - int in32 = Inlines.silk_LSHIFT(input[input_ptr + k], 10); - int Y = Inlines.silk_SUB32(in32, S[0]); - int X = Inlines.silk_SMULWB(Y, SilkTables.silk_resampler_up2_hq_0[0]); - int out32_1 = Inlines.silk_ADD32(S[0], X); - S[0] = Inlines.silk_ADD32(in32, X); - Y = Inlines.silk_SUB32(out32_1, S[1]); - X = Inlines.silk_SMULWB(Y, SilkTables.silk_resampler_up2_hq_0[1]); - int out32_2 = Inlines.silk_ADD32(S[1], X); - S[1] = Inlines.silk_ADD32(out32_1, X); - Y = Inlines.silk_SUB32(out32_2, S[2]); - X = Inlines.silk_SMLAWB(Y, Y, SilkTables.silk_resampler_up2_hq_0[2]); - out32_1 = Inlines.silk_ADD32(S[2], X); - S[2] = Inlines.silk_ADD32(out32_2, X); - output[output_ptr + 2 * k] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(out32_1, 10)); - Y = Inlines.silk_SUB32(in32, S[3]); - X = Inlines.silk_SMULWB(Y, SilkTables.silk_resampler_up2_hq_1[0]); - out32_1 = Inlines.silk_ADD32(S[3], X); - S[3] = Inlines.silk_ADD32(in32, X); - Y = Inlines.silk_SUB32(out32_1, S[4]); - X = Inlines.silk_SMULWB(Y, SilkTables.silk_resampler_up2_hq_1[1]); - out32_2 = Inlines.silk_ADD32(S[4], X); - S[4] = Inlines.silk_ADD32(out32_1, X); - Y = Inlines.silk_SUB32(out32_2, S[5]); - X = Inlines.silk_SMLAWB(Y, Y, SilkTables.silk_resampler_up2_hq_1[2]); - out32_1 = Inlines.silk_ADD32(S[5], X); - S[5] = Inlines.silk_ADD32(out32_2, X); - output[output_ptr + 2 * k + 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(out32_1, 10)); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/ResidualEnergy.java b/source/decompiled/de/maxhenkel/voicechat/concentus/ResidualEnergy.java deleted file mode 100644 index 459a5f2..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/ResidualEnergy.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SumSqrShift; - -class ResidualEnergy { - ResidualEnergy() { - } - - static void silk_residual_energy(int[] nrgs, int[] nrgsQ, short[] x, short[][] a_Q12, int[] gains, int subfr_length, int nb_subfr, int LPC_order) { - int i; - BoxedValueInt rshift = new BoxedValueInt(0); - BoxedValueInt energy = new BoxedValueInt(0); - int x_ptr = 0; - int offset = LPC_order + subfr_length; - short[] LPC_res = new short[2 * offset]; - Inlines.OpusAssert((nb_subfr >> 1) * 2 == nb_subfr); - for (i = 0; i < nb_subfr >> 1; ++i) { - Filters.silk_LPC_analysis_filter(LPC_res, 0, x, x_ptr, a_Q12[i], 0, 2 * offset, LPC_order); - int LPC_res_ptr = LPC_order; - for (int j = 0; j < 2; ++j) { - SumSqrShift.silk_sum_sqr_shift(energy, rshift, LPC_res, LPC_res_ptr, subfr_length); - nrgs[i * 2 + j] = energy.Val; - nrgsQ[i * 2 + j] = 0 - rshift.Val; - LPC_res_ptr += offset; - } - x_ptr += 2 * offset; - } - i = 0; - while (i < nb_subfr) { - int lz1 = Inlines.silk_CLZ32(nrgs[i]) - 1; - int lz2 = Inlines.silk_CLZ32(gains[i]) - 1; - int tmp32 = Inlines.silk_LSHIFT32(gains[i], lz2); - tmp32 = Inlines.silk_SMMUL(tmp32, tmp32); - nrgs[i] = Inlines.silk_SMMUL(tmp32, Inlines.silk_LSHIFT32(nrgs[i], lz1)); - int n = i++; - nrgsQ[n] = nrgsQ[n] + (lz1 + 2 * lz2 - 32 - 32); - } - } - - static int silk_residual_energy16_covar(short[] c, int c_ptr, int[] wXX, int wXX_ptr, int[] wXx, int wxx, int D, int cQ) { - int i; - int lshifts; - int[] cn = new int[D]; - Inlines.OpusAssert(D >= 0); - Inlines.OpusAssert(D <= 16); - Inlines.OpusAssert(cQ > 0); - Inlines.OpusAssert(cQ < 16); - int Qxtra = lshifts = 16 - cQ; - int c_max = 0; - for (i = c_ptr; i < c_ptr + D; ++i) { - c_max = Inlines.silk_max_32(c_max, Inlines.silk_abs(c[i])); - } - Qxtra = Inlines.silk_min_int(Qxtra, Inlines.silk_CLZ32(c_max) - 17); - int w_max = Inlines.silk_max_32(wXX[wXX_ptr], wXX[wXX_ptr + D * D - 1]); - Qxtra = Inlines.silk_min_int(Qxtra, Inlines.silk_CLZ32(Inlines.silk_MUL(D, Inlines.silk_RSHIFT(Inlines.silk_SMULWB(w_max, c_max), 4))) - 5); - Qxtra = Inlines.silk_max_int(Qxtra, 0); - for (i = 0; i < D; ++i) { - cn[i] = Inlines.silk_LSHIFT(c[c_ptr + i], Qxtra); - Inlines.OpusAssert(Inlines.silk_abs(cn[i]) <= 32768); - } - lshifts -= Qxtra; - int tmp = 0; - for (i = 0; i < D; ++i) { - tmp = Inlines.silk_SMLAWB(tmp, wXx[i], cn[i]); - } - int nrg = Inlines.silk_RSHIFT(wxx, 1 + lshifts) - tmp; - int tmp2 = 0; - for (i = 0; i < D; ++i) { - tmp = 0; - int pRow = wXX_ptr + i * D; - for (int j = i + 1; j < D; ++j) { - tmp = Inlines.silk_SMLAWB(tmp, wXX[pRow + j], cn[j]); - } - tmp = Inlines.silk_SMLAWB(tmp, Inlines.silk_RSHIFT(wXX[pRow + i], 1), cn[i]); - tmp2 = Inlines.silk_SMLAWB(tmp2, tmp, cn[i]); - } - nrg = (nrg = Inlines.silk_ADD_LSHIFT32(nrg, tmp2, lshifts)) < 1 ? 1 : (nrg > Inlines.silk_RSHIFT(Integer.MAX_VALUE, lshifts + 2) ? 0x3FFFFFFF : Inlines.silk_LSHIFT(nrg, lshifts + 1)); - return nrg; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Schur.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Schur.java deleted file mode 100644 index a7135cd..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Schur.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.Inlines; - -class Schur { - Schur() { - } - - static int silk_schur(short[] rc_Q15, int[] c, int order) { - int k; - int[][] C = Arrays.InitTwoDimensionalArrayInt(17, 2); - Inlines.OpusAssert(order == 6 || order == 8 || order == 10 || order == 12 || order == 14 || order == 16); - int lz = Inlines.silk_CLZ32(c[0]); - if (lz < 2) { - for (k = 0; k < order + 1; ++k) { - int n = Inlines.silk_RSHIFT(c[k], 1); - C[k][1] = n; - C[k][0] = n; - } - } else if (lz > 2) { - lz -= 2; - for (k = 0; k < order + 1; ++k) { - int n = Inlines.silk_LSHIFT(c[k], lz); - C[k][1] = n; - C[k][0] = n; - } - } else { - for (k = 0; k < order + 1; ++k) { - int n = c[k]; - C[k][1] = n; - C[k][0] = n; - } - } - for (k = 0; k < order; ++k) { - if (Inlines.silk_abs_int32(C[k + 1][0]) >= C[0][1]) { - rc_Q15[k] = C[k + 1][0] > 0 ? -32440 : 32440; - ++k; - break; - } - int rc_tmp_Q15 = 0 - Inlines.silk_DIV32_16(C[k + 1][0], Inlines.silk_max_32(Inlines.silk_RSHIFT(C[0][1], 15), 1)); - rc_tmp_Q15 = Inlines.silk_SAT16(rc_tmp_Q15); - rc_Q15[k] = (short)rc_tmp_Q15; - for (int n = 0; n < order - k; ++n) { - int Ctmp1 = C[n + k + 1][0]; - int Ctmp2 = C[n][1]; - C[n + k + 1][0] = Inlines.silk_SMLAWB(Ctmp1, Inlines.silk_LSHIFT(Ctmp2, 1), rc_tmp_Q15); - C[n][1] = Inlines.silk_SMLAWB(Ctmp2, Inlines.silk_LSHIFT(Ctmp1, 1), rc_tmp_Q15); - } - } - while (k < order) { - rc_Q15[k] = 0; - ++k; - } - return Inlines.silk_max_32(1, C[0][1]); - } - - static int silk_schur64(int[] rc_Q16, int[] c, int order) { - int k; - int[][] C = Arrays.InitTwoDimensionalArrayInt(17, 2); - Inlines.OpusAssert(order == 6 || order == 8 || order == 10 || order == 12 || order == 14 || order == 16); - if (c[0] <= 0) { - Arrays.MemSet(rc_Q16, 0, order); - return 0; - } - for (k = 0; k < order + 1; ++k) { - int n = c[k]; - C[k][1] = n; - C[k][0] = n; - } - for (k = 0; k < order; ++k) { - if (Inlines.silk_abs_int32(C[k + 1][0]) >= C[0][1]) { - rc_Q16[k] = C[k + 1][0] > 0 ? -64881 : 64881; - ++k; - break; - } - int rc_tmp_Q31 = Inlines.silk_DIV32_varQ(-C[k + 1][0], C[0][1], 31); - rc_Q16[k] = Inlines.silk_RSHIFT_ROUND(rc_tmp_Q31, 15); - for (int n = 0; n < order - k; ++n) { - int Ctmp1_Q30 = C[n + k + 1][0]; - int Ctmp2_Q30 = C[n][1]; - C[n + k + 1][0] = Ctmp1_Q30 + Inlines.silk_SMMUL(Inlines.silk_LSHIFT(Ctmp2_Q30, 1), rc_tmp_Q31); - C[n][1] = Ctmp2_Q30 + Inlines.silk_SMMUL(Inlines.silk_LSHIFT(Ctmp1_Q30, 1), rc_tmp_Q31); - } - } - while (k < order) { - rc_Q16[k] = 0; - ++k; - } - return Inlines.silk_max_32(1, C[0][1]); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/ShellCoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/ShellCoder.java deleted file mode 100644 index 9c92bed..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/ShellCoder.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class ShellCoder { - ShellCoder() { - } - - static void combine_pulses(int[] output, int[] input, int input_ptr, int len) { - for (int k = 0; k < len; ++k) { - output[k] = input[input_ptr + 2 * k] + input[input_ptr + 2 * k + 1]; - } - } - - static void combine_pulses(int[] output, int[] input, int len) { - for (int k = 0; k < len; ++k) { - output[k] = input[2 * k] + input[2 * k + 1]; - } - } - - static void encode_split(EntropyCoder psRangeEnc, int p_child1, int p, short[] shell_table) { - if (p > 0) { - psRangeEnc.enc_icdf(p_child1, shell_table, SilkTables.silk_shell_code_table_offsets[p], 8); - } - } - - static void decode_split(short[] p_child1, int child1_ptr, short[] p_child2, int p_child2_ptr, EntropyCoder psRangeDec, int p, short[] shell_table) { - if (p > 0) { - p_child1[child1_ptr] = (short)psRangeDec.dec_icdf(shell_table, SilkTables.silk_shell_code_table_offsets[p], 8); - p_child2[p_child2_ptr] = (short)(p - p_child1[child1_ptr]); - } else { - p_child1[child1_ptr] = 0; - p_child2[p_child2_ptr] = 0; - } - } - - static void silk_shell_encoder(EntropyCoder psRangeEnc, int[] pulses0, int pulses0_ptr) { - int[] pulses1 = new int[8]; - int[] pulses2 = new int[4]; - int[] pulses3 = new int[2]; - int[] pulses4 = new int[1]; - Inlines.OpusAssert(true); - ShellCoder.combine_pulses(pulses1, pulses0, pulses0_ptr, 8); - ShellCoder.combine_pulses(pulses2, pulses1, 4); - ShellCoder.combine_pulses(pulses3, pulses2, 2); - ShellCoder.combine_pulses(pulses4, pulses3, 1); - ShellCoder.encode_split(psRangeEnc, pulses3[0], pulses4[0], SilkTables.silk_shell_code_table3); - ShellCoder.encode_split(psRangeEnc, pulses2[0], pulses3[0], SilkTables.silk_shell_code_table2); - ShellCoder.encode_split(psRangeEnc, pulses1[0], pulses2[0], SilkTables.silk_shell_code_table1); - ShellCoder.encode_split(psRangeEnc, pulses0[pulses0_ptr], pulses1[0], SilkTables.silk_shell_code_table0); - ShellCoder.encode_split(psRangeEnc, pulses0[pulses0_ptr + 2], pulses1[1], SilkTables.silk_shell_code_table0); - ShellCoder.encode_split(psRangeEnc, pulses1[2], pulses2[1], SilkTables.silk_shell_code_table1); - ShellCoder.encode_split(psRangeEnc, pulses0[pulses0_ptr + 4], pulses1[2], SilkTables.silk_shell_code_table0); - ShellCoder.encode_split(psRangeEnc, pulses0[pulses0_ptr + 6], pulses1[3], SilkTables.silk_shell_code_table0); - ShellCoder.encode_split(psRangeEnc, pulses2[2], pulses3[1], SilkTables.silk_shell_code_table2); - ShellCoder.encode_split(psRangeEnc, pulses1[4], pulses2[2], SilkTables.silk_shell_code_table1); - ShellCoder.encode_split(psRangeEnc, pulses0[pulses0_ptr + 8], pulses1[4], SilkTables.silk_shell_code_table0); - ShellCoder.encode_split(psRangeEnc, pulses0[pulses0_ptr + 10], pulses1[5], SilkTables.silk_shell_code_table0); - ShellCoder.encode_split(psRangeEnc, pulses1[6], pulses2[3], SilkTables.silk_shell_code_table1); - ShellCoder.encode_split(psRangeEnc, pulses0[pulses0_ptr + 12], pulses1[6], SilkTables.silk_shell_code_table0); - ShellCoder.encode_split(psRangeEnc, pulses0[pulses0_ptr + 14], pulses1[7], SilkTables.silk_shell_code_table0); - } - - static void silk_shell_decoder(short[] pulses0, int pulses0_ptr, EntropyCoder psRangeDec, int pulses4) { - short[] pulses1 = new short[8]; - short[] pulses2 = new short[4]; - short[] pulses3 = new short[2]; - Inlines.OpusAssert(true); - ShellCoder.decode_split(pulses3, 0, pulses3, 1, psRangeDec, pulses4, SilkTables.silk_shell_code_table3); - ShellCoder.decode_split(pulses2, 0, pulses2, 1, psRangeDec, pulses3[0], SilkTables.silk_shell_code_table2); - ShellCoder.decode_split(pulses1, 0, pulses1, 1, psRangeDec, pulses2[0], SilkTables.silk_shell_code_table1); - ShellCoder.decode_split(pulses0, pulses0_ptr, pulses0, pulses0_ptr + 1, psRangeDec, pulses1[0], SilkTables.silk_shell_code_table0); - ShellCoder.decode_split(pulses0, pulses0_ptr + 2, pulses0, pulses0_ptr + 3, psRangeDec, pulses1[1], SilkTables.silk_shell_code_table0); - ShellCoder.decode_split(pulses1, 2, pulses1, 3, psRangeDec, pulses2[1], SilkTables.silk_shell_code_table1); - ShellCoder.decode_split(pulses0, pulses0_ptr + 4, pulses0, pulses0_ptr + 5, psRangeDec, pulses1[2], SilkTables.silk_shell_code_table0); - ShellCoder.decode_split(pulses0, pulses0_ptr + 6, pulses0, pulses0_ptr + 7, psRangeDec, pulses1[3], SilkTables.silk_shell_code_table0); - ShellCoder.decode_split(pulses2, 2, pulses2, 3, psRangeDec, pulses3[1], SilkTables.silk_shell_code_table2); - ShellCoder.decode_split(pulses1, 4, pulses1, 5, psRangeDec, pulses2[2], SilkTables.silk_shell_code_table1); - ShellCoder.decode_split(pulses0, pulses0_ptr + 8, pulses0, pulses0_ptr + 9, psRangeDec, pulses1[4], SilkTables.silk_shell_code_table0); - ShellCoder.decode_split(pulses0, pulses0_ptr + 10, pulses0, pulses0_ptr + 11, psRangeDec, pulses1[5], SilkTables.silk_shell_code_table0); - ShellCoder.decode_split(pulses1, 6, pulses1, 7, psRangeDec, pulses2[3], SilkTables.silk_shell_code_table1); - ShellCoder.decode_split(pulses0, pulses0_ptr + 12, pulses0, pulses0_ptr + 13, psRangeDec, pulses1[6], SilkTables.silk_shell_code_table0); - ShellCoder.decode_split(pulses0, pulses0_ptr + 14, pulses0, pulses0_ptr + 15, psRangeDec, pulses1[7], SilkTables.silk_shell_code_table0); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SideInfoIndices.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SideInfoIndices.java deleted file mode 100644 index 0549f79..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SideInfoIndices.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class SideInfoIndices { - final byte[] GainsIndices = new byte[4]; - final byte[] LTPIndex = new byte[4]; - final byte[] NLSFIndices = new byte[17]; - short lagIndex = 0; - byte contourIndex = 0; - byte signalType = 0; - byte quantOffsetType = 0; - byte NLSFInterpCoef_Q2 = 0; - byte PERIndex = 0; - byte LTP_scaleIndex = 0; - byte Seed = 0; - - SideInfoIndices() { - } - - void Reset() { - Arrays.MemSet(this.GainsIndices, (byte)0, 4); - Arrays.MemSet(this.LTPIndex, (byte)0, 4); - Arrays.MemSet(this.NLSFIndices, (byte)0, 17); - this.lagIndex = 0; - this.contourIndex = 0; - this.signalType = 0; - this.quantOffsetType = 0; - this.NLSFInterpCoef_Q2 = 0; - this.PERIndex = 0; - this.LTP_scaleIndex = 0; - this.Seed = 0; - } - - void Assign(SideInfoIndices other) { - System.arraycopy(other.GainsIndices, 0, this.GainsIndices, 0, 4); - System.arraycopy(other.LTPIndex, 0, this.LTPIndex, 0, 4); - System.arraycopy(other.NLSFIndices, 0, this.NLSFIndices, 0, 17); - this.lagIndex = other.lagIndex; - this.contourIndex = other.contourIndex; - this.signalType = other.signalType; - this.quantOffsetType = other.quantOffsetType; - this.NLSFInterpCoef_Q2 = other.NLSFInterpCoef_Q2; - this.PERIndex = other.PERIndex; - this.LTP_scaleIndex = other.LTP_scaleIndex; - this.Seed = other.Seed; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Sigmoid.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Sigmoid.java deleted file mode 100644 index 3aa0ad2..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Sigmoid.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; - -class Sigmoid { - private static final int[] sigm_LUT_slope_Q10 = new int[]{237, 153, 73, 30, 12, 7}; - private static final int[] sigm_LUT_pos_Q15 = new int[]{16384, 23955, 28861, 31213, 32178, 32548}; - private static final int[] sigm_LUT_neg_Q15 = new int[]{16384, 8812, 3906, 1554, 589, 219}; - - Sigmoid() { - } - - static int silk_sigm_Q15(int in_Q5) { - if (in_Q5 < 0) { - if ((in_Q5 = -in_Q5) >= 192) { - return 0; - } - int ind = Inlines.silk_RSHIFT(in_Q5, 5); - return sigm_LUT_neg_Q15[ind] - Inlines.silk_SMULBB(sigm_LUT_slope_Q10[ind], in_Q5 & 0x1F); - } - if (in_Q5 >= 192) { - return Short.MAX_VALUE; - } - int ind = Inlines.silk_RSHIFT(in_Q5, 5); - return sigm_LUT_pos_Q15[ind] + Inlines.silk_SMULBB(sigm_LUT_slope_Q10[ind], in_Q5 & 0x1F); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkChannelDecoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkChannelDecoder.java deleted file mode 100644 index 05b0ce3..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkChannelDecoder.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.CNG; -import de.maxhenkel.voicechat.concentus.CNGState; -import de.maxhenkel.voicechat.concentus.DecodeCore; -import de.maxhenkel.voicechat.concentus.DecodeIndices; -import de.maxhenkel.voicechat.concentus.DecodeParameters; -import de.maxhenkel.voicechat.concentus.DecodePulses; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.NLSFCodebook; -import de.maxhenkel.voicechat.concentus.PLC; -import de.maxhenkel.voicechat.concentus.PLCStruct; -import de.maxhenkel.voicechat.concentus.Resampler; -import de.maxhenkel.voicechat.concentus.SideInfoIndices; -import de.maxhenkel.voicechat.concentus.SilkDecoderControl; -import de.maxhenkel.voicechat.concentus.SilkResamplerState; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class SilkChannelDecoder { - int prev_gain_Q16 = 0; - final int[] exc_Q14 = new int[320]; - final int[] sLPC_Q14_buf = new int[16]; - final short[] outBuf = new short[480]; - int lagPrev = 0; - byte LastGainIndex = 0; - int fs_kHz = 0; - int fs_API_hz = 0; - int nb_subfr = 0; - int frame_length = 0; - int subfr_length = 0; - int ltp_mem_length = 0; - int LPC_order = 0; - final short[] prevNLSF_Q15 = new short[16]; - int first_frame_after_reset = 0; - short[] pitch_lag_low_bits_iCDF; - short[] pitch_contour_iCDF; - int nFramesDecoded = 0; - int nFramesPerPacket = 0; - int ec_prevSignalType = 0; - short ec_prevLagIndex = 0; - final int[] VAD_flags = new int[3]; - int LBRR_flag = 0; - final int[] LBRR_flags = new int[3]; - final SilkResamplerState resampler_state = new SilkResamplerState(); - NLSFCodebook psNLSF_CB = null; - final SideInfoIndices indices = new SideInfoIndices(); - final CNGState sCNG = new CNGState(); - int lossCnt = 0; - int prevSignalType = 0; - final PLCStruct sPLC = new PLCStruct(); - - SilkChannelDecoder() { - } - - void Reset() { - this.prev_gain_Q16 = 0; - Arrays.MemSet(this.exc_Q14, 0, 320); - Arrays.MemSet(this.sLPC_Q14_buf, 0, 16); - Arrays.MemSet(this.outBuf, (short)0, 480); - this.lagPrev = 0; - this.LastGainIndex = 0; - this.fs_kHz = 0; - this.fs_API_hz = 0; - this.nb_subfr = 0; - this.frame_length = 0; - this.subfr_length = 0; - this.ltp_mem_length = 0; - this.LPC_order = 0; - Arrays.MemSet(this.prevNLSF_Q15, (short)0, 16); - this.first_frame_after_reset = 0; - this.pitch_lag_low_bits_iCDF = null; - this.pitch_contour_iCDF = null; - this.nFramesDecoded = 0; - this.nFramesPerPacket = 0; - this.ec_prevSignalType = 0; - this.ec_prevLagIndex = 0; - Arrays.MemSet(this.VAD_flags, 0, 3); - this.LBRR_flag = 0; - Arrays.MemSet(this.LBRR_flags, 0, 3); - this.resampler_state.Reset(); - this.psNLSF_CB = null; - this.indices.Reset(); - this.sCNG.Reset(); - this.lossCnt = 0; - this.prevSignalType = 0; - this.sPLC.Reset(); - } - - int silk_init_decoder() { - this.Reset(); - this.first_frame_after_reset = 1; - this.prev_gain_Q16 = 65536; - this.silk_CNG_Reset(); - this.silk_PLC_Reset(); - return 0; - } - - private void silk_CNG_Reset() { - int NLSF_step_Q15 = Inlines.silk_DIV32_16(Short.MAX_VALUE, this.LPC_order + 1); - int NLSF_acc_Q15 = 0; - for (int i = 0; i < this.LPC_order; ++i) { - this.sCNG.CNG_smth_NLSF_Q15[i] = (short)(NLSF_acc_Q15 += NLSF_step_Q15); - } - this.sCNG.CNG_smth_Gain_Q16 = 0; - this.sCNG.rand_seed = 3176576; - } - - private void silk_PLC_Reset() { - this.sPLC.pitchL_Q8 = Inlines.silk_LSHIFT(this.frame_length, 7); - this.sPLC.prevGain_Q16[0] = 65536; - this.sPLC.prevGain_Q16[1] = 65536; - this.sPLC.subfr_length = 20; - this.sPLC.nb_subfr = 2; - } - - int silk_decoder_set_fs(int fs_kHz, int fs_API_Hz) { - int ret = 0; - Inlines.OpusAssert(fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16); - Inlines.OpusAssert(this.nb_subfr == 4 || this.nb_subfr == 2); - this.subfr_length = Inlines.silk_SMULBB(5, fs_kHz); - int frame_length = Inlines.silk_SMULBB(this.nb_subfr, this.subfr_length); - if (this.fs_kHz != fs_kHz || this.fs_API_hz != fs_API_Hz) { - ret += Resampler.silk_resampler_init(this.resampler_state, Inlines.silk_SMULBB(fs_kHz, 1000), fs_API_Hz, 0); - this.fs_API_hz = fs_API_Hz; - } - if (this.fs_kHz != fs_kHz || frame_length != this.frame_length) { - this.pitch_contour_iCDF = fs_kHz == 8 ? (this.nb_subfr == 4 ? SilkTables.silk_pitch_contour_NB_iCDF : SilkTables.silk_pitch_contour_10_ms_NB_iCDF) : (this.nb_subfr == 4 ? SilkTables.silk_pitch_contour_iCDF : SilkTables.silk_pitch_contour_10_ms_iCDF); - if (this.fs_kHz != fs_kHz) { - this.ltp_mem_length = Inlines.silk_SMULBB(20, fs_kHz); - if (fs_kHz == 8 || fs_kHz == 12) { - this.LPC_order = 10; - this.psNLSF_CB = SilkTables.silk_NLSF_CB_NB_MB; - } else { - this.LPC_order = 16; - this.psNLSF_CB = SilkTables.silk_NLSF_CB_WB; - } - if (fs_kHz == 16) { - this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform8_iCDF; - } else if (fs_kHz == 12) { - this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform6_iCDF; - } else if (fs_kHz == 8) { - this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform4_iCDF; - } else { - Inlines.OpusAssert(false); - } - this.first_frame_after_reset = 1; - this.lagPrev = 100; - this.LastGainIndex = (byte)10; - this.prevSignalType = 0; - Arrays.MemSet(this.outBuf, (short)0, 480); - Arrays.MemSet(this.sLPC_Q14_buf, 0, 16); - } - this.fs_kHz = fs_kHz; - this.frame_length = frame_length; - } - Inlines.OpusAssert(this.frame_length > 0 && this.frame_length <= 320); - return ret; - } - - int silk_decode_frame(EntropyCoder psRangeDec, short[] pOut, int pOut_ptr, BoxedValueInt pN, int lostFlag, int condCoding) { - SilkDecoderControl thisCtrl = new SilkDecoderControl(); - int ret = 0; - int L = this.frame_length; - thisCtrl.LTP_scale_Q14 = 0; - Inlines.OpusAssert(L > 0 && L <= 320); - if (lostFlag == 0 || lostFlag == 2 && this.LBRR_flags[this.nFramesDecoded] == 1) { - short[] pulses = new short[L + 16 - 1 & 0xFFFFFFF0]; - DecodeIndices.silk_decode_indices(this, psRangeDec, this.nFramesDecoded, lostFlag, condCoding); - DecodePulses.silk_decode_pulses(psRangeDec, pulses, this.indices.signalType, this.indices.quantOffsetType, this.frame_length); - DecodeParameters.silk_decode_parameters(this, thisCtrl, condCoding); - DecodeCore.silk_decode_core(this, thisCtrl, pOut, pOut_ptr, pulses); - PLC.silk_PLC(this, thisCtrl, pOut, pOut_ptr, 0); - this.lossCnt = 0; - this.prevSignalType = this.indices.signalType; - Inlines.OpusAssert(this.prevSignalType >= 0 && this.prevSignalType <= 2); - this.first_frame_after_reset = 0; - } else { - PLC.silk_PLC(this, thisCtrl, pOut, pOut_ptr, 1); - } - Inlines.OpusAssert(this.ltp_mem_length >= this.frame_length); - int mv_len = this.ltp_mem_length - this.frame_length; - Arrays.MemMove(this.outBuf, this.frame_length, 0, mv_len); - System.arraycopy(pOut, pOut_ptr, this.outBuf, mv_len, this.frame_length); - CNG.silk_CNG(this, thisCtrl, pOut, pOut_ptr, L); - PLC.silk_PLC_glue_frames(this, pOut, pOut_ptr, L); - this.lagPrev = thisCtrl.pitchL[this.nb_subfr - 1]; - pN.Val = L; - return ret; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkChannelEncoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkChannelEncoder.java deleted file mode 100644 index 166084a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkChannelEncoder.java +++ /dev/null @@ -1,671 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.EncControlState; -import de.maxhenkel.voicechat.concentus.EncodeIndices; -import de.maxhenkel.voicechat.concentus.EncodePulses; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.FindPitchLags; -import de.maxhenkel.voicechat.concentus.FindPredCoefs; -import de.maxhenkel.voicechat.concentus.GainQuantization; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.NLSFCodebook; -import de.maxhenkel.voicechat.concentus.NoiseShapeAnalysis; -import de.maxhenkel.voicechat.concentus.ProcessGains; -import de.maxhenkel.voicechat.concentus.Resampler; -import de.maxhenkel.voicechat.concentus.SideInfoIndices; -import de.maxhenkel.voicechat.concentus.SilkEncoderControl; -import de.maxhenkel.voicechat.concentus.SilkError; -import de.maxhenkel.voicechat.concentus.SilkLPState; -import de.maxhenkel.voicechat.concentus.SilkNSQState; -import de.maxhenkel.voicechat.concentus.SilkPrefilterState; -import de.maxhenkel.voicechat.concentus.SilkResamplerState; -import de.maxhenkel.voicechat.concentus.SilkShapeState; -import de.maxhenkel.voicechat.concentus.SilkTables; -import de.maxhenkel.voicechat.concentus.SilkVADState; -import de.maxhenkel.voicechat.concentus.VoiceActivityDetection; - -class SilkChannelEncoder { - final int[] In_HP_State = new int[2]; - int variable_HP_smth1_Q15 = 0; - int variable_HP_smth2_Q15 = 0; - final SilkLPState sLP = new SilkLPState(); - final SilkVADState sVAD = new SilkVADState(); - final SilkNSQState sNSQ = new SilkNSQState(); - final short[] prev_NLSFq_Q15 = new short[16]; - int speech_activity_Q8 = 0; - int allow_bandwidth_switch = 0; - byte LBRRprevLastGainIndex = 0; - byte prevSignalType = 0; - int prevLag = 0; - int pitch_LPC_win_length = 0; - int max_pitch_lag = 0; - int API_fs_Hz = 0; - int prev_API_fs_Hz = 0; - int maxInternal_fs_Hz = 0; - int minInternal_fs_Hz = 0; - int desiredInternal_fs_Hz = 0; - int fs_kHz = 0; - int nb_subfr = 0; - int frame_length = 0; - int subfr_length = 0; - int ltp_mem_length = 0; - int la_pitch = 0; - int la_shape = 0; - int shapeWinLength = 0; - int TargetRate_bps = 0; - int PacketSize_ms = 0; - int PacketLoss_perc = 0; - int frameCounter = 0; - int Complexity = 0; - int nStatesDelayedDecision = 0; - int useInterpolatedNLSFs = 0; - int shapingLPCOrder = 0; - int predictLPCOrder = 0; - int pitchEstimationComplexity = 0; - int pitchEstimationLPCOrder = 0; - int pitchEstimationThreshold_Q16 = 0; - int LTPQuantLowComplexity = 0; - int mu_LTP_Q9 = 0; - int sum_log_gain_Q7 = 0; - int NLSF_MSVQ_Survivors = 0; - int first_frame_after_reset = 0; - int controlled_since_last_payload = 0; - int warping_Q16 = 0; - int useCBR = 0; - int prefillFlag = 0; - short[] pitch_lag_low_bits_iCDF = null; - short[] pitch_contour_iCDF = null; - NLSFCodebook psNLSF_CB = null; - final int[] input_quality_bands_Q15 = new int[4]; - int input_tilt_Q15 = 0; - int SNR_dB_Q7 = 0; - final byte[] VAD_flags = new byte[3]; - byte LBRR_flag = 0; - final int[] LBRR_flags = new int[3]; - final SideInfoIndices indices = new SideInfoIndices(); - final byte[] pulses = new byte[320]; - final short[] inputBuf = new short[322]; - int inputBufIx = 0; - int nFramesPerPacket = 0; - int nFramesEncoded = 0; - int nChannelsAPI = 0; - int nChannelsInternal = 0; - int channelNb = 0; - int frames_since_onset = 0; - int ec_prevSignalType = 0; - short ec_prevLagIndex = 0; - final SilkResamplerState resampler_state = new SilkResamplerState(); - int useDTX = 0; - int inDTX = 0; - int noSpeechCounter = 0; - int useInBandFEC = 0; - int LBRR_enabled = 0; - int LBRR_GainIncreases = 0; - final SideInfoIndices[] indices_LBRR = new SideInfoIndices[3]; - final byte[][] pulses_LBRR = Arrays.InitTwoDimensionalArrayByte(3, 320); - final SilkShapeState sShape = new SilkShapeState(); - final SilkPrefilterState sPrefilt = new SilkPrefilterState(); - final short[] x_buf = new short[720]; - int LTPCorr_Q15 = 0; - - SilkChannelEncoder() { - for (int c = 0; c < 3; ++c) { - this.indices_LBRR[c] = new SideInfoIndices(); - } - } - - void Reset() { - Arrays.MemSet(this.In_HP_State, 0, 2); - this.variable_HP_smth1_Q15 = 0; - this.variable_HP_smth2_Q15 = 0; - this.sLP.Reset(); - this.sVAD.Reset(); - this.sNSQ.Reset(); - Arrays.MemSet(this.prev_NLSFq_Q15, (short)0, 16); - this.speech_activity_Q8 = 0; - this.allow_bandwidth_switch = 0; - this.LBRRprevLastGainIndex = 0; - this.prevSignalType = 0; - this.prevLag = 0; - this.pitch_LPC_win_length = 0; - this.max_pitch_lag = 0; - this.API_fs_Hz = 0; - this.prev_API_fs_Hz = 0; - this.maxInternal_fs_Hz = 0; - this.minInternal_fs_Hz = 0; - this.desiredInternal_fs_Hz = 0; - this.fs_kHz = 0; - this.nb_subfr = 0; - this.frame_length = 0; - this.subfr_length = 0; - this.ltp_mem_length = 0; - this.la_pitch = 0; - this.la_shape = 0; - this.shapeWinLength = 0; - this.TargetRate_bps = 0; - this.PacketSize_ms = 0; - this.PacketLoss_perc = 0; - this.frameCounter = 0; - this.Complexity = 0; - this.nStatesDelayedDecision = 0; - this.useInterpolatedNLSFs = 0; - this.shapingLPCOrder = 0; - this.predictLPCOrder = 0; - this.pitchEstimationComplexity = 0; - this.pitchEstimationLPCOrder = 0; - this.pitchEstimationThreshold_Q16 = 0; - this.LTPQuantLowComplexity = 0; - this.mu_LTP_Q9 = 0; - this.sum_log_gain_Q7 = 0; - this.NLSF_MSVQ_Survivors = 0; - this.first_frame_after_reset = 0; - this.controlled_since_last_payload = 0; - this.warping_Q16 = 0; - this.useCBR = 0; - this.prefillFlag = 0; - this.pitch_lag_low_bits_iCDF = null; - this.pitch_contour_iCDF = null; - this.psNLSF_CB = null; - Arrays.MemSet(this.input_quality_bands_Q15, 0, 4); - this.input_tilt_Q15 = 0; - this.SNR_dB_Q7 = 0; - Arrays.MemSet(this.VAD_flags, (byte)0, 3); - this.LBRR_flag = 0; - Arrays.MemSet(this.LBRR_flags, 0, 3); - this.indices.Reset(); - Arrays.MemSet(this.pulses, (byte)0, 320); - Arrays.MemSet(this.inputBuf, (short)0, 322); - this.inputBufIx = 0; - this.nFramesPerPacket = 0; - this.nFramesEncoded = 0; - this.nChannelsAPI = 0; - this.nChannelsInternal = 0; - this.channelNb = 0; - this.frames_since_onset = 0; - this.ec_prevSignalType = 0; - this.ec_prevLagIndex = 0; - this.resampler_state.Reset(); - this.useDTX = 0; - this.inDTX = 0; - this.noSpeechCounter = 0; - this.useInBandFEC = 0; - this.LBRR_enabled = 0; - this.LBRR_GainIncreases = 0; - for (int c = 0; c < 3; ++c) { - this.indices_LBRR[c].Reset(); - Arrays.MemSet(this.pulses_LBRR[c], (byte)0, 320); - } - this.sShape.Reset(); - this.sPrefilt.Reset(); - Arrays.MemSet(this.x_buf, (short)0, 720); - this.LTPCorr_Q15 = 0; - } - - int silk_control_encoder(EncControlState encControl, int TargetRate_bps, int allow_bw_switch, int channelNb, int force_fs_kHz) { - int ret = SilkError.SILK_NO_ERROR; - this.useDTX = encControl.useDTX; - this.useCBR = encControl.useCBR; - this.API_fs_Hz = encControl.API_sampleRate; - this.maxInternal_fs_Hz = encControl.maxInternalSampleRate; - this.minInternal_fs_Hz = encControl.minInternalSampleRate; - this.desiredInternal_fs_Hz = encControl.desiredInternalSampleRate; - this.useInBandFEC = encControl.useInBandFEC; - this.nChannelsAPI = encControl.nChannelsAPI; - this.nChannelsInternal = encControl.nChannelsInternal; - this.allow_bandwidth_switch = allow_bw_switch; - this.channelNb = channelNb; - if (this.controlled_since_last_payload != 0 && this.prefillFlag == 0) { - if (this.API_fs_Hz != this.prev_API_fs_Hz && this.fs_kHz > 0) { - ret = this.silk_setup_resamplers(this.fs_kHz); - } - return ret; - } - int fs_kHz = this.silk_control_audio_bandwidth(encControl); - if (force_fs_kHz != 0) { - fs_kHz = force_fs_kHz; - } - ret = this.silk_setup_resamplers(fs_kHz); - ret = this.silk_setup_fs(fs_kHz, encControl.payloadSize_ms); - ret = this.silk_setup_complexity(encControl.complexity); - this.PacketLoss_perc = encControl.packetLossPercentage; - ret = this.silk_setup_LBRR(TargetRate_bps); - this.controlled_since_last_payload = 1; - return ret; - } - - private int silk_setup_resamplers(int fs_kHz) { - int ret = 0; - if (this.fs_kHz != fs_kHz || this.prev_API_fs_Hz != this.API_fs_Hz) { - if (this.fs_kHz == 0) { - ret += Resampler.silk_resampler_init(this.resampler_state, this.API_fs_Hz, fs_kHz * 1000, 1); - } else { - SilkResamplerState temp_resampler_state = null; - int buf_length_ms = Inlines.silk_LSHIFT(this.nb_subfr * 5, 1) + 5; - int old_buf_samples = buf_length_ms * this.fs_kHz; - temp_resampler_state = new SilkResamplerState(); - ret += Resampler.silk_resampler_init(temp_resampler_state, Inlines.silk_SMULBB(this.fs_kHz, 1000), this.API_fs_Hz, 0); - int api_buf_samples = buf_length_ms * Inlines.silk_DIV32_16(this.API_fs_Hz, 1000); - short[] x_buf_API_fs_Hz = new short[api_buf_samples]; - ret += Resampler.silk_resampler(temp_resampler_state, x_buf_API_fs_Hz, 0, this.x_buf, 0, old_buf_samples); - ret += Resampler.silk_resampler_init(this.resampler_state, this.API_fs_Hz, Inlines.silk_SMULBB(fs_kHz, 1000), 1); - ret += Resampler.silk_resampler(this.resampler_state, this.x_buf, 0, x_buf_API_fs_Hz, 0, api_buf_samples); - } - } - this.prev_API_fs_Hz = this.API_fs_Hz; - return ret; - } - - private int silk_setup_fs(int fs_kHz, int PacketSize_ms) { - int ret = SilkError.SILK_NO_ERROR; - if (PacketSize_ms != this.PacketSize_ms) { - if (PacketSize_ms != 10 && PacketSize_ms != 20 && PacketSize_ms != 40 && PacketSize_ms != 60) { - ret = SilkError.SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; - } - if (PacketSize_ms <= 10) { - this.nFramesPerPacket = 1; - this.nb_subfr = PacketSize_ms == 10 ? 2 : 1; - this.frame_length = Inlines.silk_SMULBB(PacketSize_ms, fs_kHz); - this.pitch_LPC_win_length = Inlines.silk_SMULBB(14, fs_kHz); - this.pitch_contour_iCDF = this.fs_kHz == 8 ? SilkTables.silk_pitch_contour_10_ms_NB_iCDF : SilkTables.silk_pitch_contour_10_ms_iCDF; - } else { - this.nFramesPerPacket = Inlines.silk_DIV32_16(PacketSize_ms, 20); - this.nb_subfr = 4; - this.frame_length = Inlines.silk_SMULBB(20, fs_kHz); - this.pitch_LPC_win_length = Inlines.silk_SMULBB(24, fs_kHz); - this.pitch_contour_iCDF = this.fs_kHz == 8 ? SilkTables.silk_pitch_contour_NB_iCDF : SilkTables.silk_pitch_contour_iCDF; - } - this.PacketSize_ms = PacketSize_ms; - this.TargetRate_bps = 0; - } - Inlines.OpusAssert(fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16); - Inlines.OpusAssert(this.nb_subfr == 2 || this.nb_subfr == 4); - if (this.fs_kHz != fs_kHz) { - this.sShape.Reset(); - this.sPrefilt.Reset(); - this.sNSQ.Reset(); - Arrays.MemSet(this.prev_NLSFq_Q15, (short)0, 16); - Arrays.MemSet(this.sLP.In_LP_State, 0, 2); - this.inputBufIx = 0; - this.nFramesEncoded = 0; - this.TargetRate_bps = 0; - this.prevLag = 100; - this.first_frame_after_reset = 1; - this.sPrefilt.lagPrev = 100; - this.sShape.LastGainIndex = (byte)10; - this.sNSQ.lagPrev = 100; - this.sNSQ.prev_gain_Q16 = 65536; - this.prevSignalType = 0; - this.fs_kHz = fs_kHz; - this.pitch_contour_iCDF = this.fs_kHz == 8 ? (this.nb_subfr == 4 ? SilkTables.silk_pitch_contour_NB_iCDF : SilkTables.silk_pitch_contour_10_ms_NB_iCDF) : (this.nb_subfr == 4 ? SilkTables.silk_pitch_contour_iCDF : SilkTables.silk_pitch_contour_10_ms_iCDF); - if (this.fs_kHz == 8 || this.fs_kHz == 12) { - this.predictLPCOrder = 10; - this.psNLSF_CB = SilkTables.silk_NLSF_CB_NB_MB; - } else { - this.predictLPCOrder = 16; - this.psNLSF_CB = SilkTables.silk_NLSF_CB_WB; - } - this.subfr_length = 5 * fs_kHz; - this.frame_length = Inlines.silk_SMULBB(this.subfr_length, this.nb_subfr); - this.ltp_mem_length = Inlines.silk_SMULBB(20, fs_kHz); - this.la_pitch = Inlines.silk_SMULBB(2, fs_kHz); - this.max_pitch_lag = Inlines.silk_SMULBB(18, fs_kHz); - this.pitch_LPC_win_length = this.nb_subfr == 4 ? Inlines.silk_SMULBB(24, fs_kHz) : Inlines.silk_SMULBB(14, fs_kHz); - if (this.fs_kHz == 16) { - this.mu_LTP_Q9 = 10; - this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform8_iCDF; - } else if (this.fs_kHz == 12) { - this.mu_LTP_Q9 = 13; - this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform6_iCDF; - } else { - this.mu_LTP_Q9 = 15; - this.pitch_lag_low_bits_iCDF = SilkTables.silk_uniform4_iCDF; - } - } - Inlines.OpusAssert(this.subfr_length * this.nb_subfr == this.frame_length); - return ret; - } - - private int silk_setup_complexity(int Complexity) { - int ret = 0; - Inlines.OpusAssert(Complexity >= 0 && Complexity <= 10); - if (Complexity < 2) { - this.pitchEstimationComplexity = 0; - this.pitchEstimationThreshold_Q16 = 52429; - this.pitchEstimationLPCOrder = 6; - this.shapingLPCOrder = 8; - this.la_shape = 3 * this.fs_kHz; - this.nStatesDelayedDecision = 1; - this.useInterpolatedNLSFs = 0; - this.LTPQuantLowComplexity = 1; - this.NLSF_MSVQ_Survivors = 2; - this.warping_Q16 = 0; - } else if (Complexity < 4) { - this.pitchEstimationComplexity = 1; - this.pitchEstimationThreshold_Q16 = 49807; - this.pitchEstimationLPCOrder = 8; - this.shapingLPCOrder = 10; - this.la_shape = 5 * this.fs_kHz; - this.nStatesDelayedDecision = 1; - this.useInterpolatedNLSFs = 0; - this.LTPQuantLowComplexity = 0; - this.NLSF_MSVQ_Survivors = 4; - this.warping_Q16 = 0; - } else if (Complexity < 6) { - this.pitchEstimationComplexity = 1; - this.pitchEstimationThreshold_Q16 = 48497; - this.pitchEstimationLPCOrder = 10; - this.shapingLPCOrder = 12; - this.la_shape = 5 * this.fs_kHz; - this.nStatesDelayedDecision = 2; - this.useInterpolatedNLSFs = 1; - this.LTPQuantLowComplexity = 0; - this.NLSF_MSVQ_Survivors = 8; - this.warping_Q16 = this.fs_kHz * 983; - } else if (Complexity < 8) { - this.pitchEstimationComplexity = 1; - this.pitchEstimationThreshold_Q16 = 47186; - this.pitchEstimationLPCOrder = 12; - this.shapingLPCOrder = 14; - this.la_shape = 5 * this.fs_kHz; - this.nStatesDelayedDecision = 3; - this.useInterpolatedNLSFs = 1; - this.LTPQuantLowComplexity = 0; - this.NLSF_MSVQ_Survivors = 16; - this.warping_Q16 = this.fs_kHz * 983; - } else { - this.pitchEstimationComplexity = 2; - this.pitchEstimationThreshold_Q16 = 45875; - this.pitchEstimationLPCOrder = 16; - this.shapingLPCOrder = 16; - this.la_shape = 5 * this.fs_kHz; - this.nStatesDelayedDecision = 4; - this.useInterpolatedNLSFs = 1; - this.LTPQuantLowComplexity = 0; - this.NLSF_MSVQ_Survivors = 32; - this.warping_Q16 = this.fs_kHz * 983; - } - this.pitchEstimationLPCOrder = Inlines.silk_min_int(this.pitchEstimationLPCOrder, this.predictLPCOrder); - this.shapeWinLength = 5 * this.fs_kHz + 2 * this.la_shape; - this.Complexity = Complexity; - Inlines.OpusAssert(this.pitchEstimationLPCOrder <= 16); - Inlines.OpusAssert(this.shapingLPCOrder <= 16); - Inlines.OpusAssert(this.nStatesDelayedDecision <= 4); - Inlines.OpusAssert(this.warping_Q16 <= Short.MAX_VALUE); - Inlines.OpusAssert(this.la_shape <= 80); - Inlines.OpusAssert(this.shapeWinLength <= 240); - Inlines.OpusAssert(this.NLSF_MSVQ_Survivors <= 32); - return ret; - } - - private int silk_setup_LBRR(int TargetRate_bps) { - int ret = SilkError.SILK_NO_ERROR; - int LBRR_in_previous_packet = this.LBRR_enabled; - this.LBRR_enabled = 0; - if (this.useInBandFEC != 0 && this.PacketLoss_perc > 0) { - int LBRR_rate_thres_bps = this.fs_kHz == 8 ? 12000 : (this.fs_kHz == 12 ? 14000 : 16000); - if (TargetRate_bps > (LBRR_rate_thres_bps = Inlines.silk_SMULWB(Inlines.silk_MUL(LBRR_rate_thres_bps, 125 - Inlines.silk_min(this.PacketLoss_perc, 25)), 655))) { - this.LBRR_GainIncreases = LBRR_in_previous_packet == 0 ? 7 : Inlines.silk_max_int(7 - Inlines.silk_SMULWB(this.PacketLoss_perc, 26214), 2); - this.LBRR_enabled = 1; - } - } - return ret; - } - - int silk_control_audio_bandwidth(EncControlState encControl) { - int fs_kHz = this.fs_kHz; - int fs_Hz = Inlines.silk_SMULBB(fs_kHz, 1000); - if (fs_Hz == 0) { - fs_Hz = Inlines.silk_min(this.desiredInternal_fs_Hz, this.API_fs_Hz); - fs_kHz = Inlines.silk_DIV32_16(fs_Hz, 1000); - } else if (fs_Hz > this.API_fs_Hz || fs_Hz > this.maxInternal_fs_Hz || fs_Hz < this.minInternal_fs_Hz) { - fs_Hz = this.API_fs_Hz; - fs_Hz = Inlines.silk_min(fs_Hz, this.maxInternal_fs_Hz); - fs_Hz = Inlines.silk_max(fs_Hz, this.minInternal_fs_Hz); - fs_kHz = Inlines.silk_DIV32_16(fs_Hz, 1000); - } else { - if (this.sLP.transition_frame_no >= 256) { - this.sLP.mode = 0; - } - if (this.allow_bandwidth_switch != 0 || encControl.opusCanSwitch != 0) { - if (Inlines.silk_SMULBB(this.fs_kHz, 1000) > this.desiredInternal_fs_Hz) { - if (this.sLP.mode == 0) { - this.sLP.transition_frame_no = 256; - Arrays.MemSet(this.sLP.In_LP_State, 0, 2); - } - if (encControl.opusCanSwitch != 0) { - this.sLP.mode = 0; - fs_kHz = this.fs_kHz == 16 ? 12 : 8; - } else if (this.sLP.transition_frame_no <= 0) { - encControl.switchReady = 1; - encControl.maxBits -= encControl.maxBits * 5 / (encControl.payloadSize_ms + 5); - } else { - this.sLP.mode = -2; - } - } else if (Inlines.silk_SMULBB(this.fs_kHz, 1000) < this.desiredInternal_fs_Hz) { - if (encControl.opusCanSwitch != 0) { - fs_kHz = this.fs_kHz == 8 ? 12 : 16; - this.sLP.transition_frame_no = 0; - Arrays.MemSet(this.sLP.In_LP_State, 0, 2); - this.sLP.mode = 1; - } else if (this.sLP.mode == 0) { - encControl.switchReady = 1; - encControl.maxBits -= encControl.maxBits * 5 / (encControl.payloadSize_ms + 5); - } else { - this.sLP.mode = 1; - } - } else if (this.sLP.mode < 0) { - this.sLP.mode = 1; - } - } - } - return fs_kHz; - } - - int silk_control_SNR(int TargetRate_bps) { - int ret = SilkError.SILK_NO_ERROR; - if ((TargetRate_bps = Inlines.silk_LIMIT(TargetRate_bps, 5000, 80000)) != this.TargetRate_bps) { - this.TargetRate_bps = TargetRate_bps; - int[] rateTable = this.fs_kHz == 8 ? SilkTables.silk_TargetRate_table_NB : (this.fs_kHz == 12 ? SilkTables.silk_TargetRate_table_MB : SilkTables.silk_TargetRate_table_WB); - if (this.nb_subfr == 2) { - TargetRate_bps -= 2200; - } - for (int k = 1; k < 8; ++k) { - if (TargetRate_bps > rateTable[k]) continue; - int frac_Q6 = Inlines.silk_DIV32(Inlines.silk_LSHIFT(TargetRate_bps - rateTable[k - 1], 6), rateTable[k] - rateTable[k - 1]); - this.SNR_dB_Q7 = Inlines.silk_LSHIFT(SilkTables.silk_SNR_table_Q1[k - 1], 6) + Inlines.silk_MUL(frac_Q6, SilkTables.silk_SNR_table_Q1[k] - SilkTables.silk_SNR_table_Q1[k - 1]); - break; - } - } - return ret; - } - - void silk_encode_do_VAD() { - VoiceActivityDetection.silk_VAD_GetSA_Q8(this, this.inputBuf, 1); - if (this.speech_activity_Q8 < 13) { - this.indices.signalType = 0; - ++this.noSpeechCounter; - if (this.noSpeechCounter < 10) { - this.inDTX = 0; - } else if (this.noSpeechCounter > 30) { - this.noSpeechCounter = 10; - this.inDTX = 0; - } - this.VAD_flags[this.nFramesEncoded] = 0; - } else { - this.noSpeechCounter = 0; - this.inDTX = 0; - this.indices.signalType = 1; - this.VAD_flags[this.nFramesEncoded] = 1; - } - } - - int silk_encode_frame(BoxedValueInt pnBytesOut, EntropyCoder psRangeEnc, int condCoding, int maxBits, int useCBR) { - SilkEncoderControl sEncCtrl = new SilkEncoderControl(); - int ret = 0; - EntropyCoder sRangeEnc_copy = new EntropyCoder(); - EntropyCoder sRangeEnc_copy2 = new EntropyCoder(); - SilkNSQState sNSQ_copy = new SilkNSQState(); - SilkNSQState sNSQ_copy2 = new SilkNSQState(); - byte LastGainIndex_copy2 = 0; - int gainMult_upper = 0; - int gainMult_lower = 0; - int nBits_upper = 0; - int nBits_lower = 0; - this.indices.Seed = (byte)(this.frameCounter++ & 3); - int x_frame = this.ltp_mem_length; - this.sLP.silk_LP_variable_cutoff(this.inputBuf, 1, this.frame_length); - System.arraycopy(this.inputBuf, 1, this.x_buf, x_frame + 5 * this.fs_kHz, this.frame_length); - if (this.prefillFlag == 0) { - short[] res_pitch = new short[this.la_pitch + this.frame_length + this.ltp_mem_length]; - int res_pitch_frame = this.ltp_mem_length; - FindPitchLags.silk_find_pitch_lags(this, sEncCtrl, res_pitch, this.x_buf, x_frame); - NoiseShapeAnalysis.silk_noise_shape_analysis(this, sEncCtrl, res_pitch, res_pitch_frame, this.x_buf, x_frame); - FindPredCoefs.silk_find_pred_coefs(this, sEncCtrl, res_pitch, this.x_buf, x_frame, condCoding); - ProcessGains.silk_process_gains(this, sEncCtrl, condCoding); - int[] xfw_Q3 = new int[this.frame_length]; - Filters.silk_prefilter(this, sEncCtrl, xfw_Q3, this.x_buf, x_frame); - this.silk_LBRR_encode(sEncCtrl, xfw_Q3, condCoding); - int maxIter = 6; - int gainMult_Q8 = 256; - boolean found_lower = false; - boolean found_upper = false; - int gainsID = GainQuantization.silk_gains_ID(this.indices.GainsIndices, this.nb_subfr); - int gainsID_lower = -1; - int gainsID_upper = -1; - sRangeEnc_copy.Assign(psRangeEnc); - sNSQ_copy.Assign(this.sNSQ); - byte seed_copy = this.indices.Seed; - short ec_prevLagIndex_copy = this.ec_prevLagIndex; - int ec_prevSignalType_copy = this.ec_prevSignalType; - byte[] ec_buf_copy = new byte[1275]; - int iter = 0; - while (true) { - int nBits; - if (gainsID == gainsID_lower) { - nBits = nBits_lower; - } else if (gainsID == gainsID_upper) { - nBits = nBits_upper; - } else { - if (iter > 0) { - psRangeEnc.Assign(sRangeEnc_copy); - this.sNSQ.Assign(sNSQ_copy); - this.indices.Seed = seed_copy; - this.ec_prevLagIndex = ec_prevLagIndex_copy; - this.ec_prevSignalType = ec_prevSignalType_copy; - } - if (this.nStatesDelayedDecision > 1 || this.warping_Q16 > 0) { - this.sNSQ.silk_NSQ_del_dec(this, this.indices, xfw_Q3, this.pulses, sEncCtrl.PredCoef_Q12, sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14); - } else { - this.sNSQ.silk_NSQ(this, this.indices, xfw_Q3, this.pulses, sEncCtrl.PredCoef_Q12, sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14); - } - EncodeIndices.silk_encode_indices(this, psRangeEnc, this.nFramesEncoded, 0, condCoding); - EncodePulses.silk_encode_pulses(psRangeEnc, this.indices.signalType, this.indices.quantOffsetType, this.pulses, this.frame_length); - nBits = psRangeEnc.tell(); - if (useCBR == 0 && iter == 0 && nBits <= maxBits) break; - } - if (iter == maxIter) { - if (!found_lower || gainsID != gainsID_lower && nBits <= maxBits) break; - psRangeEnc.Assign(sRangeEnc_copy2); - Inlines.OpusAssert(sRangeEnc_copy2.offs <= 1275); - psRangeEnc.write_buffer(ec_buf_copy, 0, 0, sRangeEnc_copy2.offs); - this.sNSQ.Assign(sNSQ_copy2); - this.sShape.LastGainIndex = LastGainIndex_copy2; - break; - } - if (nBits > maxBits) { - if (!found_lower && iter >= 2) { - sEncCtrl.Lambda_Q10 = Inlines.silk_ADD_RSHIFT32(sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1); - found_upper = false; - gainsID_upper = -1; - } else { - found_upper = true; - nBits_upper = nBits; - gainMult_upper = gainMult_Q8; - gainsID_upper = gainsID; - } - } else { - if (nBits >= maxBits - 5) break; - found_lower = true; - nBits_lower = nBits; - gainMult_lower = gainMult_Q8; - if (gainsID != gainsID_lower) { - gainsID_lower = gainsID; - sRangeEnc_copy2.Assign(psRangeEnc); - Inlines.OpusAssert(psRangeEnc.offs <= 1275); - System.arraycopy(psRangeEnc.get_buffer(), 0, ec_buf_copy, 0, psRangeEnc.offs); - sNSQ_copy2.Assign(this.sNSQ); - LastGainIndex_copy2 = this.sShape.LastGainIndex; - } - } - if (!(found_lower & found_upper)) { - int gain_factor_Q16 = Inlines.silk_log2lin(Inlines.silk_LSHIFT(nBits - maxBits, 7) / this.frame_length + 2048); - gain_factor_Q16 = Inlines.silk_min_32(gain_factor_Q16, 131072); - if (nBits > maxBits) { - gain_factor_Q16 = Inlines.silk_max_32(gain_factor_Q16, 85197); - } - gainMult_Q8 = (short)Inlines.silk_SMULWB(gain_factor_Q16, gainMult_Q8); - } else { - gainMult_Q8 = (short)(gainMult_lower + Inlines.silk_DIV32_16(Inlines.silk_MUL(gainMult_upper - gainMult_lower, maxBits - nBits_lower), nBits_upper - nBits_lower)); - if (gainMult_Q8 > Inlines.silk_ADD_RSHIFT32(gainMult_lower, gainMult_upper - gainMult_lower, 2)) { - gainMult_Q8 = (short)Inlines.silk_ADD_RSHIFT32(gainMult_lower, gainMult_upper - gainMult_lower, 2); - } else if (gainMult_Q8 < Inlines.silk_SUB_RSHIFT32(gainMult_upper, gainMult_upper - gainMult_lower, 2)) { - gainMult_Q8 = (short)Inlines.silk_SUB_RSHIFT32(gainMult_upper, gainMult_upper - gainMult_lower, 2); - } - } - for (int i = 0; i < this.nb_subfr; ++i) { - sEncCtrl.Gains_Q16[i] = Inlines.silk_LSHIFT_SAT32(Inlines.silk_SMULWB(sEncCtrl.GainsUnq_Q16[i], gainMult_Q8), 8); - } - this.sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; - BoxedValueByte boxed_gainIndex = new BoxedValueByte(this.sShape.LastGainIndex); - GainQuantization.silk_gains_quant(this.indices.GainsIndices, sEncCtrl.Gains_Q16, boxed_gainIndex, condCoding == 2 ? 1 : 0, this.nb_subfr); - this.sShape.LastGainIndex = boxed_gainIndex.Val; - gainsID = GainQuantization.silk_gains_ID(this.indices.GainsIndices, this.nb_subfr); - ++iter; - } - } - Arrays.MemMove(this.x_buf, this.frame_length, 0, this.ltp_mem_length + 5 * this.fs_kHz); - if (this.prefillFlag != 0) { - pnBytesOut.Val = 0; - return ret; - } - this.prevLag = sEncCtrl.pitchL[this.nb_subfr - 1]; - this.prevSignalType = this.indices.signalType; - this.first_frame_after_reset = 0; - pnBytesOut.Val = Inlines.silk_RSHIFT(psRangeEnc.tell() + 7, 3); - return ret; - } - - void silk_LBRR_encode(SilkEncoderControl thisCtrl, int[] xfw_Q3, int condCoding) { - int[] TempGains_Q16 = new int[this.nb_subfr]; - SideInfoIndices psIndices_LBRR = this.indices_LBRR[this.nFramesEncoded]; - SilkNSQState sNSQ_LBRR = new SilkNSQState(); - if (this.LBRR_enabled != 0 && this.speech_activity_Q8 > 77) { - this.LBRR_flags[this.nFramesEncoded] = 1; - sNSQ_LBRR.Assign(this.sNSQ); - psIndices_LBRR.Assign(this.indices); - System.arraycopy(thisCtrl.Gains_Q16, 0, TempGains_Q16, 0, this.nb_subfr); - if (this.nFramesEncoded == 0 || this.LBRR_flags[this.nFramesEncoded - 1] == 0) { - this.LBRRprevLastGainIndex = this.sShape.LastGainIndex; - psIndices_LBRR.GainsIndices[0] = (byte)(psIndices_LBRR.GainsIndices[0] + this.LBRR_GainIncreases); - psIndices_LBRR.GainsIndices[0] = (byte)Inlines.silk_min_int(psIndices_LBRR.GainsIndices[0], 63); - } - BoxedValueByte boxed_gainIndex = new BoxedValueByte(this.LBRRprevLastGainIndex); - GainQuantization.silk_gains_dequant(thisCtrl.Gains_Q16, psIndices_LBRR.GainsIndices, boxed_gainIndex, condCoding == 2 ? 1 : 0, this.nb_subfr); - this.LBRRprevLastGainIndex = boxed_gainIndex.Val; - if (this.nStatesDelayedDecision > 1 || this.warping_Q16 > 0) { - sNSQ_LBRR.silk_NSQ_del_dec(this, psIndices_LBRR, xfw_Q3, this.pulses_LBRR[this.nFramesEncoded], thisCtrl.PredCoef_Q12, thisCtrl.LTPCoef_Q14, thisCtrl.AR2_Q13, thisCtrl.HarmShapeGain_Q14, thisCtrl.Tilt_Q14, thisCtrl.LF_shp_Q14, thisCtrl.Gains_Q16, thisCtrl.pitchL, thisCtrl.Lambda_Q10, thisCtrl.LTP_scale_Q14); - } else { - sNSQ_LBRR.silk_NSQ(this, psIndices_LBRR, xfw_Q3, this.pulses_LBRR[this.nFramesEncoded], thisCtrl.PredCoef_Q12, thisCtrl.LTPCoef_Q14, thisCtrl.AR2_Q13, thisCtrl.HarmShapeGain_Q14, thisCtrl.Tilt_Q14, thisCtrl.LF_shp_Q14, thisCtrl.Gains_Q16, thisCtrl.pitchL, thisCtrl.Lambda_Q10, thisCtrl.LTP_scale_Q14); - } - System.arraycopy(TempGains_Q16, 0, thisCtrl.Gains_Q16, 0, this.nb_subfr); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkConstants.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkConstants.java deleted file mode 100644 index 0d28397..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkConstants.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class SilkConstants { - public static final int ENCODER_NUM_CHANNELS = 2; - public static final int DECODER_NUM_CHANNELS = 2; - public static final int MAX_FRAMES_PER_PACKET = 3; - public static final int MIN_TARGET_RATE_BPS = 5000; - public static final int MAX_TARGET_RATE_BPS = 80000; - public static final int TARGET_RATE_TAB_SZ = 8; - public static final int LBRR_NB_MIN_RATE_BPS = 12000; - public static final int LBRR_MB_MIN_RATE_BPS = 14000; - public static final int LBRR_WB_MIN_RATE_BPS = 16000; - public static final int NB_SPEECH_FRAMES_BEFORE_DTX = 10; - public static final int MAX_CONSECUTIVE_DTX = 20; - public static final int MAX_FS_KHZ = 16; - public static final int MAX_API_FS_KHZ = 48; - public static final int TYPE_NO_VOICE_ACTIVITY = 0; - public static final int TYPE_UNVOICED = 1; - public static final int TYPE_VOICED = 2; - public static final int CODE_INDEPENDENTLY = 0; - public static final int CODE_INDEPENDENTLY_NO_LTP_SCALING = 1; - public static final int CODE_CONDITIONALLY = 2; - public static final int STEREO_QUANT_TAB_SIZE = 16; - public static final int STEREO_QUANT_SUB_STEPS = 5; - public static final int STEREO_INTERP_LEN_MS = 8; - public static final float STEREO_RATIO_SMOOTH_COEF = 0.01f; - public static final int PITCH_EST_MIN_LAG_MS = 2; - public static final int PITCH_EST_MAX_LAG_MS = 18; - public static final int MAX_NB_SUBFR = 4; - public static final int LTP_MEM_LENGTH_MS = 20; - public static final int SUB_FRAME_LENGTH_MS = 5; - public static final int MAX_SUB_FRAME_LENGTH = 80; - public static final int MAX_FRAME_LENGTH_MS = 20; - public static final int MAX_FRAME_LENGTH = 320; - public static final int LA_PITCH_MS = 2; - public static final int LA_PITCH_MAX = 32; - public static final int MAX_FIND_PITCH_LPC_ORDER = 16; - public static final int FIND_PITCH_LPC_WIN_MS = 24; - public static final int FIND_PITCH_LPC_WIN_MS_2_SF = 14; - public static final int FIND_PITCH_LPC_WIN_MAX = 384; - public static final int LA_SHAPE_MS = 5; - public static final int LA_SHAPE_MAX = 80; - public static final int SHAPE_LPC_WIN_MAX = 240; - public static final int MIN_QGAIN_DB = 2; - public static final int MAX_QGAIN_DB = 88; - public static final int N_LEVELS_QGAIN = 64; - public static final int MAX_DELTA_GAIN_QUANT = 36; - public static final int MIN_DELTA_GAIN_QUANT = -4; - public static final short OFFSET_VL_Q10 = 32; - public static final short OFFSET_VH_Q10 = 100; - public static final short OFFSET_UVL_Q10 = 100; - public static final short OFFSET_UVH_Q10 = 240; - public static final int QUANT_LEVEL_ADJUST_Q10 = 80; - public static final int MAX_LPC_STABILIZE_ITERATIONS = 16; - public static final float MAX_PREDICTION_POWER_GAIN = 10000.0f; - public static final float MAX_PREDICTION_POWER_GAIN_AFTER_RESET = 100.0f; - public static final int SILK_MAX_ORDER_LPC = 16; - public static final int MAX_LPC_ORDER = 16; - public static final int MIN_LPC_ORDER = 10; - public static final int LTP_ORDER = 5; - public static final int NB_LTP_CBKS = 3; - public static final int USE_HARM_SHAPING = 1; - public static final int MAX_SHAPE_LPC_ORDER = 16; - public static final int HARM_SHAPE_FIR_TAPS = 3; - public static final int MAX_DEL_DEC_STATES = 4; - public static final int LTP_BUF_LENGTH = 512; - public static final int LTP_MASK = 511; - public static final int DECISION_DELAY = 32; - public static final int DECISION_DELAY_MASK = 31; - public static final int SHELL_CODEC_FRAME_LENGTH = 16; - public static final int LOG2_SHELL_CODEC_FRAME_LENGTH = 4; - public static final int MAX_NB_SHELL_BLOCKS = 20; - public static final int N_RATE_LEVELS = 10; - public static final int SILK_MAX_PULSES = 16; - public static final int MAX_MATRIX_SIZE = 16; - static final int NSQ_LPC_BUF_LENGTH = Math.max(16, 32); - public static final int VAD_N_BANDS = 4; - public static final int VAD_INTERNAL_SUBFRAMES_LOG2 = 2; - public static final int VAD_INTERNAL_SUBFRAMES = 4; - public static final int VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 = 1024; - public static final int VAD_NOISE_LEVELS_BIAS = 50; - public static final int VAD_NEGATIVE_OFFSET_Q5 = 128; - public static final int VAD_SNR_FACTOR_Q16 = 45000; - public static final int VAD_SNR_SMOOTH_COEF_Q18 = 4096; - public static final int LSF_COS_TAB_SZ = 128; - public static final int NLSF_W_Q = 2; - public static final int NLSF_VQ_MAX_VECTORS = 32; - public static final int NLSF_VQ_MAX_SURVIVORS = 32; - public static final int NLSF_QUANT_MAX_AMPLITUDE = 4; - public static final int NLSF_QUANT_MAX_AMPLITUDE_EXT = 10; - public static final float NLSF_QUANT_LEVEL_ADJ = 0.1f; - public static final int NLSF_QUANT_DEL_DEC_STATES_LOG2 = 2; - public static final int NLSF_QUANT_DEL_DEC_STATES = 4; - public static final int TRANSITION_TIME_MS = 5120; - public static final int TRANSITION_NB = 3; - public static final int TRANSITION_NA = 2; - public static final int TRANSITION_INT_NUM = 5; - public static final int TRANSITION_FRAMES = 256; - public static final int TRANSITION_INT_STEPS = 64; - public static final int BWE_AFTER_LOSS_Q16 = 63570; - public static final int CNG_BUF_MASK_MAX = 255; - public static final int CNG_GAIN_SMTH_Q16 = 4634; - public static final int CNG_NLSF_SMTH_Q16 = 16348; - public static final int PE_MAX_FS_KHZ = 16; - public static final int PE_MAX_NB_SUBFR = 4; - public static final int PE_SUBFR_LENGTH_MS = 5; - public static final int PE_LTP_MEM_LENGTH_MS = 20; - public static final int PE_MAX_FRAME_LENGTH_MS = 40; - public static final int PE_MAX_FRAME_LENGTH = 640; - public static final int PE_MAX_FRAME_LENGTH_ST_1 = 160; - public static final int PE_MAX_FRAME_LENGTH_ST_2 = 320; - public static final int PE_MAX_LAG_MS = 18; - public static final int PE_MIN_LAG_MS = 2; - public static final int PE_MAX_LAG = 288; - public static final int PE_MIN_LAG = 32; - public static final int PE_D_SRCH_LENGTH = 24; - public static final int PE_NB_STAGE3_LAGS = 5; - public static final int PE_NB_CBKS_STAGE2 = 3; - public static final int PE_NB_CBKS_STAGE2_EXT = 11; - public static final int PE_NB_CBKS_STAGE3_MAX = 34; - public static final int PE_NB_CBKS_STAGE3_MID = 24; - public static final int PE_NB_CBKS_STAGE3_MIN = 16; - public static final int PE_NB_CBKS_STAGE3_10MS = 12; - public static final int PE_NB_CBKS_STAGE2_10MS = 3; - public static final float PE_SHORTLAG_BIAS = 0.2f; - public static final float PE_PREVLAG_BIAS = 0.2f; - public static final float PE_FLATCONTOUR_BIAS = 0.05f; - public static final int SILK_PE_MIN_COMPLEX = 0; - public static final int SILK_PE_MID_COMPLEX = 1; - public static final int SILK_PE_MAX_COMPLEX = 2; - public static final float BWE_COEF = 0.99f; - public static final int V_PITCH_GAIN_START_MIN_Q14 = 11469; - public static final int V_PITCH_GAIN_START_MAX_Q14 = 15565; - public static final int MAX_PITCH_LAG_MS = 18; - public static final int RAND_BUF_SIZE = 128; - public static final int RAND_BUF_MASK = 127; - public static final int LOG2_INV_LPC_GAIN_HIGH_THRES = 3; - public static final int LOG2_INV_LPC_GAIN_LOW_THRES = 8; - public static final int PITCH_DRIFT_FAC_Q16 = 655; - public static final int SILK_RESAMPLER_MAX_FIR_ORDER = 36; - public static final int SILK_RESAMPLER_MAX_IIR_ORDER = 6; - public static final int RESAMPLER_DOWN_ORDER_FIR0 = 18; - public static final int RESAMPLER_DOWN_ORDER_FIR1 = 24; - public static final int RESAMPLER_DOWN_ORDER_FIR2 = 36; - public static final int RESAMPLER_ORDER_FIR_12 = 8; - public static final int RESAMPLER_MAX_BATCH_SIZE_MS = 10; - public static final int RESAMPLER_MAX_FS_KHZ = 48; - public static final int RESAMPLER_MAX_BATCH_SIZE_IN = 480; - public static final int SILK_MAX_FRAMES_PER_PACKET = 3; - - SilkConstants() { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkDecoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkDecoder.java deleted file mode 100644 index af6bbc4..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkDecoder.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.SilkChannelDecoder; -import de.maxhenkel.voicechat.concentus.StereoDecodeState; - -class SilkDecoder { - final SilkChannelDecoder[] channel_state = new SilkChannelDecoder[2]; - final StereoDecodeState sStereo = new StereoDecodeState(); - int nChannelsAPI = 0; - int nChannelsInternal = 0; - int prev_decode_only_middle = 0; - - SilkDecoder() { - for (int c = 0; c < 2; ++c) { - this.channel_state[c] = new SilkChannelDecoder(); - } - } - - void Reset() { - for (int c = 0; c < 2; ++c) { - this.channel_state[c].Reset(); - } - this.sStereo.Reset(); - this.nChannelsAPI = 0; - this.nChannelsInternal = 0; - this.prev_decode_only_middle = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkDecoderControl.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkDecoderControl.java deleted file mode 100644 index 1f0f1ff..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkDecoderControl.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class SilkDecoderControl { - final int[] pitchL = new int[4]; - final int[] Gains_Q16 = new int[4]; - final short[][] PredCoef_Q12 = Arrays.InitTwoDimensionalArrayShort(2, 16); - final short[] LTPCoef_Q14 = new short[20]; - int LTP_scale_Q14 = 0; - - SilkDecoderControl() { - } - - void Reset() { - Arrays.MemSet(this.pitchL, 0, 4); - Arrays.MemSet(this.Gains_Q16, 0, 4); - Arrays.MemSet(this.PredCoef_Q12[0], (short)0, 16); - Arrays.MemSet(this.PredCoef_Q12[1], (short)0, 16); - Arrays.MemSet(this.LTPCoef_Q14, (short)0, 20); - this.LTP_scale_Q14 = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkEncoder.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkEncoder.java deleted file mode 100644 index 831490b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkEncoder.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.StereoEncodeState; -import de.maxhenkel.voicechat.concentus.VoiceActivityDetection; - -class SilkEncoder { - final SilkChannelEncoder[] state_Fxx = new SilkChannelEncoder[2]; - final StereoEncodeState sStereo = new StereoEncodeState(); - int nBitsUsedLBRR = 0; - int nBitsExceeded = 0; - int nChannelsAPI = 0; - int nChannelsInternal = 0; - int nPrevChannelsInternal = 0; - int timeSinceSwitchAllowed_ms = 0; - int allowBandwidthSwitch = 0; - int prev_decode_only_middle = 0; - - SilkEncoder() { - for (int c = 0; c < 2; ++c) { - this.state_Fxx[c] = new SilkChannelEncoder(); - } - } - - void Reset() { - for (int c = 0; c < 2; ++c) { - this.state_Fxx[c].Reset(); - } - this.sStereo.Reset(); - this.nBitsUsedLBRR = 0; - this.nBitsExceeded = 0; - this.nChannelsAPI = 0; - this.nChannelsInternal = 0; - this.nPrevChannelsInternal = 0; - this.timeSinceSwitchAllowed_ms = 0; - this.allowBandwidthSwitch = 0; - this.prev_decode_only_middle = 0; - } - - static int silk_init_encoder(SilkChannelEncoder psEnc) { - int ret = 0; - psEnc.Reset(); - psEnc.variable_HP_smth2_Q15 = psEnc.variable_HP_smth1_Q15 = Inlines.silk_LSHIFT(Inlines.silk_lin2log(0x3C0000) - 2048, 8); - psEnc.first_frame_after_reset = 1; - return ret += VoiceActivityDetection.silk_VAD_Init(psEnc.sVAD); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkEncoderControl.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkEncoderControl.java deleted file mode 100644 index 8a61578..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkEncoderControl.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class SilkEncoderControl { - final int[] Gains_Q16 = new int[4]; - final short[][] PredCoef_Q12 = Arrays.InitTwoDimensionalArrayShort(2, 16); - final short[] LTPCoef_Q14 = new short[20]; - int LTP_scale_Q14 = 0; - final int[] pitchL = new int[4]; - final short[] AR1_Q13 = new short[64]; - final short[] AR2_Q13 = new short[64]; - final int[] LF_shp_Q14 = new int[4]; - final int[] GainsPre_Q14 = new int[4]; - final int[] HarmBoost_Q14 = new int[4]; - final int[] Tilt_Q14 = new int[4]; - final int[] HarmShapeGain_Q14 = new int[4]; - int Lambda_Q10 = 0; - int input_quality_Q14 = 0; - int coding_quality_Q14 = 0; - int sparseness_Q8 = 0; - int predGain_Q16 = 0; - int LTPredCodGain_Q7 = 0; - final int[] ResNrg = new int[4]; - final int[] ResNrgQ = new int[4]; - final int[] GainsUnq_Q16 = new int[4]; - byte lastGainIndexPrev = 0; - - SilkEncoderControl() { - } - - void Reset() { - Arrays.MemSet(this.Gains_Q16, 0, 4); - Arrays.MemSet(this.PredCoef_Q12[0], (short)0, 16); - Arrays.MemSet(this.PredCoef_Q12[1], (short)0, 16); - Arrays.MemSet(this.LTPCoef_Q14, (short)0, 20); - this.LTP_scale_Q14 = 0; - Arrays.MemSet(this.pitchL, 0, 4); - Arrays.MemSet(this.AR1_Q13, (short)0, 64); - Arrays.MemSet(this.AR2_Q13, (short)0, 64); - Arrays.MemSet(this.LF_shp_Q14, 0, 4); - Arrays.MemSet(this.GainsPre_Q14, 0, 4); - Arrays.MemSet(this.HarmBoost_Q14, 0, 4); - Arrays.MemSet(this.Tilt_Q14, 0, 4); - Arrays.MemSet(this.HarmShapeGain_Q14, 0, 4); - this.Lambda_Q10 = 0; - this.input_quality_Q14 = 0; - this.coding_quality_Q14 = 0; - this.sparseness_Q8 = 0; - this.predGain_Q16 = 0; - this.LTPredCodGain_Q7 = 0; - Arrays.MemSet(this.ResNrg, 0, 4); - Arrays.MemSet(this.ResNrgQ, 0, 4); - Arrays.MemSet(this.GainsUnq_Q16, 0, 4); - this.lastGainIndexPrev = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkError.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkError.java deleted file mode 100644 index ae5bbc4..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkError.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class SilkError { - static int SILK_NO_ERROR = 0; - static int SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES = -101; - static int SILK_ENC_FS_NOT_SUPPORTED = -102; - static int SILK_ENC_PACKET_SIZE_NOT_SUPPORTED = -103; - static int SILK_ENC_PAYLOAD_BUF_TOO_SHORT = -104; - static int SILK_ENC_INVALID_LOSS_RATE = -105; - static int SILK_ENC_INVALID_COMPLEXITY_SETTING = -106; - static int SILK_ENC_INVALID_INBAND_FEC_SETTING = -107; - static int SILK_ENC_INVALID_DTX_SETTING = -108; - static int SILK_ENC_INVALID_CBR_SETTING = -109; - static int SILK_ENC_INTERNAL_ERROR = -110; - static int SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR = -111; - static int SILK_DEC_INVALID_SAMPLING_FREQUENCY = -200; - static int SILK_DEC_PAYLOAD_TOO_LARGE = -201; - static int SILK_DEC_PAYLOAD_ERROR = -202; - static int SILK_DEC_INVALID_FRAME_SIZE = -203; - - SilkError() { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkLPState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkLPState.java deleted file mode 100644 index 3d60a80..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkLPState.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.Inlines; - -class SilkLPState { - final int[] In_LP_State = new int[2]; - int transition_frame_no = 0; - int mode = 0; - - SilkLPState() { - } - - void Reset() { - this.In_LP_State[0] = 0; - this.In_LP_State[1] = 0; - this.transition_frame_no = 0; - this.mode = 0; - } - - void silk_LP_variable_cutoff(short[] frame, int frame_ptr, int frame_length) { - int[] B_Q28 = new int[3]; - int[] A_Q28 = new int[2]; - int fac_Q16 = 0; - int ind = 0; - Inlines.OpusAssert(this.transition_frame_no >= 0 && this.transition_frame_no <= 256); - if (this.mode != 0) { - fac_Q16 = Inlines.silk_LSHIFT(256 - this.transition_frame_no, 10); - ind = Inlines.silk_RSHIFT(fac_Q16, 16); - Inlines.OpusAssert(ind >= 0); - Inlines.OpusAssert(ind < 5); - Filters.silk_LP_interpolate_filter_taps(B_Q28, A_Q28, ind, fac_Q16 -= Inlines.silk_LSHIFT(ind, 16)); - this.transition_frame_no = Inlines.silk_LIMIT(this.transition_frame_no + this.mode, 0, 256); - Inlines.OpusAssert(true); - Filters.silk_biquad_alt(frame, frame_ptr, B_Q28, A_Q28, this.In_LP_State, frame, frame_ptr, frame_length, 1); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkNSQState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkNSQState.java deleted file mode 100644 index 8b9bb62..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkNSQState.java +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SideInfoIndices; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkConstants; -import de.maxhenkel.voicechat.concentus.SilkTables; - -class SilkNSQState { - final short[] xq = new short[640]; - final int[] sLTP_shp_Q14 = new int[640]; - final int[] sLPC_Q14 = new int[80 + SilkConstants.NSQ_LPC_BUF_LENGTH]; - final int[] sAR2_Q14 = new int[16]; - int sLF_AR_shp_Q14 = 0; - int lagPrev = 0; - int sLTP_buf_idx = 0; - int sLTP_shp_buf_idx = 0; - int rand_seed = 0; - int prev_gain_Q16 = 0; - int rewhite_flag = 0; - - SilkNSQState() { - } - - void Reset() { - Arrays.MemSet(this.xq, (short)0, 640); - Arrays.MemSet(this.sLTP_shp_Q14, 0, 640); - Arrays.MemSet(this.sLPC_Q14, 0, 80 + SilkConstants.NSQ_LPC_BUF_LENGTH); - Arrays.MemSet(this.sAR2_Q14, 0, 16); - this.sLF_AR_shp_Q14 = 0; - this.lagPrev = 0; - this.sLTP_buf_idx = 0; - this.sLTP_shp_buf_idx = 0; - this.rand_seed = 0; - this.prev_gain_Q16 = 0; - this.rewhite_flag = 0; - } - - void Assign(SilkNSQState other) { - this.sLF_AR_shp_Q14 = other.sLF_AR_shp_Q14; - this.lagPrev = other.lagPrev; - this.sLTP_buf_idx = other.sLTP_buf_idx; - this.sLTP_shp_buf_idx = other.sLTP_shp_buf_idx; - this.rand_seed = other.rand_seed; - this.prev_gain_Q16 = other.prev_gain_Q16; - this.rewhite_flag = other.rewhite_flag; - System.arraycopy(other.xq, 0, this.xq, 0, 640); - System.arraycopy(other.sLTP_shp_Q14, 0, this.sLTP_shp_Q14, 0, 640); - System.arraycopy(other.sLPC_Q14, 0, this.sLPC_Q14, 0, 80 + SilkConstants.NSQ_LPC_BUF_LENGTH); - System.arraycopy(other.sAR2_Q14, 0, this.sAR2_Q14, 0, 16); - } - - void silk_NSQ(SilkChannelEncoder psEncC, SideInfoIndices psIndices, int[] x_Q3, byte[] pulses, short[][] PredCoef_Q12, short[] LTPCoef_Q14, short[] AR2_Q13, int[] HarmShapeGain_Q14, int[] Tilt_Q14, int[] LF_shp_Q14, int[] Gains_Q16, int[] pitchL, int Lambda_Q10, int LTP_scale_Q14) { - int pulses_ptr = 0; - int x_Q3_ptr = 0; - this.rand_seed = psIndices.Seed; - int lag = this.lagPrev; - Inlines.OpusAssert(this.prev_gain_Q16 != 0); - short offset_Q10 = SilkTables.silk_Quantization_Offsets_Q10[psIndices.signalType >> 1][psIndices.quantOffsetType]; - int LSF_interpolation_flag = psIndices.NLSFInterpCoef_Q2 == 4 ? 0 : 1; - int[] sLTP_Q15 = new int[psEncC.ltp_mem_length + psEncC.frame_length]; - short[] sLTP = new short[psEncC.ltp_mem_length + psEncC.frame_length]; - int[] x_sc_Q10 = new int[psEncC.subfr_length]; - this.sLTP_shp_buf_idx = psEncC.ltp_mem_length; - this.sLTP_buf_idx = psEncC.ltp_mem_length; - int pxq = psEncC.ltp_mem_length; - for (int k = 0; k < psEncC.nb_subfr; ++k) { - int A_Q12 = k >> 1 | 1 - LSF_interpolation_flag; - int B_Q14 = k * 5; - int AR_shp_Q13 = k * 16; - Inlines.OpusAssert(HarmShapeGain_Q14[k] >= 0); - int HarmShapeFIRPacked_Q14 = Inlines.silk_RSHIFT(HarmShapeGain_Q14[k], 2); - HarmShapeFIRPacked_Q14 |= Inlines.silk_LSHIFT(Inlines.silk_RSHIFT(HarmShapeGain_Q14[k], 1), 16); - this.rewhite_flag = 0; - if (psIndices.signalType == 2) { - lag = pitchL[k]; - if ((k & 3 - Inlines.silk_LSHIFT(LSF_interpolation_flag, 1)) == 0) { - int start_idx = psEncC.ltp_mem_length - lag - psEncC.predictLPCOrder - 2; - Inlines.OpusAssert(start_idx > 0); - Filters.silk_LPC_analysis_filter(sLTP, start_idx, this.xq, start_idx + k * psEncC.subfr_length, PredCoef_Q12[A_Q12], 0, psEncC.ltp_mem_length - start_idx, psEncC.predictLPCOrder); - this.rewhite_flag = 1; - this.sLTP_buf_idx = psEncC.ltp_mem_length; - } - } - this.silk_nsq_scale_states(psEncC, x_Q3, x_Q3_ptr, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices.signalType); - this.silk_noise_shape_quantizer(psIndices.signalType, x_sc_Q10, pulses, pulses_ptr, this.xq, pxq, sLTP_Q15, PredCoef_Q12[A_Q12], LTPCoef_Q14, B_Q14, AR2_Q13, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[k], LF_shp_Q14[k], Gains_Q16[k], Lambda_Q10, offset_Q10, psEncC.subfr_length, psEncC.shapingLPCOrder, psEncC.predictLPCOrder); - x_Q3_ptr += psEncC.subfr_length; - pulses_ptr += psEncC.subfr_length; - pxq += psEncC.subfr_length; - } - this.lagPrev = pitchL[psEncC.nb_subfr - 1]; - Arrays.MemMove(this.xq, psEncC.frame_length, 0, psEncC.ltp_mem_length); - Arrays.MemMove(this.sLTP_shp_Q14, psEncC.frame_length, 0, psEncC.ltp_mem_length); - } - - private void silk_noise_shape_quantizer(int signalType, int[] x_sc_Q10, byte[] pulses, int pulses_ptr, short[] xq, int xq_ptr, int[] sLTP_Q15, short[] a_Q12, short[] b_Q14, int b_Q14_ptr, short[] AR_shp_Q13, int AR_shp_Q13_ptr, int lag, int HarmShapeFIRPacked_Q14, int Tilt_Q14, int LF_shp_Q14, int Gain_Q16, int Lambda_Q10, int offset_Q10, int length, int shapingLPCOrder, int predictLPCOrder) { - int shp_lag_ptr = this.sLTP_shp_buf_idx - lag + 1; - int pred_lag_ptr = this.sLTP_buf_idx - lag + 2; - int Gain_Q10 = Inlines.silk_RSHIFT(Gain_Q16, 6); - int psLPC_Q14 = SilkConstants.NSQ_LPC_BUF_LENGTH - 1; - for (int i = 0; i < length; ++i) { - int sLF_AR_shp_Q14; - int rd2_Q20; - int rd1_Q20; - int q2_Q10; - int q1_Q10; - int q1_Q0; - int LTP_pred_Q13; - this.rand_seed = Inlines.silk_RAND(this.rand_seed); - Inlines.OpusAssert(predictLPCOrder == 10 || predictLPCOrder == 16); - int LPC_pred_Q10 = Inlines.silk_RSHIFT(predictLPCOrder, 1); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 0], a_Q12[0]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 1], a_Q12[1]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 2], a_Q12[2]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 3], a_Q12[3]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 4], a_Q12[4]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 5], a_Q12[5]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 6], a_Q12[6]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 7], a_Q12[7]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 8], a_Q12[8]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 9], a_Q12[9]); - if (predictLPCOrder == 16) { - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 10], a_Q12[10]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 11], a_Q12[11]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 12], a_Q12[12]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 13], a_Q12[13]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 14], a_Q12[14]); - LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, this.sLPC_Q14[psLPC_Q14 - 15], a_Q12[15]); - } - if (signalType == 2) { - LTP_pred_Q13 = 2; - LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr], b_Q14[b_Q14_ptr]); - LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 1], b_Q14[b_Q14_ptr + 1]); - LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 2], b_Q14[b_Q14_ptr + 2]); - LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 3], b_Q14[b_Q14_ptr + 3]); - LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 4], b_Q14[b_Q14_ptr + 4]); - ++pred_lag_ptr; - } else { - LTP_pred_Q13 = 0; - } - Inlines.OpusAssert((shapingLPCOrder & 1) == 0); - int tmp2 = this.sLPC_Q14[psLPC_Q14]; - int tmp1 = this.sAR2_Q14[0]; - this.sAR2_Q14[0] = tmp2; - int n_AR_Q12 = Inlines.silk_RSHIFT(shapingLPCOrder, 1); - n_AR_Q12 = Inlines.silk_SMLAWB(n_AR_Q12, tmp2, AR_shp_Q13[AR_shp_Q13_ptr]); - for (int j = 2; j < shapingLPCOrder; j += 2) { - tmp2 = this.sAR2_Q14[j - 1]; - this.sAR2_Q14[j - 1] = tmp1; - n_AR_Q12 = Inlines.silk_SMLAWB(n_AR_Q12, tmp1, AR_shp_Q13[AR_shp_Q13_ptr + j - 1]); - tmp1 = this.sAR2_Q14[j + 0]; - this.sAR2_Q14[j + 0] = tmp2; - n_AR_Q12 = Inlines.silk_SMLAWB(n_AR_Q12, tmp2, AR_shp_Q13[AR_shp_Q13_ptr + j]); - } - this.sAR2_Q14[shapingLPCOrder - 1] = tmp1; - n_AR_Q12 = Inlines.silk_SMLAWB(n_AR_Q12, tmp1, AR_shp_Q13[AR_shp_Q13_ptr + shapingLPCOrder - 1]); - n_AR_Q12 = Inlines.silk_LSHIFT32(n_AR_Q12, 1); - n_AR_Q12 = Inlines.silk_SMLAWB(n_AR_Q12, this.sLF_AR_shp_Q14, Tilt_Q14); - int n_LF_Q12 = Inlines.silk_SMULWB(this.sLTP_shp_Q14[this.sLTP_shp_buf_idx - 1], LF_shp_Q14); - n_LF_Q12 = Inlines.silk_SMLAWT(n_LF_Q12, this.sLF_AR_shp_Q14, LF_shp_Q14); - Inlines.OpusAssert(lag > 0 || signalType != 2); - tmp1 = Inlines.silk_SUB32(Inlines.silk_LSHIFT32(LPC_pred_Q10, 2), n_AR_Q12); - tmp1 = Inlines.silk_SUB32(tmp1, n_LF_Q12); - if (lag > 0) { - int n_LTP_Q13 = Inlines.silk_SMULWB(Inlines.silk_ADD32(this.sLTP_shp_Q14[shp_lag_ptr], this.sLTP_shp_Q14[shp_lag_ptr - 2]), HarmShapeFIRPacked_Q14); - n_LTP_Q13 = Inlines.silk_SMLAWT(n_LTP_Q13, this.sLTP_shp_Q14[shp_lag_ptr - 1], HarmShapeFIRPacked_Q14); - n_LTP_Q13 = Inlines.silk_LSHIFT(n_LTP_Q13, 1); - ++shp_lag_ptr; - tmp2 = Inlines.silk_SUB32(LTP_pred_Q13, n_LTP_Q13); - tmp1 = Inlines.silk_ADD_LSHIFT32(tmp2, tmp1, 1); - tmp1 = Inlines.silk_RSHIFT_ROUND(tmp1, 3); - } else { - tmp1 = Inlines.silk_RSHIFT_ROUND(tmp1, 2); - } - int r_Q10 = Inlines.silk_SUB32(x_sc_Q10[i], tmp1); - if (this.rand_seed < 0) { - r_Q10 = -r_Q10; - } - if ((q1_Q0 = Inlines.silk_RSHIFT(q1_Q10 = Inlines.silk_SUB32(r_Q10 = Inlines.silk_LIMIT_32(r_Q10, -31744, 30720), offset_Q10), 10)) > 0) { - q1_Q10 = Inlines.silk_SUB32(Inlines.silk_LSHIFT(q1_Q0, 10), 80); - q1_Q10 = Inlines.silk_ADD32(q1_Q10, offset_Q10); - q2_Q10 = Inlines.silk_ADD32(q1_Q10, 1024); - rd1_Q20 = Inlines.silk_SMULBB(q1_Q10, Lambda_Q10); - rd2_Q20 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10); - } else if (q1_Q0 == 0) { - q1_Q10 = offset_Q10; - q2_Q10 = Inlines.silk_ADD32(q1_Q10, 944); - rd1_Q20 = Inlines.silk_SMULBB(q1_Q10, Lambda_Q10); - rd2_Q20 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10); - } else if (q1_Q0 == -1) { - q2_Q10 = offset_Q10; - q1_Q10 = Inlines.silk_SUB32(q2_Q10, 944); - rd1_Q20 = Inlines.silk_SMULBB(-q1_Q10, Lambda_Q10); - rd2_Q20 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10); - } else { - q1_Q10 = Inlines.silk_ADD32(Inlines.silk_LSHIFT(q1_Q0, 10), 80); - q1_Q10 = Inlines.silk_ADD32(q1_Q10, offset_Q10); - q2_Q10 = Inlines.silk_ADD32(q1_Q10, 1024); - rd1_Q20 = Inlines.silk_SMULBB(-q1_Q10, Lambda_Q10); - rd2_Q20 = Inlines.silk_SMULBB(-q2_Q10, Lambda_Q10); - } - int rr_Q10 = Inlines.silk_SUB32(r_Q10, q1_Q10); - rd1_Q20 = Inlines.silk_SMLABB(rd1_Q20, rr_Q10, rr_Q10); - rr_Q10 = Inlines.silk_SUB32(r_Q10, q2_Q10); - rd2_Q20 = Inlines.silk_SMLABB(rd2_Q20, rr_Q10, rr_Q10); - if (rd2_Q20 < rd1_Q20) { - q1_Q10 = q2_Q10; - } - pulses[pulses_ptr + i] = (byte)Inlines.silk_RSHIFT_ROUND(q1_Q10, 10); - int exc_Q14 = Inlines.silk_LSHIFT(q1_Q10, 4); - if (this.rand_seed < 0) { - exc_Q14 = -exc_Q14; - } - int LPC_exc_Q14 = Inlines.silk_ADD_LSHIFT32(exc_Q14, LTP_pred_Q13, 1); - int xq_Q14 = Inlines.silk_ADD_LSHIFT32(LPC_exc_Q14, LPC_pred_Q10, 4); - xq[xq_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(xq_Q14, Gain_Q10), 8)); - this.sLPC_Q14[++psLPC_Q14] = xq_Q14; - this.sLF_AR_shp_Q14 = sLF_AR_shp_Q14 = Inlines.silk_SUB_LSHIFT32(xq_Q14, n_AR_Q12, 2); - this.sLTP_shp_Q14[this.sLTP_shp_buf_idx] = Inlines.silk_SUB_LSHIFT32(sLF_AR_shp_Q14, n_LF_Q12, 2); - sLTP_Q15[this.sLTP_buf_idx] = Inlines.silk_LSHIFT(LPC_exc_Q14, 1); - ++this.sLTP_shp_buf_idx; - ++this.sLTP_buf_idx; - this.rand_seed = Inlines.silk_ADD32_ovflw(this.rand_seed, pulses[pulses_ptr + i]); - } - System.arraycopy(this.sLPC_Q14, length, this.sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH); - } - - private void silk_nsq_scale_states(SilkChannelEncoder psEncC, int[] x_Q3, int x_Q3_ptr, int[] x_sc_Q10, short[] sLTP, int[] sLTP_Q15, int subfr, int LTP_scale_Q14, int[] Gains_Q16, int[] pitchL, int signal_type) { - int i; - int lag = pitchL[subfr]; - int inv_gain_Q31 = Inlines.silk_INVERSE32_varQ(Inlines.silk_max(Gains_Q16[subfr], 1), 47); - Inlines.OpusAssert(inv_gain_Q31 != 0); - int gain_adj_Q16 = Gains_Q16[subfr] != this.prev_gain_Q16 ? Inlines.silk_DIV32_varQ(this.prev_gain_Q16, Gains_Q16[subfr], 16) : 65536; - int inv_gain_Q23 = Inlines.silk_RSHIFT_ROUND(inv_gain_Q31, 8); - for (i = 0; i < psEncC.subfr_length; ++i) { - x_sc_Q10[i] = Inlines.silk_SMULWW(x_Q3[x_Q3_ptr + i], inv_gain_Q23); - } - this.prev_gain_Q16 = Gains_Q16[subfr]; - if (this.rewhite_flag != 0) { - if (subfr == 0) { - inv_gain_Q31 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(inv_gain_Q31, LTP_scale_Q14), 2); - } - for (i = this.sLTP_buf_idx - lag - 2; i < this.sLTP_buf_idx; ++i) { - Inlines.OpusAssert(i < 320); - sLTP_Q15[i] = Inlines.silk_SMULWB(inv_gain_Q31, sLTP[i]); - } - } - if (gain_adj_Q16 != 65536) { - for (i = this.sLTP_shp_buf_idx - psEncC.ltp_mem_length; i < this.sLTP_shp_buf_idx; ++i) { - this.sLTP_shp_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, this.sLTP_shp_Q14[i]); - } - if (signal_type == 2 && this.rewhite_flag == 0) { - for (i = this.sLTP_buf_idx - lag - 2; i < this.sLTP_buf_idx; ++i) { - sLTP_Q15[i] = Inlines.silk_SMULWW(gain_adj_Q16, sLTP_Q15[i]); - } - } - this.sLF_AR_shp_Q14 = Inlines.silk_SMULWW(gain_adj_Q16, this.sLF_AR_shp_Q14); - for (i = 0; i < SilkConstants.NSQ_LPC_BUF_LENGTH; ++i) { - this.sLPC_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, this.sLPC_Q14[i]); - } - for (i = 0; i < 16; ++i) { - this.sAR2_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, this.sAR2_Q14[i]); - } - } - } - - void silk_NSQ_del_dec(SilkChannelEncoder psEncC, SideInfoIndices psIndices, int[] x_Q3, byte[] pulses, short[][] PredCoef_Q12, short[] LTPCoef_Q14, short[] AR2_Q13, int[] HarmShapeGain_Q14, int[] Tilt_Q14, int[] LF_shp_Q14, int[] Gains_Q16, int[] pitchL, int Lambda_Q10, int LTP_scale_Q14) { - int last_smple_idx; - int i; - int Winner_ind; - int RDmin_Q10; - NSQ_del_dec_struct psDD; - int k; - int pulses_ptr = 0; - int x_Q3_ptr = 0; - int lag = this.lagPrev; - Inlines.OpusAssert(this.prev_gain_Q16 != 0); - NSQ_del_dec_struct[] psDelDec = new NSQ_del_dec_struct[psEncC.nStatesDelayedDecision]; - for (int c = 0; c < psEncC.nStatesDelayedDecision; ++c) { - psDelDec[c] = new NSQ_del_dec_struct(psEncC.shapingLPCOrder); - } - for (k = 0; k < psEncC.nStatesDelayedDecision; ++k) { - psDD = psDelDec[k]; - psDD.SeedInit = psDD.Seed = k + psIndices.Seed & 3; - psDD.RD_Q10 = 0; - psDD.LF_AR_Q14 = this.sLF_AR_shp_Q14; - psDD.Shape_Q14[0] = this.sLTP_shp_Q14[psEncC.ltp_mem_length - 1]; - System.arraycopy(this.sLPC_Q14, 0, psDD.sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH); - System.arraycopy(this.sAR2_Q14, 0, psDD.sAR2_Q14, 0, psEncC.shapingLPCOrder); - } - short offset_Q10 = SilkTables.silk_Quantization_Offsets_Q10[psIndices.signalType >> 1][psIndices.quantOffsetType]; - int smpl_buf_idx = 0; - int decisionDelay = Inlines.silk_min_int(32, psEncC.subfr_length); - if (psIndices.signalType == 2) { - for (k = 0; k < psEncC.nb_subfr; ++k) { - decisionDelay = Inlines.silk_min_int(decisionDelay, pitchL[k] - 2 - 1); - } - } else if (lag > 0) { - decisionDelay = Inlines.silk_min_int(decisionDelay, lag - 2 - 1); - } - int LSF_interpolation_flag = psIndices.NLSFInterpCoef_Q2 == 4 ? 0 : 1; - int[] sLTP_Q15 = new int[psEncC.ltp_mem_length + psEncC.frame_length]; - short[] sLTP = new short[psEncC.ltp_mem_length + psEncC.frame_length]; - int[] x_sc_Q10 = new int[psEncC.subfr_length]; - int[] delayedGain_Q10 = new int[32]; - int pxq = psEncC.ltp_mem_length; - this.sLTP_shp_buf_idx = psEncC.ltp_mem_length; - this.sLTP_buf_idx = psEncC.ltp_mem_length; - int subfr = 0; - for (k = 0; k < psEncC.nb_subfr; ++k) { - int A_Q12 = k >> 1 | 1 - LSF_interpolation_flag; - Inlines.OpusAssert(HarmShapeGain_Q14[k] >= 0); - int HarmShapeFIRPacked_Q14 = Inlines.silk_RSHIFT(HarmShapeGain_Q14[k], 2); - HarmShapeFIRPacked_Q14 |= Inlines.silk_LSHIFT(Inlines.silk_RSHIFT(HarmShapeGain_Q14[k], 1), 16); - this.rewhite_flag = 0; - if (psIndices.signalType == 2) { - lag = pitchL[k]; - if ((k & 3 - Inlines.silk_LSHIFT(LSF_interpolation_flag, 1)) == 0) { - int start_idx; - if (k == 2) { - RDmin_Q10 = psDelDec[0].RD_Q10; - Winner_ind = 0; - for (i = 1; i < psEncC.nStatesDelayedDecision; ++i) { - if (psDelDec[i].RD_Q10 >= RDmin_Q10) continue; - RDmin_Q10 = psDelDec[i].RD_Q10; - Winner_ind = i; - } - for (i = 0; i < psEncC.nStatesDelayedDecision; ++i) { - if (i == Winner_ind) continue; - psDelDec[i].RD_Q10 += 0x7FFFFFF; - Inlines.OpusAssert(psDelDec[i].RD_Q10 >= 0); - } - psDD = psDelDec[Winner_ind]; - last_smple_idx = smpl_buf_idx + decisionDelay; - for (i = 0; i < decisionDelay; ++i) { - last_smple_idx = last_smple_idx - 1 & 0x1F; - pulses[pulses_ptr + i - decisionDelay] = (byte)Inlines.silk_RSHIFT_ROUND(psDD.Q_Q10[last_smple_idx], 10); - this.xq[pxq + i - decisionDelay] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(psDD.Xq_Q14[last_smple_idx], Gains_Q16[1]), 14)); - this.sLTP_shp_Q14[this.sLTP_shp_buf_idx - decisionDelay + i] = psDD.Shape_Q14[last_smple_idx]; - } - subfr = 0; - } - Inlines.OpusAssert((start_idx = psEncC.ltp_mem_length - lag - psEncC.predictLPCOrder - 2) > 0); - Filters.silk_LPC_analysis_filter(sLTP, start_idx, this.xq, start_idx + k * psEncC.subfr_length, PredCoef_Q12[A_Q12], 0, psEncC.ltp_mem_length - start_idx, psEncC.predictLPCOrder); - this.sLTP_buf_idx = psEncC.ltp_mem_length; - this.rewhite_flag = 1; - } - } - this.silk_nsq_del_dec_scale_states(psEncC, psDelDec, x_Q3, x_Q3_ptr, x_sc_Q10, sLTP, sLTP_Q15, k, psEncC.nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices.signalType, decisionDelay); - BoxedValueInt smpl_buf_idx_boxed = new BoxedValueInt(smpl_buf_idx); - this.silk_noise_shape_quantizer_del_dec(psDelDec, psIndices.signalType, x_sc_Q10, pulses, pulses_ptr, this.xq, pxq, sLTP_Q15, delayedGain_Q10, PredCoef_Q12[A_Q12], LTPCoef_Q14, k * 5, AR2_Q13, k * 16, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[k], LF_shp_Q14[k], Gains_Q16[k], Lambda_Q10, offset_Q10, psEncC.subfr_length, subfr++, psEncC.shapingLPCOrder, psEncC.predictLPCOrder, psEncC.warping_Q16, psEncC.nStatesDelayedDecision, smpl_buf_idx_boxed, decisionDelay); - smpl_buf_idx = smpl_buf_idx_boxed.Val; - x_Q3_ptr += psEncC.subfr_length; - pulses_ptr += psEncC.subfr_length; - pxq += psEncC.subfr_length; - } - RDmin_Q10 = psDelDec[0].RD_Q10; - Winner_ind = 0; - for (k = 1; k < psEncC.nStatesDelayedDecision; ++k) { - if (psDelDec[k].RD_Q10 >= RDmin_Q10) continue; - RDmin_Q10 = psDelDec[k].RD_Q10; - Winner_ind = k; - } - psDD = psDelDec[Winner_ind]; - psIndices.Seed = (byte)psDD.SeedInit; - last_smple_idx = smpl_buf_idx + decisionDelay; - int Gain_Q10 = Inlines.silk_RSHIFT32(Gains_Q16[psEncC.nb_subfr - 1], 6); - for (i = 0; i < decisionDelay; ++i) { - last_smple_idx = last_smple_idx - 1 & 0x1F; - pulses[pulses_ptr + i - decisionDelay] = (byte)Inlines.silk_RSHIFT_ROUND(psDD.Q_Q10[last_smple_idx], 10); - this.xq[pxq + i - decisionDelay] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(psDD.Xq_Q14[last_smple_idx], Gain_Q10), 8)); - this.sLTP_shp_Q14[this.sLTP_shp_buf_idx - decisionDelay + i] = psDD.Shape_Q14[last_smple_idx]; - } - System.arraycopy(psDD.sLPC_Q14, psEncC.subfr_length, this.sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH); - System.arraycopy(psDD.sAR2_Q14, 0, this.sAR2_Q14, 0, psEncC.shapingLPCOrder); - this.sLF_AR_shp_Q14 = psDD.LF_AR_Q14; - this.lagPrev = pitchL[psEncC.nb_subfr - 1]; - Arrays.MemMove(this.xq, psEncC.frame_length, 0, psEncC.ltp_mem_length); - Arrays.MemMove(this.sLTP_shp_Q14, psEncC.frame_length, 0, psEncC.ltp_mem_length); - } - - private void silk_noise_shape_quantizer_del_dec(NSQ_del_dec_struct[] psDelDec, int signalType, int[] x_Q10, byte[] pulses, int pulses_ptr, short[] xq, int xq_ptr, int[] sLTP_Q15, int[] delayedGain_Q10, short[] a_Q12, short[] b_Q14, int b_Q14_ptr, short[] AR_shp_Q13, int AR_shp_Q13_ptr, int lag, int HarmShapeFIRPacked_Q14, int Tilt_Q14, int LF_shp_Q14, int Gain_Q16, int Lambda_Q10, int offset_Q10, int length, int subfr, int shapingLPCOrder, int predictLPCOrder, int warping_Q16, int nStatesDelayedDecision, BoxedValueInt smpl_buf_idx, int decisionDelay) { - NSQ_del_dec_struct psDD; - int k; - Inlines.OpusAssert(nStatesDelayedDecision > 0); - NSQ_sample_struct[] sampleStates = new NSQ_sample_struct[2 * nStatesDelayedDecision]; - for (int c = 0; c < 2 * nStatesDelayedDecision; ++c) { - sampleStates[c] = new NSQ_sample_struct(); - } - int shp_lag_ptr = this.sLTP_shp_buf_idx - lag + 1; - int pred_lag_ptr = this.sLTP_buf_idx - lag + 2; - int Gain_Q10 = Inlines.silk_RSHIFT(Gain_Q16, 6); - for (int i = 0; i < length; ++i) { - int k2; - int SS_left; - int n_LTP_Q14; - int LTP_pred_Q14; - if (signalType == 2) { - LTP_pred_Q14 = 2; - LTP_pred_Q14 = Inlines.silk_SMLAWB(LTP_pred_Q14, sLTP_Q15[pred_lag_ptr], b_Q14[b_Q14_ptr + 0]); - LTP_pred_Q14 = Inlines.silk_SMLAWB(LTP_pred_Q14, sLTP_Q15[pred_lag_ptr - 1], b_Q14[b_Q14_ptr + 1]); - LTP_pred_Q14 = Inlines.silk_SMLAWB(LTP_pred_Q14, sLTP_Q15[pred_lag_ptr - 2], b_Q14[b_Q14_ptr + 2]); - LTP_pred_Q14 = Inlines.silk_SMLAWB(LTP_pred_Q14, sLTP_Q15[pred_lag_ptr - 3], b_Q14[b_Q14_ptr + 3]); - LTP_pred_Q14 = Inlines.silk_SMLAWB(LTP_pred_Q14, sLTP_Q15[pred_lag_ptr - 4], b_Q14[b_Q14_ptr + 4]); - LTP_pred_Q14 = Inlines.silk_LSHIFT(LTP_pred_Q14, 1); - ++pred_lag_ptr; - } else { - LTP_pred_Q14 = 0; - } - if (lag > 0) { - n_LTP_Q14 = Inlines.silk_SMULWB(Inlines.silk_ADD32(this.sLTP_shp_Q14[shp_lag_ptr], this.sLTP_shp_Q14[shp_lag_ptr - 2]), HarmShapeFIRPacked_Q14); - n_LTP_Q14 = Inlines.silk_SMLAWT(n_LTP_Q14, this.sLTP_shp_Q14[shp_lag_ptr - 1], HarmShapeFIRPacked_Q14); - n_LTP_Q14 = Inlines.silk_SUB_LSHIFT32(LTP_pred_Q14, n_LTP_Q14, 2); - ++shp_lag_ptr; - } else { - n_LTP_Q14 = 0; - } - for (k = 0; k < nStatesDelayedDecision; ++k) { - int rd2_Q10; - int rd1_Q10; - int q2_Q10; - int q1_Q10; - int q1_Q0; - psDD = psDelDec[k]; - int[] psDD_sAR2 = psDD.sAR2_Q14; - SS_left = 2 * k; - int SS_right = SS_left + 1; - psDD.Seed = Inlines.silk_RAND(psDD.Seed); - int psLPC_Q14 = SilkConstants.NSQ_LPC_BUF_LENGTH - 1 + i; - Inlines.OpusAssert(predictLPCOrder == 10 || predictLPCOrder == 16); - int LPC_pred_Q14 = Inlines.silk_RSHIFT(predictLPCOrder, 1); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14], a_Q12[0]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 1], a_Q12[1]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 2], a_Q12[2]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 3], a_Q12[3]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 4], a_Q12[4]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 5], a_Q12[5]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 6], a_Q12[6]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 7], a_Q12[7]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 8], a_Q12[8]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 9], a_Q12[9]); - if (predictLPCOrder == 16) { - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 10], a_Q12[10]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 11], a_Q12[11]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 12], a_Q12[12]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 13], a_Q12[13]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 14], a_Q12[14]); - LPC_pred_Q14 = Inlines.silk_SMLAWB(LPC_pred_Q14, psDD.sLPC_Q14[psLPC_Q14 - 15], a_Q12[15]); - } - LPC_pred_Q14 = Inlines.silk_LSHIFT(LPC_pred_Q14, 4); - Inlines.OpusAssert((shapingLPCOrder & 1) == 0); - int tmp2 = Inlines.silk_SMLAWB(psDD.sLPC_Q14[psLPC_Q14], psDD_sAR2[0], warping_Q16); - int tmp1 = Inlines.silk_SMLAWB(psDD_sAR2[0], psDD_sAR2[1] - tmp2, warping_Q16); - psDD_sAR2[0] = tmp2; - int n_AR_Q14 = Inlines.silk_RSHIFT(shapingLPCOrder, 1); - n_AR_Q14 = Inlines.silk_SMLAWB(n_AR_Q14, tmp2, AR_shp_Q13[AR_shp_Q13_ptr]); - for (int j = 2; j < shapingLPCOrder; j += 2) { - tmp2 = Inlines.silk_SMLAWB(psDD_sAR2[j - 1], psDD_sAR2[j + 0] - tmp1, warping_Q16); - psDD_sAR2[j - 1] = tmp1; - n_AR_Q14 = Inlines.silk_SMLAWB(n_AR_Q14, tmp1, AR_shp_Q13[AR_shp_Q13_ptr + j - 1]); - tmp1 = Inlines.silk_SMLAWB(psDD_sAR2[j + 0], psDD_sAR2[j + 1] - tmp2, warping_Q16); - psDD_sAR2[j + 0] = tmp2; - n_AR_Q14 = Inlines.silk_SMLAWB(n_AR_Q14, tmp2, AR_shp_Q13[AR_shp_Q13_ptr + j]); - } - psDD_sAR2[shapingLPCOrder - 1] = tmp1; - n_AR_Q14 = Inlines.silk_SMLAWB(n_AR_Q14, tmp1, AR_shp_Q13[AR_shp_Q13_ptr + shapingLPCOrder - 1]); - n_AR_Q14 = Inlines.silk_LSHIFT(n_AR_Q14, 1); - n_AR_Q14 = Inlines.silk_SMLAWB(n_AR_Q14, psDD.LF_AR_Q14, Tilt_Q14); - n_AR_Q14 = Inlines.silk_LSHIFT(n_AR_Q14, 2); - int n_LF_Q14 = Inlines.silk_SMULWB(psDD.Shape_Q14[smpl_buf_idx.Val], LF_shp_Q14); - n_LF_Q14 = Inlines.silk_SMLAWT(n_LF_Q14, psDD.LF_AR_Q14, LF_shp_Q14); - n_LF_Q14 = Inlines.silk_LSHIFT(n_LF_Q14, 2); - tmp1 = Inlines.silk_ADD32(n_AR_Q14, n_LF_Q14); - tmp2 = Inlines.silk_ADD32(n_LTP_Q14, LPC_pred_Q14); - tmp1 = Inlines.silk_SUB32(tmp2, tmp1); - tmp1 = Inlines.silk_RSHIFT_ROUND(tmp1, 4); - int r_Q10 = Inlines.silk_SUB32(x_Q10[i], tmp1); - if (psDD.Seed < 0) { - r_Q10 = -r_Q10; - } - if ((q1_Q0 = Inlines.silk_RSHIFT(q1_Q10 = Inlines.silk_SUB32(r_Q10 = Inlines.silk_LIMIT_32(r_Q10, -31744, 30720), offset_Q10), 10)) > 0) { - q1_Q10 = Inlines.silk_SUB32(Inlines.silk_LSHIFT(q1_Q0, 10), 80); - q1_Q10 = Inlines.silk_ADD32(q1_Q10, offset_Q10); - q2_Q10 = Inlines.silk_ADD32(q1_Q10, 1024); - rd1_Q10 = Inlines.silk_SMULBB(q1_Q10, Lambda_Q10); - rd2_Q10 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10); - } else if (q1_Q0 == 0) { - q1_Q10 = offset_Q10; - q2_Q10 = Inlines.silk_ADD32(q1_Q10, 944); - rd1_Q10 = Inlines.silk_SMULBB(q1_Q10, Lambda_Q10); - rd2_Q10 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10); - } else if (q1_Q0 == -1) { - q2_Q10 = offset_Q10; - q1_Q10 = Inlines.silk_SUB32(q2_Q10, 944); - rd1_Q10 = Inlines.silk_SMULBB(-q1_Q10, Lambda_Q10); - rd2_Q10 = Inlines.silk_SMULBB(q2_Q10, Lambda_Q10); - } else { - q1_Q10 = Inlines.silk_ADD32(Inlines.silk_LSHIFT(q1_Q0, 10), 80); - q1_Q10 = Inlines.silk_ADD32(q1_Q10, offset_Q10); - q2_Q10 = Inlines.silk_ADD32(q1_Q10, 1024); - rd1_Q10 = Inlines.silk_SMULBB(-q1_Q10, Lambda_Q10); - rd2_Q10 = Inlines.silk_SMULBB(-q2_Q10, Lambda_Q10); - } - int rr_Q10 = Inlines.silk_SUB32(r_Q10, q1_Q10); - rd1_Q10 = Inlines.silk_RSHIFT(Inlines.silk_SMLABB(rd1_Q10, rr_Q10, rr_Q10), 10); - rr_Q10 = Inlines.silk_SUB32(r_Q10, q2_Q10); - rd2_Q10 = Inlines.silk_RSHIFT(Inlines.silk_SMLABB(rd2_Q10, rr_Q10, rr_Q10), 10); - if (rd1_Q10 < rd2_Q10) { - sampleStates[SS_left].RD_Q10 = Inlines.silk_ADD32(psDD.RD_Q10, rd1_Q10); - sampleStates[SS_right].RD_Q10 = Inlines.silk_ADD32(psDD.RD_Q10, rd2_Q10); - sampleStates[SS_left].Q_Q10 = q1_Q10; - sampleStates[SS_right].Q_Q10 = q2_Q10; - } else { - sampleStates[SS_left].RD_Q10 = Inlines.silk_ADD32(psDD.RD_Q10, rd2_Q10); - sampleStates[SS_right].RD_Q10 = Inlines.silk_ADD32(psDD.RD_Q10, rd1_Q10); - sampleStates[SS_left].Q_Q10 = q2_Q10; - sampleStates[SS_right].Q_Q10 = q1_Q10; - } - int exc_Q14 = Inlines.silk_LSHIFT32(sampleStates[SS_left].Q_Q10, 4); - if (psDD.Seed < 0) { - exc_Q14 = -exc_Q14; - } - int LPC_exc_Q14 = Inlines.silk_ADD32(exc_Q14, LTP_pred_Q14); - int xq_Q14 = Inlines.silk_ADD32(LPC_exc_Q14, LPC_pred_Q14); - int sLF_AR_shp_Q14 = Inlines.silk_SUB32(xq_Q14, n_AR_Q14); - sampleStates[SS_left].sLTP_shp_Q14 = Inlines.silk_SUB32(sLF_AR_shp_Q14, n_LF_Q14); - sampleStates[SS_left].LF_AR_Q14 = sLF_AR_shp_Q14; - sampleStates[SS_left].LPC_exc_Q14 = LPC_exc_Q14; - sampleStates[SS_left].xq_Q14 = xq_Q14; - exc_Q14 = Inlines.silk_LSHIFT32(sampleStates[SS_right].Q_Q10, 4); - if (psDD.Seed < 0) { - exc_Q14 = -exc_Q14; - } - LPC_exc_Q14 = Inlines.silk_ADD32(exc_Q14, LTP_pred_Q14); - xq_Q14 = Inlines.silk_ADD32(LPC_exc_Q14, LPC_pred_Q14); - sLF_AR_shp_Q14 = Inlines.silk_SUB32(xq_Q14, n_AR_Q14); - sampleStates[SS_right].sLTP_shp_Q14 = Inlines.silk_SUB32(sLF_AR_shp_Q14, n_LF_Q14); - sampleStates[SS_right].LF_AR_Q14 = sLF_AR_shp_Q14; - sampleStates[SS_right].LPC_exc_Q14 = LPC_exc_Q14; - sampleStates[SS_right].xq_Q14 = xq_Q14; - } - smpl_buf_idx.Val = smpl_buf_idx.Val - 1 & 0x1F; - int last_smple_idx = smpl_buf_idx.Val + decisionDelay & 0x1F; - int RDmin_Q10 = sampleStates[0].RD_Q10; - int Winner_ind = 0; - for (k = 1; k < nStatesDelayedDecision; ++k) { - if (sampleStates[k * 2].RD_Q10 >= RDmin_Q10) continue; - RDmin_Q10 = sampleStates[k * 2].RD_Q10; - Winner_ind = k; - } - int Winner_rand_state = psDelDec[Winner_ind].RandState[last_smple_idx]; - for (k = 0; k < nStatesDelayedDecision; ++k) { - if (psDelDec[k].RandState[last_smple_idx] == Winner_rand_state) continue; - k2 = k * 2; - sampleStates[k2].RD_Q10 = Inlines.silk_ADD32(sampleStates[k2].RD_Q10, 0x7FFFFFF); - sampleStates[k2 + 1].RD_Q10 = Inlines.silk_ADD32(sampleStates[k2 + 1].RD_Q10, 0x7FFFFFF); - Inlines.OpusAssert(sampleStates[k2].RD_Q10 >= 0); - } - int RDmax_Q10 = sampleStates[0].RD_Q10; - RDmin_Q10 = sampleStates[1].RD_Q10; - int RDmax_ind = 0; - int RDmin_ind = 0; - for (k = 1; k < nStatesDelayedDecision; ++k) { - k2 = k * 2; - if (sampleStates[k2].RD_Q10 > RDmax_Q10) { - RDmax_Q10 = sampleStates[k2].RD_Q10; - RDmax_ind = k; - } - if (sampleStates[k2 + 1].RD_Q10 >= RDmin_Q10) continue; - RDmin_Q10 = sampleStates[k2 + 1].RD_Q10; - RDmin_ind = k; - } - if (RDmin_Q10 < RDmax_Q10) { - psDelDec[RDmax_ind].PartialCopyFrom(psDelDec[RDmin_ind], i); - sampleStates[RDmax_ind * 2].Assign(sampleStates[RDmin_ind * 2 + 1]); - } - psDD = psDelDec[Winner_ind]; - if (subfr > 0 || i >= decisionDelay) { - pulses[pulses_ptr + i - decisionDelay] = (byte)Inlines.silk_RSHIFT_ROUND(psDD.Q_Q10[last_smple_idx], 10); - xq[xq_ptr + i - decisionDelay] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(psDD.Xq_Q14[last_smple_idx], delayedGain_Q10[last_smple_idx]), 8)); - this.sLTP_shp_Q14[this.sLTP_shp_buf_idx - decisionDelay] = psDD.Shape_Q14[last_smple_idx]; - sLTP_Q15[this.sLTP_buf_idx - decisionDelay] = psDD.Pred_Q15[last_smple_idx]; - } - ++this.sLTP_shp_buf_idx; - ++this.sLTP_buf_idx; - for (k = 0; k < nStatesDelayedDecision; ++k) { - psDD = psDelDec[k]; - SS_left = k * 2; - psDD.LF_AR_Q14 = sampleStates[SS_left].LF_AR_Q14; - psDD.sLPC_Q14[SilkConstants.NSQ_LPC_BUF_LENGTH + i] = sampleStates[SS_left].xq_Q14; - psDD.Xq_Q14[smpl_buf_idx.Val] = sampleStates[SS_left].xq_Q14; - psDD.Q_Q10[smpl_buf_idx.Val] = sampleStates[SS_left].Q_Q10; - psDD.Pred_Q15[smpl_buf_idx.Val] = Inlines.silk_LSHIFT32(sampleStates[SS_left].LPC_exc_Q14, 1); - psDD.Shape_Q14[smpl_buf_idx.Val] = sampleStates[SS_left].sLTP_shp_Q14; - psDD.RandState[smpl_buf_idx.Val] = psDD.Seed = Inlines.silk_ADD32_ovflw(psDD.Seed, Inlines.silk_RSHIFT_ROUND(sampleStates[SS_left].Q_Q10, 10)); - psDD.RD_Q10 = sampleStates[SS_left].RD_Q10; - } - delayedGain_Q10[smpl_buf_idx.Val] = Gain_Q10; - } - for (k = 0; k < nStatesDelayedDecision; ++k) { - psDD = psDelDec[k]; - System.arraycopy(psDD.sLPC_Q14, length, psDD.sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH); - } - } - - private void silk_nsq_del_dec_scale_states(SilkChannelEncoder psEncC, NSQ_del_dec_struct[] psDelDec, int[] x_Q3, int x_Q3_ptr, int[] x_sc_Q10, short[] sLTP, int[] sLTP_Q15, int subfr, int nStatesDelayedDecision, int LTP_scale_Q14, int[] Gains_Q16, int[] pitchL, int signal_type, int decisionDelay) { - int i; - int lag = pitchL[subfr]; - int inv_gain_Q31 = Inlines.silk_INVERSE32_varQ(Inlines.silk_max(Gains_Q16[subfr], 1), 47); - Inlines.OpusAssert(inv_gain_Q31 != 0); - int gain_adj_Q16 = Gains_Q16[subfr] != this.prev_gain_Q16 ? Inlines.silk_DIV32_varQ(this.prev_gain_Q16, Gains_Q16[subfr], 16) : 65536; - int inv_gain_Q23 = Inlines.silk_RSHIFT_ROUND(inv_gain_Q31, 8); - for (i = 0; i < psEncC.subfr_length; ++i) { - x_sc_Q10[i] = Inlines.silk_SMULWW(x_Q3[x_Q3_ptr + i], inv_gain_Q23); - } - this.prev_gain_Q16 = Gains_Q16[subfr]; - if (this.rewhite_flag != 0) { - if (subfr == 0) { - inv_gain_Q31 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(inv_gain_Q31, LTP_scale_Q14), 2); - } - for (i = this.sLTP_buf_idx - lag - 2; i < this.sLTP_buf_idx; ++i) { - Inlines.OpusAssert(i < 320); - sLTP_Q15[i] = Inlines.silk_SMULWB(inv_gain_Q31, sLTP[i]); - } - } - if (gain_adj_Q16 != 65536) { - for (i = this.sLTP_shp_buf_idx - psEncC.ltp_mem_length; i < this.sLTP_shp_buf_idx; ++i) { - this.sLTP_shp_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, this.sLTP_shp_Q14[i]); - } - if (signal_type == 2 && this.rewhite_flag == 0) { - for (i = this.sLTP_buf_idx - lag - 2; i < this.sLTP_buf_idx - decisionDelay; ++i) { - sLTP_Q15[i] = Inlines.silk_SMULWW(gain_adj_Q16, sLTP_Q15[i]); - } - } - for (int k = 0; k < nStatesDelayedDecision; ++k) { - NSQ_del_dec_struct psDD = psDelDec[k]; - psDD.LF_AR_Q14 = Inlines.silk_SMULWW(gain_adj_Q16, psDD.LF_AR_Q14); - for (i = 0; i < SilkConstants.NSQ_LPC_BUF_LENGTH; ++i) { - psDD.sLPC_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, psDD.sLPC_Q14[i]); - } - for (i = 0; i < psEncC.shapingLPCOrder; ++i) { - psDD.sAR2_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, psDD.sAR2_Q14[i]); - } - for (i = 0; i < 32; ++i) { - psDD.Pred_Q15[i] = Inlines.silk_SMULWW(gain_adj_Q16, psDD.Pred_Q15[i]); - psDD.Shape_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, psDD.Shape_Q14[i]); - } - } - } - } - - private class NSQ_del_dec_struct { - final int[] sLPC_Q14 = new int[80 + SilkConstants.NSQ_LPC_BUF_LENGTH]; - final int[] RandState = new int[32]; - final int[] Q_Q10 = new int[32]; - final int[] Xq_Q14 = new int[32]; - final int[] Pred_Q15 = new int[32]; - final int[] Shape_Q14 = new int[32]; - int[] sAR2_Q14; - int LF_AR_Q14 = 0; - int Seed = 0; - int SeedInit = 0; - int RD_Q10 = 0; - - NSQ_del_dec_struct(int shapingOrder) { - this.sAR2_Q14 = new int[shapingOrder]; - } - - void PartialCopyFrom(NSQ_del_dec_struct other, int q14Offset) { - System.arraycopy(other.sLPC_Q14, q14Offset, this.sLPC_Q14, q14Offset, 80 + SilkConstants.NSQ_LPC_BUF_LENGTH - q14Offset); - System.arraycopy(other.RandState, 0, this.RandState, 0, 32); - System.arraycopy(other.Q_Q10, 0, this.Q_Q10, 0, 32); - System.arraycopy(other.Xq_Q14, 0, this.Xq_Q14, 0, 32); - System.arraycopy(other.Pred_Q15, 0, this.Pred_Q15, 0, 32); - System.arraycopy(other.Shape_Q14, 0, this.Shape_Q14, 0, 32); - System.arraycopy(other.sAR2_Q14, 0, this.sAR2_Q14, 0, this.sAR2_Q14.length); - this.LF_AR_Q14 = other.LF_AR_Q14; - this.Seed = other.Seed; - this.SeedInit = other.SeedInit; - this.RD_Q10 = other.RD_Q10; - } - - void Assign(NSQ_del_dec_struct other) { - this.PartialCopyFrom(other, 0); - } - } - - private class NSQ_sample_struct { - int Q_Q10; - int RD_Q10; - int xq_Q14; - int LF_AR_Q14; - int sLTP_shp_Q14; - int LPC_exc_Q14; - - private NSQ_sample_struct() { - } - - void Assign(NSQ_sample_struct other) { - this.Q_Q10 = other.Q_Q10; - this.RD_Q10 = other.RD_Q10; - this.xq_Q14 = other.xq_Q14; - this.LF_AR_Q14 = other.LF_AR_Q14; - this.sLTP_shp_Q14 = other.sLTP_shp_Q14; - this.LPC_exc_Q14 = other.LPC_exc_Q14; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkPrefilterState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkPrefilterState.java deleted file mode 100644 index 917db81..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkPrefilterState.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class SilkPrefilterState { - final short[] sLTP_shp = new short[512]; - final int[] sAR_shp = new int[17]; - int sLTP_shp_buf_idx = 0; - int sLF_AR_shp_Q12 = 0; - int sLF_MA_shp_Q12 = 0; - int sHarmHP_Q2 = 0; - int rand_seed = 0; - int lagPrev = 0; - - SilkPrefilterState() { - } - - void Reset() { - Arrays.MemSet(this.sLTP_shp, (short)0, 512); - Arrays.MemSet(this.sAR_shp, 0, 17); - this.sLTP_shp_buf_idx = 0; - this.sLF_AR_shp_Q12 = 0; - this.sLF_MA_shp_Q12 = 0; - this.sHarmHP_Q2 = 0; - this.rand_seed = 0; - this.lagPrev = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkResamplerState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkResamplerState.java deleted file mode 100644 index e82a127..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkResamplerState.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class SilkResamplerState { - final int[] sIIR = new int[6]; - final int[] sFIR_i32 = new int[36]; - final short[] sFIR_i16 = new short[36]; - final short[] delayBuf = new short[48]; - int resampler_function = 0; - int batchSize = 0; - int invRatio_Q16 = 0; - int FIR_Order = 0; - int FIR_Fracs = 0; - int Fs_in_kHz = 0; - int Fs_out_kHz = 0; - int inputDelay = 0; - short[] Coefs = null; - - SilkResamplerState() { - } - - void Reset() { - Arrays.MemSet(this.sIIR, 0, 6); - Arrays.MemSet(this.sFIR_i32, 0, 36); - Arrays.MemSet(this.sFIR_i16, (short)0, 36); - Arrays.MemSet(this.delayBuf, (short)0, 48); - this.resampler_function = 0; - this.batchSize = 0; - this.invRatio_Q16 = 0; - this.FIR_Order = 0; - this.FIR_Fracs = 0; - this.Fs_in_kHz = 0; - this.Fs_out_kHz = 0; - this.inputDelay = 0; - this.Coefs = null; - } - - void Assign(SilkResamplerState other) { - this.resampler_function = other.resampler_function; - this.batchSize = other.batchSize; - this.invRatio_Q16 = other.invRatio_Q16; - this.FIR_Order = other.FIR_Order; - this.FIR_Fracs = other.FIR_Fracs; - this.Fs_in_kHz = other.Fs_in_kHz; - this.Fs_out_kHz = other.Fs_out_kHz; - this.inputDelay = other.inputDelay; - this.Coefs = other.Coefs; - System.arraycopy(other.sIIR, 0, this.sIIR, 0, 6); - System.arraycopy(other.sFIR_i32, 0, this.sFIR_i32, 0, 36); - System.arraycopy(other.sFIR_i16, 0, this.sFIR_i16, 0, 36); - System.arraycopy(other.delayBuf, 0, this.delayBuf, 0, 48); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkShapeState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkShapeState.java deleted file mode 100644 index 90bccab..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkShapeState.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class SilkShapeState { - byte LastGainIndex = 0; - int HarmBoost_smth_Q16 = 0; - int HarmShapeGain_smth_Q16 = 0; - int Tilt_smth_Q16 = 0; - - SilkShapeState() { - } - - void Reset() { - this.LastGainIndex = 0; - this.HarmBoost_smth_Q16 = 0; - this.HarmShapeGain_smth_Q16 = 0; - this.Tilt_smth_Q16 = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkTables.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkTables.java deleted file mode 100644 index 8a67825..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkTables.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.NLSFCodebook; - -class SilkTables { - static final short[] silk_LSFCosTab_Q12 = new short[]{8192, 8190, 8182, 8170, 8152, 8130, 8104, 8072, 8034, 7994, 7946, 7896, 7840, 7778, 7714, 7644, 7568, 7490, 7406, 7318, 7226, 7128, 7026, 6922, 6812, 6698, 6580, 6458, 6332, 6204, 6070, 5934, 5792, 5648, 5502, 5352, 5198, 5040, 4880, 4718, 4552, 4382, 4212, 4038, 3862, 3684, 3502, 3320, 3136, 2948, 2760, 2570, 2378, 2186, 1990, 1794, 1598, 1400, 1202, 1002, 802, 602, 402, 202, 0, -202, -402, -602, -802, -1002, -1202, -1400, -1598, -1794, -1990, -2186, -2378, -2570, -2760, -2948, -3136, -3320, -3502, -3684, -3862, -4038, -4212, -4382, -4552, -4718, -4880, -5040, -5198, -5352, -5502, -5648, -5792, -5934, -6070, -6204, -6332, -6458, -6580, -6698, -6812, -6922, -7026, -7128, -7226, -7318, -7406, -7490, -7568, -7644, -7714, -7778, -7840, -7896, -7946, -7994, -8034, -8072, -8104, -8130, -8152, -8170, -8182, -8190, -8192}; - static final short[][] silk_gain_iCDF = new short[][]{{224, 112, 44, 15, 3, 2, 1, 0}, {254, 237, 192, 132, 70, 23, 4, 0}, {255, 252, 226, 155, 61, 11, 2, 0}}; - static final short[] silk_delta_gain_iCDF = new short[]{250, 245, 234, 203, 71, 50, 42, 38, 35, 33, 31, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; - static final short[] silk_LTP_per_index_iCDF = new short[]{179, 99, 0}; - static final short[] silk_LTP_gain_iCDF_0 = new short[]{71, 56, 43, 30, 21, 12, 6, 0}; - static final short[] silk_LTP_gain_iCDF_1 = new short[]{199, 165, 144, 124, 109, 96, 84, 71, 61, 51, 42, 32, 23, 15, 8, 0}; - static final short[] silk_LTP_gain_iCDF_2 = new short[]{241, 225, 211, 199, 187, 175, 164, 153, 142, 132, 123, 114, 105, 96, 88, 80, 72, 64, 57, 50, 44, 38, 33, 29, 24, 20, 16, 12, 9, 5, 2, 0}; - static final short silk_LTP_gain_middle_avg_RD_Q14 = 12304; - static final short[] silk_LTP_gain_BITS_Q5_0 = new short[]{15, 131, 138, 138, 155, 155, 173, 173}; - static final short[] silk_LTP_gain_BITS_Q5_1 = new short[]{69, 93, 115, 118, 131, 138, 141, 138, 150, 150, 155, 150, 155, 160, 166, 160}; - static final short[] silk_LTP_gain_BITS_Q5_2 = new short[]{131, 128, 134, 141, 141, 141, 145, 145, 145, 150, 155, 155, 155, 155, 160, 160, 160, 160, 166, 166, 173, 173, 182, 192, 182, 192, 192, 192, 205, 192, 205, 224}; - static final short[][] silk_LTP_gain_iCDF_ptrs = new short[][]{silk_LTP_gain_iCDF_0, silk_LTP_gain_iCDF_1, silk_LTP_gain_iCDF_2}; - static final short[][] silk_LTP_gain_BITS_Q5_ptrs = new short[][]{silk_LTP_gain_BITS_Q5_0, silk_LTP_gain_BITS_Q5_1, silk_LTP_gain_BITS_Q5_2}; - static final byte[][] silk_LTP_gain_vq_0 = new byte[][]{{4, 6, 24, 7, 5}, {0, 0, 2, 0, 0}, {12, 28, 41, 13, -4}, {-9, 15, 42, 25, 14}, {1, -2, 62, 41, -9}, {-10, 37, 65, -4, 3}, {-6, 4, 66, 7, -8}, {16, 14, 38, -3, 33}}; - static final byte[][] silk_LTP_gain_vq_1 = new byte[][]{{13, 22, 39, 23, 12}, {-1, 36, 64, 27, -6}, {-7, 10, 55, 43, 17}, {1, 1, 8, 1, 1}, {6, -11, 74, 53, -9}, {-12, 55, 76, -12, 8}, {-3, 3, 93, 27, -4}, {26, 39, 59, 3, -8}, {2, 0, 77, 11, 9}, {-8, 22, 44, -6, 7}, {40, 9, 26, 3, 9}, {-7, 20, 101, -7, 4}, {3, -8, 42, 26, 0}, {-15, 33, 68, 2, 23}, {-2, 55, 46, -2, 15}, {3, -1, 21, 16, 41}}; - static final byte[][] silk_LTP_gain_vq_2 = new byte[][]{{-6, 27, 61, 39, 5}, {-11, 42, 88, 4, 1}, {-2, 60, 65, 6, -4}, {-1, -5, 73, 56, 1}, {-9, 19, 94, 29, -9}, {0, 12, 99, 6, 4}, {8, -19, 102, 46, -13}, {3, 2, 13, 3, 2}, {9, -21, 84, 72, -18}, {-11, 46, 104, -22, 8}, {18, 38, 48, 23, 0}, {-16, 70, 83, -21, 11}, {5, -11, 117, 22, -8}, {-6, 23, 117, -12, 3}, {3, -8, 95, 28, 4}, {-10, 15, 77, 60, -15}, {-1, 4, 124, 2, -4}, {3, 38, 84, 24, -25}, {2, 13, 42, 13, 31}, {21, -4, 56, 46, -1}, {-1, 35, 79, -13, 19}, {-7, 65, 88, -9, -14}, {20, 4, 81, 49, -29}, {20, 0, 75, 3, -17}, {5, -9, 44, 92, -8}, {1, -3, 22, 69, 31}, {-6, 95, 41, -12, 5}, {39, 67, 16, -4, 1}, {0, -6, 120, 55, -36}, {-13, 44, 122, 4, -24}, {81, 5, 11, 3, 7}, {2, 0, 9, 10, 88}}; - static final byte[][][] silk_LTP_vq_ptrs_Q7 = new byte[][][]{silk_LTP_gain_vq_0, silk_LTP_gain_vq_1, silk_LTP_gain_vq_2}; - static final short[] silk_LTP_gain_vq_0_gain = new short[]{46, 2, 90, 87, 93, 91, 82, 98}; - static final short[] silk_LTP_gain_vq_1_gain = new short[]{109, 120, 118, 12, 113, 115, 117, 119, 99, 59, 87, 111, 63, 111, 112, 80}; - static final short[] silk_LTP_gain_vq_2_gain = new short[]{126, 124, 125, 124, 129, 121, 126, 23, 132, 127, 127, 127, 126, 127, 122, 133, 130, 134, 101, 118, 119, 145, 126, 86, 124, 120, 123, 119, 170, 173, 107, 109}; - static final short[][] silk_LTP_vq_gain_ptrs_Q7 = new short[][]{silk_LTP_gain_vq_0_gain, silk_LTP_gain_vq_1_gain, silk_LTP_gain_vq_2_gain}; - static final byte[] silk_LTP_vq_sizes = new byte[]{8, 16, 32}; - static final short[] silk_NLSF_CB1_NB_MB_Q8 = new short[]{12, 35, 60, 83, 108, 132, 157, 180, 206, 228, 15, 32, 55, 77, 101, 125, 151, 175, 201, 225, 19, 42, 66, 89, 114, 137, 162, 184, 209, 230, 12, 25, 50, 72, 97, 120, 147, 172, 200, 223, 26, 44, 69, 90, 114, 135, 159, 180, 205, 225, 13, 22, 53, 80, 106, 130, 156, 180, 205, 228, 15, 25, 44, 64, 90, 115, 142, 168, 196, 222, 19, 24, 62, 82, 100, 120, 145, 168, 190, 214, 22, 31, 50, 79, 103, 120, 151, 170, 203, 227, 21, 29, 45, 65, 106, 124, 150, 171, 196, 224, 30, 49, 75, 97, 121, 142, 165, 186, 209, 229, 19, 25, 52, 70, 93, 116, 143, 166, 192, 219, 26, 34, 62, 75, 97, 118, 145, 167, 194, 217, 25, 33, 56, 70, 91, 113, 143, 165, 196, 223, 21, 34, 51, 72, 97, 117, 145, 171, 196, 222, 20, 29, 50, 67, 90, 117, 144, 168, 197, 221, 22, 31, 48, 66, 95, 117, 146, 168, 196, 222, 24, 33, 51, 77, 116, 134, 158, 180, 200, 224, 21, 28, 70, 87, 106, 124, 149, 170, 194, 217, 26, 33, 53, 64, 83, 117, 152, 173, 204, 225, 27, 34, 65, 95, 108, 129, 155, 174, 210, 225, 20, 26, 72, 99, 113, 131, 154, 176, 200, 219, 34, 43, 61, 78, 93, 114, 155, 177, 205, 229, 23, 29, 54, 97, 124, 138, 163, 179, 209, 229, 30, 38, 56, 89, 118, 129, 158, 178, 200, 231, 21, 29, 49, 63, 85, 111, 142, 163, 193, 222, 27, 48, 77, 103, 133, 158, 179, 196, 215, 232, 29, 47, 74, 99, 124, 151, 176, 198, 220, 237, 33, 42, 61, 76, 93, 121, 155, 174, 207, 225, 29, 53, 87, 112, 136, 154, 170, 188, 208, 227, 24, 30, 52, 84, 131, 150, 166, 186, 203, 229, 37, 48, 64, 84, 104, 118, 156, 177, 201, 230}; - static final short[] silk_NLSF_CB1_iCDF_NB_MB = new short[]{212, 178, 148, 129, 108, 96, 85, 82, 79, 77, 61, 59, 57, 56, 51, 49, 48, 45, 42, 41, 40, 38, 36, 34, 31, 30, 21, 12, 10, 3, 1, 0, 255, 245, 244, 236, 233, 225, 217, 203, 190, 176, 175, 161, 149, 136, 125, 114, 102, 91, 81, 71, 60, 52, 43, 35, 28, 20, 19, 18, 12, 11, 5, 0}; - static final short[] silk_NLSF_CB2_SELECT_NB_MB = new short[]{16, 0, 0, 0, 0, 99, 66, 36, 36, 34, 36, 34, 34, 34, 34, 83, 69, 36, 52, 34, 116, 102, 70, 68, 68, 176, 102, 68, 68, 34, 65, 85, 68, 84, 36, 116, 141, 152, 139, 170, 132, 187, 184, 216, 137, 132, 249, 168, 185, 139, 104, 102, 100, 68, 68, 178, 218, 185, 185, 170, 244, 216, 187, 187, 170, 244, 187, 187, 219, 138, 103, 155, 184, 185, 137, 116, 183, 155, 152, 136, 132, 217, 184, 184, 170, 164, 217, 171, 155, 139, 244, 169, 184, 185, 170, 164, 216, 223, 218, 138, 214, 143, 188, 218, 168, 244, 141, 136, 155, 170, 168, 138, 220, 219, 139, 164, 219, 202, 216, 137, 168, 186, 246, 185, 139, 116, 185, 219, 185, 138, 100, 100, 134, 100, 102, 34, 68, 68, 100, 68, 168, 203, 221, 218, 168, 167, 154, 136, 104, 70, 164, 246, 171, 137, 139, 137, 155, 218, 219, 139}; - static final short[] silk_NLSF_CB2_iCDF_NB_MB = new short[]{255, 254, 253, 238, 14, 3, 2, 1, 0, 255, 254, 252, 218, 35, 3, 2, 1, 0, 255, 254, 250, 208, 59, 4, 2, 1, 0, 255, 254, 246, 194, 71, 10, 2, 1, 0, 255, 252, 236, 183, 82, 8, 2, 1, 0, 255, 252, 235, 180, 90, 17, 2, 1, 0, 255, 248, 224, 171, 97, 30, 4, 1, 0, 255, 254, 236, 173, 95, 37, 7, 1, 0}; - static final short[] silk_NLSF_CB2_BITS_NB_MB_Q5 = new short[]{255, 255, 255, 131, 6, 145, 255, 255, 255, 255, 255, 236, 93, 15, 96, 255, 255, 255, 255, 255, 194, 83, 25, 71, 221, 255, 255, 255, 255, 162, 73, 34, 66, 162, 255, 255, 255, 210, 126, 73, 43, 57, 173, 255, 255, 255, 201, 125, 71, 48, 58, 130, 255, 255, 255, 166, 110, 73, 57, 62, 104, 210, 255, 255, 251, 123, 65, 55, 68, 100, 171, 255}; - static final short[] silk_NLSF_PRED_NB_MB_Q8 = new short[]{179, 138, 140, 148, 151, 149, 153, 151, 163, 116, 67, 82, 59, 92, 72, 100, 89, 92}; - static final short[] silk_NLSF_DELTA_MIN_NB_MB_Q15 = new short[]{250, 3, 6, 3, 3, 3, 4, 3, 3, 3, 461}; - static final NLSFCodebook silk_NLSF_CB_NB_MB = new NLSFCodebook(); - static final short[] silk_NLSF_CB1_WB_Q8; - static final short[] silk_NLSF_CB1_iCDF_WB; - static final short[] silk_NLSF_CB2_SELECT_WB; - static final short[] silk_NLSF_CB2_iCDF_WB; - static final short[] silk_NLSF_CB2_BITS_WB_Q5; - static final short[] silk_NLSF_PRED_WB_Q8; - static final short[] silk_NLSF_DELTA_MIN_WB_Q15; - static final NLSFCodebook silk_NLSF_CB_WB; - static final int[] silk_TargetRate_table_NB; - static final int[] silk_TargetRate_table_MB; - static final int[] silk_TargetRate_table_WB; - static final short[] silk_SNR_table_Q1; - static final short[] silk_stereo_pred_quant_Q13; - static final short[] silk_stereo_pred_joint_iCDF; - static final short[] silk_stereo_only_code_mid_iCDF; - static final short[] silk_LBRR_flags_2_iCDF; - static final short[] silk_LBRR_flags_3_iCDF; - static final short[][] silk_LBRR_flags_iCDF_ptr; - static final short[] silk_lsb_iCDF; - static final short[] silk_LTPscale_iCDF; - static final short[] silk_type_offset_VAD_iCDF; - static final short[] silk_type_offset_no_VAD_iCDF; - static final short[] silk_NLSF_interpolation_factor_iCDF; - static final short[][] silk_Quantization_Offsets_Q10; - static final short[] silk_LTPScales_table_Q14; - static final short[] silk_uniform3_iCDF; - static final short[] silk_uniform4_iCDF; - static final short[] silk_uniform5_iCDF; - static final short[] silk_uniform6_iCDF; - static final short[] silk_uniform8_iCDF; - static final short[] silk_NLSF_EXT_iCDF; - static final int[][] silk_Transition_LP_B_Q28; - static final int[][] silk_Transition_LP_A_Q28; - static final short[] silk_pitch_lag_iCDF; - static final short[] silk_pitch_delta_iCDF; - static final short[] silk_pitch_contour_iCDF; - static final short[] silk_pitch_contour_NB_iCDF; - static final short[] silk_pitch_contour_10_ms_iCDF; - static final short[] silk_pitch_contour_10_ms_NB_iCDF; - static final byte[] silk_max_pulses_table; - static final short[][] silk_pulses_per_block_iCDF; - static final short[][] silk_pulses_per_block_BITS_Q5; - static final short[][] silk_rate_levels_iCDF; - static final short[][] silk_rate_levels_BITS_Q5; - static final short[] silk_shell_code_table0; - static final short[] silk_shell_code_table1; - static final short[] silk_shell_code_table2; - static final short[] silk_shell_code_table3; - static final short[] silk_shell_code_table_offsets; - static final short[] silk_sign_iCDF; - static final byte[][] delay_matrix_enc; - static final byte[][] delay_matrix_dec; - static final short[] silk_Resampler_3_4_COEFS; - static final short[] silk_Resampler_2_3_COEFS; - static final short[] silk_Resampler_1_2_COEFS; - static final short[] silk_Resampler_1_3_COEFS; - static final short[] silk_Resampler_1_4_COEFS; - static final short[] silk_Resampler_1_6_COEFS; - static final short[] silk_Resampler_2_3_COEFS_LQ; - static final short[][] silk_resampler_frac_FIR_12; - public static final short silk_resampler_down2_0 = 9872; - public static final short silk_resampler_down2_1 = -25727; - static final short[] silk_resampler_up2_hq_0; - static final short[] silk_resampler_up2_hq_1; - static final byte[][] silk_CB_lags_stage2_10_ms; - static final byte[][] silk_CB_lags_stage3_10_ms; - static final byte[][] silk_CB_lags_stage2; - static final byte[][] silk_CB_lags_stage3; - static final byte[][] silk_Lag_range_stage3_10_ms; - static final byte[][][] silk_Lag_range_stage3; - static final byte[] silk_nb_cbk_searchs_stage3; - - SilkTables() { - } - - /* - * Opcode count of 17815 triggered aggressive code reduction. Override with --aggressivesizethreshold. - */ - static { - SilkTables.silk_NLSF_CB_NB_MB.nVectors = (short)32; - SilkTables.silk_NLSF_CB_NB_MB.order = (short)10; - SilkTables.silk_NLSF_CB_NB_MB.quantStepSize_Q16 = (short)11796; - SilkTables.silk_NLSF_CB_NB_MB.invQuantStepSize_Q6 = (short)356; - SilkTables.silk_NLSF_CB_NB_MB.CB1_NLSF_Q8 = silk_NLSF_CB1_NB_MB_Q8; - SilkTables.silk_NLSF_CB_NB_MB.CB1_iCDF = silk_NLSF_CB1_iCDF_NB_MB; - SilkTables.silk_NLSF_CB_NB_MB.pred_Q8 = silk_NLSF_PRED_NB_MB_Q8; - SilkTables.silk_NLSF_CB_NB_MB.ec_sel = silk_NLSF_CB2_SELECT_NB_MB; - SilkTables.silk_NLSF_CB_NB_MB.ec_iCDF = silk_NLSF_CB2_iCDF_NB_MB; - SilkTables.silk_NLSF_CB_NB_MB.ec_Rates_Q5 = silk_NLSF_CB2_BITS_NB_MB_Q5; - SilkTables.silk_NLSF_CB_NB_MB.deltaMin_Q15 = silk_NLSF_DELTA_MIN_NB_MB_Q15; - silk_NLSF_CB1_WB_Q8 = new short[]{7, 23, 38, 54, 69, 85, 100, 116, 131, 147, 162, 178, 193, 208, 223, 239, 13, 25, 41, 55, 69, 83, 98, 112, 127, 142, 157, 171, 187, 203, 220, 236, 15, 21, 34, 51, 61, 78, 92, 106, 126, 136, 152, 167, 185, 205, 225, 240, 10, 21, 36, 50, 63, 79, 95, 110, 126, 141, 157, 173, 189, 205, 221, 237, 17, 20, 37, 51, 59, 78, 89, 107, 123, 134, 150, 164, 184, 205, 224, 240, 10, 15, 32, 51, 67, 81, 96, 112, 129, 142, 158, 173, 189, 204, 220, 236, 8, 21, 37, 51, 65, 79, 98, 113, 126, 138, 155, 168, 179, 192, 209, 218, 12, 15, 34, 55, 63, 78, 87, 108, 118, 131, 148, 167, 185, 203, 219, 236, 16, 19, 32, 36, 56, 79, 91, 108, 118, 136, 154, 171, 186, 204, 220, 237, 11, 28, 43, 58, 74, 89, 105, 120, 135, 150, 165, 180, 196, 211, 226, 241, 6, 16, 33, 46, 60, 75, 92, 107, 123, 137, 156, 169, 185, 199, 214, 225, 11, 19, 30, 44, 57, 74, 89, 105, 121, 135, 152, 169, 186, 202, 218, 234, 12, 19, 29, 46, 57, 71, 88, 100, 120, 132, 148, 165, 182, 199, 216, 233, 17, 23, 35, 46, 56, 77, 92, 106, 123, 134, 152, 167, 185, 204, 222, 237, 14, 17, 45, 53, 63, 75, 89, 107, 115, 132, 151, 171, 188, 206, 221, 240, 9, 16, 29, 40, 56, 71, 88, 103, 119, 137, 154, 171, 189, 205, 222, 237, 16, 19, 36, 48, 57, 76, 87, 105, 118, 132, 150, 167, 185, 202, 218, 236, 12, 17, 29, 54, 71, 81, 94, 104, 126, 136, 149, 164, 182, 201, 221, 237, 15, 28, 47, 62, 79, 97, 115, 129, 142, 155, 168, 180, 194, 208, 223, 238, 8, 14, 30, 45, 62, 78, 94, 111, 127, 143, 159, 175, 192, 207, 223, 239, 17, 30, 49, 62, 79, 92, 107, 119, 132, 145, 160, 174, 190, 204, 220, 235, 14, 19, 36, 45, 61, 76, 91, 108, 121, 138, 154, 172, 189, 205, 222, 238, 12, 18, 31, 45, 60, 76, 91, 107, 123, 138, 154, 171, 187, 204, 221, 236, 13, 17, 31, 43, 53, 70, 83, 103, 114, 131, 149, 167, 185, 203, 220, 237, 17, 22, 35, 42, 58, 78, 93, 110, 125, 139, 155, 170, 188, 206, 224, 240, 8, 15, 34, 50, 67, 83, 99, 115, 131, 146, 162, 178, 193, 209, 224, 239, 13, 16, 41, 66, 73, 86, 95, 111, 128, 137, 150, 163, 183, 206, 225, 241, 17, 25, 37, 52, 63, 75, 92, 102, 119, 132, 144, 160, 175, 191, 212, 231, 19, 31, 49, 65, 83, 100, 117, 133, 147, 161, 174, 187, 200, 213, 227, 242, 18, 31, 52, 68, 88, 103, 117, 126, 138, 149, 163, 177, 192, 207, 223, 239, 16, 29, 47, 61, 76, 90, 106, 119, 133, 147, 161, 176, 193, 209, 224, 240, 15, 21, 35, 50, 61, 73, 86, 97, 110, 119, 129, 141, 175, 198, 218, 237}; - silk_NLSF_CB1_iCDF_WB = new short[]{225, 204, 201, 184, 183, 175, 158, 154, 153, 135, 119, 115, 113, 110, 109, 99, 98, 95, 79, 68, 52, 50, 48, 45, 43, 32, 31, 27, 18, 10, 3, 0, 255, 251, 235, 230, 212, 201, 196, 182, 167, 166, 163, 151, 138, 124, 110, 104, 90, 78, 76, 70, 69, 57, 45, 34, 24, 21, 11, 6, 5, 4, 3, 0}; - silk_NLSF_CB2_SELECT_WB = new short[]{0, 0, 0, 0, 0, 0, 0, 1, 100, 102, 102, 68, 68, 36, 34, 96, 164, 107, 158, 185, 180, 185, 139, 102, 64, 66, 36, 34, 34, 0, 1, 32, 208, 139, 141, 191, 152, 185, 155, 104, 96, 171, 104, 166, 102, 102, 102, 132, 1, 0, 0, 0, 0, 16, 16, 0, 80, 109, 78, 107, 185, 139, 103, 101, 208, 212, 141, 139, 173, 153, 123, 103, 36, 0, 0, 0, 0, 0, 0, 1, 48, 0, 0, 0, 0, 0, 0, 32, 68, 135, 123, 119, 119, 103, 69, 98, 68, 103, 120, 118, 118, 102, 71, 98, 134, 136, 157, 184, 182, 153, 139, 134, 208, 168, 248, 75, 189, 143, 121, 107, 32, 49, 34, 34, 34, 0, 17, 2, 210, 235, 139, 123, 185, 137, 105, 134, 98, 135, 104, 182, 100, 183, 171, 134, 100, 70, 68, 70, 66, 66, 34, 131, 64, 166, 102, 68, 36, 2, 1, 0, 134, 166, 102, 68, 34, 34, 66, 132, 212, 246, 158, 139, 107, 107, 87, 102, 100, 219, 125, 122, 137, 118, 103, 132, 114, 135, 137, 105, 171, 106, 50, 34, 164, 214, 141, 143, 185, 151, 121, 103, 192, 34, 0, 0, 0, 0, 0, 1, 208, 109, 74, 187, 134, 249, 159, 137, 102, 110, 154, 118, 87, 101, 119, 101, 0, 2, 0, 36, 36, 66, 68, 35, 96, 164, 102, 100, 36, 0, 2, 33, 167, 138, 174, 102, 100, 84, 2, 2, 100, 107, 120, 119, 36, 197, 24, 0}; - silk_NLSF_CB2_iCDF_WB = new short[]{255, 254, 253, 244, 12, 3, 2, 1, 0, 255, 254, 252, 224, 38, 3, 2, 1, 0, 255, 254, 251, 209, 57, 4, 2, 1, 0, 255, 254, 244, 195, 69, 4, 2, 1, 0, 255, 251, 232, 184, 84, 7, 2, 1, 0, 255, 254, 240, 186, 86, 14, 2, 1, 0, 255, 254, 239, 178, 91, 30, 5, 1, 0, 255, 248, 227, 177, 100, 19, 2, 1, 0}; - silk_NLSF_CB2_BITS_WB_Q5 = new short[]{255, 255, 255, 156, 4, 154, 255, 255, 255, 255, 255, 227, 102, 15, 92, 255, 255, 255, 255, 255, 213, 83, 24, 72, 236, 255, 255, 255, 255, 150, 76, 33, 63, 214, 255, 255, 255, 190, 121, 77, 43, 55, 185, 255, 255, 255, 245, 137, 71, 43, 59, 139, 255, 255, 255, 255, 131, 66, 50, 66, 107, 194, 255, 255, 166, 116, 76, 55, 53, 125, 255, 255}; - silk_NLSF_PRED_WB_Q8 = new short[]{175, 148, 160, 176, 178, 173, 174, 164, 177, 174, 196, 182, 198, 192, 182, 68, 62, 66, 60, 72, 117, 85, 90, 118, 136, 151, 142, 160, 142, 155}; - silk_NLSF_DELTA_MIN_WB_Q15 = new short[]{100, 3, 40, 3, 3, 3, 5, 14, 14, 10, 11, 3, 8, 9, 7, 3, 347}; - silk_NLSF_CB_WB = new NLSFCodebook(); - SilkTables.silk_NLSF_CB_WB.nVectors = (short)32; - SilkTables.silk_NLSF_CB_WB.order = (short)16; - SilkTables.silk_NLSF_CB_WB.quantStepSize_Q16 = (short)9830; - SilkTables.silk_NLSF_CB_WB.invQuantStepSize_Q6 = (short)427; - SilkTables.silk_NLSF_CB_WB.CB1_NLSF_Q8 = silk_NLSF_CB1_WB_Q8; - SilkTables.silk_NLSF_CB_WB.CB1_iCDF = silk_NLSF_CB1_iCDF_WB; - SilkTables.silk_NLSF_CB_WB.pred_Q8 = silk_NLSF_PRED_WB_Q8; - SilkTables.silk_NLSF_CB_WB.ec_sel = silk_NLSF_CB2_SELECT_WB; - SilkTables.silk_NLSF_CB_WB.ec_iCDF = silk_NLSF_CB2_iCDF_WB; - SilkTables.silk_NLSF_CB_WB.ec_Rates_Q5 = silk_NLSF_CB2_BITS_WB_Q5; - SilkTables.silk_NLSF_CB_WB.deltaMin_Q15 = silk_NLSF_DELTA_MIN_WB_Q15; - silk_TargetRate_table_NB = new int[]{0, 8000, 9400, 11500, 13500, 17500, 25000, 80000}; - silk_TargetRate_table_MB = new int[]{0, 9000, 12000, 14500, 18500, 24500, 35500, 80000}; - silk_TargetRate_table_WB = new int[]{0, 10500, 14000, 17000, 21500, 28500, 42000, 80000}; - silk_SNR_table_Q1 = new short[]{18, 29, 38, 40, 46, 52, 62, 84}; - silk_stereo_pred_quant_Q13 = new short[]{-13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732}; - silk_stereo_pred_joint_iCDF = new short[]{249, 247, 246, 245, 244, 234, 210, 202, 201, 200, 197, 174, 82, 59, 56, 55, 54, 46, 22, 12, 11, 10, 9, 7, 0}; - silk_stereo_only_code_mid_iCDF = new short[]{64, 0}; - silk_LBRR_flags_2_iCDF = new short[]{203, 150, 0}; - silk_LBRR_flags_3_iCDF = new short[]{215, 195, 166, 125, 110, 82, 0}; - silk_LBRR_flags_iCDF_ptr = new short[][]{silk_LBRR_flags_2_iCDF, silk_LBRR_flags_3_iCDF}; - silk_lsb_iCDF = new short[]{120, 0}; - silk_LTPscale_iCDF = new short[]{128, 64, 0}; - silk_type_offset_VAD_iCDF = new short[]{232, 158, 10, 0}; - silk_type_offset_no_VAD_iCDF = new short[]{230, 0}; - silk_NLSF_interpolation_factor_iCDF = new short[]{243, 221, 192, 181, 0}; - silk_Quantization_Offsets_Q10 = new short[][]{{100, 240}, {32, 100}}; - silk_LTPScales_table_Q14 = new short[]{15565, 12288, 8192}; - silk_uniform3_iCDF = new short[]{171, 85, 0}; - silk_uniform4_iCDF = new short[]{192, 128, 64, 0}; - silk_uniform5_iCDF = new short[]{205, 154, 102, 51, 0}; - silk_uniform6_iCDF = new short[]{213, 171, 128, 85, 43, 0}; - silk_uniform8_iCDF = new short[]{224, 192, 160, 128, 96, 64, 32, 0}; - silk_NLSF_EXT_iCDF = new short[]{100, 40, 16, 7, 3, 1, 0}; - silk_Transition_LP_B_Q28 = new int[][]{{250767114, 501534038, 250767114}, {209867381, 419732057, 209867381}, {170987846, 341967853, 170987846}, {131531482, 263046905, 131531482}, {89306658, 178584282, 89306658}}; - silk_Transition_LP_A_Q28 = new int[][]{{506393414, 239854379}, {411067935, 169683996}, {306733530, 116694253}, {185807084, 77959395}, {35497197, 57401098}}; - silk_pitch_lag_iCDF = new short[]{253, 250, 244, 233, 212, 182, 150, 131, 120, 110, 98, 85, 72, 60, 49, 40, 32, 25, 19, 15, 13, 11, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; - silk_pitch_delta_iCDF = new short[]{210, 208, 206, 203, 199, 193, 183, 168, 142, 104, 74, 52, 37, 27, 20, 14, 10, 6, 4, 2, 0}; - silk_pitch_contour_iCDF = new short[]{223, 201, 183, 167, 152, 138, 124, 111, 98, 88, 79, 70, 62, 56, 50, 44, 39, 35, 31, 27, 24, 21, 18, 16, 14, 12, 10, 8, 6, 4, 3, 2, 1, 0}; - silk_pitch_contour_NB_iCDF = new short[]{188, 176, 155, 138, 119, 97, 67, 43, 26, 10, 0}; - silk_pitch_contour_10_ms_iCDF = new short[]{165, 119, 80, 61, 47, 35, 27, 20, 14, 9, 4, 0}; - silk_pitch_contour_10_ms_NB_iCDF = new short[]{113, 63, 0}; - silk_max_pulses_table = new byte[]{8, 10, 12, 16}; - silk_pulses_per_block_iCDF = new short[][]{{125, 51, 26, 18, 15, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, {198, 105, 45, 22, 15, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, {213, 162, 116, 83, 59, 43, 32, 24, 18, 15, 12, 9, 7, 6, 5, 3, 2, 0}, {239, 187, 116, 59, 28, 16, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, {250, 229, 188, 135, 86, 51, 30, 19, 13, 10, 8, 6, 5, 4, 3, 2, 1, 0}, {249, 235, 213, 185, 156, 128, 103, 83, 66, 53, 42, 33, 26, 21, 17, 13, 10, 0}, {254, 249, 235, 206, 164, 118, 77, 46, 27, 16, 10, 7, 5, 4, 3, 2, 1, 0}, {255, 253, 249, 239, 220, 191, 156, 119, 85, 57, 37, 23, 15, 10, 6, 4, 2, 0}, {255, 253, 251, 246, 237, 223, 203, 179, 152, 124, 98, 75, 55, 40, 29, 21, 15, 0}, {255, 254, 253, 247, 220, 162, 106, 67, 42, 28, 18, 12, 9, 6, 4, 3, 2, 0}}; - silk_pulses_per_block_BITS_Q5 = new short[][]{{31, 57, 107, 160, 205, 205, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, {69, 47, 67, 111, 166, 205, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, {82, 74, 79, 95, 109, 128, 145, 160, 173, 205, 205, 205, 224, 255, 255, 224, 255, 224}, {125, 74, 59, 69, 97, 141, 182, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, {173, 115, 85, 73, 76, 92, 115, 145, 173, 205, 224, 224, 255, 255, 255, 255, 255, 255}, {166, 134, 113, 102, 101, 102, 107, 118, 125, 138, 145, 155, 166, 182, 192, 192, 205, 150}, {224, 182, 134, 101, 83, 79, 85, 97, 120, 145, 173, 205, 224, 255, 255, 255, 255, 255}, {255, 224, 192, 150, 120, 101, 92, 89, 93, 102, 118, 134, 160, 182, 192, 224, 224, 224}, {255, 224, 224, 182, 155, 134, 118, 109, 104, 102, 106, 111, 118, 131, 145, 160, 173, 131}}; - silk_rate_levels_iCDF = new short[][]{{241, 190, 178, 132, 87, 74, 41, 14, 0}, {223, 193, 157, 140, 106, 57, 39, 18, 0}}; - silk_rate_levels_BITS_Q5 = new short[][]{{131, 74, 141, 79, 80, 138, 95, 104, 134}, {95, 99, 91, 125, 93, 76, 123, 115, 123}}; - silk_shell_code_table0 = new short[]{128, 0, 214, 42, 0, 235, 128, 21, 0, 244, 184, 72, 11, 0, 248, 214, 128, 42, 7, 0, 248, 225, 170, 80, 25, 5, 0, 251, 236, 198, 126, 54, 18, 3, 0, 250, 238, 211, 159, 82, 35, 15, 5, 0, 250, 231, 203, 168, 128, 88, 53, 25, 6, 0, 252, 238, 216, 185, 148, 108, 71, 40, 18, 4, 0, 253, 243, 225, 199, 166, 128, 90, 57, 31, 13, 3, 0, 254, 246, 233, 212, 183, 147, 109, 73, 44, 23, 10, 2, 0, 255, 250, 240, 223, 198, 166, 128, 90, 58, 33, 16, 6, 1, 0, 255, 251, 244, 231, 210, 181, 146, 110, 75, 46, 25, 12, 5, 1, 0, 255, 253, 248, 238, 221, 196, 164, 128, 92, 60, 35, 18, 8, 3, 1, 0, 255, 253, 249, 242, 229, 208, 180, 146, 110, 76, 48, 27, 14, 7, 3, 1, 0}; - silk_shell_code_table1 = new short[]{129, 0, 207, 50, 0, 236, 129, 20, 0, 245, 185, 72, 10, 0, 249, 213, 129, 42, 6, 0, 250, 226, 169, 87, 27, 4, 0, 251, 233, 194, 130, 62, 20, 4, 0, 250, 236, 207, 160, 99, 47, 17, 3, 0, 255, 240, 217, 182, 131, 81, 41, 11, 1, 0, 255, 254, 233, 201, 159, 107, 61, 20, 2, 1, 0, 255, 249, 233, 206, 170, 128, 86, 50, 23, 7, 1, 0, 255, 250, 238, 217, 186, 148, 108, 70, 39, 18, 6, 1, 0, 255, 252, 243, 226, 200, 166, 128, 90, 56, 30, 13, 4, 1, 0, 255, 252, 245, 231, 209, 180, 146, 110, 76, 47, 25, 11, 4, 1, 0, 255, 253, 248, 237, 219, 194, 163, 128, 93, 62, 37, 19, 8, 3, 1, 0, 255, 254, 250, 241, 226, 205, 177, 145, 111, 79, 51, 30, 15, 6, 2, 1, 0}; - silk_shell_code_table2 = new short[]{129, 0, 203, 54, 0, 234, 129, 23, 0, 245, 184, 73, 10, 0, 250, 215, 129, 41, 5, 0, 252, 232, 173, 86, 24, 3, 0, 253, 240, 200, 129, 56, 15, 2, 0, 253, 244, 217, 164, 94, 38, 10, 1, 0, 253, 245, 226, 189, 132, 71, 27, 7, 1, 0, 253, 246, 231, 203, 159, 105, 56, 23, 6, 1, 0, 255, 248, 235, 213, 179, 133, 85, 47, 19, 5, 1, 0, 255, 254, 243, 221, 194, 159, 117, 70, 37, 12, 2, 1, 0, 255, 254, 248, 234, 208, 171, 128, 85, 48, 22, 8, 2, 1, 0, 255, 254, 250, 240, 220, 189, 149, 107, 67, 36, 16, 6, 2, 1, 0, 255, 254, 251, 243, 227, 201, 166, 128, 90, 55, 29, 13, 5, 2, 1, 0, 255, 254, 252, 246, 234, 213, 183, 147, 109, 73, 43, 22, 10, 4, 2, 1, 0}; - silk_shell_code_table3 = new short[]{130, 0, 200, 58, 0, 231, 130, 26, 0, 244, 184, 76, 12, 0, 249, 214, 130, 43, 6, 0, 252, 232, 173, 87, 24, 3, 0, 253, 241, 203, 131, 56, 14, 2, 0, 254, 246, 221, 167, 94, 35, 8, 1, 0, 254, 249, 232, 193, 130, 65, 23, 5, 1, 0, 255, 251, 239, 211, 162, 99, 45, 15, 4, 1, 0, 255, 251, 243, 223, 186, 131, 74, 33, 11, 3, 1, 0, 255, 252, 245, 230, 202, 158, 105, 57, 24, 8, 2, 1, 0, 255, 253, 247, 235, 214, 179, 132, 84, 44, 19, 7, 2, 1, 0, 255, 254, 250, 240, 223, 196, 159, 112, 69, 36, 15, 6, 2, 1, 0, 255, 254, 253, 245, 231, 209, 176, 136, 93, 55, 27, 11, 3, 2, 1, 0, 255, 254, 253, 252, 239, 221, 194, 158, 117, 76, 42, 18, 4, 3, 2, 1, 0}; - silk_shell_code_table_offsets = new short[]{0, 0, 2, 5, 9, 14, 20, 27, 35, 44, 54, 65, 77, 90, 104, 119, 135}; - silk_sign_iCDF = new short[]{254, 49, 67, 77, 82, 93, 99, 198, 11, 18, 24, 31, 36, 45, 255, 46, 66, 78, 87, 94, 104, 208, 14, 21, 32, 42, 51, 66, 255, 94, 104, 109, 112, 115, 118, 248, 53, 69, 80, 88, 95, 102}; - delay_matrix_enc = new byte[][]{{6, 0, 3}, {0, 7, 3}, {0, 1, 10}, {0, 2, 6}, {18, 10, 12}}; - delay_matrix_dec = new byte[][]{{4, 0, 2, 0, 0}, {0, 9, 4, 7, 4}, {0, 3, 12, 7, 7}}; - silk_Resampler_3_4_COEFS = new short[]{-20694, -13867, -49, 64, 17, -157, 353, -496, 163, 11047, 22205, -39, 6, 91, -170, 186, 23, -896, 6336, 19928, -19, -36, 102, -89, -24, 328, -951, 2568, 15909}; - silk_Resampler_2_3_COEFS = new short[]{-14457, -14019, 64, 128, -122, 36, 310, -768, 584, 9267, 17733, 12, 128, 18, -142, 288, -117, -865, 4123, 14459}; - silk_Resampler_1_2_COEFS = new short[]{616, -14323, -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024}; - silk_Resampler_1_3_COEFS = new short[]{16102, -15162, -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271}; - silk_Resampler_1_4_COEFS = new short[]{22500, -15099, 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464}; - silk_Resampler_1_6_COEFS = new short[]{27540, -15257, 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455}; - silk_Resampler_2_3_COEFS_LQ = new short[]{-2797, -6507, 4697, 10739, 1567, 8276}; - silk_resampler_frac_FIR_12 = new short[][]{{189, -600, 617, 30567}, {117, -159, -1070, 29704}, {52, 221, -2392, 28276}, {-4, 529, -3350, 26341}, {-48, 758, -3956, 23973}, {-80, 905, -4235, 21254}, {-99, 972, -4222, 18278}, {-107, 967, -3957, 15143}, {-103, 896, -3487, 11950}, {-91, 773, -2865, 8798}, {-71, 611, -2143, 5784}, {-46, 425, -1375, 2996}}; - silk_resampler_up2_hq_0 = new short[]{1746, 14986, -26453}; - silk_resampler_up2_hq_1 = new short[]{6854, 25769, -9994}; - silk_CB_lags_stage2_10_ms = new byte[][]{{0, 1, 0}, {0, 0, 1}}; - silk_CB_lags_stage3_10_ms = new byte[][]{{0, 0, 1, -1, 1, -1, 2, -2, 2, -2, 3, -3}, {0, 1, 0, 1, -1, 2, -1, 2, -2, 3, -2, 3}}; - silk_CB_lags_stage2 = new byte[][]{{0, 2, -1, -1, -1, 0, 0, 1, 1, 0, 1}, {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0}, {0, -1, 2, 1, 0, 1, 1, 0, 0, -1, -1}}; - silk_CB_lags_stage3 = new byte[][]{{0, 0, 1, -1, 0, 1, -1, 0, -1, 1, -2, 2, -2, -2, 2, -3, 2, 3, -3, -4, 3, -4, 4, 4, -5, 5, -6, -5, 6, -7, 6, 5, 8, -9}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 1, -1, 0, 1, -1, -1, 1, -1, 2, 1, -1, 2, -2, -2, 2, -2, 2, 2, 3, -3}, {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, -1, 1, 0, 0, 2, 1, -1, 2, -1, -1, 2, -1, 2, 2, -1, 3, -2, -2, -2, 3}, {0, 1, 0, 0, 1, 0, 1, -1, 2, -1, 2, -1, 2, 3, -2, 3, -2, -2, 4, 4, -3, 5, -3, -4, 6, -4, 6, 5, -5, 8, -6, -5, -7, 9}}; - silk_Lag_range_stage3_10_ms = new byte[][]{{-3, 7}, {-2, 7}}; - silk_Lag_range_stage3 = new byte[][][]{new byte[][]{{-5, 8}, {-1, 6}, {-1, 6}, {-4, 10}}, new byte[][]{{-6, 10}, {-2, 6}, {-1, 6}, {-5, 10}}, new byte[][]{{-9, 12}, {-3, 7}, {-2, 7}, {-7, 13}}}; - silk_nb_cbk_searchs_stage3 = new byte[]{16, 24, 34}; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkVADState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SilkVADState.java deleted file mode 100644 index fe6a773..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SilkVADState.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class SilkVADState { - final int[] AnaState = new int[2]; - final int[] AnaState1 = new int[2]; - final int[] AnaState2 = new int[2]; - final int[] XnrgSubfr = new int[4]; - final int[] NrgRatioSmth_Q8 = new int[4]; - short HPstate = 0; - final int[] NL = new int[4]; - final int[] inv_NL = new int[4]; - final int[] NoiseLevelBias = new int[4]; - int counter = 0; - - SilkVADState() { - } - - void Reset() { - Arrays.MemSet(this.AnaState, 0, 2); - Arrays.MemSet(this.AnaState1, 0, 2); - Arrays.MemSet(this.AnaState2, 0, 2); - Arrays.MemSet(this.XnrgSubfr, 0, 4); - Arrays.MemSet(this.NrgRatioSmth_Q8, 0, 4); - this.HPstate = 0; - Arrays.MemSet(this.NL, 0, 4); - Arrays.MemSet(this.inv_NL, 0, 4); - Arrays.MemSet(this.NoiseLevelBias, 0, 4); - this.counter = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Sort.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Sort.java deleted file mode 100644 index 6c0de8a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Sort.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Inlines; - -class Sort { - Sort() { - } - - static void silk_insertion_sort_increasing(int[] a, int[] idx, int L, int K) { - int j; - int value; - int i; - Inlines.OpusAssert(K > 0); - Inlines.OpusAssert(L > 0); - Inlines.OpusAssert(L >= K); - for (i = 0; i < K; ++i) { - idx[i] = i; - } - i = 1; - while (i < K) { - value = a[i]; - for (j = i - 1; j >= 0 && value < a[j]; --j) { - a[j + 1] = a[j]; - idx[j + 1] = idx[j]; - } - a[j + 1] = value; - idx[j + 1] = i++; - } - for (i = K; i < L; ++i) { - value = a[i]; - if (value >= a[K - 1]) continue; - for (j = K - 2; j >= 0 && value < a[j]; --j) { - a[j + 1] = a[j]; - idx[j + 1] = idx[j]; - } - a[j + 1] = value; - idx[j + 1] = i; - } - } - - static void silk_insertion_sort_increasing_all_values_int16(short[] a, int L) { - Inlines.OpusAssert(L > 0); - for (int i = 1; i < L; ++i) { - short value = a[i]; - for (int j = i - 1; j >= 0 && value < a[j]; --j) { - a[j + 1] = a[j]; - } - a[j + 1] = value; - } - } - - static void silk_insertion_sort_decreasing_int16(short[] a, int[] idx, int L, int K) { - int j; - short value; - int i; - Inlines.OpusAssert(K > 0); - Inlines.OpusAssert(L > 0); - Inlines.OpusAssert(L >= K); - for (i = 0; i < K; ++i) { - idx[i] = i; - } - i = 1; - while (i < K) { - value = a[i]; - for (j = i - 1; j >= 0 && value > a[j]; --j) { - a[j + 1] = a[j]; - idx[j + 1] = idx[j]; - } - a[j + 1] = value; - idx[j + 1] = i++; - } - for (i = K; i < L; ++i) { - value = a[i]; - if (value <= a[K - 1]) continue; - for (j = K - 2; j >= 0 && value > a[j]; --j) { - a[j + 1] = a[j]; - idx[j + 1] = idx[j]; - } - a[j + 1] = value; - idx[j + 1] = i; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Spread.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Spread.java deleted file mode 100644 index c1ea5e2..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Spread.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class Spread { - public static final int SPREAD_NONE = 0; - public static final int SPREAD_LIGHT = 1; - public static final int SPREAD_NORMAL = 2; - public static final int SPREAD_AGGRESSIVE = 3; - - Spread() { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/Stereo.java b/source/decompiled/de/maxhenkel/voicechat/concentus/Stereo.java deleted file mode 100644 index 7dc0203..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/Stereo.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.SilkTables; -import de.maxhenkel.voicechat.concentus.StereoDecodeState; -import de.maxhenkel.voicechat.concentus.StereoEncodeState; -import de.maxhenkel.voicechat.concentus.SumSqrShift; - -class Stereo { - Stereo() { - } - - static void silk_stereo_decode_pred(EntropyCoder psRangeDec, int[] pred_Q13) { - int[][] ix = Arrays.InitTwoDimensionalArrayInt(2, 3); - int n = psRangeDec.dec_icdf(SilkTables.silk_stereo_pred_joint_iCDF, 8); - ix[0][2] = Inlines.silk_DIV32_16(n, 5); - ix[1][2] = n - 5 * ix[0][2]; - for (n = 0; n < 2; ++n) { - ix[n][0] = psRangeDec.dec_icdf(SilkTables.silk_uniform3_iCDF, 8); - ix[n][1] = psRangeDec.dec_icdf(SilkTables.silk_uniform5_iCDF, 8); - } - for (n = 0; n < 2; ++n) { - int[] nArray = ix[n]; - nArray[0] = nArray[0] + 3 * ix[n][2]; - short low_Q13 = SilkTables.silk_stereo_pred_quant_Q13[ix[n][0]]; - int step_Q13 = Inlines.silk_SMULWB(SilkTables.silk_stereo_pred_quant_Q13[ix[n][0] + 1] - low_Q13, 6554); - pred_Q13[n] = Inlines.silk_SMLABB(low_Q13, step_Q13, 2 * ix[n][1] + 1); - } - pred_Q13[0] = pred_Q13[0] - pred_Q13[1]; - } - - static void silk_stereo_decode_mid_only(EntropyCoder psRangeDec, BoxedValueInt decode_only_mid) { - decode_only_mid.Val = psRangeDec.dec_icdf(SilkTables.silk_stereo_only_code_mid_iCDF, 8); - } - - static void silk_stereo_encode_pred(EntropyCoder psRangeEnc, byte[][] ix) { - int n = 5 * ix[0][2] + ix[1][2]; - Inlines.OpusAssert(n < 25); - psRangeEnc.enc_icdf(n, SilkTables.silk_stereo_pred_joint_iCDF, 8); - for (n = 0; n < 2; ++n) { - Inlines.OpusAssert(ix[n][0] < 3); - Inlines.OpusAssert(ix[n][1] < 5); - psRangeEnc.enc_icdf(ix[n][0], SilkTables.silk_uniform3_iCDF, 8); - psRangeEnc.enc_icdf(ix[n][1], SilkTables.silk_uniform5_iCDF, 8); - } - } - - static void silk_stereo_encode_mid_only(EntropyCoder psRangeEnc, byte mid_only_flag) { - psRangeEnc.enc_icdf(mid_only_flag, SilkTables.silk_stereo_only_code_mid_iCDF, 8); - } - - static int silk_stereo_find_predictor(BoxedValueInt ratio_Q14, short[] x, short[] y, int[] mid_res_amp_Q0, int mid_res_amp_Q0_ptr, int length, int smooth_coef_Q16) { - BoxedValueInt nrgx = new BoxedValueInt(0); - BoxedValueInt nrgy = new BoxedValueInt(0); - BoxedValueInt scale1 = new BoxedValueInt(0); - BoxedValueInt scale2 = new BoxedValueInt(0); - SumSqrShift.silk_sum_sqr_shift(nrgx, scale1, x, length); - SumSqrShift.silk_sum_sqr_shift(nrgy, scale2, y, length); - int scale = Inlines.silk_max_int(scale1.Val, scale2.Val); - scale += scale & 1; - nrgy.Val = Inlines.silk_RSHIFT32(nrgy.Val, scale - scale2.Val); - nrgx.Val = Inlines.silk_RSHIFT32(nrgx.Val, scale - scale1.Val); - nrgx.Val = Inlines.silk_max_int(nrgx.Val, 1); - int corr = Inlines.silk_inner_prod_aligned_scale(x, y, scale, length); - int pred_Q13 = Inlines.silk_DIV32_varQ(corr, nrgx.Val, 13); - pred_Q13 = Inlines.silk_LIMIT(pred_Q13, -16384, 16384); - int pred2_Q10 = Inlines.silk_SMULWB(pred_Q13, pred_Q13); - smooth_coef_Q16 = Inlines.silk_max_int(smooth_coef_Q16, Inlines.silk_abs(pred2_Q10)); - Inlines.OpusAssert(smooth_coef_Q16 < 32768); - scale = Inlines.silk_RSHIFT(scale, 1); - mid_res_amp_Q0[mid_res_amp_Q0_ptr] = Inlines.silk_SMLAWB(mid_res_amp_Q0[mid_res_amp_Q0_ptr], Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(nrgx.Val), scale) - mid_res_amp_Q0[mid_res_amp_Q0_ptr], smooth_coef_Q16); - nrgy.Val = Inlines.silk_SUB_LSHIFT32(nrgy.Val, Inlines.silk_SMULWB(corr, pred_Q13), 4); - nrgy.Val = Inlines.silk_ADD_LSHIFT32(nrgy.Val, Inlines.silk_SMULWB(nrgx.Val, pred2_Q10), 6); - mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1] = Inlines.silk_SMLAWB(mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1], Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(nrgy.Val), scale) - mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1], smooth_coef_Q16); - ratio_Q14.Val = Inlines.silk_DIV32_varQ(mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1], Inlines.silk_max(mid_res_amp_Q0[mid_res_amp_Q0_ptr], 1), 14); - ratio_Q14.Val = Inlines.silk_LIMIT(ratio_Q14.Val, 0, Short.MAX_VALUE); - return pred_Q13; - } - - static void silk_stereo_LR_to_MS(StereoEncodeState state, short[] x1, int x1_ptr, short[] x2, int x2_ptr, byte[][] ix, BoxedValueByte mid_only_flag, int[] mid_side_rates_bps, int total_rate_bps, int prev_speech_act_Q8, int toMono, int fs_kHz, int frame_length) { - int width_Q14; - int min_mid_rate_bps; - int sum; - int n; - int[] pred_Q13 = new int[2]; - BoxedValueInt LP_ratio_Q14 = new BoxedValueInt(0); - BoxedValueInt HP_ratio_Q14 = new BoxedValueInt(0); - int mid = x1_ptr - 2; - short[] side = new short[frame_length + 2]; - for (n = 0; n < frame_length + 2; ++n) { - sum = x1[x1_ptr + n - 2] + x2[x2_ptr + n - 2]; - int diff = x1[x1_ptr + n - 2] - x2[x2_ptr + n - 2]; - x1[mid + n] = (short)Inlines.silk_RSHIFT_ROUND(sum, 1); - side[n] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(diff, 1)); - } - System.arraycopy(state.sMid, 0, x1, mid, 2); - System.arraycopy(state.sSide, 0, side, 0, 2); - System.arraycopy(x1, mid + frame_length, state.sMid, 0, 2); - System.arraycopy(side, frame_length, state.sSide, 0, 2); - short[] LP_mid = new short[frame_length]; - short[] HP_mid = new short[frame_length]; - for (n = 0; n < frame_length; ++n) { - sum = Inlines.silk_RSHIFT_ROUND(Inlines.silk_ADD_LSHIFT32(x1[mid + n] + x1[mid + n + 2], x1[mid + n + 1], 1), 2); - LP_mid[n] = (short)sum; - HP_mid[n] = (short)(x1[mid + n + 1] - sum); - } - short[] LP_side = new short[frame_length]; - short[] HP_side = new short[frame_length]; - for (n = 0; n < frame_length; ++n) { - sum = Inlines.silk_RSHIFT_ROUND(Inlines.silk_ADD_LSHIFT32(side[n] + side[n + 2], side[n + 1], 1), 2); - LP_side[n] = (short)sum; - HP_side[n] = (short)(side[n + 1] - sum); - } - boolean is10msFrame = frame_length == 10 * fs_kHz; - int smooth_coef_Q16 = is10msFrame ? 328 : 655; - smooth_coef_Q16 = Inlines.silk_SMULWB(Inlines.silk_SMULBB(prev_speech_act_Q8, prev_speech_act_Q8), smooth_coef_Q16); - pred_Q13[0] = Stereo.silk_stereo_find_predictor(LP_ratio_Q14, LP_mid, LP_side, state.mid_side_amp_Q0, 0, frame_length, smooth_coef_Q16); - pred_Q13[1] = Stereo.silk_stereo_find_predictor(HP_ratio_Q14, HP_mid, HP_side, state.mid_side_amp_Q0, 2, frame_length, smooth_coef_Q16); - int frac_Q16 = Inlines.silk_SMLABB(HP_ratio_Q14.Val, LP_ratio_Q14.Val, 3); - frac_Q16 = Inlines.silk_min(frac_Q16, 65536); - if ((total_rate_bps -= is10msFrame ? 1200 : 600) < 1) { - total_rate_bps = 1; - } - Inlines.OpusAssert((min_mid_rate_bps = Inlines.silk_SMLABB(2000, fs_kHz, 900)) < Short.MAX_VALUE); - int frac_3_Q16 = Inlines.silk_MUL(3, frac_Q16); - mid_side_rates_bps[0] = Inlines.silk_DIV32_varQ(total_rate_bps, 851968 + frac_3_Q16, 19); - if (mid_side_rates_bps[0] < min_mid_rate_bps) { - mid_side_rates_bps[0] = min_mid_rate_bps; - mid_side_rates_bps[1] = total_rate_bps - mid_side_rates_bps[0]; - width_Q14 = Inlines.silk_DIV32_varQ(Inlines.silk_LSHIFT(mid_side_rates_bps[1], 1) - min_mid_rate_bps, Inlines.silk_SMULWB(65536 + frac_3_Q16, min_mid_rate_bps), 16); - width_Q14 = Inlines.silk_LIMIT(width_Q14, 0, 16384); - } else { - mid_side_rates_bps[1] = total_rate_bps - mid_side_rates_bps[0]; - width_Q14 = 16384; - } - state.smth_width_Q14 = (short)Inlines.silk_SMLAWB(state.smth_width_Q14, width_Q14 - state.smth_width_Q14, smooth_coef_Q16); - mid_only_flag.Val = 0; - if (toMono != 0) { - width_Q14 = 0; - pred_Q13[0] = 0; - pred_Q13[1] = 0; - Stereo.silk_stereo_quant_pred(pred_Q13, ix); - } else if (state.width_prev_Q14 == 0 && (8 * total_rate_bps < 13 * min_mid_rate_bps || Inlines.silk_SMULWB(frac_Q16, state.smth_width_Q14) < 819)) { - pred_Q13[0] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[0]), 14); - pred_Q13[1] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[1]), 14); - Stereo.silk_stereo_quant_pred(pred_Q13, ix); - width_Q14 = 0; - pred_Q13[0] = 0; - pred_Q13[1] = 0; - mid_side_rates_bps[0] = total_rate_bps; - mid_side_rates_bps[1] = 0; - mid_only_flag.Val = 1; - } else if (state.width_prev_Q14 != 0 && (8 * total_rate_bps < 11 * min_mid_rate_bps || Inlines.silk_SMULWB(frac_Q16, state.smth_width_Q14) < 328)) { - pred_Q13[0] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[0]), 14); - pred_Q13[1] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[1]), 14); - Stereo.silk_stereo_quant_pred(pred_Q13, ix); - width_Q14 = 0; - pred_Q13[0] = 0; - pred_Q13[1] = 0; - } else if (state.smth_width_Q14 > 15565) { - Stereo.silk_stereo_quant_pred(pred_Q13, ix); - width_Q14 = 16384; - } else { - pred_Q13[0] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[0]), 14); - pred_Q13[1] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, pred_Q13[1]), 14); - Stereo.silk_stereo_quant_pred(pred_Q13, ix); - width_Q14 = state.smth_width_Q14; - } - if (mid_only_flag.Val == 1) { - state.silent_side_len = (short)(state.silent_side_len + (short)(frame_length - 8 * fs_kHz)); - if (state.silent_side_len < 5 * fs_kHz) { - mid_only_flag.Val = 0; - } else { - state.silent_side_len = (short)10000; - } - } else { - state.silent_side_len = 0; - } - if (mid_only_flag.Val == 0 && mid_side_rates_bps[1] < 1) { - mid_side_rates_bps[1] = 1; - mid_side_rates_bps[0] = Inlines.silk_max_int(1, total_rate_bps - mid_side_rates_bps[1]); - } - int pred0_Q13 = -state.pred_prev_Q13[0]; - int pred1_Q13 = -state.pred_prev_Q13[1]; - int w_Q24 = Inlines.silk_LSHIFT(state.width_prev_Q14, 10); - int denom_Q16 = Inlines.silk_DIV32_16(65536, 8 * fs_kHz); - int delta0_Q13 = 0 - Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(pred_Q13[0] - state.pred_prev_Q13[0], denom_Q16), 16); - int delta1_Q13 = 0 - Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(pred_Q13[1] - state.pred_prev_Q13[1], denom_Q16), 16); - int deltaw_Q24 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(width_Q14 - state.width_prev_Q14, denom_Q16), 10); - for (n = 0; n < 8 * fs_kHz; ++n) { - sum = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[mid + n] + x1[mid + n + 2], x1[mid + n + 1], 1), 9); - sum = Inlines.silk_SMLAWB(Inlines.silk_SMULWB(w_Q24 += deltaw_Q24, side[n + 1]), sum, pred0_Q13 += delta0_Q13); - sum = Inlines.silk_SMLAWB(sum, Inlines.silk_LSHIFT(x1[mid + n + 1], 11), pred1_Q13 += delta1_Q13); - x2[x2_ptr + n - 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sum, 8)); - } - pred0_Q13 = 0 - pred_Q13[0]; - pred1_Q13 = 0 - pred_Q13[1]; - w_Q24 = Inlines.silk_LSHIFT(width_Q14, 10); - for (n = 8 * fs_kHz; n < frame_length; ++n) { - sum = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[mid + n] + x1[mid + n + 2], x1[mid + n + 1], 1), 9); - sum = Inlines.silk_SMLAWB(Inlines.silk_SMULWB(w_Q24, side[n + 1]), sum, pred0_Q13); - sum = Inlines.silk_SMLAWB(sum, Inlines.silk_LSHIFT(x1[mid + n + 1], 11), pred1_Q13); - x2[x2_ptr + n - 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sum, 8)); - } - state.pred_prev_Q13[0] = (short)pred_Q13[0]; - state.pred_prev_Q13[1] = (short)pred_Q13[1]; - state.width_prev_Q14 = (short)width_Q14; - } - - static void silk_stereo_MS_to_LR(StereoDecodeState state, short[] x1, int x1_ptr, short[] x2, int x2_ptr, int[] pred_Q13, int fs_kHz, int frame_length) { - int sum; - int n; - System.arraycopy(state.sMid, 0, x1, x1_ptr, 2); - System.arraycopy(state.sSide, 0, x2, x2_ptr, 2); - System.arraycopy(x1, x1_ptr + frame_length, state.sMid, 0, 2); - System.arraycopy(x2, x2_ptr + frame_length, state.sSide, 0, 2); - int pred0_Q13 = state.pred_prev_Q13[0]; - int pred1_Q13 = state.pred_prev_Q13[1]; - int denom_Q16 = Inlines.silk_DIV32_16(65536, 8 * fs_kHz); - int delta0_Q13 = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(pred_Q13[0] - state.pred_prev_Q13[0], denom_Q16), 16); - int delta1_Q13 = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(pred_Q13[1] - state.pred_prev_Q13[1], denom_Q16), 16); - for (n = 0; n < 8 * fs_kHz; ++n) { - sum = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[x1_ptr + n] + x1[x1_ptr + n + 2], x1[x1_ptr + n + 1], 1), 9); - sum = Inlines.silk_SMLAWB(Inlines.silk_LSHIFT(x2[x2_ptr + n + 1], 8), sum, pred0_Q13 += delta0_Q13); - sum = Inlines.silk_SMLAWB(sum, Inlines.silk_LSHIFT(x1[x1_ptr + n + 1], 11), pred1_Q13 += delta1_Q13); - x2[x2_ptr + n + 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sum, 8)); - } - pred0_Q13 = pred_Q13[0]; - pred1_Q13 = pred_Q13[1]; - for (n = 8 * fs_kHz; n < frame_length; ++n) { - sum = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[x1_ptr + n] + x1[x1_ptr + n + 2], x1[x1_ptr + n + 1], 1), 9); - sum = Inlines.silk_SMLAWB(Inlines.silk_LSHIFT(x2[x2_ptr + n + 1], 8), sum, pred0_Q13); - sum = Inlines.silk_SMLAWB(sum, Inlines.silk_LSHIFT(x1[x1_ptr + n + 1], 11), pred1_Q13); - x2[x2_ptr + n + 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sum, 8)); - } - state.pred_prev_Q13[0] = (short)pred_Q13[0]; - state.pred_prev_Q13[1] = (short)pred_Q13[1]; - for (n = 0; n < frame_length; ++n) { - sum = x1[x1_ptr + n + 1] + x2[x2_ptr + n + 1]; - int diff = x1[x1_ptr + n + 1] - x2[x2_ptr + n + 1]; - x1[x1_ptr + n + 1] = (short)Inlines.silk_SAT16(sum); - x2[x2_ptr + n + 1] = (short)Inlines.silk_SAT16(diff); - } - } - - static void silk_stereo_quant_pred(int[] pred_Q13, byte[][] ix) { - int quant_pred_Q13 = 0; - Arrays.MemSet(ix[0], (byte)0, 3); - Arrays.MemSet(ix[1], (byte)0, 3); - for (int n = 0; n < 2; ++n) { - boolean done = false; - int err_min_Q13 = Integer.MAX_VALUE; - for (int i = 0; !done && i < 15; i = (int)((byte)(i + 1))) { - short low_Q13 = SilkTables.silk_stereo_pred_quant_Q13[i]; - int step_Q13 = Inlines.silk_SMULWB(SilkTables.silk_stereo_pred_quant_Q13[i + 1] - low_Q13, 6554); - for (int j = 0; !done && j < 5; j = (int)((byte)(j + 1))) { - int lvl_Q13 = Inlines.silk_SMLABB(low_Q13, step_Q13, 2 * j + 1); - int err_Q13 = Inlines.silk_abs(pred_Q13[n] - lvl_Q13); - if (err_Q13 < err_min_Q13) { - err_min_Q13 = err_Q13; - quant_pred_Q13 = lvl_Q13; - ix[n][0] = i; - ix[n][1] = j; - continue; - } - done = true; - } - } - ix[n][2] = (byte)Inlines.silk_DIV32_16(ix[n][0], 3); - ix[n][0] = (byte)(ix[n][0] - (byte)(ix[n][2] * 3)); - pred_Q13[n] = quant_pred_Q13; - } - pred_Q13[0] = pred_Q13[0] - pred_Q13[1]; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/StereoDecodeState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/StereoDecodeState.java deleted file mode 100644 index 2f9a1d3..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/StereoDecodeState.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class StereoDecodeState { - final short[] pred_prev_Q13 = new short[2]; - final short[] sMid = new short[2]; - final short[] sSide = new short[2]; - - StereoDecodeState() { - } - - void Reset() { - Arrays.MemSet(this.pred_prev_Q13, (short)0, 2); - Arrays.MemSet(this.sMid, (short)0, 2); - Arrays.MemSet(this.sSide, (short)0, 2); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/StereoEncodeState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/StereoEncodeState.java deleted file mode 100644 index 8822ba0..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/StereoEncodeState.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class StereoEncodeState { - final short[] pred_prev_Q13 = new short[2]; - final short[] sMid = new short[2]; - final short[] sSide = new short[2]; - final int[] mid_side_amp_Q0 = new int[4]; - short smth_width_Q14 = 0; - short width_prev_Q14 = 0; - short silent_side_len = 0; - final byte[][][] predIx = Arrays.InitThreeDimensionalArrayByte(3, 2, 3); - final byte[] mid_only_flags = new byte[3]; - - StereoEncodeState() { - } - - void Reset() { - Arrays.MemSet(this.pred_prev_Q13, (short)0, 2); - Arrays.MemSet(this.sMid, (short)0, 2); - Arrays.MemSet(this.sSide, (short)0, 2); - Arrays.MemSet(this.mid_side_amp_Q0, 0, 4); - this.smth_width_Q14 = 0; - this.width_prev_Q14 = 0; - this.silent_side_len = 0; - for (int x = 0; x < 3; ++x) { - for (int y = 0; y < 2; ++y) { - Arrays.MemSet(this.predIx[x][y], (byte)0, 3); - } - } - Arrays.MemSet(this.mid_only_flags, (byte)0, 3); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/StereoWidthState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/StereoWidthState.java deleted file mode 100644 index f81c623..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/StereoWidthState.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class StereoWidthState { - int XX; - int XY; - int YY; - int smoothed_width; - int max_follower; - - StereoWidthState() { - } - - void Reset() { - this.XX = 0; - this.XY = 0; - this.YY = 0; - this.smoothed_width = 0; - this.max_follower = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/SumSqrShift.java b/source/decompiled/de/maxhenkel/voicechat/concentus/SumSqrShift.java deleted file mode 100644 index 72eeb6c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/SumSqrShift.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Inlines; - -class SumSqrShift { - SumSqrShift() { - } - - static void silk_sum_sqr_shift(BoxedValueInt energy, BoxedValueInt shift, short[] x, int x_ptr, int len) { - int nrg_tmp; - int i; - int nrg = 0; - int shft = 0; - --len; - for (i = 0; i < len; i += 2) { - nrg = Inlines.silk_SMLABB_ovflw(nrg, x[x_ptr + i], x[x_ptr + i]); - if ((nrg = Inlines.silk_SMLABB_ovflw(nrg, x[x_ptr + i + 1], x[x_ptr + i + 1])) >= 0) continue; - nrg = (int)Inlines.silk_RSHIFT_uint(nrg, 2); - shft = 2; - i += 2; - break; - } - while (i < len) { - nrg_tmp = Inlines.silk_SMULBB(x[x_ptr + i], x[x_ptr + i]); - if ((nrg = (int)Inlines.silk_ADD_RSHIFT_uint(nrg, nrg_tmp = Inlines.silk_SMLABB_ovflw(nrg_tmp, x[x_ptr + i + 1], x[x_ptr + i + 1]), shft)) < 0) { - nrg = (int)Inlines.silk_RSHIFT_uint(nrg, 2); - shft += 2; - } - i += 2; - } - if (i == len) { - nrg_tmp = Inlines.silk_SMULBB(x[x_ptr + i], x[x_ptr + i]); - nrg = (int)Inlines.silk_ADD_RSHIFT_uint(nrg, nrg_tmp, shft); - } - if ((nrg & 0xC0000000) != 0) { - nrg = (int)Inlines.silk_RSHIFT_uint(nrg, 2); - shft += 2; - } - shift.Val = shft; - energy.Val = nrg; - } - - static void silk_sum_sqr_shift(BoxedValueInt energy, BoxedValueInt shift, short[] x, int len) { - int nrg_tmp; - int i; - int nrg = 0; - int shft = 0; - --len; - for (i = 0; i < len; i += 2) { - nrg = Inlines.silk_SMLABB_ovflw(nrg, x[i], x[i]); - if ((nrg = Inlines.silk_SMLABB_ovflw(nrg, x[i + 1], x[i + 1])) >= 0) continue; - nrg = (int)Inlines.silk_RSHIFT_uint(nrg, 2); - shft = 2; - i += 2; - break; - } - while (i < len) { - nrg_tmp = Inlines.silk_SMULBB(x[i], x[i]); - if ((nrg = (int)Inlines.silk_ADD_RSHIFT_uint(nrg, nrg_tmp = Inlines.silk_SMLABB_ovflw(nrg_tmp, x[i + 1], x[i + 1]), shft)) < 0) { - nrg = (int)Inlines.silk_RSHIFT_uint(nrg, 2); - shft += 2; - } - i += 2; - } - if (i == len) { - nrg_tmp = Inlines.silk_SMULBB(x[i], x[i]); - nrg = (int)Inlines.silk_ADD_RSHIFT_uint(nrg, nrg_tmp, shft); - } - if ((nrg & 0xC0000000) != 0) { - nrg = (int)Inlines.silk_RSHIFT_uint(nrg, 2); - shft += 2; - } - shift.Val = shft; - energy.Val = nrg; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/TOCStruct.java b/source/decompiled/de/maxhenkel/voicechat/concentus/TOCStruct.java deleted file mode 100644 index bb301ff..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/TOCStruct.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Arrays; - -class TOCStruct { - int VADFlag = 0; - final int[] VADFlags = new int[3]; - int inbandFECFlag = 0; - - TOCStruct() { - } - - void Reset() { - this.VADFlag = 0; - Arrays.MemSet(this.VADFlags, 0, 3); - this.inbandFECFlag = 0; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/TonalityAnalysisState.java b/source/decompiled/de/maxhenkel/voicechat/concentus/TonalityAnalysisState.java deleted file mode 100644 index 27dd45c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/TonalityAnalysisState.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.AnalysisInfo; -import de.maxhenkel.voicechat.concentus.Arrays; - -class TonalityAnalysisState { - boolean enabled = false; - final float[] angle = new float[240]; - final float[] d_angle = new float[240]; - final float[] d2_angle = new float[240]; - final int[] inmem = new int[720]; - int mem_fill; - final float[] prev_band_tonality = new float[18]; - float prev_tonality; - final float[][] E = Arrays.InitTwoDimensionalArrayFloat(8, 18); - final float[] lowE = new float[18]; - final float[] highE = new float[18]; - final float[] meanE = new float[21]; - final float[] mem = new float[32]; - final float[] cmean = new float[8]; - final float[] std = new float[9]; - float music_prob; - float Etracker; - float lowECount; - int E_count; - int last_music; - int last_transition; - int count; - final float[] subframe_mem = new float[3]; - int analysis_offset; - final float[] pspeech = new float[200]; - final float[] pmusic = new float[200]; - float speech_confidence; - float music_confidence; - int speech_confidence_count; - int music_confidence_count; - int write_pos; - int read_pos; - int read_subframe; - final AnalysisInfo[] info = new AnalysisInfo[200]; - - TonalityAnalysisState() { - for (int c = 0; c < 200; ++c) { - this.info[c] = new AnalysisInfo(); - } - } - - void Reset() { - int c; - Arrays.MemSet(this.angle, 0.0f, 240); - Arrays.MemSet(this.d_angle, 0.0f, 240); - Arrays.MemSet(this.d2_angle, 0.0f, 240); - Arrays.MemSet(this.inmem, 0, 720); - this.mem_fill = 0; - Arrays.MemSet(this.prev_band_tonality, 0.0f, 18); - this.prev_tonality = 0.0f; - for (c = 0; c < 8; ++c) { - Arrays.MemSet(this.E[c], 0.0f, 18); - } - Arrays.MemSet(this.lowE, 0.0f, 18); - Arrays.MemSet(this.highE, 0.0f, 18); - Arrays.MemSet(this.meanE, 0.0f, 21); - Arrays.MemSet(this.mem, 0.0f, 32); - Arrays.MemSet(this.cmean, 0.0f, 8); - Arrays.MemSet(this.std, 0.0f, 9); - this.music_prob = 0.0f; - this.Etracker = 0.0f; - this.lowECount = 0.0f; - this.E_count = 0; - this.last_music = 0; - this.last_transition = 0; - this.count = 0; - Arrays.MemSet(this.subframe_mem, 0.0f, 3); - this.analysis_offset = 0; - Arrays.MemSet(this.pspeech, 0.0f, 200); - Arrays.MemSet(this.pmusic, 0.0f, 200); - this.speech_confidence = 0.0f; - this.music_confidence = 0.0f; - this.speech_confidence_count = 0; - this.music_confidence_count = 0; - this.write_pos = 0; - this.read_pos = 0; - this.read_subframe = 0; - for (c = 0; c < 200; ++c) { - this.info[c].Reset(); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/TuningParameters.java b/source/decompiled/de/maxhenkel/voicechat/concentus/TuningParameters.java deleted file mode 100644 index a0ffd2d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/TuningParameters.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class TuningParameters { - static final int BITRESERVOIR_DECAY_TIME_MS = 500; - static final float FIND_PITCH_WHITE_NOISE_FRACTION = 0.001f; - static final float FIND_PITCH_BANDWIDTH_EXPANSION = 0.99f; - static final float FIND_LPC_COND_FAC = 1.0E-5f; - static final float FIND_LTP_COND_FAC = 1.0E-5f; - static final float LTP_DAMPING = 0.05f; - static final float LTP_SMOOTHING = 0.1f; - static final float MU_LTP_QUANT_NB = 0.03f; - static final float MU_LTP_QUANT_MB = 0.025f; - static final float MU_LTP_QUANT_WB = 0.02f; - static final float MAX_SUM_LOG_GAIN_DB = 250.0f; - static final float VARIABLE_HP_SMTH_COEF1 = 0.1f; - static final float VARIABLE_HP_SMTH_COEF2 = 0.015f; - static final float VARIABLE_HP_MAX_DELTA_FREQ = 0.4f; - static final int VARIABLE_HP_MIN_CUTOFF_HZ = 60; - static final int VARIABLE_HP_MAX_CUTOFF_HZ = 100; - static final float SPEECH_ACTIVITY_DTX_THRES = 0.05f; - static final float LBRR_SPEECH_ACTIVITY_THRES = 0.3f; - static final float BG_SNR_DECR_dB = 2.0f; - static final float HARM_SNR_INCR_dB = 2.0f; - static final float SPARSE_SNR_INCR_dB = 2.0f; - static final float SPARSENESS_THRESHOLD_QNT_OFFSET = 0.75f; - static final float WARPING_MULTIPLIER = 0.015f; - static final float SHAPE_WHITE_NOISE_FRACTION = 5.0E-5f; - static final float BANDWIDTH_EXPANSION = 0.95f; - static final float LOW_RATE_BANDWIDTH_EXPANSION_DELTA = 0.01f; - static final float LOW_RATE_HARMONIC_BOOST = 0.1f; - static final float LOW_INPUT_QUALITY_HARMONIC_BOOST = 0.1f; - static final float HARMONIC_SHAPING = 0.3f; - static final float HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING = 0.2f; - static final float HP_NOISE_COEF = 0.25f; - static final float HARM_HP_NOISE_COEF = 0.35f; - static final float INPUT_TILT = 0.05f; - static final float HIGH_RATE_INPUT_TILT = 0.1f; - static final float LOW_FREQ_SHAPING = 4.0f; - static final float LOW_QUALITY_LOW_FREQ_SHAPING_DECR = 0.5f; - static final float SUBFR_SMTH_COEF = 0.4f; - static final float LAMBDA_OFFSET = 1.2f; - static final float LAMBDA_SPEECH_ACT = -0.2f; - static final float LAMBDA_DELAYED_DECISIONS = -0.05f; - static final float LAMBDA_INPUT_QUALITY = -0.1f; - static final float LAMBDA_CODING_QUALITY = -0.2f; - static final float LAMBDA_QUANT_OFFSET = 0.8f; - static final int REDUCE_BITRATE_10_MS_BPS = 2200; - static final int MAX_BANDWIDTH_SWITCH_DELAY_MS = 5000; - - TuningParameters() { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/VQ.java b/source/decompiled/de/maxhenkel/voicechat/concentus/VQ.java deleted file mode 100644 index c609a11..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/VQ.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.CWRS; -import de.maxhenkel.voicechat.concentus.EntropyCoder; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Kernels; - -class VQ { - private static int[] SPREAD_FACTOR = new int[]{15, 10, 5}; - - VQ() { - } - - static void exp_rotation1(int[] X, int X_ptr, int len, int stride, int c, int s) { - int x2; - int x1; - int i; - int Xptr = X_ptr; - int ms = Inlines.NEG16(s); - for (i = 0; i < len - stride; ++i) { - x1 = X[Xptr]; - x2 = X[Xptr + stride]; - X[Xptr + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x2), s, x1), 15)); - X[Xptr] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x1), ms, x2), 15)); - ++Xptr; - } - Xptr = X_ptr + (len - 2 * stride - 1); - for (i = len - 2 * stride - 1; i >= 0; --i) { - x1 = X[Xptr]; - x2 = X[Xptr + stride]; - X[Xptr + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x2), s, x1), 15)); - X[Xptr] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x1), ms, x2), 15)); - --Xptr; - } - } - - static void exp_rotation(int[] X, int X_ptr, int len, int dir, int stride, int K, int spread) { - int stride2 = 0; - if (2 * K >= len || spread == 0) { - return; - } - int factor = SPREAD_FACTOR[spread - 1]; - int gain = Inlines.celt_div(Inlines.MULT16_16(Short.MAX_VALUE, len), len + factor * K); - int theta = Inlines.HALF16(Inlines.MULT16_16_Q15(gain, gain)); - int c = Inlines.celt_cos_norm(Inlines.EXTEND32(theta)); - int s = Inlines.celt_cos_norm(Inlines.EXTEND32(Inlines.SUB16(Short.MAX_VALUE, theta))); - if (len >= 8 * stride) { - stride2 = 1; - while ((stride2 * stride2 + stride2) * stride + (stride >> 2) < len) { - ++stride2; - } - } - len = Inlines.celt_udiv(len, stride); - for (int i = 0; i < stride; ++i) { - if (dir < 0) { - if (stride2 != 0) { - VQ.exp_rotation1(X, X_ptr + i * len, len, stride2, s, c); - } - VQ.exp_rotation1(X, X_ptr + i * len, len, 1, c, s); - continue; - } - VQ.exp_rotation1(X, X_ptr + i * len, len, 1, c, (short)(0 - s)); - if (stride2 == 0) continue; - VQ.exp_rotation1(X, X_ptr + i * len, len, stride2, s, (short)(0 - c)); - } - } - - static void normalise_residual(int[] iy, int[] X, int X_ptr, int N, int Ryy, int gain) { - int k = Inlines.celt_ilog2(Ryy) >> 1; - int t = Inlines.VSHR32(Ryy, 2 * (k - 7)); - int g = Inlines.MULT16_16_P15(Inlines.celt_rsqrt_norm(t), gain); - int i = 0; - do { - X[X_ptr + i] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(g, iy[i]), k + 1)); - } while (++i < N); - } - - static int extract_collapse_mask(int[] iy, int N, int B) { - if (B <= 1) { - return 1; - } - int N0 = Inlines.celt_udiv(N, B); - int collapse_mask = 0; - int i = 0; - do { - int tmp = 0; - int j = 0; - do { - tmp |= iy[i * N0 + j]; - } while (++j < N0); - collapse_mask |= (tmp != 0 ? 1 : 0) << i; - } while (++i < B); - return collapse_mask; - } - - static int alg_quant(int[] X, int X_ptr, int N, int K, int spread, int B, EntropyCoder enc) { - int[] y = new int[N]; - int[] iy = new int[N]; - int[] signx = new int[N]; - Inlines.OpusAssert(K > 0, "alg_quant() needs at least one pulse"); - Inlines.OpusAssert(N > 1, "alg_quant() needs at least two dimensions"); - VQ.exp_rotation(X, X_ptr, N, 1, B, K, spread); - int sum = 0; - int j = 0; - do { - if (X[X_ptr + j] > 0) { - signx[j] = 1; - } else { - signx[j] = -1; - X[X_ptr + j] = 0 - X[X_ptr + j]; - } - iy[j] = 0; - y[j] = 0; - } while (++j < N); - int yy = 0; - int xy = 0; - int pulsesLeft = K; - if (K > N >> 1) { - j = 0; - do { - sum += X[X_ptr + j]; - } while (++j < N); - if (sum <= K) { - X[X_ptr] = 16384; - j = X_ptr + 1; - do { - X[j] = 0; - } while (++j < N + X_ptr); - sum = 16384; - } - short rcp = Inlines.EXTRACT16(Inlines.MULT16_32_Q16(K - 1, Inlines.celt_rcp(sum))); - j = 0; - do { - iy[j] = Inlines.MULT16_16_Q15(X[X_ptr + j], (int)rcp); - y[j] = iy[j]; - yy = Inlines.MAC16_16(yy, y[j], y[j]); - xy = Inlines.MAC16_16(xy, X[X_ptr + j], y[j]); - int n = j; - y[n] = y[n] * 2; - pulsesLeft -= iy[j]; - } while (++j < N); - } - Inlines.OpusAssert(pulsesLeft >= 1, "Allocated too many pulses in the quick pass"); - if (pulsesLeft > N + 3) { - int tmp = pulsesLeft; - yy = Inlines.MAC16_16(yy, tmp, tmp); - yy = Inlines.MAC16_16(yy, tmp, y[0]); - iy[0] = iy[0] + pulsesLeft; - pulsesLeft = 0; - } - int s = 1; - for (int i = 0; i < pulsesLeft; ++i) { - int best_num = -32767; - int best_den = 0; - int rshift = 1 + Inlines.celt_ilog2(K - pulsesLeft + i + 1); - int best_id = 0; - yy = Inlines.ADD16(yy, 1); - j = 0; - do { - int Rxy = Inlines.EXTRACT16(Inlines.SHR32(Inlines.ADD32(xy, Inlines.EXTEND32(X[X_ptr + j])), rshift)); - int Ryy = Inlines.ADD16(yy, y[j]); - if (Inlines.MULT16_16(best_den, Rxy = Inlines.MULT16_16_Q15(Rxy, Rxy)) <= Inlines.MULT16_16(Ryy, best_num)) continue; - best_den = Ryy; - best_num = Rxy; - best_id = j; - } while (++j < N); - xy = Inlines.ADD32(xy, Inlines.EXTEND32(X[X_ptr + best_id])); - yy = Inlines.ADD16(yy, y[best_id]); - y[best_id] = y[best_id] + 2 * s; - int n = best_id; - iy[n] = iy[n] + 1; - } - j = 0; - do { - X[X_ptr + j] = Inlines.MULT16_16(signx[j], X[X_ptr + j]); - if (signx[j] >= 0) continue; - iy[j] = -iy[j]; - } while (++j < N); - CWRS.encode_pulses(iy, N, K, enc); - int collapse_mask = VQ.extract_collapse_mask(iy, N, B); - return collapse_mask; - } - - static int alg_unquant(int[] X, int X_ptr, int N, int K, int spread, int B, EntropyCoder dec, int gain) { - int[] iy = new int[N]; - Inlines.OpusAssert(K > 0, "alg_unquant() needs at least one pulse"); - Inlines.OpusAssert(N > 1, "alg_unquant() needs at least two dimensions"); - int Ryy = CWRS.decode_pulses(iy, N, K, dec); - VQ.normalise_residual(iy, X, X_ptr, N, Ryy, gain); - VQ.exp_rotation(X, X_ptr, N, -1, B, K, spread); - int collapse_mask = VQ.extract_collapse_mask(iy, N, B); - return collapse_mask; - } - - static void renormalise_vector(int[] X, int X_ptr, int N, int gain) { - int E = 1 + Kernels.celt_inner_prod(X, X_ptr, X, X_ptr, N); - int k = Inlines.celt_ilog2(E) >> 1; - int t = Inlines.VSHR32(E, 2 * (k - 7)); - int g = Inlines.MULT16_16_P15(Inlines.celt_rsqrt_norm(t), gain); - int xptr = X_ptr; - for (int i = 0; i < N; ++i) { - X[xptr] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(g, X[xptr]), k + 1)); - ++xptr; - } - } - - static int stereo_itheta(int[] X, int X_ptr, int[] Y, int Y_ptr, int stereo, int N) { - int Eside = 1; - int Emid = 1; - if (stereo != 0) { - for (int i = 0; i < N; ++i) { - int m = Inlines.ADD16(Inlines.SHR16(X[X_ptr + i], 1), Inlines.SHR16(Y[Y_ptr + i], 1)); - int s = Inlines.SUB16(Inlines.SHR16(X[X_ptr + i], 1), Inlines.SHR16(Y[Y_ptr + i], 1)); - Emid = Inlines.MAC16_16(Emid, m, m); - Eside = Inlines.MAC16_16(Eside, s, s); - } - } else { - Emid += Kernels.celt_inner_prod(X, X_ptr, X, X_ptr, N); - Eside += Kernels.celt_inner_prod(Y, Y_ptr, Y, Y_ptr, N); - } - int mid = Inlines.celt_sqrt(Emid); - int side = Inlines.celt_sqrt(Eside); - int itheta = Inlines.MULT16_16_Q15(20861, Inlines.celt_atan2p(side, mid)); - return itheta; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/VQ_WMat_EC.java b/source/decompiled/de/maxhenkel/voicechat/concentus/VQ_WMat_EC.java deleted file mode 100644 index 82ce4a6..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/VQ_WMat_EC.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.BoxedValueByte; -import de.maxhenkel.voicechat.concentus.BoxedValueInt; -import de.maxhenkel.voicechat.concentus.Inlines; - -class VQ_WMat_EC { - VQ_WMat_EC() { - } - - static void silk_VQ_WMat_EC(BoxedValueByte ind, BoxedValueInt rate_dist_Q14, BoxedValueInt gain_Q7, short[] in_Q14, int in_Q14_ptr, int[] W_Q18, int W_Q18_ptr, byte[][] cb_Q7, short[] cb_gain_Q7, short[] cl_Q5, int mu_Q9, int max_gain_Q7, int L) { - int cb_row_Q7_ptr = 0; - short[] diff_Q14 = new short[5]; - rate_dist_Q14.Val = Integer.MAX_VALUE; - for (int k = 0; k < L; ++k) { - byte[] cb_row_Q7 = cb_Q7[cb_row_Q7_ptr++]; - int gain_tmp_Q7 = cb_gain_Q7[k]; - diff_Q14[0] = (short)(in_Q14[in_Q14_ptr] - Inlines.silk_LSHIFT(cb_row_Q7[0], 7)); - diff_Q14[1] = (short)(in_Q14[in_Q14_ptr + 1] - Inlines.silk_LSHIFT(cb_row_Q7[1], 7)); - diff_Q14[2] = (short)(in_Q14[in_Q14_ptr + 2] - Inlines.silk_LSHIFT(cb_row_Q7[2], 7)); - diff_Q14[3] = (short)(in_Q14[in_Q14_ptr + 3] - Inlines.silk_LSHIFT(cb_row_Q7[3], 7)); - diff_Q14[4] = (short)(in_Q14[in_Q14_ptr + 4] - Inlines.silk_LSHIFT(cb_row_Q7[4], 7)); - int sum1_Q14 = Inlines.silk_SMULBB(mu_Q9, cl_Q5[k]); - Inlines.OpusAssert((sum1_Q14 = Inlines.silk_ADD_LSHIFT32(sum1_Q14, Inlines.silk_max(Inlines.silk_SUB32(gain_tmp_Q7, max_gain_Q7), 0), 10)) >= 0); - int sum2_Q16 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 1], diff_Q14[1]); - sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 2], diff_Q14[2]); - sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 3], diff_Q14[3]); - sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 4], diff_Q14[4]); - sum2_Q16 = Inlines.silk_LSHIFT(sum2_Q16, 1); - sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr], diff_Q14[0]); - sum1_Q14 = Inlines.silk_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14[0]); - sum2_Q16 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 7], diff_Q14[2]); - sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 8], diff_Q14[3]); - sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 9], diff_Q14[4]); - sum2_Q16 = Inlines.silk_LSHIFT(sum2_Q16, 1); - sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 6], diff_Q14[1]); - sum1_Q14 = Inlines.silk_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14[1]); - sum2_Q16 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 13], diff_Q14[3]); - sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 14], diff_Q14[4]); - sum2_Q16 = Inlines.silk_LSHIFT(sum2_Q16, 1); - sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 12], diff_Q14[2]); - sum1_Q14 = Inlines.silk_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14[2]); - sum2_Q16 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 19], diff_Q14[4]); - sum2_Q16 = Inlines.silk_LSHIFT(sum2_Q16, 1); - sum2_Q16 = Inlines.silk_SMLAWB(sum2_Q16, W_Q18[W_Q18_ptr + 18], diff_Q14[3]); - sum1_Q14 = Inlines.silk_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14[3]); - sum2_Q16 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 24], diff_Q14[4]); - sum1_Q14 = Inlines.silk_SMLAWB(sum1_Q14, sum2_Q16, diff_Q14[4]); - Inlines.OpusAssert(sum1_Q14 >= 0); - if (sum1_Q14 >= rate_dist_Q14.Val) continue; - rate_dist_Q14.Val = sum1_Q14; - ind.Val = (byte)k; - gain_Q7.Val = gain_tmp_Q7; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/VoiceActivityDetection.java b/source/decompiled/de/maxhenkel/voicechat/concentus/VoiceActivityDetection.java deleted file mode 100644 index 8813a75..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/VoiceActivityDetection.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -import de.maxhenkel.voicechat.concentus.Filters; -import de.maxhenkel.voicechat.concentus.Inlines; -import de.maxhenkel.voicechat.concentus.Sigmoid; -import de.maxhenkel.voicechat.concentus.SilkChannelEncoder; -import de.maxhenkel.voicechat.concentus.SilkVADState; - -class VoiceActivityDetection { - private static final int[] tiltWeights = new int[]{30000, 6000, -12000, -12000}; - - VoiceActivityDetection() { - } - - static int silk_VAD_Init(SilkVADState psSilk_VAD) { - int b; - int ret = 0; - psSilk_VAD.Reset(); - for (b = 0; b < 4; ++b) { - psSilk_VAD.NoiseLevelBias[b] = Inlines.silk_max_32(Inlines.silk_DIV32_16(50, (short)(b + 1)), 1); - } - for (b = 0; b < 4; ++b) { - psSilk_VAD.NL[b] = Inlines.silk_MUL(100, psSilk_VAD.NoiseLevelBias[b]); - psSilk_VAD.inv_NL[b] = Inlines.silk_DIV32(Integer.MAX_VALUE, psSilk_VAD.NL[b]); - } - psSilk_VAD.counter = 15; - for (b = 0; b < 4; ++b) { - psSilk_VAD.NrgRatioSmth_Q8[b] = 25600; - } - return ret; - } - - static int silk_VAD_GetSA_Q8(SilkChannelEncoder psEncC, short[] pIn, int pIn_ptr) { - int SNR_Q7; - int speech_nrg; - int b; - int i; - int sumSquared = 0; - int[] Xnrg = new int[4]; - int[] NrgToNoiseRatio_Q8 = new int[4]; - int[] X_offset = new int[4]; - int ret = 0; - SilkVADState psSilk_VAD = psEncC.sVAD; - Inlines.OpusAssert(true); - Inlines.OpusAssert(320 >= psEncC.frame_length); - Inlines.OpusAssert(psEncC.frame_length <= 512); - Inlines.OpusAssert(psEncC.frame_length == 8 * Inlines.silk_RSHIFT(psEncC.frame_length, 3)); - int decimated_framelength1 = Inlines.silk_RSHIFT(psEncC.frame_length, 1); - int decimated_framelength2 = Inlines.silk_RSHIFT(psEncC.frame_length, 2); - int decimated_framelength = Inlines.silk_RSHIFT(psEncC.frame_length, 3); - X_offset[0] = 0; - X_offset[1] = decimated_framelength + decimated_framelength2; - X_offset[2] = X_offset[1] + decimated_framelength; - X_offset[3] = X_offset[2] + decimated_framelength2; - short[] X = new short[X_offset[3] + decimated_framelength1]; - Filters.silk_ana_filt_bank_1(pIn, pIn_ptr, psSilk_VAD.AnaState, X, X, X_offset[3], psEncC.frame_length); - Filters.silk_ana_filt_bank_1(X, 0, psSilk_VAD.AnaState1, X, X, X_offset[2], decimated_framelength1); - Filters.silk_ana_filt_bank_1(X, 0, psSilk_VAD.AnaState2, X, X, X_offset[1], decimated_framelength2); - X[decimated_framelength - 1] = (short)Inlines.silk_RSHIFT(X[decimated_framelength - 1], 1); - short HPstateTmp = X[decimated_framelength - 1]; - for (i = decimated_framelength - 1; i > 0; --i) { - X[i - 1] = (short)Inlines.silk_RSHIFT(X[i - 1], 1); - int n = i; - X[n] = (short)(X[n] - X[i - 1]); - } - X[0] = (short)(X[0] - psSilk_VAD.HPstate); - psSilk_VAD.HPstate = HPstateTmp; - for (b = 0; b < 4; ++b) { - decimated_framelength = Inlines.silk_RSHIFT(psEncC.frame_length, Inlines.silk_min_int(4 - b, 3)); - int dec_subframe_length = Inlines.silk_RSHIFT(decimated_framelength, 2); - int dec_subframe_offset = 0; - Xnrg[b] = psSilk_VAD.XnrgSubfr[b]; - for (int s = 0; s < 4; ++s) { - sumSquared = 0; - for (i = 0; i < dec_subframe_length; ++i) { - int x_tmp = Inlines.silk_RSHIFT(X[X_offset[b] + i + dec_subframe_offset], 3); - Inlines.OpusAssert((sumSquared = Inlines.silk_SMLABB(sumSquared, x_tmp, x_tmp)) >= 0); - } - Xnrg[b] = s < 3 ? Inlines.silk_ADD_POS_SAT32(Xnrg[b], sumSquared) : Inlines.silk_ADD_POS_SAT32(Xnrg[b], Inlines.silk_RSHIFT(sumSquared, 1)); - dec_subframe_offset += dec_subframe_length; - } - psSilk_VAD.XnrgSubfr[b] = sumSquared; - } - VoiceActivityDetection.silk_VAD_GetNoiseLevels(Xnrg, psSilk_VAD); - sumSquared = 0; - int input_tilt = 0; - for (b = 0; b < 4; ++b) { - speech_nrg = Xnrg[b] - psSilk_VAD.NL[b]; - if (speech_nrg > 0) { - NrgToNoiseRatio_Q8[b] = (Xnrg[b] & 0xFF800000) == 0 ? Inlines.silk_DIV32(Inlines.silk_LSHIFT(Xnrg[b], 8), psSilk_VAD.NL[b] + 1) : Inlines.silk_DIV32(Xnrg[b], Inlines.silk_RSHIFT(psSilk_VAD.NL[b], 8) + 1); - SNR_Q7 = Inlines.silk_lin2log(NrgToNoiseRatio_Q8[b]) - 1024; - sumSquared = Inlines.silk_SMLABB(sumSquared, SNR_Q7, SNR_Q7); - if (speech_nrg < 0x100000) { - SNR_Q7 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(speech_nrg), 6), SNR_Q7); - } - input_tilt = Inlines.silk_SMLAWB(input_tilt, tiltWeights[b], SNR_Q7); - continue; - } - NrgToNoiseRatio_Q8[b] = 256; - } - sumSquared = Inlines.silk_DIV32_16(sumSquared, 4); - short pSNR_dB_Q7 = (short)(3 * Inlines.silk_SQRT_APPROX(sumSquared)); - int SA_Q15 = Sigmoid.silk_sigm_Q15(Inlines.silk_SMULWB(45000, pSNR_dB_Q7) - 128); - psEncC.input_tilt_Q15 = Inlines.silk_LSHIFT(Sigmoid.silk_sigm_Q15(input_tilt) - 16384, 1); - speech_nrg = 0; - for (b = 0; b < 4; ++b) { - speech_nrg += (b + 1) * Inlines.silk_RSHIFT(Xnrg[b] - psSilk_VAD.NL[b], 4); - } - if (speech_nrg <= 0) { - SA_Q15 = Inlines.silk_RSHIFT(SA_Q15, 1); - } else if (speech_nrg < 32768) { - speech_nrg = psEncC.frame_length == 10 * psEncC.fs_kHz ? Inlines.silk_LSHIFT_SAT32(speech_nrg, 16) : Inlines.silk_LSHIFT_SAT32(speech_nrg, 15); - speech_nrg = Inlines.silk_SQRT_APPROX(speech_nrg); - SA_Q15 = Inlines.silk_SMULWB(32768 + speech_nrg, SA_Q15); - } - psEncC.speech_activity_Q8 = Inlines.silk_min_int(Inlines.silk_RSHIFT(SA_Q15, 7), 255); - int smooth_coef_Q16 = Inlines.silk_SMULWB(4096, Inlines.silk_SMULWB(SA_Q15, SA_Q15)); - if (psEncC.frame_length == 10 * psEncC.fs_kHz) { - smooth_coef_Q16 >>= 1; - } - for (b = 0; b < 4; ++b) { - psSilk_VAD.NrgRatioSmth_Q8[b] = Inlines.silk_SMLAWB(psSilk_VAD.NrgRatioSmth_Q8[b], NrgToNoiseRatio_Q8[b] - psSilk_VAD.NrgRatioSmth_Q8[b], smooth_coef_Q16); - SNR_Q7 = 3 * (Inlines.silk_lin2log(psSilk_VAD.NrgRatioSmth_Q8[b]) - 1024); - psEncC.input_quality_bands_Q15[b] = Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT(SNR_Q7 - 2048, 4)); - } - return ret; - } - - static void silk_VAD_GetNoiseLevels(int[] pX, SilkVADState psSilk_VAD) { - int min_coef = psSilk_VAD.counter < 1000 ? Inlines.silk_DIV32_16(Short.MAX_VALUE, (short)(Inlines.silk_RSHIFT(psSilk_VAD.counter, 4) + 1)) : 0; - for (int k = 0; k < 4; ++k) { - int nl = psSilk_VAD.NL[k]; - Inlines.OpusAssert(nl >= 0); - int nrg = Inlines.silk_ADD_POS_SAT32(pX[k], psSilk_VAD.NoiseLevelBias[k]); - Inlines.OpusAssert(nrg > 0); - int inv_nrg = Inlines.silk_DIV32(Integer.MAX_VALUE, nrg); - Inlines.OpusAssert(inv_nrg >= 0); - int coef = nrg > Inlines.silk_LSHIFT(nl, 3) ? 128 : (nrg < nl ? 1024 : Inlines.silk_SMULWB(Inlines.silk_SMULWW(inv_nrg, nl), 2048)); - coef = Inlines.silk_max_int(coef, min_coef); - psSilk_VAD.inv_NL[k] = Inlines.silk_SMLAWB(psSilk_VAD.inv_NL[k], inv_nrg - psSilk_VAD.inv_NL[k], coef); - Inlines.OpusAssert(psSilk_VAD.inv_NL[k] >= 0); - nl = Inlines.silk_DIV32(Integer.MAX_VALUE, psSilk_VAD.inv_NL[k]); - Inlines.OpusAssert(nl >= 0); - psSilk_VAD.NL[k] = nl = Inlines.silk_min(nl, 0xFFFFFF); - } - ++psSilk_VAD.counter; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/concentus/VorbisLayout.java b/source/decompiled/de/maxhenkel/voicechat/concentus/VorbisLayout.java deleted file mode 100644 index e0cb934..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/concentus/VorbisLayout.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.concentus; - -class VorbisLayout { - int nb_streams; - int nb_coupled_streams; - short[] mapping; - static final VorbisLayout[] vorbis_mappings = new VorbisLayout[]{new VorbisLayout(1, 0, new short[]{0}), new VorbisLayout(1, 1, new short[]{0, 1}), new VorbisLayout(2, 1, new short[]{0, 2, 1}), new VorbisLayout(2, 2, new short[]{0, 1, 2, 3}), new VorbisLayout(3, 2, new short[]{0, 4, 1, 2, 3}), new VorbisLayout(4, 2, new short[]{0, 4, 1, 2, 3, 5}), new VorbisLayout(4, 3, new short[]{0, 4, 1, 2, 3, 5, 6}), new VorbisLayout(5, 3, new short[]{0, 6, 1, 2, 3, 4, 5, 7})}; - - VorbisLayout(int streams, int coupled_streams, short[] map) { - this.nb_streams = streams; - this.nb_coupled_streams = coupled_streams; - this.mapping = map; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/config/ServerConfig.java b/source/decompiled/de/maxhenkel/voicechat/config/ServerConfig.java deleted file mode 100644 index d467657..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/config/ServerConfig.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.config; - -import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.configbuilder.ConfigBuilder; -import de.maxhenkel.voicechat.configbuilder.entry.ConfigEntry; - -public class ServerConfig { - public final ConfigEntry voiceChatPort; - public final ConfigEntry voiceChatBindAddress; - public final ConfigEntry voiceChatDistance; - public ConfigEntry whisperDistance; - public final ConfigEntry voiceChatCodec; - public final ConfigEntry voiceChatMtuSize; - public final ConfigEntry tcpRateLimit; - public final ConfigEntry keepAlive; - public final ConfigEntry groupsEnabled; - public final ConfigEntry voiceHost; - public final ConfigEntry allowRecording; - public final ConfigEntry spectatorInteraction; - public ConfigEntry spectatorPlayerPossession; - public ConfigEntry forceVoiceChat; - public ConfigEntry loginTimeout; - public ConfigEntry broadcastRange; - public ConfigEntry allowPings; - public ConfigEntry threadedServerSupport; - - public ServerConfig(ConfigBuilder builder) { - builder.header(String.format("%s server config v%s", "Simple Voice Chat", Voicechat.INSTANCE.getDescription().getVersion())); - this.voiceChatPort = builder.integerEntry("port", (Integer)24454, -1, 65535, "The port number to use for the voice chat communication.", "Audio packets are always transmitted via the UDP protocol on the port number", "specified here, independently of other networking used for the game server.", "Set this to '-1' to use the same port number that is used by the Minecraft server.", "However, it is strongly recommended NOT to use the same port number because UDP on", "it is also used by default for the server query. Doing so may crash the server!"); - this.voiceChatBindAddress = builder.stringEntry("bind_address", "", "The server IP address to bind the voice chat to", "Leave blank to use the 'server-ip' property from the 'server.properties' config file", "To bind to the wildcard IP address, use '*'"); - this.voiceChatDistance = builder.doubleEntry("max_voice_distance", (Double)48.0, 1.0, 1000000.0, "The distance to which the voice can be heard"); - this.whisperDistance = builder.doubleEntry("whisper_distance", (Double)24.0, 1.0, 1000000.0, "The distance to which the voice can be heard when whispering"); - this.voiceChatCodec = builder.enumEntry("codec", Codec.VOIP, "The Opus codec", "Valid values are 'VOIP', 'AUDIO', and 'RESTRICTED_LOWDELAY'"); - this.voiceChatMtuSize = builder.integerEntry("mtu_size", (Integer)1275, 512, 2048, "The maximum size that audio packets are allowed to have (in bytes)", "Setting this to lower values might cause issues"); - this.tcpRateLimit = builder.integerEntry("tcp_rate_limit", (Integer)16, -1, 1024, "The maximum number of packets a player can send per second", "Set this to -1 to disable the rate limit - This must be greater than 0 in all other cases", "This only applies to voice chat packets that are sent through Minecrafts networking", "This affects actions like opening/joining/leaving voice chat groups or general state changes like disabling/enabling the voice chat"); - this.keepAlive = builder.integerEntry("keep_alive", (Integer)1000, 1000, Integer.MAX_VALUE, "The frequency at which keep-alive packets are sent (in milliseconds)", "Setting this to a higher value may result in timeouts"); - this.groupsEnabled = builder.booleanEntry("enable_groups", true, "If group chats are allowed"); - this.voiceHost = builder.stringEntry("voice_host", "", "The hostname that clients should use to connect to the voice chat", "This may also include a port, e.g. 'example.com:24454'", "Do NOT change this value if you don't know what you're doing"); - this.allowRecording = builder.booleanEntry("allow_recording", true, "If players are allowed to record the voice chat audio"); - this.spectatorInteraction = builder.booleanEntry("spectator_interaction", false, "If spectators are allowed to talk to other players"); - this.spectatorPlayerPossession = builder.booleanEntry("spectator_player_possession", false, "If spectators can talk to players they are spectating"); - this.forceVoiceChat = builder.booleanEntry("force_voice_chat", false, "If players without the voice chat mod should be kicked from the server"); - this.loginTimeout = builder.integerEntry("login_timeout", (Integer)10000, 100, Integer.MAX_VALUE, "The amount of time the server should wait to check if a player has the mod installed (in milliseconds)", "Only relevant when 'force_voice_chat' is set to 'true'"); - this.broadcastRange = builder.doubleEntry("broadcast_range", (Double)-1.0, -1.0, (Double)Double.MAX_VALUE, "The range in which the voice chat should broadcast audio", "A value less than 0 means 'max_voice_distance'"); - this.allowPings = builder.booleanEntry("allow_pings", true, "If the voice chat server should reply to external pings"); - this.threadedServerSupport = builder.booleanEntry("threaded_server_support", true, "If the voice chat should support servers that run multiple threads, like Folia", "Disabling this may slightly improve performance, but can cause issues on servers that don't run everything on a single thread"); - } - - public static enum Codec { - VOIP, - AUDIO, - RESTRICTED_LOWDELAY; - - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/config/Translations.java b/source/decompiled/de/maxhenkel/voicechat/config/Translations.java deleted file mode 100644 index 27207ef..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/config/Translations.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.config; - -import de.maxhenkel.voicechat.configbuilder.ConfigBuilder; -import de.maxhenkel.voicechat.configbuilder.entry.ConfigEntry; - -public class Translations { - public final ConfigEntry forceVoicechatKickMessage; - public final ConfigEntry rateLimitKickMessage; - public final ConfigEntry voicechatNotCompatibleMessage; - public final ConfigEntry voicechatNeededForCommandMessage; - public final ConfigEntry playerCommandMessage; - public final ConfigEntry placeholderVoicechatInstalled; - public final ConfigEntry placeholderVoicechatNotInstalled; - public final ConfigEntry placeholderVoicechatDisabled; - - public Translations(ConfigBuilder builder) { - builder.header("Simple Voice Chat translations", "This file contains all server-side translations for the Simple Voice Chat plugin"); - this.forceVoicechatKickMessage = builder.stringEntry("force_voicechat_kick_message", "You need %s %s to play on this server", "The message a player gets when kicked for not having voice chat installed and the server has force_voicechat enabled", "The first parameter is the mod/plugin name and the second parameter is the mod/plugin version"); - this.rateLimitKickMessage = builder.stringEntry("rate_limit_kick_message", "Kicked for exceeding packet rate limit", "The message a player gets when kicked for sending too many voice chat packets"); - this.voicechatNotCompatibleMessage = builder.stringEntry("voicechat_not_compatible_message", "Your voice chat client version is not compatible with the server-side version.\\nPlease install version %s of %s.", "The message a player gets when joining a server with an incompatible voice chat version", "The first parameter is the mod/plugin version and the second parameter is the mod/plugin name"); - this.voicechatNeededForCommandMessage = builder.stringEntry("voicechat_needed_for_command_message", "You need to have %s installed on your client to use this command", "The message a player gets when trying to execute a command that requires the voice chat mod installed on the client side.", "The first parameter is the mod/plugin name"); - this.playerCommandMessage = builder.stringEntry("player_command_message", "This command can only be executed as a player", "The message a player gets when trying to execute a command that can only be executed as a player"); - this.placeholderVoicechatInstalled = builder.stringEntry("placeholder_api_voicechat_installed", "", "The Placeholder API string for '%voicechat_installed%'"); - this.placeholderVoicechatNotInstalled = builder.stringEntry("placeholder_api_voicechat_not_installed", "", "The Placeholder API string for '%voicechat_not_installed%'"); - this.placeholderVoicechatDisabled = builder.stringEntry("placeholder_api_voicechat_disabled", "", "The Placeholder API string for '%voicechat_disabled%'"); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/CommentedProperties.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/CommentedProperties.java deleted file mode 100644 index c118ff1..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/CommentedProperties.java +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder; - -import java.io.BufferedReader; -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.StringReader; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nullable; - -public class CommentedProperties -implements Map { - private final boolean strict; - private final List headerComments; - private final Map properties; - - public CommentedProperties(boolean strict) { - this.strict = strict; - this.headerComments = new ArrayList(); - this.properties = new LinkedHashMap(); - } - - public CommentedProperties() { - this(true); - } - - public CommentedProperties addHeaderComment(String comment) { - this.headerComments.add(comment); - return this; - } - - public CommentedProperties setHeaderComments(List headerComments) { - this.headerComments.clear(); - this.headerComments.addAll(headerComments); - return this; - } - - void sort(Comparator comparator) { - ArrayList> list = new ArrayList>(this.properties.entrySet()); - list.sort((o1, o2) -> comparator.compare((String)o1.getKey(), (String)o2.getKey())); - this.properties.clear(); - for (Map.Entry entry : list) { - this.properties.put((String)entry.getKey(), (Property)entry.getValue()); - } - } - - @Nullable - public String get(String key) { - Objects.requireNonNull(key); - Property property = this.properties.get(key); - if (property == null) { - return null; - } - return property.value; - } - - @Nullable - public List getComments(String key) { - Objects.requireNonNull(key); - Property property = this.properties.get(key); - if (property == null) { - return null; - } - return property.comments; - } - - public CommentedProperties setComments(String key, List comments) { - Objects.requireNonNull(key); - Property property = this.properties.get(key); - if (property == null) { - this.properties.put(key, new Property(comments, "")); - return this; - } - property.comments = comments; - return this; - } - - public CommentedProperties set(String key, String value, String ... comments) { - Objects.requireNonNull(key); - Objects.requireNonNull(value); - this.properties.put(key, new Property(Arrays.asList(comments), value)); - return this; - } - - public CommentedProperties load(InputStream inputStream) throws IOException { - ArrayList headerComments = new ArrayList(); - LinkedHashMap properties = new LinkedHashMap(); - try (LineReader reader = LineReader.fromInputStream(inputStream);){ - String line; - boolean header = true; - ArrayList previousComments = new ArrayList(); - while ((line = reader.nextLine()) != null) { - if (line.trim().isEmpty()) { - if (!header) continue; - headerComments.addAll(previousComments); - previousComments.clear(); - header = false; - continue; - } - Pair pair = CommentedProperties.readLine(line); - if (pair.key == null) { - previousComments.add(pair.value); - continue; - } - Property property = new Property(pair.value); - property.comments.addAll(previousComments); - previousComments.clear(); - properties.put(pair.key, property); - header = false; - } - } - this.setHeaderComments(headerComments); - this.properties.clear(); - this.properties.putAll(properties); - return this; - } - - protected static Pair readLine(String line) throws IOException { - int c; - StringBuilder key = new StringBuilder(); - StringBuilder value = new StringBuilder(); - StringReader reader = new StringReader(line); - boolean isKey = true; - boolean isComment = false; - boolean isPrecedingBackslash = false; - boolean onlyHadWhitespace = true; - boolean isStartOfValue = false; - while ((c = reader.read()) != -1) { - boolean isWhitespace = CommentedProperties.isWhitespace(c); - if (isComment) { - if (onlyHadWhitespace && isWhitespace) continue; - onlyHadWhitespace = false; - value.append((char)c); - continue; - } - if (isPrecedingBackslash) { - if (isKey) { - key.append((char)CommentedProperties.readEscapedCharacter(c, reader)); - } else { - value.append((char)CommentedProperties.readEscapedCharacter(c, reader)); - } - isPrecedingBackslash = false; - isStartOfValue = false; - continue; - } - if (c == 92) { - isPrecedingBackslash = true; - continue; - } - if ((c == 35 || c == 33) && onlyHadWhitespace) { - isComment = true; - continue; - } - if (isKey) { - if (key.length() <= 0 && CommentedProperties.isWhitespace(c)) continue; - if (CommentedProperties.isSeparator(c)) { - isKey = false; - isStartOfValue = true; - onlyHadWhitespace = false; - continue; - } - if (CommentedProperties.isWhitespace(c)) continue; - key.append((char)c); - } else { - if (isStartOfValue && (CommentedProperties.isWhitespace(c) || CommentedProperties.isSeparator(c))) continue; - value.append((char)c); - isStartOfValue = false; - } - if (!onlyHadWhitespace || isWhitespace) continue; - onlyHadWhitespace = false; - } - return new Pair(isComment ? null : key.toString(), value.toString()); - } - - private static int readEscapedCharacter(int c, StringReader reader) throws IOException { - if (c == 117) { - int u = 0; - for (int i = 0; i < 4; ++i) { - int uc = reader.read(); - if (uc == -1) { - throw new IOException("Invalid unicode escape sequence"); - } - u <<= 4; - if (uc >= 48 && uc <= 57) { - u += uc - 48; - continue; - } - if (uc >= 97 && uc <= 102) { - u += uc - 97 + 10; - continue; - } - if (uc >= 65 && uc <= 70) { - u += uc - 65 + 10; - continue; - } - throw new IOException("Invalid unicode escape sequence"); - } - return u; - } - if (c == 116) { - return 9; - } - if (c == 114) { - return 13; - } - if (c == 110) { - return 10; - } - if (c == 102) { - return 12; - } - return c; - } - - private static boolean isWhitespace(int c) { - return c == 32 || c == 9 || c == 13 || c == 12 || Character.isWhitespace(c); - } - - private static boolean isSeparator(int c) { - return c == 61 || c == 58 || c == 32 || c == 9 || c == 12; - } - - public CommentedProperties save(OutputStream outputStream) { - try (PrintWriter writer = new PrintWriter(outputStream);){ - for (String string : CommentedProperties.removeNewLines(this.headerComments)) { - writer.print("# "); - writer.println(string); - } - if (this.headerComments.size() > 0) { - writer.println(); - } - for (Map.Entry entry : this.properties.entrySet()) { - for (String comment : CommentedProperties.removeNewLines(((Property)entry.getValue()).comments)) { - writer.print("# "); - writer.println(comment); - } - writer.print(this.escapeKey((String)entry.getKey())); - writer.print("="); - writer.println(this.escapeValue(((Property)entry.getValue()).value)); - } - writer.flush(); - } - return this; - } - - private static List removeNewLines(List comments) { - ArrayList newComments = new ArrayList(); - for (String comment : comments) { - newComments.addAll(Arrays.asList(comment.split("\\r?\\n"))); - } - return newComments; - } - - private String escapeKey(String str) { - str = this.escape(str); - str = str.replace(" ", "\\ "); - str = str.replace("=", "\\="); - str = str.replace(":", "\\:"); - return str; - } - - private String escapeValue(String str) { - str = this.escape(str); - if (this.strict) { - str = str.replace("=", "\\="); - str = str.replace(":", "\\:"); - } - if (str.startsWith(" ")) { - str = String.format("\\%s", str); - } - return str; - } - - private String escape(String str) { - str = str.replace("\\", "\\\\"); - str = str.replace("\n", "\\n"); - str = str.replace("\r", "\\n"); - str = str.replace("\t", "\\t"); - str = str.replace("#", "\\#"); - str = str.replace("!", "\\!"); - for (int i = 0; i < str.length(); ++i) { - char c = str.charAt(i); - if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.BASIC_LATIN) continue; - str = String.format("%s\\u%04X%s", str.substring(0, i), (int)c, str.substring(i + 1)); - } - return str; - } - - @Override - public int size() { - return this.properties.size(); - } - - @Override - public boolean isEmpty() { - return this.properties.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return this.properties.containsKey(key); - } - - @Override - @Deprecated - public boolean containsValue(Object value) { - for (Property property : this.properties.values()) { - if (!property.value.equals(value)) continue; - return true; - } - return false; - } - - @Override - @Nullable - @Deprecated - public String get(Object key) { - if (!(key instanceof String)) { - return null; - } - return this.get((String)key); - } - - @Override - @Deprecated - public String put(String key, String value) { - Objects.requireNonNull(key); - Objects.requireNonNull(value); - Property put = this.properties.put(key, new Property(value)); - if (put == null) { - return null; - } - return put.value; - } - - @Override - public String remove(Object key) { - Property removed = this.properties.remove(key); - if (removed == null) { - return null; - } - return removed.value; - } - - @Override - @Deprecated - public void putAll(Map map) { - for (Map.Entry entry : map.entrySet()) { - this.put(entry.getKey(), entry.getValue()); - } - } - - @Override - public void clear() { - this.headerComments.clear(); - this.properties.clear(); - } - - @Override - public Set keySet() { - return this.properties.keySet(); - } - - @Override - @Deprecated - public Collection values() { - return this.properties.values().stream().map(property -> ((Property)property).value).collect(Collectors.toList()); - } - - @Override - @Deprecated - public Set> entrySet() { - return this.properties.entrySet().stream().map(entry -> new AbstractMap.SimpleEntry((String)entry.getKey(), ((Property)entry.getValue()).value)).collect(Collectors.toSet()); - } - - protected static class Property { - private List comments; - private String value; - - public Property(List comments, String value) { - this.comments = comments; - this.value = value; - } - - public Property(String value) { - this(new ArrayList(), value); - } - } - - protected static class LineReader - implements Closeable { - private final BufferedReader reader; - - public LineReader(BufferedReader reader) { - this.reader = reader; - } - - public static LineReader fromInputStream(InputStream inputStream) { - return new LineReader(new BufferedReader(new InputStreamReader(inputStream))); - } - - @Nullable - public String nextLine() throws IOException { - String line = this.reader.readLine(); - if (line == null) { - return null; - } - if (line.endsWith("\\")) { - line = line.substring(0, line.length() - 1); - String nextLine = this.nextLine(); - if (nextLine == null) { - return line; - } - return line + nextLine; - } - return line; - } - - @Override - public void close() throws IOException { - this.reader.close(); - } - } - - protected static class Pair { - private String key; - private String value; - - public Pair(String key, String value) { - this.key = key; - this.value = value; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/CommentedPropertyConfig.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/CommentedPropertyConfig.java deleted file mode 100644 index b26328c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/CommentedPropertyConfig.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder; - -import de.maxhenkel.voicechat.configbuilder.CommentedProperties; -import de.maxhenkel.voicechat.configbuilder.Config; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.OpenOption; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.nio.file.attribute.FileAttribute; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.annotation.Nullable; - -public class CommentedPropertyConfig -implements Config { - private static final Logger LOGGER = Logger.getLogger(CommentedPropertyConfig.class.getName()); - private static final ExecutorService SAVE_EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(runnable -> { - Thread thread = new Thread(runnable); - thread.setName("ConfigSaver"); - thread.setDaemon(true); - return thread; - }); - protected CommentedProperties properties; - @Nullable - protected Path path; - - protected CommentedPropertyConfig(CommentedProperties properties) { - this.properties = properties; - } - - public static Builder builder() { - return new Builder(); - } - - public String get(String key) { - return this.properties.get(key); - } - - public boolean has(String key) { - return this.properties.containsKey(key); - } - - public void set(String key, String value, String ... comments) { - this.properties.set(key, value, comments); - } - - public CommentedProperties getProperties() { - return this.properties; - } - - public void load() throws IOException { - if (this.path == null) { - return; - } - if (Files.exists(this.path, new LinkOption[0])) { - try (InputStream inputStream = Files.newInputStream(this.path, new OpenOption[0]);){ - this.properties.load(inputStream); - } - } - } - - public void reload() { - this.properties.clear(); - try { - this.load(); - } - catch (IOException e) { - LOGGER.log(Level.SEVERE, "Failed to reload config", e); - } - } - - public synchronized void saveSync() { - if (this.path == null) { - return; - } - try { - Files.createDirectories(this.path.getParent(), new FileAttribute[0]); - } - catch (Exception e) { - LOGGER.log(Level.SEVERE, "Failed to create parent directories of config", e); - } - try (OutputStream stream = Files.newOutputStream(this.path, StandardOpenOption.CREATE, StandardOpenOption.SYNC, StandardOpenOption.TRUNCATE_EXISTING);){ - this.properties.save(stream); - } - catch (Exception e) { - LOGGER.log(Level.SEVERE, "Failed to save config", e); - } - } - - public void save() { - if (this.path == null) { - return; - } - SAVE_EXECUTOR_SERVICE.execute(this::saveSync); - } - - @Override - public Map getEntries() { - return Collections.unmodifiableMap(this.properties); - } - - public static class Builder { - @Nullable - private Path path; - private boolean strict = true; - - private Builder() { - } - - public Builder path(Path path) { - this.path = path; - return this; - } - - public Builder strict(boolean strict) { - this.strict = strict; - return this; - } - - public CommentedPropertyConfig build() { - CommentedPropertyConfig config = new CommentedPropertyConfig(new CommentedProperties(this.strict)); - if (this.path != null) { - config.path = this.path.toAbsolutePath(); - } - config.reload(); - return config; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/Config.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/Config.java deleted file mode 100644 index 22e9990..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/Config.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder; - -import java.util.Map; - -public interface Config { - public Map getEntries(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/ConfigBuilder.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/ConfigBuilder.java deleted file mode 100644 index 1d6329f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/ConfigBuilder.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nonnull - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.ConfigBuilderImpl; -import de.maxhenkel.voicechat.configbuilder.MigratableConfig; -import de.maxhenkel.voicechat.configbuilder.MigratableConfigImpl; -import de.maxhenkel.voicechat.configbuilder.entry.BooleanConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.ConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.DoubleConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.EnumConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.FloatConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.IntegerConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.LongConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.StringConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; -import java.util.function.Function; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public interface ConfigBuilder { - public ConfigBuilder header(String ... var1); - - public BooleanConfigEntry booleanEntry(String var1, Boolean var2, String ... var3); - - public IntegerConfigEntry integerEntry(String var1, Integer var2, Integer var3, Integer var4, String ... var5); - - default public IntegerConfigEntry integerEntry(String key, Integer def, String ... comments) { - return this.integerEntry(key, def, (Integer)null, (Integer)null, comments); - } - - public LongConfigEntry longEntry(String var1, Long var2, Long var3, Long var4, String ... var5); - - default public LongConfigEntry longEntry(String key, Long def, String ... comments) { - return this.longEntry(key, def, (Long)null, (Long)null, comments); - } - - public DoubleConfigEntry doubleEntry(String var1, Double var2, Double var3, Double var4, String ... var5); - - default public DoubleConfigEntry doubleEntry(String key, Double def, String ... comments) { - return this.doubleEntry(key, def, (Double)null, (Double)null, comments); - } - - public FloatConfigEntry floatEntry(String var1, Float var2, Float var3, Float var4, String ... var5); - - default public FloatConfigEntry floatEntry(String key, Float def, String ... comments) { - return this.floatEntry(key, def, (Float)null, (Float)null, comments); - } - - public StringConfigEntry stringEntry(String var1, String var2, String ... var3); - - public > EnumConfigEntry enumEntry(String var1, E var2, String ... var3); - - public ConfigEntry entry(String var1, T var2, String ... var3); - - public static Builder builder(@Nonnull Function builderConsumer) { - return new Builder(builderConsumer); - } - - public static class Builder { - @Nonnull - private final Function builderConsumer; - @Nullable - private Path path; - private final Map, ValueSerializer> valueSerializers; - private boolean removeUnused; - private boolean strict; - private boolean keepOrder; - private boolean saveAfterBuild; - private boolean saveSyncAfterBuild; - @Nullable - private Consumer migration; - - private Builder(@Nonnull Function builderConsumer) { - this.builderConsumer = builderConsumer; - this.valueSerializers = new HashMap(); - this.removeUnused = true; - this.strict = false; - this.keepOrder = true; - this.saveAfterBuild = true; - this.saveSyncAfterBuild = false; - } - - public Builder path(Path path) { - this.path = path; - return this; - } - - public Builder addValueSerializer(Class type, ValueSerializer serializer) { - this.valueSerializers.put(type, serializer); - return this; - } - - public Builder removeUnused(boolean removeUnused) { - this.removeUnused = removeUnused; - return this; - } - - public Builder strict(boolean strict) { - this.strict = strict; - return this; - } - - public Builder keepOrder(boolean keepOrder) { - this.keepOrder = keepOrder; - return this; - } - - public Builder saveAfterBuild(boolean saveAfterBuild) { - this.saveAfterBuild = saveAfterBuild; - if (saveAfterBuild) { - this.saveSyncAfterBuild = false; - } - return this; - } - - public Builder saveSyncAfterBuild(boolean saveSyncAfterBuild) { - this.saveSyncAfterBuild = saveSyncAfterBuild; - if (saveSyncAfterBuild) { - this.saveAfterBuild = false; - } - return this; - } - - public Builder migration(Consumer migration) { - this.migration = migration; - return this; - } - - public C build() { - CommentedPropertyConfig cpc = CommentedPropertyConfig.builder().path(this.path).strict(this.strict).build(); - if (this.migration != null && this.path != null && Files.exists(this.path, new LinkOption[0])) { - MigratableConfigImpl migratableConfig = new MigratableConfigImpl(cpc); - this.migration.accept(migratableConfig); - migratableConfig.freeze(); - } - ConfigBuilderImpl builder = new ConfigBuilderImpl(cpc, this.valueSerializers); - C config = this.builderConsumer.apply(builder); - builder.freeze(); - if (this.removeUnused) { - builder.removeUnused(); - } - if (this.keepOrder) { - builder.sortEntries(); - } - if (this.saveAfterBuild) { - builder.config.save(); - } else if (this.saveSyncAfterBuild) { - builder.config.saveSync(); - } - return config; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/ConfigBuilderImpl.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/ConfigBuilderImpl.java deleted file mode 100644 index f9c7158..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/ConfigBuilderImpl.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.ConfigBuilder; -import de.maxhenkel.voicechat.configbuilder.custom.IntegerList; -import de.maxhenkel.voicechat.configbuilder.custom.StringList; -import de.maxhenkel.voicechat.configbuilder.custom.StringMap; -import de.maxhenkel.voicechat.configbuilder.custom.serializer.IntegerListValueSerializer; -import de.maxhenkel.voicechat.configbuilder.custom.serializer.StringListValueSerializer; -import de.maxhenkel.voicechat.configbuilder.custom.serializer.StringMapValueSerializer; -import de.maxhenkel.voicechat.configbuilder.custom.serializer.UUIDSerializer; -import de.maxhenkel.voicechat.configbuilder.entry.AbstractConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.BooleanConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.ConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.DoubleConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.EnumConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.FloatConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.GenericConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.IntegerConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.LongConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.StringConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.BooleanSerializer; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.DoubleSerializer; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.EnumSerializer; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.FloatSerializer; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.IntegerSerializer; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.LongSerializer; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.StringSerializer; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializable; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; -import javax.annotation.Nullable; - -public class ConfigBuilderImpl -implements ConfigBuilder { - protected final CommentedPropertyConfig config; - protected final Map, ValueSerializer> valueSerializers; - protected List> entries; - protected boolean frozen; - - public ConfigBuilderImpl(CommentedPropertyConfig config) { - this(config, null); - } - - public ConfigBuilderImpl(CommentedPropertyConfig config, @Nullable Map, ValueSerializer> customValueSerializers) { - this.config = config; - this.valueSerializers = ConfigBuilderImpl.getDefaultValueSerializers(); - if (customValueSerializers != null) { - this.valueSerializers.putAll(customValueSerializers); - } - this.entries = new ArrayList(); - } - - void removeUnused() { - List existingKeys = this.entries.stream().map(AbstractConfigEntry::getKey).collect(Collectors.toList()); - List toRemove = this.config.getProperties().keySet().stream().filter(s -> !existingKeys.contains(s)).collect(Collectors.toList()); - for (String key : toRemove) { - this.config.getProperties().remove(key); - } - } - - void sortEntries() { - HashMap map = new HashMap(); - for (int i = 0; i < this.entries.size(); ++i) { - map.put(this.entries.get(i).getKey(), i); - } - this.config.getProperties().sort(Comparator.comparingInt(o -> map.getOrDefault(o, Integer.MAX_VALUE))); - } - - void reloadFromDisk() { - this.config.reload(); - this.entries.forEach(AbstractConfigEntry::reload); - } - - void freeze() { - this.frozen = true; - } - - void checkFrozen() { - if (this.frozen) { - throw new IllegalStateException("ConfigBuilder is frozen"); - } - } - - @Override - public ConfigBuilderImpl header(String ... header) { - this.checkFrozen(); - this.config.getProperties().setHeaderComments(Arrays.asList(header)); - return this; - } - - @Override - public BooleanConfigEntry booleanEntry(String key, Boolean def, String ... comments) { - this.checkFrozen(); - BooleanConfigEntry entry = new BooleanConfigEntry(this.config, BooleanSerializer.INSTANCE, comments, key, def); - this.entries.add(entry); - return entry; - } - - @Override - public IntegerConfigEntry integerEntry(String key, Integer def, Integer min, Integer max, String ... comments) { - this.checkFrozen(); - IntegerConfigEntry entry = new IntegerConfigEntry(this.config, IntegerSerializer.INSTANCE, comments, key, def, min, max); - this.entries.add(entry); - return entry; - } - - @Override - public LongConfigEntry longEntry(String key, Long def, Long min, Long max, String ... comments) { - this.checkFrozen(); - LongConfigEntry entry = new LongConfigEntry(this.config, LongSerializer.INSTANCE, comments, key, def, min, max); - this.entries.add(entry); - return entry; - } - - @Override - public DoubleConfigEntry doubleEntry(String key, Double def, Double min, Double max, String ... comments) { - this.checkFrozen(); - DoubleConfigEntry entry = new DoubleConfigEntry(this.config, DoubleSerializer.INSTANCE, comments, key, def, min, max); - this.entries.add(entry); - return entry; - } - - @Override - public FloatConfigEntry floatEntry(String key, Float def, Float min, Float max, String ... comments) { - this.checkFrozen(); - FloatConfigEntry entry = new FloatConfigEntry(this.config, FloatSerializer.INSTANCE, comments, key, def, min, max); - this.entries.add(entry); - return entry; - } - - @Override - public StringConfigEntry stringEntry(String key, String def, String ... comments) { - this.checkFrozen(); - StringConfigEntry entry = new StringConfigEntry(this.config, StringSerializer.INSTANCE, comments, key, def); - this.entries.add(entry); - return entry; - } - - @Override - public > EnumConfigEntry enumEntry(String key, E def, String ... comments) { - this.checkFrozen(); - EnumConfigEntry entry = new EnumConfigEntry(this.config, new EnumSerializer(def.getClass()), comments, key, def); - this.entries.add(entry); - return entry; - } - - @Override - public ConfigEntry entry(String key, T def, String ... comments) { - this.checkFrozen(); - AbstractConfigEntry entry = this.entryInternal(key, def, comments); - this.entries.add(entry); - return entry; - } - - private AbstractConfigEntry entryInternal(String key, T def, String ... comments) { - ValueSerializer valueSerializer = this.valueSerializers.get(def.getClass()); - if (valueSerializer != null) { - return new GenericConfigEntry(this.config, valueSerializer, comments, key, def); - } - if (def instanceof Enum) { - return this.enumEntry(key, (Enum)def, comments); - } - try { - ValueSerializable annotation = def.getClass().getDeclaredAnnotation(ValueSerializable.class); - if (annotation == null) { - throw new IllegalArgumentException(String.format("Unsupported data type: %s", def.getClass().getName())); - } - Class> entryConverterClass = annotation.value(); - Constructor> constructor = entryConverterClass.getDeclaredConstructor(new Class[0]); - constructor.setAccessible(true); - constructor.newInstance(new Object[0]); - ValueSerializer converter = constructor.newInstance(new Object[0]); - return new GenericConfigEntry(this.config, converter, comments, key, def); - } - catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { - throw new IllegalArgumentException("Could not instantiate value serializer", e); - } - } - - protected static Map, ValueSerializer> getDefaultValueSerializers() { - HashMap valueSerializers = new HashMap(); - valueSerializers.put(Boolean.class, new BooleanSerializer()); - valueSerializers.put(Integer.class, new IntegerSerializer()); - valueSerializers.put(Long.class, new LongSerializer()); - valueSerializers.put(Float.class, new FloatSerializer()); - valueSerializers.put(Double.class, new DoubleSerializer()); - valueSerializers.put(String.class, new StringSerializer()); - valueSerializers.put(UUID.class, UUIDSerializer.INSTANCE); - valueSerializers.put(StringList.class, StringListValueSerializer.INSTANCE); - valueSerializers.put(IntegerList.class, IntegerListValueSerializer.INSTANCE); - valueSerializers.put(StringMap.class, StringMapValueSerializer.INSTANCE); - return valueSerializers; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/MigratableConfig.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/MigratableConfig.java deleted file mode 100644 index ecaf694..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/MigratableConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder; - -import de.maxhenkel.voicechat.configbuilder.Config; -import javax.annotation.Nullable; - -public interface MigratableConfig -extends Config { - @Nullable - public String get(String var1); - - public boolean has(String var1); - - public void set(String var1, String var2); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/MigratableConfigImpl.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/MigratableConfigImpl.java deleted file mode 100644 index d5a8f4f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/MigratableConfigImpl.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.MigratableConfig; -import java.util.Map; -import javax.annotation.Nullable; - -class MigratableConfigImpl -implements MigratableConfig { - private final CommentedPropertyConfig config; - private boolean frozen; - - public MigratableConfigImpl(CommentedPropertyConfig config) { - this.config = config; - } - - @Override - @Nullable - public String get(String key) { - this.checkFrozen(); - return this.config.get(key); - } - - @Override - public boolean has(String key) { - this.checkFrozen(); - return this.config.has(key); - } - - @Override - public void set(String key, String value) { - this.checkFrozen(); - this.config.set(key, value, new String[0]); - } - - @Override - public Map getEntries() { - this.checkFrozen(); - return this.config.getEntries(); - } - - public void freeze() { - this.frozen = true; - } - - private void checkFrozen() { - if (this.frozen) { - throw new IllegalStateException("ConfigBuilder is frozen"); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/AbstractValueList.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/AbstractValueList.java deleted file mode 100644 index 97f8bc3..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/AbstractValueList.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.custom; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Objects; - -public abstract class AbstractValueList -implements List { - protected final List list; - - protected AbstractValueList(T ... values) { - this(Arrays.asList(values)); - } - - protected AbstractValueList(List values) { - this.list = Collections.unmodifiableList(values); - } - - @Override - public int size() { - return this.list.size(); - } - - @Override - public boolean isEmpty() { - return this.list.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return this.list.contains(o); - } - - @Override - public Iterator iterator() { - return this.list.iterator(); - } - - @Override - public Object[] toArray() { - return this.list.toArray(); - } - - @Override - public T[] toArray(T[] a) { - return this.list.toArray(a); - } - - @Override - public boolean add(T s) { - return (Boolean)AbstractValueList.throwException(); - } - - @Override - public boolean remove(Object o) { - return (Boolean)AbstractValueList.throwException(); - } - - @Override - public boolean containsAll(Collection c) { - return this.list.containsAll(c); - } - - @Override - public boolean addAll(Collection c) { - return (Boolean)AbstractValueList.throwException(); - } - - @Override - public boolean addAll(int index, Collection c) { - return (Boolean)AbstractValueList.throwException(); - } - - @Override - public boolean removeAll(Collection c) { - return (Boolean)AbstractValueList.throwException(); - } - - @Override - public boolean retainAll(Collection c) { - return (Boolean)AbstractValueList.throwException(); - } - - @Override - public void clear() { - AbstractValueList.throwException(); - } - - @Override - public T get(int index) { - return this.list.get(index); - } - - @Override - public T set(int index, T element) { - return AbstractValueList.throwException(); - } - - @Override - public void add(int index, T element) { - AbstractValueList.throwException(); - } - - @Override - public T remove(int index) { - return AbstractValueList.throwException(); - } - - @Override - public int indexOf(Object o) { - return this.list.indexOf(o); - } - - @Override - public int lastIndexOf(Object o) { - return this.list.lastIndexOf(o); - } - - @Override - public ListIterator listIterator() { - return this.list.listIterator(); - } - - @Override - public ListIterator listIterator(int index) { - return this.list.listIterator(index); - } - - @Override - public List subList(int fromIndex, int toIndex) { - return this.list.subList(fromIndex, toIndex); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || this.getClass() != o.getClass()) { - return false; - } - AbstractValueList that = (AbstractValueList)o; - return Objects.equals(this.list, that.list); - } - - @Override - public int hashCode() { - return this.list.hashCode(); - } - - private static T throwException() { - throw new UnsupportedOperationException("Can't modify config entries"); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/AbstractValueMap.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/AbstractValueMap.java deleted file mode 100644 index df4022c..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/AbstractValueMap.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.custom; - -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; - -public class AbstractValueMap -implements Map { - protected final Map map; - - protected AbstractValueMap(Map map) { - this.map = Collections.unmodifiableMap(new LinkedHashMap(map)); - } - - @Override - public int size() { - return this.map.size(); - } - - @Override - public boolean isEmpty() { - return this.map.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return this.map.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return this.map.containsValue(value); - } - - @Override - public V get(Object key) { - return this.map.get(key); - } - - @Override - public V put(K key, V value) { - return (V)AbstractValueMap.throwException(); - } - - @Override - public V remove(Object key) { - return (V)AbstractValueMap.throwException(); - } - - @Override - public void putAll(Map m) { - AbstractValueMap.throwException(); - } - - @Override - public void clear() { - AbstractValueMap.throwException(); - } - - @Override - public Set keySet() { - return this.map.keySet(); - } - - @Override - public Collection values() { - return this.map.values(); - } - - @Override - public Set> entrySet() { - return this.map.entrySet(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || this.getClass() != o.getClass()) { - return false; - } - AbstractValueMap that = (AbstractValueMap)o; - return this.map.equals(that.map); - } - - @Override - public int hashCode() { - return this.map.hashCode(); - } - - private static T throwException() { - throw new UnsupportedOperationException("Can't modify config entries"); - } - - public static abstract class Builder> { - protected final Map map = new LinkedHashMap(); - - protected Builder() { - } - - public Builder put(K key, V value) { - this.map.put(key, value); - return this; - } - - public Builder putAll(Map map) { - this.map.putAll(map); - return this; - } - - public abstract M build(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/IntegerList.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/IntegerList.java deleted file mode 100644 index 3421cab..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/IntegerList.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.custom; - -import de.maxhenkel.voicechat.configbuilder.custom.AbstractValueList; -import java.util.List; - -public class IntegerList -extends AbstractValueList { - protected IntegerList(Integer ... values) { - super(values); - } - - protected IntegerList(List values) { - super(values); - } - - public static IntegerList of(Integer ... values) { - return new IntegerList(values); - } - - public static IntegerList of(List values) { - return new IntegerList(values); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/StringList.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/StringList.java deleted file mode 100644 index f279aab..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/StringList.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.custom; - -import de.maxhenkel.voicechat.configbuilder.custom.AbstractValueList; -import java.util.List; - -public class StringList -extends AbstractValueList { - protected StringList(String ... values) { - super(values); - } - - protected StringList(List values) { - super(values); - } - - public static StringList of(String ... values) { - return new StringList(values); - } - - public static StringList of(List values) { - return new StringList(values); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/StringMap.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/StringMap.java deleted file mode 100644 index de730d0..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/StringMap.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.custom; - -import de.maxhenkel.voicechat.configbuilder.custom.AbstractValueMap; -import java.util.Collections; -import java.util.Map; - -public class StringMap -extends AbstractValueMap { - protected StringMap(Map map) { - super(map); - } - - public static StringMap of(Map map) { - return new StringMap(map); - } - - public static StringMap of() { - return new StringMap(Collections.emptyMap()); - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder - extends AbstractValueMap.Builder { - @Override - public StringMap build() { - return new StringMap(this.map); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/IntegerListValueSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/IntegerListValueSerializer.java deleted file mode 100644 index e132604..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/IntegerListValueSerializer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.custom.serializer; - -import de.maxhenkel.voicechat.configbuilder.custom.IntegerList; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import java.util.ArrayList; -import javax.annotation.Nullable; - -public class IntegerListValueSerializer -implements ValueSerializer { - public static final IntegerListValueSerializer INSTANCE = new IntegerListValueSerializer(); - - @Override - @Nullable - public IntegerList deserialize(String str) { - ArrayList resultList = new ArrayList(); - for (String s : str.split(",")) { - try { - resultList.add(Integer.valueOf(s)); - } - catch (NumberFormatException e) { - return null; - } - } - return IntegerList.of(resultList); - } - - @Override - public String serialize(IntegerList val) { - ArrayList resultList = new ArrayList(val.size()); - for (Integer i : val) { - resultList.add(String.valueOf(i)); - } - return String.join((CharSequence)",", resultList); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/StringListValueSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/StringListValueSerializer.java deleted file mode 100644 index 793b41a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/StringListValueSerializer.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.custom.serializer; - -import de.maxhenkel.voicechat.configbuilder.custom.StringList; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import java.util.ArrayList; - -public class StringListValueSerializer -implements ValueSerializer { - public static final StringListValueSerializer INSTANCE = new StringListValueSerializer(); - - @Override - public StringList deserialize(String str) { - ArrayList resultList = new ArrayList(); - for (String s : str.split("(? resultList = new ArrayList(val.size()); - for (String str : val) { - resultList.add(str.replace(",", "\\,")); - } - return String.join((CharSequence)",", resultList); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/StringMapValueSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/StringMapValueSerializer.java deleted file mode 100644 index e3822a0..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/StringMapValueSerializer.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.custom.serializer; - -import de.maxhenkel.voicechat.configbuilder.custom.StringMap; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.annotation.Nullable; - -public class StringMapValueSerializer -implements ValueSerializer { - public static final StringMapValueSerializer INSTANCE = new StringMapValueSerializer(); - public static final Pattern QUOTE_ESCAPE_PATTERN = Pattern.compile("\"((?:(?![\"\\\\]).|\\\\.)*)\"\\s*=\\s*\"((?:(?![\"\\\\]).|\\\\.)*)\""); - - @Override - @Nullable - public StringMap deserialize(String str) { - boolean matches = QUOTE_ESCAPE_PATTERN.splitAsStream(str).allMatch(s -> s.trim().isEmpty() || s.trim().equals(",")); - if (!matches) { - return null; - } - LinkedHashMap map = new LinkedHashMap(); - Matcher matcher = QUOTE_ESCAPE_PATTERN.matcher(str); - while (matcher.find()) { - map.put(StringMapValueSerializer.unescape(matcher.group(1)), StringMapValueSerializer.unescape(matcher.group(2))); - } - return StringMap.of(map); - } - - @Override - public String serialize(StringMap val) { - ArrayList resultList = new ArrayList(val.size()); - for (Map.Entry entry : val.entrySet()) { - resultList.add("\"" + StringMapValueSerializer.escape((String)entry.getKey()) + "\"=\"" + StringMapValueSerializer.escape((String)entry.getValue()) + "\""); - } - return String.join((CharSequence)",", resultList); - } - - private static String escape(String input) { - return input.replace("\\", "\\\\").replace("\"", "\\\""); - } - - private static String unescape(String input) { - return input.replace("\\\"", "\"").replace("\\\\", "\\"); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/UUIDSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/UUIDSerializer.java deleted file mode 100644 index a0d4593..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/custom/serializer/UUIDSerializer.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.custom.serializer; - -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import java.util.UUID; - -public class UUIDSerializer -implements ValueSerializer { - public static final UUIDSerializer INSTANCE = new UUIDSerializer(); - - @Override - public UUID deserialize(String str) { - return UUID.fromString(str); - } - - @Override - public String serialize(UUID val) { - return val.toString(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/AbstractConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/AbstractConfigEntry.java deleted file mode 100644 index 8ed87e8..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/AbstractConfigEntry.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.Config; -import de.maxhenkel.voicechat.configbuilder.entry.ConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import java.util.Objects; -import javax.annotation.Nullable; - -public abstract class AbstractConfigEntry -implements ConfigEntry { - protected final CommentedPropertyConfig config; - protected final ValueSerializer serializer; - protected String[] comments; - protected String key; - protected T def; - @Nullable - protected T value; - - public AbstractConfigEntry(CommentedPropertyConfig config, ValueSerializer serializer, String[] comments, String key, T def) { - Objects.requireNonNull(config); - Objects.requireNonNull(serializer); - Objects.requireNonNull(comments); - Objects.requireNonNull(key); - Objects.requireNonNull(def); - this.config = config; - this.serializer = serializer; - this.comments = comments; - this.key = key; - this.def = def; - } - - public void reload() { - if (this.config.getProperties().containsKey(this.key)) { - T val = this.serializer.deserialize(this.config.getProperties().get(this.key)); - if (val == null) { - this.reset(); - } else { - this.value = this.fixValue(val); - this.syncEntryToProperties(); - } - } else { - this.reset(); - } - } - - @Override - public T get() { - return this.value; - } - - @Override - public AbstractConfigEntry set(T value) { - if (this.value != null && this.value.equals(value)) { - return this; - } - this.value = this.fixValue(value); - this.syncEntryToProperties(); - return this; - } - - @Override - public String getKey() { - return this.key; - } - - @Override - public AbstractConfigEntry comment(String ... comments) { - this.comments = comments; - this.syncEntryToProperties(); - return this; - } - - @Override - public String[] getComments() { - return this.comments; - } - - @Override - public ConfigEntry reset() { - this.value = this.def; - this.syncEntryToProperties(); - return this; - } - - private void syncEntryToProperties() { - String serialized = this.serializer.serialize(this.value); - if (serialized == null) { - if (this.value == this.def) { - throw new IllegalStateException("Failed to serialize default value"); - } - this.reset(); - return; - } - this.config.getProperties().set(this.key, serialized, this.comments); - } - - @Override - public ConfigEntry save() { - this.config.save(); - return this; - } - - @Override - public ConfigEntry saveSync() { - this.config.saveSync(); - return this; - } - - T fixValue(T value) { - return value; - } - - @Override - public T getDefault() { - return this.def; - } - - @Override - public Config getConfig() { - return this.config; - } - - public ValueSerializer getSerializer() { - return this.serializer; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/AbstractRangedConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/AbstractRangedConfigEntry.java deleted file mode 100644 index 5f2a066..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/AbstractRangedConfigEntry.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nonnull - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.entry.AbstractConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.RangedConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public abstract class AbstractRangedConfigEntry -extends AbstractConfigEntry -implements RangedConfigEntry { - @Nonnull - protected final T min; - @Nonnull - protected final T max; - - public AbstractRangedConfigEntry(CommentedPropertyConfig config, ValueSerializer serializer, String[] comments, String key, T def, @Nullable T min, @Nullable T max) { - super(config, serializer, comments, key, def); - this.min = min != null ? min : this.minimumPossibleValue(); - this.max = max != null ? max : this.maximumPossibleValue(); - } - - @Override - @Nonnull - public T getMin() { - return this.min; - } - - @Override - @Nonnull - public T getMax() { - return this.max; - } - - @Nonnull - abstract T minimumPossibleValue(); - - @Nonnull - abstract T maximumPossibleValue(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/BooleanConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/BooleanConfigEntry.java deleted file mode 100644 index 6e432b1..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/BooleanConfigEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.entry.AbstractConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; - -public class BooleanConfigEntry -extends AbstractConfigEntry { - public BooleanConfigEntry(CommentedPropertyConfig config, ValueSerializer serializer, String[] comments, String key, Boolean def) { - super(config, serializer, comments, key, def); - this.reload(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/ConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/ConfigEntry.java deleted file mode 100644 index 1da2262..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/ConfigEntry.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.Config; - -public interface ConfigEntry { - public ConfigEntry comment(String ... var1); - - public String[] getComments(); - - public T get(); - - public ConfigEntry set(T var1); - - public String getKey(); - - public ConfigEntry reset(); - - public ConfigEntry save(); - - public ConfigEntry saveSync(); - - public T getDefault(); - - public Config getConfig(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/DoubleConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/DoubleConfigEntry.java deleted file mode 100644 index da2d53f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/DoubleConfigEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nonnull - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.entry.AbstractRangedConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class DoubleConfigEntry -extends AbstractRangedConfigEntry { - public DoubleConfigEntry(CommentedPropertyConfig config, ValueSerializer serializer, String[] comments, String key, Double def, @Nullable Double min, @Nullable Double max) { - super(config, serializer, comments, key, def, min, max); - this.reload(); - } - - @Override - @Nonnull - Double minimumPossibleValue() { - return Double.MIN_VALUE; - } - - @Override - @Nonnull - Double maximumPossibleValue() { - return Double.MAX_VALUE; - } - - @Override - Double fixValue(Double value) { - return Math.max(Math.min(value, (Double)this.max), (Double)this.min); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/EnumConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/EnumConfigEntry.java deleted file mode 100644 index c3981e8..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/EnumConfigEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.entry.AbstractConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; - -public class EnumConfigEntry> -extends AbstractConfigEntry { - public EnumConfigEntry(CommentedPropertyConfig config, ValueSerializer serializer, String[] comments, String key, E def) { - super(config, serializer, comments, key, def); - this.reload(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/FloatConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/FloatConfigEntry.java deleted file mode 100644 index 53442b8..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/FloatConfigEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nonnull - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.entry.AbstractRangedConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class FloatConfigEntry -extends AbstractRangedConfigEntry { - public FloatConfigEntry(CommentedPropertyConfig config, ValueSerializer serializer, String[] comments, String key, Float def, @Nullable Float min, @Nullable Float max) { - super(config, serializer, comments, key, def, min, max); - this.reload(); - } - - @Override - @Nonnull - Float minimumPossibleValue() { - return Float.valueOf(Float.MIN_VALUE); - } - - @Override - @Nonnull - Float maximumPossibleValue() { - return Float.valueOf(Float.MAX_VALUE); - } - - @Override - Float fixValue(Float value) { - return Float.valueOf(Math.max(Math.min(value.floatValue(), ((Float)this.max).floatValue()), ((Float)this.min).floatValue())); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/GenericConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/GenericConfigEntry.java deleted file mode 100644 index 9abe5b6..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/GenericConfigEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.entry.AbstractConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; - -public class GenericConfigEntry -extends AbstractConfigEntry { - public GenericConfigEntry(CommentedPropertyConfig config, ValueSerializer serializer, String[] comments, String key, T def) { - super(config, serializer, comments, key, def); - this.reload(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/IntegerConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/IntegerConfigEntry.java deleted file mode 100644 index 2fc1cfe..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/IntegerConfigEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nonnull - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.entry.AbstractRangedConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class IntegerConfigEntry -extends AbstractRangedConfigEntry { - public IntegerConfigEntry(CommentedPropertyConfig config, ValueSerializer serializer, String[] comments, String key, Integer def, @Nullable Integer min, @Nullable Integer max) { - super(config, serializer, comments, key, def, min, max); - this.reload(); - } - - @Override - @Nonnull - Integer minimumPossibleValue() { - return Integer.MIN_VALUE; - } - - @Override - @Nonnull - Integer maximumPossibleValue() { - return Integer.MAX_VALUE; - } - - @Override - Integer fixValue(Integer value) { - return Math.max(Math.min(value, (Integer)this.max), (Integer)this.min); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/LongConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/LongConfigEntry.java deleted file mode 100644 index 868ef97..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/LongConfigEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nonnull - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.entry.AbstractRangedConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class LongConfigEntry -extends AbstractRangedConfigEntry { - public LongConfigEntry(CommentedPropertyConfig config, ValueSerializer serializer, String[] comments, String key, Long def, @Nullable Long min, @Nullable Long max) { - super(config, serializer, comments, key, def, min, max); - this.reload(); - } - - @Override - @Nonnull - Long minimumPossibleValue() { - return Long.MIN_VALUE; - } - - @Override - @Nonnull - Long maximumPossibleValue() { - return Long.MAX_VALUE; - } - - @Override - Long fixValue(Long value) { - return Math.max(Math.min(value, (Long)this.max), (Long)this.min); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/RangedConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/RangedConfigEntry.java deleted file mode 100644 index ebe99ed..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/RangedConfigEntry.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nonnull - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.entry.ConfigEntry; -import javax.annotation.Nonnull; - -public interface RangedConfigEntry -extends ConfigEntry { - @Nonnull - public T getMin(); - - @Nonnull - public T getMax(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/StringConfigEntry.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/StringConfigEntry.java deleted file mode 100644 index e975311..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/StringConfigEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.entry; - -import de.maxhenkel.voicechat.configbuilder.CommentedPropertyConfig; -import de.maxhenkel.voicechat.configbuilder.entry.AbstractConfigEntry; -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; - -public class StringConfigEntry -extends AbstractConfigEntry { - public StringConfigEntry(CommentedPropertyConfig config, ValueSerializer serializer, String[] comments, String key, String def) { - super(config, serializer, comments, key, def); - this.reload(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/BooleanSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/BooleanSerializer.java deleted file mode 100644 index 66b42e7..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/BooleanSerializer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry.serializer; - -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nullable; - -public class BooleanSerializer -implements ValueSerializer { - public static final BooleanSerializer INSTANCE = new BooleanSerializer(); - - @Override - @Nullable - public Boolean deserialize(String str) { - return Boolean.valueOf(str); - } - - @Override - @Nullable - public String serialize(Boolean val) { - return String.valueOf(val); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/DoubleSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/DoubleSerializer.java deleted file mode 100644 index a6322f7..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/DoubleSerializer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry.serializer; - -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nullable; - -public class DoubleSerializer -implements ValueSerializer { - public static final DoubleSerializer INSTANCE = new DoubleSerializer(); - - @Override - @Nullable - public Double deserialize(String str) { - try { - return Double.parseDouble(str); - } - catch (NumberFormatException e) { - return null; - } - } - - @Override - @Nullable - public String serialize(Double val) { - return String.valueOf(val); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/EnumSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/EnumSerializer.java deleted file mode 100644 index d2c0dfe..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/EnumSerializer.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry.serializer; - -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nullable; - -public class EnumSerializer> -implements ValueSerializer { - protected Class enumClass; - - public EnumSerializer(Class enumClass) { - this.enumClass = enumClass; - } - - @Override - @Nullable - public E deserialize(String str) { - try { - return Enum.valueOf(this.enumClass, str); - } - catch (Exception e) { - return null; - } - } - - @Override - @Nullable - public String serialize(E val) { - return ((Enum)val).name(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/FloatSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/FloatSerializer.java deleted file mode 100644 index bb6c715..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/FloatSerializer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry.serializer; - -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nullable; - -public class FloatSerializer -implements ValueSerializer { - public static final FloatSerializer INSTANCE = new FloatSerializer(); - - @Override - @Nullable - public Float deserialize(String str) { - try { - return Float.valueOf(Float.parseFloat(str)); - } - catch (NumberFormatException e) { - return null; - } - } - - @Override - @Nullable - public String serialize(Float val) { - return String.valueOf(val); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/IntegerSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/IntegerSerializer.java deleted file mode 100644 index af1e84f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/IntegerSerializer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry.serializer; - -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nullable; - -public class IntegerSerializer -implements ValueSerializer { - public static final IntegerSerializer INSTANCE = new IntegerSerializer(); - - @Override - @Nullable - public Integer deserialize(String str) { - try { - return Integer.parseInt(str); - } - catch (NumberFormatException e) { - return null; - } - } - - @Override - @Nullable - public String serialize(Integer val) { - return String.valueOf(val); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/LongSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/LongSerializer.java deleted file mode 100644 index 7c46a98..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/LongSerializer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry.serializer; - -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nullable; - -public class LongSerializer -implements ValueSerializer { - public static final LongSerializer INSTANCE = new LongSerializer(); - - @Override - @Nullable - public Long deserialize(String str) { - try { - return Long.parseLong(str); - } - catch (NumberFormatException e) { - return null; - } - } - - @Override - @Nullable - public String serialize(Long val) { - return String.valueOf(val); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/StringSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/StringSerializer.java deleted file mode 100644 index b96a62e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/StringSerializer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry.serializer; - -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import javax.annotation.Nullable; - -public class StringSerializer -implements ValueSerializer { - public static final StringSerializer INSTANCE = new StringSerializer(); - - @Override - @Nullable - public String deserialize(String str) { - return str; - } - - @Override - @Nullable - public String serialize(String val) { - return val; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/ValueSerializable.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/ValueSerializable.java deleted file mode 100644 index 5b3bbe3..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/ValueSerializable.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.configbuilder.entry.serializer; - -import de.maxhenkel.voicechat.configbuilder.entry.serializer.ValueSerializer; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(value=RetentionPolicy.RUNTIME) -@Target(value={ElementType.TYPE}) -public @interface ValueSerializable { - public Class> value(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/ValueSerializer.java b/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/ValueSerializer.java deleted file mode 100644 index d7550e1..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/configbuilder/entry/serializer/ValueSerializer.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - */ -package de.maxhenkel.voicechat.configbuilder.entry.serializer; - -import javax.annotation.Nullable; - -public interface ValueSerializer { - @Nullable - public T deserialize(String var1); - - @Nullable - public String serialize(T var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/integration/commodore/CommodoreCommands.java b/source/decompiled/de/maxhenkel/voicechat/integration/commodore/CommodoreCommands.java deleted file mode 100644 index 7748660..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/integration/commodore/CommodoreCommands.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * com.mojang.brigadier.arguments.ArgumentType - * com.mojang.brigadier.arguments.StringArgumentType - * com.mojang.brigadier.builder.ArgumentBuilder - * com.mojang.brigadier.builder.LiteralArgumentBuilder - * com.mojang.brigadier.builder.RequiredArgumentBuilder - * com.mojang.brigadier.suggestion.SuggestionProvider - */ -package de.maxhenkel.voicechat.integration.commodore; - -import com.mojang.brigadier.arguments.ArgumentType; -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.builder.ArgumentBuilder; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.builder.RequiredArgumentBuilder; -import com.mojang.brigadier.suggestion.SuggestionProvider; -import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.commodore.Commodore; -import de.maxhenkel.voicechat.integration.commodore.GroupNameSuggestionProvider; -import de.maxhenkel.voicechat.integration.commodore.MissingArgumentTypeException; - -public class CommodoreCommands { - public static void registerCompletions(Commodore commodore) throws MissingArgumentTypeException { - ArgumentType playerArgument = CommodoreCommands.playerArgument(); - ArgumentType uuidArgument = CommodoreCommands.uuidArgument(); - if (playerArgument == null || uuidArgument == null) { - throw new MissingArgumentTypeException("Could not acquire argument types"); - } - LiteralArgumentBuilder literalBuilder = (LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)LiteralArgumentBuilder.literal((String)"voicechat").then((ArgumentBuilder)LiteralArgumentBuilder.literal((String)"help"))).then(LiteralArgumentBuilder.literal((String)"test").then((ArgumentBuilder)RequiredArgumentBuilder.argument((String)"target", playerArgument)))).then(LiteralArgumentBuilder.literal((String)"invite").then((ArgumentBuilder)RequiredArgumentBuilder.argument((String)"target", playerArgument)))).then(LiteralArgumentBuilder.literal((String)"join").then((ArgumentBuilder)RequiredArgumentBuilder.argument((String)"group_id", uuidArgument)))).then(LiteralArgumentBuilder.literal((String)"join").then(RequiredArgumentBuilder.argument((String)"group_id", uuidArgument).then((ArgumentBuilder)RequiredArgumentBuilder.argument((String)"password", (ArgumentType)StringArgumentType.string()))))).then(LiteralArgumentBuilder.literal((String)"join").then((ArgumentBuilder)RequiredArgumentBuilder.argument((String)"group_name", (ArgumentType)StringArgumentType.string()).suggests((SuggestionProvider)GroupNameSuggestionProvider.INSTANCE)))).then(LiteralArgumentBuilder.literal((String)"join").then(RequiredArgumentBuilder.argument((String)"group_name", (ArgumentType)StringArgumentType.string()).suggests((SuggestionProvider)GroupNameSuggestionProvider.INSTANCE).then((ArgumentBuilder)RequiredArgumentBuilder.argument((String)"password", (ArgumentType)StringArgumentType.string()))))).then((ArgumentBuilder)LiteralArgumentBuilder.literal((String)"leave")); - commodore.register(literalBuilder); - } - - private static ArgumentType playerArgument() { - return Voicechat.compatibility.playerArgument(); - } - - private static ArgumentType uuidArgument() { - return Voicechat.compatibility.uuidArgument(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/logging/VoicechatLogger.java b/source/decompiled/de/maxhenkel/voicechat/logging/VoicechatLogger.java deleted file mode 100644 index 097510b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/logging/VoicechatLogger.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.logging; - -import de.maxhenkel.voicechat.logging.LogLevel; - -public interface VoicechatLogger { - public void log(LogLevel var1, String var2, Object ... var3); - - public boolean isEnabled(LogLevel var1); - - default public void trace(String message, Object ... args) { - this.log(LogLevel.TRACE, message, args); - } - - default public void debug(String message, Object ... args) { - this.log(LogLevel.DEBUG, message, args); - } - - default public void info(String message, Object ... args) { - this.log(LogLevel.INFO, message, args); - } - - default public void warn(String message, Object ... args) { - this.log(LogLevel.WARN, message, args); - } - - default public void error(String message, Object ... args) { - this.log(LogLevel.ERROR, message, args); - } - - default public void fatal(String message, Object ... args) { - this.log(LogLevel.FATAL, message, args); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/net/NetManager.java b/source/decompiled/de/maxhenkel/voicechat/net/NetManager.java deleted file mode 100644 index d02c681..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/net/NetManager.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * io.netty.buffer.Unpooled - * org.bukkit.Bukkit - * org.bukkit.entity.Player - * org.bukkit.event.EventHandler - * org.bukkit.event.Listener - * org.bukkit.event.player.PlayerJoinEvent - * org.bukkit.event.player.PlayerQuitEvent - * org.bukkit.plugin.Plugin - */ -package de.maxhenkel.voicechat.net; - -import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.net.AddCategoryPacket; -import de.maxhenkel.voicechat.net.AddGroupPacket; -import de.maxhenkel.voicechat.net.CreateGroupPacket; -import de.maxhenkel.voicechat.net.JoinGroupPacket; -import de.maxhenkel.voicechat.net.JoinedGroupPacket; -import de.maxhenkel.voicechat.net.LeaveGroupPacket; -import de.maxhenkel.voicechat.net.Packet; -import de.maxhenkel.voicechat.net.PlayerStatePacket; -import de.maxhenkel.voicechat.net.PlayerStatesPacket; -import de.maxhenkel.voicechat.net.RemoveCategoryPacket; -import de.maxhenkel.voicechat.net.RemoveGroupPacket; -import de.maxhenkel.voicechat.net.RemovePlayerStatePacket; -import de.maxhenkel.voicechat.net.RequestSecretPacket; -import de.maxhenkel.voicechat.net.SecretPacket; -import de.maxhenkel.voicechat.net.UpdateStatePacket; -import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import io.netty.buffer.Unpooled; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.HashSet; -import java.util.Set; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.plugin.Plugin; - -public class NetManager -implements Listener { - private final Set packets = new HashSet(); - - public void onEnable() { - this.packets.clear(); - Bukkit.getPluginManager().registerEvents((Listener)this, (Plugin)Voicechat.INSTANCE); - try { - this.registerIncomingPacket(UpdateStatePacket.class); - this.registerIncomingPacket(RequestSecretPacket.class); - this.registerIncomingPacket(CreateGroupPacket.class); - this.registerIncomingPacket(JoinGroupPacket.class); - this.registerIncomingPacket(LeaveGroupPacket.class); - this.registerOutgoingPacket(SecretPacket.class); - this.registerOutgoingPacket(PlayerStatesPacket.class); - this.registerOutgoingPacket(PlayerStatePacket.class); - this.registerOutgoingPacket(RemovePlayerStatePacket.class); - this.registerOutgoingPacket(AddGroupPacket.class); - this.registerOutgoingPacket(RemoveGroupPacket.class); - this.registerOutgoingPacket(JoinedGroupPacket.class); - this.registerOutgoingPacket(AddCategoryPacket.class); - this.registerOutgoingPacket(RemoveCategoryPacket.class); - } - catch (Exception e) { - throw new IllegalStateException("Failed to register voice chat packets", e); - } - } - - public void onDisable() { - Set incomingChannels = Bukkit.getMessenger().getIncomingChannels((Plugin)Voicechat.INSTANCE); - Set outgoingChannels = Bukkit.getMessenger().getOutgoingChannels((Plugin)Voicechat.INSTANCE); - for (String channel : incomingChannels) { - Bukkit.getMessenger().unregisterIncomingPluginChannel((Plugin)Voicechat.INSTANCE, channel); - } - for (String channel : outgoingChannels) { - Bukkit.getMessenger().unregisterOutgoingPluginChannel((Plugin)Voicechat.INSTANCE, channel); - } - this.packets.clear(); - } - - public Set getPackets() { - return this.packets; - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - Set outgoingChannels = Bukkit.getMessenger().getOutgoingChannels((Plugin)Voicechat.INSTANCE); - for (String channel : outgoingChannels) { - Voicechat.compatibility.addChannel(event.getPlayer(), channel); - } - } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - Set outgoingChannels = Bukkit.getMessenger().getOutgoingChannels((Plugin)Voicechat.INSTANCE); - for (String channel : outgoingChannels) { - Voicechat.compatibility.removeChannel(event.getPlayer(), channel); - } - } - - private > void registerIncomingPacket(Class packetClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { - Constructor c = packetClass.getDeclaredConstructor(new Class[0]); - String id = ((Packet)c.newInstance(new Object[0])).getID().toString(); - this.packets.add(id); - Bukkit.getMessenger().registerIncomingPluginChannel((Plugin)Voicechat.INSTANCE, id, (s, player, bytes) -> { - Packet packet; - if (!Voicechat.SERVER.getRateLimiter().allow(player.getUniqueId())) { - Voicechat.LOGGER.warn("Player {} exceeded packet rate limit", player.getDisplayName()); - player.kickPlayer(Voicechat.TRANSLATIONS.rateLimitKickMessage.get()); - return; - } - try { - packet = (Packet)c.newInstance(new Object[0]); - } - catch (Exception e) { - Voicechat.LOGGER.error("Failed to create new packet instance of {}", packetClass.getSimpleName(), e); - return; - } - FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.wrappedBuffer((byte[])bytes)); - packet.fromBytes(buffer); - packet.onPacket(player); - }); - } - - private > void registerOutgoingPacket(Class packetClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { - String id = ((Packet)packetClass.getDeclaredConstructor(new Class[0]).newInstance(new Object[0])).getID().toString(); - this.packets.add(id); - Bukkit.getMessenger().registerOutgoingPluginChannel((Plugin)Voicechat.INSTANCE, id); - } - - public static void sendToClient(Player player, Packet p) { - Voicechat.compatibility.runTask(() -> { - if (!Voicechat.SERVER.isCompatible(player)) { - return; - } - try { - FriendlyByteBuf buf = new FriendlyByteBuf(); - p.toBytes(buf); - byte[] bytes = new byte[buf.readableBytes()]; - buf.readBytes(bytes); - player.sendPluginMessage((Plugin)Voicechat.INSTANCE, p.getID().toString(), bytes); - } - catch (Exception e) { - Voicechat.LOGGER.error("Failed to send packet to '{}'", player.getName(), e); - } - }); - } - - public static void sendMessage(Player player, String key, String ... args) { - Voicechat.compatibility.sendTranslationMessage(player, key, args); - } - - public static void sendStatusMessage(Player player, String key, String ... args) { - Voicechat.compatibility.sendStatusMessage(player, key, args); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/net/Packet.java b/source/decompiled/de/maxhenkel/voicechat/net/Packet.java deleted file mode 100644 index 97233ee..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/net/Packet.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.net; - -import de.maxhenkel.voicechat.util.FriendlyByteBuf; -import de.maxhenkel.voicechat.util.Key; -import org.bukkit.entity.Player; - -public interface Packet { - public Key getID(); - - public T fromBytes(FriendlyByteBuf var1); - - public void toBytes(FriendlyByteBuf var1); - - default public void onPacket(Player player) { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/CDL.java b/source/decompiled/de/maxhenkel/voicechat/org/json/CDL.java deleted file mode 100644 index ee27067..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/CDL.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONArray; -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONObject; -import de.maxhenkel.voicechat.org.json.JSONTokener; - -public class CDL { - @Deprecated - public CDL() { - } - - private static String getValue(JSONTokener x, char delimiter) throws JSONException { - char c; - while ((c = x.next()) == ' ' || c == '\t') { - } - if (c == '\u0000') { - return null; - } - if (c == '\"' || c == '\'') { - char q = c; - StringBuilder sb = new StringBuilder(); - while (true) { - char nextC; - if ((c = x.next()) == q && (nextC = x.next()) != '\"') { - if (nextC <= '\u0000') break; - x.back(); - break; - } - if (c == '\u0000' || c == '\n' || c == '\r') { - throw x.syntaxError("Missing close quote '" + q + "'."); - } - sb.append(c); - } - return sb.toString(); - } - if (c == delimiter) { - x.back(); - return ""; - } - x.back(); - return x.nextTo(delimiter); - } - - public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException { - return CDL.rowToJSONArray(x, ','); - } - - public static JSONArray rowToJSONArray(JSONTokener x, char delimiter) throws JSONException { - JSONArray ja = new JSONArray(); - block0: while (true) { - String value = CDL.getValue(x, delimiter); - char c = x.next(); - if (value != null) { - ja.put(value); - } else { - if (ja.length() == 0 && c != delimiter) { - return null; - } - ja.put(""); - } - while (true) { - if (c == delimiter) continue block0; - if (c != ' ') { - if (c == '\n' || c == '\r' || c == '\u0000') { - return ja; - } - throw x.syntaxError("Bad character '" + c + "' (" + c + ")."); - } - c = x.next(); - } - break; - } - } - - public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) throws JSONException { - return CDL.rowToJSONObject(names, x, ','); - } - - public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x, char delimiter) throws JSONException { - JSONArray ja = CDL.rowToJSONArray(x, delimiter); - return ja != null ? ja.toJSONObject(names) : null; - } - - public static String rowToString(JSONArray ja) { - return CDL.rowToString(ja, ','); - } - - public static String rowToString(JSONArray ja, char delimiter) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < ja.length(); ++i) { - Object object; - if (i > 0) { - sb.append(delimiter); - } - if ((object = ja.opt(i)) == null) continue; - String string = object.toString(); - if (!(string.isEmpty() || string.indexOf(delimiter) < 0 && string.indexOf(10) < 0 && string.indexOf(13) < 0 && string.indexOf(0) < 0 && string.charAt(0) != '\"')) { - sb.append('\"'); - int length = string.length(); - for (int j = 0; j < length; ++j) { - char c = string.charAt(j); - if (c < ' ' || c == '\"') continue; - sb.append(c); - } - sb.append('\"'); - continue; - } - sb.append(string); - } - sb.append('\n'); - return sb.toString(); - } - - public static JSONArray toJSONArray(String string) throws JSONException { - return CDL.toJSONArray(string, ','); - } - - public static JSONArray toJSONArray(String string, char delimiter) throws JSONException { - return CDL.toJSONArray(new JSONTokener(string), delimiter); - } - - public static JSONArray toJSONArray(JSONTokener x) throws JSONException { - return CDL.toJSONArray(x, ','); - } - - public static JSONArray toJSONArray(JSONTokener x, char delimiter) throws JSONException { - return CDL.toJSONArray(CDL.rowToJSONArray(x, delimiter), x, delimiter); - } - - public static JSONArray toJSONArray(JSONArray names, String string) throws JSONException { - return CDL.toJSONArray(names, string, ','); - } - - public static JSONArray toJSONArray(JSONArray names, String string, char delimiter) throws JSONException { - return CDL.toJSONArray(names, new JSONTokener(string), delimiter); - } - - public static JSONArray toJSONArray(JSONArray names, JSONTokener x) throws JSONException { - return CDL.toJSONArray(names, x, ','); - } - - public static JSONArray toJSONArray(JSONArray names, JSONTokener x, char delimiter) throws JSONException { - String key; - JSONObject j; - JSONObject jo; - if (names == null || names.length() == 0) { - return null; - } - JSONArray ja = new JSONArray(); - while ((jo = CDL.rowToJSONObject(names, x, delimiter)) != null) { - ja.put(jo); - } - if (ja.length() == 0) { - return null; - } - if (ja.length() == 1 && (j = ja.getJSONObject(0)).length() == 1 && "".equals(key = j.keys().next()) && "".equals(j.get(key))) { - return null; - } - return ja; - } - - public static String toString(JSONArray ja) throws JSONException { - return CDL.toString(ja, ','); - } - - public static String toString(JSONArray ja, char delimiter) throws JSONException { - JSONArray names; - JSONObject jo = ja.optJSONObject(0); - if (jo != null && (names = jo.names()) != null) { - return CDL.rowToString(names, delimiter) + CDL.toString(names, ja, delimiter); - } - return null; - } - - public static String toString(JSONArray names, JSONArray ja) throws JSONException { - return CDL.toString(names, ja, ','); - } - - public static String toString(JSONArray names, JSONArray ja, char delimiter) throws JSONException { - if (names == null || names.length() == 0) { - return null; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < ja.length(); ++i) { - JSONObject jo = ja.optJSONObject(i); - if (jo == null) continue; - sb.append(CDL.rowToString(jo.toJSONArray(names), delimiter)); - } - return sb.toString(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/Cookie.java b/source/decompiled/de/maxhenkel/voicechat/org/json/Cookie.java deleted file mode 100644 index c45c429..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/Cookie.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONObject; -import de.maxhenkel.voicechat.org.json.JSONTokener; -import java.util.Locale; - -public class Cookie { - @Deprecated - public Cookie() { - } - - public static String escape(String string) { - String s = string.trim(); - int length = s.length(); - StringBuilder sb = new StringBuilder(length); - for (int i = 0; i < length; ++i) { - char c = s.charAt(i); - if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') { - sb.append('%'); - sb.append(Character.forDigit((char)(c >>> 4 & 0xF), 16)); - sb.append(Character.forDigit((char)(c & 0xF), 16)); - continue; - } - sb.append(c); - } - return sb.toString(); - } - - public static JSONObject toJSONObject(String string) { - JSONObject jo = new JSONObject(); - JSONTokener x = new JSONTokener(string); - String name = Cookie.unescape(x.nextTo('=').trim()); - if ("".equals(name)) { - throw new JSONException("Cookies must have a 'name'"); - } - jo.put("name", name); - x.next('='); - jo.put("value", Cookie.unescape(x.nextTo(';')).trim()); - x.next(); - while (x.more()) { - Object value; - name = Cookie.unescape(x.nextTo("=;")).trim().toLowerCase(Locale.ROOT); - if ("name".equalsIgnoreCase(name)) { - throw new JSONException("Illegal attribute name: 'name'"); - } - if ("value".equalsIgnoreCase(name)) { - throw new JSONException("Illegal attribute name: 'value'"); - } - if (x.next() != '=') { - value = Boolean.TRUE; - } else { - value = Cookie.unescape(x.nextTo(';')).trim(); - x.next(); - } - if ("".equals(name) || "".equals(value)) continue; - jo.put(name, value); - } - return jo; - } - - public static String toString(JSONObject jo) throws JSONException { - StringBuilder sb = new StringBuilder(); - String name = null; - Object value = null; - for (String key : jo.keySet()) { - if ("name".equalsIgnoreCase(key)) { - name = jo.getString(key).trim(); - } - if ("value".equalsIgnoreCase(key)) { - value = jo.getString(key).trim(); - } - if (name == null || value == null) continue; - break; - } - if (name == null || "".equals(name.trim())) { - throw new JSONException("Cookie does not have a name"); - } - if (value == null) { - value = ""; - } - sb.append(Cookie.escape(name)); - sb.append("="); - sb.append(Cookie.escape((String)value)); - for (String key : jo.keySet()) { - if ("name".equalsIgnoreCase(key) || "value".equalsIgnoreCase(key)) continue; - value = jo.opt(key); - if (value instanceof Boolean) { - if (!Boolean.TRUE.equals(value)) continue; - sb.append(';').append(Cookie.escape(key)); - continue; - } - sb.append(';').append(Cookie.escape(key)).append('=').append(Cookie.escape(value.toString())); - } - return sb.toString(); - } - - public static String unescape(String string) { - int length = string.length(); - StringBuilder sb = new StringBuilder(length); - for (int i = 0; i < length; ++i) { - char c = string.charAt(i); - if (c == '+') { - c = ' '; - } else if (c == '%' && i + 2 < length) { - int d = JSONTokener.dehexchar(string.charAt(i + 1)); - int e = JSONTokener.dehexchar(string.charAt(i + 2)); - if (d >= 0 && e >= 0) { - c = (char)(d * 16 + e); - i += 2; - } - } - sb.append(c); - } - return sb.toString(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/CookieList.java b/source/decompiled/de/maxhenkel/voicechat/org/json/CookieList.java deleted file mode 100644 index 5aed590..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/CookieList.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.Cookie; -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONObject; -import de.maxhenkel.voicechat.org.json.JSONTokener; - -public class CookieList { - @Deprecated - public CookieList() { - } - - public static JSONObject toJSONObject(String string) throws JSONException { - JSONObject jo = new JSONObject(); - JSONTokener x = new JSONTokener(string); - while (x.more()) { - String name = Cookie.unescape(x.nextTo('=')); - x.next('='); - jo.put(name, Cookie.unescape(x.nextTo(';'))); - x.next(); - } - return jo; - } - - public static String toString(JSONObject jo) throws JSONException { - boolean isEndOfPair = false; - StringBuilder sb = new StringBuilder(); - for (String key : jo.keySet()) { - Object value = jo.opt(key); - if (JSONObject.NULL.equals(value)) continue; - if (isEndOfPair) { - sb.append(';'); - } - sb.append(Cookie.escape(key)); - sb.append("="); - sb.append(Cookie.escape(value.toString())); - isEndOfPair = true; - } - return sb.toString(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/HTTP.java b/source/decompiled/de/maxhenkel/voicechat/org/json/HTTP.java deleted file mode 100644 index 386067d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/HTTP.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.HTTPTokener; -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONObject; -import java.util.Locale; - -public class HTTP { - public static final String CRLF = "\r\n"; - - public static JSONObject toJSONObject(String string) throws JSONException { - JSONObject jo = new JSONObject(); - HTTPTokener x = new HTTPTokener(string); - String token = x.nextToken(); - if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) { - jo.put("HTTP-Version", token); - jo.put("Status-Code", x.nextToken()); - jo.put("Reason-Phrase", x.nextTo('\u0000')); - x.next(); - } else { - jo.put("Method", token); - jo.put("Request-URI", x.nextToken()); - jo.put("HTTP-Version", x.nextToken()); - } - while (x.more()) { - String name = x.nextTo(':'); - x.next(':'); - jo.put(name, x.nextTo('\u0000')); - x.next(); - } - return jo; - } - - public static String toString(JSONObject jo) throws JSONException { - StringBuilder sb = new StringBuilder(); - if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { - sb.append(jo.getString("HTTP-Version")); - sb.append(' '); - sb.append(jo.getString("Status-Code")); - sb.append(' '); - sb.append(jo.getString("Reason-Phrase")); - } else if (jo.has("Method") && jo.has("Request-URI")) { - sb.append(jo.getString("Method")); - sb.append(' '); - sb.append('\"'); - sb.append(jo.getString("Request-URI")); - sb.append('\"'); - sb.append(' '); - sb.append(jo.getString("HTTP-Version")); - } else { - throw new JSONException("Not enough material for an HTTP header."); - } - sb.append(CRLF); - for (String key : jo.keySet()) { - String value = jo.optString(key); - if ("HTTP-Version".equals(key) || "Status-Code".equals(key) || "Reason-Phrase".equals(key) || "Method".equals(key) || "Request-URI".equals(key) || JSONObject.NULL.equals(value)) continue; - sb.append(key); - sb.append(": "); - sb.append(jo.optString(key)); - sb.append(CRLF); - } - sb.append(CRLF); - return sb.toString(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/HTTPTokener.java b/source/decompiled/de/maxhenkel/voicechat/org/json/HTTPTokener.java deleted file mode 100644 index 0ffb14d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/HTTPTokener.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONTokener; - -public class HTTPTokener -extends JSONTokener { - public HTTPTokener(String string) { - super(string); - } - - public String nextToken() throws JSONException { - char c; - StringBuilder sb = new StringBuilder(); - while (Character.isWhitespace(c = this.next())) { - } - if (c == '\"' || c == '\'') { - char q = c; - while (true) { - if ((c = this.next()) < ' ') { - throw this.syntaxError("Unterminated string."); - } - if (c == q) { - return sb.toString(); - } - sb.append(c); - } - } - while (c != '\u0000' && !Character.isWhitespace(c)) { - sb.append(c); - c = this.next(); - } - return sb.toString(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONArray.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONArray.java deleted file mode 100644 index 66706ec..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONArray.java +++ /dev/null @@ -1,855 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONObject; -import de.maxhenkel.voicechat.org.json.JSONParserConfiguration; -import de.maxhenkel.voicechat.org.json.JSONPointer; -import de.maxhenkel.voicechat.org.json.JSONPointerException; -import de.maxhenkel.voicechat.org.json.JSONString; -import de.maxhenkel.voicechat.org.json.JSONTokener; -import de.maxhenkel.voicechat.org.json.StringBuilderWriter; -import java.io.IOException; -import java.io.Writer; -import java.lang.reflect.Array; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -public class JSONArray -implements Iterable { - private final ArrayList myArrayList; - - public JSONArray() { - this.myArrayList = new ArrayList(); - } - - public JSONArray(JSONTokener x) throws JSONException { - this(x, x.getJsonParserConfiguration()); - } - - public JSONArray(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException { - this(); - boolean isInitial; - boolean bl = isInitial = x.getPrevious() == '\u0000'; - if (x.nextClean() != '[') { - throw x.syntaxError("A JSONArray text must start with '['"); - } - char nextChar = x.nextClean(); - if (nextChar == '\u0000') { - throw x.syntaxError("Expected a ',' or ']'"); - } - if (nextChar == ',' && jsonParserConfiguration.isStrictMode()) { - throw x.syntaxError("Array content starts with a ','"); - } - if (nextChar != ']') { - x.back(); - do { - if (x.nextClean() == ',') { - x.back(); - this.myArrayList.add(JSONObject.NULL); - continue; - } - x.back(); - this.myArrayList.add(x.nextValue()); - } while (!JSONArray.checkForSyntaxError(x, jsonParserConfiguration, isInitial)); - return; - } - if (isInitial && jsonParserConfiguration.isStrictMode() && x.nextClean() != '\u0000') { - throw x.syntaxError("Strict mode error: Unparsed characters found at end of input text"); - } - } - - private static boolean checkForSyntaxError(JSONTokener x, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) { - switch (x.nextClean()) { - case '\u0000': { - throw x.syntaxError("Expected a ',' or ']'"); - } - case ',': { - char nextChar = x.nextClean(); - if (nextChar == '\u0000') { - throw x.syntaxError("Expected a ',' or ']'"); - } - if (nextChar == ']') { - if (jsonParserConfiguration.isStrictMode()) { - throw x.syntaxError("Strict mode error: Expected another array element"); - } - return true; - } - if (nextChar == ',') { - if (jsonParserConfiguration.isStrictMode()) { - throw x.syntaxError("Strict mode error: Expected a valid array element"); - } - return true; - } - x.back(); - break; - } - case ']': { - if (isInitial && jsonParserConfiguration.isStrictMode() && x.nextClean() != '\u0000') { - throw x.syntaxError("Strict mode error: Unparsed characters found at end of input text"); - } - return true; - } - default: { - throw x.syntaxError("Expected a ',' or ']'"); - } - } - return false; - } - - public JSONArray(String source) throws JSONException { - this(source, new JSONParserConfiguration()); - } - - public JSONArray(String source, JSONParserConfiguration jsonParserConfiguration) throws JSONException { - this(new JSONTokener(source, jsonParserConfiguration), jsonParserConfiguration); - } - - public JSONArray(Collection collection) { - this(collection, 0, new JSONParserConfiguration()); - } - - public JSONArray(Collection collection, JSONParserConfiguration jsonParserConfiguration) { - this(collection, 0, jsonParserConfiguration); - } - - JSONArray(Collection collection, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { - if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) { - throw new JSONException("JSONArray has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); - } - if (collection == null) { - this.myArrayList = new ArrayList(); - } else { - this.myArrayList = new ArrayList(collection.size()); - this.addAll(collection, true, recursionDepth, jsonParserConfiguration); - } - } - - public JSONArray(Iterable iter) { - this(); - if (iter == null) { - return; - } - this.addAll(iter, true); - } - - public JSONArray(JSONArray array) { - this.myArrayList = array == null ? new ArrayList() : new ArrayList(array.myArrayList); - } - - public JSONArray(Object array) throws JSONException { - this(); - if (!array.getClass().isArray()) { - throw new JSONException("JSONArray initial value should be a string or collection or array."); - } - this.addAll(array, true, 0); - } - - public JSONArray(int initialCapacity) throws JSONException { - if (initialCapacity < 0) { - throw new JSONException("JSONArray initial capacity cannot be negative."); - } - this.myArrayList = new ArrayList(initialCapacity); - } - - @Override - public Iterator iterator() { - return this.myArrayList.iterator(); - } - - public Object get(int index) throws JSONException { - Object object = this.opt(index); - if (object == null) { - throw new JSONException("JSONArray[" + index + "] not found."); - } - return object; - } - - public boolean getBoolean(int index) throws JSONException { - Object object = this.get(index); - if (Boolean.FALSE.equals(object) || object instanceof String && "false".equalsIgnoreCase((String)object)) { - return false; - } - if (Boolean.TRUE.equals(object) || object instanceof String && "true".equalsIgnoreCase((String)object)) { - return true; - } - throw JSONArray.wrongValueFormatException(index, "boolean", object, null); - } - - public double getDouble(int index) throws JSONException { - Object object = this.get(index); - if (object instanceof Number) { - return ((Number)object).doubleValue(); - } - try { - return Double.parseDouble(object.toString()); - } - catch (Exception e) { - throw JSONArray.wrongValueFormatException(index, "double", object, e); - } - } - - public float getFloat(int index) throws JSONException { - Object object = this.get(index); - if (object instanceof Number) { - return ((Number)object).floatValue(); - } - try { - return Float.parseFloat(object.toString()); - } - catch (Exception e) { - throw JSONArray.wrongValueFormatException(index, "float", object, e); - } - } - - public Number getNumber(int index) throws JSONException { - Object object = this.get(index); - try { - if (object instanceof Number) { - return (Number)object; - } - return JSONObject.stringToNumber(object.toString()); - } - catch (Exception e) { - throw JSONArray.wrongValueFormatException(index, "number", object, e); - } - } - - public > E getEnum(Class clazz, int index) throws JSONException { - E val = this.optEnum(clazz, index); - if (val == null) { - throw JSONArray.wrongValueFormatException(index, "enum of type " + JSONObject.quote(clazz.getSimpleName()), this.opt(index), null); - } - return val; - } - - public BigDecimal getBigDecimal(int index) throws JSONException { - Object object = this.get(index); - BigDecimal val = JSONObject.objectToBigDecimal(object, null); - if (val == null) { - throw JSONArray.wrongValueFormatException(index, "BigDecimal", object, null); - } - return val; - } - - public BigInteger getBigInteger(int index) throws JSONException { - Object object = this.get(index); - BigInteger val = JSONObject.objectToBigInteger(object, null); - if (val == null) { - throw JSONArray.wrongValueFormatException(index, "BigInteger", object, null); - } - return val; - } - - public int getInt(int index) throws JSONException { - Object object = this.get(index); - if (object instanceof Number) { - return ((Number)object).intValue(); - } - try { - return Integer.parseInt(object.toString()); - } - catch (Exception e) { - throw JSONArray.wrongValueFormatException(index, "int", object, e); - } - } - - public JSONArray getJSONArray(int index) throws JSONException { - Object object = this.get(index); - if (object instanceof JSONArray) { - return (JSONArray)object; - } - throw JSONArray.wrongValueFormatException(index, "JSONArray", object, null); - } - - public JSONObject getJSONObject(int index) throws JSONException { - Object object = this.get(index); - if (object instanceof JSONObject) { - return (JSONObject)object; - } - throw JSONArray.wrongValueFormatException(index, "JSONObject", object, null); - } - - public long getLong(int index) throws JSONException { - Object object = this.get(index); - if (object instanceof Number) { - return ((Number)object).longValue(); - } - try { - return Long.parseLong(object.toString()); - } - catch (Exception e) { - throw JSONArray.wrongValueFormatException(index, "long", object, e); - } - } - - public String getString(int index) throws JSONException { - Object object = this.get(index); - if (object instanceof String) { - return (String)object; - } - throw JSONArray.wrongValueFormatException(index, "String", object, null); - } - - public boolean isNull(int index) { - return JSONObject.NULL.equals(this.opt(index)); - } - - public String join(String separator) throws JSONException { - int len = this.length(); - if (len == 0) { - return ""; - } - StringBuilder sb = new StringBuilder(JSONObject.valueToString(this.myArrayList.get(0))); - for (int i = 1; i < len; ++i) { - sb.append(separator).append(JSONObject.valueToString(this.myArrayList.get(i))); - } - return sb.toString(); - } - - public int length() { - return this.myArrayList.size(); - } - - public void clear() { - this.myArrayList.clear(); - } - - public Object opt(int index) { - return index < 0 || index >= this.length() ? null : this.myArrayList.get(index); - } - - public boolean optBoolean(int index) { - return this.optBoolean(index, false); - } - - public boolean optBoolean(int index, boolean defaultValue) { - try { - return this.getBoolean(index); - } - catch (Exception e) { - return defaultValue; - } - } - - public Boolean optBooleanObject(int index) { - return this.optBooleanObject(index, false); - } - - public Boolean optBooleanObject(int index, Boolean defaultValue) { - try { - return this.getBoolean(index); - } - catch (Exception e) { - return defaultValue; - } - } - - public double optDouble(int index) { - return this.optDouble(index, Double.NaN); - } - - public double optDouble(int index, double defaultValue) { - Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - return val.doubleValue(); - } - - public Double optDoubleObject(int index) { - return this.optDoubleObject(index, Double.NaN); - } - - public Double optDoubleObject(int index, Double defaultValue) { - Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - return val.doubleValue(); - } - - public float optFloat(int index) { - return this.optFloat(index, Float.NaN); - } - - public float optFloat(int index, float defaultValue) { - Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - return val.floatValue(); - } - - public Float optFloatObject(int index) { - return this.optFloatObject(index, Float.valueOf(Float.NaN)); - } - - public Float optFloatObject(int index, Float defaultValue) { - Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - return Float.valueOf(val.floatValue()); - } - - public int optInt(int index) { - return this.optInt(index, 0); - } - - public int optInt(int index, int defaultValue) { - Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - return val.intValue(); - } - - public Integer optIntegerObject(int index) { - return this.optIntegerObject(index, 0); - } - - public Integer optIntegerObject(int index, Integer defaultValue) { - Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - return val.intValue(); - } - - public > E optEnum(Class clazz, int index) { - return this.optEnum(clazz, index, null); - } - - public > E optEnum(Class clazz, int index, E defaultValue) { - try { - Object val = this.opt(index); - if (JSONObject.NULL.equals(val)) { - return defaultValue; - } - if (clazz.isAssignableFrom(val.getClass())) { - Enum myE = (Enum)val; - return (E)myE; - } - return Enum.valueOf(clazz, val.toString()); - } - catch (IllegalArgumentException e) { - return defaultValue; - } - catch (NullPointerException e) { - return defaultValue; - } - } - - public BigInteger optBigInteger(int index, BigInteger defaultValue) { - Object val = this.opt(index); - return JSONObject.objectToBigInteger(val, defaultValue); - } - - public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { - Object val = this.opt(index); - return JSONObject.objectToBigDecimal(val, defaultValue); - } - - public JSONArray optJSONArray(int index) { - return this.optJSONArray(index, null); - } - - public JSONArray optJSONArray(int index, JSONArray defaultValue) { - Object object = this.opt(index); - return object instanceof JSONArray ? (JSONArray)object : defaultValue; - } - - public JSONObject optJSONObject(int index) { - return this.optJSONObject(index, null); - } - - public JSONObject optJSONObject(int index, JSONObject defaultValue) { - Object object = this.opt(index); - return object instanceof JSONObject ? (JSONObject)object : defaultValue; - } - - public long optLong(int index) { - return this.optLong(index, 0L); - } - - public long optLong(int index, long defaultValue) { - Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - return val.longValue(); - } - - public Long optLongObject(int index) { - return this.optLongObject(index, 0L); - } - - public Long optLongObject(int index, Long defaultValue) { - Number val = this.optNumber(index, null); - if (val == null) { - return defaultValue; - } - return val.longValue(); - } - - public Number optNumber(int index) { - return this.optNumber(index, null); - } - - public Number optNumber(int index, Number defaultValue) { - Object val = this.opt(index); - if (JSONObject.NULL.equals(val)) { - return defaultValue; - } - if (val instanceof Number) { - return (Number)val; - } - if (val instanceof String) { - try { - return JSONObject.stringToNumber((String)val); - } - catch (Exception e) { - return defaultValue; - } - } - return defaultValue; - } - - public String optString(int index) { - return this.optString(index, ""); - } - - public String optString(int index, String defaultValue) { - Object object = this.opt(index); - return JSONObject.NULL.equals(object) ? defaultValue : object.toString(); - } - - public JSONArray put(boolean value) { - return this.put(value ? Boolean.TRUE : Boolean.FALSE); - } - - public JSONArray put(Collection value) { - return this.put(new JSONArray(value)); - } - - public JSONArray put(double value) throws JSONException { - return this.put((Object)value); - } - - public JSONArray put(float value) throws JSONException { - return this.put(Float.valueOf(value)); - } - - public JSONArray put(int value) { - return this.put((Object)value); - } - - public JSONArray put(long value) { - return this.put((Object)value); - } - - public JSONArray put(Map value) { - return this.put(new JSONObject(value)); - } - - public JSONArray put(Object value) { - JSONObject.testValidity(value); - this.myArrayList.add(value); - return this; - } - - public JSONArray put(int index, boolean value) throws JSONException { - return this.put(index, value ? Boolean.TRUE : Boolean.FALSE); - } - - public JSONArray put(int index, Collection value) throws JSONException { - return this.put(index, new JSONArray(value)); - } - - public JSONArray put(int index, double value) throws JSONException { - return this.put(index, (Object)value); - } - - public JSONArray put(int index, float value) throws JSONException { - return this.put(index, Float.valueOf(value)); - } - - public JSONArray put(int index, int value) throws JSONException { - return this.put(index, (Object)value); - } - - public JSONArray put(int index, long value) throws JSONException { - return this.put(index, (Object)value); - } - - public JSONArray put(int index, Map value) throws JSONException { - this.put(index, new JSONObject(value, new JSONParserConfiguration())); - return this; - } - - public JSONArray put(int index, Map value, JSONParserConfiguration jsonParserConfiguration) throws JSONException { - this.put(index, new JSONObject(value, jsonParserConfiguration)); - return this; - } - - public JSONArray put(int index, Object value) throws JSONException { - if (index < 0) { - throw new JSONException("JSONArray[" + index + "] not found."); - } - if (index < this.length()) { - JSONObject.testValidity(value); - this.myArrayList.set(index, value); - return this; - } - if (index == this.length()) { - return this.put(value); - } - this.myArrayList.ensureCapacity(index + 1); - while (index != this.length()) { - this.myArrayList.add(JSONObject.NULL); - } - return this.put(value); - } - - public JSONArray putAll(Collection collection) { - this.addAll(collection, false); - return this; - } - - public JSONArray putAll(Iterable iter) { - this.addAll(iter, false); - return this; - } - - public JSONArray putAll(JSONArray array) { - this.myArrayList.addAll(array.myArrayList); - return this; - } - - public JSONArray putAll(Object array) throws JSONException { - this.addAll(array, false); - return this; - } - - public Object query(String jsonPointer) { - return this.query(new JSONPointer(jsonPointer)); - } - - public Object query(JSONPointer jsonPointer) { - return jsonPointer.queryFrom(this); - } - - public Object optQuery(String jsonPointer) { - return this.optQuery(new JSONPointer(jsonPointer)); - } - - public Object optQuery(JSONPointer jsonPointer) { - try { - return jsonPointer.queryFrom(this); - } - catch (JSONPointerException e) { - return null; - } - } - - public Object remove(int index) { - return index >= 0 && index < this.length() ? this.myArrayList.remove(index) : null; - } - - public boolean similar(Object other) { - if (!(other instanceof JSONArray)) { - return false; - } - int len = this.length(); - if (len != ((JSONArray)other).length()) { - return false; - } - for (int i = 0; i < len; ++i) { - Object valueOther; - Object valueThis = this.myArrayList.get(i); - if (valueThis == (valueOther = ((JSONArray)other).myArrayList.get(i))) continue; - if (valueThis == null) { - return false; - } - if (this.isSimilar(valueThis, valueOther)) continue; - return false; - } - return true; - } - - private boolean isSimilar(Object valueThis, Object valueOther) { - return !(valueThis instanceof JSONObject ? !((JSONObject)valueThis).similar(valueOther) : (valueThis instanceof JSONArray ? !((JSONArray)valueThis).similar(valueOther) : (valueThis instanceof Number && valueOther instanceof Number ? !JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther) : (valueThis instanceof JSONString && valueOther instanceof JSONString ? !((JSONString)valueThis).toJSONString().equals(((JSONString)valueOther).toJSONString()) : !valueThis.equals(valueOther))))); - } - - public JSONObject toJSONObject(JSONArray names) throws JSONException { - if (names == null || names.isEmpty() || this.isEmpty()) { - return null; - } - JSONObject jo = new JSONObject(names.length()); - for (int i = 0; i < names.length(); ++i) { - jo.put(names.getString(i), this.opt(i)); - } - return jo; - } - - public String toString() { - try { - return this.toString(0); - } - catch (Exception e) { - return null; - } - } - - public String toString(int indentFactor) throws JSONException { - int initialSize = this.myArrayList.size() * 2; - StringBuilderWriter sw = new StringBuilderWriter(Math.max(initialSize, 16)); - return this.write(sw, indentFactor, 0).toString(); - } - - public Writer write(Writer writer) throws JSONException { - return this.write(writer, 0, 0); - } - - public Writer write(Writer writer, int indentFactor, int indent) throws JSONException { - try { - boolean needsComma = false; - int length = this.length(); - writer.write(91); - if (length == 1) { - this.writeArrayAttempt(writer, indentFactor, indent, 0); - } else if (length != 0) { - int newIndent = indent + indentFactor; - for (int i = 0; i < length; ++i) { - if (needsComma) { - writer.write(44); - } - if (indentFactor > 0) { - writer.write(10); - } - JSONObject.indent(writer, newIndent); - this.writeArrayAttempt(writer, indentFactor, newIndent, i); - needsComma = true; - } - if (indentFactor > 0) { - writer.write(10); - } - JSONObject.indent(writer, indent); - } - writer.write(93); - return writer; - } - catch (IOException e) { - throw new JSONException(e); - } - } - - private void writeArrayAttempt(Writer writer, int indentFactor, int indent, int i) { - try { - JSONObject.writeValue(writer, this.myArrayList.get(i), indentFactor, indent); - } - catch (Exception e) { - throw new JSONException("Unable to write JSONArray value at index: " + i, e); - } - } - - public List toList() { - ArrayList results = new ArrayList(this.myArrayList.size()); - for (Object element : this.myArrayList) { - if (element == null || JSONObject.NULL.equals(element)) { - results.add(null); - continue; - } - if (element instanceof JSONArray) { - results.add(((JSONArray)element).toList()); - continue; - } - if (element instanceof JSONObject) { - results.add(((JSONObject)element).toMap()); - continue; - } - results.add(element); - } - return results; - } - - public boolean isEmpty() { - return this.myArrayList.isEmpty(); - } - - private void addAll(Collection collection, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { - this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size()); - if (wrap) { - for (Object o : collection) { - this.put(JSONObject.wrap(o, recursionDepth + 1, jsonParserConfiguration)); - } - } else { - for (Object o : collection) { - this.put(o); - } - } - } - - private void addAll(Iterable iter, boolean wrap) { - if (wrap) { - for (Object o : iter) { - this.put(JSONObject.wrap(o)); - } - } else { - for (Object o : iter) { - this.put(o); - } - } - } - - private void addAll(Object array, boolean wrap) throws JSONException { - this.addAll(array, wrap, 0); - } - - private void addAll(Object array, boolean wrap, int recursionDepth) { - this.addAll(array, wrap, recursionDepth, new JSONParserConfiguration()); - } - - private void addAll(Object array, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) throws JSONException { - if (array.getClass().isArray()) { - int length = Array.getLength(array); - this.myArrayList.ensureCapacity(this.myArrayList.size() + length); - if (wrap) { - for (int i = 0; i < length; ++i) { - this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1, jsonParserConfiguration)); - } - } else { - for (int i = 0; i < length; ++i) { - this.put(Array.get(array, i)); - } - } - } else if (array instanceof JSONArray) { - this.myArrayList.addAll(((JSONArray)array).myArrayList); - } else if (array instanceof Collection) { - this.addAll((Collection)array, wrap, recursionDepth, jsonParserConfiguration); - } else if (array instanceof Iterable) { - this.addAll((Iterable)array, wrap); - } else { - throw new JSONException("JSONArray initial value should be a string or collection or array."); - } - } - - private static JSONException wrongValueFormatException(int idx, String valueType, Object value, Throwable cause) { - if (value == null) { - return new JSONException("JSONArray[" + idx + "] is not a " + valueType + " (null).", cause); - } - if (value instanceof Map || value instanceof Iterable || value instanceof JSONObject) { - return new JSONException("JSONArray[" + idx + "] is not a " + valueType + " (" + value.getClass() + ").", cause); - } - return new JSONException("JSONArray[" + idx + "] is not a " + valueType + " (" + value.getClass() + " : " + value + ").", cause); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONException.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONException.java deleted file mode 100644 index 1afc7e7..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONException.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -public class JSONException -extends RuntimeException { - private static final long serialVersionUID = 0L; - - public JSONException(String message) { - super(message); - } - - public JSONException(String message, Throwable cause) { - super(message, cause); - } - - public JSONException(Throwable cause) { - super(cause.getMessage(), cause); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONML.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONML.java deleted file mode 100644 index 516bcbb..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONML.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONArray; -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONMLParserConfiguration; -import de.maxhenkel.voicechat.org.json.JSONObject; -import de.maxhenkel.voicechat.org.json.XML; -import de.maxhenkel.voicechat.org.json.XMLTokener; - -public class JSONML { - @Deprecated - public JSONML() { - } - - private static Object parse(XMLTokener x, boolean arrayForm, JSONArray ja, boolean keepStrings, int currentNestingDepth) throws JSONException { - return JSONML.parse(x, arrayForm, ja, keepStrings ? JSONMLParserConfiguration.KEEP_STRINGS : JSONMLParserConfiguration.ORIGINAL, currentNestingDepth); - } - - private static Object parse(XMLTokener x, boolean arrayForm, JSONArray ja, JSONMLParserConfiguration config, int currentNestingDepth) throws JSONException { - String closeTag = null; - JSONArray newja = null; - JSONObject newjo = null; - String tagName = null; - while (true) { - Object value; - if (!x.more()) { - throw x.syntaxError("Bad XML"); - } - Object token = x.nextContent(); - if (token == XML.LT) { - token = x.nextToken(); - if (token instanceof Character) { - if (token == XML.SLASH) { - token = x.nextToken(); - if (!(token instanceof String)) { - throw new JSONException("Expected a closing name instead of '" + token + "'."); - } - if (x.nextToken() != XML.GT) { - throw x.syntaxError("Misshaped close tag"); - } - return token; - } - if (token == XML.BANG) { - char c = x.next(); - if (c == '-') { - if (x.next() == '-') { - x.skipPast("-->"); - continue; - } - x.back(); - continue; - } - if (c == '[') { - token = x.nextToken(); - if ("CDATA".equals(token) && x.next() == '[') { - if (ja == null) continue; - ja.put(x.nextCDATA()); - continue; - } - throw x.syntaxError("Expected 'CDATA['"); - } - int i = 1; - do { - if ((token = x.nextMeta()) == null) { - throw x.syntaxError("Missing '>' after ' 0); - continue; - } - if (token == XML.QUEST) { - x.skipPast("?>"); - continue; - } - throw x.syntaxError("Misshaped tag"); - } - if (!(token instanceof String)) { - throw x.syntaxError("Bad tagName '" + token + "'."); - } - tagName = (String)token; - newja = new JSONArray(); - newjo = new JSONObject(); - if (arrayForm) { - newja.put(tagName); - if (ja != null) { - ja.put(newja); - } - } else { - newjo.put("tagName", tagName); - if (ja != null) { - ja.put(newjo); - } - } - token = null; - while (true) { - if (token == null) { - token = x.nextToken(); - } - if (token == null) { - throw x.syntaxError("Misshaped tag"); - } - if (!(token instanceof String)) break; - String attribute = (String)token; - if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) { - throw x.syntaxError("Reserved attribute."); - } - token = x.nextToken(); - if (token == XML.EQ) { - token = x.nextToken(); - if (!(token instanceof String)) { - throw x.syntaxError("Missing value"); - } - newjo.accumulate(attribute, config.isKeepStrings() ? (String)token : XML.stringToValue((String)token)); - token = null; - continue; - } - newjo.accumulate(attribute, ""); - } - if (arrayForm && newjo.length() > 0) { - newja.put(newjo); - } - if (token == XML.SLASH) { - if (x.nextToken() != XML.GT) { - throw x.syntaxError("Misshaped tag"); - } - if (ja != null) continue; - if (arrayForm) { - return newja; - } - return newjo; - } - if (token != XML.GT) { - throw x.syntaxError("Misshaped tag"); - } - if (currentNestingDepth == config.getMaxNestingDepth()) { - throw x.syntaxError("Maximum nesting depth of " + config.getMaxNestingDepth() + " reached"); - } - closeTag = (String)JSONML.parse(x, arrayForm, newja, config, currentNestingDepth + 1); - if (closeTag == null) continue; - if (!closeTag.equals(tagName)) { - throw x.syntaxError("Mismatched '" + tagName + "' and '" + closeTag + "'"); - } - tagName = null; - if (!arrayForm && newja.length() > 0) { - newjo.put("childNodes", newja); - } - if (ja != null) continue; - if (arrayForm) { - return newja; - } - return newjo; - } - if (ja == null) continue; - if (token instanceof String) { - String strToken = (String)token; - value = config.isKeepStrings() ? XML.unescape(strToken) : XML.stringToValue(strToken); - } else { - value = token; - } - ja.put(value); - } - } - - public static JSONArray toJSONArray(String string) throws JSONException { - return (JSONArray)JSONML.parse(new XMLTokener(string), true, null, JSONMLParserConfiguration.ORIGINAL, 0); - } - - public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { - return (JSONArray)JSONML.parse(new XMLTokener(string), true, null, keepStrings, 0); - } - - public static JSONArray toJSONArray(String string, JSONMLParserConfiguration config) throws JSONException { - return (JSONArray)JSONML.parse(new XMLTokener(string), true, null, config, 0); - } - - public static JSONArray toJSONArray(XMLTokener x, JSONMLParserConfiguration config) throws JSONException { - return (JSONArray)JSONML.parse(x, true, null, config, 0); - } - - public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { - return (JSONArray)JSONML.parse(x, true, null, keepStrings, 0); - } - - public static JSONArray toJSONArray(XMLTokener x) throws JSONException { - return (JSONArray)JSONML.parse(x, true, null, false, 0); - } - - public static JSONObject toJSONObject(String string) throws JSONException { - return (JSONObject)JSONML.parse(new XMLTokener(string), false, null, false, 0); - } - - public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { - return (JSONObject)JSONML.parse(new XMLTokener(string), false, null, keepStrings, 0); - } - - public static JSONObject toJSONObject(String string, JSONMLParserConfiguration config) throws JSONException { - return (JSONObject)JSONML.parse(new XMLTokener(string), false, null, config, 0); - } - - public static JSONObject toJSONObject(XMLTokener x) throws JSONException { - return (JSONObject)JSONML.parse(x, false, null, false, 0); - } - - public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { - return (JSONObject)JSONML.parse(x, false, null, keepStrings, 0); - } - - public static JSONObject toJSONObject(XMLTokener x, JSONMLParserConfiguration config) throws JSONException { - return (JSONObject)JSONML.parse(x, false, null, config, 0); - } - - public static String toString(JSONArray ja) throws JSONException { - int length; - int i; - StringBuilder sb = new StringBuilder(); - String tagName = ja.getString(0); - XML.noSpace(tagName); - tagName = XML.escape(tagName); - sb.append('<'); - sb.append(tagName); - Object object = ja.opt(1); - if (object instanceof JSONObject) { - i = 2; - JSONObject jo = (JSONObject)object; - for (String key : jo.keySet()) { - Object value = jo.opt(key); - XML.noSpace(key); - if (value == null) continue; - sb.append(' '); - sb.append(XML.escape(key)); - sb.append('='); - sb.append('\"'); - sb.append(XML.escape(value.toString())); - sb.append('\"'); - } - } else { - i = 1; - } - if (i >= (length = ja.length())) { - sb.append('/'); - sb.append('>'); - } else { - sb.append('>'); - do { - object = ja.get(i); - ++i; - if (object == null) continue; - if (object instanceof String) { - sb.append(XML.escape(object.toString())); - continue; - } - if (object instanceof JSONObject) { - sb.append(JSONML.toString((JSONObject)object)); - continue; - } - if (object instanceof JSONArray) { - sb.append(JSONML.toString((JSONArray)object)); - continue; - } - sb.append(object.toString()); - } while (i < length); - sb.append('<'); - sb.append('/'); - sb.append(tagName); - sb.append('>'); - } - return sb.toString(); - } - - public static String toString(JSONObject jo) throws JSONException { - StringBuilder sb = new StringBuilder(); - String tagName = jo.optString("tagName"); - if (tagName == null) { - return XML.escape(jo.toString()); - } - XML.noSpace(tagName); - tagName = XML.escape(tagName); - sb.append('<'); - sb.append(tagName); - for (String key : jo.keySet()) { - if ("tagName".equals(key) || "childNodes".equals(key)) continue; - XML.noSpace(key); - Object value = jo.opt(key); - if (value == null) continue; - sb.append(' '); - sb.append(XML.escape(key)); - sb.append('='); - sb.append('\"'); - sb.append(XML.escape(value.toString())); - sb.append('\"'); - } - JSONArray ja = jo.optJSONArray("childNodes"); - if (ja == null) { - sb.append('/'); - sb.append('>'); - } else { - sb.append('>'); - int length = ja.length(); - for (int i = 0; i < length; ++i) { - Object object = ja.get(i); - if (object == null) continue; - if (object instanceof String) { - sb.append(XML.escape(object.toString())); - continue; - } - if (object instanceof JSONObject) { - sb.append(JSONML.toString((JSONObject)object)); - continue; - } - if (object instanceof JSONArray) { - sb.append(JSONML.toString((JSONArray)object)); - continue; - } - sb.append(object.toString()); - } - sb.append('<'); - sb.append('/'); - sb.append(tagName); - sb.append('>'); - } - return sb.toString(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONMLParserConfiguration.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONMLParserConfiguration.java deleted file mode 100644 index 6c65751..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONMLParserConfiguration.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.ParserConfiguration; - -public class JSONMLParserConfiguration -extends ParserConfiguration { - public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = 512; - public static final JSONMLParserConfiguration ORIGINAL = new JSONMLParserConfiguration(); - public static final JSONMLParserConfiguration KEEP_STRINGS = new JSONMLParserConfiguration().withKeepStrings(true); - - public JSONMLParserConfiguration() { - this.maxNestingDepth = 512; - } - - protected JSONMLParserConfiguration(boolean keepStrings, int maxNestingDepth) { - super(keepStrings, maxNestingDepth); - } - - @Override - protected JSONMLParserConfiguration clone() { - return new JSONMLParserConfiguration(this.keepStrings, this.maxNestingDepth); - } - - public JSONMLParserConfiguration withKeepStrings(boolean newVal) { - return (JSONMLParserConfiguration)super.withKeepStrings(newVal); - } - - public JSONMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) { - return (JSONMLParserConfiguration)super.withMaxNestingDepth(maxNestingDepth); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONObject.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONObject.java deleted file mode 100644 index aff7e1d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONObject.java +++ /dev/null @@ -1,1771 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONArray; -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONParserConfiguration; -import de.maxhenkel.voicechat.org.json.JSONPointer; -import de.maxhenkel.voicechat.org.json.JSONPointerException; -import de.maxhenkel.voicechat.org.json.JSONPropertyIgnore; -import de.maxhenkel.voicechat.org.json.JSONPropertyName; -import de.maxhenkel.voicechat.org.json.JSONString; -import de.maxhenkel.voicechat.org.json.JSONTokener; -import de.maxhenkel.voicechat.org.json.JSONWriter; -import de.maxhenkel.voicechat.org.json.StringBuilderWriter; -import java.io.Closeable; -import java.io.IOException; -import java.io.Writer; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.ResourceBundle; -import java.util.Set; -import java.util.regex.Pattern; - -public class JSONObject { - static final Pattern NUMBER_PATTERN = Pattern.compile("-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?"); - private final Map map; - public static final Object NULL = new Null(); - private static final Set EXCLUDED_RECORD_METHOD_NAMES = Collections.unmodifiableSet(new HashSet(Arrays.asList("get", "is", "set", "toString", "hashCode", "equals", "clone", "notify", "notifyAll", "wait"))); - - public Class getMapType() { - return this.map.getClass(); - } - - public JSONObject() { - this.map = new HashMap(); - } - - public JSONObject(JSONObject jo, String ... names) { - this(names.length); - for (int i = 0; i < names.length; ++i) { - try { - this.putOnce(names[i], jo.opt(names[i])); - continue; - } - catch (Exception exception) { - // empty catch block - } - } - } - - public JSONObject(JSONTokener x) throws JSONException { - this(x, x.getJsonParserConfiguration()); - } - - public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException { - this(); - boolean isInitial; - boolean bl = isInitial = x.getPrevious() == '\u0000'; - if (x.nextClean() != '{') { - throw x.syntaxError("A JSONObject text must begin with '{'"); - } - while (!this.parseJSONObject(x, jsonParserConfiguration, isInitial)) { - } - } - - private boolean parseJSONObject(JSONTokener jsonTokener, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) { - boolean doneParsing = false; - char c = jsonTokener.nextClean(); - switch (c) { - case '\u0000': { - throw jsonTokener.syntaxError("A JSONObject text must end with '}'"); - } - case '}': { - if (isInitial && jsonParserConfiguration.isStrictMode() && jsonTokener.nextClean() != '\u0000') { - throw jsonTokener.syntaxError("Strict mode error: Unparsed characters found at end of input text"); - } - return true; - } - } - Object obj = jsonTokener.nextSimpleValue(c); - String key = obj.toString(); - JSONObject.checkKeyForStrictMode(jsonTokener, jsonParserConfiguration, obj); - c = jsonTokener.nextClean(); - if (c != ':') { - throw jsonTokener.syntaxError("Expected a ':' after a key"); - } - if (key != null) { - boolean keyExists; - boolean bl = keyExists = this.opt(key) != null; - if (keyExists && !jsonParserConfiguration.isOverwriteDuplicateKey()) { - throw jsonTokener.syntaxError("Duplicate key \"" + key + "\""); - } - Object value = jsonTokener.nextValue(); - if (value != null) { - this.put(key, value); - } - } - if (JSONObject.parseEndOfKeyValuePair(jsonTokener, jsonParserConfiguration, isInitial)) { - doneParsing = true; - } - return doneParsing; - } - - private static boolean parseEndOfKeyValuePair(JSONTokener jsonTokener, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) { - switch (jsonTokener.nextClean()) { - case ';': { - if (!jsonParserConfiguration.isStrictMode()) break; - throw jsonTokener.syntaxError("Strict mode error: Invalid character ';' found"); - } - case ',': { - if (jsonTokener.nextClean() == '}') { - if (jsonParserConfiguration.isStrictMode()) { - throw jsonTokener.syntaxError("Strict mode error: Expected another object element"); - } - return true; - } - if (jsonTokener.end()) { - throw jsonTokener.syntaxError("A JSONObject text must end with '}'"); - } - jsonTokener.back(); - break; - } - case '}': { - if (isInitial && jsonParserConfiguration.isStrictMode() && jsonTokener.nextClean() != '\u0000') { - throw jsonTokener.syntaxError("Strict mode error: Unparsed characters found at end of input text"); - } - return true; - } - default: { - throw jsonTokener.syntaxError("Expected a ',' or '}'"); - } - } - return false; - } - - private static void checkKeyForStrictMode(JSONTokener jsonTokener, JSONParserConfiguration jsonParserConfiguration, Object obj) { - if (jsonParserConfiguration != null && jsonParserConfiguration.isStrictMode()) { - if (obj instanceof Boolean) { - throw jsonTokener.syntaxError(String.format("Strict mode error: key '%s' cannot be boolean", obj.toString())); - } - if (obj == NULL) { - throw jsonTokener.syntaxError(String.format("Strict mode error: key '%s' cannot be null", obj.toString())); - } - if (obj instanceof Number) { - throw jsonTokener.syntaxError(String.format("Strict mode error: key '%s' cannot be number", obj.toString())); - } - } - } - - public JSONObject(Map m) { - this(m, 0, new JSONParserConfiguration()); - } - - public JSONObject(Map m, JSONParserConfiguration jsonParserConfiguration) { - this(m, 0, jsonParserConfiguration); - } - - private JSONObject(Map m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { - if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) { - throw new JSONException("JSONObject has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); - } - if (m == null) { - this.map = new HashMap(); - } else { - this.map = new HashMap(m.size()); - for (Map.Entry e : m.entrySet()) { - if (e.getKey() == null) { - throw new NullPointerException("Null key."); - } - Object value = e.getValue(); - if (value == null && !jsonParserConfiguration.isUseNativeNulls()) continue; - JSONObject.testValidity(value); - this.map.put(String.valueOf(e.getKey()), JSONObject.wrap(value, recursionDepth + 1, jsonParserConfiguration)); - } - } - } - - public JSONObject(Object bean) { - this(); - this.populateMap(bean, new JSONParserConfiguration()); - } - - public JSONObject(Object bean, JSONParserConfiguration jsonParserConfiguration) { - this(); - this.populateMap(bean, jsonParserConfiguration); - } - - private JSONObject(Object bean, Set objectsRecord) { - this(); - this.populateMap(bean, objectsRecord, new JSONParserConfiguration()); - } - - public JSONObject(Object object, String ... names) { - this(names.length); - Class c = object.getClass(); - for (int i = 0; i < names.length; ++i) { - String name = names[i]; - try { - this.putOpt(name, c.getField(name).get(object)); - continue; - } - catch (Exception exception) { - // empty catch block - } - } - } - - public JSONObject(String source) throws JSONException { - this(source, new JSONParserConfiguration()); - } - - public JSONObject(String source, JSONParserConfiguration jsonParserConfiguration) throws JSONException { - this(new JSONTokener(source, jsonParserConfiguration), jsonParserConfiguration); - } - - public JSONObject(String baseName, Locale locale) throws JSONException { - this(); - ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, Thread.currentThread().getContextClassLoader()); - Enumeration keys = bundle.getKeys(); - while (keys.hasMoreElements()) { - String key = keys.nextElement(); - if (key == null) continue; - String[] path = key.split("\\."); - int last = path.length - 1; - JSONObject target = this; - for (int i = 0; i < last; ++i) { - String segment = path[i]; - JSONObject nextTarget = target.optJSONObject(segment); - if (nextTarget == null) { - nextTarget = new JSONObject(); - target.put(segment, nextTarget); - } - target = nextTarget; - } - target.put(path[last], bundle.getString(key)); - } - } - - protected JSONObject(int initialCapacity) { - this.map = new HashMap(initialCapacity); - } - - public JSONObject accumulate(String key, Object value) throws JSONException { - JSONObject.testValidity(value); - Object object = this.opt(key); - if (object == null) { - this.put(key, value instanceof JSONArray ? new JSONArray().put(value) : value); - } else if (object instanceof JSONArray) { - ((JSONArray)object).put(value); - } else { - this.put(key, new JSONArray().put(object).put(value)); - } - return this; - } - - public JSONObject append(String key, Object value) throws JSONException { - JSONObject.testValidity(value); - Object object = this.opt(key); - if (object == null) { - this.put(key, new JSONArray().put(value)); - } else if (object instanceof JSONArray) { - this.put(key, ((JSONArray)object).put(value)); - } else { - throw JSONObject.wrongValueFormatException(key, "JSONArray", null, null); - } - return this; - } - - public static String doubleToString(double d) { - if (Double.isInfinite(d) || Double.isNaN(d)) { - return "null"; - } - String string = Double.toString(d); - if (string.indexOf(46) > 0 && string.indexOf(101) < 0 && string.indexOf(69) < 0) { - while (string.endsWith("0")) { - string = string.substring(0, string.length() - 1); - } - if (string.endsWith(".")) { - string = string.substring(0, string.length() - 1); - } - } - return string; - } - - public Object get(String key) throws JSONException { - if (key == null) { - throw new JSONException("Null key."); - } - Object object = this.opt(key); - if (object == null) { - throw new JSONException("JSONObject[" + JSONObject.quote(key) + "] not found."); - } - return object; - } - - public > E getEnum(Class clazz, String key) throws JSONException { - E val = this.optEnum(clazz, key); - if (val == null) { - throw JSONObject.wrongValueFormatException(key, "enum of type " + JSONObject.quote(clazz.getSimpleName()), this.opt(key), null); - } - return val; - } - - public boolean getBoolean(String key) throws JSONException { - Object object = this.get(key); - if (Boolean.FALSE.equals(object) || object instanceof String && "false".equalsIgnoreCase((String)object)) { - return false; - } - if (Boolean.TRUE.equals(object) || object instanceof String && "true".equalsIgnoreCase((String)object)) { - return true; - } - throw JSONObject.wrongValueFormatException(key, "Boolean", object, null); - } - - public BigInteger getBigInteger(String key) throws JSONException { - Object object = this.get(key); - BigInteger ret = JSONObject.objectToBigInteger(object, null); - if (ret != null) { - return ret; - } - throw JSONObject.wrongValueFormatException(key, "BigInteger", object, null); - } - - public BigDecimal getBigDecimal(String key) throws JSONException { - Object object = this.get(key); - BigDecimal ret = JSONObject.objectToBigDecimal(object, null); - if (ret != null) { - return ret; - } - throw JSONObject.wrongValueFormatException(key, "BigDecimal", object, null); - } - - public double getDouble(String key) throws JSONException { - Object object = this.get(key); - if (object instanceof Number) { - return ((Number)object).doubleValue(); - } - try { - return Double.parseDouble(object.toString()); - } - catch (Exception e) { - throw JSONObject.wrongValueFormatException(key, "double", object, e); - } - } - - public float getFloat(String key) throws JSONException { - Object object = this.get(key); - if (object instanceof Number) { - return ((Number)object).floatValue(); - } - try { - return Float.parseFloat(object.toString()); - } - catch (Exception e) { - throw JSONObject.wrongValueFormatException(key, "float", object, e); - } - } - - public Number getNumber(String key) throws JSONException { - Object object = this.get(key); - try { - if (object instanceof Number) { - return (Number)object; - } - return JSONObject.stringToNumber(object.toString()); - } - catch (Exception e) { - throw JSONObject.wrongValueFormatException(key, "number", object, e); - } - } - - public int getInt(String key) throws JSONException { - Object object = this.get(key); - if (object instanceof Number) { - return ((Number)object).intValue(); - } - try { - return Integer.parseInt(object.toString()); - } - catch (Exception e) { - throw JSONObject.wrongValueFormatException(key, "int", object, e); - } - } - - public JSONArray getJSONArray(String key) throws JSONException { - Object object = this.get(key); - if (object instanceof JSONArray) { - return (JSONArray)object; - } - throw JSONObject.wrongValueFormatException(key, "JSONArray", object, null); - } - - public JSONObject getJSONObject(String key) throws JSONException { - Object object = this.get(key); - if (object instanceof JSONObject) { - return (JSONObject)object; - } - throw JSONObject.wrongValueFormatException(key, "JSONObject", object, null); - } - - public long getLong(String key) throws JSONException { - Object object = this.get(key); - if (object instanceof Number) { - return ((Number)object).longValue(); - } - try { - return Long.parseLong(object.toString()); - } - catch (Exception e) { - throw JSONObject.wrongValueFormatException(key, "long", object, e); - } - } - - public static String[] getNames(JSONObject jo) { - if (jo.isEmpty()) { - return null; - } - return jo.keySet().toArray(new String[jo.length()]); - } - - public static String[] getNames(Object object) { - if (object == null) { - return null; - } - Class klass = object.getClass(); - Field[] fields = klass.getFields(); - int length = fields.length; - if (length == 0) { - return null; - } - String[] names = new String[length]; - for (int i = 0; i < length; ++i) { - names[i] = fields[i].getName(); - } - return names; - } - - public String getString(String key) throws JSONException { - Object object = this.get(key); - if (object instanceof String) { - return (String)object; - } - throw JSONObject.wrongValueFormatException(key, "string", object, null); - } - - public boolean has(String key) { - return this.map.containsKey(key); - } - - public JSONObject increment(String key) throws JSONException { - Object value = this.opt(key); - if (value == null) { - this.put(key, 1); - } else if (value instanceof Integer) { - this.put(key, (Integer)value + 1); - } else if (value instanceof Long) { - this.put(key, (Long)value + 1L); - } else if (value instanceof BigInteger) { - this.put(key, ((BigInteger)value).add(BigInteger.ONE)); - } else if (value instanceof Float) { - this.put(key, ((Float)value).floatValue() + 1.0f); - } else if (value instanceof Double) { - this.put(key, (Double)value + 1.0); - } else if (value instanceof BigDecimal) { - this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); - } else { - throw new JSONException("Unable to increment [" + JSONObject.quote(key) + "]."); - } - return this; - } - - public boolean isNull(String key) { - return NULL.equals(this.opt(key)); - } - - public Iterator keys() { - return this.keySet().iterator(); - } - - public Set keySet() { - return this.map.keySet(); - } - - protected Set> entrySet() { - return this.map.entrySet(); - } - - public int length() { - return this.map.size(); - } - - public void clear() { - this.map.clear(); - } - - public boolean isEmpty() { - return this.map.isEmpty(); - } - - public JSONArray names() { - if (this.map.isEmpty()) { - return null; - } - return new JSONArray((Collection)this.map.keySet()); - } - - public static String numberToString(Number number) throws JSONException { - if (number == null) { - throw new JSONException("Null pointer"); - } - JSONObject.testValidity(number); - String string = number.toString(); - if (string.indexOf(46) > 0 && string.indexOf(101) < 0 && string.indexOf(69) < 0) { - while (string.endsWith("0")) { - string = string.substring(0, string.length() - 1); - } - if (string.endsWith(".")) { - string = string.substring(0, string.length() - 1); - } - } - return string; - } - - public Object opt(String key) { - return key == null ? null : this.map.get(key); - } - - public > E optEnum(Class clazz, String key) { - return this.optEnum(clazz, key, null); - } - - public > E optEnum(Class clazz, String key, E defaultValue) { - try { - Object val = this.opt(key); - if (NULL.equals(val)) { - return defaultValue; - } - if (clazz.isAssignableFrom(val.getClass())) { - Enum myE = (Enum)val; - return (E)myE; - } - return Enum.valueOf(clazz, val.toString()); - } - catch (IllegalArgumentException e) { - return defaultValue; - } - catch (NullPointerException e) { - return defaultValue; - } - } - - public boolean optBoolean(String key) { - return this.optBoolean(key, false); - } - - public boolean optBoolean(String key, boolean defaultValue) { - Object val = this.opt(key); - if (NULL.equals(val)) { - return defaultValue; - } - if (val instanceof Boolean) { - return (Boolean)val; - } - try { - return this.getBoolean(key); - } - catch (Exception e) { - return defaultValue; - } - } - - public Boolean optBooleanObject(String key) { - return this.optBooleanObject(key, false); - } - - public Boolean optBooleanObject(String key, Boolean defaultValue) { - Object val = this.opt(key); - if (NULL.equals(val)) { - return defaultValue; - } - if (val instanceof Boolean) { - return (boolean)((Boolean)val); - } - try { - return this.getBoolean(key); - } - catch (Exception e) { - return defaultValue; - } - } - - public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { - Object val = this.opt(key); - return JSONObject.objectToBigDecimal(val, defaultValue); - } - - static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) { - return JSONObject.objectToBigDecimal(val, defaultValue, true); - } - - static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue, boolean exact) { - if (NULL.equals(val)) { - return defaultValue; - } - if (val instanceof BigDecimal) { - return (BigDecimal)val; - } - if (val instanceof BigInteger) { - return new BigDecimal((BigInteger)val); - } - if (val instanceof Double || val instanceof Float) { - if (!JSONObject.numberIsFinite((Number)val)) { - return defaultValue; - } - if (exact) { - return new BigDecimal(((Number)val).doubleValue()); - } - return new BigDecimal(val.toString()); - } - if (val instanceof Long || val instanceof Integer || val instanceof Short || val instanceof Byte) { - return new BigDecimal(((Number)val).longValue()); - } - try { - return new BigDecimal(val.toString()); - } - catch (Exception e) { - return defaultValue; - } - } - - public BigInteger optBigInteger(String key, BigInteger defaultValue) { - Object val = this.opt(key); - return JSONObject.objectToBigInteger(val, defaultValue); - } - - static BigInteger objectToBigInteger(Object val, BigInteger defaultValue) { - if (NULL.equals(val)) { - return defaultValue; - } - if (val instanceof BigInteger) { - return (BigInteger)val; - } - if (val instanceof BigDecimal) { - return ((BigDecimal)val).toBigInteger(); - } - if (val instanceof Double || val instanceof Float) { - if (!JSONObject.numberIsFinite((Number)val)) { - return defaultValue; - } - return BigDecimal.valueOf(((Number)val).doubleValue()).toBigInteger(); - } - if (val instanceof Long || val instanceof Integer || val instanceof Short || val instanceof Byte) { - return BigInteger.valueOf(((Number)val).longValue()); - } - try { - String valStr = val.toString(); - if (JSONObject.isDecimalNotation(valStr)) { - return new BigDecimal(valStr).toBigInteger(); - } - return new BigInteger(valStr); - } - catch (Exception e) { - return defaultValue; - } - } - - public double optDouble(String key) { - return this.optDouble(key, Double.NaN); - } - - public double optDouble(String key, double defaultValue) { - Number val = this.optNumber(key); - if (val == null) { - return defaultValue; - } - return val.doubleValue(); - } - - public Double optDoubleObject(String key) { - return this.optDoubleObject(key, Double.NaN); - } - - public Double optDoubleObject(String key, Double defaultValue) { - Number val = this.optNumber(key); - if (val == null) { - return defaultValue; - } - return val.doubleValue(); - } - - public float optFloat(String key) { - return this.optFloat(key, Float.NaN); - } - - public float optFloat(String key, float defaultValue) { - Number val = this.optNumber(key); - if (val == null) { - return defaultValue; - } - return val.floatValue(); - } - - public Float optFloatObject(String key) { - return this.optFloatObject(key, Float.valueOf(Float.NaN)); - } - - public Float optFloatObject(String key, Float defaultValue) { - Number val = this.optNumber(key); - if (val == null) { - return defaultValue; - } - return Float.valueOf(val.floatValue()); - } - - public int optInt(String key) { - return this.optInt(key, 0); - } - - public int optInt(String key, int defaultValue) { - Number val = this.optNumber(key, null); - if (val == null) { - return defaultValue; - } - return val.intValue(); - } - - public Integer optIntegerObject(String key) { - return this.optIntegerObject(key, 0); - } - - public Integer optIntegerObject(String key, Integer defaultValue) { - Number val = this.optNumber(key, null); - if (val == null) { - return defaultValue; - } - return val.intValue(); - } - - public JSONArray optJSONArray(String key) { - return this.optJSONArray(key, null); - } - - public JSONArray optJSONArray(String key, JSONArray defaultValue) { - Object object = this.opt(key); - return object instanceof JSONArray ? (JSONArray)object : defaultValue; - } - - public JSONObject optJSONObject(String key) { - return this.optJSONObject(key, null); - } - - public JSONObject optJSONObject(String key, JSONObject defaultValue) { - Object object = this.opt(key); - return object instanceof JSONObject ? (JSONObject)object : defaultValue; - } - - public long optLong(String key) { - return this.optLong(key, 0L); - } - - public long optLong(String key, long defaultValue) { - Number val = this.optNumber(key, null); - if (val == null) { - return defaultValue; - } - return val.longValue(); - } - - public Long optLongObject(String key) { - return this.optLongObject(key, 0L); - } - - public Long optLongObject(String key, Long defaultValue) { - Number val = this.optNumber(key, null); - if (val == null) { - return defaultValue; - } - return val.longValue(); - } - - public Number optNumber(String key) { - return this.optNumber(key, null); - } - - public Number optNumber(String key, Number defaultValue) { - Object val = this.opt(key); - if (NULL.equals(val)) { - return defaultValue; - } - if (val instanceof Number) { - return (Number)val; - } - try { - return JSONObject.stringToNumber(val.toString()); - } - catch (Exception e) { - return defaultValue; - } - } - - public String optString(String key) { - return this.optString(key, ""); - } - - public String optString(String key, String defaultValue) { - Object object = this.opt(key); - return NULL.equals(object) ? defaultValue : object.toString(); - } - - private void populateMap(Object bean, JSONParserConfiguration jsonParserConfiguration) { - this.populateMap(bean, Collections.newSetFromMap(new IdentityHashMap()), jsonParserConfiguration); - } - - private void populateMap(Object bean, Set objectsRecord, JSONParserConfiguration jsonParserConfiguration) { - Method[] methods; - Class klass = bean.getClass(); - boolean isRecord = JSONObject.isRecordType(klass); - for (Method method : methods = JSONObject.getMethods(klass)) { - String key; - if (!JSONObject.isValidMethod(method) || (key = JSONObject.getKeyNameFromMethod(method, isRecord)) == null || key.isEmpty()) continue; - this.processMethod(bean, objectsRecord, jsonParserConfiguration, method, key); - } - } - - private void processMethod(Object bean, Set objectsRecord, JSONParserConfiguration jsonParserConfiguration, Method method, String key) { - try { - Object result = method.invoke(bean, new Object[0]); - if (result != null || jsonParserConfiguration.isUseNativeNulls()) { - if (objectsRecord.contains(result)) { - throw JSONObject.recursivelyDefinedObjectException(key); - } - objectsRecord.add(result); - JSONObject.testValidity(result); - this.map.put(key, JSONObject.wrap(result, objectsRecord)); - objectsRecord.remove(result); - JSONObject.closeClosable(result); - } - } - catch (IllegalAccessException illegalAccessException) { - } - catch (IllegalArgumentException illegalArgumentException) { - } - catch (InvocationTargetException invocationTargetException) { - // empty catch block - } - } - - private static boolean isRecordType(Class klass) { - try { - Method isRecordMethod = Class.class.getMethod("isRecord", new Class[0]); - return (Boolean)isRecordMethod.invoke(klass, new Object[0]); - } - catch (NoSuchMethodException e) { - return false; - } - catch (Exception e) { - return false; - } - } - - private static Method[] getMethods(Class klass) { - boolean includeSuperClass = klass.getClassLoader() != null; - return includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods(); - } - - private static boolean isValidMethodName(String name) { - return !"getClass".equals(name) && !"getDeclaringClass".equals(name); - } - - private static String getKeyNameFromMethod(Method method, boolean isRecordType) { - String key; - int forcedNameDepth; - int ignoreDepth = JSONObject.getAnnotationDepth(method, JSONPropertyIgnore.class); - if (ignoreDepth > 0 && ((forcedNameDepth = JSONObject.getAnnotationDepth(method, JSONPropertyName.class)) < 0 || ignoreDepth <= forcedNameDepth)) { - return null; - } - JSONPropertyName annotation = JSONObject.getAnnotation(method, JSONPropertyName.class); - if (JSONObject.annotationValueNotEmpty(annotation)) { - return annotation.value(); - } - String name = method.getName(); - if (name.startsWith("get") && name.length() > 3) { - key = name.substring(3); - } else if (name.startsWith("is") && name.length() > 2) { - key = name.substring(2); - } else { - if (isRecordType && JSONObject.isRecordStyleAccessor(name, method)) { - return name; - } - return null; - } - if (key.isEmpty() || Character.isLowerCase(key.charAt(0))) { - return null; - } - if (key.length() == 1) { - key = key.toLowerCase(Locale.ROOT); - } else if (!Character.isUpperCase(key.charAt(1))) { - key = key.substring(0, 1).toLowerCase(Locale.ROOT) + key.substring(1); - } - return key; - } - - private static boolean isRecordStyleAccessor(String methodName, Method method) { - if (methodName.isEmpty() || !Character.isLowerCase(methodName.charAt(0))) { - return false; - } - if (EXCLUDED_RECORD_METHOD_NAMES.contains(methodName)) { - return false; - } - Class declaringClass = method.getDeclaringClass(); - if (declaringClass == null || declaringClass == Object.class) { - return false; - } - if (Enum.class.isAssignableFrom(declaringClass) || Number.class.isAssignableFrom(declaringClass)) { - return false; - } - String className = declaringClass.getName(); - return !className.startsWith("java.") && !className.startsWith("javax."); - } - - private static boolean annotationValueNotEmpty(JSONPropertyName annotation) { - return annotation != null && annotation.value() != null && !annotation.value().isEmpty(); - } - - private static boolean isValidMethod(Method method) { - int modifiers = method.getModifiers(); - return Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && method.getParameterTypes().length == 0 && !method.isBridge() && method.getReturnType() != Void.TYPE && JSONObject.isValidMethodName(method.getName()); - } - - private static void closeClosable(Object input) { - if (input instanceof Closeable) { - try { - ((Closeable)input).close(); - } - catch (IOException iOException) { - // empty catch block - } - } - } - - private static A getAnnotation(Method m, Class annotationClass) { - if (m == null || annotationClass == null) { - return null; - } - if (m.isAnnotationPresent(annotationClass)) { - return m.getAnnotation(annotationClass); - } - Class c = m.getDeclaringClass(); - if (c.getSuperclass() == null) { - return null; - } - for (Class i : c.getInterfaces()) { - try { - Method im = i.getMethod(m.getName(), m.getParameterTypes()); - return JSONObject.getAnnotation(im, annotationClass); - } - catch (SecurityException securityException) { - } - catch (NoSuchMethodException noSuchMethodException) { - // empty catch block - } - } - if (Object.class.equals(c.getSuperclass())) { - return null; - } - try { - return JSONObject.getAnnotation(c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()), annotationClass); - } - catch (SecurityException ex) { - return null; - } - catch (NoSuchMethodException ex) { - return null; - } - } - - private static int getAnnotationDepth(Method m, Class annotationClass) { - if (m == null || annotationClass == null) { - return -1; - } - if (m.isAnnotationPresent(annotationClass)) { - return 1; - } - Class c = m.getDeclaringClass(); - if (c.getSuperclass() == null) { - return -1; - } - for (Class i : c.getInterfaces()) { - try { - Method im = i.getMethod(m.getName(), m.getParameterTypes()); - int d = JSONObject.getAnnotationDepth(im, annotationClass); - if (d <= 0) continue; - return d + 1; - } - catch (SecurityException securityException) { - } - catch (NoSuchMethodException noSuchMethodException) { - // empty catch block - } - } - if (Object.class.equals(c.getSuperclass())) { - return -1; - } - try { - int d = JSONObject.getAnnotationDepth(c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()), annotationClass); - if (d > 0) { - return d + 1; - } - return -1; - } - catch (SecurityException ex) { - return -1; - } - catch (NoSuchMethodException ex) { - return -1; - } - } - - public JSONObject put(String key, boolean value) throws JSONException { - return this.put(key, value ? Boolean.TRUE : Boolean.FALSE); - } - - public JSONObject put(String key, Collection value) throws JSONException { - return this.put(key, new JSONArray(value)); - } - - public JSONObject put(String key, double value) throws JSONException { - return this.put(key, (Object)value); - } - - public JSONObject put(String key, float value) throws JSONException { - return this.put(key, Float.valueOf(value)); - } - - public JSONObject put(String key, int value) throws JSONException { - return this.put(key, (Object)value); - } - - public JSONObject put(String key, long value) throws JSONException { - return this.put(key, (Object)value); - } - - public JSONObject put(String key, Map value) throws JSONException { - return this.put(key, new JSONObject(value)); - } - - public JSONObject put(String key, Object value) throws JSONException { - if (key == null) { - throw new NullPointerException("Null key."); - } - if (value != null) { - JSONObject.testValidity(value); - this.map.put(key, value); - } else { - this.remove(key); - } - return this; - } - - public JSONObject putOnce(String key, Object value) throws JSONException { - if (key != null && value != null) { - if (this.opt(key) != null) { - throw new JSONException("Duplicate key \"" + key + "\""); - } - return this.put(key, value); - } - return this; - } - - public JSONObject putOpt(String key, Object value) throws JSONException { - if (key != null && value != null) { - return this.put(key, value); - } - return this; - } - - public Object query(String jsonPointer) { - return this.query(new JSONPointer(jsonPointer)); - } - - public Object query(JSONPointer jsonPointer) { - return jsonPointer.queryFrom(this); - } - - public Object optQuery(String jsonPointer) { - return this.optQuery(new JSONPointer(jsonPointer)); - } - - public Object optQuery(JSONPointer jsonPointer) { - try { - return jsonPointer.queryFrom(this); - } - catch (JSONPointerException e) { - return null; - } - } - - public static String quote(String string) { - if (string == null || string.isEmpty()) { - return "\"\""; - } - StringBuilderWriter sw = new StringBuilderWriter(string.length() + 2); - try { - return JSONObject.quote(string, sw).toString(); - } - catch (IOException ignored) { - return ""; - } - } - - public static Writer quote(String string, Writer w) throws IOException { - if (string == null || string.isEmpty()) { - w.write("\"\""); - return w; - } - char c = '\u0000'; - int len = string.length(); - w.write(34); - block9: for (int i = 0; i < len; ++i) { - char b = c; - c = string.charAt(i); - switch (c) { - case '\"': - case '\\': { - w.write(92); - w.write(c); - continue block9; - } - case '/': { - if (b == '<') { - w.write(92); - } - w.write(c); - continue block9; - } - case '\b': { - w.write("\\b"); - continue block9; - } - case '\t': { - w.write("\\t"); - continue block9; - } - case '\n': { - w.write("\\n"); - continue block9; - } - case '\f': { - w.write("\\f"); - continue block9; - } - case '\r': { - w.write("\\r"); - continue block9; - } - default: { - JSONObject.writeAsHex(w, c); - } - } - } - w.write(34); - return w; - } - - private static void writeAsHex(Writer w, char c) throws IOException { - if (c < ' ' || c >= '\u0080' && c < '\u00a0' || c >= '\u2000' && c < '\u2100') { - w.write("\\u"); - String hhhh = Integer.toHexString(c); - w.write("0000", 0, 4 - hhhh.length()); - w.write(hhhh); - } else { - w.write(c); - } - } - - public Object remove(String key) { - return this.map.remove(key); - } - - public boolean similar(Object other) { - try { - if (!(other instanceof JSONObject)) { - return false; - } - if (!this.keySet().equals(((JSONObject)other).keySet())) { - return false; - } - return this.checkSimilarEntries(other); - } - catch (Exception e) { - return false; - } - } - - private boolean checkSimilarEntries(Object other) { - for (Map.Entry entry : this.entrySet()) { - Object valueOther; - String name = entry.getKey(); - Object valueThis = entry.getValue(); - if (valueThis == (valueOther = ((JSONObject)other).get(name))) continue; - if (valueThis == null) { - return false; - } - if (this.checkObjectType(valueThis, valueOther)) continue; - return false; - } - return true; - } - - private boolean checkObjectType(Object valueThis, Object valueOther) { - if (valueThis instanceof JSONObject) { - return ((JSONObject)valueThis).similar(valueOther); - } - if (valueThis instanceof JSONArray) { - return ((JSONArray)valueThis).similar(valueOther); - } - if (valueThis instanceof Number && valueOther instanceof Number) { - return JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther); - } - if (valueThis instanceof JSONString && valueOther instanceof JSONString) { - return ((JSONString)valueThis).toJSONString().equals(((JSONString)valueOther).toJSONString()); - } - return valueThis.equals(valueOther); - } - - static boolean isNumberSimilar(Number l, Number r) { - if (!JSONObject.numberIsFinite(l) || !JSONObject.numberIsFinite(r)) { - return false; - } - if (l.getClass().equals(r.getClass()) && l instanceof Comparable) { - int compareTo = ((Comparable)((Object)l)).compareTo(r); - return compareTo == 0; - } - BigDecimal lBigDecimal = JSONObject.objectToBigDecimal(l, null, false); - BigDecimal rBigDecimal = JSONObject.objectToBigDecimal(r, null, false); - if (lBigDecimal == null || rBigDecimal == null) { - return false; - } - return lBigDecimal.compareTo(rBigDecimal) == 0; - } - - private static boolean numberIsFinite(Number n) { - if (n instanceof Double && (((Double)n).isInfinite() || ((Double)n).isNaN())) { - return false; - } - return !(n instanceof Float) || !((Float)n).isInfinite() && !((Float)n).isNaN(); - } - - protected static boolean isDecimalNotation(String val) { - return val.indexOf(46) > -1 || val.indexOf(101) > -1 || val.indexOf(69) > -1 || "-0".equals(val); - } - - public static Object stringToValue(String string) { - if ("".equals(string)) { - return string; - } - if ("true".equalsIgnoreCase(string)) { - return Boolean.TRUE; - } - if ("false".equalsIgnoreCase(string)) { - return Boolean.FALSE; - } - if ("null".equalsIgnoreCase(string)) { - return NULL; - } - char initial = string.charAt(0); - if (initial >= '0' && initial <= '9' || initial == '-') { - try { - return JSONObject.stringToNumber(string); - } - catch (Exception exception) { - // empty catch block - } - } - return string; - } - - protected static Number stringToNumber(String val) throws NumberFormatException { - char initial = val.charAt(0); - if (initial >= '0' && initial <= '9' || initial == '-') { - if (JSONObject.isDecimalNotation(val)) { - return JSONObject.getNumber(val, initial); - } - JSONObject.checkForInvalidNumberFormat(val, initial); - BigInteger bi = new BigInteger(val); - if (bi.bitLength() <= 31) { - return bi.intValue(); - } - if (bi.bitLength() <= 63) { - return bi.longValue(); - } - return bi; - } - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - - private static void checkForInvalidNumberFormat(String val, char initial) { - if (initial == '0' && val.length() > 1) { - char at1 = val.charAt(1); - if (at1 >= '0' && at1 <= '9') { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - } else if (initial == '-' && val.length() > 2) { - char at1 = val.charAt(1); - char at2 = val.charAt(2); - if (at1 == '0' && at2 >= '0' && at2 <= '9') { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - } - } - - private static Number getNumber(String val, char initial) { - try { - BigDecimal bd = new BigDecimal(val); - if (initial == '-' && BigDecimal.ZERO.compareTo(bd) == 0) { - return -0.0; - } - return bd; - } - catch (NumberFormatException retryAsDouble) { - try { - Double d = Double.valueOf(val); - if (d.isNaN() || d.isInfinite()) { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - return d; - } - catch (NumberFormatException ignore) { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - } - } - - public static void testValidity(Object o) throws JSONException { - if (o instanceof Number && !JSONObject.numberIsFinite((Number)o)) { - throw new JSONException("JSON does not allow non-finite numbers."); - } - } - - public JSONArray toJSONArray(JSONArray names) throws JSONException { - if (names == null || names.isEmpty()) { - return null; - } - JSONArray ja = new JSONArray(); - for (int i = 0; i < names.length(); ++i) { - ja.put(this.opt(names.getString(i))); - } - return ja; - } - - public String toString() { - try { - return this.toString(0); - } - catch (Exception e) { - return null; - } - } - - public String toString(int indentFactor) throws JSONException { - int initialSize = this.map.size() * 6; - StringBuilderWriter w = new StringBuilderWriter(Math.max(initialSize, 16)); - return this.write(w, indentFactor, 0).toString(); - } - - public static String valueToString(Object value) throws JSONException { - return JSONWriter.valueToString(value); - } - - public static Object wrap(Object object) { - return JSONObject.wrap(object, null); - } - - static Object wrap(Object object, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { - return JSONObject.wrap(object, null, recursionDepth, jsonParserConfiguration); - } - - private static Object wrap(Object object, Set objectsRecord) { - return JSONObject.wrap(object, objectsRecord, 0, new JSONParserConfiguration()); - } - - private static Object wrap(Object object, Set objectsRecord, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { - try { - String objectPackageName; - if (NULL.equals(object)) { - return NULL; - } - if (object instanceof JSONObject || object instanceof JSONArray || object instanceof JSONString || object instanceof String || object instanceof Byte || object instanceof Character || object instanceof Short || object instanceof Integer || object instanceof Long || object instanceof Boolean || object instanceof Float || object instanceof Double || object instanceof BigInteger || object instanceof BigDecimal || object instanceof Enum) { - return object; - } - if (object instanceof Collection) { - Collection coll = (Collection)object; - return new JSONArray(coll, recursionDepth, jsonParserConfiguration); - } - if (object.getClass().isArray()) { - return new JSONArray(object); - } - if (object instanceof Map) { - Map map = (Map)object; - return new JSONObject(map, recursionDepth, jsonParserConfiguration); - } - Package objectPackage = object.getClass().getPackage(); - String string = objectPackageName = objectPackage != null ? objectPackage.getName() : ""; - if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.") || object.getClass().getClassLoader() == null) { - return object.toString(); - } - if (objectsRecord != null) { - return new JSONObject(object, objectsRecord); - } - return new JSONObject(object); - } - catch (JSONException exception) { - throw exception; - } - catch (Exception exception) { - return null; - } - } - - public Writer write(Writer writer) throws JSONException { - return this.write(writer, 0, 0); - } - - static final Writer writeValue(Writer writer, Object value, int indentFactor, int indent) throws JSONException, IOException { - if (value == null || value.equals(null)) { - writer.write("null"); - } else if (value instanceof JSONString) { - JSONObject.processJsonStringToWriteValue(writer, value); - } else { - if (value instanceof String) { - JSONObject.quote(value.toString(), writer); - return writer; - } - if (value instanceof Number) { - JSONObject.processNumberToWriteValue(writer, (Number)value); - } else if (value instanceof Boolean) { - writer.write(value.toString()); - } else if (value instanceof Enum) { - writer.write(JSONObject.quote(((Enum)value).name())); - } else if (value instanceof JSONObject) { - ((JSONObject)value).write(writer, indentFactor, indent); - } else if (value instanceof JSONArray) { - ((JSONArray)value).write(writer, indentFactor, indent); - } else if (value instanceof Map) { - Map map = (Map)value; - new JSONObject(map).write(writer, indentFactor, indent); - } else if (value instanceof Collection) { - Collection coll = (Collection)value; - new JSONArray(coll).write(writer, indentFactor, indent); - } else if (value.getClass().isArray()) { - new JSONArray(value).write(writer, indentFactor, indent); - } else { - JSONObject.quote(value.toString(), writer); - } - } - return writer; - } - - private static void processJsonStringToWriteValue(Writer writer, Object value) throws IOException { - String o; - try { - o = ((JSONString)value).toJSONString(); - } - catch (Exception e) { - throw new JSONException(e); - } - writer.write(o != null ? o.toString() : JSONObject.quote(value.toString())); - } - - private static void processNumberToWriteValue(Writer writer, Number value) throws IOException { - String numberAsString = JSONObject.numberToString(value); - if (NUMBER_PATTERN.matcher(numberAsString).matches()) { - writer.write(numberAsString); - } else { - JSONObject.quote(numberAsString, writer); - } - } - - static final void indent(Writer writer, int indent) throws IOException { - for (int i = 0; i < indent; ++i) { - writer.write(32); - } - } - - public Writer write(Writer writer, int indentFactor, int indent) throws JSONException { - try { - boolean needsComma = false; - int length = this.length(); - writer.write(123); - if (length == 1) { - Map.Entry entry = this.entrySet().iterator().next(); - String key = entry.getKey(); - writer.write(JSONObject.quote(key)); - writer.write(58); - if (indentFactor > 0) { - writer.write(32); - } - JSONObject.attemptWriteValue(writer, indentFactor, indent, entry, key); - } else if (length != 0) { - this.writeContent(writer, indentFactor, indent, needsComma); - } - writer.write(125); - return writer; - } - catch (IOException exception) { - throw new JSONException(exception); - } - } - - private void writeContent(Writer writer, int indentFactor, int indent, boolean needsComma) throws IOException { - int newIndent = indent + indentFactor; - for (Map.Entry entry : this.entrySet()) { - if (needsComma) { - writer.write(44); - } - if (indentFactor > 0) { - writer.write(10); - } - JSONObject.indent(writer, newIndent); - String key = entry.getKey(); - writer.write(JSONObject.quote(key)); - writer.write(58); - if (indentFactor > 0) { - writer.write(32); - } - JSONObject.attemptWriteValue(writer, indentFactor, newIndent, entry, key); - needsComma = true; - } - if (indentFactor > 0) { - writer.write(10); - } - JSONObject.indent(writer, indent); - } - - private static void attemptWriteValue(Writer writer, int indentFactor, int indent, Map.Entry entry, String key) { - try { - JSONObject.writeValue(writer, entry.getValue(), indentFactor, indent); - } - catch (Exception e) { - throw new JSONException("Unable to write JSONObject value for key: " + key, e); - } - } - - public Map toMap() { - HashMap results = new HashMap(); - for (Map.Entry entry : this.entrySet()) { - Object value = entry.getValue() == null || NULL.equals(entry.getValue()) ? null : (entry.getValue() instanceof JSONObject ? ((JSONObject)entry.getValue()).toMap() : (entry.getValue() instanceof JSONArray ? ((JSONArray)entry.getValue()).toList() : entry.getValue())); - results.put(entry.getKey(), value); - } - return results; - } - - private static JSONException wrongValueFormatException(String key, String valueType, Object value, Throwable cause) { - if (value == null) { - return new JSONException("JSONObject[" + JSONObject.quote(key) + "] is not a " + valueType + " (null).", cause); - } - if (value instanceof Map || value instanceof Iterable || value instanceof JSONObject) { - return new JSONException("JSONObject[" + JSONObject.quote(key) + "] is not a " + valueType + " (" + value.getClass() + ").", cause); - } - return new JSONException("JSONObject[" + JSONObject.quote(key) + "] is not a " + valueType + " (" + value.getClass() + " : " + value + ").", cause); - } - - private static JSONException recursivelyDefinedObjectException(String key) { - return new JSONException("JavaBean object contains recursively defined member variable of key " + JSONObject.quote(key)); - } - - private Class getRawType(Type type) { - if (type instanceof Class) { - return (Class)type; - } - if (type instanceof ParameterizedType) { - return (Class)((ParameterizedType)type).getRawType(); - } - if (type instanceof GenericArrayType) { - return Object[].class; - } - return Object.class; - } - - private Type getElementType(Type type) { - if (type instanceof ParameterizedType) { - Type[] args = ((ParameterizedType)type).getActualTypeArguments(); - return args.length > 0 ? args[0] : Object.class; - } - return Object.class; - } - - private Type[] getMapTypes(Type type) { - Type[] args; - if (type instanceof ParameterizedType && (args = ((ParameterizedType)type).getActualTypeArguments()).length == 2) { - return args; - } - return new Type[]{Object.class, Object.class}; - } - - public static T fromJson(String jsonString, Class clazz) { - JSONObject jsonObject = new JSONObject(jsonString); - return jsonObject.fromJson(clazz); - } - - public T fromJson(Class clazz) { - try { - T obj = clazz.getDeclaredConstructor(new Class[0]).newInstance(new Object[0]); - for (Field field : clazz.getDeclaredFields()) { - field.setAccessible(true); - String fieldName = field.getName(); - if (!this.has(fieldName)) continue; - Object value = this.get(fieldName); - Type fieldType = field.getGenericType(); - Object convertedValue = this.convertValue(value, fieldType); - field.set(obj, convertedValue); - } - return obj; - } - catch (NoSuchMethodException e) { - throw new JSONException("No no-arg constructor for class: " + clazz.getName(), e); - } - catch (Exception e) { - throw new JSONException("Failed to instantiate or set field for class: " + clazz.getName(), e); - } - } - - private Object convertValue(Object value, Type targetType) throws JSONException { - if (value == null) { - return null; - } - Class rawType = this.getRawType(targetType); - if (rawType.isAssignableFrom(value.getClass())) { - return value; - } - if (rawType == Integer.TYPE || rawType == Integer.class) { - return ((Number)value).intValue(); - } - if (rawType == Double.TYPE || rawType == Double.class) { - return ((Number)value).doubleValue(); - } - if (rawType == Float.TYPE || rawType == Float.class) { - return Float.valueOf(((Number)value).floatValue()); - } - if (rawType == Long.TYPE || rawType == Long.class) { - return ((Number)value).longValue(); - } - if (rawType == Boolean.TYPE || rawType == Boolean.class) { - return value; - } - if (rawType == String.class) { - return value; - } - if (rawType == BigDecimal.class) { - return new BigDecimal((String)value); - } - if (rawType == BigInteger.class) { - return new BigInteger((String)value); - } - if (rawType.isEnum() && value instanceof String) { - return this.stringToEnum(rawType, (String)value); - } - if (Collection.class.isAssignableFrom(rawType)) { - if (value instanceof JSONArray) { - Type elementType = this.getElementType(targetType); - return this.fromJsonArray((JSONArray)value, rawType, elementType); - } - } else { - if (Map.class.isAssignableFrom(rawType) && value instanceof JSONObject) { - Type[] mapTypes = this.getMapTypes(targetType); - Type keyType = mapTypes[0]; - Type valueType = mapTypes[1]; - return this.convertToMap((JSONObject)value, keyType, valueType, rawType); - } - if (!rawType.isPrimitive() && !rawType.isEnum() && value instanceof JSONObject) { - return ((JSONObject)value).fromJson(rawType); - } - } - return value.toString(); - } - - private Map convertToMap(JSONObject jsonMap, Type keyType, Type valueType, Class mapType) throws JSONException { - try { - HashMap createdMap = new HashMap(); - Iterator iterator = jsonMap.keySet().iterator(); - while (iterator.hasNext()) { - String keyObj; - String keyStr = keyObj = iterator.next(); - Object mapValue = jsonMap.get(keyStr); - Object convertedKey = this.convertValue(keyStr, keyType); - Object convertedValue = this.convertValue(mapValue, valueType); - createdMap.put(convertedKey, convertedValue); - } - return createdMap; - } - catch (Exception e) { - throw new JSONException("Failed to convert JSONObject to Map: " + mapType.getName(), e); - } - } - - private E stringToEnum(Class enumClass, String value) throws JSONException { - try { - Class enumType = enumClass; - Method valueOfMethod = enumType.getMethod("valueOf", String.class); - return (E)valueOfMethod.invoke(null, value); - } - catch (Exception e) { - throw new JSONException("Failed to convert string to enum: " + value + " for " + enumClass.getName(), e); - } - } - - private Collection fromJsonArray(JSONArray jsonArray, Class collectionType, Type elementType) throws JSONException { - try { - Collection collection = this.getCollection(collectionType); - for (int i = 0; i < jsonArray.length(); ++i) { - Object jsonElement = jsonArray.get(i); - Object convertedValue = this.convertValue(jsonElement, elementType); - collection.add(convertedValue); - } - return collection; - } - catch (Exception e) { - throw new JSONException("Failed to convert JSONArray to Collection: " + collectionType.getName(), e); - } - } - - private Collection getCollection(Class collectionType) throws JSONException { - if (collectionType == List.class || collectionType == ArrayList.class) { - return new ArrayList(); - } - if (collectionType == Set.class || collectionType == HashSet.class) { - return new HashSet(); - } - throw new JSONException("Unsupported Collection type: " + collectionType.getName()); - } - - private static final class Null { - private Null() { - } - - public boolean equals(Object object) { - return object == null || object == this; - } - - public int hashCode() { - return 0; - } - - public String toString() { - return "null"; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONParserConfiguration.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONParserConfiguration.java deleted file mode 100644 index 933c56f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONParserConfiguration.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.ParserConfiguration; - -public class JSONParserConfiguration -extends ParserConfiguration { - private boolean overwriteDuplicateKey = false; - private boolean useNativeNulls; - private boolean strictMode; - - @Override - protected JSONParserConfiguration clone() { - JSONParserConfiguration clone = new JSONParserConfiguration(); - clone.overwriteDuplicateKey = this.overwriteDuplicateKey; - clone.strictMode = this.strictMode; - clone.maxNestingDepth = this.maxNestingDepth; - clone.keepStrings = this.keepStrings; - clone.useNativeNulls = this.useNativeNulls; - return clone; - } - - public JSONParserConfiguration withMaxNestingDepth(int maxNestingDepth) { - JSONParserConfiguration clone = this.clone(); - clone.maxNestingDepth = maxNestingDepth; - return clone; - } - - public JSONParserConfiguration withOverwriteDuplicateKey(boolean overwriteDuplicateKey) { - JSONParserConfiguration clone = this.clone(); - clone.overwriteDuplicateKey = overwriteDuplicateKey; - return clone; - } - - public JSONParserConfiguration withUseNativeNulls(boolean useNativeNulls) { - JSONParserConfiguration clone = this.clone(); - clone.useNativeNulls = useNativeNulls; - return clone; - } - - public JSONParserConfiguration withStrictMode() { - return this.withStrictMode(true); - } - - public JSONParserConfiguration withStrictMode(boolean mode) { - JSONParserConfiguration clone = this.clone(); - clone.strictMode = mode; - return clone; - } - - public boolean isOverwriteDuplicateKey() { - return this.overwriteDuplicateKey; - } - - public boolean isUseNativeNulls() { - return this.useNativeNulls; - } - - public boolean isStrictMode() { - return this.strictMode; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPointer.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPointer.java deleted file mode 100644 index 2c4e415..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPointer.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONArray; -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONObject; -import de.maxhenkel.voicechat.org.json.JSONPointerException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class JSONPointer { - private static final String ENCODING = "utf-8"; - private final List refTokens; - - public static Builder builder() { - return new Builder(); - } - - public JSONPointer(String pointer) { - String refs; - if (pointer == null) { - throw new NullPointerException("pointer cannot be null"); - } - if (pointer.isEmpty() || "#".equals(pointer)) { - this.refTokens = Collections.emptyList(); - return; - } - if (pointer.startsWith("#/")) { - refs = pointer.substring(2); - try { - refs = URLDecoder.decode(refs, ENCODING); - } - catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } else if (pointer.startsWith("/")) { - refs = pointer.substring(1); - } else { - throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'"); - } - this.refTokens = new ArrayList(); - int slashIdx = -1; - int prevSlashIdx = 0; - do { - String token; - if ((prevSlashIdx = slashIdx + 1) == (slashIdx = refs.indexOf(47, prevSlashIdx)) || prevSlashIdx == refs.length()) { - this.refTokens.add(""); - continue; - } - if (slashIdx >= 0) { - token = refs.substring(prevSlashIdx, slashIdx); - this.refTokens.add(JSONPointer.unescape(token)); - continue; - } - token = refs.substring(prevSlashIdx); - this.refTokens.add(JSONPointer.unescape(token)); - } while (slashIdx >= 0); - } - - public JSONPointer(List refTokens) { - this.refTokens = new ArrayList(refTokens); - } - - private static String unescape(String token) { - return token.replace("~1", "/").replace("~0", "~"); - } - - public Object queryFrom(Object document) throws JSONPointerException { - if (this.refTokens.isEmpty()) { - return document; - } - Object current = document; - for (String token : this.refTokens) { - if (current instanceof JSONObject) { - current = ((JSONObject)current).opt(JSONPointer.unescape(token)); - continue; - } - if (current instanceof JSONArray) { - current = JSONPointer.readByIndexToken(current, token); - continue; - } - throw new JSONPointerException(String.format("value [%s] is not an array or object therefore its key %s cannot be resolved", current, token)); - } - return current; - } - - private static Object readByIndexToken(Object current, String indexToken) throws JSONPointerException { - try { - int index = Integer.parseInt(indexToken); - JSONArray currentArr = (JSONArray)current; - if (index >= currentArr.length()) { - throw new JSONPointerException(String.format("index %s is out of bounds - the array has %d elements", indexToken, currentArr.length())); - } - try { - return currentArr.get(index); - } - catch (JSONException e) { - throw new JSONPointerException("Error reading value at index position " + index, e); - } - } - catch (NumberFormatException e) { - throw new JSONPointerException(String.format("%s is not an array index", indexToken), e); - } - } - - public String toString() { - StringBuilder rval = new StringBuilder(); - for (String token : this.refTokens) { - rval.append('/').append(JSONPointer.escape(token)); - } - return rval.toString(); - } - - private static String escape(String token) { - return token.replace("~", "~0").replace("/", "~1"); - } - - public String toURIFragment() { - try { - StringBuilder rval = new StringBuilder("#"); - for (String token : this.refTokens) { - rval.append('/').append(URLEncoder.encode(token, ENCODING)); - } - return rval.toString(); - } - catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - public static class Builder { - private final List refTokens = new ArrayList(); - - public JSONPointer build() { - return new JSONPointer(this.refTokens); - } - - public Builder append(String token) { - if (token == null) { - throw new NullPointerException("token cannot be null"); - } - this.refTokens.add(token); - return this; - } - - public Builder append(int arrayIndex) { - this.refTokens.add(String.valueOf(arrayIndex)); - return this; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPointerException.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPointerException.java deleted file mode 100644 index 7b3138b..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPointerException.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONException; - -public class JSONPointerException -extends JSONException { - private static final long serialVersionUID = 8872944667561856751L; - - public JSONPointerException(String message) { - super(message); - } - - public JSONPointerException(String message, Throwable cause) { - super(message, cause); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPropertyIgnore.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPropertyIgnore.java deleted file mode 100644 index 458c9ac..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPropertyIgnore.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Documented -@Retention(value=RetentionPolicy.RUNTIME) -@Target(value={ElementType.METHOD}) -public @interface JSONPropertyIgnore { -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPropertyName.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPropertyName.java deleted file mode 100644 index a5f0270..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONPropertyName.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Documented -@Retention(value=RetentionPolicy.RUNTIME) -@Target(value={ElementType.METHOD}) -public @interface JSONPropertyName { - public String value(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONString.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONString.java deleted file mode 100644 index 6549811..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONString.java +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -public interface JSONString { - public String toJSONString(); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONStringer.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONStringer.java deleted file mode 100644 index ca8241a..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONStringer.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONWriter; -import java.io.StringWriter; - -public class JSONStringer -extends JSONWriter { - public JSONStringer() { - super(new StringWriter()); - } - - public String toString() { - return this.mode == 'd' ? this.writer.toString() : null; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONTokener.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONTokener.java deleted file mode 100644 index c6d13bb..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONTokener.java +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONArray; -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONObject; -import de.maxhenkel.voicechat.org.json.JSONParserConfiguration; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.nio.charset.Charset; - -public class JSONTokener { - private long character; - private boolean eof; - private long index; - private long line; - private char previous; - private final Reader reader; - private boolean usePrevious; - private long characterPreviousLine; - private JSONParserConfiguration jsonParserConfiguration; - - public JSONTokener(Reader reader) { - this(reader, new JSONParserConfiguration()); - } - - public JSONTokener(Reader reader, JSONParserConfiguration jsonParserConfiguration) { - this.jsonParserConfiguration = jsonParserConfiguration; - this.reader = reader.markSupported() ? reader : new BufferedReader(reader); - this.eof = false; - this.usePrevious = false; - this.previous = '\u0000'; - this.index = 0L; - this.character = 1L; - this.characterPreviousLine = 0L; - this.line = 1L; - } - - public JSONTokener(InputStream inputStream) { - this(inputStream, new JSONParserConfiguration()); - } - - public JSONTokener(InputStream inputStream, JSONParserConfiguration jsonParserConfiguration) { - this(new InputStreamReader(inputStream, Charset.forName("UTF-8")), jsonParserConfiguration); - } - - public JSONTokener(String source) { - this(new StringReader(source)); - } - - public JSONTokener(String source, JSONParserConfiguration jsonParserConfiguration) { - this(new StringReader(source), jsonParserConfiguration); - } - - public JSONParserConfiguration getJsonParserConfiguration() { - return this.jsonParserConfiguration; - } - - @Deprecated - public void setJsonParserConfiguration(JSONParserConfiguration jsonParserConfiguration) { - this.jsonParserConfiguration = jsonParserConfiguration; - } - - public void back() throws JSONException { - if (this.usePrevious || this.index <= 0L) { - throw new JSONException("Stepping back two steps is not supported"); - } - this.decrementIndexes(); - this.usePrevious = true; - this.eof = false; - } - - private void decrementIndexes() { - --this.index; - if (this.previous == '\r' || this.previous == '\n') { - --this.line; - this.character = this.characterPreviousLine; - } else if (this.character > 0L) { - --this.character; - } - } - - public static int dehexchar(char c) { - if (c >= '0' && c <= '9') { - return c - 48; - } - if (c >= 'A' && c <= 'F') { - return c - 55; - } - if (c >= 'a' && c <= 'f') { - return c - 87; - } - return -1; - } - - public boolean end() { - return this.eof && !this.usePrevious; - } - - public boolean more() throws JSONException { - if (this.usePrevious) { - return true; - } - try { - this.reader.mark(1); - } - catch (IOException e) { - throw new JSONException("Unable to preserve stream position", e); - } - try { - if (this.reader.read() <= 0) { - this.eof = true; - return false; - } - this.reader.reset(); - } - catch (IOException e) { - throw new JSONException("Unable to read the next character from the stream", e); - } - return true; - } - - public char next() throws JSONException { - int c; - if (this.usePrevious) { - this.usePrevious = false; - c = this.previous; - } else { - try { - c = this.reader.read(); - } - catch (IOException exception) { - throw new JSONException(exception); - } - } - if (c <= 0) { - this.eof = true; - return '\u0000'; - } - this.incrementIndexes(c); - this.previous = (char)c; - return this.previous; - } - - protected char getPrevious() { - return this.previous; - } - - private void incrementIndexes(int c) { - if (c > 0) { - ++this.index; - if (c == 13) { - ++this.line; - this.characterPreviousLine = this.character; - this.character = 0L; - } else if (c == 10) { - if (this.previous != '\r') { - ++this.line; - this.characterPreviousLine = this.character; - } - this.character = 0L; - } else { - ++this.character; - } - } - } - - public char next(char c) throws JSONException { - char n = this.next(); - if (n != c) { - if (n > '\u0000') { - throw this.syntaxError("Expected '" + c + "' and instead saw '" + n + "'"); - } - throw this.syntaxError("Expected '" + c + "' and instead saw ''"); - } - return n; - } - - public String next(int n) throws JSONException { - if (n == 0) { - return ""; - } - char[] chars = new char[n]; - for (int pos = 0; pos < n; ++pos) { - chars[pos] = this.next(); - if (!this.end()) continue; - throw this.syntaxError("Substring bounds error"); - } - return new String(chars); - } - - public char nextClean() throws JSONException { - char c; - while ((c = this.next()) != '\u0000' && c <= ' ') { - } - return c; - } - - public String nextString(char quote) throws JSONException { - StringBuilder sb = new StringBuilder(); - block15: while (true) { - char c = this.next(); - switch (c) { - case '\u0000': - case '\n': - case '\r': { - throw this.syntaxError("Unterminated string. Character with int code " + c + " is not allowed within a quoted string."); - } - case '\\': { - c = this.next(); - switch (c) { - case 'b': { - sb.append('\b'); - continue block15; - } - case 't': { - sb.append('\t'); - continue block15; - } - case 'n': { - sb.append('\n'); - continue block15; - } - case 'f': { - sb.append('\f'); - continue block15; - } - case 'r': { - sb.append('\r'); - continue block15; - } - case 'u': { - String next = this.next(4); - try { - sb.append((char)Integer.parseInt(next, 16)); - continue block15; - } - catch (NumberFormatException e) { - throw this.syntaxError("Illegal escape. \\u must be followed by a 4 digit hexadecimal number. \\" + next + " is not valid.", e); - } - } - case '\"': - case '\'': - case '/': - case '\\': { - sb.append(c); - continue block15; - } - } - throw this.syntaxError("Illegal escape. Escape sequence \\" + c + " is not valid."); - } - } - if (c == quote) { - return sb.toString(); - } - sb.append(c); - } - } - - public String nextTo(char delimiter) throws JSONException { - StringBuilder sb = new StringBuilder(); - while (true) { - char c; - if ((c = this.next()) == delimiter || c == '\u0000' || c == '\n' || c == '\r') { - if (c != '\u0000') { - this.back(); - } - return sb.toString().trim(); - } - sb.append(c); - } - } - - public String nextTo(String delimiters) throws JSONException { - StringBuilder sb = new StringBuilder(); - while (true) { - char c; - if (delimiters.indexOf(c = this.next()) >= 0 || c == '\u0000' || c == '\n' || c == '\r') { - if (c != '\u0000') { - this.back(); - } - return sb.toString().trim(); - } - sb.append(c); - } - } - - public Object nextValue() throws JSONException { - char c = this.nextClean(); - switch (c) { - case '{': { - this.back(); - try { - return new JSONObject(this, this.jsonParserConfiguration); - } - catch (StackOverflowError e) { - throw new JSONException("JSON Array or Object depth too large to process.", e); - } - } - case '[': { - this.back(); - try { - return new JSONArray(this, this.jsonParserConfiguration); - } - catch (StackOverflowError e) { - throw new JSONException("JSON Array or Object depth too large to process.", e); - } - } - } - return this.nextSimpleValue(c); - } - - Object nextSimpleValue(char c) { - String string; - if (this.jsonParserConfiguration != null && this.jsonParserConfiguration.isStrictMode() && c == '\'') { - throw this.syntaxError("Strict mode error: Single quoted strings are not allowed"); - } - switch (c) { - case '\"': - case '\'': { - return this.nextString(c); - } - } - StringBuilder sb = new StringBuilder(); - while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { - sb.append(c); - c = this.next(); - } - if (!this.eof) { - this.back(); - } - if ("".equals(string = sb.toString().trim())) { - throw this.syntaxError("Missing value"); - } - if (this.jsonParserConfiguration != null && this.jsonParserConfiguration.isStrictMode() && string.endsWith(".")) { - throw this.syntaxError(String.format("Strict mode error: Value '%s' ends with dot", string)); - } - Object obj = JSONObject.stringToValue(string); - if (this.jsonParserConfiguration != null && this.jsonParserConfiguration.isStrictMode()) { - if (obj instanceof Boolean && !"true".equals(string) && !"false".equals(string)) { - throw this.syntaxError(String.format("Strict mode error: Value '%s' is not lowercase boolean", obj)); - } - if (obj == JSONObject.NULL && !"null".equals(string)) { - throw this.syntaxError(String.format("Strict mode error: Value '%s' is not lowercase null", obj)); - } - if (obj instanceof String) { - throw this.syntaxError(String.format("Strict mode error: Value '%s' is not surrounded by quotes", obj)); - } - } - return obj; - } - - public char skipTo(char to) throws JSONException { - char c; - try { - long startIndex = this.index; - long startCharacter = this.character; - long startLine = this.line; - this.reader.mark(1000000); - do { - if ((c = this.next()) != '\u0000') continue; - this.reader.reset(); - this.index = startIndex; - this.character = startCharacter; - this.line = startLine; - return '\u0000'; - } while (c != to); - this.reader.mark(1); - } - catch (IOException exception) { - throw new JSONException(exception); - } - this.back(); - return c; - } - - public JSONException syntaxError(String message) { - return new JSONException(message + this.toString()); - } - - public JSONException syntaxError(String message, Throwable causedBy) { - return new JSONException(message + this.toString(), causedBy); - } - - public String toString() { - return " at " + this.index + " [character " + this.character + " line " + this.line + "]"; - } - - public void close() throws IOException { - if (this.reader != null) { - this.reader.close(); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONWriter.java b/source/decompiled/de/maxhenkel/voicechat/org/json/JSONWriter.java deleted file mode 100644 index d4db3e1..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/JSONWriter.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONArray; -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONObject; -import de.maxhenkel.voicechat.org.json.JSONString; -import java.io.IOException; -import java.util.Collection; -import java.util.Map; - -public class JSONWriter { - private static final int maxdepth = 200; - private boolean comma = false; - protected char mode = (char)105; - private final JSONObject[] stack = new JSONObject[200]; - private int top = 0; - protected Appendable writer; - - public JSONWriter(Appendable w) { - this.writer = w; - } - - private JSONWriter append(String string) throws JSONException { - if (string == null) { - throw new JSONException("Null pointer"); - } - if (this.mode == 'o' || this.mode == 'a') { - try { - if (this.comma && this.mode == 'a') { - this.writer.append(','); - } - this.writer.append(string); - } - catch (IOException e) { - throw new JSONException(e); - } - if (this.mode == 'o') { - this.mode = (char)107; - } - this.comma = true; - return this; - } - throw new JSONException("Value out of sequence."); - } - - public JSONWriter array() throws JSONException { - if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { - this.push(null); - this.append("["); - this.comma = false; - return this; - } - throw new JSONException("Misplaced array."); - } - - private JSONWriter end(char m, char c) throws JSONException { - if (this.mode != m) { - throw new JSONException(m == 'a' ? "Misplaced endArray." : "Misplaced endObject."); - } - this.pop(m); - try { - this.writer.append(c); - } - catch (IOException e) { - throw new JSONException(e); - } - this.comma = true; - return this; - } - - public JSONWriter endArray() throws JSONException { - return this.end('a', ']'); - } - - public JSONWriter endObject() throws JSONException { - return this.end('k', '}'); - } - - public JSONWriter key(String string) throws JSONException { - if (string == null) { - throw new JSONException("Null key."); - } - if (this.mode == 'k') { - try { - JSONObject topObject = this.stack[this.top - 1]; - if (topObject.has(string)) { - throw new JSONException("Duplicate key \"" + string + "\""); - } - topObject.put(string, true); - if (this.comma) { - this.writer.append(','); - } - this.writer.append(JSONObject.quote(string)); - this.writer.append(':'); - this.comma = false; - this.mode = (char)111; - return this; - } - catch (IOException e) { - throw new JSONException(e); - } - } - throw new JSONException("Misplaced key."); - } - - public JSONWriter object() throws JSONException { - if (this.mode == 'i') { - this.mode = (char)111; - } - if (this.mode == 'o' || this.mode == 'a') { - this.append("{"); - this.push(new JSONObject()); - this.comma = false; - return this; - } - throw new JSONException("Misplaced object."); - } - - private void pop(char c) throws JSONException { - char m; - if (this.top <= 0) { - throw new JSONException("Nesting error."); - } - char c2 = m = this.stack[this.top - 1] == null ? (char)'a' : 'k'; - if (m != c) { - throw new JSONException("Nesting error."); - } - --this.top; - this.mode = (char)(this.top == 0 ? 100 : (this.stack[this.top - 1] == null ? 97 : 107)); - } - - private void push(JSONObject jo) throws JSONException { - if (this.top >= 200) { - throw new JSONException("Nesting too deep."); - } - this.stack[this.top] = jo; - this.mode = (char)(jo == null ? 97 : 107); - ++this.top; - } - - public static String valueToString(Object value) throws JSONException { - if (value == null || value.equals(null)) { - return "null"; - } - if (value instanceof JSONString) { - String object; - try { - object = ((JSONString)value).toJSONString(); - } - catch (Exception e) { - throw new JSONException(e); - } - if (object != null) { - return object; - } - throw new JSONException("Bad value from toJSONString: " + object); - } - if (value instanceof Number) { - String numberAsString = JSONObject.numberToString((Number)value); - if (JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) { - return numberAsString; - } - return JSONObject.quote(numberAsString); - } - if (value instanceof Boolean || value instanceof JSONObject || value instanceof JSONArray) { - return value.toString(); - } - if (value instanceof Map) { - Map map = (Map)value; - return new JSONObject(map).toString(); - } - if (value instanceof Collection) { - Collection coll = (Collection)value; - return new JSONArray(coll).toString(); - } - if (value.getClass().isArray()) { - return new JSONArray(value).toString(); - } - if (value instanceof Enum) { - return JSONObject.quote(((Enum)value).name()); - } - return JSONObject.quote(value.toString()); - } - - public JSONWriter value(boolean b) throws JSONException { - return this.append(b ? "true" : "false"); - } - - public JSONWriter value(double d) throws JSONException { - return this.value((Object)d); - } - - public JSONWriter value(long l) throws JSONException { - return this.append(Long.toString(l)); - } - - public JSONWriter value(Object object) throws JSONException { - return this.append(JSONWriter.valueToString(object)); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/ParserConfiguration.java b/source/decompiled/de/maxhenkel/voicechat/org/json/ParserConfiguration.java deleted file mode 100644 index 0255516..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/ParserConfiguration.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -public class ParserConfiguration { - public static final int UNDEFINED_MAXIMUM_NESTING_DEPTH = -1; - public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = 512; - protected boolean keepStrings; - protected int maxNestingDepth; - - public ParserConfiguration() { - this.keepStrings = false; - this.maxNestingDepth = 512; - } - - protected ParserConfiguration(boolean keepStrings, int maxNestingDepth) { - this.keepStrings = keepStrings; - this.maxNestingDepth = maxNestingDepth; - } - - protected ParserConfiguration clone() { - return new ParserConfiguration(this.keepStrings, this.maxNestingDepth); - } - - public boolean isKeepStrings() { - return this.keepStrings; - } - - public T withKeepStrings(boolean newVal) { - ParserConfiguration newConfig = this.clone(); - newConfig.keepStrings = newVal; - return (T)newConfig; - } - - public int getMaxNestingDepth() { - return this.maxNestingDepth; - } - - public T withMaxNestingDepth(int maxNestingDepth) { - ParserConfiguration newConfig = this.clone(); - newConfig.maxNestingDepth = maxNestingDepth > -1 ? maxNestingDepth : -1; - return (T)newConfig; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/Property.java b/source/decompiled/de/maxhenkel/voicechat/org/json/Property.java deleted file mode 100644 index fbe5b0d..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/Property.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONObject; -import java.util.Enumeration; -import java.util.Properties; - -public class Property { - public static JSONObject toJSONObject(Properties properties) throws JSONException { - JSONObject jo = new JSONObject(); - if (properties != null && !properties.isEmpty()) { - Enumeration enumProperties = properties.propertyNames(); - while (enumProperties.hasMoreElements()) { - String name = (String)enumProperties.nextElement(); - jo.put(name, properties.getProperty(name)); - } - } - return jo; - } - - public static Properties toProperties(JSONObject jo) throws JSONException { - Properties properties = new Properties(); - if (jo != null) { - for (String key : jo.keySet()) { - Object value = jo.opt(key); - if (JSONObject.NULL.equals(value)) continue; - properties.put(key, value.toString()); - } - } - return properties; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/StringBuilderWriter.java b/source/decompiled/de/maxhenkel/voicechat/org/json/StringBuilderWriter.java deleted file mode 100644 index d094217..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/StringBuilderWriter.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import java.io.IOException; -import java.io.Writer; - -public class StringBuilderWriter -extends Writer { - private final StringBuilder builder; - - public StringBuilderWriter() { - this.builder = new StringBuilder(); - this.lock = this.builder; - } - - public StringBuilderWriter(int initialSize) { - this.builder = new StringBuilder(initialSize); - this.lock = this.builder; - } - - @Override - public void write(int c) { - this.builder.append((char)c); - } - - @Override - public void write(char[] cbuf, int offset, int length) { - if (offset < 0 || offset > cbuf.length || length < 0 || offset + length > cbuf.length || offset + length < 0) { - throw new IndexOutOfBoundsException(); - } - if (length == 0) { - return; - } - this.builder.append(cbuf, offset, length); - } - - @Override - public void write(String str) { - this.builder.append(str); - } - - @Override - public void write(String str, int offset, int length) { - this.builder.append(str, offset, offset + length); - } - - @Override - public StringBuilderWriter append(CharSequence csq) { - this.write(String.valueOf(csq)); - return this; - } - - @Override - public StringBuilderWriter append(CharSequence csq, int start, int end) { - if (csq == null) { - csq = "null"; - } - return this.append(csq.subSequence(start, end)); - } - - @Override - public StringBuilderWriter append(char c) { - this.write(c); - return this; - } - - public String toString() { - return this.builder.toString(); - } - - @Override - public void flush() { - } - - @Override - public void close() throws IOException { - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/XML.java b/source/decompiled/de/maxhenkel/voicechat/org/json/XML.java deleted file mode 100644 index 7583461..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/XML.java +++ /dev/null @@ -1,623 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONArray; -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONObject; -import de.maxhenkel.voicechat.org.json.XMLParserConfiguration; -import de.maxhenkel.voicechat.org.json.XMLTokener; -import de.maxhenkel.voicechat.org.json.XMLXsiTypeConverter; -import java.io.Reader; -import java.io.StringReader; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Iterator; - -public class XML { - public static final Character AMP = Character.valueOf('&'); - public static final Character APOS = Character.valueOf('\''); - public static final Character BANG = Character.valueOf('!'); - public static final Character EQ = Character.valueOf('='); - public static final Character GT = Character.valueOf('>'); - public static final Character LT = Character.valueOf('<'); - public static final Character QUEST = Character.valueOf('?'); - public static final Character QUOT = Character.valueOf('\"'); - public static final Character SLASH = Character.valueOf('/'); - public static final String NULL_ATTR = "xsi:nil"; - public static final String TYPE_ATTR = "xsi:type"; - - private static Iterable codePointIterator(final String string) { - return new Iterable(){ - - @Override - public Iterator iterator() { - return new Iterator(){ - private int nextIndex = 0; - private int length; - { - this.length = string.length(); - } - - @Override - public boolean hasNext() { - return this.nextIndex < this.length; - } - - @Override - public Integer next() { - int result = string.codePointAt(this.nextIndex); - this.nextIndex += Character.charCount(result); - return result; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - }; - } - - public static String escape(String string) { - StringBuilder sb = new StringBuilder(string.length()); - block7: for (int cp : XML.codePointIterator(string)) { - switch (cp) { - case 38: { - sb.append("&"); - continue block7; - } - case 60: { - sb.append("<"); - continue block7; - } - case 62: { - sb.append(">"); - continue block7; - } - case 34: { - sb.append("""); - continue block7; - } - case 39: { - sb.append("'"); - continue block7; - } - } - if (XML.mustEscape(cp)) { - sb.append("&#x"); - sb.append(Integer.toHexString(cp)); - sb.append(';'); - continue; - } - sb.appendCodePoint(cp); - } - return sb.toString(); - } - - private static boolean mustEscape(int cp) { - return Character.isISOControl(cp) && cp != 9 && cp != 10 && cp != 13 || (cp < 32 || cp > 55295) && (cp < 57344 || cp > 65533) && (cp < 65536 || cp > 0x10FFFF); - } - - public static String unescape(String string) { - StringBuilder sb = new StringBuilder(string.length()); - int length = string.length(); - for (int i = 0; i < length; ++i) { - char c = string.charAt(i); - if (c == '&') { - int semic = string.indexOf(59, i); - if (semic > i) { - String entity = string.substring(i + 1, semic); - sb.append(XMLTokener.unescapeEntity(entity)); - i += entity.length() + 1; - continue; - } - sb.append(c); - continue; - } - sb.append(c); - } - return sb.toString(); - } - - public static void noSpace(String string) throws JSONException { - int length = string.length(); - if (length == 0) { - throw new JSONException("Empty string."); - } - for (int i = 0; i < length; ++i) { - if (!Character.isWhitespace(string.charAt(i))) continue; - throw new JSONException("'" + string + "' contains a space character."); - } - } - - private static boolean parse(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config, int currentNestingDepth) throws JSONException { - Object obj; - String string; - JSONObject jsonObject = null; - Object token = x.nextToken(); - if (token == BANG) { - char c = x.next(); - if (c == '-') { - if (x.next() == '-') { - x.skipPast("-->"); - return false; - } - x.back(); - } else if (c == '[') { - token = x.nextToken(); - if ("CDATA".equals(token) && x.next() == '[') { - String string2 = x.nextCDATA(); - if (string2.length() > 0) { - context.accumulate(config.getcDataTagName(), string2); - } - return false; - } - throw x.syntaxError("Expected 'CDATA['"); - } - int i = 1; - do { - if ((token = x.nextMeta()) == null) { - throw x.syntaxError("Missing '>' after ' 0); - return false; - } - if (token == QUEST) { - x.skipPast("?>"); - return false; - } - if (token == SLASH) { - token = x.nextToken(); - if (name == null) { - throw x.syntaxError("Mismatched close tag " + token); - } - if (!token.equals(name)) { - throw x.syntaxError("Mismatched " + name + " and " + token); - } - if (x.nextToken() != GT) { - throw x.syntaxError("Misshaped close tag"); - } - return true; - } - if (token instanceof Character) { - throw x.syntaxError("Misshaped tag"); - } - String tagName = (String)token; - token = null; - jsonObject = new JSONObject(); - boolean nilAttributeFound = false; - XMLXsiTypeConverter xmlXsiTypeConverter = null; - while (true) { - if (token == null) { - token = x.nextToken(); - } - if (!(token instanceof String)) break; - string = (String)token; - token = x.nextToken(); - if (token == EQ) { - token = x.nextToken(); - if (!(token instanceof String)) { - throw x.syntaxError("Missing value"); - } - if (config.isConvertNilAttributeToNull() && NULL_ATTR.equals(string) && Boolean.parseBoolean((String)token)) { - nilAttributeFound = true; - } else if (config.getXsiTypeMap() != null && !config.getXsiTypeMap().isEmpty() && TYPE_ATTR.equals(string)) { - xmlXsiTypeConverter = config.getXsiTypeMap().get(token); - } else if (!nilAttributeFound) { - obj = XML.stringToValue((String)token); - if (obj instanceof Boolean) { - jsonObject.accumulate(string, config.isKeepBooleanAsString() ? (String)token : obj); - } else if (obj instanceof Number) { - jsonObject.accumulate(string, config.isKeepNumberAsString() ? (String)token : obj); - } else { - jsonObject.accumulate(string, XML.stringToValue((String)token)); - } - } - token = null; - continue; - } - jsonObject.accumulate(string, ""); - } - if (token == SLASH) { - if (x.nextToken() != GT) { - throw x.syntaxError("Misshaped tag"); - } - if (config.getForceList().contains(tagName)) { - if (nilAttributeFound) { - context.append(tagName, JSONObject.NULL); - } else if (jsonObject.length() > 0) { - context.append(tagName, jsonObject); - } else { - context.put(tagName, new JSONArray()); - } - } else if (nilAttributeFound) { - context.accumulate(tagName, JSONObject.NULL); - } else if (jsonObject.length() > 0) { - context.accumulate(tagName, jsonObject); - } else { - context.accumulate(tagName, ""); - } - return false; - } - if (token == GT) { - while (true) { - if ((token = x.nextContent()) == null) { - if (tagName != null) { - throw x.syntaxError("Unclosed tag " + tagName); - } - return false; - } - if (token instanceof String) { - string = (String)token; - if (string.length() <= 0) continue; - if (xmlXsiTypeConverter != null) { - jsonObject.accumulate(config.getcDataTagName(), XML.stringToValue(string, xmlXsiTypeConverter)); - continue; - } - obj = XML.stringToValue((String)token); - if (obj instanceof Boolean) { - jsonObject.accumulate(config.getcDataTagName(), config.isKeepBooleanAsString() ? (String)token : obj); - continue; - } - if (obj instanceof Number) { - jsonObject.accumulate(config.getcDataTagName(), config.isKeepNumberAsString() ? (String)token : obj); - continue; - } - if (obj == JSONObject.NULL) { - jsonObject.accumulate(config.getcDataTagName(), config.isKeepStrings() ? (String)token : obj); - continue; - } - jsonObject.accumulate(config.getcDataTagName(), XML.stringToValue((String)token)); - continue; - } - if (token != LT) continue; - if (currentNestingDepth == config.getMaxNestingDepth()) { - throw x.syntaxError("Maximum nesting depth of " + config.getMaxNestingDepth() + " reached"); - } - if (XML.parse(x, jsonObject, tagName, config, currentNestingDepth + 1)) break; - } - if (config.getForceList().contains(tagName)) { - if (jsonObject.length() == 0) { - context.put(tagName, new JSONArray()); - } else if (jsonObject.length() == 1 && jsonObject.opt(config.getcDataTagName()) != null) { - context.append(tagName, jsonObject.opt(config.getcDataTagName())); - } else { - context.append(tagName, jsonObject); - } - } else if (jsonObject.length() == 0) { - context.accumulate(tagName, ""); - } else if (jsonObject.length() == 1 && jsonObject.opt(config.getcDataTagName()) != null) { - context.accumulate(tagName, jsonObject.opt(config.getcDataTagName())); - } else { - if (!config.shouldTrimWhiteSpace()) { - XML.removeEmpty(jsonObject, config); - } - context.accumulate(tagName, jsonObject); - } - return false; - } - throw x.syntaxError("Misshaped tag"); - } - - private static void removeEmpty(JSONObject jsonObject, XMLParserConfiguration config) { - if (jsonObject.has(config.getcDataTagName())) { - Object s = jsonObject.get(config.getcDataTagName()); - if (s instanceof String) { - if (XML.isStringAllWhiteSpace(s.toString())) { - jsonObject.remove(config.getcDataTagName()); - } - } else if (s instanceof JSONArray) { - JSONArray sArray = (JSONArray)s; - for (int k = sArray.length() - 1; k >= 0; --k) { - String s1; - Object eachString = sArray.get(k); - if (!(eachString instanceof String) || !XML.isStringAllWhiteSpace(s1 = (String)eachString)) continue; - sArray.remove(k); - } - if (sArray.isEmpty()) { - jsonObject.remove(config.getcDataTagName()); - } - } - } - } - - private static boolean isStringAllWhiteSpace(String s) { - for (int k = 0; k < s.length(); ++k) { - char eachChar = s.charAt(k); - if (Character.isWhitespace(eachChar)) continue; - return false; - } - return true; - } - - private static Number stringToNumber(String val) throws NumberFormatException { - char initial = val.charAt(0); - if (initial >= '0' && initial <= '9' || initial == '-') { - BigInteger bi; - char at1; - if (XML.isDecimalNotation(val)) { - try { - BigDecimal bd = new BigDecimal(val); - if (initial == '-' && BigDecimal.ZERO.compareTo(bd) == 0) { - return -0.0; - } - return bd; - } - catch (NumberFormatException retryAsDouble) { - try { - Double d = Double.valueOf(val); - if (d.isNaN() || d.isInfinite()) { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - return d; - } - catch (NumberFormatException ignore) { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - } - } - if (initial == '0' && val.length() > 1) { - at1 = val.charAt(1); - if (at1 >= '0' && at1 <= '9') { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - } else if (initial == '-' && val.length() > 2) { - at1 = val.charAt(1); - char at2 = val.charAt(2); - if (at1 == '0' && at2 >= '0' && at2 <= '9') { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - } - if ((bi = new BigInteger(val)).bitLength() <= 31) { - return bi.intValue(); - } - if (bi.bitLength() <= 63) { - return bi.longValue(); - } - return bi; - } - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - - private static boolean isDecimalNotation(String val) { - return val.indexOf(46) > -1 || val.indexOf(101) > -1 || val.indexOf(69) > -1 || "-0".equals(val); - } - - public static Object stringToValue(String string, XMLXsiTypeConverter typeConverter) { - if (typeConverter != null) { - return typeConverter.convert(string); - } - return XML.stringToValue(string); - } - - public static Object stringToValue(String string) { - if ("".equals(string)) { - return string; - } - if ("true".equalsIgnoreCase(string)) { - return Boolean.TRUE; - } - if ("false".equalsIgnoreCase(string)) { - return Boolean.FALSE; - } - if ("null".equalsIgnoreCase(string)) { - return JSONObject.NULL; - } - char initial = string.charAt(0); - if (initial >= '0' && initial <= '9' || initial == '-') { - try { - return XML.stringToNumber(string); - } - catch (Exception exception) { - // empty catch block - } - } - return string; - } - - public static JSONObject toJSONObject(String string) throws JSONException { - return XML.toJSONObject(string, XMLParserConfiguration.ORIGINAL); - } - - public static JSONObject toJSONObject(Reader reader) throws JSONException { - return XML.toJSONObject(reader, XMLParserConfiguration.ORIGINAL); - } - - public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws JSONException { - if (keepStrings) { - return XML.toJSONObject(reader, XMLParserConfiguration.KEEP_STRINGS); - } - return XML.toJSONObject(reader, XMLParserConfiguration.ORIGINAL); - } - - public static JSONObject toJSONObject(Reader reader, boolean keepNumberAsString, boolean keepBooleanAsString) throws JSONException { - XMLParserConfiguration xmlParserConfiguration = new XMLParserConfiguration(); - if (keepNumberAsString) { - xmlParserConfiguration = xmlParserConfiguration.withKeepNumberAsString(keepNumberAsString); - } - if (keepBooleanAsString) { - xmlParserConfiguration = xmlParserConfiguration.withKeepBooleanAsString(keepBooleanAsString); - } - return XML.toJSONObject(reader, xmlParserConfiguration); - } - - public static JSONObject toJSONObject(Reader reader, XMLParserConfiguration config) throws JSONException { - JSONObject jo = new JSONObject(); - XMLTokener x = new XMLTokener(reader, config); - while (x.more()) { - x.skipPast("<"); - if (!x.more()) continue; - XML.parse(x, jo, null, config, 0); - } - return jo; - } - - public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { - return XML.toJSONObject((Reader)new StringReader(string), keepStrings); - } - - public static JSONObject toJSONObject(String string, boolean keepNumberAsString, boolean keepBooleanAsString) throws JSONException { - return XML.toJSONObject(new StringReader(string), keepNumberAsString, keepBooleanAsString); - } - - public static JSONObject toJSONObject(String string, XMLParserConfiguration config) throws JSONException { - return XML.toJSONObject((Reader)new StringReader(string), config); - } - - public static String toString(Object object) throws JSONException { - return XML.toString(object, null, XMLParserConfiguration.ORIGINAL); - } - - public static String toString(Object object, String tagName) { - return XML.toString(object, tagName, XMLParserConfiguration.ORIGINAL); - } - - public static String toString(Object object, String tagName, XMLParserConfiguration config) throws JSONException { - return XML.toString(object, tagName, config, 0, 0); - } - - private static String toString(Object object, String tagName, XMLParserConfiguration config, int indentFactor, int indent) throws JSONException { - String indentationSuffix; - StringBuilder sb = new StringBuilder(); - if (object instanceof JSONObject) { - if (tagName != null) { - sb.append(XML.indent(indent)); - sb.append('<'); - sb.append(tagName); - sb.append('>'); - if (indentFactor > 0) { - sb.append("\n"); - indent += indentFactor; - } - } - JSONObject jo = (JSONObject)object; - for (String key : jo.keySet()) { - Object val; - int i; - int jaLength; - JSONArray ja; - Object value = jo.opt(key); - if (value == null) { - value = ""; - } else if (value.getClass().isArray()) { - value = new JSONArray(value); - } - if (key.equals(config.getcDataTagName())) { - if (value instanceof JSONArray) { - ja = (JSONArray)value; - jaLength = ja.length(); - for (i = 0; i < jaLength; ++i) { - if (i > 0) { - sb.append('\n'); - } - val = ja.opt(i); - sb.append(XML.escape(val.toString())); - } - continue; - } - sb.append(XML.escape(value.toString())); - continue; - } - if (value instanceof JSONArray) { - ja = (JSONArray)value; - jaLength = ja.length(); - for (i = 0; i < jaLength; ++i) { - val = ja.opt(i); - if (val instanceof JSONArray) { - sb.append('<'); - sb.append(key); - sb.append('>'); - sb.append(XML.toString(val, null, config, indentFactor, indent)); - sb.append("'); - continue; - } - sb.append(XML.toString(val, key, config, indentFactor, indent)); - } - continue; - } - if ("".equals(value)) { - if (config.isCloseEmptyTag()) { - sb.append(XML.indent(indent)); - sb.append('<'); - sb.append(key); - sb.append(">"); - sb.append(""); - if (indentFactor <= 0) continue; - sb.append("\n"); - continue; - } - sb.append(XML.indent(indent)); - sb.append('<'); - sb.append(key); - sb.append("/>"); - if (indentFactor <= 0) continue; - sb.append("\n"); - continue; - } - sb.append(XML.toString(value, key, config, indentFactor, indent)); - } - if (tagName != null) { - sb.append(XML.indent(indent - indentFactor)); - sb.append("'); - if (indentFactor > 0) { - sb.append("\n"); - } - } - return sb.toString(); - } - if (object != null && (object instanceof JSONArray || object.getClass().isArray())) { - JSONArray ja = object.getClass().isArray() ? new JSONArray(object) : (JSONArray)object; - int jaLength = ja.length(); - for (int i = 0; i < jaLength; ++i) { - Object val = ja.opt(i); - sb.append(XML.toString(val, tagName == null ? "array" : tagName, config, indentFactor, indent)); - } - return sb.toString(); - } - String string = object == null ? "null" : XML.escape(object.toString()); - String string2 = indentationSuffix = indentFactor > 0 ? "\n" : ""; - if (tagName == null) { - return XML.indent(indent) + "\"" + string + "\"" + indentationSuffix; - } - if (string.length() == 0) { - return XML.indent(indent) + "<" + tagName + "/>" + indentationSuffix; - } - return XML.indent(indent) + "<" + tagName + ">" + string + "" + indentationSuffix; - } - - public static String toString(Object object, int indentFactor) { - return XML.toString(object, null, XMLParserConfiguration.ORIGINAL, indentFactor); - } - - public static String toString(Object object, String tagName, int indentFactor) { - return XML.toString(object, tagName, XMLParserConfiguration.ORIGINAL, indentFactor); - } - - public static String toString(Object object, String tagName, XMLParserConfiguration config, int indentFactor) throws JSONException { - return XML.toString(object, tagName, config, indentFactor, 0); - } - - private static final String indent(int indent) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < indent; ++i) { - sb.append(' '); - } - return sb.toString(); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/XMLParserConfiguration.java b/source/decompiled/de/maxhenkel/voicechat/org/json/XMLParserConfiguration.java deleted file mode 100644 index 8a552e3..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/XMLParserConfiguration.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.ParserConfiguration; -import de.maxhenkel.voicechat.org.json.XMLXsiTypeConverter; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class XMLParserConfiguration -extends ParserConfiguration { - private boolean keepNumberAsString; - private boolean keepBooleanAsString; - public static final XMLParserConfiguration ORIGINAL = new XMLParserConfiguration(); - public static final XMLParserConfiguration KEEP_STRINGS = new XMLParserConfiguration().withKeepStrings(true); - private String cDataTagName; - private boolean convertNilAttributeToNull; - private boolean closeEmptyTag; - private Map> xsiTypeMap; - private Set forceList; - private boolean shouldTrimWhiteSpace; - - public XMLParserConfiguration() { - this.cDataTagName = "content"; - this.convertNilAttributeToNull = false; - this.xsiTypeMap = Collections.emptyMap(); - this.forceList = Collections.emptySet(); - this.shouldTrimWhiteSpace = true; - } - - @Deprecated - public XMLParserConfiguration(boolean keepStrings) { - this(keepStrings, "content", false); - } - - @Deprecated - public XMLParserConfiguration(String cDataTagName) { - this(false, cDataTagName, false); - } - - @Deprecated - public XMLParserConfiguration(boolean keepStrings, String cDataTagName) { - super(keepStrings, 512); - this.cDataTagName = cDataTagName; - this.convertNilAttributeToNull = false; - } - - @Deprecated - public XMLParserConfiguration(boolean keepStrings, String cDataTagName, boolean convertNilAttributeToNull) { - super(false, 512); - this.keepNumberAsString = keepStrings; - this.keepBooleanAsString = keepStrings; - this.cDataTagName = cDataTagName; - this.convertNilAttributeToNull = convertNilAttributeToNull; - } - - private XMLParserConfiguration(boolean keepStrings, String cDataTagName, boolean convertNilAttributeToNull, Map> xsiTypeMap, Set forceList, int maxNestingDepth, boolean closeEmptyTag, boolean keepNumberAsString, boolean keepBooleanAsString) { - super(false, maxNestingDepth); - this.keepNumberAsString = keepNumberAsString; - this.keepBooleanAsString = keepBooleanAsString; - this.cDataTagName = cDataTagName; - this.convertNilAttributeToNull = convertNilAttributeToNull; - this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap); - this.forceList = Collections.unmodifiableSet(forceList); - this.closeEmptyTag = closeEmptyTag; - } - - @Override - protected XMLParserConfiguration clone() { - XMLParserConfiguration config = new XMLParserConfiguration(this.keepStrings, this.cDataTagName, this.convertNilAttributeToNull, this.xsiTypeMap, this.forceList, this.maxNestingDepth, this.closeEmptyTag, this.keepNumberAsString, this.keepBooleanAsString); - config.shouldTrimWhiteSpace = this.shouldTrimWhiteSpace; - return config; - } - - public XMLParserConfiguration withKeepStrings(boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.keepStrings = newVal; - newConfig.keepNumberAsString = newVal; - newConfig.keepBooleanAsString = newVal; - return newConfig; - } - - public XMLParserConfiguration withKeepNumberAsString(boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.keepNumberAsString = newVal; - newConfig.keepStrings = newConfig.keepBooleanAsString && newConfig.keepNumberAsString; - return newConfig; - } - - public XMLParserConfiguration withKeepBooleanAsString(boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.keepBooleanAsString = newVal; - newConfig.keepStrings = newConfig.keepBooleanAsString && newConfig.keepNumberAsString; - return newConfig; - } - - public String getcDataTagName() { - return this.cDataTagName; - } - - public boolean isKeepNumberAsString() { - return this.keepNumberAsString; - } - - public boolean isKeepBooleanAsString() { - return this.keepBooleanAsString; - } - - public XMLParserConfiguration withcDataTagName(String newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.cDataTagName = newVal; - return newConfig; - } - - public boolean isConvertNilAttributeToNull() { - return this.convertNilAttributeToNull; - } - - public XMLParserConfiguration withConvertNilAttributeToNull(boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.convertNilAttributeToNull = newVal; - return newConfig; - } - - public Map> getXsiTypeMap() { - return this.xsiTypeMap; - } - - public XMLParserConfiguration withXsiTypeMap(Map> xsiTypeMap) { - XMLParserConfiguration newConfig = this.clone(); - HashMap cloneXsiTypeMap = new HashMap(xsiTypeMap); - newConfig.xsiTypeMap = Collections.unmodifiableMap(cloneXsiTypeMap); - return newConfig; - } - - public Set getForceList() { - return this.forceList; - } - - public XMLParserConfiguration withForceList(Set forceList) { - XMLParserConfiguration newConfig = this.clone(); - HashSet cloneForceList = new HashSet(forceList); - newConfig.forceList = Collections.unmodifiableSet(cloneForceList); - return newConfig; - } - - public XMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) { - return (XMLParserConfiguration)super.withMaxNestingDepth(maxNestingDepth); - } - - public XMLParserConfiguration withCloseEmptyTag(boolean closeEmptyTag) { - XMLParserConfiguration clonedConfiguration = this.clone(); - clonedConfiguration.closeEmptyTag = closeEmptyTag; - return clonedConfiguration; - } - - public XMLParserConfiguration withShouldTrimWhitespace(boolean shouldTrimWhiteSpace) { - XMLParserConfiguration clonedConfiguration = this.clone(); - clonedConfiguration.shouldTrimWhiteSpace = shouldTrimWhiteSpace; - return clonedConfiguration; - } - - public boolean isCloseEmptyTag() { - return this.closeEmptyTag; - } - - public boolean shouldTrimWhiteSpace() { - return this.shouldTrimWhiteSpace; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/XMLTokener.java b/source/decompiled/de/maxhenkel/voicechat/org/json/XMLTokener.java deleted file mode 100644 index b1fb94e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/XMLTokener.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -import de.maxhenkel.voicechat.org.json.JSONException; -import de.maxhenkel.voicechat.org.json.JSONTokener; -import de.maxhenkel.voicechat.org.json.XML; -import de.maxhenkel.voicechat.org.json.XMLParserConfiguration; -import java.io.Reader; -import java.util.HashMap; - -public class XMLTokener -extends JSONTokener { - public static final HashMap entity = new HashMap(8); - private XMLParserConfiguration configuration = XMLParserConfiguration.ORIGINAL; - - public XMLTokener(Reader r) { - super(r); - } - - public XMLTokener(String s) { - super(s); - } - - public XMLTokener(Reader r, XMLParserConfiguration configuration) { - super(r); - this.configuration = configuration; - } - - public String nextCDATA() throws JSONException { - StringBuilder sb = new StringBuilder(); - while (this.more()) { - char c = this.next(); - sb.append(c); - int i = sb.length() - 3; - if (i < 0 || sb.charAt(i) != ']' || sb.charAt(i + 1) != ']' || sb.charAt(i + 2) != '>') continue; - sb.setLength(i); - return sb.toString(); - } - throw this.syntaxError("Unclosed CDATA"); - } - - public Object nextContent() throws JSONException { - char c; - while (Character.isWhitespace(c = this.next()) && this.configuration.shouldTrimWhiteSpace()) { - } - if (c == '\u0000') { - return null; - } - if (c == '<') { - return XML.LT; - } - StringBuilder sb = new StringBuilder(); - while (c != '\u0000') { - if (c == '<') { - this.back(); - if (this.configuration.shouldTrimWhiteSpace()) { - return sb.toString().trim(); - } - return sb.toString(); - } - if (c == '&') { - sb.append(this.nextEntity(c)); - } else { - sb.append(c); - } - c = this.next(); - } - return sb.toString().trim(); - } - - public Object nextEntity(char ampersand) throws JSONException { - char c; - StringBuilder sb = new StringBuilder(); - while (Character.isLetterOrDigit(c = this.next()) || c == '#') { - sb.append(Character.toLowerCase(c)); - } - if (c != ';') { - throw this.syntaxError("Missing ';' in XML entity: &" + sb); - } - String string = sb.toString(); - return XMLTokener.unescapeEntity(string); - } - - static String unescapeEntity(String e) { - if (e == null || e.isEmpty()) { - return ""; - } - if (e.charAt(0) == '#') { - int cp = e.charAt(1) == 'x' || e.charAt(1) == 'X' ? Integer.parseInt(e.substring(2), 16) : Integer.parseInt(e.substring(1)); - return new String(new int[]{cp}, 0, 1); - } - Character knownEntity = entity.get(e); - if (knownEntity == null) { - return '&' + e + ';'; - } - return knownEntity.toString(); - } - - public Object nextMeta() throws JSONException { - char c; - while (Character.isWhitespace(c = this.next())) { - } - switch (c) { - case '\u0000': { - throw this.syntaxError("Misshaped meta tag"); - } - case '<': { - return XML.LT; - } - case '>': { - return XML.GT; - } - case '/': { - return XML.SLASH; - } - case '=': { - return XML.EQ; - } - case '!': { - return XML.BANG; - } - case '?': { - return XML.QUEST; - } - case '\"': - case '\'': { - char q = c; - do { - if ((c = this.next()) != '\u0000') continue; - throw this.syntaxError("Unterminated string"); - } while (c != q); - return Boolean.TRUE; - } - } - while (!Character.isWhitespace(c = this.next())) { - switch (c) { - case '\u0000': { - throw this.syntaxError("Unterminated string"); - } - case '!': - case '\"': - case '\'': - case '/': - case '<': - case '=': - case '>': - case '?': { - this.back(); - return Boolean.TRUE; - } - } - } - return Boolean.TRUE; - } - - public Object nextToken() throws JSONException { - char c; - while (Character.isWhitespace(c = this.next())) { - } - switch (c) { - case '\u0000': { - throw this.syntaxError("Misshaped element"); - } - case '<': { - throw this.syntaxError("Misplaced '<'"); - } - case '>': { - return XML.GT; - } - case '/': { - return XML.SLASH; - } - case '=': { - return XML.EQ; - } - case '!': { - return XML.BANG; - } - case '?': { - return XML.QUEST; - } - case '\"': - case '\'': { - char q = c; - StringBuilder sb = new StringBuilder(); - while (true) { - if ((c = this.next()) == '\u0000') { - throw this.syntaxError("Unterminated string"); - } - if (c == q) { - return sb.toString(); - } - if (c == '&') { - sb.append(this.nextEntity(c)); - continue; - } - sb.append(c); - } - } - } - StringBuilder sb = new StringBuilder(); - while (true) { - sb.append(c); - c = this.next(); - if (Character.isWhitespace(c)) { - return sb.toString(); - } - switch (c) { - case '\u0000': { - return sb.toString(); - } - case '!': - case '/': - case '=': - case '>': - case '?': - case '[': - case ']': { - this.back(); - return sb.toString(); - } - case '\"': - case '\'': - case '<': { - throw this.syntaxError("Bad character in a name"); - } - } - } - } - - public void skipPast(String to) { - char c; - int i; - int offset = 0; - int length = to.length(); - char[] circle = new char[length]; - for (i = 0; i < length; ++i) { - c = this.next(); - if (c == '\u0000') { - return; - } - circle[i] = c; - } - while (true) { - int j = offset; - boolean b = true; - for (i = 0; i < length; ++i) { - if (circle[j] != to.charAt(i)) { - b = false; - break; - } - if (++j < length) continue; - j -= length; - } - if (b) { - return; - } - c = this.next(); - if (c == '\u0000') { - return; - } - circle[offset] = c; - if (++offset < length) continue; - offset -= length; - } - } - - static { - entity.put("amp", XML.AMP); - entity.put("apos", XML.APOS); - entity.put("gt", XML.GT); - entity.put("lt", XML.LT); - entity.put("quot", XML.QUOT); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/org/json/XMLXsiTypeConverter.java b/source/decompiled/de/maxhenkel/voicechat/org/json/XMLXsiTypeConverter.java deleted file mode 100644 index c6f2dcb..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/org/json/XMLXsiTypeConverter.java +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.org.json; - -public interface XMLXsiTypeConverter { - public T convert(String var1); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/permission/PermissionManager.java b/source/decompiled/de/maxhenkel/voicechat/permission/PermissionManager.java deleted file mode 100644 index e12de96..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/permission/PermissionManager.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.permissions.Permission - * org.bukkit.permissions.PermissionDefault - */ -package de.maxhenkel.voicechat.permission; - -import org.bukkit.permissions.Permission; -import org.bukkit.permissions.PermissionDefault; - -public class PermissionManager { - public static Permission LISTEN_PERMISSION = new Permission("voicechat.listen", PermissionDefault.TRUE); - public static Permission SPEAK_PERMISSION = new Permission("voicechat.speak", PermissionDefault.TRUE); - public static Permission GROUPS_PERMISSION = new Permission("voicechat.groups", PermissionDefault.TRUE); - public static Permission ADMIN_PERMISSION = new Permission("voicechat.admin", PermissionDefault.OP); -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/PluginManager.java b/source/decompiled/de/maxhenkel/voicechat/plugins/PluginManager.java deleted file mode 100644 index a3fbed8..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/PluginManager.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.plugins; - -import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.VoicechatPlugin; -import de.maxhenkel.voicechat.api.VoicechatSocket; -import de.maxhenkel.voicechat.api.VolumeCategory; -import de.maxhenkel.voicechat.api.audiolistener.AudioListener; -import de.maxhenkel.voicechat.api.audiolistener.PlayerAudioListener; -import de.maxhenkel.voicechat.api.events.CreateGroupEvent; -import de.maxhenkel.voicechat.api.events.EntitySoundPacketEvent; -import de.maxhenkel.voicechat.api.events.Event; -import de.maxhenkel.voicechat.api.events.EventRegistration; -import de.maxhenkel.voicechat.api.events.JoinGroupEvent; -import de.maxhenkel.voicechat.api.events.LeaveGroupEvent; -import de.maxhenkel.voicechat.api.events.LocationalSoundPacketEvent; -import de.maxhenkel.voicechat.api.events.MicrophonePacketEvent; -import de.maxhenkel.voicechat.api.events.PlayerConnectedEvent; -import de.maxhenkel.voicechat.api.events.PlayerDisconnectedEvent; -import de.maxhenkel.voicechat.api.events.PlayerStateChangedEvent; -import de.maxhenkel.voicechat.api.events.RegisterVolumeCategoryEvent; -import de.maxhenkel.voicechat.api.events.RemoveGroupEvent; -import de.maxhenkel.voicechat.api.events.StaticSoundPacketEvent; -import de.maxhenkel.voicechat.api.events.UnregisterVolumeCategoryEvent; -import de.maxhenkel.voicechat.api.events.VoiceDistanceEvent; -import de.maxhenkel.voicechat.api.events.VoiceHostEvent; -import de.maxhenkel.voicechat.api.events.VoicechatServerStartedEvent; -import de.maxhenkel.voicechat.api.events.VoicechatServerStartingEvent; -import de.maxhenkel.voicechat.api.events.VoicechatServerStoppedEvent; -import de.maxhenkel.voicechat.plugins.EventBuilder; -import de.maxhenkel.voicechat.plugins.impl.GroupImpl; -import de.maxhenkel.voicechat.plugins.impl.VoicechatConnectionImpl; -import de.maxhenkel.voicechat.plugins.impl.VoicechatServerApiImpl; -import de.maxhenkel.voicechat.plugins.impl.VoicechatSocketImpl; -import de.maxhenkel.voicechat.plugins.impl.audiolistener.PlayerAudioListenerImpl; -import de.maxhenkel.voicechat.plugins.impl.events.CreateGroupEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.EntitySoundPacketEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.JoinGroupEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.LeaveGroupEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.LocationalSoundPacketEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.MicrophonePacketEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.PlayerConnectedEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.PlayerDisconnectedEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.PlayerStateChangedEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.RegisterVolumeCategoryEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.RemoveGroupEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.StaticSoundPacketEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.UnregisterVolumeCategoryEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.VoiceDistanceEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.VoiceHostEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.VoicechatServerStartedEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.VoicechatServerStartingEventImpl; -import de.maxhenkel.voicechat.plugins.impl.events.VoicechatServerStoppedEventImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.EntitySoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.LocationalSoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.MicrophonePacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.SoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.StaticSoundPacketImpl; -import de.maxhenkel.voicechat.voice.common.GroupSoundPacket; -import de.maxhenkel.voicechat.voice.common.LocationSoundPacket; -import de.maxhenkel.voicechat.voice.common.MicPacket; -import de.maxhenkel.voicechat.voice.common.PlayerSoundPacket; -import de.maxhenkel.voicechat.voice.common.PlayerState; -import de.maxhenkel.voicechat.voice.common.SoundPacket; -import de.maxhenkel.voicechat.voice.server.Group; -import de.maxhenkel.voicechat.voice.server.Server; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.Consumer; -import javax.annotation.Nullable; -import org.bukkit.entity.Player; - -public class PluginManager { - private List plugins; - private Map, List>> events; - private final Map> playerAudioListeners = new ConcurrentHashMap>(); - private static PluginManager instance; - - public void init() { - Voicechat.LOGGER.info("Loading plugins", new Object[0]); - this.plugins = Voicechat.apiService.getPlugins(); - Voicechat.LOGGER.info("Loaded {} plugin(s)", this.plugins.size()); - Voicechat.LOGGER.info("Initializing plugins", new Object[0]); - for (VoicechatPlugin plugin : this.plugins) { - try { - plugin.initialize(VoicechatServerApiImpl.instance()); - } - catch (Exception e) { - Voicechat.LOGGER.error("Failed to initialize plugin '{}'", plugin.getPluginId(), e); - } - } - Voicechat.LOGGER.info("Initialized {} plugin(s)", this.plugins.size()); - this.gatherEvents(); - } - - private void gatherEvents() { - EventBuilder eventBuilder = EventBuilder.create(); - EventRegistration registration = eventBuilder::addEvent; - for (VoicechatPlugin plugin : this.plugins) { - Voicechat.LOGGER.info("Registering events for '{}'", plugin.getPluginId()); - try { - plugin.registerEvents(registration); - } - catch (Throwable t) { - Voicechat.LOGGER.error("Failed to register events for '{}'", plugin.getPluginId(), t); - } - } - this.events = eventBuilder.build(); - } - - public synchronized boolean registerAudioListener(AudioListener l) { - if (!(l instanceof PlayerAudioListener)) { - return false; - } - PlayerAudioListener listener = (PlayerAudioListener)l; - boolean exists = this.playerAudioListeners.values().stream().anyMatch(listeners -> listeners.stream().anyMatch(playerAudioListener -> playerAudioListener.getListenerId().equals(listener.getListenerId()))); - if (exists) { - return false; - } - this.playerAudioListeners.computeIfAbsent(listener.getPlayerUuid(), k -> new CopyOnWriteArrayList()).add(listener); - return true; - } - - public synchronized boolean unregisterAudioListener(UUID listenerId) { - boolean removed = this.playerAudioListeners.values().stream().anyMatch(listeners -> listeners.removeIf(listener -> listener.getListenerId().equals(listenerId))); - if (!removed) { - return false; - } - this.playerAudioListeners.values().removeIf(List::isEmpty); - return true; - } - - public List getPlayerAudioListeners(UUID playerUuid) { - return this.playerAudioListeners.getOrDefault(playerUuid, Collections.emptyList()); - } - - public void onListenerAudio(UUID playerUuid, SoundPacket packet) { - if (playerUuid.equals(packet.getSender())) { - return; - } - List listeners = this.getPlayerAudioListeners(playerUuid); - if (listeners.isEmpty()) { - return; - } - SoundPacketImpl soundPacket = packet instanceof GroupSoundPacket ? new StaticSoundPacketImpl((GroupSoundPacket)packet) : (packet instanceof PlayerSoundPacket ? new EntitySoundPacketImpl((PlayerSoundPacket)packet) : (packet instanceof LocationSoundPacket ? new LocationalSoundPacketImpl((LocationSoundPacket)packet) : new SoundPacketImpl(packet))); - for (PlayerAudioListener l : listeners) { - if (!(l instanceof PlayerAudioListenerImpl)) continue; - try { - ((PlayerAudioListenerImpl)l).getListener().accept(soundPacket); - } - catch (Throwable t) { - Voicechat.LOGGER.error("Failed to process audio listener", t); - } - } - } - - public boolean dispatchEvent(Class eventClass, T event) { - List> events = this.events.get(eventClass); - if (events == null) { - return false; - } - for (Consumer evt : events) { - try { - Consumer e = evt; - e.accept(event); - if (!event.isCancelled()) continue; - break; - } - catch (Throwable t) { - Voicechat.LOGGER.error("Failed to dispatch event '{}'", eventClass.getSimpleName(), t); - } - } - return event.isCancelled(); - } - - public VoicechatSocket getSocketImplementation() { - VoicechatServerStartingEventImpl event = new VoicechatServerStartingEventImpl(); - this.dispatchEvent(VoicechatServerStartingEvent.class, event); - VoicechatSocket socket = event.getSocketImplementation(); - if (socket == null) { - socket = new VoicechatSocketImpl(); - Voicechat.LOGGER.debug("Using default voicechat socket implementation", new Object[0]); - } else { - Voicechat.LOGGER.info("Using custom voicechat socket implementation: {}", socket.getClass().getName()); - } - return socket; - } - - public String getVoiceHost(Player player, String voiceHost) { - VoiceHostEventImpl event = new VoiceHostEventImpl(player, voiceHost); - this.dispatchEvent(VoiceHostEvent.class, event); - return event.getVoiceHost(); - } - - public void onRegisterVolumeCategory(VolumeCategory category) { - this.dispatchEvent(RegisterVolumeCategoryEvent.class, new RegisterVolumeCategoryEventImpl(category)); - } - - public void onUnregisterVolumeCategory(VolumeCategory category) { - this.dispatchEvent(UnregisterVolumeCategoryEvent.class, new UnregisterVolumeCategoryEventImpl(category)); - } - - public void onServerStarted() { - this.dispatchEvent(VoicechatServerStartedEvent.class, new VoicechatServerStartedEventImpl()); - } - - public void onServerStopped() { - this.dispatchEvent(VoicechatServerStoppedEvent.class, new VoicechatServerStoppedEventImpl()); - } - - public void onPlayerConnected(@Nullable Player player) { - if (player == null) { - return; - } - this.dispatchEvent(PlayerConnectedEvent.class, new PlayerConnectedEventImpl(VoicechatConnectionImpl.fromPlayer(player))); - } - - public void onPlayerDisconnected(UUID player) { - this.dispatchEvent(PlayerDisconnectedEvent.class, new PlayerDisconnectedEventImpl(player)); - } - - public void onPlayerStateChanged(PlayerState state) { - this.dispatchEvent(PlayerStateChangedEvent.class, new PlayerStateChangedEventImpl(state)); - } - - public boolean onJoinGroup(Player player, @Nullable Group group) { - if (group == null) { - return this.onLeaveGroup(player); - } - return this.dispatchEvent(JoinGroupEvent.class, new JoinGroupEventImpl(new GroupImpl(group), VoicechatConnectionImpl.fromPlayer(player))); - } - - public boolean onCreateGroup(@Nullable Player player, @Nullable Group group) { - if (group == null) { - if (player == null) { - return false; - } - return this.onLeaveGroup(player); - } - return this.dispatchEvent(CreateGroupEvent.class, new CreateGroupEventImpl(new GroupImpl(group), VoicechatConnectionImpl.fromPlayer(player))); - } - - public boolean onLeaveGroup(Player player) { - Group g; - UUID groupUUID; - Server server = Voicechat.SERVER.getServer(); - if (server == null) { - return false; - } - GroupImpl group = null; - PlayerState state = server.getPlayerStateManager().getState(player.getUniqueId()); - if (state != null && (groupUUID = state.getGroup()) != null && (g = server.getGroupManager().getGroup(groupUUID)) != null) { - group = new GroupImpl(g); - } - return this.dispatchEvent(LeaveGroupEvent.class, new LeaveGroupEventImpl(group, VoicechatConnectionImpl.fromPlayer(player))); - } - - public boolean onRemoveGroup(Group group) { - return this.dispatchEvent(RemoveGroupEvent.class, new RemoveGroupEventImpl(new GroupImpl(group))); - } - - public boolean onMicPacket(Player sender, PlayerState senderState, MicPacket packet) { - return this.dispatchEvent(MicrophonePacketEvent.class, new MicrophonePacketEventImpl(new MicrophonePacketImpl(packet, sender.getUniqueId()), new VoicechatConnectionImpl(sender, senderState))); - } - - public float getDistance(Player sender, PlayerState senderState, MicPacket packet, float originalDistance) { - VoiceDistanceEventImpl event = new VoiceDistanceEventImpl(new MicrophonePacketImpl(packet, sender.getUniqueId()), new VoicechatConnectionImpl(sender, senderState), originalDistance); - this.dispatchEvent(VoiceDistanceEvent.class, event); - return event.getDistance(); - } - - public boolean onSoundPacket(@Nullable Player sender, @Nullable PlayerState senderState, Player receiver, PlayerState receiverState, SoundPacket p, String source) { - VoicechatConnectionImpl senderConnection = null; - if (sender != null && senderState != null) { - senderConnection = new VoicechatConnectionImpl(sender, senderState); - } - VoicechatConnectionImpl receiverConnection = new VoicechatConnectionImpl(receiver, receiverState); - if (p instanceof LocationSoundPacket) { - return this.dispatchEvent(LocationalSoundPacketEvent.class, new LocationalSoundPacketEventImpl(new LocationalSoundPacketImpl((LocationSoundPacket)p), (VoicechatConnection)senderConnection, (VoicechatConnection)receiverConnection, source)); - } - if (p instanceof PlayerSoundPacket) { - return this.dispatchEvent(EntitySoundPacketEvent.class, new EntitySoundPacketEventImpl(new EntitySoundPacketImpl((PlayerSoundPacket)p), (VoicechatConnection)senderConnection, (VoicechatConnection)receiverConnection, source)); - } - if (p instanceof GroupSoundPacket) { - return this.dispatchEvent(StaticSoundPacketEvent.class, new StaticSoundPacketEventImpl(new StaticSoundPacketImpl((GroupSoundPacket)p), (VoicechatConnection)senderConnection, (VoicechatConnection)receiverConnection, source)); - } - return false; - } - - public static synchronized PluginManager instance() { - if (instance == null) { - instance = new PluginManager(); - } - return instance; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/PlayerImpl.java b/source/decompiled/de/maxhenkel/voicechat/plugins/impl/PlayerImpl.java deleted file mode 100644 index 82b027f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/PlayerImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Entity - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.plugins.impl; - -import de.maxhenkel.voicechat.plugins.impl.EntityImpl; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; - -public class PlayerImpl -extends EntityImpl -implements de.maxhenkel.voicechat.api.Player { - public PlayerImpl(Player entity) { - super((Entity)entity); - } - - @Override - public Object getPlayer() { - return this.entity; - } - - public Player getRealPlayer() { - return (Player)this.entity; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/ServerPlayerImpl.java b/source/decompiled/de/maxhenkel/voicechat/plugins/impl/ServerPlayerImpl.java deleted file mode 100644 index e9e72ff..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/ServerPlayerImpl.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.plugins.impl; - -import de.maxhenkel.voicechat.api.ServerLevel; -import de.maxhenkel.voicechat.api.ServerPlayer; -import de.maxhenkel.voicechat.plugins.impl.PlayerImpl; -import de.maxhenkel.voicechat.plugins.impl.ServerLevelImpl; -import org.bukkit.entity.Player; - -public class ServerPlayerImpl -extends PlayerImpl -implements ServerPlayer { - public ServerPlayerImpl(Player entity) { - super(entity); - } - - public Player getRealServerPlayer() { - return (Player)this.entity; - } - - @Override - public ServerLevel getServerLevel() { - return new ServerLevelImpl(this.entity.getWorld()); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioSupplier.java b/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioSupplier.java deleted file mode 100644 index f137323..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/AudioSupplier.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.plugins.impl.audiochannel; - -import java.util.Arrays; -import java.util.function.Supplier; - -public class AudioSupplier -implements Supplier { - private final short[] audioData; - private final short[] frame; - private int framePosition; - - public AudioSupplier(short[] audioData) { - this.audioData = audioData; - this.frame = new short[960]; - } - - @Override - public short[] get() { - if (this.framePosition >= this.audioData.length) { - return null; - } - Arrays.fill(this.frame, (short)0); - System.arraycopy(this.audioData, this.framePosition, this.frame, 0, Math.min(this.frame.length, this.audioData.length - this.framePosition)); - this.framePosition += this.frame.length; - return this.frame; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/StaticAudioChannelImpl.java b/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/StaticAudioChannelImpl.java deleted file mode 100644 index fbd924f..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/audiochannel/StaticAudioChannelImpl.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.Bukkit - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.plugins.impl.audiochannel; - -import de.maxhenkel.voicechat.api.VoicechatConnection; -import de.maxhenkel.voicechat.api.audiochannel.StaticAudioChannel; -import de.maxhenkel.voicechat.api.packets.MicrophonePacket; -import de.maxhenkel.voicechat.plugins.impl.ServerPlayerImpl; -import de.maxhenkel.voicechat.plugins.impl.VoicechatServerApiImpl; -import de.maxhenkel.voicechat.plugins.impl.audiochannel.AudioChannelImpl; -import de.maxhenkel.voicechat.voice.common.GroupSoundPacket; -import de.maxhenkel.voicechat.voice.server.ClientConnection; -import de.maxhenkel.voicechat.voice.server.Group; -import de.maxhenkel.voicechat.voice.server.Server; -import de.maxhenkel.voicechat.voice.server.ServerGroupManager; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -public class StaticAudioChannelImpl -extends AudioChannelImpl -implements StaticAudioChannel { - protected boolean bypassGroupIsolation; - protected final Set targets = new HashSet(); - - public StaticAudioChannelImpl(UUID channelId, Server server) { - super(channelId, server); - } - - @Override - public void send(byte[] opusData) { - this.broadcast(new GroupSoundPacket(this.channelId, this.channelId, opusData, this.sequenceNumber.getAndIncrement(), this.category)); - } - - @Override - public void send(MicrophonePacket packet) { - this.send(packet.getOpusEncodedData()); - } - - @Override - public void flush() { - GroupSoundPacket packet = new GroupSoundPacket(this.channelId, this.channelId, new byte[0], this.sequenceNumber.getAndIncrement(), this.category); - this.broadcast(packet); - } - - /* - * WARNING - Removed try catching itself - possible behaviour change. - */ - private void broadcast(GroupSoundPacket packet) { - Set set = this.targets; - synchronized (set) { - ServerGroupManager groupManager = this.server.getGroupManager(); - for (UUID target : this.targets) { - Group playerGroup; - Player player; - ClientConnection connection = this.server.getConnection(target); - if (connection == null || (player = Bukkit.getPlayer((UUID)target)) == null || !this.bypassGroupIsolation && (playerGroup = groupManager.getPlayerGroup(player)) != null && playerGroup.isIsolated() || this.filter != null && !this.filter.test(new ServerPlayerImpl(player))) continue; - VoicechatServerApiImpl.sendPacket(player, packet); - } - } - } - - @Override - public void setBypassGroupIsolation(boolean bypassGroupIsolation) { - this.bypassGroupIsolation = bypassGroupIsolation; - } - - @Override - public boolean bypassesGroupIsolation() { - return this.bypassGroupIsolation; - } - - /* - * WARNING - Removed try catching itself - possible behaviour change. - */ - @Override - public void addTarget(VoicechatConnection target) { - Set set = this.targets; - synchronized (set) { - this.targets.add(target.getPlayer().getUuid()); - } - } - - /* - * WARNING - Removed try catching itself - possible behaviour change. - */ - @Override - public void removeTarget(VoicechatConnection target) { - Set set = this.targets; - synchronized (set) { - this.targets.remove(target.getPlayer().getUuid()); - } - } - - /* - * WARNING - Removed try catching itself - possible behaviour change. - */ - @Override - public void clearTargets() { - Set set = this.targets; - synchronized (set) { - this.targets.clear(); - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartedEventImpl.java b/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartedEventImpl.java deleted file mode 100644 index 851b8ec..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStartedEventImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.plugins.impl.events; - -import de.maxhenkel.voicechat.api.events.VoicechatServerStartedEvent; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; - -public class VoicechatServerStartedEventImpl -extends ServerEventImpl -implements VoicechatServerStartedEvent { - @Override - public boolean isCancellable() { - return false; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStoppedEventImpl.java b/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStoppedEventImpl.java deleted file mode 100644 index ba9ac36..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/events/VoicechatServerStoppedEventImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.plugins.impl.events; - -import de.maxhenkel.voicechat.api.events.VoicechatServerStoppedEvent; -import de.maxhenkel.voicechat.plugins.impl.events.ServerEventImpl; - -public class VoicechatServerStoppedEventImpl -extends ServerEventImpl -implements VoicechatServerStoppedEvent { - @Override - public boolean isCancellable() { - return false; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/MicrophonePacketImpl.java b/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/MicrophonePacketImpl.java deleted file mode 100644 index de0432e..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/plugins/impl/packets/MicrophonePacketImpl.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.plugins.impl.packets; - -import de.maxhenkel.voicechat.api.Position; -import de.maxhenkel.voicechat.api.packets.EntitySoundPacket; -import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket; -import de.maxhenkel.voicechat.api.packets.MicrophonePacket; -import de.maxhenkel.voicechat.api.packets.StaticSoundPacket; -import de.maxhenkel.voicechat.plugins.impl.PositionImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.EntitySoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.LocationalSoundPacketImpl; -import de.maxhenkel.voicechat.plugins.impl.packets.StaticSoundPacketImpl; -import de.maxhenkel.voicechat.voice.common.GroupSoundPacket; -import de.maxhenkel.voicechat.voice.common.LocationSoundPacket; -import de.maxhenkel.voicechat.voice.common.MicPacket; -import de.maxhenkel.voicechat.voice.common.PlayerSoundPacket; -import de.maxhenkel.voicechat.voice.common.Utils; -import java.util.Objects; -import java.util.UUID; - -public class MicrophonePacketImpl -implements MicrophonePacket { - private final MicPacket packet; - private final UUID sender; - - public MicrophonePacketImpl(MicPacket packet, UUID sender) { - this.packet = packet; - this.sender = sender; - } - - @Override - public boolean isWhispering() { - return this.packet.isWhispering(); - } - - @Override - public byte[] getOpusEncodedData() { - return this.packet.getData(); - } - - @Override - public void setOpusEncodedData(byte[] data) { - this.packet.setData(Objects.requireNonNull(data)); - } - - @Override - public EntitySoundPacket.Builder entitySoundPacketBuilder() { - return new EntitySoundPacketImpl.BuilderImpl(this.sender, this.sender, this.packet.getData(), this.packet.getSequenceNumber(), null); - } - - @Override - public LocationalSoundPacket.Builder locationalSoundPacketBuilder() { - return new LocationalSoundPacketImpl.BuilderImpl(this.sender, this.sender, this.packet.getData(), this.packet.getSequenceNumber(), null); - } - - @Override - public StaticSoundPacket.Builder staticSoundPacketBuilder() { - return new StaticSoundPacketImpl.BuilderImpl(this.sender, this.sender, this.packet.getData(), this.packet.getSequenceNumber(), null); - } - - @Override - @Deprecated - public EntitySoundPacket toEntitySoundPacket(UUID entityUuid, boolean whispering) { - return new EntitySoundPacketImpl(new PlayerSoundPacket(this.sender, entityUuid, this.packet.getData(), this.packet.getSequenceNumber(), whispering, Utils.getDefaultDistance(), null)); - } - - @Override - @Deprecated - public LocationalSoundPacket toLocationalSoundPacket(Position position) { - if (position instanceof PositionImpl) { - return new LocationalSoundPacketImpl(new LocationSoundPacket(this.sender, this.sender, ((PositionImpl)position).getPosition(), this.packet.getData(), this.packet.getSequenceNumber(), Utils.getDefaultDistance(), null)); - } - throw new IllegalArgumentException("position is not an instance of PositionImpl"); - } - - @Override - @Deprecated - public StaticSoundPacket toStaticSoundPacket() { - return new StaticSoundPacketImpl(new GroupSoundPacket(this.sender, this.sender, this.packet.getData(), this.packet.getSequenceNumber(), null)); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/Packet.java b/source/decompiled/de/maxhenkel/voicechat/voice/common/Packet.java deleted file mode 100644 index ec38293..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/Packet.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Decompiled with CFR 0.152. - */ -package de.maxhenkel.voicechat.voice.common; - -import de.maxhenkel.voicechat.util.FriendlyByteBuf; - -public interface Packet { - public T fromBytes(FriendlyByteBuf var1); - - public void toBytes(FriendlyByteBuf var1); - - default public long getTTL() { - return 10000L; - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/common/Secret.java b/source/decompiled/de/maxhenkel/voicechat/voice/common/Secret.java deleted file mode 100644 index b030976..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/voice/common/Secret.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * io.netty.buffer.ByteBuf - */ -package de.maxhenkel.voicechat.voice.common; - -import io.netty.buffer.ByteBuf; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Arrays; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -public class Secret { - public static final int SECRET_SIZE_BYTES = 16; - public static final int IV_SIZE_BYTES = 12; - public static final int TAG_LEN_BITS = 128; - public static final String CIPHER = "AES/GCM/NoPadding"; - private static final SecureRandom RANDOM = new SecureRandom(); - private final byte[] secret; - private final SecretKeySpec keySpec; - private volatile boolean legacyProtocol; - - protected Secret(byte[] byArray) { - if (byArray == null || byArray.length != 16) { - throw new IllegalArgumentException("Voice chat secret must contain exactly 16 bytes"); - } - this.secret = (byte[])byArray.clone(); - this.keySpec = new SecretKeySpec(this.secret, "AES"); - } - - public static Secret generateNewRandomSecret() { - byte[] byArray = new byte[16]; - RANDOM.nextBytes(byArray); - return new Secret(byArray); - } - - public static Secret fromBytes(byte[] byArray) { - return new Secret(byArray); - } - - public static Secret fromBytes(ByteBuf byteBuf) { - byte[] byArray = new byte[16]; - byteBuf.readBytes(byArray); - return Secret.fromBytes(byArray); - } - - public void toBytes(ByteBuf byteBuf) { - byteBuf.writeBytes(this.secret); - } - - public byte[] getSecret() { - return (byte[])this.secret.clone(); - } - - public SecretKeySpec getKeySpec() { - return this.keySpec; - } - - public void setLegacyProtocol(boolean bl) { - this.legacyProtocol = bl; - } - - public boolean isLegacyProtocol() { - return this.legacyProtocol; - } - - public static byte[] generateIV() { - byte[] byArray = new byte[12]; - RANDOM.nextBytes(byArray); - return byArray; - } - - private static byte[] generateLegacyIV() { - byte[] byArray = new byte[16]; - RANDOM.nextBytes(byArray); - return byArray; - } - - public byte[] encrypt(byte[] byArray) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { - if (this.legacyProtocol) { - byte[] byArray2 = Secret.generateLegacyIV(); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(1, (Key)this.keySpec, new IvParameterSpec(byArray2)); - byte[] byArray3 = cipher.doFinal(byArray); - byte[] byArray4 = new byte[byArray2.length + byArray3.length]; - System.arraycopy(byArray2, 0, byArray4, 0, byArray2.length); - System.arraycopy(byArray3, 0, byArray4, byArray2.length, byArray3.length); - return byArray4; - } - byte[] byArray5 = Secret.generateIV(); - Cipher cipher = Cipher.getInstance(CIPHER); - cipher.init(1, (Key)this.keySpec, new GCMParameterSpec(128, byArray5)); - byte[] byArray6 = cipher.doFinal(byArray); - byte[] byArray7 = new byte[byArray5.length + byArray6.length]; - System.arraycopy(byArray5, 0, byArray7, 0, byArray5.length); - System.arraycopy(byArray6, 0, byArray7, byArray5.length, byArray6.length); - return byArray7; - } - - public byte[] decrypt(byte[] byArray) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { - if (this.legacyProtocol) { - if (byArray.length < 32 || (byArray.length - 16) % 16 != 0) { - throw new IllegalBlockSizeException("Invalid legacy AES-CBC packet size"); - } - byte[] byArray2 = Arrays.copyOfRange(byArray, 0, 16); - byte[] byArray3 = Arrays.copyOfRange(byArray, 16, byArray.length); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(2, (Key)this.keySpec, new IvParameterSpec(byArray2)); - return cipher.doFinal(byArray3); - } - if (byArray.length < 28) { - throw new IllegalBlockSizeException("Invalid AES-GCM packet size"); - } - byte[] byArray4 = Arrays.copyOfRange(byArray, 0, 12); - byte[] byArray5 = Arrays.copyOfRange(byArray, 12, byArray.length); - Cipher cipher = Cipher.getInstance(CIPHER); - cipher.init(2, (Key)this.keySpec, new GCMParameterSpec(128, byArray4)); - return cipher.doFinal(byArray5); - } - - public boolean equals(Object object) { - return object instanceof Secret && Arrays.equals(this.secret, ((Secret)object).secret); - } - - public int hashCode() { - return Arrays.hashCode(this.secret); - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/server/Server.java b/source/decompiled/de/maxhenkel/voicechat/voice/server/Server.java deleted file mode 100644 index 3cb1838..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/voice/server/Server.java +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * javax.annotation.Nullable - * org.bukkit.Bukkit - * org.bukkit.GameMode - * org.bukkit.Server - * org.bukkit.entity.Entity - * org.bukkit.entity.Player - */ -package de.maxhenkel.voicechat.voice.server; - -import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.api.RawUdpPacket; -import de.maxhenkel.voicechat.api.VoicechatSocket; -import de.maxhenkel.voicechat.debug.CooldownTimer; -import de.maxhenkel.voicechat.debug.VoicechatUncaughtExceptionHandler; -import de.maxhenkel.voicechat.net.NetManager; -import de.maxhenkel.voicechat.permission.PermissionManager; -import de.maxhenkel.voicechat.plugins.PluginManager; -import de.maxhenkel.voicechat.voice.common.AuthenticateAckPacket; -import de.maxhenkel.voicechat.voice.common.AuthenticatePacket; -import de.maxhenkel.voicechat.voice.common.ConnectionCheckAckPacket; -import de.maxhenkel.voicechat.voice.common.ConnectionCheckPacket; -import de.maxhenkel.voicechat.voice.common.GroupSoundPacket; -import de.maxhenkel.voicechat.voice.common.KeepAlivePacket; -import de.maxhenkel.voicechat.voice.common.LocationSoundPacket; -import de.maxhenkel.voicechat.voice.common.MicPacket; -import de.maxhenkel.voicechat.voice.common.NetworkMessage; -import de.maxhenkel.voicechat.voice.common.Packet; -import de.maxhenkel.voicechat.voice.common.PingPacket; -import de.maxhenkel.voicechat.voice.common.PlayerSoundPacket; -import de.maxhenkel.voicechat.voice.common.PlayerState; -import de.maxhenkel.voicechat.voice.common.Secret; -import de.maxhenkel.voicechat.voice.common.SoundPacket; -import de.maxhenkel.voicechat.voice.common.Utils; -import de.maxhenkel.voicechat.voice.server.ClientConnection; -import de.maxhenkel.voicechat.voice.server.Group; -import de.maxhenkel.voicechat.voice.server.PingManager; -import de.maxhenkel.voicechat.voice.server.PlayerStateManager; -import de.maxhenkel.voicechat.voice.server.ServerCategoryManager; -import de.maxhenkel.voicechat.voice.server.ServerGroupManager; -import de.maxhenkel.voicechat.voice.server.ServerPlayerManager; -import java.net.InetAddress; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.nio.channels.AsynchronousCloseException; -import java.util.Collection; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import javax.annotation.Nullable; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; - -public class Server -extends Thread { - private final Map connections; - private final Map unCheckedConnections; - private final Map secrets; - private final int port; - private final org.bukkit.Server server; - private final VoicechatSocket socket; - private final ProcessThread processThread; - private final BlockingQueue packetQueue; - private final PingManager pingManager; - private final PlayerStateManager playerStateManager; - private final ServerGroupManager groupManager; - private final ServerCategoryManager categoryManager; - - public Server() { - int configPort = Voicechat.SERVER_CONFIG.voiceChatPort.get(); - if (configPort < 0) { - Voicechat.LOGGER.info("Using the Minecraft servers port as voice chat port", new Object[0]); - this.port = Bukkit.getPort(); - } else { - this.port = configPort; - } - this.server = Bukkit.getServer(); - this.socket = PluginManager.instance().getSocketImplementation(); - this.connections = new ConcurrentHashMap(); - this.unCheckedConnections = new ConcurrentHashMap(); - this.secrets = new ConcurrentHashMap(); - this.packetQueue = new LinkedBlockingQueue(); - this.pingManager = new PingManager(this); - this.playerStateManager = new PlayerStateManager(); - this.groupManager = new ServerGroupManager(); - this.categoryManager = new ServerCategoryManager(); - this.setDaemon(true); - this.setName("VoiceChatServerThread"); - this.setUncaughtExceptionHandler(new VoicechatUncaughtExceptionHandler()); - this.processThread = new ProcessThread(); - this.processThread.start(); - } - - @Override - public void run() { - try { - String bindAddress = this.getBindAddress(); - try { - InetAddress.getByName(bindAddress); - } - catch (UnknownHostException e) { - Voicechat.LOGGER.error("Failed to parse bind IP address '{}'", bindAddress, e); - Voicechat.LOGGER.info("Binding to wildcard IP address", new Object[0]); - bindAddress = ""; - } - this.socket.open(this.port, bindAddress); - if (bindAddress.isEmpty()) { - Voicechat.LOGGER.info("Voice chat server started at port {}", this.socket.getLocalPort()); - } else { - Voicechat.LOGGER.info("Voice chat server started at {}:{}", bindAddress, this.socket.getLocalPort()); - } - while (!this.socket.isClosed()) { - try { - this.packetQueue.add(this.socket.read()); - } - catch (Exception e) { - if (e instanceof SocketException && e.getCause() instanceof AsynchronousCloseException || !Voicechat.debugMode()) continue; - Voicechat.LOGGER.error("Failed to read from socket", e); - } - } - } - catch (Exception e) { - Voicechat.LOGGER.error("Voice chat server error", e); - } - } - - private String getBindAddress() { - String bindAddress; - block8: { - bindAddress = Voicechat.SERVER_CONFIG.voiceChatBindAddress.get(); - if (bindAddress.trim().equals("*")) { - bindAddress = ""; - } else if (bindAddress.trim().isEmpty()) { - try { - bindAddress = Bukkit.getIp(); - if (bindAddress.trim().isEmpty()) break block8; - try { - InetAddress address = InetAddress.getByName(bindAddress); - if (address.isLoopbackAddress()) { - bindAddress = ""; - break block8; - } - Voicechat.LOGGER.info("Using server-ip as bind address: {}", bindAddress); - } - catch (Exception e) { - Voicechat.LOGGER.warn("Invalid server-ip", e); - bindAddress = ""; - } - } - catch (Throwable t) { - Voicechat.LOGGER.warn("Failed to get server-ip from server.properties - binding to wildcard address", t); - } - } - } - return bindAddress; - } - - public Secret getSecret(UUID playerUUID) { - if (this.hasSecret(playerUUID)) { - return this.secrets.get(playerUUID); - } - Secret secret = Secret.generateNewRandomSecret(); - this.secrets.put(playerUUID, secret); - return secret; - } - - @Nullable - public Secret generateNewSecret(UUID playerUUID) { - if (this.hasSecret(playerUUID)) { - return null; - } - return this.getSecret(playerUUID); - } - - public boolean hasSecret(UUID playerUUID) { - return this.secrets.containsKey(playerUUID); - } - - public void disconnectClient(UUID playerUUID) { - this.connections.remove(playerUUID); - this.unCheckedConnections.remove(playerUUID); - this.secrets.remove(playerUUID); - PluginManager.instance().onPlayerDisconnected(playerUUID); - } - - public void close() { - this.socket.close(); - this.processThread.close(); - PluginManager.instance().onServerStopped(); - } - - public boolean isClosed() { - return !this.processThread.running; - } - - public void onMicPacket(UUID playerUuid, MicPacket packet) { - Player player = this.server.getPlayer(playerUuid); - if (player == null) { - return; - } - if (!player.hasPermission(PermissionManager.SPEAK_PERMISSION)) { - CooldownTimer.run("no-speak-" + playerUuid, () -> NetManager.sendStatusMessage(player, "message.voicechat.no_speak_permission", new String[0])); - return; - } - PlayerState state = this.playerStateManager.getState(player.getUniqueId()); - if (state == null) { - return; - } - if (!PluginManager.instance().onMicPacket(player, state, packet)) { - this.processMicPacket(player, state, packet); - } - } - - private void processMicPacket(Player player, PlayerState state, MicPacket packet) { - if (state.hasGroup()) { - Group group = this.groupManager.getGroup(state.getGroup()); - this.processGroupPacket(state, player, packet); - if (group == null || group.isOpen()) { - this.processProximityPacket(state, player, packet); - } - return; - } - this.processProximityPacket(state, player, packet); - } - - private void processGroupPacket(PlayerState senderState, Player sender, MicPacket packet) { - UUID groupId = senderState.getGroup(); - if (groupId == null) { - return; - } - GroupSoundPacket groupSoundPacket = new GroupSoundPacket(senderState.getUuid(), senderState.getUuid(), packet.getData(), packet.getSequenceNumber(), null); - for (PlayerState state : this.playerStateManager.getStates()) { - Player p; - if (!groupId.equals(state.getGroup()) || senderState.getUuid().equals(state.getUuid()) || (p = this.server.getPlayer(state.getUuid())) == null) continue; - ClientConnection connection = this.getConnection(state.getUuid()); - this.sendSoundPacket(sender, senderState, p, state, connection, groupSoundPacket, "group"); - } - } - - private void processProximityPacket(PlayerState senderState, Player sender, MicPacket packet) { - UUID groupId = senderState.getGroup(); - float distance = packet.isWhispering() ? Voicechat.SERVER_CONFIG.whisperDistance.get().floatValue() : Utils.getDefaultDistance(); - distance = PluginManager.instance().getDistance(sender, senderState, packet, distance); - SoundPacket soundPacket = null; - String source = null; - if (sender.getGameMode().equals((Object)GameMode.SPECTATOR)) { - Player spectatingPlayer; - Entity camera; - if (Voicechat.SERVER_CONFIG.spectatorPlayerPossession.get().booleanValue() && (camera = sender.getSpectatorTarget()) instanceof Player && (spectatingPlayer = (Player)camera) != sender) { - PlayerState receiverState = this.playerStateManager.getState(spectatingPlayer.getUniqueId()); - if (receiverState == null) { - return; - } - GroupSoundPacket groupSoundPacket = new GroupSoundPacket(senderState.getUuid(), senderState.getUuid(), packet.getData(), packet.getSequenceNumber(), null); - ClientConnection connection = this.getConnection(receiverState.getUuid()); - this.sendSoundPacket(sender, senderState, spectatingPlayer, receiverState, connection, groupSoundPacket, "spectator"); - return; - } - if (Voicechat.SERVER_CONFIG.spectatorInteraction.get().booleanValue()) { - soundPacket = new LocationSoundPacket(sender.getUniqueId(), sender.getUniqueId(), sender.getLocation(), packet.getData(), packet.getSequenceNumber(), distance, null); - source = "spectator"; - } - } - if (soundPacket == null) { - soundPacket = new PlayerSoundPacket(sender.getUniqueId(), sender.getUniqueId(), packet.getData(), packet.getSequenceNumber(), packet.isWhispering(), distance, null); - source = "proximity"; - } - this.broadcast(ServerPlayerManager.getPlayersInRange(sender.getWorld(), sender.getLocation(), this.getBroadcastRange(distance), p -> !p.getUniqueId().equals(sender.getUniqueId())), soundPacket, sender, senderState, groupId, source); - } - - public void sendSoundPacket(@Nullable Player sender, @Nullable PlayerState senderState, Player receiver, PlayerState receiverState, @Nullable ClientConnection connection, SoundPacket soundPacket, String source) { - PluginManager.instance().onListenerAudio(receiver.getUniqueId(), soundPacket); - if (connection == null) { - return; - } - if (receiverState.isDisabled() || receiverState.isDisconnected()) { - return; - } - if (PluginManager.instance().onSoundPacket(sender, senderState, receiver, receiverState, soundPacket, source)) { - return; - } - if (!receiver.hasPermission(PermissionManager.LISTEN_PERMISSION)) { - CooldownTimer.run(String.format("no-listen-%s", receiver.getUniqueId()), 30000L, () -> NetManager.sendStatusMessage(receiver, "message.voicechat.no_listen_permission", new String[0])); - return; - } - this.sendPacket(soundPacket, connection); - } - - public double getBroadcastRange(float minRange) { - double broadcastRange = Voicechat.SERVER_CONFIG.broadcastRange.get(); - if (broadcastRange < 0.0) { - broadcastRange = Voicechat.SERVER_CONFIG.voiceChatDistance.get() + 1.0; - } - return Math.max(broadcastRange, (double)minRange); - } - - public void broadcast(Collection players, SoundPacket packet, @Nullable Player sender, @Nullable PlayerState senderState, @Nullable UUID groupId, String source) { - for (Player player : players) { - PlayerState state = this.playerStateManager.getState(player.getUniqueId()); - if (state == null || state.hasGroup() && state.getGroup().equals(groupId)) continue; - Group receiverGroup = null; - if (state.hasGroup()) { - receiverGroup = this.groupManager.getGroup(state.getGroup()); - } - if (receiverGroup != null && receiverGroup.isIsolated()) continue; - ClientConnection connection = this.getConnection(state.getUuid()); - this.sendSoundPacket(sender, senderState, player, state, connection, packet, source); - } - } - - private void sendKeepAlives() { - long timestamp = System.currentTimeMillis(); - this.connections.values().removeIf(connection -> { - if (timestamp - connection.getLastKeepAliveResponse() >= (long)Voicechat.SERVER_CONFIG.keepAlive.get().intValue() * 10L) { - this.secrets.remove(connection.getPlayerUUID()); - Voicechat.LOGGER.info("Player {} timed out", connection.getPlayerUUID()); - Player player = this.server.getPlayer(connection.getPlayerUUID()); - if (player != null) { - Voicechat.LOGGER.info("Reconnecting player {}", player.getName()); - Voicechat.SERVER.initializePlayerConnection(player); - } else { - Voicechat.LOGGER.error("Reconnecting player {} failed (Could not find player)", connection.getPlayerUUID()); - } - this.playerStateManager.onPlayerVoicechatDisconnect(connection.getPlayerUUID()); - PluginManager.instance().onPlayerDisconnected(connection.getPlayerUUID()); - return true; - } - return false; - }); - for (ClientConnection connection2 : this.connections.values()) { - this.sendPacket(new KeepAlivePacket(), connection2); - } - } - - @Nullable - public ClientConnection getSender(NetworkMessage message) { - return this.connections.values().stream().filter(connection -> connection.getAddress().equals(message.getAddress())).findAny().orElse(null); - } - - @Nullable - public ClientConnection getUnconnectedSender(NetworkMessage message) { - return this.unCheckedConnections.values().stream().filter(connection -> connection.getAddress().equals(message.getAddress())).findAny().orElse(null); - } - - public Map getConnections() { - return this.connections; - } - - @Nullable - public ClientConnection getConnection(UUID playerID) { - return this.connections.get(playerID); - } - - public VoicechatSocket getSocket() { - return this.socket; - } - - public int getPort() { - return this.socket.getLocalPort(); - } - - public boolean sendPacket(Packet packet, ClientConnection connection) { - try { - this.sendPacketRaw(packet, connection); - return true; - } - catch (Exception e) { - Voicechat.LOGGER.error("Failed to send voice chat packet to {}", connection.getPlayerUUID()); - return false; - } - } - - public void sendPacketRaw(Packet packet, ClientConnection connection) throws Exception { - connection.send(this, new NetworkMessage(packet)); - } - - public PingManager getPingManager() { - return this.pingManager; - } - - public PlayerStateManager getPlayerStateManager() { - return this.playerStateManager; - } - - public ServerGroupManager getGroupManager() { - return this.groupManager; - } - - public ServerCategoryManager getCategoryManager() { - return this.categoryManager; - } - - private class ProcessThread - extends Thread { - private boolean running = true; - private long lastKeepAlive = 0L; - - public ProcessThread() { - this.setDaemon(true); - this.setName("VoiceChatPacketProcessingThread"); - this.setUncaughtExceptionHandler(new VoicechatUncaughtExceptionHandler()); - } - - @Override - public void run() { - while (this.running) { - try { - NetworkMessage message; - RawUdpPacket rawPacket; - Server.this.pingManager.checkTimeouts(); - long keepAliveTime = System.currentTimeMillis(); - if (keepAliveTime - this.lastKeepAlive > (long)Voicechat.SERVER_CONFIG.keepAlive.get().intValue()) { - Server.this.sendKeepAlives(); - this.lastKeepAlive = keepAliveTime; - } - if ((rawPacket = (RawUdpPacket)Server.this.packetQueue.poll(10L, TimeUnit.MILLISECONDS)) == null) continue; - try { - message = NetworkMessage.readPacketServer(rawPacket, Server.this); - } - catch (Exception e) { - CooldownTimer.run("failed_reading_packet", () -> Voicechat.LOGGER.warn("Failed to read packet from {}", rawPacket.getSocketAddress())); - continue; - } - if (message == null) continue; - if (System.currentTimeMillis() - message.getTimestamp() > message.getTTL()) { - CooldownTimer.run("ttl", () -> { - Voicechat.LOGGER.error("Dropping voice chat packets! Your Server might be overloaded!", new Object[0]); - Voicechat.LOGGER.error("Packet queue has {} packets", Server.this.packetQueue.size()); - }); - continue; - } - if (message.getPacket() instanceof AuthenticatePacket) { - AuthenticatePacket packet = (AuthenticatePacket)message.getPacket(); - Secret secret = (Secret)Server.this.secrets.get(packet.getPlayerUUID()); - if (secret != null && secret.equals(packet.getSecret())) { - ClientConnection connection = (ClientConnection)Server.this.unCheckedConnections.get(packet.getPlayerUUID()); - if (connection == null) { - connection = (ClientConnection)Server.this.connections.get(packet.getPlayerUUID()); - } - if (connection == null) { - connection = new ClientConnection(packet.getPlayerUUID(), message.getAddress()); - Server.this.unCheckedConnections.put(packet.getPlayerUUID(), connection); - Voicechat.LOGGER.info("Successfully authenticated player {}", packet.getPlayerUUID()); - } - Server.this.sendPacket(new AuthenticateAckPacket(), connection); - } - } - if (message.getPacket() instanceof ConnectionCheckPacket) { - ClientConnection connection = Server.this.getUnconnectedSender(message); - if (connection == null) { - connection = Server.this.getSender(message); - if (connection == null) continue; - Server.this.sendPacket(new ConnectionCheckAckPacket(), connection); - continue; - } - connection.setLastKeepAliveResponse(System.currentTimeMillis()); - Server.this.connections.put(connection.getPlayerUUID(), connection); - Server.this.unCheckedConnections.remove(connection.getPlayerUUID()); - Voicechat.LOGGER.info("Successfully validated connection of player {}", connection.getPlayerUUID()); - Player player = Server.this.server.getPlayer(connection.getPlayerUUID()); - if (player != null) { - Server.this.playerStateManager.onPlayerVoicechatConnect(player); - PluginManager.instance().onPlayerConnected(player); - Voicechat.LOGGER.info("Player {} ({}) successfully connected to voice chat", player.getName(), connection.getPlayerUUID()); - } - Server.this.sendPacket(new ConnectionCheckAckPacket(), connection); - continue; - } - ClientConnection conn = Server.this.getSender(message); - if (conn == null) continue; - if (message.getPacket() instanceof MicPacket) { - Server.this.onMicPacket(conn.getPlayerUUID(), (MicPacket)message.getPacket()); - continue; - } - if (message.getPacket() instanceof PingPacket) { - PingPacket packet = (PingPacket)message.getPacket(); - Server.this.pingManager.onPongPacket(packet); - continue; - } - if (!(message.getPacket() instanceof KeepAlivePacket)) continue; - conn.setLastKeepAliveResponse(System.currentTimeMillis()); - } - catch (Exception e) { - Voicechat.LOGGER.error("Voice chat server error", e); - } - } - } - - public void close() { - this.running = false; - } - } -} - diff --git a/source/decompiled/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java b/source/decompiled/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java deleted file mode 100644 index f1886cc..0000000 --- a/source/decompiled/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Decompiled with CFR 0.152. - * - * Could not load the following classes: - * org.bukkit.Bukkit - * org.bukkit.entity.Player - * org.bukkit.event.EventHandler - * org.bukkit.event.Listener - * org.bukkit.event.player.PlayerJoinEvent - * org.bukkit.event.player.PlayerQuitEvent - */ -package de.maxhenkel.voicechat.voice.server; - -import de.maxhenkel.voicechat.Voicechat; -import de.maxhenkel.voicechat.compatibility.PlayerHideEvent; -import de.maxhenkel.voicechat.compatibility.PlayerShowEvent; -import de.maxhenkel.voicechat.net.NetManager; -import de.maxhenkel.voicechat.net.PacketRateLimiter; -import de.maxhenkel.voicechat.net.RequestSecretPacket; -import de.maxhenkel.voicechat.net.SecretPacket; -import de.maxhenkel.voicechat.plugins.PluginManager; -import de.maxhenkel.voicechat.voice.common.Secret; -import de.maxhenkel.voicechat.voice.server.Server; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -public class ServerVoiceEvents -implements Listener { - private static final int LEGACY_COMPATIBILITY_VERSION = 18; - private static final int CURRENT_COMPATIBILITY_VERSION = 20; - private final Map clientCompatibilities = new ConcurrentHashMap(); - private final PacketRateLimiter rateLimiter; - private Server server; - - public ServerVoiceEvents() { - this.rateLimiter = new PacketRateLimiter(Voicechat.SERVER_CONFIG.tcpRateLimit.get()); - } - - public void init() { - if (this.server != null) { - return; - } - if (!Bukkit.getOnlineMode()) { - Voicechat.LOGGER.warn("Running in offline mode - Voice chat encryption is not secure!", new Object[0]); - } - Voicechat.compatibility.registerPlayerHideEvent(this::onPlayerHide); - Voicechat.compatibility.registerPlayerShowEvent(this::onPlayerShow); - this.server = new Server(); - this.server.start(); - PluginManager.instance().onServerStarted(); - } - - public void onRequestSecretPacket(Player player, RequestSecretPacket requestSecretPacket) { - UUID uUID; - int n = requestSecretPacket.getCompatibilityVersion(); - Voicechat.LOGGER.info("Received secret request of {} ({})", player.getName(), n); - try { - uUID = player.getUniqueId(); - } - catch (UnsupportedOperationException unsupportedOperationException) { - player.kickPlayer("Tried to authenticate voice chat while still connecting"); - Voicechat.LOGGER.warn("{} tried to authenticate voice chat while still connecting", player.getName()); - return; - } - this.clientCompatibilities.put(uUID, n); - if (!ServerVoiceEvents.isSupportedCompatibilityVersion(n)) { - Voicechat.LOGGER.warn("Connected client {} has incompatible voice chat version (server={}, client={})", player.getName(), Voicechat.COMPATIBILITY_VERSION, n); - ServerVoiceEvents.sendIncompatibleMessage(player, n); - return; - } - this.initializePlayerConnection(player); - } - - private static boolean isSupportedCompatibilityVersion(int n) { - return n == 18 || n == 20; - } - - public boolean isCompatible(Player player) { - return this.isCompatible(player.getUniqueId()); - } - - public boolean isCompatible(UUID uUID) { - return ServerVoiceEvents.isSupportedCompatibilityVersion(this.clientCompatibilities.getOrDefault(uUID, -1)); - } - - public static void sendIncompatibleMessage(Player player, int n) { - if (n <= 6) { - player.sendMessage(String.format(Voicechat.TRANSLATIONS.voicechatNotCompatibleMessage.get(), "2.6.x", "Simple Voice Chat")); - } else { - Voicechat.compatibility.sendIncompatibleMessage(player, "2.6.x", "Simple Voice Chat"); - } - } - - public void initializePlayerConnection(Player player) { - if (this.server == null) { - return; - } - UUID uUID = player.getUniqueId(); - this.server.getPlayerStateManager().onPlayerCompatibilityCheckSucceeded(player); - this.server.getCategoryManager().onPlayerCompatibilityCheckSucceeded(player); - this.server.getGroupManager().onPlayerCompatibilityCheckSucceeded(player); - Secret secret = this.server.generateNewSecret(uUID); - if (secret == null) { - Voicechat.LOGGER.warn("Player already requested secret - ignoring", new Object[0]); - return; - } - secret.setLegacyProtocol(this.clientCompatibilities.getOrDefault(uUID, -1) == 18); - String string = PluginManager.instance().getVoiceHost(player, Voicechat.SERVER_CONFIG.voiceHost.get()); - NetManager.sendToClient(player, new SecretPacket(player, secret, this.server.getPort(), Voicechat.SERVER_CONFIG, string)); - Voicechat.LOGGER.info("Sent secret to {}", player.getName()); - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent playerJoinEvent) { - this.server.getPlayerStateManager().onPlayerJoin(playerJoinEvent); - if (!Voicechat.SERVER_CONFIG.forceVoiceChat.get().booleanValue()) { - return; - } - Player player = playerJoinEvent.getPlayer(); - Voicechat.compatibility.runTaskLater(() -> { - if (!player.isOnline()) { - return; - } - if (!this.isCompatible(player)) { - player.kickPlayer(String.format(Voicechat.TRANSLATIONS.forceVoicechatKickMessage.get(), "Simple Voice Chat", Voicechat.INSTANCE.getDescription().getVersion())); - } - }, (long)Voicechat.SERVER_CONFIG.loginTimeout.get().intValue() / 50L); - } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent playerQuitEvent) { - this.server.getPlayerStateManager().onPlayerQuit(playerQuitEvent); - this.server.getGroupManager().onPlayerQuit(playerQuitEvent); - UUID uUID = playerQuitEvent.getPlayer().getUniqueId(); - this.clientCompatibilities.remove(uUID); - this.rateLimiter.onPlayerLoggedOut(playerQuitEvent.getPlayer()); - if (this.server == null) { - return; - } - this.server.disconnectClient(uUID); - Voicechat.LOGGER.info("Disconnecting client {}", playerQuitEvent.getPlayer().getName()); - } - - public void onPlayerHide(PlayerHideEvent playerHideEvent) { - this.server.getPlayerStateManager().onPlayerHide(playerHideEvent); - } - - public void onPlayerShow(PlayerShowEvent playerShowEvent) { - this.server.getPlayerStateManager().onPlayerShow(playerShowEvent); - } - - public PacketRateLimiter getRateLimiter() { - return this.rateLimiter; - } - - public Server getServer() { - return this.server; - } -} - diff --git a/source/decompiled/summary.txt b/source/decompiled/summary.txt deleted file mode 100644 index 559f9a2..0000000 --- a/source/decompiled/summary.txt +++ /dev/null @@ -1,2 +0,0 @@ -Summary for A:\Projekty\voicechat\git\AsminVoiceChat-1.0.0.jar -Decompiled with CFR 0.152 diff --git a/source/resources/CONCENTUS_LICENSE b/source/resources/CONCENTUS_LICENSE deleted file mode 100644 index 62d21b6..0000000 --- a/source/resources/CONCENTUS_LICENSE +++ /dev/null @@ -1,37 +0,0 @@ -Copyright (c) by various holding parties, including (but not limited to): -Skype Limited, Xiph.Org Foundation, CSIRO, Microsoft Corporation, -Jean-Marc Valin, Gregory Maxwell, Mark Borgerding, Timothy B. Terriberry, -Logan Stromberg. All rights are reserved by their respective holders. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of Internet Society, IETF or IETF Trust, nor the - names of specific contributors, may be used to endorse or promote - products derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -This repository and its redistributable packages contain independently compiled -versions of the Opus C reference library, which is maintained by Xiph.org and the -Opus open-source contributors. The source code for these libraries is freely available -at https://gitlab.xiph.org/xiph/opus/-/tags/v1.5.2, and all binaries are being -redistributed to you under the same terms of the general Opus license dictated above. \ No newline at end of file diff --git a/source/resources/META-INF/MANIFEST.MF b/source/resources/META-INF/MANIFEST.MF deleted file mode 100644 index 936a396..0000000 --- a/source/resources/META-INF/MANIFEST.MF +++ /dev/null @@ -1,6 +0,0 @@ -Manifest-Version: 1.0 -Class-Path: voicechat-api-2.6.25.jar configbuilder-2.1.0.jar json-202512 - 24.jar commodore-2.2.jar Concentus-1.0.1.jar commodore-file-1.0.jar bri - gadier-1.0.18.jar -Multi-Release: true - diff --git a/source/resources/META-INF/maven/de.maxhenkel.configbuilder/configbuilder/pom.properties b/source/resources/META-INF/maven/de.maxhenkel.configbuilder/configbuilder/pom.properties deleted file mode 100644 index 083c94a..0000000 --- a/source/resources/META-INF/maven/de.maxhenkel.configbuilder/configbuilder/pom.properties +++ /dev/null @@ -1,3 +0,0 @@ -artifactId=configbuilder -groupId=de.maxhenkel.configbuilder -version=2.1.0 diff --git a/source/resources/META-INF/maven/de.maxhenkel.configbuilder/configbuilder/pom.xml b/source/resources/META-INF/maven/de.maxhenkel.configbuilder/configbuilder/pom.xml deleted file mode 100644 index 8ffeade..0000000 --- a/source/resources/META-INF/maven/de.maxhenkel.configbuilder/configbuilder/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - 4.0.0 - - de.maxhenkel.configbuilder - configbuilder - 2.1.0 - - - 8 - 8 - UTF-8 - - - - - com.google.code.findbugs - jsr305 - 3.0.2 - provided - - - org.junit.jupiter - junit-jupiter - 5.9.2 - test - - - org.mockito - mockito-core - 5.4.0 - test - - - - - - - org.apache.maven.plugins - maven-source-plugin - 3.2.1 - - - attach-sources - verify - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.2 - - -Dfile.encoding=UTF-8 - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 1.8 - 1.8 - - - - - - - - henkelmax.public - https://maven.maxhenkel.de/repository/public - - - - \ No newline at end of file diff --git a/source/resources/META-INF/maven/me.lucko/commodore/pom.properties b/source/resources/META-INF/maven/me.lucko/commodore/pom.properties deleted file mode 100644 index dd61b5d..0000000 --- a/source/resources/META-INF/maven/me.lucko/commodore/pom.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Generated by Maven -#Wed Aug 03 22:00:27 BST 2022 -groupId=me.lucko -artifactId=commodore -version=2.2 diff --git a/source/resources/META-INF/maven/me.lucko/commodore/pom.xml b/source/resources/META-INF/maven/me.lucko/commodore/pom.xml deleted file mode 100644 index 05aeec3..0000000 --- a/source/resources/META-INF/maven/me.lucko/commodore/pom.xml +++ /dev/null @@ -1,162 +0,0 @@ - - - 4.0.0 - - me.lucko - commodore - 2.2 - - commodore - Utility for using Minecraft's 1.13 'brigadier' library in Bukkit plugins. - https://github.com/lucko/commodore - - - - MIT - https://opensource.org/licenses/MIT - - - - - - Luck - git@lucko.me - https://github.com/lucko - - - - - scm:git:https://github.com/lucko/commodore.git - scm:git:git@github.com:lucko/commodore.git - https://github.com/lucko/commodore - - - - UTF-8 - 1.8 - 1.8 - - - - - me.lucko - commodore-file - 1.0 - compile - - - com.mojang - brigadier - - - - - com.mojang - brigadier - 1.0.18 - compile - - - com.google.guava - guava - - - - - io.papermc.paper - paper-api - 1.19.1-R0.1-SNAPSHOT - provided - - - io.papermc.paper - paper-mojangapi - 1.19.1-R0.1-SNAPSHOT - provided - - - - - - minecraft-repo - https://libraries.minecraft.net/ - - - papermc - https://repo.papermc.io/repository/maven-public/ - - - - - - sign - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - - - - ossrh - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - - - deployment - - - - org.apache.maven.plugins - maven-source-plugin - 3.2.1 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.4.0 - - - attach-javadocs - - jar - - - - - - - - - - \ No newline at end of file diff --git a/source/resources/META-INF/maven/org.concentus/Concentus/pom.properties b/source/resources/META-INF/maven/org.concentus/Concentus/pom.properties deleted file mode 100644 index d1e58be..0000000 --- a/source/resources/META-INF/maven/org.concentus/Concentus/pom.properties +++ /dev/null @@ -1,3 +0,0 @@ -artifactId=Concentus -groupId=org.concentus -version=1.0.1 diff --git a/source/resources/META-INF/maven/org.concentus/Concentus/pom.xml b/source/resources/META-INF/maven/org.concentus/Concentus/pom.xml deleted file mode 100644 index 7352e4a..0000000 --- a/source/resources/META-INF/maven/org.concentus/Concentus/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - 4.0.0 - org.concentus - Concentus - 1.0.1 - jar - - UTF-8 - 1.8 - 1.8 - - Concentus - This package is a pure portable Java implementation of the Opus audio compression codec (see - https://opus-codec.org/ for more details). This package contains the Opus encoder, decoder, multistream codecs, - and repacketizer. It does NOT contain code to parse .ogg or .opus container files or to manage RTP packet - streams. - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.14.0 - - 8 - 8 - - - - maven-antrun-plugin - 3.1.0 - - - copy-and-rename-license - process-resources - - run - - - - - - - - - - - - - - - henkelmax.public - https://maven.maxhenkel.de/repository/public - - - - \ No newline at end of file diff --git a/source/resources/META-INF/maven/org.json/json/pom.properties b/source/resources/META-INF/maven/org.json/json/pom.properties deleted file mode 100644 index 8683715..0000000 --- a/source/resources/META-INF/maven/org.json/json/pom.properties +++ /dev/null @@ -1,3 +0,0 @@ -version=20251224 -groupId=org.json -artifactId=json diff --git a/source/resources/META-INF/maven/org.json/json/pom.xml b/source/resources/META-INF/maven/org.json/json/pom.xml deleted file mode 100644 index 6269edc..0000000 --- a/source/resources/META-INF/maven/org.json/json/pom.xml +++ /dev/null @@ -1,263 +0,0 @@ - - 4.0.0 - - org.json - json - 20251224 - bundle - - JSON in Java - - JSON is a light-weight, language independent, data interchange format. - See http://www.JSON.org/ - - The files in this package implement JSON encoders/decoders in Java. - It also includes the capability to convert between JSON and XML, HTTP - headers, Cookies, and CDL. - - This is a reference implementation. There are a large number of JSON packages - in Java. Perhaps someday the Java community will standardize on one. Until - then, choose carefully. - - https://github.com/douglascrockford/JSON-java - - - https://github.com/douglascrockford/JSON-java.git - scm:git:git://github.com/douglascrockford/JSON-java.git - scm:git:git@github.com:douglascrockford/JSON-java.git - - - - - Public Domain - https://github.com/stleary/JSON-java/blob/master/LICENSE - repo - - - - - - Douglas Crockford - douglas@crockford.com - - - - - UTF-8 - - - - - - ossrh - Central Repository OSSRH - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - - - - - junit - junit - 4.13.2 - test - - - com.jayway.jsonpath - json-path - 2.9.0 - test - - - org.mockito - mockito-core - 4.2.0 - test - - - - - - - org.sonatype.central - central-publishing-maven-plugin - 0.9.0 - true - - central - - - - org.apache.felix - maven-bundle-plugin - 5.1.9 - true - - - - org.json - - ${project.artifactId} - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.11.0 - - 1.8 - 1.8 - - -Xlint:unchecked - - - - - org.apache.maven.plugins - maven-source-plugin - 3.3.0 - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.5.0 - - - attach-javadocs - - jar - - - -Xdoclint:none - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - --pinentry-mode - loopback - - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.3 - true - - ossrh - https://oss.sonatype.org/ - false - - - - org.moditect - moditect-maven-plugin - 1.0.0.Final - - - add-module-infos - package - - add-module-info - - - 9 - - - module org.json { - exports org.json; - } - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.3.0 - - - - - - test-strict-mode - - - - com.google.code.maven-replacer-plugin - replacer - 1.5.3 - - - - enable-strict-mode - process-sources - - replace - - - src/main/java/org/json/JSONParserConfiguration.java - - - // this.strictMode = true; - this.strictMode = true; - - - - - - - restore-original - test - - replace - - - src/main/java/org/json/JSONParserConfiguration.java - - - this.strictMode = true; - // this.strictMode = true; - - - - - - - - - - - - diff --git a/source/resources/plugin.yml b/source/resources/plugin.yml deleted file mode 100644 index 5803eba..0000000 --- a/source/resources/plugin.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: AsminVoicechat -version: 1.0.0 -main: de.maxhenkel.voicechat.Voicechat -api-version: '1.13' -prefix: AsminVoicechat -authors: - - Asmin Studios (asmin.me) - - Max Henkel - - Matthew Wells -description: Simple Voice Chat server fork with support for 2.5 and 2.6 clients -website: https://git.asmin.me/asminme/AsminVoicechat -load: STARTUP -provides: [voicechat] -folia-supported: true -commands: - voicechat: - description: Manage voice chat - usage: Invalid command syntax -permissions: - voicechat.listen: - description: Allows to listen to voice chat - voicechat.speak: - description: Allows to speak in voice chat - voicechat.groups: - description: Allows to join groups - voicechat.admin: - description: Allows to test voice chat connections -softdepend: [PlaceholderAPI, ViaVersion]